| | |
| | |
| | |
| |
|
| | package big |
| |
|
| | import ( |
| | "flag" |
| | "fmt" |
| | "math" |
| | "strconv" |
| | "strings" |
| | "testing" |
| | ) |
| |
|
| | |
| | var _ error = ErrNaN{} |
| |
|
| | func (x *Float) uint64() uint64 { |
| | u, acc := x.Uint64() |
| | if acc != Exact { |
| | panic(fmt.Sprintf("%s is not a uint64", x.Text('g', 10))) |
| | } |
| | return u |
| | } |
| |
|
| | func (x *Float) int64() int64 { |
| | i, acc := x.Int64() |
| | if acc != Exact { |
| | panic(fmt.Sprintf("%s is not an int64", x.Text('g', 10))) |
| | } |
| | return i |
| | } |
| |
|
| | func TestFloatZeroValue(t *testing.T) { |
| | |
| | var x Float |
| | if s := x.Text('f', 1); s != "0.0" { |
| | t.Errorf("zero value = %s; want 0.0", s) |
| | } |
| |
|
| | |
| | if prec := x.Prec(); prec != 0 { |
| | t.Errorf("prec = %d; want 0", prec) |
| | } |
| |
|
| | |
| | make := func(x int) *Float { |
| | var f Float |
| | if x != 0 { |
| | f.SetInt64(int64(x)) |
| | } |
| | |
| | return &f |
| | } |
| | for _, test := range []struct { |
| | z, x, y, want int |
| | opname rune |
| | op func(z, x, y *Float) *Float |
| | }{ |
| | {0, 0, 0, 0, '+', (*Float).Add}, |
| | {0, 1, 2, 3, '+', (*Float).Add}, |
| | {1, 2, 0, 2, '+', (*Float).Add}, |
| | {2, 0, 1, 1, '+', (*Float).Add}, |
| |
|
| | {0, 0, 0, 0, '-', (*Float).Sub}, |
| | {0, 1, 2, -1, '-', (*Float).Sub}, |
| | {1, 2, 0, 2, '-', (*Float).Sub}, |
| | {2, 0, 1, -1, '-', (*Float).Sub}, |
| |
|
| | {0, 0, 0, 0, '*', (*Float).Mul}, |
| | {0, 1, 2, 2, '*', (*Float).Mul}, |
| | {1, 2, 0, 0, '*', (*Float).Mul}, |
| | {2, 0, 1, 0, '*', (*Float).Mul}, |
| |
|
| | |
| | {0, 2, 1, 2, '/', (*Float).Quo}, |
| | {1, 2, 0, 0, '/', (*Float).Quo}, |
| | {2, 0, 1, 0, '/', (*Float).Quo}, |
| | } { |
| | z := make(test.z) |
| | test.op(z, make(test.x), make(test.y)) |
| | got := 0 |
| | if !z.IsInf() { |
| | got = int(z.int64()) |
| | } |
| | if got != test.want { |
| | t.Errorf("%d %c %d = %d; want %d", test.x, test.opname, test.y, got, test.want) |
| | } |
| | } |
| |
|
| | |
| | } |
| |
|
| | func makeFloat(s string) *Float { |
| | x, _, err := ParseFloat(s, 0, 1000, ToNearestEven) |
| | if err != nil { |
| | panic(err) |
| | } |
| | return x |
| | } |
| |
|
| | func TestFloatSetPrec(t *testing.T) { |
| | for _, test := range []struct { |
| | x string |
| | prec uint |
| | want string |
| | acc Accuracy |
| | }{ |
| | |
| | {"0", 0, "0", Exact}, |
| | {"-0", 0, "-0", Exact}, |
| | {"-Inf", 0, "-Inf", Exact}, |
| | {"+Inf", 0, "+Inf", Exact}, |
| | {"123", 0, "0", Below}, |
| | {"-123", 0, "-0", Above}, |
| |
|
| | |
| | {"0", MaxPrec, "0", Exact}, |
| | {"-0", MaxPrec, "-0", Exact}, |
| | {"-Inf", MaxPrec, "-Inf", Exact}, |
| | {"+Inf", MaxPrec, "+Inf", Exact}, |
| |
|
| | |
| | {"1.5", 1, "2", Above}, |
| | {"-1.5", 1, "-2", Below}, |
| | {"123", 1e6, "123", Exact}, |
| | {"-123", 1e6, "-123", Exact}, |
| | } { |
| | x := makeFloat(test.x).SetPrec(test.prec) |
| | prec := test.prec |
| | if prec > MaxPrec { |
| | prec = MaxPrec |
| | } |
| | if got := x.Prec(); got != prec { |
| | t.Errorf("%s.SetPrec(%d).Prec() == %d; want %d", test.x, test.prec, got, prec) |
| | } |
| | if got, acc := x.String(), x.Acc(); got != test.want || acc != test.acc { |
| | t.Errorf("%s.SetPrec(%d) = %s (%s); want %s (%s)", test.x, test.prec, got, acc, test.want, test.acc) |
| | } |
| | } |
| | } |
| |
|
| | func TestFloatMinPrec(t *testing.T) { |
| | const max = 100 |
| | for _, test := range []struct { |
| | x string |
| | want uint |
| | }{ |
| | {"0", 0}, |
| | {"-0", 0}, |
| | {"+Inf", 0}, |
| | {"-Inf", 0}, |
| | {"1", 1}, |
| | {"2", 1}, |
| | {"3", 2}, |
| | {"0x8001", 16}, |
| | {"0x8001p-1000", 16}, |
| | {"0x8001p+1000", 16}, |
| | {"0.1", max}, |
| | } { |
| | x := makeFloat(test.x).SetPrec(max) |
| | if got := x.MinPrec(); got != test.want { |
| | t.Errorf("%s.MinPrec() = %d; want %d", test.x, got, test.want) |
| | } |
| | } |
| | } |
| |
|
| | func TestFloatSign(t *testing.T) { |
| | for _, test := range []struct { |
| | x string |
| | s int |
| | }{ |
| | {"-Inf", -1}, |
| | {"-1", -1}, |
| | {"-0", 0}, |
| | {"+0", 0}, |
| | {"+1", +1}, |
| | {"+Inf", +1}, |
| | } { |
| | x := makeFloat(test.x) |
| | s := x.Sign() |
| | if s != test.s { |
| | t.Errorf("%s.Sign() = %d; want %d", test.x, s, test.s) |
| | } |
| | } |
| | } |
| |
|
| | |
| | func alike(x, y *Float) bool { |
| | return x.Cmp(y) == 0 && x.Signbit() == y.Signbit() |
| | } |
| |
|
| | func alike32(x, y float32) bool { |
| | |
| | return x == y && math.Signbit(float64(x)) == math.Signbit(float64(y)) |
| | } |
| |
|
| | func alike64(x, y float64) bool { |
| | |
| | return x == y && math.Signbit(x) == math.Signbit(y) |
| | } |
| |
|
| | func TestFloatMantExp(t *testing.T) { |
| | for _, test := range []struct { |
| | x string |
| | mant string |
| | exp int |
| | }{ |
| | {"0", "0", 0}, |
| | {"+0", "0", 0}, |
| | {"-0", "-0", 0}, |
| | {"Inf", "+Inf", 0}, |
| | {"+Inf", "+Inf", 0}, |
| | {"-Inf", "-Inf", 0}, |
| | {"1.5", "0.75", 1}, |
| | {"1.024e3", "0.5", 11}, |
| | {"-0.125", "-0.5", -2}, |
| | } { |
| | x := makeFloat(test.x) |
| | mant := makeFloat(test.mant) |
| | m := new(Float) |
| | e := x.MantExp(m) |
| | if !alike(m, mant) || e != test.exp { |
| | t.Errorf("%s.MantExp() = %s, %d; want %s, %d", test.x, m.Text('g', 10), e, test.mant, test.exp) |
| | } |
| | } |
| | } |
| |
|
| | func TestFloatMantExpAliasing(t *testing.T) { |
| | x := makeFloat("0.5p10") |
| | if e := x.MantExp(x); e != 10 { |
| | t.Fatalf("Float.MantExp aliasing error: got %d; want 10", e) |
| | } |
| | if want := makeFloat("0.5"); !alike(x, want) { |
| | t.Fatalf("Float.MantExp aliasing error: got %s; want %s", x.Text('g', 10), want.Text('g', 10)) |
| | } |
| | } |
| |
|
| | func TestFloatSetMantExp(t *testing.T) { |
| | for _, test := range []struct { |
| | frac string |
| | exp int |
| | z string |
| | }{ |
| | {"0", 0, "0"}, |
| | {"+0", 0, "0"}, |
| | {"-0", 0, "-0"}, |
| | {"Inf", 1234, "+Inf"}, |
| | {"+Inf", -1234, "+Inf"}, |
| | {"-Inf", -1234, "-Inf"}, |
| | {"0", MinExp, "0"}, |
| | {"0.25", MinExp, "+0"}, |
| | {"-0.25", MinExp, "-0"}, |
| | {"1", MaxExp, "+Inf"}, |
| | {"2", MaxExp - 1, "+Inf"}, |
| | {"0.75", 1, "1.5"}, |
| | {"0.5", 11, "1024"}, |
| | {"-0.5", -2, "-0.125"}, |
| | {"32", 5, "1024"}, |
| | {"1024", -10, "1"}, |
| | } { |
| | frac := makeFloat(test.frac) |
| | want := makeFloat(test.z) |
| | var z Float |
| | z.SetMantExp(frac, test.exp) |
| | if !alike(&z, want) { |
| | t.Errorf("SetMantExp(%s, %d) = %s; want %s", test.frac, test.exp, z.Text('g', 10), test.z) |
| | } |
| | |
| | mant := new(Float) |
| | if z.SetMantExp(mant, want.MantExp(mant)).Cmp(want) != 0 { |
| | t.Errorf("Inverse property not satisfied: got %s; want %s", z.Text('g', 10), test.z) |
| | } |
| | } |
| | } |
| |
|
| | func TestFloatPredicates(t *testing.T) { |
| | for _, test := range []struct { |
| | x string |
| | sign int |
| | signbit, inf bool |
| | }{ |
| | {x: "-Inf", sign: -1, signbit: true, inf: true}, |
| | {x: "-1", sign: -1, signbit: true}, |
| | {x: "-0", signbit: true}, |
| | {x: "0"}, |
| | {x: "1", sign: 1}, |
| | {x: "+Inf", sign: 1, inf: true}, |
| | } { |
| | x := makeFloat(test.x) |
| | if got := x.Signbit(); got != test.signbit { |
| | t.Errorf("(%s).Signbit() = %v; want %v", test.x, got, test.signbit) |
| | } |
| | if got := x.Sign(); got != test.sign { |
| | t.Errorf("(%s).Sign() = %d; want %d", test.x, got, test.sign) |
| | } |
| | if got := x.IsInf(); got != test.inf { |
| | t.Errorf("(%s).IsInf() = %v; want %v", test.x, got, test.inf) |
| | } |
| | } |
| | } |
| |
|
| | func TestFloatIsInt(t *testing.T) { |
| | for _, test := range []string{ |
| | "0 int", |
| | "-0 int", |
| | "1 int", |
| | "-1 int", |
| | "0.5", |
| | "1.23", |
| | "1.23e1", |
| | "1.23e2 int", |
| | "0.000000001e+8", |
| | "0.000000001e+9 int", |
| | "1.2345e200 int", |
| | "Inf", |
| | "+Inf", |
| | "-Inf", |
| | } { |
| | s := strings.TrimSuffix(test, " int") |
| | want := s != test |
| | if got := makeFloat(s).IsInt(); got != want { |
| | t.Errorf("%s.IsInt() == %t", s, got) |
| | } |
| | } |
| | } |
| |
|
| | 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) { |
| | |
| | var ok bool |
| | switch mode { |
| | case ToNearestEven, ToNearestAway: |
| | ok = true |
| | 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)) |
| | } |
| |
|
| | |
| | a := Exact |
| | switch { |
| | case r < x: |
| | a = Below |
| | case r > x: |
| | a = Above |
| | } |
| |
|
| | |
| | f := new(Float).SetMode(mode).SetInt64(x).SetPrec(prec) |
| |
|
| | |
| | r1 := f.int64() |
| | p1 := f.Prec() |
| | a1 := f.Acc() |
| | if r1 != r || p1 != prec || a1 != a { |
| | t.Errorf("round %s (%d bits, %s) incorrect: got %s (%d bits, %s); want %s (%d bits, %s)", |
| | toBinary(x), prec, mode, |
| | toBinary(r1), p1, a1, |
| | toBinary(r), prec, a) |
| | return |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | g := new(Float).SetMode(mode).SetPrec(prec).SetInt64(x) |
| | if !alike(g, f) { |
| | t.Errorf("round %s (%d bits, %s) not symmetric: got %s and %s; want %s", |
| | toBinary(x), prec, mode, |
| | toBinary(g.int64()), |
| | toBinary(r1), |
| | toBinary(r), |
| | ) |
| | return |
| | } |
| |
|
| | |
| | |
| | h := new(Float).SetMode(mode).SetPrec(prec).Set(f) |
| | if !alike(h, f) { |
| | t.Errorf("round %s (%d bits, %s) not idempotent: got %s and %s; want %s", |
| | toBinary(x), prec, mode, |
| | toBinary(h.int64()), |
| | toBinary(r1), |
| | toBinary(r), |
| | ) |
| | return |
| | } |
| | } |
| |
|
| | |
| | func TestFloatRound(t *testing.T) { |
| | for _, test := range []struct { |
| | prec uint |
| | x, zero, neven, naway, away string |
| | }{ |
| | {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"}, |
| | } { |
| | 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) |
| | } |
| | } |
| |
|
| | |
| | |
| | |
| | func TestFloatRound24(t *testing.T) { |
| | const x0 = 1<<26 - 0x10 |
| | for d := 0; d <= 0x10; d++ { |
| | x := float64(x0 + d) |
| | f := new(Float).SetPrec(24).SetFloat64(x) |
| | got, _ := f.Float32() |
| | want := float32(x) |
| | if got != want { |
| | t.Errorf("Round(%g, 24) = %g; want %g", x, got, want) |
| | } |
| | } |
| | } |
| |
|
| | func TestFloatSetUint64(t *testing.T) { |
| | for _, want := range []uint64{ |
| | 0, |
| | 1, |
| | 2, |
| | 10, |
| | 100, |
| | 1<<32 - 1, |
| | 1 << 32, |
| | 1<<64 - 1, |
| | } { |
| | var f Float |
| | f.SetUint64(want) |
| | if got := f.uint64(); got != want { |
| | t.Errorf("got %#x (%s); want %#x", got, f.Text('p', 0), want) |
| | } |
| | } |
| |
|
| | |
| | const x uint64 = 0x8765432187654321 |
| | for prec := uint(1); prec <= 64; prec++ { |
| | f := new(Float).SetPrec(prec).SetMode(ToZero).SetUint64(x) |
| | got := f.uint64() |
| | want := x &^ (1<<(64-prec) - 1) |
| | if got != want { |
| | t.Errorf("got %#x (%s); want %#x", got, f.Text('p', 0), want) |
| | } |
| | } |
| | } |
| |
|
| | func TestFloatSetInt64(t *testing.T) { |
| | for _, want := range []int64{ |
| | 0, |
| | 1, |
| | 2, |
| | 10, |
| | 100, |
| | 1<<32 - 1, |
| | 1 << 32, |
| | 1<<63 - 1, |
| | } { |
| | for i := range [2]int{} { |
| | if i&1 != 0 { |
| | want = -want |
| | } |
| | var f Float |
| | f.SetInt64(want) |
| | if got := f.int64(); got != want { |
| | t.Errorf("got %#x (%s); want %#x", got, f.Text('p', 0), want) |
| | } |
| | } |
| | } |
| |
|
| | |
| | const x int64 = 0x7654321076543210 |
| | for prec := uint(1); prec <= 63; prec++ { |
| | f := new(Float).SetPrec(prec).SetMode(ToZero).SetInt64(x) |
| | got := f.int64() |
| | want := x &^ (1<<(63-prec) - 1) |
| | if got != want { |
| | t.Errorf("got %#x (%s); want %#x", got, f.Text('p', 0), want) |
| | } |
| | } |
| | } |
| |
|
| | func TestFloatSetFloat64(t *testing.T) { |
| | for _, want := range []float64{ |
| | 0, |
| | 1, |
| | 2, |
| | 12345, |
| | 1e10, |
| | 1e100, |
| | 3.14159265e10, |
| | 2.718281828e-123, |
| | 1.0 / 3, |
| | math.MaxFloat32, |
| | math.MaxFloat64, |
| | math.SmallestNonzeroFloat32, |
| | math.SmallestNonzeroFloat64, |
| | math.Inf(-1), |
| | math.Inf(0), |
| | -math.Inf(1), |
| | } { |
| | for i := range [2]int{} { |
| | if i&1 != 0 { |
| | want = -want |
| | } |
| | var f Float |
| | f.SetFloat64(want) |
| | if got, acc := f.Float64(); got != want || acc != Exact { |
| | t.Errorf("got %g (%s, %s); want %g (Exact)", got, f.Text('p', 0), acc, want) |
| | } |
| | } |
| | } |
| |
|
| | |
| | const x uint64 = 0x8765432143218 |
| | for prec := uint(1); prec <= 52; prec++ { |
| | f := new(Float).SetPrec(prec).SetMode(ToZero).SetFloat64(float64(x)) |
| | got, _ := f.Float64() |
| | want := float64(x &^ (1<<(52-prec) - 1)) |
| | if got != want { |
| | t.Errorf("got %g (%s); want %g", got, f.Text('p', 0), want) |
| | } |
| | } |
| |
|
| | |
| | defer func() { |
| | if p, ok := recover().(ErrNaN); !ok { |
| | t.Errorf("got %v; want ErrNaN panic", p) |
| | } |
| | }() |
| | var f Float |
| | f.SetFloat64(math.NaN()) |
| | |
| | t.Errorf("got %s; want ErrNaN panic", f.Text('p', 0)) |
| | } |
| |
|
| | func TestFloatSetInt(t *testing.T) { |
| | for _, want := range []string{ |
| | "0", |
| | "1", |
| | "-1", |
| | "1234567890", |
| | "123456789012345678901234567890", |
| | "123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890", |
| | } { |
| | var x Int |
| | _, ok := x.SetString(want, 0) |
| | if !ok { |
| | t.Errorf("invalid integer %s", want) |
| | continue |
| | } |
| | n := x.BitLen() |
| |
|
| | var f Float |
| | f.SetInt(&x) |
| |
|
| | |
| | if n < 64 { |
| | n = 64 |
| | } |
| | if prec := f.Prec(); prec != uint(n) { |
| | t.Errorf("got prec = %d; want %d", prec, n) |
| | } |
| |
|
| | |
| | got := f.Text('g', 100) |
| | if got != want { |
| | t.Errorf("got %s (%s); want %s", got, f.Text('p', 0), want) |
| | } |
| | } |
| |
|
| | |
| | } |
| |
|
| | func TestFloatSetRat(t *testing.T) { |
| | for _, want := range []string{ |
| | "0", |
| | "1", |
| | "-1", |
| | "1234567890", |
| | "123456789012345678901234567890", |
| | "123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890", |
| | "1.2", |
| | "3.14159265", |
| | |
| | } { |
| | var x Rat |
| | _, ok := x.SetString(want) |
| | if !ok { |
| | t.Errorf("invalid fraction %s", want) |
| | continue |
| | } |
| | n := max(x.Num().BitLen(), x.Denom().BitLen()) |
| |
|
| | var f1, f2 Float |
| | f2.SetPrec(1000) |
| | f1.SetRat(&x) |
| | f2.SetRat(&x) |
| |
|
| | |
| | if n < 64 { |
| | n = 64 |
| | } |
| | if prec := f1.Prec(); prec != uint(n) { |
| | t.Errorf("got prec = %d; want %d", prec, n) |
| | } |
| |
|
| | got := f2.Text('g', 100) |
| | if got != want { |
| | t.Errorf("got %s (%s); want %s", got, f2.Text('p', 0), want) |
| | } |
| | } |
| | } |
| |
|
| | func TestFloatSetInf(t *testing.T) { |
| | var f Float |
| | for _, test := range []struct { |
| | signbit bool |
| | prec uint |
| | want string |
| | }{ |
| | {false, 0, "+Inf"}, |
| | {true, 0, "-Inf"}, |
| | {false, 10, "+Inf"}, |
| | {true, 30, "-Inf"}, |
| | } { |
| | x := f.SetPrec(test.prec).SetInf(test.signbit) |
| | if got := x.String(); got != test.want || x.Prec() != test.prec { |
| | t.Errorf("SetInf(%v) = %s (prec = %d); want %s (prec = %d)", test.signbit, got, x.Prec(), test.want, test.prec) |
| | } |
| | } |
| | } |
| |
|
| | func TestFloatUint64(t *testing.T) { |
| | for _, test := range []struct { |
| | x string |
| | out uint64 |
| | acc Accuracy |
| | }{ |
| | {"-Inf", 0, Above}, |
| | {"-1", 0, Above}, |
| | {"-1e-1000", 0, Above}, |
| | {"-0", 0, Exact}, |
| | {"0", 0, Exact}, |
| | {"1e-1000", 0, Below}, |
| | {"1", 1, Exact}, |
| | {"1.000000000000000000001", 1, Below}, |
| | {"12345.0", 12345, Exact}, |
| | {"12345.000000000000000000001", 12345, Below}, |
| | {"18446744073709551615", 18446744073709551615, Exact}, |
| | {"18446744073709551615.000000000000000000001", math.MaxUint64, Below}, |
| | {"18446744073709551616", math.MaxUint64, Below}, |
| | {"1e10000", math.MaxUint64, Below}, |
| | {"+Inf", math.MaxUint64, Below}, |
| | } { |
| | x := makeFloat(test.x) |
| | out, acc := x.Uint64() |
| | if out != test.out || acc != test.acc { |
| | t.Errorf("%s: got %d (%s); want %d (%s)", test.x, out, acc, test.out, test.acc) |
| | } |
| | } |
| | } |
| |
|
| | func TestFloatInt64(t *testing.T) { |
| | for _, test := range []struct { |
| | x string |
| | out int64 |
| | acc Accuracy |
| | }{ |
| | {"-Inf", math.MinInt64, Above}, |
| | {"-1e10000", math.MinInt64, Above}, |
| | {"-9223372036854775809", math.MinInt64, Above}, |
| | {"-9223372036854775808.000000000000000000001", math.MinInt64, Above}, |
| | {"-9223372036854775808", -9223372036854775808, Exact}, |
| | {"-9223372036854775807.000000000000000000001", -9223372036854775807, Above}, |
| | {"-9223372036854775807", -9223372036854775807, Exact}, |
| | {"-12345.000000000000000000001", -12345, Above}, |
| | {"-12345.0", -12345, Exact}, |
| | {"-1.000000000000000000001", -1, Above}, |
| | {"-1.5", -1, Above}, |
| | {"-1", -1, Exact}, |
| | {"-1e-1000", 0, Above}, |
| | {"0", 0, Exact}, |
| | {"1e-1000", 0, Below}, |
| | {"1", 1, Exact}, |
| | {"1.000000000000000000001", 1, Below}, |
| | {"1.5", 1, Below}, |
| | {"12345.0", 12345, Exact}, |
| | {"12345.000000000000000000001", 12345, Below}, |
| | {"9223372036854775807", 9223372036854775807, Exact}, |
| | {"9223372036854775807.000000000000000000001", math.MaxInt64, Below}, |
| | {"9223372036854775808", math.MaxInt64, Below}, |
| | {"1e10000", math.MaxInt64, Below}, |
| | {"+Inf", math.MaxInt64, Below}, |
| | } { |
| | x := makeFloat(test.x) |
| | out, acc := x.Int64() |
| | if out != test.out || acc != test.acc { |
| | t.Errorf("%s: got %d (%s); want %d (%s)", test.x, out, acc, test.out, test.acc) |
| | } |
| | } |
| | } |
| |
|
| | func TestFloatFloat32(t *testing.T) { |
| | for _, test := range []struct { |
| | x string |
| | out float32 |
| | acc Accuracy |
| | }{ |
| | {"0", 0, Exact}, |
| |
|
| | |
| | {"1e-1000", 0, Below}, |
| | {"0x0.000002p-127", 0, Below}, |
| | {"0x.0000010p-126", 0, Below}, |
| |
|
| | |
| | {"1.401298464e-45", math.SmallestNonzeroFloat32, Above}, |
| | {"0x.ffffff8p-149", math.SmallestNonzeroFloat32, Above}, |
| | {"0x.0000018p-126", math.SmallestNonzeroFloat32, Above}, |
| | {"0x.0000020p-126", math.SmallestNonzeroFloat32, Exact}, |
| | {"0x.8p-148", math.SmallestNonzeroFloat32, Exact}, |
| | {"1p-149", math.SmallestNonzeroFloat32, Exact}, |
| | {"0x.fffffep-126", math.Float32frombits(0x7fffff), Exact}, |
| |
|
| | |
| | {"0x0.0000001p-126", math.Float32frombits(0x00000000), Below}, |
| | {"0x0.0000008p-126", math.Float32frombits(0x00000000), Below}, |
| | {"0x0.0000010p-126", math.Float32frombits(0x00000000), Below}, |
| | {"0x0.0000011p-126", math.Float32frombits(0x00000001), Above}, |
| | {"0x0.0000018p-126", math.Float32frombits(0x00000001), Above}, |
| |
|
| | {"0x1.0000000p-149", math.Float32frombits(0x00000001), Exact}, |
| | {"0x0.0000020p-126", math.Float32frombits(0x00000001), Exact}, |
| | {"0x0.fffffe0p-126", math.Float32frombits(0x007fffff), Exact}, |
| | {"0x1.0000000p-126", math.Float32frombits(0x00800000), Exact}, |
| |
|
| | {"0x0.8p-149", math.Float32frombits(0x000000000), Below}, |
| | {"0x0.9p-149", math.Float32frombits(0x000000001), Above}, |
| | {"0x0.ap-149", math.Float32frombits(0x000000001), Above}, |
| | {"0x0.bp-149", math.Float32frombits(0x000000001), Above}, |
| | {"0x0.cp-149", math.Float32frombits(0x000000001), Above}, |
| |
|
| | {"0x1.0p-149", math.Float32frombits(0x000000001), Exact}, |
| | {"0x1.7p-149", math.Float32frombits(0x000000001), Below}, |
| | {"0x1.8p-149", math.Float32frombits(0x000000002), Above}, |
| | {"0x1.9p-149", math.Float32frombits(0x000000002), Above}, |
| |
|
| | {"0x2.0p-149", math.Float32frombits(0x000000002), Exact}, |
| | {"0x2.8p-149", math.Float32frombits(0x000000002), Below}, |
| | {"0x2.9p-149", math.Float32frombits(0x000000003), Above}, |
| |
|
| | {"0x3.0p-149", math.Float32frombits(0x000000003), Exact}, |
| | {"0x3.7p-149", math.Float32frombits(0x000000003), Below}, |
| | {"0x3.8p-149", math.Float32frombits(0x000000004), Above}, |
| |
|
| | {"0x4.0p-149", math.Float32frombits(0x000000004), Exact}, |
| | {"0x4.8p-149", math.Float32frombits(0x000000004), Below}, |
| | {"0x4.9p-149", math.Float32frombits(0x000000005), Above}, |
| |
|
| | |
| | {"0x7.7p-149", math.Float32frombits(0x000000007), Below}, |
| | {"0x7.8p-149", math.Float32frombits(0x000000008), Above}, |
| | {"0x7.9p-149", math.Float32frombits(0x000000008), Above}, |
| |
|
| | |
| | {"0x.ffffffp-126", math.Float32frombits(0x00800000), Above}, |
| | {"1p-126", math.Float32frombits(0x00800000), Exact}, |
| | {"0x1.fffffep-126", math.Float32frombits(0x00ffffff), Exact}, |
| | {"0x1.ffffffp-126", math.Float32frombits(0x01000000), Above}, |
| | {"1", 1, Exact}, |
| | {"1.000000000000000000001", 1, Below}, |
| | {"12345.0", 12345, Exact}, |
| | {"12345.000000000000000000001", 12345, Below}, |
| | {"0x1.fffffe0p127", math.MaxFloat32, Exact}, |
| | {"0x1.fffffe8p127", math.MaxFloat32, Below}, |
| |
|
| | |
| | {"0x1.ffffff0p127", float32(math.Inf(+1)), Above}, |
| | {"0x1p128", float32(math.Inf(+1)), Above}, |
| | {"1e10000", float32(math.Inf(+1)), Above}, |
| | {"0x1.ffffff0p2147483646", float32(math.Inf(+1)), Above}, |
| |
|
| | |
| | {"Inf", float32(math.Inf(+1)), Exact}, |
| | } { |
| | for i := 0; i < 2; i++ { |
| | |
| | tx, tout, tacc := test.x, test.out, test.acc |
| | if i != 0 { |
| | tx = "-" + tx |
| | tout = -tout |
| | tacc = -tacc |
| | } |
| |
|
| | |
| | if f, err := strconv.ParseFloat(tx, 32); err == nil && !alike32(float32(f), tout) { |
| | t.Errorf("%s: got %g; want %g (incorrect test data)", tx, f, tout) |
| | } |
| |
|
| | x := makeFloat(tx) |
| | out, acc := x.Float32() |
| | if !alike32(out, tout) || acc != tacc { |
| | t.Errorf("%s: got %g (%#08x, %s); want %g (%#08x, %s)", tx, out, math.Float32bits(out), acc, test.out, math.Float32bits(test.out), tacc) |
| | } |
| |
|
| | |
| | var x2 Float |
| | out2, acc2 := x2.SetFloat64(float64(out)).Float32() |
| | if !alike32(out2, out) || acc2 != Exact { |
| | t.Errorf("idempotency test: got %g (%s); want %g (Exact)", out2, acc2, out) |
| | } |
| | } |
| | } |
| | } |
| |
|
| | func TestFloatFloat64(t *testing.T) { |
| | const smallestNormalFloat64 = 2.2250738585072014e-308 |
| | for _, test := range []struct { |
| | x string |
| | out float64 |
| | acc Accuracy |
| | }{ |
| | {"0", 0, Exact}, |
| |
|
| | |
| | {"1e-1000", 0, Below}, |
| | {"0x0.0000000000001p-1023", 0, Below}, |
| | {"0x0.00000000000008p-1022", 0, Below}, |
| |
|
| | |
| | {"0x0.0000000000000cp-1022", math.SmallestNonzeroFloat64, Above}, |
| | {"0x0.00000000000010p-1022", math.SmallestNonzeroFloat64, Exact}, |
| | {"0x.8p-1073", math.SmallestNonzeroFloat64, Exact}, |
| | {"1p-1074", math.SmallestNonzeroFloat64, Exact}, |
| | {"0x.fffffffffffffp-1022", math.Float64frombits(0x000fffffffffffff), Exact}, |
| |
|
| | |
| | {"0x0.00000000000001p-1022", math.Float64frombits(0x00000000000000000), Below}, |
| | {"0x0.00000000000004p-1022", math.Float64frombits(0x00000000000000000), Below}, |
| | {"0x0.00000000000008p-1022", math.Float64frombits(0x00000000000000000), Below}, |
| | {"0x0.00000000000009p-1022", math.Float64frombits(0x00000000000000001), Above}, |
| | {"0x0.0000000000000ap-1022", math.Float64frombits(0x00000000000000001), Above}, |
| |
|
| | {"0x0.8p-1074", math.Float64frombits(0x00000000000000000), Below}, |
| | {"0x0.9p-1074", math.Float64frombits(0x00000000000000001), Above}, |
| | {"0x0.ap-1074", math.Float64frombits(0x00000000000000001), Above}, |
| | {"0x0.bp-1074", math.Float64frombits(0x00000000000000001), Above}, |
| | {"0x0.cp-1074", math.Float64frombits(0x00000000000000001), Above}, |
| |
|
| | {"0x1.0p-1074", math.Float64frombits(0x00000000000000001), Exact}, |
| | {"0x1.7p-1074", math.Float64frombits(0x00000000000000001), Below}, |
| | {"0x1.8p-1074", math.Float64frombits(0x00000000000000002), Above}, |
| | {"0x1.9p-1074", math.Float64frombits(0x00000000000000002), Above}, |
| |
|
| | {"0x2.0p-1074", math.Float64frombits(0x00000000000000002), Exact}, |
| | {"0x2.8p-1074", math.Float64frombits(0x00000000000000002), Below}, |
| | {"0x2.9p-1074", math.Float64frombits(0x00000000000000003), Above}, |
| |
|
| | {"0x3.0p-1074", math.Float64frombits(0x00000000000000003), Exact}, |
| | {"0x3.7p-1074", math.Float64frombits(0x00000000000000003), Below}, |
| | {"0x3.8p-1074", math.Float64frombits(0x00000000000000004), Above}, |
| |
|
| | {"0x4.0p-1074", math.Float64frombits(0x00000000000000004), Exact}, |
| | {"0x4.8p-1074", math.Float64frombits(0x00000000000000004), Below}, |
| | {"0x4.9p-1074", math.Float64frombits(0x00000000000000005), Above}, |
| |
|
| | |
| | {"0x.fffffffffffff8p-1022", math.Float64frombits(0x0010000000000000), Above}, |
| | {"1p-1022", math.Float64frombits(0x0010000000000000), Exact}, |
| | {"1", 1, Exact}, |
| | {"1.000000000000000000001", 1, Below}, |
| | {"12345.0", 12345, Exact}, |
| | {"12345.000000000000000000001", 12345, Below}, |
| | {"0x1.fffffffffffff0p1023", math.MaxFloat64, Exact}, |
| | {"0x1.fffffffffffff4p1023", math.MaxFloat64, Below}, |
| |
|
| | |
| | {"0x1.fffffffffffff8p1023", math.Inf(+1), Above}, |
| | {"0x1p1024", math.Inf(+1), Above}, |
| | {"1e10000", math.Inf(+1), Above}, |
| | {"0x1.fffffffffffff8p2147483646", math.Inf(+1), Above}, |
| | {"Inf", math.Inf(+1), Exact}, |
| |
|
| | |
| | {"0x.fffffffffffffp-1022", smallestNormalFloat64 - math.SmallestNonzeroFloat64, Exact}, |
| | {"4503599627370495p-1074", smallestNormalFloat64 - math.SmallestNonzeroFloat64, Exact}, |
| |
|
| | |
| | {"2.2250738585072011e-308", 2.225073858507201e-308, Below}, |
| | |
| | {"2.2250738585072012e-308", 2.2250738585072014e-308, Above}, |
| | } { |
| | for i := 0; i < 2; i++ { |
| | |
| | tx, tout, tacc := test.x, test.out, test.acc |
| | if i != 0 { |
| | tx = "-" + tx |
| | tout = -tout |
| | tacc = -tacc |
| | } |
| |
|
| | |
| | if f, err := strconv.ParseFloat(tx, 64); err == nil && !alike64(f, tout) { |
| | t.Errorf("%s: got %g; want %g (incorrect test data)", tx, f, tout) |
| | } |
| |
|
| | x := makeFloat(tx) |
| | out, acc := x.Float64() |
| | if !alike64(out, tout) || acc != tacc { |
| | t.Errorf("%s: got %g (%#016x, %s); want %g (%#016x, %s)", tx, out, math.Float64bits(out), acc, test.out, math.Float64bits(test.out), tacc) |
| | } |
| |
|
| | |
| | var x2 Float |
| | out2, acc2 := x2.SetFloat64(out).Float64() |
| | if !alike64(out2, out) || acc2 != Exact { |
| | t.Errorf("idempotency test: got %g (%s); want %g (Exact)", out2, acc2, out) |
| | } |
| | } |
| | } |
| | } |
| |
|
| | func TestFloatInt(t *testing.T) { |
| | for _, test := range []struct { |
| | x string |
| | want string |
| | acc Accuracy |
| | }{ |
| | {"0", "0", Exact}, |
| | {"+0", "0", Exact}, |
| | {"-0", "0", Exact}, |
| | {"Inf", "nil", Below}, |
| | {"+Inf", "nil", Below}, |
| | {"-Inf", "nil", Above}, |
| | {"1", "1", Exact}, |
| | {"-1", "-1", Exact}, |
| | {"1.23", "1", Below}, |
| | {"-1.23", "-1", Above}, |
| | {"123e-2", "1", Below}, |
| | {"123e-3", "0", Below}, |
| | {"123e-4", "0", Below}, |
| | {"1e-1000", "0", Below}, |
| | {"-1e-1000", "0", Above}, |
| | {"1e+10", "10000000000", Exact}, |
| | {"1e+100", "10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", Exact}, |
| | } { |
| | x := makeFloat(test.x) |
| | res, acc := x.Int(nil) |
| | got := "nil" |
| | if res != nil { |
| | got = res.String() |
| | } |
| | if got != test.want || acc != test.acc { |
| | t.Errorf("%s: got %s (%s); want %s (%s)", test.x, got, acc, test.want, test.acc) |
| | } |
| | } |
| |
|
| | |
| | for _, f := range []string{"0", "1", "-1", "1234"} { |
| | x := makeFloat(f) |
| | i := new(Int) |
| | if res, _ := x.Int(i); res != i { |
| | t.Errorf("(%s).Int is not using supplied *Int", f) |
| | } |
| | } |
| | } |
| |
|
| | func TestFloatRat(t *testing.T) { |
| | for _, test := range []struct { |
| | x, want string |
| | acc Accuracy |
| | }{ |
| | {"0", "0/1", Exact}, |
| | {"+0", "0/1", Exact}, |
| | {"-0", "0/1", Exact}, |
| | {"Inf", "nil", Below}, |
| | {"+Inf", "nil", Below}, |
| | {"-Inf", "nil", Above}, |
| | {"1", "1/1", Exact}, |
| | {"-1", "-1/1", Exact}, |
| | {"1.25", "5/4", Exact}, |
| | {"-1.25", "-5/4", Exact}, |
| | {"1e10", "10000000000/1", Exact}, |
| | {"1p10", "1024/1", Exact}, |
| | {"-1p-10", "-1/1024", Exact}, |
| | {"3.14159265", "7244019449799623199/2305843009213693952", Exact}, |
| | } { |
| | x := makeFloat(test.x).SetPrec(64) |
| | res, acc := x.Rat(nil) |
| | got := "nil" |
| | if res != nil { |
| | got = res.String() |
| | } |
| | if got != test.want { |
| | t.Errorf("%s: got %s; want %s", test.x, got, test.want) |
| | continue |
| | } |
| | if acc != test.acc { |
| | t.Errorf("%s: got %s; want %s", test.x, acc, test.acc) |
| | continue |
| | } |
| |
|
| | |
| | if res != nil { |
| | got := new(Float).SetPrec(64).SetRat(res) |
| | if got.Cmp(x) != 0 { |
| | t.Errorf("%s: got %s; want %s", test.x, got, x) |
| | } |
| | } |
| | } |
| |
|
| | |
| | for _, f := range []string{"0", "1", "-1", "1234"} { |
| | x := makeFloat(f) |
| | r := new(Rat) |
| | if res, _ := x.Rat(r); res != r { |
| | t.Errorf("(%s).Rat is not using supplied *Rat", f) |
| | } |
| | } |
| | } |
| |
|
| | func TestFloatAbs(t *testing.T) { |
| | for _, test := range []string{ |
| | "0", |
| | "1", |
| | "1234", |
| | "1.23e-2", |
| | "1e-1000", |
| | "1e1000", |
| | "Inf", |
| | } { |
| | p := makeFloat(test) |
| | a := new(Float).Abs(p) |
| | if !alike(a, p) { |
| | t.Errorf("%s: got %s; want %s", test, a.Text('g', 10), test) |
| | } |
| |
|
| | n := makeFloat("-" + test) |
| | a.Abs(n) |
| | if !alike(a, p) { |
| | t.Errorf("-%s: got %s; want %s", test, a.Text('g', 10), test) |
| | } |
| | } |
| | } |
| |
|
| | func TestFloatNeg(t *testing.T) { |
| | for _, test := range []string{ |
| | "0", |
| | "1", |
| | "1234", |
| | "1.23e-2", |
| | "1e-1000", |
| | "1e1000", |
| | "Inf", |
| | } { |
| | p1 := makeFloat(test) |
| | n1 := makeFloat("-" + test) |
| | n2 := new(Float).Neg(p1) |
| | p2 := new(Float).Neg(n2) |
| | if !alike(n2, n1) { |
| | t.Errorf("%s: got %s; want %s", test, n2.Text('g', 10), n1.Text('g', 10)) |
| | } |
| | if !alike(p2, p1) { |
| | t.Errorf("%s: got %s; want %s", test, p2.Text('g', 10), p1.Text('g', 10)) |
| | } |
| | } |
| | } |
| |
|
| | func TestFloatInc(t *testing.T) { |
| | const n = 10 |
| | for _, prec := range precList { |
| | if 1<<prec < n { |
| | continue |
| | } |
| | var x, one Float |
| | x.SetPrec(prec) |
| | one.SetInt64(1) |
| | for i := 0; i < n; i++ { |
| | x.Add(&x, &one) |
| | } |
| | if x.Cmp(new(Float).SetInt64(n)) != 0 { |
| | t.Errorf("prec = %d: got %s; want %d", prec, &x, n) |
| | } |
| | } |
| | } |
| |
|
| | |
| | var precList = [...]uint{1, 2, 5, 8, 10, 16, 23, 24, 32, 50, 53, 64, 100, 128, 500, 511, 512, 513, 1000, 10000} |
| |
|
| | |
| | |
| | var bitsList = [...]Bits{ |
| | {}, |
| | {0}, |
| | {1}, |
| | {-1}, |
| | {10}, |
| | {-10}, |
| | {100, 10, 1}, |
| | {0, -1, -2, -10}, |
| | |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | func TestFloatAdd(t *testing.T) { |
| | for _, xbits := range bitsList { |
| | for _, ybits := range bitsList { |
| | |
| | x := xbits.Float() |
| | y := ybits.Float() |
| | zbits := xbits.add(ybits) |
| | z := zbits.Float() |
| |
|
| | for i, mode := range [...]RoundingMode{ToZero, ToNearestEven, AwayFromZero} { |
| | for _, prec := range precList { |
| | got := new(Float).SetPrec(prec).SetMode(mode) |
| | got.Add(x, y) |
| | want := zbits.round(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) |
| | } |
| |
|
| | got.Sub(z, x) |
| | want = ybits.round(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, z, zbits, x, xbits, got, want) |
| | } |
| | } |
| | } |
| | } |
| | } |
| | } |
| |
|
| | |
| | |
| | |
| | func TestFloatAddRoundZero(t *testing.T) { |
| | for _, mode := range [...]RoundingMode{ToNearestEven, ToNearestAway, ToZero, AwayFromZero, ToPositiveInf, ToNegativeInf} { |
| | x := NewFloat(5.0) |
| | y := new(Float).Neg(x) |
| | want := NewFloat(0.0) |
| | if mode == ToNegativeInf { |
| | want.Neg(want) |
| | } |
| | got := new(Float).SetMode(mode) |
| | got.Add(x, y) |
| | if got.Cmp(want) != 0 || got.neg != (mode == ToNegativeInf) { |
| | t.Errorf("%s:\n\t %v\n\t+ %v\n\t= %v\n\twant %v", |
| | mode, x, y, got, want) |
| | } |
| | got.Sub(x, x) |
| | if got.Cmp(want) != 0 || got.neg != (mode == ToNegativeInf) { |
| | t.Errorf("%v:\n\t %v\n\t- %v\n\t= %v\n\twant %v", |
| | mode, x, x, got, want) |
| | } |
| | } |
| | } |
| |
|
| | |
| | |
| | |
| | func TestFloatAdd32(t *testing.T) { |
| | |
| | const base = 1<<26 - 0x10 |
| | 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 := NewFloat(x0) |
| | y := NewFloat(y0) |
| | z := new(Float).SetPrec(24) |
| |
|
| | z.Add(x, y) |
| | got, acc := z.Float32() |
| | want := float32(y0) + float32(x0) |
| | if got != want || acc != Exact { |
| | t.Errorf("d = %d: %g + %g = %g (%s); want %g (Exact)", d, x0, y0, got, acc, want) |
| | } |
| |
|
| | z.Sub(z, y) |
| | got, acc = z.Float32() |
| | want = float32(want) - float32(y0) |
| | if got != want || acc != Exact { |
| | t.Errorf("d = %d: %g - %g = %g (%s); want %g (Exact)", d, x0+y0, y0, got, acc, want) |
| | } |
| | } |
| | } |
| | } |
| |
|
| | |
| | |
| | func TestFloatAdd64(t *testing.T) { |
| | |
| | const base = 1<<55 - 0x10 |
| | 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 := NewFloat(x0) |
| | y := NewFloat(y0) |
| | z := new(Float).SetPrec(53) |
| |
|
| | z.Add(x, y) |
| | got, acc := z.Float64() |
| | want := x0 + y0 |
| | if got != want || acc != Exact { |
| | t.Errorf("d = %d: %g + %g = %g (%s); want %g (Exact)", 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 (%s); want %g (Exact)", d, x0+y0, y0, got, acc, want) |
| | } |
| | } |
| | } |
| | } |
| |
|
| | func TestIssue20490(t *testing.T) { |
| | var tests = []struct { |
| | a, b float64 |
| | }{ |
| | {4, 1}, |
| | {-4, 1}, |
| | {4, -1}, |
| | {-4, -1}, |
| | } |
| |
|
| | for _, test := range tests { |
| | a, b := NewFloat(test.a), NewFloat(test.b) |
| | diff := new(Float).Sub(a, b) |
| | b.Sub(a, b) |
| | if b.Cmp(diff) != 0 { |
| | t.Errorf("got %g - %g = %g; want %g\n", a, NewFloat(test.b), b, diff) |
| | } |
| |
|
| | b = NewFloat(test.b) |
| | sum := new(Float).Add(a, b) |
| | b.Add(a, b) |
| | if b.Cmp(sum) != 0 { |
| | t.Errorf("got %g + %g = %g; want %g\n", a, NewFloat(test.b), b, sum) |
| | } |
| |
|
| | } |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | func TestFloatMul(t *testing.T) { |
| | for _, xbits := range bitsList { |
| | for _, ybits := range bitsList { |
| | |
| | x := xbits.Float() |
| | y := ybits.Float() |
| | zbits := xbits.mul(ybits) |
| | z := zbits.Float() |
| |
|
| | for i, mode := range [...]RoundingMode{ToZero, ToNearestEven, AwayFromZero} { |
| | for _, prec := range precList { |
| | got := new(Float).SetPrec(prec).SetMode(mode) |
| | got.Mul(x, y) |
| | want := zbits.round(prec, mode) |
| | if got.Cmp(want) != 0 { |
| | t.Errorf("i = %d, prec = %d, %s:\n\t %v %v\n\t* %v %v\n\t= %v\n\twant %v", |
| | i, prec, mode, x, xbits, y, ybits, got, want) |
| | } |
| |
|
| | if x.Sign() == 0 { |
| | continue |
| | } |
| | got.Quo(z, x) |
| | want = ybits.round(prec, mode) |
| | if got.Cmp(want) != 0 { |
| | t.Errorf("i = %d, prec = %d, %s:\n\t %v %v\n\t/ %v %v\n\t= %v\n\twant %v", |
| | i, prec, mode, z, zbits, x, xbits, got, want) |
| | } |
| | } |
| | } |
| | } |
| | } |
| | } |
| |
|
| | |
| | |
| | func TestFloatMul64(t *testing.T) { |
| | for _, test := range []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 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 := NewFloat(x0) |
| | y := NewFloat(y0) |
| | z := new(Float).SetPrec(53) |
| |
|
| | 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 |
| | } |
| | 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 := new(Float).SetPrec(prec).SetInt64(2) |
| | one := new(Float).SetPrec(prec).SetInt64(1) |
| | three := new(Float).SetPrec(prec).SetInt64(3) |
| | msix := new(Float).SetPrec(prec).SetInt64(-6) |
| | psix := new(Float).SetPrec(prec).SetInt64(+6) |
| |
|
| | p := new(Float).SetPrec(prec) |
| | z1 := new(Float).SetPrec(prec) |
| | z2 := new(Float).SetPrec(prec) |
| |
|
| | |
| | p.Quo(one, three) |
| | p.Mul(p, msix) |
| | z1.Add(two, p) |
| |
|
| | |
| | p.Quo(one, three) |
| | p.Mul(p, psix) |
| | z2.Sub(two, p) |
| |
|
| | if z1.Cmp(z2) != 0 { |
| | t.Fatalf("prec %d: got z1 = %v != z2 = %v; want z1 == z2\n", prec, z1, z2) |
| | } |
| | if z1.Sign() != 0 { |
| | t.Errorf("prec %d: got z1 = %v; want 0", prec, z1) |
| | } |
| | if z2.Sign() != 0 { |
| | t.Errorf("prec %d: got z2 = %v; want 0", prec, z2) |
| | } |
| | } |
| | } |
| |
|
| | func TestFloatQuo(t *testing.T) { |
| | |
| | preci := 200 |
| | precf := 20 |
| |
|
| | for i := 0; i < 8; i++ { |
| | |
| | bits := Bits{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 := bits.Float() |
| |
|
| | |
| | y := NewFloat(3.14159265358979323e123) |
| |
|
| | x := new(Float).SetPrec(z.Prec() + y.Prec()).SetMode(ToZero) |
| | x.Mul(z, y) |
| |
|
| | |
| | |
| |
|
| | if got := x.Acc(); got != Exact { |
| | t.Errorf("got acc = %s; want exact", got) |
| | } |
| |
|
| | |
| | |
| | for _, mode := range [...]RoundingMode{ToZero, ToNearestEven, AwayFromZero} { |
| | for d := -5; d < 5; d++ { |
| | prec := uint(preci + d) |
| | got := new(Float).SetPrec(prec).SetMode(mode).Quo(x, y) |
| | want := bits.round(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) |
| | } |
| | } |
| | } |
| | } |
| | } |
| |
|
| | var long = flag.Bool("long", false, "run very long tests") |
| |
|
| | |
| | |
| | func TestFloatQuoSmoke(t *testing.T) { |
| | n := 10 |
| | if *long { |
| | n = 1000 |
| | } |
| |
|
| | const dprec = 3 |
| | const prec = 10 + dprec |
| | for x := -n; x <= n; x++ { |
| | for y := -n; y < n; y++ { |
| | if y == 0 { |
| | continue |
| | } |
| |
|
| | a := float64(x) |
| | b := float64(y) |
| | c := a / b |
| |
|
| | |
| | for ad := -dprec; ad <= dprec; ad++ { |
| | for bd := -dprec; bd <= dprec; bd++ { |
| | A := new(Float).SetPrec(uint(prec + ad)).SetFloat64(a) |
| | B := new(Float).SetPrec(uint(prec + bd)).SetFloat64(b) |
| | C := new(Float).SetPrec(53).Quo(A, B) |
| |
|
| | cc, acc := C.Float64() |
| | if cc != c { |
| | t.Errorf("%g/%g = %s; want %.5g\n", a, b, C.Text('g', 5), c) |
| | continue |
| | } |
| | if acc != Exact { |
| | t.Errorf("%g/%g got %s result; want exact result", a, b, acc) |
| | } |
| | } |
| | } |
| | } |
| | } |
| | } |
| |
|
| | |
| | |
| | |
| | func TestFloatArithmeticSpecialValues(t *testing.T) { |
| | zero := 0.0 |
| | args := []float64{math.Inf(-1), -2.71828, -1, -zero, zero, 1, 2.71828, math.Inf(1)} |
| | xx := new(Float) |
| | yy := new(Float) |
| | got := new(Float) |
| | want := new(Float) |
| | for i := 0; i < 4; i++ { |
| | for _, x := range args { |
| | xx.SetFloat64(x) |
| | |
| | |
| | |
| | if got, acc := xx.Float64(); got != x || acc != Exact { |
| | t.Errorf("Float(%g) == %g (%s)", x, got, acc) |
| | } |
| | for _, y := range args { |
| | yy.SetFloat64(y) |
| | var ( |
| | op string |
| | z float64 |
| | f func(z, x, y *Float) *Float |
| | ) |
| | switch i { |
| | case 0: |
| | op = "+" |
| | z = x + y |
| | f = (*Float).Add |
| | case 1: |
| | op = "-" |
| | z = x - y |
| | f = (*Float).Sub |
| | case 2: |
| | op = "*" |
| | z = x * y |
| | f = (*Float).Mul |
| | case 3: |
| | op = "/" |
| | z = x / y |
| | f = (*Float).Quo |
| | default: |
| | panic("unreachable") |
| | } |
| | var errnan bool |
| | |
| | func() { |
| | defer func() { |
| | if p := recover(); p != nil { |
| | _ = p.(ErrNaN) |
| | errnan = true |
| | } |
| | }() |
| | f(got, xx, yy) |
| | }() |
| | if math.IsNaN(z) { |
| | if !errnan { |
| | t.Errorf("%5g %s %5g = %5s; want ErrNaN panic", x, op, y, got) |
| | } |
| | continue |
| | } |
| | if errnan { |
| | t.Errorf("%5g %s %5g panicked with ErrNan; want %5s", x, op, y, want) |
| | continue |
| | } |
| | want.SetFloat64(z) |
| | if !alike(got, want) { |
| | t.Errorf("%5g %s %5g = %5s; want %5s", x, op, y, got, want) |
| | } |
| | } |
| | } |
| | } |
| | } |
| |
|
| | func TestFloatArithmeticOverflow(t *testing.T) { |
| | for _, test := range []struct { |
| | prec uint |
| | mode RoundingMode |
| | op byte |
| | x, y, want string |
| | acc Accuracy |
| | }{ |
| | {4, ToNearestEven, '+', "0", "0", "0", Exact}, |
| | {4, ToNearestEven, '+', "0x.8p+0", "0x.8p+0", "0x.8p+1", Exact}, |
| |
|
| | {4, ToNearestEven, '+', "0", "0x.8p2147483647", "0x.8p+2147483647", Exact}, |
| | {4, ToNearestEven, '+', "0x.8p2147483500", "0x.8p2147483647", "0x.8p+2147483647", Below}, |
| | {4, ToNearestEven, '+', "0x.8p2147483647", "0x.8p2147483647", "+Inf", Above}, |
| | {4, ToNearestEven, '+', "-0x.8p2147483647", "-0x.8p2147483647", "-Inf", Below}, |
| | {4, ToNearestEven, '-', "-0x.8p2147483647", "0x.8p2147483647", "-Inf", Below}, |
| |
|
| | {4, ToZero, '+', "0x.fp2147483647", "0x.8p2147483643", "0x.fp+2147483647", Below}, |
| | {4, ToNearestEven, '+', "0x.fp2147483647", "0x.8p2147483643", "+Inf", Above}, |
| | {4, AwayFromZero, '+', "0x.fp2147483647", "0x.8p2147483643", "+Inf", Above}, |
| |
|
| | {4, AwayFromZero, '-', "-0x.fp2147483647", "0x.8p2147483644", "-Inf", Below}, |
| | {4, ToNearestEven, '-', "-0x.fp2147483647", "0x.8p2147483643", "-Inf", Below}, |
| | {4, ToZero, '-', "-0x.fp2147483647", "0x.8p2147483643", "-0x.fp+2147483647", Above}, |
| |
|
| | {4, ToNearestEven, '+', "0", "0x.8p-2147483648", "0x.8p-2147483648", Exact}, |
| | {4, ToNearestEven, '+', "0x.8p-2147483648", "0x.8p-2147483648", "0x.8p-2147483647", Exact}, |
| |
|
| | {4, ToNearestEven, '*', "1", "0x.8p2147483647", "0x.8p+2147483647", Exact}, |
| | {4, ToNearestEven, '*', "2", "0x.8p2147483647", "+Inf", Above}, |
| | {4, ToNearestEven, '*', "-2", "0x.8p2147483647", "-Inf", Below}, |
| |
|
| | {4, ToNearestEven, '/', "0.5", "0x.8p2147483647", "0x.8p-2147483646", Exact}, |
| | {4, ToNearestEven, '/', "0x.8p+0", "0x.8p2147483647", "0x.8p-2147483646", Exact}, |
| | {4, ToNearestEven, '/', "0x.8p-1", "0x.8p2147483647", "0x.8p-2147483647", Exact}, |
| | {4, ToNearestEven, '/', "0x.8p-2", "0x.8p2147483647", "0x.8p-2147483648", Exact}, |
| | {4, ToNearestEven, '/', "0x.8p-3", "0x.8p2147483647", "0", Below}, |
| | } { |
| | x := makeFloat(test.x) |
| | y := makeFloat(test.y) |
| | z := new(Float).SetPrec(test.prec).SetMode(test.mode) |
| | switch test.op { |
| | case '+': |
| | z.Add(x, y) |
| | case '-': |
| | z.Sub(x, y) |
| | case '*': |
| | z.Mul(x, y) |
| | case '/': |
| | z.Quo(x, y) |
| | default: |
| | panic("unreachable") |
| | } |
| | if got := z.Text('p', 0); got != test.want || z.Acc() != test.acc { |
| | t.Errorf( |
| | "prec = %d (%s): %s %c %s = %s (%s); want %s (%s)", |
| | test.prec, test.mode, x.Text('p', 0), test.op, y.Text('p', 0), got, z.Acc(), test.want, test.acc, |
| | ) |
| | } |
| | } |
| | } |
| |
|
| | |
| |
|
| | |
| | |
| | |
| | |
| | |
| | func TestFloatArithmeticRounding(t *testing.T) { |
| | for _, test := range []struct { |
| | mode RoundingMode |
| | prec uint |
| | x, y, want int64 |
| | op byte |
| | }{ |
| | {ToZero, 3, -0x8, -0x1, -0x8, '+'}, |
| | {AwayFromZero, 3, -0x8, -0x1, -0xa, '+'}, |
| | {ToNegativeInf, 3, -0x8, -0x1, -0xa, '+'}, |
| |
|
| | {ToZero, 3, -0x8, 0x1, -0x8, '-'}, |
| | {AwayFromZero, 3, -0x8, 0x1, -0xa, '-'}, |
| | {ToNegativeInf, 3, -0x8, 0x1, -0xa, '-'}, |
| |
|
| | {ToZero, 3, -0x9, 0x1, -0x8, '*'}, |
| | {AwayFromZero, 3, -0x9, 0x1, -0xa, '*'}, |
| | {ToNegativeInf, 3, -0x9, 0x1, -0xa, '*'}, |
| |
|
| | {ToZero, 3, -0x9, 0x1, -0x8, '/'}, |
| | {AwayFromZero, 3, -0x9, 0x1, -0xa, '/'}, |
| | {ToNegativeInf, 3, -0x9, 0x1, -0xa, '/'}, |
| | } { |
| | var x, y, z Float |
| | x.SetInt64(test.x) |
| | y.SetInt64(test.y) |
| | z.SetPrec(test.prec).SetMode(test.mode) |
| | switch test.op { |
| | case '+': |
| | z.Add(&x, &y) |
| | case '-': |
| | z.Sub(&x, &y) |
| | case '*': |
| | z.Mul(&x, &y) |
| | case '/': |
| | z.Quo(&x, &y) |
| | default: |
| | panic("unreachable") |
| | } |
| | if got, acc := z.Int64(); got != test.want || acc != Exact { |
| | t.Errorf("%s, %d bits: %d %c %d = %d (%s); want %d (Exact)", |
| | test.mode, test.prec, test.x, test.op, test.y, got, acc, test.want, |
| | ) |
| | } |
| | } |
| | } |
| |
|
| | |
| | |
| | |
| | func TestFloatCmpSpecialValues(t *testing.T) { |
| | zero := 0.0 |
| | args := []float64{math.Inf(-1), -2.71828, -1, -zero, zero, 1, 2.71828, math.Inf(1)} |
| | xx := new(Float) |
| | yy := new(Float) |
| | for i := 0; i < 4; i++ { |
| | for _, x := range args { |
| | xx.SetFloat64(x) |
| | |
| | |
| | |
| | if got, acc := xx.Float64(); got != x || acc != Exact { |
| | t.Errorf("Float(%g) == %g (%s)", x, got, acc) |
| | } |
| | for _, y := range args { |
| | yy.SetFloat64(y) |
| | got := xx.Cmp(yy) |
| | want := 0 |
| | switch { |
| | case x < y: |
| | want = -1 |
| | case x > y: |
| | want = +1 |
| | } |
| | if got != want { |
| | t.Errorf("(%g).Cmp(%g) = %v; want %v", x, y, got, want) |
| | } |
| | } |
| | } |
| | } |
| | } |
| |
|
| | func BenchmarkFloatAdd(b *testing.B) { |
| | x := new(Float) |
| | y := new(Float) |
| | z := new(Float) |
| |
|
| | for _, prec := range []uint{10, 1e2, 1e3, 1e4, 1e5} { |
| | x.SetPrec(prec).SetRat(NewRat(1, 3)) |
| | y.SetPrec(prec).SetRat(NewRat(1, 6)) |
| | z.SetPrec(prec) |
| |
|
| | b.Run(fmt.Sprintf("%v", prec), func(b *testing.B) { |
| | b.ReportAllocs() |
| | for i := 0; i < b.N; i++ { |
| | z.Add(x, y) |
| | } |
| | }) |
| | } |
| | } |
| |
|
| | func BenchmarkFloatSub(b *testing.B) { |
| | x := new(Float) |
| | y := new(Float) |
| | z := new(Float) |
| |
|
| | for _, prec := range []uint{10, 1e2, 1e3, 1e4, 1e5} { |
| | x.SetPrec(prec).SetRat(NewRat(1, 3)) |
| | y.SetPrec(prec).SetRat(NewRat(1, 6)) |
| | z.SetPrec(prec) |
| |
|
| | b.Run(fmt.Sprintf("%v", prec), func(b *testing.B) { |
| | b.ReportAllocs() |
| | for i := 0; i < b.N; i++ { |
| | z.Sub(x, y) |
| | } |
| | }) |
| | } |
| | } |
| |
|