| // Copyright 2015 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. |
| |
| package big |
| |
| import ( |
| "io" |
| "math" |
| "strconv" |
| "testing" |
| ) |
| |
| func TestFloatSetFloat64String(t *testing.T) { |
| for _, test := range []struct { |
| s string |
| x float64 |
| }{ |
| {"0", 0}, |
| {"-0", -0}, |
| {"+0", 0}, |
| {"1", 1}, |
| {"-1", -1}, |
| {"+1", 1}, |
| {"1.234", 1.234}, |
| {"-1.234", -1.234}, |
| {"+1.234", 1.234}, |
| {".1", 0.1}, |
| {"1.", 1}, |
| {"+1.", 1}, |
| |
| {"0e100", 0}, |
| {"-0e+100", 0}, |
| {"+0e-100", 0}, |
| {"0E100", 0}, |
| {"-0E+100", 0}, |
| {"+0E-100", 0}, |
| {"0p100", 0}, |
| {"-0p+100", 0}, |
| {"+0p-100", 0}, |
| |
| {"1.e10", 1e10}, |
| {"1e+10", 1e10}, |
| {"+1e-10", 1e-10}, |
| {"1E10", 1e10}, |
| {"1.E+10", 1e10}, |
| {"+1E-10", 1e-10}, |
| {"1p10", 1 << 10}, |
| {"1p+10", 1 << 10}, |
| {"+1.p-10", 1.0 / (1 << 10)}, |
| |
| {"-687436.79457e-245", -687436.79457e-245}, |
| {"-687436.79457E245", -687436.79457e245}, |
| {"1024.p-12", 0.25}, |
| {"-1.p10", -1024}, |
| {"0.25p2", 1}, |
| |
| {".0000000000000000000000000000000000000001", 1e-40}, |
| {"+10000000000000000000000000000000000000000e-0", 1e40}, |
| } { |
| var x Float |
| x.prec = 53 // TODO(gri) find better solution |
| _, ok := x.SetString(test.s) |
| if !ok { |
| t.Errorf("%s: parse error", test.s) |
| continue |
| } |
| f, _ := x.Float64() |
| want := new(Float).SetFloat64(test.x) |
| if x.Cmp(want) != 0 { |
| t.Errorf("%s: got %s (%v); want %v", test.s, &x, f, test.x) |
| } |
| } |
| } |
| |
| const ( |
| below1e23 = 99999999999999974834176 |
| above1e23 = 100000000000000008388608 |
| ) |
| |
| func TestFloat64Format(t *testing.T) { |
| for _, test := range []struct { |
| x float64 |
| format byte |
| prec int |
| want string |
| }{ |
| {0, 'f', 0, "0"}, |
| {math.Copysign(0, -1), 'f', 0, "-0"}, |
| {1, 'f', 0, "1"}, |
| {-1, 'f', 0, "-1"}, |
| |
| {1.459, 'e', 0, "1e+00"}, |
| {2.459, 'e', 1, "2.5e+00"}, |
| {3.459, 'e', 2, "3.46e+00"}, |
| {4.459, 'e', 3, "4.459e+00"}, |
| {5.459, 'e', 4, "5.4590e+00"}, |
| |
| {1.459, 'f', 0, "1"}, |
| {2.459, 'f', 1, "2.5"}, |
| {3.459, 'f', 2, "3.46"}, |
| {4.459, 'f', 3, "4.459"}, |
| {5.459, 'f', 4, "5.4590"}, |
| |
| {0, 'b', 0, "0"}, |
| {math.Copysign(0, -1), 'b', 0, "-0"}, |
| {1.0, 'b', 0, "4503599627370496p-52"}, |
| {-1.0, 'b', 0, "-4503599627370496p-52"}, |
| {4503599627370496, 'b', 0, "4503599627370496p+0"}, |
| |
| {0, 'p', 0, "0"}, |
| {math.Copysign(0, -1), 'p', 0, "-0"}, |
| {1024.0, 'p', 0, "0x.8p11"}, |
| {-1024.0, 'p', 0, "-0x.8p11"}, |
| |
| // all test cases below from strconv/ftoa_test.go |
| {1, 'e', 5, "1.00000e+00"}, |
| {1, 'f', 5, "1.00000"}, |
| {1, 'g', 5, "1"}, |
| // {1, 'g', -1, "1"}, |
| // {20, 'g', -1, "20"}, |
| // {1234567.8, 'g', -1, "1.2345678e+06"}, |
| // {200000, 'g', -1, "200000"}, |
| // {2000000, 'g', -1, "2e+06"}, |
| |
| // g conversion and zero suppression |
| {400, 'g', 2, "4e+02"}, |
| {40, 'g', 2, "40"}, |
| {4, 'g', 2, "4"}, |
| {.4, 'g', 2, "0.4"}, |
| {.04, 'g', 2, "0.04"}, |
| {.004, 'g', 2, "0.004"}, |
| {.0004, 'g', 2, "0.0004"}, |
| {.00004, 'g', 2, "4e-05"}, |
| {.000004, 'g', 2, "4e-06"}, |
| |
| {0, 'e', 5, "0.00000e+00"}, |
| {0, 'f', 5, "0.00000"}, |
| {0, 'g', 5, "0"}, |
| // {0, 'g', -1, "0"}, |
| |
| {-1, 'e', 5, "-1.00000e+00"}, |
| {-1, 'f', 5, "-1.00000"}, |
| {-1, 'g', 5, "-1"}, |
| // {-1, 'g', -1, "-1"}, |
| |
| {12, 'e', 5, "1.20000e+01"}, |
| {12, 'f', 5, "12.00000"}, |
| {12, 'g', 5, "12"}, |
| // {12, 'g', -1, "12"}, |
| |
| {123456700, 'e', 5, "1.23457e+08"}, |
| {123456700, 'f', 5, "123456700.00000"}, |
| {123456700, 'g', 5, "1.2346e+08"}, |
| // {123456700, 'g', -1, "1.234567e+08"}, |
| |
| {1.2345e6, 'e', 5, "1.23450e+06"}, |
| {1.2345e6, 'f', 5, "1234500.00000"}, |
| {1.2345e6, 'g', 5, "1.2345e+06"}, |
| |
| {1e23, 'e', 17, "9.99999999999999916e+22"}, |
| {1e23, 'f', 17, "99999999999999991611392.00000000000000000"}, |
| {1e23, 'g', 17, "9.9999999999999992e+22"}, |
| |
| // {1e23, 'e', -1, "1e+23"}, |
| // {1e23, 'f', -1, "100000000000000000000000"}, |
| // {1e23, 'g', -1, "1e+23"}, |
| |
| {below1e23, 'e', 17, "9.99999999999999748e+22"}, |
| {below1e23, 'f', 17, "99999999999999974834176.00000000000000000"}, |
| {below1e23, 'g', 17, "9.9999999999999975e+22"}, |
| |
| // {below1e23, 'e', -1, "9.999999999999997e+22"}, |
| // {below1e23, 'f', -1, "99999999999999970000000"}, |
| // {below1e23, 'g', -1, "9.999999999999997e+22"}, |
| |
| {above1e23, 'e', 17, "1.00000000000000008e+23"}, |
| {above1e23, 'f', 17, "100000000000000008388608.00000000000000000"}, |
| // {above1e23, 'g', 17, "1.0000000000000001e+23"}, |
| |
| // {above1e23, 'e', -1, "1.0000000000000001e+23"}, |
| // {above1e23, 'f', -1, "100000000000000010000000"}, |
| // {above1e23, 'g', -1, "1.0000000000000001e+23"}, |
| |
| // {fdiv(5e-304, 1e20), 'g', -1, "5e-324"}, |
| // {fdiv(-5e-304, 1e20), 'g', -1, "-5e-324"}, |
| |
| // {32, 'g', -1, "32"}, |
| // {32, 'g', 0, "3e+01"}, |
| |
| // {100, 'x', -1, "%x"}, |
| |
| // {math.NaN(), 'g', -1, "NaN"}, |
| // {-math.NaN(), 'g', -1, "NaN"}, |
| // {math.Inf(0), 'g', -1, "+Inf"}, |
| // {math.Inf(-1), 'g', -1, "-Inf"}, |
| // {-math.Inf(0), 'g', -1, "-Inf"}, |
| |
| {-1, 'b', -1, "-4503599627370496p-52"}, |
| |
| // fixed bugs |
| {0.9, 'f', 1, "0.9"}, |
| {0.09, 'f', 1, "0.1"}, |
| {0.0999, 'f', 1, "0.1"}, |
| {0.05, 'f', 1, "0.1"}, |
| {0.05, 'f', 0, "0"}, |
| {0.5, 'f', 1, "0.5"}, |
| {0.5, 'f', 0, "0"}, |
| {1.5, 'f', 0, "2"}, |
| |
| // http://www.exploringbinary.com/java-hangs-when-converting-2-2250738585072012e-308/ |
| // {2.2250738585072012e-308, 'g', -1, "2.2250738585072014e-308"}, |
| // http://www.exploringbinary.com/php-hangs-on-numeric-value-2-2250738585072011e-308/ |
| // {2.2250738585072011e-308, 'g', -1, "2.225073858507201e-308"}, |
| |
| // Issue 2625. |
| {383260575764816448, 'f', 0, "383260575764816448"}, |
| // {383260575764816448, 'g', -1, "3.8326057576481645e+17"}, |
| } { |
| f := new(Float).SetFloat64(test.x) |
| got := f.Format(test.format, test.prec) |
| if got != test.want { |
| t.Errorf("%v: got %s; want %s", test, got, test.want) |
| } |
| |
| if test.format == 'b' && test.x == 0 { |
| continue // 'b' format in strconv.Float requires knowledge of bias for 0.0 |
| } |
| if test.format == 'p' { |
| continue // 'p' format not supported in strconv.Format |
| } |
| |
| // verify that Float format matches strconv format |
| want := strconv.FormatFloat(test.x, test.format, test.prec, 64) |
| if got != want { |
| t.Errorf("%v: got %s; want %s (strconv)", test, got, want) |
| } |
| } |
| } |
| |
| func TestFloatFormat(t *testing.T) { |
| for _, test := range []struct { |
| x string |
| format byte |
| prec int |
| want string |
| }{ |
| {"0", 'f', 0, "0"}, |
| {"-0", 'f', 0, "-0"}, |
| {"1", 'f', 0, "1"}, |
| {"-1", 'f', 0, "-1"}, |
| |
| {"1.459", 'e', 0, "1e+00"}, |
| {"2.459", 'e', 1, "2.5e+00"}, |
| {"3.459", 'e', 2, "3.46e+00"}, |
| {"4.459", 'e', 3, "4.459e+00"}, |
| {"5.459", 'e', 4, "5.4590e+00"}, |
| |
| {"1.459", 'E', 0, "1E+00"}, |
| {"2.459", 'E', 1, "2.5E+00"}, |
| {"3.459", 'E', 2, "3.46E+00"}, |
| {"4.459", 'E', 3, "4.459E+00"}, |
| {"5.459", 'E', 4, "5.4590E+00"}, |
| |
| {"1.459", 'f', 0, "1"}, |
| {"2.459", 'f', 1, "2.5"}, |
| {"3.459", 'f', 2, "3.46"}, |
| {"4.459", 'f', 3, "4.459"}, |
| {"5.459", 'f', 4, "5.4590"}, |
| |
| {"1.459", 'g', 0, "1"}, |
| {"2.459", 'g', 1, "2"}, |
| {"3.459", 'g', 2, "3.5"}, |
| {"4.459", 'g', 3, "4.46"}, |
| {"5.459", 'g', 4, "5.459"}, |
| |
| {"1459", 'g', 0, "1e+03"}, |
| {"2459", 'g', 1, "2e+03"}, |
| {"3459", 'g', 2, "3.5e+03"}, |
| {"4459", 'g', 3, "4.46e+03"}, |
| {"5459", 'g', 4, "5459"}, |
| |
| {"1459", 'G', 0, "1E+03"}, |
| {"2459", 'G', 1, "2E+03"}, |
| {"3459", 'G', 2, "3.5E+03"}, |
| {"4459", 'G', 3, "4.46E+03"}, |
| {"5459", 'G', 4, "5459"}, |
| |
| {"3", 'e', 40, "3.0000000000000000000000000000000000000000e+00"}, |
| {"3", 'f', 40, "3.0000000000000000000000000000000000000000"}, |
| {"3", 'g', 40, "3"}, |
| |
| {"3e40", 'e', 40, "3.0000000000000000000000000000000000000000e+40"}, |
| {"3e40", 'f', 4, "30000000000000000000000000000000000000000.0000"}, |
| {"3e40", 'g', 40, "3e+40"}, |
| |
| // TODO(gri) need tests for actual large Floats |
| |
| // These depend on the selected mantissa length to match strconv.FormatFloat. |
| // Disabled for now. |
| // {"0", 'b', 0, "0"}, |
| // {"-0", 'b', 0, "-0"}, |
| // {"1.0", 'b', 0, "4503599627370496p-52"}, |
| // {"-1.0", 'b', 0, "-4503599627370496p-52"}, |
| // {"4503599627370496", 'b', 0, "4503599627370496p+0"}, |
| |
| {"0", 'p', 0, "0"}, |
| {"-0", 'p', 0, "-0"}, |
| {"1024.0", 'p', 0, "0x.8p11"}, |
| {"-1024.0", 'p', 0, "-0x.8p11"}, |
| |
| // unsupported format |
| {"3.14", 'x', 0, "%x"}, |
| } { |
| f, _, err := ParseFloat(test.x, 0, 1000, ToNearestEven) |
| // TODO(gri) should we return io.EOF at the end? |
| if err != nil && err != io.EOF { |
| t.Errorf("%v: %s", test, err) |
| continue |
| } |
| |
| got := f.Format(test.format, test.prec) |
| if got != test.want { |
| t.Errorf("%v: got %s; want %s", test, got, test.want) |
| } |
| } |
| } |