1 // Copyright 2009 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package strconv_test 6 7 import ( 8 "math" 9 "math/rand" 10 . "strconv" 11 "testing" 12 ) 13 14 type ftoaTest struct { 15 f float64 16 fmt byte 17 prec int 18 s string 19 } 20 21 func fdiv(a, b float64) float64 { return a / b } // keep compiler in the dark 22 23 const ( 24 below1e23 = 99999999999999974834176 25 above1e23 = 100000000000000008388608 26 ) 27 28 var ftoatests = []ftoaTest{ 29 {1, 'e', 5, "1.00000e+00"}, 30 {1, 'f', 5, "1.00000"}, 31 {1, 'g', 5, "1"}, 32 {1, 'g', -1, "1"}, 33 {20, 'g', -1, "20"}, 34 {1234567.8, 'g', -1, "1.2345678e+06"}, 35 {200000, 'g', -1, "200000"}, 36 {2000000, 'g', -1, "2e+06"}, 37 38 // g conversion and zero suppression 39 {400, 'g', 2, "4e+02"}, 40 {40, 'g', 2, "40"}, 41 {4, 'g', 2, "4"}, 42 {.4, 'g', 2, "0.4"}, 43 {.04, 'g', 2, "0.04"}, 44 {.004, 'g', 2, "0.004"}, 45 {.0004, 'g', 2, "0.0004"}, 46 {.00004, 'g', 2, "4e-05"}, 47 {.000004, 'g', 2, "4e-06"}, 48 49 {0, 'e', 5, "0.00000e+00"}, 50 {0, 'f', 5, "0.00000"}, 51 {0, 'g', 5, "0"}, 52 {0, 'g', -1, "0"}, 53 54 {-1, 'e', 5, "-1.00000e+00"}, 55 {-1, 'f', 5, "-1.00000"}, 56 {-1, 'g', 5, "-1"}, 57 {-1, 'g', -1, "-1"}, 58 59 {12, 'e', 5, "1.20000e+01"}, 60 {12, 'f', 5, "12.00000"}, 61 {12, 'g', 5, "12"}, 62 {12, 'g', -1, "12"}, 63 64 {123456700, 'e', 5, "1.23457e+08"}, 65 {123456700, 'f', 5, "123456700.00000"}, 66 {123456700, 'g', 5, "1.2346e+08"}, 67 {123456700, 'g', -1, "1.234567e+08"}, 68 69 {1.2345e6, 'e', 5, "1.23450e+06"}, 70 {1.2345e6, 'f', 5, "1234500.00000"}, 71 {1.2345e6, 'g', 5, "1.2345e+06"}, 72 73 {1e23, 'e', 17, "9.99999999999999916e+22"}, 74 {1e23, 'f', 17, "99999999999999991611392.00000000000000000"}, 75 {1e23, 'g', 17, "9.9999999999999992e+22"}, 76 77 {1e23, 'e', -1, "1e+23"}, 78 {1e23, 'f', -1, "100000000000000000000000"}, 79 {1e23, 'g', -1, "1e+23"}, 80 81 {below1e23, 'e', 17, "9.99999999999999748e+22"}, 82 {below1e23, 'f', 17, "99999999999999974834176.00000000000000000"}, 83 {below1e23, 'g', 17, "9.9999999999999975e+22"}, 84 85 {below1e23, 'e', -1, "9.999999999999997e+22"}, 86 {below1e23, 'f', -1, "99999999999999970000000"}, 87 {below1e23, 'g', -1, "9.999999999999997e+22"}, 88 89 {above1e23, 'e', 17, "1.00000000000000008e+23"}, 90 {above1e23, 'f', 17, "100000000000000008388608.00000000000000000"}, 91 {above1e23, 'g', 17, "1.0000000000000001e+23"}, 92 93 {above1e23, 'e', -1, "1.0000000000000001e+23"}, 94 {above1e23, 'f', -1, "100000000000000010000000"}, 95 {above1e23, 'g', -1, "1.0000000000000001e+23"}, 96 97 {fdiv(5e-304, 1e20), 'g', -1, "5e-324"}, 98 {fdiv(-5e-304, 1e20), 'g', -1, "-5e-324"}, 99 100 {32, 'g', -1, "32"}, 101 {32, 'g', 0, "3e+01"}, 102 103 {100, 'x', -1, "%x"}, 104 105 {math.NaN(), 'g', -1, "NaN"}, 106 {-math.NaN(), 'g', -1, "NaN"}, 107 {math.Inf(0), 'g', -1, "+Inf"}, 108 {math.Inf(-1), 'g', -1, "-Inf"}, 109 {-math.Inf(0), 'g', -1, "-Inf"}, 110 111 {-1, 'b', -1, "-4503599627370496p-52"}, 112 113 // fixed bugs 114 {0.9, 'f', 1, "0.9"}, 115 {0.09, 'f', 1, "0.1"}, 116 {0.0999, 'f', 1, "0.1"}, 117 {0.05, 'f', 1, "0.1"}, 118 {0.05, 'f', 0, "0"}, 119 {0.5, 'f', 1, "0.5"}, 120 {0.5, 'f', 0, "0"}, 121 {1.5, 'f', 0, "2"}, 122 123 // http://www.exploringbinary.com/java-hangs-when-converting-2-2250738585072012e-308/ 124 {2.2250738585072012e-308, 'g', -1, "2.2250738585072014e-308"}, 125 // http://www.exploringbinary.com/php-hangs-on-numeric-value-2-2250738585072011e-308/ 126 {2.2250738585072011e-308, 'g', -1, "2.225073858507201e-308"}, 127 128 // Issue 2625. 129 {383260575764816448, 'f', 0, "383260575764816448"}, 130 {383260575764816448, 'g', -1, "3.8326057576481645e+17"}, 131 } 132 133 func TestFtoa(t *testing.T) { 134 for i := 0; i < len(ftoatests); i++ { 135 test := &ftoatests[i] 136 s := FormatFloat(test.f, test.fmt, test.prec, 64) 137 if s != test.s { 138 t.Error("testN=64", test.f, string(test.fmt), test.prec, "want", test.s, "got", s) 139 } 140 x := AppendFloat([]byte("abc"), test.f, test.fmt, test.prec, 64) 141 if string(x) != "abc"+test.s { 142 t.Error("AppendFloat testN=64", test.f, string(test.fmt), test.prec, "want", "abc"+test.s, "got", string(x)) 143 } 144 if float64(float32(test.f)) == test.f && test.fmt != 'b' { 145 s := FormatFloat(test.f, test.fmt, test.prec, 32) 146 if s != test.s { 147 t.Error("testN=32", test.f, string(test.fmt), test.prec, "want", test.s, "got", s) 148 } 149 x := AppendFloat([]byte("abc"), test.f, test.fmt, test.prec, 32) 150 if string(x) != "abc"+test.s { 151 t.Error("AppendFloat testN=32", test.f, string(test.fmt), test.prec, "want", "abc"+test.s, "got", string(x)) 152 } 153 } 154 } 155 } 156 157 func TestFtoaRandom(t *testing.T) { 158 N := int(1e4) 159 if testing.Short() { 160 N = 100 161 } 162 t.Logf("testing %d random numbers with fast and slow FormatFloat", N) 163 for i := 0; i < N; i++ { 164 bits := uint64(rand.Uint32())<<32 | uint64(rand.Uint32()) 165 x := math.Float64frombits(bits) 166 167 shortFast := FormatFloat(x, 'g', -1, 64) 168 SetOptimize(false) 169 shortSlow := FormatFloat(x, 'g', -1, 64) 170 SetOptimize(true) 171 if shortSlow != shortFast { 172 t.Errorf("%b printed as %s, want %s", x, shortFast, shortSlow) 173 } 174 175 prec := rand.Intn(12) + 5 176 shortFast = FormatFloat(x, 'e', prec, 64) 177 SetOptimize(false) 178 shortSlow = FormatFloat(x, 'e', prec, 64) 179 SetOptimize(true) 180 if shortSlow != shortFast { 181 t.Errorf("%b printed as %s, want %s", x, shortFast, shortSlow) 182 } 183 } 184 } 185 186 func BenchmarkFormatFloatDecimal(b *testing.B) { 187 for i := 0; i < b.N; i++ { 188 FormatFloat(33909, 'g', -1, 64) 189 } 190 } 191 192 func BenchmarkFormatFloat(b *testing.B) { 193 for i := 0; i < b.N; i++ { 194 FormatFloat(339.7784, 'g', -1, 64) 195 } 196 } 197 198 func BenchmarkFormatFloatExp(b *testing.B) { 199 for i := 0; i < b.N; i++ { 200 FormatFloat(-5.09e75, 'g', -1, 64) 201 } 202 } 203 204 func BenchmarkFormatFloatNegExp(b *testing.B) { 205 for i := 0; i < b.N; i++ { 206 FormatFloat(-5.11e-95, 'g', -1, 64) 207 } 208 } 209 210 func BenchmarkFormatFloatBig(b *testing.B) { 211 for i := 0; i < b.N; i++ { 212 FormatFloat(123456789123456789123456789, 'g', -1, 64) 213 } 214 } 215 216 func benchmarkAppendFloat(b *testing.B, f float64, fmt byte, prec, bitSize int) { 217 dst := make([]byte, 30) 218 for i := 0; i < b.N; i++ { 219 AppendFloat(dst[:0], f, fmt, prec, bitSize) 220 } 221 } 222 223 func BenchmarkAppendFloatDecimal(b *testing.B) { benchmarkAppendFloat(b, 33909, 'g', -1, 64) } 224 func BenchmarkAppendFloat(b *testing.B) { benchmarkAppendFloat(b, 339.7784, 'g', -1, 64) } 225 func BenchmarkAppendFloatExp(b *testing.B) { benchmarkAppendFloat(b, -5.09e75, 'g', -1, 64) } 226 func BenchmarkAppendFloatNegExp(b *testing.B) { benchmarkAppendFloat(b, -5.11e-95, 'g', -1, 64) } 227 func BenchmarkAppendFloatBig(b *testing.B) { 228 benchmarkAppendFloat(b, 123456789123456789123456789, 'g', -1, 64) 229 } 230 func BenchmarkAppendFloatBinaryExp(b *testing.B) { benchmarkAppendFloat(b, -1, 'b', -1, 64) } 231 232 func BenchmarkAppendFloat32Integer(b *testing.B) { benchmarkAppendFloat(b, 33909, 'g', -1, 32) } 233 func BenchmarkAppendFloat32ExactFraction(b *testing.B) { benchmarkAppendFloat(b, 3.375, 'g', -1, 32) } 234 func BenchmarkAppendFloat32Point(b *testing.B) { benchmarkAppendFloat(b, 339.7784, 'g', -1, 32) } 235 func BenchmarkAppendFloat32Exp(b *testing.B) { benchmarkAppendFloat(b, -5.09e25, 'g', -1, 32) } 236 func BenchmarkAppendFloat32NegExp(b *testing.B) { benchmarkAppendFloat(b, -5.11e-25, 'g', -1, 32) } 237 238 func BenchmarkAppendFloat64Fixed1(b *testing.B) { benchmarkAppendFloat(b, 123456, 'e', 3, 64) } 239 func BenchmarkAppendFloat64Fixed2(b *testing.B) { benchmarkAppendFloat(b, 123.456, 'e', 3, 64) } 240 func BenchmarkAppendFloat64Fixed3(b *testing.B) { benchmarkAppendFloat(b, 1.23456e+78, 'e', 3, 64) } 241 func BenchmarkAppendFloat64Fixed4(b *testing.B) { benchmarkAppendFloat(b, 1.23456e-78, 'e', 3, 64) } 242