mirror of
https://github.com/autc04/Retro68.git
synced 2024-11-30 19:53:46 +00:00
225 lines
5.1 KiB
Go
225 lines
5.1 KiB
Go
// Copyright 2015 The Go Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style
|
|
// license that can be found in the LICENSE file.
|
|
|
|
// This file implements the Bits type used for testing Float operations
|
|
// via an independent (albeit slower) representations for floating-point
|
|
// numbers.
|
|
|
|
package big
|
|
|
|
import (
|
|
"fmt"
|
|
"sort"
|
|
"testing"
|
|
)
|
|
|
|
// A Bits value b represents a finite floating-point number x of the form
|
|
//
|
|
// x = 2**b[0] + 2**b[1] + ... 2**b[len(b)-1]
|
|
//
|
|
// The order of slice elements is not significant. Negative elements may be
|
|
// used to form fractions. A Bits value is normalized if each b[i] occurs at
|
|
// most once. For instance Bits{0, 0, 1} is not normalized but represents the
|
|
// same floating-point number as Bits{2}, which is normalized. The zero (nil)
|
|
// value of Bits is a ready to use Bits value and represents the value 0.
|
|
type Bits []int
|
|
|
|
func (x Bits) add(y Bits) Bits {
|
|
return append(x, y...)
|
|
}
|
|
|
|
func (x Bits) mul(y Bits) Bits {
|
|
var p Bits
|
|
for _, x := range x {
|
|
for _, y := range y {
|
|
p = append(p, x+y)
|
|
}
|
|
}
|
|
return p
|
|
}
|
|
|
|
func TestMulBits(t *testing.T) {
|
|
for _, test := range []struct {
|
|
x, y, want Bits
|
|
}{
|
|
{nil, nil, nil},
|
|
{Bits{}, Bits{}, nil},
|
|
{Bits{0}, Bits{0}, Bits{0}},
|
|
{Bits{0}, Bits{1}, Bits{1}},
|
|
{Bits{1}, Bits{1, 2, 3}, Bits{2, 3, 4}},
|
|
{Bits{-1}, Bits{1}, Bits{0}},
|
|
{Bits{-10, -1, 0, 1, 10}, Bits{1, 2, 3}, Bits{-9, -8, -7, 0, 1, 2, 1, 2, 3, 2, 3, 4, 11, 12, 13}},
|
|
} {
|
|
got := fmt.Sprintf("%v", test.x.mul(test.y))
|
|
want := fmt.Sprintf("%v", test.want)
|
|
if got != want {
|
|
t.Errorf("%v * %v = %s; want %s", test.x, test.y, got, want)
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
// norm returns the normalized bits for x: It removes multiple equal entries
|
|
// by treating them as an addition (e.g., Bits{5, 5} => Bits{6}), and it sorts
|
|
// the result list for reproducible results.
|
|
func (x Bits) norm() Bits {
|
|
m := make(map[int]bool)
|
|
for _, b := range x {
|
|
for m[b] {
|
|
m[b] = false
|
|
b++
|
|
}
|
|
m[b] = true
|
|
}
|
|
var z Bits
|
|
for b, set := range m {
|
|
if set {
|
|
z = append(z, b)
|
|
}
|
|
}
|
|
sort.Ints([]int(z))
|
|
return z
|
|
}
|
|
|
|
func TestNormBits(t *testing.T) {
|
|
for _, test := range []struct {
|
|
x, want Bits
|
|
}{
|
|
{nil, nil},
|
|
{Bits{}, Bits{}},
|
|
{Bits{0}, Bits{0}},
|
|
{Bits{0, 0}, Bits{1}},
|
|
{Bits{3, 1, 1}, Bits{2, 3}},
|
|
{Bits{10, 9, 8, 7, 6, 6}, Bits{11}},
|
|
} {
|
|
got := fmt.Sprintf("%v", test.x.norm())
|
|
want := fmt.Sprintf("%v", test.want)
|
|
if got != want {
|
|
t.Errorf("normBits(%v) = %s; want %s", test.x, got, want)
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
// round returns the Float value corresponding to x after rounding x
|
|
// to prec bits according to mode.
|
|
func (x Bits) round(prec uint, mode RoundingMode) *Float {
|
|
x = x.norm()
|
|
|
|
// 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 x.Float()
|
|
}
|
|
// prec < prec0
|
|
|
|
// determine bit 0, rounding, and sticky bit, and result bits z
|
|
var bit0, rbit, sbit uint
|
|
var z Bits
|
|
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 := z.Float() // 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.SetMode(ToZero).SetPrec(prec)
|
|
f.Add(f, Bits{int(r) + 1}.Float())
|
|
}
|
|
return f
|
|
}
|
|
|
|
// Float 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: Bits{0, 1, 0}.Float() == 2**0 + 2**1 + 2**0 = 4.
|
|
func (bits Bits) Float() *Float {
|
|
// handle 0
|
|
if len(bits) == 0 {
|
|
return new(Float)
|
|
}
|
|
// 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
|
|
if e := int64(z.exp) + int64(min); MinExp <= e && e <= MaxExp {
|
|
z.exp = int32(e)
|
|
} else {
|
|
// this should never happen for our test cases
|
|
panic("exponent out of range")
|
|
}
|
|
return z
|
|
}
|
|
|
|
func TestFromBits(t *testing.T) {
|
|
for _, test := range []struct {
|
|
bits Bits
|
|
want string
|
|
}{
|
|
// all different bit numbers
|
|
{nil, "0"},
|
|
{Bits{0}, "0x.8p+1"},
|
|
{Bits{1}, "0x.8p+2"},
|
|
{Bits{-1}, "0x.8p+0"},
|
|
{Bits{63}, "0x.8p+64"},
|
|
{Bits{33, -30}, "0x.8000000000000001p+34"},
|
|
{Bits{255, 0}, "0x.8000000000000000000000000000000000000000000000000000000000000001p+256"},
|
|
|
|
// multiple equal bit numbers
|
|
{Bits{0, 0}, "0x.8p+2"},
|
|
{Bits{0, 0, 0, 0}, "0x.8p+3"},
|
|
{Bits{0, 1, 0}, "0x.8p+3"},
|
|
{append(Bits{2, 1, 0} /* 7 */, Bits{3, 1} /* 10 */ ...), "0x.88p+5" /* 17 */},
|
|
} {
|
|
f := test.bits.Float()
|
|
if got := f.Text('p', 0); got != test.want {
|
|
t.Errorf("setBits(%v) = %s; want %s", test.bits, got, test.want)
|
|
}
|
|
}
|
|
}
|