github.com/twelsh-aw/go/src@v0.0.0-20230516233729-a56fe86a7c81/math/big/bits_test.go (about) 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 "sort" 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 sort.Ints([]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 }