| // Copyright 2009 The Go Authors. All rights reserved. | |
| // Use of this source code is governed by a BSD-style | |
| // license that can be found in the LICENSE file. | |
| // Binary to decimal floating point conversion. | |
| // Algorithm: | |
| // 1) store mantissa in multiprecision decimal | |
| // 2) shift decimal by exponent | |
| // 3) read digits out & format | |
| package strconv | |
| import "math" | |
| // TODO: move elsewhere? | |
| type floatInfo struct { | |
| mantbits uint | |
| expbits uint | |
| bias int | |
| } | |
| var float32info = floatInfo{23, 8, -127} | |
| var float64info = floatInfo{52, 11, -1023} | |
| // FormatFloat converts the floating-point number f to a string, | |
| // according to the format fmt and precision prec. It rounds the | |
| // result assuming that the original was obtained from a floating-point | |
| // value of bitSize bits (32 for float32, 64 for float64). | |
| // | |
| // The format fmt is one of | |
| // 'b' (-ddddp±ddd, a binary exponent), | |
| // 'e' (-d.dddde±dd, a decimal exponent), | |
| // 'E' (-d.ddddE±dd, a decimal exponent), | |
| // 'f' (-ddd.dddd, no exponent), | |
| // 'g' ('e' for large exponents, 'f' otherwise), or | |
| // 'G' ('E' for large exponents, 'f' otherwise). | |
| // | |
| // The precision prec controls the number of digits | |
| // (excluding the exponent) printed by the 'e', 'E', 'f', 'g', and 'G' formats. | |
| // For 'e', 'E', and 'f' it is the number of digits after the decimal point. | |
| // For 'g' and 'G' it is the total number of digits. | |
| // The special precision -1 uses the smallest number of digits | |
| // necessary such that ParseFloat will return f exactly. | |
| func FormatFloat(f float64, fmt byte, prec, bitSize int) string { | |
| return string(genericFtoa(make([]byte, 0, max(prec+4, 24)), f, fmt, prec, bitSize)) | |
| } | |
| // AppendFloat appends the string form of the floating-point number f, | |
| // as generated by FormatFloat, to dst and returns the extended buffer. | |
| func AppendFloat(dst []byte, f float64, fmt byte, prec, bitSize int) []byte { | |
| return genericFtoa(dst, f, fmt, prec, bitSize) | |
| } | |
| func genericFtoa(dst []byte, val float64, fmt byte, prec, bitSize int) []byte { | |
| var bits uint64 | |
| var flt *floatInfo | |
| switch bitSize { | |
| case 32: | |
| bits = uint64(math.Float32bits(float32(val))) | |
| flt = &float32info | |
| case 64: | |
| bits = math.Float64bits(val) | |
| flt = &float64info | |
| default: | |
| panic("strconv: illegal AppendFloat/FormatFloat bitSize") | |
| } | |
| neg := bits>>(flt.expbits+flt.mantbits) != 0 | |
| exp := int(bits>>flt.mantbits) & (1<<flt.expbits - 1) | |
| mant := bits & (uint64(1)<<flt.mantbits - 1) | |
| switch exp { | |
| case 1<<flt.expbits - 1: | |
| // Inf, NaN | |
| var s string | |
| switch { | |
| case mant != 0: | |
| s = "NaN" | |
| case neg: | |
| s = "-Inf" | |
| default: | |
| s = "+Inf" | |
| } | |
| return append(dst, s...) | |
| case 0: | |
| // denormalized | |
| exp++ | |
| default: | |
| // add implicit top bit | |
| mant |= uint64(1) << flt.mantbits | |
| } | |
| exp += flt.bias | |
| // Pick off easy binary format. | |
| if fmt == 'b' { | |
| return fmtB(dst, neg, mant, exp, flt) | |
| } | |
| if !optimize { | |
| return bigFtoa(dst, prec, fmt, neg, mant, exp, flt) | |
| } | |
| var digs decimalSlice | |
| ok := false | |
| // Negative precision means "only as much as needed to be exact." | |
| shortest := prec < 0 | |
| if shortest { | |
| // Try Grisu3 algorithm. | |
| f := new(extFloat) | |
| lower, upper := f.AssignComputeBounds(mant, exp, neg, flt) | |
| var buf [32]byte | |
| digs.d = buf[:] | |
| ok = f.ShortestDecimal(&digs, &lower, &upper) | |
| if !ok { | |
| return bigFtoa(dst, prec, fmt, neg, mant, exp, flt) | |
| } | |
| // Precision for shortest representation mode. | |
| switch fmt { | |
| case 'e', 'E': | |
| prec = max(digs.nd-1, 0) | |
| case 'f': | |
| prec = max(digs.nd-digs.dp, 0) | |
| case 'g', 'G': | |
| prec = digs.nd | |
| } | |
| } else if fmt != 'f' { | |
| // Fixed number of digits. | |
| digits := prec | |
| switch fmt { | |
| case 'e', 'E': | |
| digits++ | |
| case 'g', 'G': | |
| if prec == 0 { | |
| prec = 1 | |
| } | |
| digits = prec | |
| } | |
| if digits <= 15 { | |
| // try fast algorithm when the number of digits is reasonable. | |
| var buf [24]byte | |
| digs.d = buf[:] | |
| f := extFloat{mant, exp - int(flt.mantbits), neg} | |
| ok = f.FixedDecimal(&digs, digits) | |
| } | |
| } | |
| if !ok { | |
| return bigFtoa(dst, prec, fmt, neg, mant, exp, flt) | |
| } | |
| return formatDigits(dst, shortest, neg, digs, prec, fmt) | |
| } | |
| // bigFtoa uses multiprecision computations to format a float. | |
| func bigFtoa(dst []byte, prec int, fmt byte, neg bool, mant uint64, exp int, flt *floatInfo) []byte { | |
| d := new(decimal) | |
| d.Assign(mant) | |
| d.Shift(exp - int(flt.mantbits)) | |
| var digs decimalSlice | |
| shortest := prec < 0 | |
| if shortest { | |
| roundShortest(d, mant, exp, flt) | |
| digs = decimalSlice{d: d.d[:], nd: d.nd, dp: d.dp} | |
| // Precision for shortest representation mode. | |
| switch fmt { | |
| case 'e', 'E': | |
| prec = digs.nd - 1 | |
| case 'f': | |
| prec = max(digs.nd-digs.dp, 0) | |
| case 'g', 'G': | |
| prec = digs.nd | |
| } | |
| } else { | |
| // Round appropriately. | |
| switch fmt { | |
| case 'e', 'E': | |
| d.Round(prec + 1) | |
| case 'f': | |
| d.Round(d.dp + prec) | |
| case 'g', 'G': | |
| if prec == 0 { | |
| prec = 1 | |
| } | |
| d.Round(prec) | |
| } | |
| digs = decimalSlice{d: d.d[:], nd: d.nd, dp: d.dp} | |
| } | |
| return formatDigits(dst, shortest, neg, digs, prec, fmt) | |
| } | |
| func formatDigits(dst []byte, shortest bool, neg bool, digs decimalSlice, prec int, fmt byte) []byte { | |
| switch fmt { | |
| case 'e', 'E': | |
| return fmtE(dst, neg, digs, prec, fmt) | |
| case 'f': | |
| return fmtF(dst, neg, digs, prec) | |
| case 'g', 'G': | |
| // trailing fractional zeros in 'e' form will be trimmed. | |
| eprec := prec | |
| if eprec > digs.nd && digs.nd >= digs.dp { | |
| eprec = digs.nd | |
| } | |
| // %e is used if the exponent from the conversion | |
| // is less than -4 or greater than or equal to the precision. | |
| // if precision was the shortest possible, use precision 6 for this decision. | |
| if shortest { | |
| eprec = 6 | |
| } | |
| exp := digs.dp - 1 | |
| if exp < -4 || exp >= eprec { | |
| if prec > digs.nd { | |
| prec = digs.nd | |
| } | |
| return fmtE(dst, neg, digs, prec-1, fmt+'e'-'g') | |
| } | |
| if prec > digs.dp { | |
| prec = digs.nd | |
| } | |
| return fmtF(dst, neg, digs, max(prec-digs.dp, 0)) | |
| } | |
| // unknown format | |
| return append(dst, '%', fmt) | |
| } | |
| // roundShortest rounds d (= mant * 2^exp) to the shortest number of digits | |
| // that will let the original floating point value be precisely reconstructed. | |
| func roundShortest(d *decimal, mant uint64, exp int, flt *floatInfo) { | |
| // If mantissa is zero, the number is zero; stop now. | |
| if mant == 0 { | |
| d.nd = 0 | |
| return | |
| } | |
| // Compute upper and lower such that any decimal number | |
| // between upper and lower (possibly inclusive) | |
| // will round to the original floating point number. | |
| // We may see at once that the number is already shortest. | |
| // | |
| // Suppose d is not denormal, so that 2^exp <= d < 10^dp. | |
| // The closest shorter number is at least 10^(dp-nd) away. | |
| // The lower/upper bounds computed below are at distance | |
| // at most 2^(exp-mantbits). | |
| // | |
| // So the number is already shortest if 10^(dp-nd) > 2^(exp-mantbits), | |
| // or equivalently log2(10)*(dp-nd) > exp-mantbits. | |
| // It is true if 332/100*(dp-nd) >= exp-mantbits (log2(10) > 3.32). | |
| minexp := flt.bias + 1 // minimum possible exponent | |
| if exp > minexp && 332*(d.dp-d.nd) >= 100*(exp-int(flt.mantbits)) { | |
| // The number is already shortest. | |
| return | |
| } | |
| // d = mant << (exp - mantbits) | |
| // Next highest floating point number is mant+1 << exp-mantbits. | |
| // Our upper bound is halfway between, mant*2+1 << exp-mantbits-1. | |
| upper := new(decimal) | |
| upper.Assign(mant*2 + 1) | |
| upper.Shift(exp - int(flt.mantbits) - 1) | |
| // d = mant << (exp - mantbits) | |
| // Next lowest floating point number is mant-1 << exp-mantbits, | |
| // unless mant-1 drops the significant bit and exp is not the minimum exp, | |
| // in which case the next lowest is mant*2-1 << exp-mantbits-1. | |
| // Either way, call it mantlo << explo-mantbits. | |
| // Our lower bound is halfway between, mantlo*2+1 << explo-mantbits-1. | |
| var mantlo uint64 | |
| var explo int | |
| if mant > 1<<flt.mantbits || exp == minexp { | |
| mantlo = mant - 1 | |
| explo = exp | |
| } else { | |
| mantlo = mant*2 - 1 | |
| explo = exp - 1 | |
| } | |
| lower := new(decimal) | |
| lower.Assign(mantlo*2 + 1) | |
| lower.Shift(explo - int(flt.mantbits) - 1) | |
| // The upper and lower bounds are possible outputs only if | |
| // the original mantissa is even, so that IEEE round-to-even | |
| // would round to the original mantissa and not the neighbors. | |
| inclusive := mant%2 == 0 | |
| // Now we can figure out the minimum number of digits required. | |
| // Walk along until d has distinguished itself from upper and lower. | |
| for i := 0; i < d.nd; i++ { | |
| l := byte('0') // lower digit | |
| if i < lower.nd { | |
| l = lower.d[i] | |
| } | |
| m := d.d[i] // middle digit | |
| u := byte('0') // upper digit | |
| if i < upper.nd { | |
| u = upper.d[i] | |
| } | |
| // Okay to round down (truncate) if lower has a different digit | |
| // or if lower is inclusive and is exactly the result of rounding | |
| // down (i.e., and we have reached the final digit of lower). | |
| okdown := l != m || inclusive && i+1 == lower.nd | |
| // Okay to round up if upper has a different digit and either upper | |
| // is inclusive or upper is bigger than the result of rounding up. | |
| okup := m != u && (inclusive || m+1 < u || i+1 < upper.nd) | |
| // If it's okay to do either, then round to the nearest one. | |
| // If it's okay to do only one, do it. | |
| switch { | |
| case okdown && okup: | |
| d.Round(i + 1) | |
| return | |
| case okdown: | |
| d.RoundDown(i + 1) | |
| return | |
| case okup: | |
| d.RoundUp(i + 1) | |
| return | |
| } | |
| } | |
| } | |
| type decimalSlice struct { | |
| d []byte | |
| nd, dp int | |
| neg bool | |
| } | |
| // %e: -d.ddddde±dd | |
| func fmtE(dst []byte, neg bool, d decimalSlice, prec int, fmt byte) []byte { | |
| // sign | |
| if neg { | |
| dst = append(dst, '-') | |
| } | |
| // first digit | |
| ch := byte('0') | |
| if d.nd != 0 { | |
| ch = d.d[0] | |
| } | |
| dst = append(dst, ch) | |
| // .moredigits | |
| if prec > 0 { | |
| dst = append(dst, '.') | |
| i := 1 | |
| m := min(d.nd, prec+1) | |
| if i < m { | |
| dst = append(dst, d.d[i:m]...) | |
| i = m | |
| } | |
| for ; i <= prec; i++ { | |
| dst = append(dst, '0') | |
| } | |
| } | |
| // e± | |
| dst = append(dst, fmt) | |
| exp := d.dp - 1 | |
| if d.nd == 0 { // special case: 0 has exponent 0 | |
| exp = 0 | |
| } | |
| if exp < 0 { | |
| ch = '-' | |
| exp = -exp | |
| } else { | |
| ch = '+' | |
| } | |
| dst = append(dst, ch) | |
| // dd or ddd | |
| switch { | |
| case exp < 10: | |
| dst = append(dst, '0', byte(exp)+'0') | |
| case exp < 100: | |
| dst = append(dst, byte(exp/10)+'0', byte(exp%10)+'0') | |
| default: | |
| dst = append(dst, byte(exp/100)+'0', byte(exp/10)%10+'0', byte(exp%10)+'0') | |
| } | |
| return dst | |
| } | |
| // %f: -ddddddd.ddddd | |
| func fmtF(dst []byte, neg bool, d decimalSlice, prec int) []byte { | |
| // sign | |
| if neg { | |
| dst = append(dst, '-') | |
| } | |
| // integer, padded with zeros as needed. | |
| if d.dp > 0 { | |
| m := min(d.nd, d.dp) | |
| dst = append(dst, d.d[:m]...) | |
| for ; m < d.dp; m++ { | |
| dst = append(dst, '0') | |
| } | |
| } else { | |
| dst = append(dst, '0') | |
| } | |
| // fraction | |
| if prec > 0 { | |
| dst = append(dst, '.') | |
| for i := 0; i < prec; i++ { | |
| ch := byte('0') | |
| if j := d.dp + i; 0 <= j && j < d.nd { | |
| ch = d.d[j] | |
| } | |
| dst = append(dst, ch) | |
| } | |
| } | |
| return dst | |
| } | |
| // %b: -ddddddddp±ddd | |
| func fmtB(dst []byte, neg bool, mant uint64, exp int, flt *floatInfo) []byte { | |
| // sign | |
| if neg { | |
| dst = append(dst, '-') | |
| } | |
| // mantissa | |
| dst, _ = formatBits(dst, mant, 10, false, true) | |
| // p | |
| dst = append(dst, 'p') | |
| // ±exponent | |
| exp -= int(flt.mantbits) | |
| if exp >= 0 { | |
| dst = append(dst, '+') | |
| } | |
| dst, _ = formatBits(dst, uint64(exp), 10, exp < 0, true) | |
| return dst | |
| } | |
| func min(a, b int) int { | |
| if a < b { | |
| return a | |
| } | |
| return b | |
| } | |
| func max(a, b int) int { | |
| if a > b { | |
| return a | |
| } | |
| return b | |
| } |