2014-12-08 14:36:39 -08:00
|
|
|
// 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) {
|
2015-01-23 21:40:35 -08:00
|
|
|
// TODO(gri) fix test for 32bit platforms
|
|
|
|
|
if _W == 32 {
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
2014-12-08 14:36:39 -08:00
|
|
|
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) {
|
2015-01-23 21:40:35 -08:00
|
|
|
// TODO(gri) fix test for 32bit platforms
|
|
|
|
|
if _W == 32 {
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
2014-12-08 14:36:39 -08:00
|
|
|
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) {
|
2015-01-23 21:40:35 -08:00
|
|
|
// TODO(gri) fix test for 32bit platforms
|
|
|
|
|
if _W == 32 {
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
2014-12-08 14:36:39 -08:00
|
|
|
// 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) {
|
2015-01-23 21:40:35 -08:00
|
|
|
// TODO(gri) fix test for 32bit platforms
|
|
|
|
|
if _W == 32 {
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
2014-12-08 14:36:39 -08:00
|
|
|
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)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|