10
var siPrefixTable = map[float64]string{
30
var revSIPrefixTable = revfmap(siPrefixTable)
32
// revfmap reverses the map and precomputes the power multiplier
33
func revfmap(in map[float64]string) map[string]float64 {
34
rv := map[string]float64{}
35
for k, v := range in {
36
rv[v] = math.Pow(10, k)
41
var riParseRegex *regexp.Regexp
45
for _, v := range siPrefixTable {
50
riParseRegex = regexp.MustCompile(ri)
53
// ComputeSI finds the most appropriate SI prefix for the given number
54
// and returns the prefix along with the value adjusted to be within
57
// See also: SI, ParseSI.
59
// e.g. ComputeSI(2.2345e-12) -> (2.2345, "p")
60
func ComputeSI(input float64) (float64, string) {
64
exponent := math.Floor(logn(input, 10))
65
exponent = math.Floor(exponent/3) * 3
67
value := input / math.Pow(10, exponent)
69
// Handle special case where value is exactly 1000.0
70
// Should return 1M instead of 1000k
73
value = input / math.Pow(10, exponent)
76
prefix := siPrefixTable[exponent]
80
// SI returns a string with default formatting.
82
// SI uses Ftoa to format float value, removing trailing zeros.
84
// See also: ComputeSI, ParseSI.
86
// e.g. SI(1000000, B) -> 1MB
87
// e.g. SI(2.2345e-12, "F") -> 2.2345pF
88
func SI(input float64, unit string) string {
89
value, prefix := ComputeSI(input)
90
return Ftoa(value) + prefix + unit
93
var errInvalid = errors.New("invalid input")
95
// ParseSI parses an SI string back into the number and unit.
97
// See also: SI, ComputeSI.
99
// e.g. ParseSI(2.2345pF) -> (2.2345e-12, "F", nil)
100
func ParseSI(input string) (float64, string, error) {
101
found := riParseRegex.FindStringSubmatch(input)
103
return 0, "", errInvalid
105
mag := revSIPrefixTable[found[2]]
108
base, err := strconv.ParseFloat(found[1], 64)
109
return base * mag, unit, err