// Ftoa32(f) is not the same as Ftoa64(float32(f)),
// because correct rounding and the number of digits
// needed to identify f depend on the precision of the representation.
-func FormatFloat(f float64, fmt byte, prec int, n int) string {
- if n == 32 {
- return genericFtoa(uint64(math.Float32bits(float32(f))), fmt, prec, &float32info)
- }
- return genericFtoa(math.Float64bits(f), fmt, prec, &float64info)
+func FormatFloat(f float64, fmt byte, prec, bitSize int) string {
+ return string(genericFtoa(make([]byte, 0, 16), 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 int, n int) []byte {
- return append(dst, FormatFloat(f, fmt, prec, n)...)
+func AppendFloat(dst []byte, f float64, fmt byte, prec int, bitSize int) []byte {
+ return genericFtoa(dst, f, fmt, prec, bitSize)
}
-func genericFtoa(bits uint64, fmt byte, prec int, flt *floatInfo) string {
+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
- if mant != 0 {
- return "NaN"
- }
- if neg {
- return "-Inf"
+ var s string
+ switch {
+ case mant != 0:
+ s = "NaN"
+ case neg:
+ s = "-Inf"
+ default:
+ s = "+Inf"
}
- return "+Inf"
+ return append(dst, s...)
case 0:
// denormalized
// Pick off easy binary format.
if fmt == 'b' {
- return fmtB(neg, mant, exp, flt)
+ return fmtB(dst, neg, mant, exp, flt)
}
// Create exact decimal representation.
switch fmt {
case 'e', 'E':
- return fmtE(neg, d, prec, fmt)
+ return fmtE(dst, neg, d, prec, fmt)
case 'f':
- return fmtF(neg, d, prec)
+ return fmtF(dst, neg, d, prec)
case 'g', 'G':
// trailing fractional zeros in 'e' form will be trimmed.
eprec := prec
if prec > d.nd {
prec = d.nd
}
- return fmtE(neg, d, prec-1, fmt+'e'-'g')
+ return fmtE(dst, neg, d, prec-1, fmt+'e'-'g')
}
if prec > d.dp {
prec = d.nd
}
- return fmtF(neg, d, max(prec-d.dp, 0))
+ return fmtF(dst, neg, d, max(prec-d.dp, 0))
}
- return "%" + string(fmt)
+ // unknown format
+ return append(dst, '%', fmt)
}
// Round d (= mant * 2^exp) to the shortest number of digits
}
// %e: -d.ddddde±dd
-func fmtE(neg bool, d *decimal, prec int, fmt byte) string {
- buf := make([]byte, 3+max(prec, 0)+30) // "-0." + prec digits + exp
- w := 0 // write index
-
+func fmtE(dst []byte, neg bool, d *decimal, prec int, fmt byte) []byte {
// sign
if neg {
- buf[w] = '-'
- w++
+ dst = append(dst, '-')
}
// first digit
- if d.nd == 0 {
- buf[w] = '0'
- } else {
- buf[w] = d.d[0]
+ ch := byte('0')
+ if d.nd != 0 {
+ ch = d.d[0]
}
- w++
+ dst = append(dst, ch)
// .moredigits
if prec > 0 {
- buf[w] = '.'
- w++
- for i := 0; i < prec; i++ {
- if 1+i < d.nd {
- buf[w] = d.d[1+i]
- } else {
- buf[w] = '0'
+ dst = append(dst, '.')
+ for i := 1; i <= prec; i++ {
+ ch = '0'
+ if i < d.nd {
+ ch = d.d[i]
}
- w++
+ dst = append(dst, ch)
}
}
// e±
- buf[w] = fmt
- w++
+ dst = append(dst, fmt)
exp := d.dp - 1
if d.nd == 0 { // special case: 0 has exponent 0
exp = 0
}
if exp < 0 {
- buf[w] = '-'
+ ch = '-'
exp = -exp
} else {
- buf[w] = '+'
+ ch = '+'
}
- w++
+ dst = append(dst, ch)
// dddd
- // count digits
- n := 0
- for e := exp; e > 0; e /= 10 {
- n++
+ var buf [3]byte
+ i := len(buf)
+ for exp >= 10 {
+ i--
+ buf[i] = byte(exp%10 + '0')
+ exp /= 10
}
- // leading zeros
- for i := n; i < 2; i++ {
- buf[w] = '0'
- w++
- }
- // digits
- w += n
- n = 0
- for e := exp; e > 0; e /= 10 {
- n++
- buf[w-n] = byte(e%10 + '0')
+ // exp < 10
+ i--
+ buf[i] = byte(exp + '0')
+
+ // leading zeroes
+ if i > len(buf)-2 {
+ i--
+ buf[i] = '0'
}
- return string(buf[0:w])
+ return append(dst, buf[i:]...)
}
// %f: -ddddddd.ddddd
-func fmtF(neg bool, d *decimal, prec int) string {
- buf := make([]byte, 1+max(d.dp, 1)+1+max(prec, 0))
- w := 0
-
+func fmtF(dst []byte, neg bool, d *decimal, prec int) []byte {
// sign
if neg {
- buf[w] = '-'
- w++
+ dst = append(dst, '-')
}
// integer, padded with zeros as needed.
if d.dp > 0 {
var i int
for i = 0; i < d.dp && i < d.nd; i++ {
- buf[w] = d.d[i]
- w++
+ dst = append(dst, d.d[i])
}
for ; i < d.dp; i++ {
- buf[w] = '0'
- w++
+ dst = append(dst, '0')
}
} else {
- buf[w] = '0'
- w++
+ dst = append(dst, '0')
}
// fraction
if prec > 0 {
- buf[w] = '.'
- w++
+ dst = append(dst, '.')
for i := 0; i < prec; i++ {
- if d.dp+i < 0 || d.dp+i >= d.nd {
- buf[w] = '0'
- } else {
- buf[w] = d.d[d.dp+i]
+ ch := byte('0')
+ if j := d.dp + i; 0 <= j && j < d.nd {
+ ch = d.d[j]
}
- w++
+ dst = append(dst, ch)
}
}
- return string(buf[0:w])
+ return dst
}
// %b: -ddddddddp+ddd
-func fmtB(neg bool, mant uint64, exp int, flt *floatInfo) string {
+func fmtB(dst []byte, neg bool, mant uint64, exp int, flt *floatInfo) []byte {
var buf [50]byte
w := len(buf)
exp -= int(flt.mantbits)
w--
buf[w] = '-'
}
- return string(buf[w:])
+ return append(dst, buf[w:]...)
}
func max(a, b int) int {
}
}
-func BenchmarkFtoa64Decimal(b *testing.B) {
+func BenchmarkFormatFloatDecimal(b *testing.B) {
for i := 0; i < b.N; i++ {
FormatFloat(33909, 'g', -1, 64)
}
}
-func BenchmarkFtoa64Float(b *testing.B) {
+func BenchmarkFormatFloat(b *testing.B) {
for i := 0; i < b.N; i++ {
FormatFloat(339.7784, 'g', -1, 64)
}
}
-func BenchmarkFtoa64FloatExp(b *testing.B) {
+func BenchmarkFormatFloatExp(b *testing.B) {
for i := 0; i < b.N; i++ {
FormatFloat(-5.09e75, 'g', -1, 64)
}
}
-func BenchmarkFtoa64Big(b *testing.B) {
+func BenchmarkFormatFloatBig(b *testing.B) {
for i := 0; i < b.N; i++ {
FormatFloat(123456789123456789123456789, 'g', -1, 64)
}
}
+
+func BenchmarkAppendFloatDecimal(b *testing.B) {
+ dst := make([]byte, 0, 30)
+ for i := 0; i < b.N; i++ {
+ AppendFloat(dst, 33909, 'g', -1, 64)
+ }
+}
+
+func BenchmarkAppendFloat(b *testing.B) {
+ dst := make([]byte, 0, 30)
+ for i := 0; i < b.N; i++ {
+ AppendFloat(dst, 339.7784, 'g', -1, 64)
+ }
+}
+
+func BenchmarkAppendFloatExp(b *testing.B) {
+ dst := make([]byte, 0, 30)
+ for i := 0; i < b.N; i++ {
+ AppendFloat(dst, -5.09e75, 'g', -1, 64)
+ }
+}
+
+func BenchmarkAppendFloatBig(b *testing.B) {
+ dst := make([]byte, 0, 30)
+ for i := 0; i < b.N; i++ {
+ AppendFloat(dst, 123456789123456789123456789, 'g', -1, 64)
+ }
+}