cubefs

Форк
0
127 строк · 2.8 Кб
1
package humanize
2

3
import (
4
	"errors"
5
	"math"
6
	"regexp"
7
	"strconv"
8
)
9

10
var 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

34
var revSIPrefixTable = revfmap(siPrefixTable)
35

36
// revfmap reverses the map and precomputes the power multiplier
37
func 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

45
var riParseRegex *regexp.Regexp
46

47
func 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")
64
func 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
95
func 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
105
func SIWithDigits(input float64, decimals int, unit string) string {
106
	value, prefix := ComputeSI(input)
107
	return FtoaWithDigits(value, decimals) + " " + prefix + unit
108
}
109

110
var 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)
117
func 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
}
128

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.