diff options
author | 2022-08-07 18:19:16 +0200 | |
---|---|---|
committer | 2022-08-07 18:19:16 +0200 | |
commit | 879b4abde722cb66463ca81a4cf6ac5465ef276d (patch) | |
tree | cdbd98840bca27317ad0860a194072671ed04ebe /vendor/github.com/tdewolff/parse/v2/strconv/float.go | |
parent | [feature] Photoswipe gallery (#740) (diff) | |
download | gotosocial-879b4abde722cb66463ca81a4cf6ac5465ef276d.tar.xz |
[bugfix] Markdown formatting updates (#743)
* add minify dependency specifically for markdown
* rearrange markdown formatting
* update markdown tests
Diffstat (limited to 'vendor/github.com/tdewolff/parse/v2/strconv/float.go')
-rw-r--r-- | vendor/github.com/tdewolff/parse/v2/strconv/float.go | 257 |
1 files changed, 257 insertions, 0 deletions
diff --git a/vendor/github.com/tdewolff/parse/v2/strconv/float.go b/vendor/github.com/tdewolff/parse/v2/strconv/float.go new file mode 100644 index 000000000..c89bdb29d --- /dev/null +++ b/vendor/github.com/tdewolff/parse/v2/strconv/float.go @@ -0,0 +1,257 @@ +package strconv + +import ( + "math" +) + +var float64pow10 = []float64{ + 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, + 1e10, 1e11, 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19, + 1e20, 1e21, 1e22, +} + +// ParseFloat parses a byte-slice and returns the float it represents. +// If an invalid character is encountered, it will stop there. +func ParseFloat(b []byte) (float64, int) { + i := 0 + neg := false + if i < len(b) && (b[i] == '+' || b[i] == '-') { + neg = b[i] == '-' + i++ + } + start := i + dot := -1 + trunk := -1 + n := uint64(0) + for ; i < len(b); i++ { + c := b[i] + if c >= '0' && c <= '9' { + if trunk == -1 { + if n > math.MaxUint64/10 { + trunk = i + } else { + n *= 10 + n += uint64(c - '0') + } + } + } else if dot == -1 && c == '.' { + dot = i + } else { + break + } + } + if i == start || i == start+1 && dot == start { + return 0.0, 0 + } + + f := float64(n) + if neg { + f = -f + } + + mantExp := int64(0) + if dot != -1 { + if trunk == -1 { + trunk = i + } + mantExp = int64(trunk - dot - 1) + } else if trunk != -1 { + mantExp = int64(trunk - i) + } + expExp := int64(0) + if i < len(b) && (b[i] == 'e' || b[i] == 'E') { + startExp := i + i++ + if e, expLen := ParseInt(b[i:]); expLen > 0 { + expExp = e + i += expLen + } else { + i = startExp + } + } + exp := expExp - mantExp + + // copied from strconv/atof.go + if exp == 0 { + return f, i + } else if exp > 0 && exp <= 15+22 { // int * 10^k + // If exponent is big but number of digits is not, + // can move a few zeros into the integer part. + if exp > 22 { + f *= float64pow10[exp-22] + exp = 22 + } + if f <= 1e15 && f >= -1e15 { + return f * float64pow10[exp], i + } + } else if exp < 0 && exp >= -22 { // int / 10^k + return f / float64pow10[-exp], i + } + f *= math.Pow10(int(-mantExp)) + return f * math.Pow10(int(expExp)), i +} + +const log2 = 0.3010299956639812 + +func float64exp(f float64) int { + exp2 := 0 + if f != 0.0 { + x := math.Float64bits(f) + exp2 = int(x>>(64-11-1))&0x7FF - 1023 + 1 + } + + exp10 := float64(exp2) * log2 + if exp10 < 0 { + exp10 -= 1.0 + } + return int(exp10) +} + +// AppendFloat appends a float to `b` with precision `prec`. It returns the new slice and whether successful or not. Precision is the number of decimals to display, thus prec + 1 == number of significant digits. +func AppendFloat(b []byte, f float64, prec int) ([]byte, bool) { + if math.IsNaN(f) || math.IsInf(f, 0) { + return b, false + } + + neg := false + if f < 0.0 { + f = -f + neg = true + } + if prec < 0 || 17 < prec { + prec = 17 // maximum number of significant digits in double + } + prec -= float64exp(f) // number of digits in front of the dot + f *= math.Pow10(prec) + + // calculate mantissa and exponent + mant := int64(f) + mantLen := LenInt(mant) + mantExp := mantLen - prec - 1 + if mant == 0 { + return append(b, '0'), true + } + + // expLen is zero for positive exponents, because positive exponents are determined later on in the big conversion loop + exp := 0 + expLen := 0 + if mantExp > 0 { + // positive exponent is determined in the loop below + // but if we initially decreased the exponent to fit in an integer, we can't set the new exponent in the loop alone, + // since the number of zeros at the end determines the positive exponent in the loop, and we just artificially lost zeros + if prec < 0 { + exp = mantExp + } + expLen = 1 + LenInt(int64(exp)) // e + digits + } else if mantExp < -3 { + exp = mantExp + expLen = 2 + LenInt(int64(exp)) // e + minus + digits + } else if mantExp < -1 { + mantLen += -mantExp - 1 // extra zero between dot and first digit + } + + // reserve space in b + i := len(b) + maxLen := 1 + mantLen + expLen // dot + mantissa digits + exponent + if neg { + maxLen++ + } + if i+maxLen > cap(b) { + b = append(b, make([]byte, maxLen)...) + } else { + b = b[:i+maxLen] + } + + // write to string representation + if neg { + b[i] = '-' + i++ + } + + // big conversion loop, start at the end and move to the front + // initially print trailing zeros and remove them later on + // for example if the first non-zero digit is three positions in front of the dot, it will overwrite the zeros with a positive exponent + zero := true + last := i + mantLen // right-most position of digit that is non-zero + dot + dot := last - prec - exp // position of dot + j := last + for mant > 0 { + if j == dot { + b[j] = '.' + j-- + } + newMant := mant / 10 + digit := mant - 10*newMant + if zero && digit > 0 { + // first non-zero digit, if we are still behind the dot we can trim the end to this position + // otherwise trim to the dot (including the dot) + if j > dot { + i = j + 1 + // decrease negative exponent further to get rid of dot + if exp < 0 { + newExp := exp - (j - dot) + // getting rid of the dot shouldn't lower the exponent to more digits (e.g. -9 -> -10) + if LenInt(int64(newExp)) == LenInt(int64(exp)) { + exp = newExp + dot = j + j-- + i-- + } + } + } else { + i = dot + } + last = j + zero = false + } + b[j] = '0' + byte(digit) + j-- + mant = newMant + } + + if j > dot { + // extra zeros behind the dot + for j > dot { + b[j] = '0' + j-- + } + b[j] = '.' + } else if last+3 < dot { + // add positive exponent because we have 3 or more zeros in front of the dot + i = last + 1 + exp = dot - last - 1 + } else if j == dot { + // handle 0.1 + b[j] = '.' + } + + // exponent + if exp != 0 { + if exp == 1 { + b[i] = '0' + i++ + } else if exp == 2 { + b[i] = '0' + b[i+1] = '0' + i += 2 + } else { + b[i] = 'e' + i++ + if exp < 0 { + b[i] = '-' + i++ + exp = -exp + } + i += LenInt(int64(exp)) + j := i + for exp > 0 { + newExp := exp / 10 + digit := exp - 10*newExp + j-- + b[j] = '0' + byte(digit) + exp = newExp + } + } + } + return b[:i], true +} |