diff options
| author | Robert Griesemer <gri@golang.org> | 2014-12-08 14:36:39 -0800 |
|---|---|---|
| committer | Robert Griesemer <gri@golang.org> | 2015-01-24 05:17:27 +0000 |
| commit | bd275b238179cdaca2c01a0bf1ac60a16fbf5a98 (patch) | |
| tree | a3bbf32c663aa010156f9b05b1be23f5ee48b273 /src/math/big/float_test.go | |
| parent | 571d02d9fef357ffb7ffe341d30164123f686efb (diff) | |
| download | go-bd275b238179cdaca2c01a0bf1ac60a16fbf5a98.tar.xz | |
math/big: multi-precision Floats (starting point)
Implemented:
- +, -, *, /, and some unary ops
- all rounding modes
- basic conversions
- string to float conversion
- tests
Missing:
- float to string conversion, formatting
- handling of +/-0 and +/-inf (under- and overflow)
- various TODOs and cleanups
With precision set to 24 or 53, the results match
float32 or float64 operations exactly (excluding
NaNs and denormalized numbers which will not be
supported).
Change-Id: I3121e90fc4b1528e40bb6ff526008da18b3c6520
Reviewed-on: https://go-review.googlesource.com/1218
Reviewed-by: Alan Donovan <adonovan@google.com>
Diffstat (limited to 'src/math/big/float_test.go')
| -rw-r--r-- | src/math/big/float_test.go | 772 |
1 files changed, 772 insertions, 0 deletions
diff --git a/src/math/big/float_test.go b/src/math/big/float_test.go new file mode 100644 index 0000000000..20c7d899a8 --- /dev/null +++ b/src/math/big/float_test.go @@ -0,0 +1,772 @@ +// Copyright 2014 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 ( + "fmt" + "sort" + "strconv" + "testing" +) + +func fromBinary(s string) int64 { + x, err := strconv.ParseInt(s, 2, 64) + if err != nil { + panic(err) + } + return x +} + +func toBinary(x int64) string { + return strconv.FormatInt(x, 2) +} + +func testFloatRound(t *testing.T, x, r int64, prec uint, mode RoundingMode) { + // verify test data + var ok bool + switch mode { + case ToNearestEven, ToNearestAway: + ok = true // nothing to do for now + case ToZero: + if x < 0 { + ok = r >= x + } else { + ok = r <= x + } + case AwayFromZero: + if x < 0 { + ok = r <= x + } else { + ok = r >= x + } + case ToNegativeInf: + ok = r <= x + case ToPositiveInf: + ok = r >= x + default: + panic("unreachable") + } + if !ok { + t.Fatalf("incorrect test data for prec = %d, %s: x = %s, r = %s", prec, mode, toBinary(x), toBinary(r)) + } + + // compute expected accuracy + a := Exact + switch { + case r < x: + a = Below + case r > x: + a = Above + } + + // round + f := new(Float).SetInt64(x) + f.Round(f, prec, mode) + + // check result + r1 := f.Int64() + p1 := f.Precision() + a1 := f.Accuracy() + if r1 != r || p1 != prec || a1 != a { + t.Errorf("Round(%s, %d, %s): got %s (%d bits, %s); want %s (%d bits, %s)", + toBinary(x), prec, mode, + toBinary(r1), p1, a1, + toBinary(r), prec, a) + } +} + +// TestFloatRound tests basic rounding. +func TestFloatRound(t *testing.T) { + var tests = []struct { + prec uint + x, zero, neven, naway, away string // input, results rounded to prec bits + }{ + {5, "1000", "1000", "1000", "1000", "1000"}, + {5, "1001", "1001", "1001", "1001", "1001"}, + {5, "1010", "1010", "1010", "1010", "1010"}, + {5, "1011", "1011", "1011", "1011", "1011"}, + {5, "1100", "1100", "1100", "1100", "1100"}, + {5, "1101", "1101", "1101", "1101", "1101"}, + {5, "1110", "1110", "1110", "1110", "1110"}, + {5, "1111", "1111", "1111", "1111", "1111"}, + + {4, "1000", "1000", "1000", "1000", "1000"}, + {4, "1001", "1001", "1001", "1001", "1001"}, + {4, "1010", "1010", "1010", "1010", "1010"}, + {4, "1011", "1011", "1011", "1011", "1011"}, + {4, "1100", "1100", "1100", "1100", "1100"}, + {4, "1101", "1101", "1101", "1101", "1101"}, + {4, "1110", "1110", "1110", "1110", "1110"}, + {4, "1111", "1111", "1111", "1111", "1111"}, + + {3, "1000", "1000", "1000", "1000", "1000"}, + {3, "1001", "1000", "1000", "1010", "1010"}, + {3, "1010", "1010", "1010", "1010", "1010"}, + {3, "1011", "1010", "1100", "1100", "1100"}, + {3, "1100", "1100", "1100", "1100", "1100"}, + {3, "1101", "1100", "1100", "1110", "1110"}, + {3, "1110", "1110", "1110", "1110", "1110"}, + {3, "1111", "1110", "10000", "10000", "10000"}, + + {3, "1000001", "1000000", "1000000", "1000000", "1010000"}, + {3, "1001001", "1000000", "1010000", "1010000", "1010000"}, + {3, "1010001", "1010000", "1010000", "1010000", "1100000"}, + {3, "1011001", "1010000", "1100000", "1100000", "1100000"}, + {3, "1100001", "1100000", "1100000", "1100000", "1110000"}, + {3, "1101001", "1100000", "1110000", "1110000", "1110000"}, + {3, "1110001", "1110000", "1110000", "1110000", "10000000"}, + {3, "1111001", "1110000", "10000000", "10000000", "10000000"}, + + {2, "1000", "1000", "1000", "1000", "1000"}, + {2, "1001", "1000", "1000", "1000", "1100"}, + {2, "1010", "1000", "1000", "1100", "1100"}, + {2, "1011", "1000", "1100", "1100", "1100"}, + {2, "1100", "1100", "1100", "1100", "1100"}, + {2, "1101", "1100", "1100", "1100", "10000"}, + {2, "1110", "1100", "10000", "10000", "10000"}, + {2, "1111", "1100", "10000", "10000", "10000"}, + + {2, "1000001", "1000000", "1000000", "1000000", "1100000"}, + {2, "1001001", "1000000", "1000000", "1000000", "1100000"}, + {2, "1010001", "1000000", "1100000", "1100000", "1100000"}, + {2, "1011001", "1000000", "1100000", "1100000", "1100000"}, + {2, "1100001", "1100000", "1100000", "1100000", "10000000"}, + {2, "1101001", "1100000", "1100000", "1100000", "10000000"}, + {2, "1110001", "1100000", "10000000", "10000000", "10000000"}, + {2, "1111001", "1100000", "10000000", "10000000", "10000000"}, + + {1, "1000", "1000", "1000", "1000", "1000"}, + {1, "1001", "1000", "1000", "1000", "10000"}, + {1, "1010", "1000", "1000", "1000", "10000"}, + {1, "1011", "1000", "1000", "1000", "10000"}, + {1, "1100", "1000", "10000", "10000", "10000"}, + {1, "1101", "1000", "10000", "10000", "10000"}, + {1, "1110", "1000", "10000", "10000", "10000"}, + {1, "1111", "1000", "10000", "10000", "10000"}, + + {1, "1000001", "1000000", "1000000", "1000000", "10000000"}, + {1, "1001001", "1000000", "1000000", "1000000", "10000000"}, + {1, "1010001", "1000000", "1000000", "1000000", "10000000"}, + {1, "1011001", "1000000", "1000000", "1000000", "10000000"}, + {1, "1100001", "1000000", "10000000", "10000000", "10000000"}, + {1, "1101001", "1000000", "10000000", "10000000", "10000000"}, + {1, "1110001", "1000000", "10000000", "10000000", "10000000"}, + {1, "1111001", "1000000", "10000000", "10000000", "10000000"}, + } + + for _, test := range tests { + x := fromBinary(test.x) + z := fromBinary(test.zero) + e := fromBinary(test.neven) + n := fromBinary(test.naway) + a := fromBinary(test.away) + prec := test.prec + + testFloatRound(t, x, z, prec, ToZero) + testFloatRound(t, x, e, prec, ToNearestEven) + testFloatRound(t, x, n, prec, ToNearestAway) + testFloatRound(t, x, a, prec, AwayFromZero) + + testFloatRound(t, x, z, prec, ToNegativeInf) + testFloatRound(t, x, a, prec, ToPositiveInf) + + testFloatRound(t, -x, -a, prec, ToNegativeInf) + testFloatRound(t, -x, -z, prec, ToPositiveInf) + } +} + +// TestFloatRound24 tests that rounding a float64 to 24 bits +// matches IEEE-754 rounding to nearest when converting a +// float64 to a float32. +func TestFloatRound24(t *testing.T) { + const x0 = 1<<26 - 0x10 // 11...110000 (26 bits) + for d := 0; d <= 0x10; d++ { + x := float64(x0 + d) + f := new(Float).SetFloat64(x) + f.Round(f, 24, ToNearestEven) + got, _ := f.Float64() + want := float64(float32(x)) + if got != want { + t.Errorf("Round(%g, 24) = %g; want %g", x, got, want) + } + } +} + +func TestFloatSetUint64(t *testing.T) { + var tests = []uint64{ + 0, + 1, + 2, + 10, + 100, + 1<<32 - 1, + 1 << 32, + 1<<64 - 1, + } + for _, want := range tests { + f := new(Float).SetUint64(want) + if got := f.Uint64(); got != want { + t.Errorf("got %d (%s); want %d", got, f.PString(), want) + } + } +} + +func TestFloatSetInt64(t *testing.T) { + var tests = []int64{ + 0, + 1, + 2, + 10, + 100, + 1<<32 - 1, + 1 << 32, + 1<<63 - 1, + } + for _, want := range tests { + for i := range [2]int{} { + if i&1 != 0 { + want = -want + } + f := new(Float).SetInt64(want) + if got := f.Int64(); got != want { + t.Errorf("got %d (%s); want %d", got, f.PString(), want) + } + } + } +} + +func TestFloatSetFloat64(t *testing.T) { + var tests = []float64{ + 0, + 1, + 2, + 12345, + 1e10, + 1e100, + 3.14159265e10, + 2.718281828e-123, + 1.0 / 3, + } + for _, want := range tests { + for i := range [2]int{} { + if i&1 != 0 { + want = -want + } + f := new(Float).SetFloat64(want) + if got, _ := f.Float64(); got != want { + t.Errorf("got %g (%s); want %g", got, f.PString(), want) + } + } + } +} + +func TestFloatSetInt(t *testing.T) { + // TODO(gri) implement +} + +// Selected precisions with which to run various tests. +var precList = [...]uint{1, 2, 5, 8, 10, 16, 23, 24, 32, 50, 53, 64, 100, 128, 500, 511, 512, 513, 1000, 10000} + +// Selected bits with which to run various tests. +// Each entry is a list of bits representing a floating-point number (see fromBits). +var bitsList = [...][]int{ + {}, // = 0 + {0}, // = 1 + {1}, // = 2 + {-1}, // = 1/2 + {10}, // = 2**10 == 1024 + {-10}, // = 2**-10 == 1/1024 + {100, 10, 1}, // = 2**100 + 2**10 + 2**1 + {0, -1, -2, -10}, + // TODO(gri) add more test cases +} + +// TestFloatAdd tests Float.Add/Sub by comparing the result of a "manual" +// addition/subtraction of arguments represented by bits lists with the +// respective floating-point addition/subtraction for a variety of precisions +// and rounding modes. +func TestFloatAdd(t *testing.T) { + for _, xbits := range bitsList { + for _, ybits := range bitsList { + // exact values + x := fromBits(xbits...) + y := fromBits(ybits...) + zbits := append(xbits, ybits...) + z := fromBits(zbits...) + + for i, mode := range [...]RoundingMode{ToZero, ToNearestEven, AwayFromZero} { + for _, prec := range precList { + // + + got := NewFloat(0, prec, mode) + got.Add(x, y) + want := roundBits(zbits, prec, mode) + if got.Cmp(want) != 0 { + t.Errorf("i = %d, prec = %d, %s:\n\t %s %v\n\t+ %s %v\n\t= %s\n\twant %s", + i, prec, mode, x, xbits, y, ybits, got, want) + return + } + + // - + got.Sub(z, x) + want = roundBits(ybits, prec, mode) + if got.Cmp(want) != 0 { + t.Errorf("i = %d, prec = %d, %s:\n\t %s\n\t- %s\n\t= %s\n\twant %s", + i, prec, mode, x, y, got, want) + } + } + } + } + } +} + +// TestFloatAdd32 tests that Float.Add/Sub of numbers with +// 24bit mantissa behaves like float32 addition/subtraction. +func TestFloatAdd32(t *testing.T) { + // chose base such that we cross the mantissa precision limit + const base = 1<<26 - 0x10 // 11...110000 (26 bits) + for d := 0; d <= 0x10; d++ { + for i := range [2]int{} { + x0, y0 := float64(base), float64(d) + if i&1 != 0 { + x0, y0 = y0, x0 + } + + x := new(Float).SetFloat64(x0) + y := new(Float).SetFloat64(y0) + z := NewFloat(0, 24, ToNearestEven) + + z.Add(x, y) + got, acc := z.Float64() + want := float64(float32(y0) + float32(x0)) + if got != want || acc != Exact { + t.Errorf("d = %d: %g + %g = %g (%s); want %g exactly", d, x0, y0, got, acc, want) + } + + z.Sub(z, y) + got, acc = z.Float64() + want = float64(float32(want) - float32(y0)) + if got != want || acc != Exact { + t.Errorf("d = %d: %g - %g = %g (%s); want %g exactly", d, x0+y0, y0, got, acc, want) + } + } + } +} + +// TestFloatAdd64 tests that Float.Add/Sub of numbers with +// 53bit mantissa behaves like float64 addition/subtraction. +func TestFloatAdd64(t *testing.T) { + // chose base such that we cross the mantissa precision limit + const base = 1<<55 - 0x10 // 11...110000 (55 bits) + for d := 0; d <= 0x10; d++ { + for i := range [2]int{} { + x0, y0 := float64(base), float64(d) + if i&1 != 0 { + x0, y0 = y0, x0 + } + + x := new(Float).SetFloat64(x0) + y := new(Float).SetFloat64(y0) + z := NewFloat(0, 53, ToNearestEven) + + z.Add(x, y) + got, acc := z.Float64() + want := x0 + y0 + if got != want || acc != Exact { + t.Errorf("d = %d: %g + %g = %g; want %g exactly", d, x0, y0, got, acc, want) + } + + z.Sub(z, y) + got, acc = z.Float64() + want -= y0 + if got != want || acc != Exact { + t.Errorf("d = %d: %g - %g = %g; want %g exactly", d, x0+y0, y0, got, acc, want) + } + } + } +} + +func TestFloatMul(t *testing.T) { +} + +// TestFloatMul64 tests that Float.Mul/Quo of numbers with +// 53bit mantissa behaves like float64 multiplication/division. +func TestFloatMul64(t *testing.T) { + var tests = []struct { + x, y float64 + }{ + {0, 0}, + {0, 1}, + {1, 1}, + {1, 1.5}, + {1.234, 0.5678}, + {2.718281828, 3.14159265358979}, + {2.718281828e10, 3.14159265358979e-32}, + {1.0 / 3, 1e200}, + } + for _, test := range tests { + for i := range [8]int{} { + x0, y0 := test.x, test.y + if i&1 != 0 { + x0 = -x0 + } + if i&2 != 0 { + y0 = -y0 + } + if i&4 != 0 { + x0, y0 = y0, x0 + } + + x := new(Float).SetFloat64(x0) + y := new(Float).SetFloat64(y0) + z := NewFloat(0, 53, ToNearestEven) + + z.Mul(x, y) + got, _ := z.Float64() + want := x0 * y0 + if got != want { + t.Errorf("%g * %g = %g; want %g", x0, y0, got, want) + } + + if y0 == 0 { + continue // avoid division-by-zero + } + z.Quo(z, y) + got, _ = z.Float64() + want /= y0 + if got != want { + t.Errorf("%g / %g = %g; want %g", x0*y0, y0, got, want) + } + } + } +} + +func TestIssue6866(t *testing.T) { + for _, prec := range precList { + two := NewFloat(2, prec, ToNearestEven) + one := NewFloat(1, prec, ToNearestEven) + three := NewFloat(3, prec, ToNearestEven) + msix := NewFloat(-6, prec, ToNearestEven) + psix := NewFloat(+6, prec, ToNearestEven) + + p := NewFloat(0, prec, ToNearestEven) + z1 := NewFloat(0, prec, ToNearestEven) + z2 := NewFloat(0, prec, ToNearestEven) + + // z1 = 2 + 1.0/3*-6 + p.Quo(one, three) + p.Mul(p, msix) + z1.Add(two, p) + + // z2 = 2 - 1.0/3*+6 + p.Quo(one, three) + p.Mul(p, psix) + z2.Sub(two, p) + + if z1.Cmp(z2) != 0 { + t.Fatalf("prec %d: got z1 = %s != z2 = %s; want z1 == z2\n", prec, z1, z2) + } + if z1.Sign() != 0 { + t.Errorf("prec %d: got z1 = %s; want 0", prec, z1) + } + if z2.Sign() != 0 { + t.Errorf("prec %d: got z2 = %s; want 0", prec, z2) + } + } +} + +func TestFloatQuo(t *testing.T) { + // TODO(gri) make the test vary these precisions + preci := 200 // precision of integer part + precf := 20 // precision of fractional part + + for i := 0; i < 8; i++ { + // compute accurate (not rounded) result z + bits := []int{preci - 1} + if i&3 != 0 { + bits = append(bits, 0) + } + if i&2 != 0 { + bits = append(bits, -1) + } + if i&1 != 0 { + bits = append(bits, -precf) + } + z := fromBits(bits...) + + // compute accurate x as z*y + y := new(Float).SetFloat64(3.14159265358979323e123) + + x := NewFloat(0, z.Precision()+y.Precision(), ToZero) + x.Mul(z, y) + + // leave for debugging + // fmt.Printf("x = %s\ny = %s\nz = %s\n", x, y, z) + + if got := x.Accuracy(); got != Exact { + t.Errorf("got acc = %s; want exact", got) + } + + // round accurate z for a variety of precisions and + // modes and compare against result of x / y. + for _, mode := range [...]RoundingMode{ToZero, ToNearestEven, AwayFromZero} { + for d := -5; d < 5; d++ { + prec := uint(preci + d) + got := NewFloat(0, prec, mode).Quo(x, y) + want := roundBits(bits, prec, mode) + if got.Cmp(want) != 0 { + t.Errorf("i = %d, prec = %d, %s:\n\t %s\n\t/ %s\n\t= %s\n\twant %s", + i, prec, mode, x, y, got, want) + } + } + } + } +} + +// normBits returns the normalized bits for x: It +// removes multiple equal entries by treating them +// as an addition (e.g., []int{5, 5} => []int{6}), +// and it sorts the result list for reproducible +// results. +func normBits(x []int) []int { + m := make(map[int]bool) + for _, b := range x { + for m[b] { + m[b] = false + b++ + } + m[b] = true + } + var z []int + for b, set := range m { + if set { + z = append(z, b) + } + } + sort.Ints(z) + return z +} + +func TestNormBits(t *testing.T) { + var tests = []struct { + x, want []int + }{ + {nil, nil}, + {[]int{}, []int{}}, + {[]int{0}, []int{0}}, + {[]int{0, 0}, []int{1}}, + {[]int{3, 1, 1}, []int{2, 3}}, + {[]int{10, 9, 8, 7, 6, 6}, []int{11}}, + } + + for _, test := range tests { + got := fmt.Sprintf("%v", normBits(test.x)) + want := fmt.Sprintf("%v", test.want) + if got != want { + t.Errorf("normBits(%v) = %s; want %s", test.x, got, want) + } + + } +} + +// roundBits returns the Float value rounded to prec bits +// according to mode from the bit set x. +func roundBits(x []int, prec uint, mode RoundingMode) *Float { + x = normBits(x) + + // determine range + var min, max int + for i, b := range x { + if i == 0 || b < min { + min = b + } + if i == 0 || b > max { + max = b + } + } + prec0 := uint(max + 1 - min) + if prec >= prec0 { + return fromBits(x...) + } + // prec < prec0 + + // determine bit 0, rounding, and sticky bit, and result bits z + var bit0, rbit, sbit uint + var z []int + r := max - int(prec) + for _, b := range x { + switch { + case b == r: + rbit = 1 + case b < r: + sbit = 1 + default: + // b > r + if b == r+1 { + bit0 = 1 + } + z = append(z, b) + } + } + + // round + f := fromBits(z...) // rounded to zero + if mode == ToNearestAway { + panic("not yet implemented") + } + if mode == ToNearestEven && rbit == 1 && (sbit == 1 || sbit == 0 && bit0 != 0) || mode == AwayFromZero { + // round away from zero + f.Round(f, prec, ToZero) // extend precision // TODO(gri) better approach? + f.Add(f, fromBits(int(r)+1)) + } + return f +} + +// fromBits returns the *Float z of the smallest possible precision +// such that z = sum(2**bits[i]), with i = range bits. +// If multiple bits[i] are equal, they are added: fromBits(0, 1, 0) +// == 2**1 + 2**0 + 2**0 = 4. +func fromBits(bits ...int) *Float { + // handle 0 + if len(bits) == 0 { + return new(Float) + // z.prec = ? + } + // len(bits) > 0 + + // determine lsb exponent + var min int + for i, b := range bits { + if i == 0 || b < min { + min = b + } + } + + // create bit pattern + x := NewInt(0) + for _, b := range bits { + badj := b - min + // propagate carry if necessary + for x.Bit(badj) != 0 { + x.SetBit(x, badj, 0) + badj++ + } + x.SetBit(x, badj, 1) + } + + // create corresponding float + z := new(Float).SetInt(x) // normalized + z.setExp(int64(z.exp) + int64(min)) + return z +} + +func TestFromBits(t *testing.T) { + var tests = []struct { + bits []int + want string + }{ + // all different bit numbers + {nil, "0.0p0"}, + {[]int{0}, "0.8000000000000000p1"}, + {[]int{1}, "0.8000000000000000p2"}, + {[]int{-1}, "0.8000000000000000p0"}, + {[]int{63}, "0.8000000000000000p64"}, + {[]int{33, -30}, "0.8000000000000001p34"}, + {[]int{255, 0}, "0.8000000000000000000000000000000000000000000000000000000000000001p256"}, + + // multiple equal bit numbers + {[]int{0, 0}, "0.8000000000000000p2"}, + {[]int{0, 0, 0, 0}, "0.8000000000000000p3"}, + {[]int{0, 1, 0}, "0.8000000000000000p3"}, + {append([]int{2, 1, 0} /* 7 */, []int{3, 1} /* 10 */ ...), "0.8800000000000000p5" /* 17 */}, + } + + for _, test := range tests { + f := fromBits(test.bits...) + if got := f.PString(); got != test.want { + t.Errorf("setBits(%v) = %s; want %s", test.bits, got, test.want) + } + } +} + +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 TestFloatPString(t *testing.T) { + var tests = []struct { + x Float + want string + }{ + {Float{}, "0.0p0"}, + {Float{neg: true}, "-0.0p0"}, + {Float{mant: nat{0x87654321}}, "0.87654321p0"}, + {Float{mant: nat{0x87654321}, exp: -10}, "0.87654321p-10"}, + } + for _, test := range tests { + if got := test.x.PString(); got != test.want { + t.Errorf("%v: got %s; want %s", test.x, got, test.want) + } + } +} |
