]> Cypherpunks repositories - gostls13.git/commitdiff
math/big: split float conversion routines and tests into separate files
authorRobert Griesemer <gri@golang.org>
Fri, 30 Jan 2015 22:53:53 +0000 (14:53 -0800)
committerRobert Griesemer <gri@golang.org>
Fri, 30 Jan 2015 23:03:06 +0000 (23:03 +0000)
No other functional changes.

Change-Id: I7e0bb7452c6a265535297ec7ce6a629f1aff695c
Reviewed-on: https://go-review.googlesource.com/3674
Reviewed-by: Alan Donovan <adonovan@google.com>
src/math/big/float.go
src/math/big/float_test.go
src/math/big/floatconv.go [new file with mode: 0644]
src/math/big/floatconv_test.go [new file with mode: 0644]

index 80b560f9b26a1370e85954e1ba82488f56639713..7047a6d996af7e40f48198988b59385edee615ab 100644 (file)
 package big
 
 import (
-       "bytes"
        "fmt"
-       "io"
        "math"
-       "strings"
 )
 
 // TODO(gri): Determine if there's a more natural way to set the precision.
@@ -958,245 +955,3 @@ func (x *Float) Sign() int {
        }
        return 1
 }
-
-// SetString sets z to the value of s and returns z and a boolean indicating
-// success. s must be a floating-point number of the same format as accepted
-// by Scan, with number prefixes permitted.
-func (z *Float) SetString(s string) (*Float, bool) {
-       r := strings.NewReader(s)
-
-       f, _, err := z.Scan(r, 0)
-       if err != nil {
-               return nil, false
-       }
-
-       // there should be no unread characters left
-       if _, _, err = r.ReadRune(); err != io.EOF {
-               return nil, false
-       }
-
-       return f, true
-}
-
-// Scan scans the number corresponding to the longest possible prefix
-// of r representing a floating-point number with a mantissa in the
-// given conversion base (the exponent is always a decimal number).
-// It returns the corresponding Float f, the actual base b, and an
-// error err, if any. The number must be of the form:
-//
-//     number   = [ sign ] [ prefix ] mantissa [ exponent ] .
-//     sign     = "+" | "-" .
-//      prefix   = "0" ( "x" | "X" | "b" | "B" ) .
-//     mantissa = digits | digits "." [ digits ] | "." digits .
-//     exponent = ( "E" | "e" | "p" ) [ sign ] digits .
-//     digits   = digit { digit } .
-//     digit    = "0" ... "9" | "a" ... "z" | "A" ... "Z" .
-//
-// The base argument must be 0 or a value between 2 through MaxBase.
-//
-// For base 0, the number prefix determines the actual base: A prefix of
-// ``0x'' or ``0X'' selects base 16, and a ``0b'' or ``0B'' prefix selects
-// base 2; otherwise, the actual base is 10 and no prefix is permitted.
-// The octal prefix ``0'' is not supported.
-//
-// A "p" exponent indicates power of 2 for the exponent; for instance "1.2p3"
-// with base 0 or 10 corresponds to the value 1.2 * 2**3.
-//
-// BUG(gri) This signature conflicts with Scan(s fmt.ScanState, ch rune) error.
-func (z *Float) Scan(r io.ByteScanner, base int) (f *Float, b int, err error) {
-       // sign
-       z.neg, err = scanSign(r)
-       if err != nil {
-               return
-       }
-
-       // mantissa
-       var ecorr int // decimal exponent correction; valid if <= 0
-       z.mant, b, ecorr, err = z.mant.scan(r, base, true)
-       if err != nil {
-               return
-       }
-
-       // exponent
-       var exp int64
-       var ebase int
-       exp, ebase, err = scanExponent(r)
-       if err != nil {
-               return
-       }
-       // special-case 0
-       if len(z.mant) == 0 {
-               z.exp = 0
-               f = z
-               return
-       }
-       // len(z.mant) > 0
-
-       // determine binary (exp2) and decimal (exp) exponent
-       exp2 := int64(len(z.mant)*_W - int(fnorm(z.mant)))
-       if ebase == 2 {
-               exp2 += exp
-               exp = 0
-       }
-       if ecorr < 0 {
-               exp += int64(ecorr)
-       }
-
-       z.setExp(exp2)
-       if exp == 0 {
-               // no decimal exponent
-               z.round(0)
-               f = z
-               return
-       }
-       // exp != 0
-
-       // compute decimal exponent power
-       expabs := exp
-       if expabs < 0 {
-               expabs = -expabs
-       }
-       powTen := new(Float).SetInt(new(Int).SetBits(nat(nil).expNN(natTen, nat(nil).setWord(Word(expabs)), nil)))
-
-       // correct result
-       if exp < 0 {
-               z.uquo(z, powTen)
-       } else {
-               z.umul(z, powTen)
-       }
-
-       f = z
-       return
-}
-
-// Parse is like z.Scan(r, base), but instead of reading from an
-// io.ByteScanner, it parses the string s. An error is returned if the
-// string contains invalid or trailing characters not belonging to the
-// number.
-//
-// TODO(gri) define possible errors more precisely
-func (z *Float) Parse(s string, base int) (f *Float, b int, err error) {
-       r := strings.NewReader(s)
-
-       if f, b, err = z.Scan(r, base); err != nil {
-               return
-       }
-
-       // entire string must have been consumed
-       var ch byte
-       if ch, err = r.ReadByte(); err != io.EOF {
-               if err == nil {
-                       err = fmt.Errorf("expected end of string, found %q", ch)
-               }
-       }
-
-       return
-}
-
-// ScanFloat is like f.Scan(r, base) with f set to the given precision
-// and rounding mode.
-func ScanFloat(r io.ByteScanner, base int, prec uint, mode RoundingMode) (f *Float, b int, err error) {
-       return NewFloat(0, prec, mode).Scan(r, base)
-}
-
-// ParseFloat is like f.Parse(s, base) with f set to the given precision
-// and rounding mode.
-func ParseFloat(s string, base int, prec uint, mode RoundingMode) (f *Float, b int, err error) {
-       return NewFloat(0, prec, mode).Parse(s, base)
-}
-
-// Format converts the floating-point number x to a string according
-// to the given format and precision prec. The format is one of:
-//
-//     'e'     -d.dddde±dd, decimal exponent
-//     'E'     -d.ddddE±dd, decimal exponent
-//     'f'     -ddddd.dddd, no exponent
-//     'g'     like 'e' for large exponents, like 'f' otherwise
-//     'G'     like 'E' for large exponents, like 'f' otherwise
-//     'b'     -ddddddp±dd, binary exponent
-//     'p'     -0x.dddp±dd, binary exponent, hexadecimal mantissa
-//
-// For the binary exponent formats, the mantissa is printed in normalized form:
-//
-//     'b'     decimal integer mantissa using x.Precision() bits, or -0
-//     'p'     hexadecimal fraction with 0.5 <= 0.mantissa < 1.0, or -0
-//
-// 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. A negative precision selects the smallest
-// number of digits necessary such that ParseFloat will return f exactly.
-// The prec value is ignored for the 'b' or 'p' format.
-//
-// BUG(gri) Currently, Format only accepts the 'b' and 'p' format.
-func (x *Float) Format(format byte, prec int) string {
-       switch format {
-       case 'b':
-               return x.bstring()
-       case 'p':
-               return x.pstring()
-       }
-       return fmt.Sprintf(`%%!c(%s)`, format, x.pstring())
-}
-
-// BUG(gri): Currently, String uses the 'p' (rather than 'g') format.
-func (x *Float) String() string {
-       return x.Format('p', 0)
-}
-
-// TODO(gri) The 'b' and 'p' formats have different meanings here than
-// in strconv: in strconv, the printed exponent is the biased (hardware)
-// exponent; here it is the unbiased exponent. Decide what to do.
-// (a strconv 'p' formatted float value can only be interpreted correctly
-// if the bias is known; i.e., we must know if it's a 32bit or 64bit number).
-
-// bstring returns x as a string in the format ["-"] mantissa "p" exponent
-// with a decimal mantissa and a binary exponent, or ["-"] "0" if x is zero.
-// The mantissa is normalized such that is uses x.Precision() bits in binary
-// representation.
-func (x *Float) bstring() string {
-       // TODO(gri) handle Inf
-       if len(x.mant) == 0 {
-               if x.neg {
-                       return "-0"
-               }
-               return "0"
-       }
-       // x != 0
-       // normalize mantissa
-       m := x.mant
-       t := uint(len(x.mant)*_W) - x.prec // 0 <= t < _W
-       if t > 0 {
-               m = nat(nil).shr(m, t)
-       }
-       var buf bytes.Buffer
-       if x.neg {
-               buf.WriteByte('-')
-       }
-       buf.WriteString(m.decimalString())
-       fmt.Fprintf(&buf, "p%d", x.exp)
-       return buf.String()
-}
-
-// pstring returns x as a string in the format ["-"] "0x." mantissa "p" exponent
-// with a hexadecimal mantissa and a binary exponent, or ["-"] "0" if x is zero.
-// The mantissa is normalized such that 0.5 <= 0.mantissa < 1.0.
-func (x *Float) pstring() string {
-       // TODO(gri) handle Inf
-       if len(x.mant) == 0 {
-               if x.neg {
-                       return "-0"
-               }
-               return "0"
-       }
-       // x != 0
-       // mantissa is stored in normalized form
-       var buf bytes.Buffer
-       if x.neg {
-               buf.WriteByte('-')
-       }
-       buf.WriteString("0x.")
-       buf.WriteString(strings.TrimRight(x.mant.hexString(), "0"))
-       fmt.Fprintf(&buf, "p%d", x.exp)
-       return buf.String()
-}
index 940cb6d353eb7d785c5ea6e055af6afd45cb4496..3281f2745aadbd4ac4bb46464e24b63501406447 100644 (file)
@@ -682,104 +682,3 @@ func TestFromBits(t *testing.T) {
                }
        }
 }
