aboutsummaryrefslogtreecommitdiffstats
path: root/vendor/github.com/dustin/go-humanize/si.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/dustin/go-humanize/si.go')
-rw-r--r--vendor/github.com/dustin/go-humanize/si.go127
1 files changed, 127 insertions, 0 deletions
diff --git a/vendor/github.com/dustin/go-humanize/si.go b/vendor/github.com/dustin/go-humanize/si.go
new file mode 100644
index 0000000..8b85019
--- /dev/null
+++ b/vendor/github.com/dustin/go-humanize/si.go
@@ -0,0 +1,127 @@
1package humanize
2
3import (
4 "errors"
5 "math"
6 "regexp"
7 "strconv"
8)
9
10var siPrefixTable = map[float64]string{
11 -30: "q", // quecto
12 -27: "r", // ronto
13 -24: "y", // yocto
14 -21: "z", // zepto
15 -18: "a", // atto
16 -15: "f", // femto
17 -12: "p", // pico
18 -9: "n", // nano
19 -6: "ยต", // micro
20 -3: "m", // milli
21 0: "",
22 3: "k", // kilo
23 6: "M", // mega
24 9: "G", // giga
25 12: "T", // tera
26 15: "P", // peta
27 18: "E", // exa
28 21: "Z", // zetta
29 24: "Y", // yotta
30 27: "R", // ronna
31 30: "Q", // quetta
32}
33
34var revSIPrefixTable = revfmap(siPrefixTable)
35
36// revfmap reverses the map and precomputes the power multiplier
37func revfmap(in map[float64]string) map[string]float64 {
38 rv := map[string]float64{}
39 for k, v := range in {
40 rv[v] = math.Pow(10, k)
41 }
42 return rv
43}
44
45var riParseRegex *regexp.Regexp
46
47func init() {
48 ri := `^([\-0-9.]+)\s?([`
49 for _, v := range siPrefixTable {
50 ri += v
51 }
52 ri += `]?)(.*)`
53
54 riParseRegex = regexp.MustCompile(ri)
55}
56
57// ComputeSI finds the most appropriate SI prefix for the given number
58// and returns the prefix along with the value adjusted to be within
59// that prefix.
60//
61// See also: SI, ParseSI.
62//
63// e.g. ComputeSI(2.2345e-12) -> (2.2345, "p")
64func ComputeSI(input float64) (float64, string) {
65 if input == 0 {
66 return 0, ""
67 }
68 mag := math.Abs(input)
69 exponent := math.Floor(logn(mag, 10))
70 exponent = math.Floor(exponent/3) * 3
71
72 value := mag / math.Pow(10, exponent)
73
74 // Handle special case where value is exactly 1000.0
75 // Should return 1 M instead of 1000 k
76 if value == 1000.0 {
77 exponent += 3
78 value = mag / math.Pow(10, exponent)
79 }
80
81 value = math.Copysign(value, input)
82
83 prefix := siPrefixTable[exponent]
84 return value, prefix
85}
86
87// SI returns a string with default formatting.
88//
89// SI uses Ftoa to format float value, removing trailing zeros.
90//
91// See also: ComputeSI, ParseSI.
92//
93// e.g. SI(1000000, "B") -> 1 MB
94// e.g. SI(2.2345e-12, "F") -> 2.2345 pF
95func SI(input float64, unit string) string {
96 value, prefix := ComputeSI(input)
97 return Ftoa(value) + " " + prefix + unit
98}
99
100// SIWithDigits works like SI but limits the resulting string to the
101// given number of decimal places.
102//
103// e.g. SIWithDigits(1000000, 0, "B") -> 1 MB
104// e.g. SIWithDigits(2.2345e-12, 2, "F") -> 2.23 pF
105func SIWithDigits(input float64, decimals int, unit string) string {
106 value, prefix := ComputeSI(input)
107 return FtoaWithDigits(value, decimals) + " " + prefix + unit
108}
109
110var errInvalid = errors.New("invalid input")
111
112// ParseSI parses an SI string back into the number and unit.
113//
114// See also: SI, ComputeSI.
115//
116// e.g. ParseSI("2.2345 pF") -> (2.2345e-12, "F", nil)
117func ParseSI(input string) (float64, string, error) {
118 found := riParseRegex.FindStringSubmatch(input)
119 if len(found) != 4 {
120 return 0, "", errInvalid
121 }
122 mag := revSIPrefixTable[found[2]]
123 unit := found[3]
124
125 base, err := strconv.ParseFloat(found[1], 64)
126 return base * mag, unit, err
127}