math/big: first version of Float %e, %f, %g, %G formatting working

Change-Id: I10efa3bc8bc7f41100feabe17837f805a42d7eb6
Reviewed-on: https://go-review.googlesource.com/3842
Reviewed-by: Alan Donovan <adonovan@google.com>
diff --git a/src/math/big/floatconv_test.go b/src/math/big/floatconv_test.go
index 0e8bfb3..27ac6c8 100644
--- a/src/math/big/floatconv_test.go
+++ b/src/math/big/floatconv_test.go
@@ -5,6 +5,7 @@
 package big
 
 import (
+	"math"
 	"strconv"
 	"testing"
 )
@@ -71,37 +72,157 @@
 	}
 }
 
-func TestFloatFormat(t *testing.T) {
+const (
+	below1e23 = 99999999999999974834176
+	above1e23 = 100000000000000008388608
+)
+
+func TestFloat64Format(t *testing.T) {
 	for _, test := range []struct {
-		x      string
+		x      float64
 		format byte
 		prec   int
 		want   string
 	}{
-		{"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, 'f', 0, "0"},
+		{math.Copysign(0, -1), 'f', 0, "-0"},
+		{1, 'f', 0, "1"},
+		{-1, 'f', 0, "-1"},
 
-		{"0", 'p', 0, "0"},
-		{"-0", 'p', 0, "-0"},
-		{"1024.0", 'p', 0, "0x.8p11"},
-		{"-1024.0", 'p', 0, "-0x.8p11"},
+		{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"},
 	} {
-		f64, err := strconv.ParseFloat(test.x, 64)
-		if err != nil {
-			t.Error(err)
-			continue
-		}
-
-		f := new(Float).SetFloat64(f64)
+		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' && f64 == 0 {
+		if test.format == 'b' && test.x == 0 {
 			continue // 'b' format in strconv.Float requires knowledge of bias for 0.0
 		}
 		if test.format == 'p' {
@@ -109,9 +230,9 @@
 		}
 
 		// verify that Float format matches strconv format
-		want := strconv.FormatFloat(f64, test.format, test.prec, 64)
+		want := strconv.FormatFloat(test.x, test.format, test.prec, 64)
 		if got != want {
-			t.Errorf("%v: got %s; want %s", test, got, want)
+			t.Errorf("%v: got %s; want %s (strconv)", test, got, want)
 		}
 	}
 }