-
-var floatSetFloat64StringTests = []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},
-}
-
-func TestFloatSetFloat64String(t *testing.T) {
-       for _, test := range floatSetFloat64StringTests {
-               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)
-               }
-       }
-}
-
-func TestFloatFormat(t *testing.T) {
-       for _, test := range []struct {
-               x      string
-               format byte
-               prec   int
-               want   string
-       }{
-               {"0", 'b', 0, "0"},
-               {"-0", 'b', 0, "-0"},
-               {"1.0", 'b', 0, "4503599627370496p1"},
-               {"-1.0", 'b', 0, "-4503599627370496p1"},
-
-               {"0", 'p', 0, "0"},
-               {"-0", 'p', 0, "-0"},
-               {"1024.0", 'p', 0, "0x.8p11"},
-               {"-1024.0", 'p', 0, "-0x.8p11"},
-       } {
-               f64, err := strconv.ParseFloat(test.x, 64)
-               if err != nil {
-                       t.Error(err)
-                       continue
-               }
-               f := new(Float).SetFloat64(f64)
-               got := f.Format(test.format, test.prec)
-               if got != test.want {
-                       t.Errorf("%v: got %s", test, got)
-               }
-               if test.format == 'b' || test.format == 'p' {
-                       continue // 'b', 'p' format not supported or different in strconv.Format
-               }
-               want := strconv.FormatFloat(f64, test.format, test.prec, 64)
-               if got != want {
-                       t.Errorf("%v: got %s; want %s", test, got, want)
-               }
-       }
-}
diff --git a/src/math/big/floatconv.go b/src/math/big/floatconv.go
new file mode 100644 (file)
index 0000000..06bbdbc
--- /dev/null
@@ -0,0 +1,256 @@
+// 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.
+
+// This file implements float-to-string conversion functions.
+
+package big
+
+import (
+       "bytes"
+       "fmt"
+       "io"
+       "strings"
+)
+
+// SetString sets z to the value of s and returns z and a boolean indicating
+// success. s must be a floating-point number of the same format as accepted
+// by Scan, with number prefixes permitted.
+func (z *Float) SetString(s string) (*Float, bool) {
+       r := strings.NewReader(s)
+
+       f, _, err := z.Scan(r, 0)
+       if err != nil {
+               return nil, false
+       }
+
+       // there should be no unread characters left
+       if _, _, err = r.ReadRune(); err != io.EOF {
+               return nil, false
+       }
+
+       return f, true
+}
+
+// Scan scans the number corresponding to the longest possible prefix
+// of r representing a floating-point number with a mantissa in the
+// given conversion base (the exponent is always a decimal number).
+// It returns the corresponding Float f, the actual base b, and an
+// error err, if any. The number must be of the form:
+//
+//     number   = [ sign ] [ prefix ] mantissa [ exponent ] .
+//     sign     = "+" | "-" .
+//      prefix   = "0" ( "x" | "X" | "b" | "B" ) .
+//     mantissa = digits | digits "." [ digits ] | "." digits .
+//     exponent = ( "E" | "e" | "p" ) [ sign ] digits .
+//     digits   = digit { digit } .
+//     digit    = "0" ... "9" | "a" ... "z" | "A" ... "Z" .
+//
+// The base argument must be 0 or a value between 2 through MaxBase.
+//
+// For base 0, the number prefix determines the actual base: A prefix of
+// ``0x'' or ``0X'' selects base 16, and a ``0b'' or ``0B'' prefix selects
+// base 2; otherwise, the actual base is 10 and no prefix is permitted.
+// The octal prefix ``0'' is not supported.
+//
+// A "p" exponent indicates power of 2 for the exponent; for instance "1.2p3"
+// with base 0 or 10 corresponds to the value 1.2 * 2**3.
+//
+// BUG(gri) This signature conflicts with Scan(s fmt.ScanState, ch rune) error.
+func (z *Float) Scan(r io.ByteScanner, base int) (f *Float, b int, err error) {
+       // sign
+       z.neg, err = scanSign(r)
+       if err != nil {
+               return
+       }
+
+       // mantissa
+       var ecorr int // decimal exponent correction; valid if <= 0
+       z.mant, b, ecorr, err = z.mant.scan(r, base, true)
+       if err != nil {
+               return
+       }
+
+       // exponent
+       var exp int64
+       var ebase int
+       exp, ebase, err = scanExponent(r)
+       if err != nil {
+               return
+       }
+       // special-case 0
+       if len(z.mant) == 0 {
+               z.exp = 0
+               f = z
+               return
+       }
+       // len(z.mant) > 0
+
+       // determine binary (exp2) and decimal (exp) exponent
+       exp2 := int64(len(z.mant)*_W - int(fnorm(z.mant)))
+       if ebase == 2 {
+               exp2 += exp
+               exp = 0
+       }
+       if ecorr < 0 {
+               exp += int64(ecorr)
+       }
+
+       z.setExp(exp2)
+       if exp == 0 {
+               // no decimal exponent
+               z.round(0)
+               f = z
+               return
+       }
+       // exp != 0
+
+       // compute decimal exponent power
+       expabs := exp
+       if expabs < 0 {
+               expabs = -expabs
+       }
+       powTen := new(Float).SetInt(new(Int).SetBits(nat(nil).expNN(natTen, nat(nil).setWord(Word(expabs)), nil)))
+
+       // correct result
+       if exp < 0 {
+               z.uquo(z, powTen)
+       } else {
+               z.umul(z, powTen)
+       }
+
+       f = z
+       return
+}
+
+// Parse is like z.Scan(r, base), but instead of reading from an
+// io.ByteScanner, it parses the string s. An error is returned if the
+// string contains invalid or trailing characters not belonging to the
+// number.
+//
+// TODO(gri) define possible errors more precisely
+func (z *Float) Parse(s string, base int) (f *Float, b int, err error) {
+       r := strings.NewReader(s)
+
+       if f, b, err = z.Scan(r, base); err != nil {
+               return
+       }
+
+       // entire string must have been consumed
+       var ch byte
+       if ch, err = r.ReadByte(); err != io.EOF {
+               if err == nil {
+                       err = fmt.Errorf("expected end of string, found %q", ch)
+               }
+       }
+
+       return
+}
+
+// ScanFloat is like f.Scan(r, base) with f set to the given precision
+// and rounding mode.
+func ScanFloat(r io.ByteScanner, base int, prec uint, mode RoundingMode) (f *Float, b int, err error) {
+       return NewFloat(0, prec, mode).Scan(r, base)
+}
+
+// ParseFloat is like f.Parse(s, base) with f set to the given precision
+// and rounding mode.
+func ParseFloat(s string, base int, prec uint, mode RoundingMode) (f *Float, b int, err error) {
+       return NewFloat(0, prec, mode).Parse(s, base)
+}
+
+// Format converts the floating-point number x to a string according
+// to the given format and precision prec. The format is one of:
+//
+//     'e'     -d.dddde±dd, decimal exponent
+//     'E'     -d.ddddE±dd, decimal exponent
+//     'f'     -ddddd.dddd, no exponent
+//     'g'     like 'e' for large exponents, like 'f' otherwise
+//     'G'     like 'E' for large exponents, like 'f' otherwise
+//     'b'     -ddddddp±dd, binary exponent
+//     'p'     -0x.dddp±dd, binary exponent, hexadecimal mantissa
+//
+// For the binary exponent formats, the mantissa is printed in normalized form:
+//
+//     'b'     decimal integer mantissa using x.Precision() bits, or -0
+//     'p'     hexadecimal fraction with 0.5 <= 0.mantissa < 1.0, or -0
+//
+// 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. A negative precision selects the smallest
+// number of digits necessary such that ParseFloat will return f exactly.
+// The prec value is ignored for the 'b' or 'p' format.
+//
+// BUG(gri) Currently, Format only accepts the 'b' and 'p' format.
+func (x *Float) Format(format byte, prec int) string {
+       switch format {
+       case 'b':
+               return x.bstring()
+       case 'p':
+               return x.pstring()
+       }
+       return fmt.Sprintf(`%%!c(%s)`, format, x.pstring())
+}
+
+// BUG(gri): Currently, String uses the 'p' (rather than 'g') format.
+func (x *Float) String() string {
+       return x.Format('p', 0)
+}
+
+// TODO(gri) The 'b' and 'p' formats have different meanings here than
+// in strconv: in strconv, the printed exponent is the biased (hardware)
+// exponent; here it is the unbiased exponent. Decide what to do.
+// (a strconv 'p' formatted float value can only be interpreted correctly
+// if the bias is known; i.e., we must know if it's a 32bit or 64bit number).
+
+// bstring returns x as a string in the format ["-"] mantissa "p" exponent
+// with a decimal mantissa and a binary exponent, or ["-"] "0" if x is zero.
+// The mantissa is normalized such that is uses x.Precision() bits in binary
+// representation.
+func (x *Float) bstring() string {
+       // TODO(gri) handle Inf
+       if len(x.mant) == 0 {
+               if x.neg {
+                       return "-0"
+               }
+               return "0"
+       }
+       // x != 0
+       // normalize mantissa
+       m := x.mant
+       t := uint(len(x.mant)*_W) - x.prec // 0 <= t < _W
+       if t > 0 {
+               m = nat(nil).shr(m, t)
+       }
+       var buf bytes.Buffer
+       if x.neg {
+               buf.WriteByte('-')
+       }
+       buf.WriteString(m.decimalString())
+       fmt.Fprintf(&buf, "p%d", x.exp)
+       return buf.String()
+}
+
+// pstring returns x as a string in the format ["-"] "0x." mantissa "p" exponent
+// with a hexadecimal mantissa and a binary exponent, or ["-"] "0" if x is zero.
+// The mantissa is normalized such that 0.5 <= 0.mantissa < 1.0.
+func (x *Float) pstring() string {
+       // TODO(gri) handle Inf
+       if len(x.mant) == 0 {
+               if x.neg {
+                       return "-0"
+               }
+               return "0"
+       }
+       // x != 0
+       // mantissa is stored in normalized form
+       var buf bytes.Buffer
+       if x.neg {
+               buf.WriteByte('-')
+       }
+       buf.WriteString("0x.")
+       buf.WriteString(strings.TrimRight(x.mant.hexString(), "0"))
+       fmt.Fprintf(&buf, "p%d", x.exp)
+       return buf.String()
+}
diff --git a/src/math/big/floatconv_test.go b/src/math/big/floatconv_test.go
new file mode 100644 (file)
index 0000000..83ea1d6
--- /dev/null
@@ -0,0 +1,111 @@
+// 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 (
+       "strconv"
+       "testing"
+)
+
+var floatSetFloat64StringTests = []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},
+}
+
+func TestFloatSetFloat64String(t *testing.T) {
+       for _, test := range floatSetFloat64StringTests {
+               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)
+               }
+       }
+}
+
+func TestFloatFormat(t *testing.T) {
+       for _, test := range []struct {
+               x      string
+               format byte
+               prec   int
+               want   string
+       }{
+               {"0", 'b', 0, "0"},
+               {"-0", 'b', 0, "-0"},
+               {"1.0", 'b', 0, "4503599627370496p1"},
+               {"-1.0", 'b', 0, "-4503599627370496p1"},
+
+               {"0", 'p', 0, "0"},
+               {"-0", 'p', 0, "-0"},
+               {"1024.0", 'p', 0, "0x.8p11"},
+               {"-1024.0", 'p', 0, "-0x.8p11"},
+       } {
+               f64, err := strconv.ParseFloat(test.x, 64)
+               if err != nil {
+                       t.Error(err)
+                       continue
+               }
+               f := new(Float).SetFloat64(f64)
+               got := f.Format(test.format, test.prec)
+               if got != test.want {
+                       t.Errorf("%v: got %s", test, got)
+               }
+               if test.format == 'b' || test.format == 'p' {
+                       continue // 'b', 'p' format not supported or different in strconv.Format
+               }
+               want := strconv.FormatFloat(f64, test.format, test.prec, 64)
+               if got != want {
+                       t.Errorf("%v: got %s; want %s", test, got, want)
+               }
+       }
+}