...

Source file src/math/big/bits_test.go

Documentation: math/big

     1  // Copyright 2015 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  // This file implements the Bits type used for testing Float operations
     6  // via an independent (albeit slower) representations for floating-point
     7  // numbers.
     8  
     9  package big
    10  
    11  import (
    12  	"fmt"
    13  	"slices"
    14  	"testing"
    15  )
    16  
    17  // A Bits value b represents a finite floating-point number x of the form
    18  //
    19  //	x = 2**b[0] + 2**b[1] + ... 2**b[len(b)-1]
    20  //
    21  // The order of slice elements is not significant. Negative elements may be
    22  // used to form fractions. A Bits value is normalized if each b[i] occurs at
    23  // most once. For instance Bits{0, 0, 1} is not normalized but represents the
    24  // same floating-point number as Bits{2}, which is normalized. The zero (nil)
    25  // value of Bits is a ready to use Bits value and represents the value 0.
    26  type Bits []int
    27  
    28  func (x Bits) add(y Bits) Bits {
    29  	return append(x, y...)
    30  }
    31  
    32  func (x Bits) mul(y Bits) Bits {
    33  	var p Bits
    34  	for _, x := range x {
    35  		for _, y := range y {
    36  			p = append(p, x+y)
    37  		}
    38  	}
    39  	return p
    40  }
    41  
    42  func TestMulBits(t *testing.T) {
    43  	for _, test := range []struct {
    44  		x, y, want Bits
    45  	}{
    46  		{nil, nil, nil},
    47  		{Bits{}, Bits{}, nil},
    48  		{Bits{0}, Bits{0}, Bits{0}},
    49  		{Bits{0}, Bits{1}, Bits{1}},
    50  		{Bits{1}, Bits{1, 2, 3}, Bits{2, 3, 4}},
    51  		{Bits{-1}, Bits{1}, Bits{0}},
    52  		{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}},
    53  	} {
    54  		got := fmt.Sprintf("%v", test.x.mul(test.y))
    55  		want := fmt.Sprintf("%v", test.want)
    56  		if got != want {
    57  			t.Errorf("%v * %v = %s; want %s", test.x, test.y, got, want)
    58  		}
    59  
    60  	}
    61  }
    62  
    63  // norm returns the normalized bits for x: It removes multiple equal entries
    64  // by treating them as an addition (e.g., Bits{5, 5} => Bits{6}), and it sorts
    65  // the result list for reproducible results.
    66  func (x Bits) norm() Bits {
    67  	m := make(map[int]bool)
    68  	for _, b := range x {
    69  		for m[b] {
    70  			m[b] = false
    71  			b++
    72  		}
    73  		m[b] = true
    74  	}
    75  	var z Bits
    76  	for b, set := range m {
    77  		if set {
    78  			z = append(z, b)
    79  		}
    80  	}
    81  	slices.Sort([]int(z))
    82  	return z
    83  }
    84  
    85  func TestNormBits(t *testing.T) {
    86  	for _, test := range []struct {
    87  		x, want Bits
    88  	}{
    89  		{nil, nil},
    90  		{Bits{}, Bits{}},
    91  		{Bits{0}, Bits{0}},
    92  		{Bits{0, 0}, Bits{1}},
    93  		{Bits{3, 1, 1}, Bits{2, 3}},
    94  		{Bits{10, 9, 8, 7, 6, 6}, Bits{11}},
    95  	} {
    96  		got := fmt.Sprintf("%v", test.x.norm())
    97  		want := fmt.Sprintf("%v", test.want)
    98  		if got != want {
    99  			t.Errorf("normBits(%v) = %s; want %s", test.x, got, want)
   100  		}
   101  
   102  	}
   103  }
   104  
   105  // round returns the Float value corresponding to x after rounding x
   106  // to prec bits according to mode.
   107  func (x Bits) round(prec uint, mode RoundingMode) *Float {
   108  	x = x.norm()
   109  
   110  	// determine range
   111  	var min, max int
   112  	for i, b := range x {
   113  		if i == 0 || b < min {
   114  			min = b
   115  		}
   116  		if i == 0 || b > max {
   117  			max = b
   118  		}
   119  	}
   120  	prec0 := uint(max + 1 - min)
   121  	if prec >= prec0 {
   122  		return x.Float()
   123  	}
   124  	// prec < prec0
   125  
   126  	// determine bit 0, rounding, and sticky bit, and result bits z
   127  	var bit0, rbit, sbit uint
   128  	var z Bits
   129  	r := max - int(prec)
   130  	for _, b := range x {
   131  		switch {
   132  		case b == r:
   133  			rbit = 1
   134  		case b < r:
   135  			sbit = 1
   136  		default:
   137  			// b > r
   138  			if b == r+1 {
   139  				bit0 = 1
   140  			}
   141  			z = append(z, b)
   142  		}
   143  	}
   144  
   145  	// round
   146  	f := z.Float() // rounded to zero
   147  	if mode == ToNearestAway {
   148  		panic("not yet implemented")
   149  	}
   150  	if mode == ToNearestEven && rbit == 1 && (sbit == 1 || sbit == 0 && bit0 != 0) || mode == AwayFromZero {
   151  		// round away from zero
   152  		f.SetMode(ToZero).SetPrec(prec)
   153  		f.Add(f, Bits{int(r) + 1}.Float())
   154  	}
   155  	return f
   156  }
   157  
   158  // Float returns the *Float z of the smallest possible precision such that
   159  // z = sum(2**bits[i]), with i = range bits. If multiple bits[i] are equal,
   160  // they are added: Bits{0, 1, 0}.Float() == 2**0 + 2**1 + 2**0 = 4.
   161  func (bits Bits) Float() *Float {
   162  	// handle 0
   163  	if len(bits) == 0 {
   164  		return new(Float)
   165  	}
   166  	// len(bits) > 0
   167  
   168  	// determine lsb exponent
   169  	var min int
   170  	for i, b := range bits {
   171  		if i == 0 || b < min {
   172  			min = b
   173  		}
   174  	}
   175  
   176  	// create bit pattern
   177  	x := NewInt(0)
   178  	for _, b := range bits {
   179  		badj := b - min
   180  		// propagate carry if necessary
   181  		for x.Bit(badj) != 0 {
   182  			x.SetBit(x, badj, 0)
   183  			badj++
   184  		}
   185  		x.SetBit(x, badj, 1)
   186  	}
   187  
   188  	// create corresponding float
   189  	z := new(Float).SetInt(x) // normalized
   190  	if e := int64(z.exp) + int64(min); MinExp <= e && e <= MaxExp {
   191  		z.exp = int32(e)
   192  	} else {
   193  		// this should never happen for our test cases
   194  		panic("exponent out of range")
   195  	}
   196  	return z
   197  }
   198  
   199  func TestFromBits(t *testing.T) {
   200  	for _, test := range []struct {
   201  		bits Bits
   202  		want string
   203  	}{
   204  		// all different bit numbers
   205  		{nil, "0"},
   206  		{Bits{0}, "0x.8p+1"},
   207  		{Bits{1}, "0x.8p+2"},
   208  		{Bits{-1}, "0x.8p+0"},
   209  		{Bits{63}, "0x.8p+64"},
   210  		{Bits{33, -30}, "0x.8000000000000001p+34"},
   211  		{Bits{255, 0}, "0x.8000000000000000000000000000000000000000000000000000000000000001p+256"},
   212  
   213  		// multiple equal bit numbers
   214  		{Bits{0, 0}, "0x.8p+2"},
   215  		{Bits{0, 0, 0, 0}, "0x.8p+3"},
   216  		{Bits{0, 1, 0}, "0x.8p+3"},
   217  		{append(Bits{2, 1, 0} /* 7 */, Bits{3, 1} /* 10 */ ...), "0x.88p+5" /* 17 */},
   218  	} {
   219  		f := test.bits.Float()
   220  		if got := f.Text('p', 0); got != test.want {
   221  			t.Errorf("setBits(%v) = %s; want %s", test.bits, got, test.want)
   222  		}
   223  	}
   224  }
   225  

View as plain text