Robert Griesemer | bd275b2 | 2014-12-08 14:36:39 -0800 | [diff] [blame] | 1 | // Copyright 2014 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 | package big |
| 6 | |
| 7 | import ( |
| 8 | "fmt" |
Robert Griesemer | 15594df | 2015-02-05 17:21:48 -0800 | [diff] [blame] | 9 | "math" |
Robert Griesemer | bd275b2 | 2014-12-08 14:36:39 -0800 | [diff] [blame] | 10 | "sort" |
| 11 | "strconv" |
Robert Griesemer | f77696a | 2015-02-09 16:59:31 -0800 | [diff] [blame] | 12 | "strings" |
Robert Griesemer | bd275b2 | 2014-12-08 14:36:39 -0800 | [diff] [blame] | 13 | "testing" |
| 14 | ) |
| 15 | |
Robert Griesemer | 15594df | 2015-02-05 17:21:48 -0800 | [diff] [blame] | 16 | func TestFloatZeroValue(t *testing.T) { |
| 17 | // zero (uninitialized) value is a ready-to-use 0.0 |
| 18 | var x Float |
| 19 | if s := x.Format('f', 1); s != "0.0" { |
| 20 | t.Errorf("zero value = %s; want 0.0", s) |
| 21 | } |
| 22 | |
| 23 | // zero value has precision 0 |
| 24 | if prec := x.Precision(); prec != 0 { |
| 25 | t.Errorf("prec = %d; want 0", prec) |
| 26 | } |
| 27 | |
| 28 | // zero value can be used in any and all positions of binary operations |
| 29 | make := func(x int) *Float { |
| 30 | if x == 0 { |
| 31 | return new(Float) // 0 translates into the zero value |
| 32 | } |
| 33 | return NewFloat(float64(x), 10, 0) |
| 34 | } |
| 35 | for _, test := range []struct { |
| 36 | z, x, y, want int |
| 37 | opname rune |
| 38 | op func(z, x, y *Float) *Float |
| 39 | }{ |
| 40 | {0, 0, 0, 0, '+', (*Float).Add}, |
| 41 | {0, 1, 2, 3, '+', (*Float).Add}, |
| 42 | {1, 2, 0, 2, '+', (*Float).Add}, |
| 43 | {2, 0, 1, 1, '+', (*Float).Add}, |
| 44 | |
| 45 | {0, 0, 0, 0, '-', (*Float).Sub}, |
| 46 | {0, 1, 2, -1, '-', (*Float).Sub}, |
| 47 | {1, 2, 0, 2, '-', (*Float).Sub}, |
| 48 | {2, 0, 1, -1, '-', (*Float).Sub}, |
| 49 | |
| 50 | {0, 0, 0, 0, '*', (*Float).Mul}, |
| 51 | {0, 1, 2, 2, '*', (*Float).Mul}, |
| 52 | {1, 2, 0, 0, '*', (*Float).Mul}, |
| 53 | {2, 0, 1, 0, '*', (*Float).Mul}, |
| 54 | |
| 55 | {0, 0, 0, 0, '/', (*Float).Quo}, |
| 56 | {0, 2, 1, 2, '/', (*Float).Quo}, |
| 57 | {1, 2, 0, 0, '/', (*Float).Quo}, |
| 58 | {2, 0, 1, 0, '/', (*Float).Quo}, |
| 59 | } { |
| 60 | z := make(test.z) |
| 61 | test.op(z, make(test.x), make(test.y)) |
| 62 | if got := int(z.Int64()); got != test.want { |
| 63 | t.Errorf("%d %c %d = %d; want %d", test.x, test.opname, test.y, got, test.want) |
| 64 | } |
| 65 | } |
| 66 | |
| 67 | // TODO(gri) test how precision is set for zero value results |
| 68 | } |
| 69 | |
Robert Griesemer | f77696a | 2015-02-09 16:59:31 -0800 | [diff] [blame] | 70 | func makeFloat(s string) *Float { |
| 71 | if s == "Inf" || s == "+Inf" { |
| 72 | return NewInf(+1) |
| 73 | } |
| 74 | if s == "-Inf" { |
| 75 | return NewInf(-1) |
| 76 | } |
| 77 | var x Float |
| 78 | x.prec = 100 // TODO(gri) find a better way to do this |
| 79 | if _, ok := x.SetString(s); !ok { |
| 80 | panic(fmt.Sprintf("%q is not a valid float", s)) |
| 81 | } |
| 82 | return &x |
| 83 | } |
| 84 | |
| 85 | func TestFloatSign(t *testing.T) { |
| 86 | for _, test := range []struct { |
| 87 | x string |
| 88 | s int |
| 89 | }{ |
| 90 | {"-Inf", -1}, |
| 91 | {"-1", -1}, |
| 92 | {"-0", 0}, |
| 93 | {"+0", 0}, |
| 94 | {"+1", +1}, |
| 95 | {"+Inf", +1}, |
| 96 | } { |
| 97 | x := makeFloat(test.x) |
| 98 | s := x.Sign() |
| 99 | if s != test.s { |
| 100 | t.Errorf("%s.Sign() = %d; want %d", test.x, s, test.s) |
| 101 | } |
| 102 | } |
| 103 | } |
| 104 | |
| 105 | // feq(x, y) is like x.Cmp(y) == 0 but it also considers the sign of 0 (0 != -0). |
| 106 | func feq(x, y *Float) bool { |
| 107 | return x.Cmp(y) == 0 && x.neg == y.neg |
| 108 | } |
| 109 | |
| 110 | func TestFloatMantExp(t *testing.T) { |
| 111 | for _, test := range []struct { |
| 112 | x string |
| 113 | frac string |
| 114 | exp int |
| 115 | }{ |
| 116 | {"0", "0", 0}, |
| 117 | {"+0", "0", 0}, |
| 118 | {"-0", "-0", 0}, |
| 119 | {"Inf", "+Inf", 0}, |
| 120 | {"+Inf", "+Inf", 0}, |
| 121 | {"-Inf", "-Inf", 0}, |
| 122 | {"1.5", "0.75", 1}, |
| 123 | {"1.024e3", "0.5", 11}, |
| 124 | {"-0.125", "-0.5", -2}, |
| 125 | } { |
| 126 | x := makeFloat(test.x) |
| 127 | frac := makeFloat(test.frac) |
| 128 | f, e := x.MantExp() |
| 129 | if !feq(f, frac) || e != test.exp { |
| 130 | t.Errorf("%s.MantExp() = %s, %d; want %s, %d", test.x, f.Format('g', 10), e, test.frac, test.exp) |
| 131 | } |
| 132 | } |
| 133 | } |
| 134 | |
| 135 | func TestFloatSetMantExp(t *testing.T) { |
| 136 | for _, test := range []struct { |
| 137 | frac string |
| 138 | exp int |
| 139 | z string |
| 140 | }{ |
| 141 | {"0", 0, "0"}, |
| 142 | {"+0", 0, "0"}, |
| 143 | {"-0", 0, "-0"}, |
| 144 | {"Inf", 1234, "+Inf"}, |
| 145 | {"+Inf", -1234, "+Inf"}, |
| 146 | {"-Inf", -1234, "-Inf"}, |
| 147 | {"0", -MaxExp - 1, "0"}, |
| 148 | {"1", -MaxExp - 1, "+Inf"}, // exponent magnitude too large |
| 149 | {"-1", -MaxExp - 1, "-Inf"}, // exponent magnitude too large |
| 150 | {"0.75", 1, "1.5"}, |
| 151 | {"0.5", 11, "1024"}, |
| 152 | {"-0.5", -2, "-0.125"}, |
| 153 | } { |
| 154 | frac := makeFloat(test.frac) |
| 155 | want := makeFloat(test.z) |
| 156 | var z Float |
| 157 | z.SetMantExp(frac, test.exp) |
| 158 | if !feq(&z, want) { |
| 159 | t.Errorf("SetMantExp(%s, %d) = %s; want %s", test.frac, test.exp, z.Format('g', 10), test.z) |
| 160 | } |
| 161 | } |
| 162 | } |
| 163 | |
| 164 | func TestFloatIsInt(t *testing.T) { |
| 165 | for _, test := range []string{ |
| 166 | "0 int", |
| 167 | "-0 int", |
| 168 | "1 int", |
| 169 | "-1 int", |
| 170 | "0.5", |
| 171 | "1.23", |
| 172 | "1.23e1", |
| 173 | "1.23e2 int", |
| 174 | "0.000000001e+8", |
| 175 | "0.000000001e+9 int", |
| 176 | "1.2345e200 int", |
| 177 | "Inf", |
| 178 | "+Inf", |
| 179 | "-Inf", |
| 180 | } { |
| 181 | s := strings.TrimSuffix(test, " int") |
| 182 | want := s != test |
| 183 | if got := makeFloat(s).IsInt(); got != want { |
| 184 | t.Errorf("%s.IsInt() == %t", s, got) |
| 185 | } |
| 186 | } |
| 187 | } |
| 188 | |
| 189 | func TestFloatIsInf(t *testing.T) { |
Robert Griesemer | 15594df | 2015-02-05 17:21:48 -0800 | [diff] [blame] | 190 | // TODO(gri) implement this |
| 191 | } |
| 192 | |
Robert Griesemer | bd275b2 | 2014-12-08 14:36:39 -0800 | [diff] [blame] | 193 | func fromBinary(s string) int64 { |
| 194 | x, err := strconv.ParseInt(s, 2, 64) |
| 195 | if err != nil { |
| 196 | panic(err) |
| 197 | } |
| 198 | return x |
| 199 | } |
| 200 | |
| 201 | func toBinary(x int64) string { |
| 202 | return strconv.FormatInt(x, 2) |
| 203 | } |
| 204 | |
| 205 | func testFloatRound(t *testing.T, x, r int64, prec uint, mode RoundingMode) { |
| 206 | // verify test data |
| 207 | var ok bool |
| 208 | switch mode { |
| 209 | case ToNearestEven, ToNearestAway: |
| 210 | ok = true // nothing to do for now |
| 211 | case ToZero: |
| 212 | if x < 0 { |
| 213 | ok = r >= x |
| 214 | } else { |
| 215 | ok = r <= x |
| 216 | } |
| 217 | case AwayFromZero: |
| 218 | if x < 0 { |
| 219 | ok = r <= x |
| 220 | } else { |
| 221 | ok = r >= x |
| 222 | } |
| 223 | case ToNegativeInf: |
| 224 | ok = r <= x |
| 225 | case ToPositiveInf: |
| 226 | ok = r >= x |
| 227 | default: |
| 228 | panic("unreachable") |
| 229 | } |
| 230 | if !ok { |
| 231 | t.Fatalf("incorrect test data for prec = %d, %s: x = %s, r = %s", prec, mode, toBinary(x), toBinary(r)) |
| 232 | } |
| 233 | |
| 234 | // compute expected accuracy |
| 235 | a := Exact |
| 236 | switch { |
| 237 | case r < x: |
| 238 | a = Below |
| 239 | case r > x: |
| 240 | a = Above |
| 241 | } |
| 242 | |
| 243 | // round |
| 244 | f := new(Float).SetInt64(x) |
| 245 | f.Round(f, prec, mode) |
| 246 | |
| 247 | // check result |
| 248 | r1 := f.Int64() |
| 249 | p1 := f.Precision() |
| 250 | a1 := f.Accuracy() |
| 251 | if r1 != r || p1 != prec || a1 != a { |
| 252 | t.Errorf("Round(%s, %d, %s): got %s (%d bits, %s); want %s (%d bits, %s)", |
| 253 | toBinary(x), prec, mode, |
| 254 | toBinary(r1), p1, a1, |
| 255 | toBinary(r), prec, a) |
| 256 | } |
| 257 | } |
| 258 | |
| 259 | // TestFloatRound tests basic rounding. |
| 260 | func TestFloatRound(t *testing.T) { |
Robert Griesemer | 9f22de7 | 2015-01-28 17:11:15 -0800 | [diff] [blame] | 261 | for _, test := range []struct { |
Robert Griesemer | bd275b2 | 2014-12-08 14:36:39 -0800 | [diff] [blame] | 262 | prec uint |
| 263 | x, zero, neven, naway, away string // input, results rounded to prec bits |
| 264 | }{ |
| 265 | {5, "1000", "1000", "1000", "1000", "1000"}, |
| 266 | {5, "1001", "1001", "1001", "1001", "1001"}, |
| 267 | {5, "1010", "1010", "1010", "1010", "1010"}, |
| 268 | {5, "1011", "1011", "1011", "1011", "1011"}, |
| 269 | {5, "1100", "1100", "1100", "1100", "1100"}, |
| 270 | {5, "1101", "1101", "1101", "1101", "1101"}, |
| 271 | {5, "1110", "1110", "1110", "1110", "1110"}, |
| 272 | {5, "1111", "1111", "1111", "1111", "1111"}, |
| 273 | |
| 274 | {4, "1000", "1000", "1000", "1000", "1000"}, |
| 275 | {4, "1001", "1001", "1001", "1001", "1001"}, |
| 276 | {4, "1010", "1010", "1010", "1010", "1010"}, |
| 277 | {4, "1011", "1011", "1011", "1011", "1011"}, |
| 278 | {4, "1100", "1100", "1100", "1100", "1100"}, |
| 279 | {4, "1101", "1101", "1101", "1101", "1101"}, |
| 280 | {4, "1110", "1110", "1110", "1110", "1110"}, |
| 281 | {4, "1111", "1111", "1111", "1111", "1111"}, |
| 282 | |
| 283 | {3, "1000", "1000", "1000", "1000", "1000"}, |
| 284 | {3, "1001", "1000", "1000", "1010", "1010"}, |
| 285 | {3, "1010", "1010", "1010", "1010", "1010"}, |
| 286 | {3, "1011", "1010", "1100", "1100", "1100"}, |
| 287 | {3, "1100", "1100", "1100", "1100", "1100"}, |
| 288 | {3, "1101", "1100", "1100", "1110", "1110"}, |
| 289 | {3, "1110", "1110", "1110", "1110", "1110"}, |
| 290 | {3, "1111", "1110", "10000", "10000", "10000"}, |
| 291 | |
| 292 | {3, "1000001", "1000000", "1000000", "1000000", "1010000"}, |
| 293 | {3, "1001001", "1000000", "1010000", "1010000", "1010000"}, |
| 294 | {3, "1010001", "1010000", "1010000", "1010000", "1100000"}, |
| 295 | {3, "1011001", "1010000", "1100000", "1100000", "1100000"}, |
| 296 | {3, "1100001", "1100000", "1100000", "1100000", "1110000"}, |
| 297 | {3, "1101001", "1100000", "1110000", "1110000", "1110000"}, |
| 298 | {3, "1110001", "1110000", "1110000", "1110000", "10000000"}, |
| 299 | {3, "1111001", "1110000", "10000000", "10000000", "10000000"}, |
| 300 | |
| 301 | {2, "1000", "1000", "1000", "1000", "1000"}, |
| 302 | {2, "1001", "1000", "1000", "1000", "1100"}, |
| 303 | {2, "1010", "1000", "1000", "1100", "1100"}, |
| 304 | {2, "1011", "1000", "1100", "1100", "1100"}, |
| 305 | {2, "1100", "1100", "1100", "1100", "1100"}, |
| 306 | {2, "1101", "1100", "1100", "1100", "10000"}, |
| 307 | {2, "1110", "1100", "10000", "10000", "10000"}, |
| 308 | {2, "1111", "1100", "10000", "10000", "10000"}, |
| 309 | |
| 310 | {2, "1000001", "1000000", "1000000", "1000000", "1100000"}, |
| 311 | {2, "1001001", "1000000", "1000000", "1000000", "1100000"}, |
| 312 | {2, "1010001", "1000000", "1100000", "1100000", "1100000"}, |
| 313 | {2, "1011001", "1000000", "1100000", "1100000", "1100000"}, |
| 314 | {2, "1100001", "1100000", "1100000", "1100000", "10000000"}, |
| 315 | {2, "1101001", "1100000", "1100000", "1100000", "10000000"}, |
| 316 | {2, "1110001", "1100000", "10000000", "10000000", "10000000"}, |
| 317 | {2, "1111001", "1100000", "10000000", "10000000", "10000000"}, |
| 318 | |
| 319 | {1, "1000", "1000", "1000", "1000", "1000"}, |
| 320 | {1, "1001", "1000", "1000", "1000", "10000"}, |
| 321 | {1, "1010", "1000", "1000", "1000", "10000"}, |
| 322 | {1, "1011", "1000", "1000", "1000", "10000"}, |
| 323 | {1, "1100", "1000", "10000", "10000", "10000"}, |
| 324 | {1, "1101", "1000", "10000", "10000", "10000"}, |
| 325 | {1, "1110", "1000", "10000", "10000", "10000"}, |
| 326 | {1, "1111", "1000", "10000", "10000", "10000"}, |
| 327 | |
| 328 | {1, "1000001", "1000000", "1000000", "1000000", "10000000"}, |
| 329 | {1, "1001001", "1000000", "1000000", "1000000", "10000000"}, |
| 330 | {1, "1010001", "1000000", "1000000", "1000000", "10000000"}, |
| 331 | {1, "1011001", "1000000", "1000000", "1000000", "10000000"}, |
| 332 | {1, "1100001", "1000000", "10000000", "10000000", "10000000"}, |
| 333 | {1, "1101001", "1000000", "10000000", "10000000", "10000000"}, |
| 334 | {1, "1110001", "1000000", "10000000", "10000000", "10000000"}, |
| 335 | {1, "1111001", "1000000", "10000000", "10000000", "10000000"}, |
Robert Griesemer | 9f22de7 | 2015-01-28 17:11:15 -0800 | [diff] [blame] | 336 | } { |
Robert Griesemer | bd275b2 | 2014-12-08 14:36:39 -0800 | [diff] [blame] | 337 | x := fromBinary(test.x) |
| 338 | z := fromBinary(test.zero) |
| 339 | e := fromBinary(test.neven) |
| 340 | n := fromBinary(test.naway) |
| 341 | a := fromBinary(test.away) |
| 342 | prec := test.prec |
| 343 | |
| 344 | testFloatRound(t, x, z, prec, ToZero) |
| 345 | testFloatRound(t, x, e, prec, ToNearestEven) |
| 346 | testFloatRound(t, x, n, prec, ToNearestAway) |
| 347 | testFloatRound(t, x, a, prec, AwayFromZero) |
| 348 | |
| 349 | testFloatRound(t, x, z, prec, ToNegativeInf) |
| 350 | testFloatRound(t, x, a, prec, ToPositiveInf) |
| 351 | |
| 352 | testFloatRound(t, -x, -a, prec, ToNegativeInf) |
| 353 | testFloatRound(t, -x, -z, prec, ToPositiveInf) |
| 354 | } |
| 355 | } |
| 356 | |
| 357 | // TestFloatRound24 tests that rounding a float64 to 24 bits |
| 358 | // matches IEEE-754 rounding to nearest when converting a |
| 359 | // float64 to a float32. |
| 360 | func TestFloatRound24(t *testing.T) { |
| 361 | const x0 = 1<<26 - 0x10 // 11...110000 (26 bits) |
| 362 | for d := 0; d <= 0x10; d++ { |
| 363 | x := float64(x0 + d) |
| 364 | f := new(Float).SetFloat64(x) |
| 365 | f.Round(f, 24, ToNearestEven) |
| 366 | got, _ := f.Float64() |
| 367 | want := float64(float32(x)) |
| 368 | if got != want { |
| 369 | t.Errorf("Round(%g, 24) = %g; want %g", x, got, want) |
| 370 | } |
| 371 | } |
| 372 | } |
| 373 | |
| 374 | func TestFloatSetUint64(t *testing.T) { |
Robert Griesemer | 9f22de7 | 2015-01-28 17:11:15 -0800 | [diff] [blame] | 375 | for _, want := range []uint64{ |
Robert Griesemer | bd275b2 | 2014-12-08 14:36:39 -0800 | [diff] [blame] | 376 | 0, |
| 377 | 1, |
| 378 | 2, |
| 379 | 10, |
| 380 | 100, |
| 381 | 1<<32 - 1, |
| 382 | 1 << 32, |
| 383 | 1<<64 - 1, |
Robert Griesemer | 9f22de7 | 2015-01-28 17:11:15 -0800 | [diff] [blame] | 384 | } { |
Robert Griesemer | acfe3a5 | 2015-02-06 16:51:00 -0800 | [diff] [blame] | 385 | var f Float |
| 386 | f.SetUint64(want) |
Robert Griesemer | bd275b2 | 2014-12-08 14:36:39 -0800 | [diff] [blame] | 387 | if got := f.Uint64(); got != want { |
Robert Griesemer | acfe3a5 | 2015-02-06 16:51:00 -0800 | [diff] [blame] | 388 | t.Errorf("got %#x (%s); want %#x", got, f.Format('p', 0), want) |
| 389 | } |
| 390 | } |
| 391 | |
| 392 | // test basic rounding behavior (exhaustive rounding testing is done elsewhere) |
| 393 | const x uint64 = 0x8765432187654321 // 64 bits needed |
| 394 | for prec := uint(1); prec <= 64; prec++ { |
| 395 | f := NewFloat(0, prec, ToZero).SetUint64(x) |
| 396 | got := f.Uint64() |
| 397 | want := x &^ (1<<(64-prec) - 1) // cut off (round to zero) low 64-prec bits |
| 398 | if got != want { |
| 399 | t.Errorf("got %#x (%s); want %#x", got, f.Format('p', 0), want) |
Robert Griesemer | bd275b2 | 2014-12-08 14:36:39 -0800 | [diff] [blame] | 400 | } |
| 401 | } |
| 402 | } |
| 403 | |
| 404 | func TestFloatSetInt64(t *testing.T) { |
Robert Griesemer | 9f22de7 | 2015-01-28 17:11:15 -0800 | [diff] [blame] | 405 | for _, want := range []int64{ |
Robert Griesemer | bd275b2 | 2014-12-08 14:36:39 -0800 | [diff] [blame] | 406 | 0, |
| 407 | 1, |
| 408 | 2, |
| 409 | 10, |
| 410 | 100, |
| 411 | 1<<32 - 1, |
| 412 | 1 << 32, |
| 413 | 1<<63 - 1, |
Robert Griesemer | 9f22de7 | 2015-01-28 17:11:15 -0800 | [diff] [blame] | 414 | } { |
Robert Griesemer | bd275b2 | 2014-12-08 14:36:39 -0800 | [diff] [blame] | 415 | for i := range [2]int{} { |
| 416 | if i&1 != 0 { |
| 417 | want = -want |
| 418 | } |
Robert Griesemer | acfe3a5 | 2015-02-06 16:51:00 -0800 | [diff] [blame] | 419 | var f Float |
| 420 | f.SetInt64(want) |
Robert Griesemer | bd275b2 | 2014-12-08 14:36:39 -0800 | [diff] [blame] | 421 | if got := f.Int64(); got != want { |
Robert Griesemer | acfe3a5 | 2015-02-06 16:51:00 -0800 | [diff] [blame] | 422 | t.Errorf("got %#x (%s); want %#x", got, f.Format('p', 0), want) |
Robert Griesemer | bd275b2 | 2014-12-08 14:36:39 -0800 | [diff] [blame] | 423 | } |
| 424 | } |
| 425 | } |
Robert Griesemer | acfe3a5 | 2015-02-06 16:51:00 -0800 | [diff] [blame] | 426 | |
| 427 | // test basic rounding behavior (exhaustive rounding testing is done elsewhere) |
| 428 | const x int64 = 0x7654321076543210 // 63 bits needed |
| 429 | for prec := uint(1); prec <= 63; prec++ { |
| 430 | f := NewFloat(0, prec, ToZero).SetInt64(x) |
| 431 | got := f.Int64() |
| 432 | want := x &^ (1<<(63-prec) - 1) // cut off (round to zero) low 63-prec bits |
| 433 | if got != want { |
| 434 | t.Errorf("got %#x (%s); want %#x", got, f.Format('p', 0), want) |
| 435 | } |
| 436 | } |
Robert Griesemer | bd275b2 | 2014-12-08 14:36:39 -0800 | [diff] [blame] | 437 | } |
| 438 | |
| 439 | func TestFloatSetFloat64(t *testing.T) { |
Robert Griesemer | 9f22de7 | 2015-01-28 17:11:15 -0800 | [diff] [blame] | 440 | for _, want := range []float64{ |
Robert Griesemer | bd275b2 | 2014-12-08 14:36:39 -0800 | [diff] [blame] | 441 | 0, |
| 442 | 1, |
| 443 | 2, |
| 444 | 12345, |
| 445 | 1e10, |
| 446 | 1e100, |
| 447 | 3.14159265e10, |
| 448 | 2.718281828e-123, |
| 449 | 1.0 / 3, |
Robert Griesemer | 15594df | 2015-02-05 17:21:48 -0800 | [diff] [blame] | 450 | math.Inf(-1), |
| 451 | math.Inf(0), |
| 452 | -math.Inf(1), |
Robert Griesemer | 9f22de7 | 2015-01-28 17:11:15 -0800 | [diff] [blame] | 453 | } { |
Robert Griesemer | bd275b2 | 2014-12-08 14:36:39 -0800 | [diff] [blame] | 454 | for i := range [2]int{} { |
| 455 | if i&1 != 0 { |
| 456 | want = -want |
| 457 | } |
Robert Griesemer | acfe3a5 | 2015-02-06 16:51:00 -0800 | [diff] [blame] | 458 | var f Float |
| 459 | f.SetFloat64(want) |
Robert Griesemer | bd275b2 | 2014-12-08 14:36:39 -0800 | [diff] [blame] | 460 | if got, _ := f.Float64(); got != want { |
Robert Griesemer | 4c91c0d | 2015-01-30 15:57:38 -0800 | [diff] [blame] | 461 | t.Errorf("got %g (%s); want %g", got, f.Format('p', 0), want) |
Robert Griesemer | bd275b2 | 2014-12-08 14:36:39 -0800 | [diff] [blame] | 462 | } |
| 463 | } |
| 464 | } |
Robert Griesemer | acfe3a5 | 2015-02-06 16:51:00 -0800 | [diff] [blame] | 465 | |
| 466 | // test basic rounding behavior (exhaustive rounding testing is done elsewhere) |
| 467 | const x uint64 = 0x8765432143218 // 53 bits needed |
| 468 | for prec := uint(1); prec <= 52; prec++ { |
| 469 | f := NewFloat(0, prec, ToZero).SetFloat64(float64(x)) |
| 470 | got, _ := f.Float64() |
| 471 | want := float64(x &^ (1<<(52-prec) - 1)) // cut off (round to zero) low 53-prec bits |
| 472 | if got != want { |
| 473 | t.Errorf("got %g (%s); want %g", got, f.Format('p', 0), want) |
| 474 | } |
| 475 | } |
Robert Griesemer | bd275b2 | 2014-12-08 14:36:39 -0800 | [diff] [blame] | 476 | } |
| 477 | |
| 478 | func TestFloatSetInt(t *testing.T) { |
Robert Griesemer | acfe3a5 | 2015-02-06 16:51:00 -0800 | [diff] [blame] | 479 | for _, want := range []string{ |
| 480 | "0", |
| 481 | "1", |
| 482 | "-1", |
| 483 | "1234567890", |
| 484 | "123456789012345678901234567890", |
| 485 | "123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890", |
| 486 | } { |
| 487 | var x Int |
| 488 | _, ok := x.SetString(want, 0) |
| 489 | if !ok { |
| 490 | t.Errorf("invalid integer %s", want) |
| 491 | continue |
| 492 | } |
| 493 | var f Float |
| 494 | f.SetInt(&x) |
| 495 | got := f.Format('g', 100) |
| 496 | if got != want { |
| 497 | t.Errorf("got %s (%s); want %s", got, f.Format('p', 0), want) |
| 498 | } |
| 499 | } |
| 500 | |
| 501 | // TODO(gri) test basic rounding behavior |
| 502 | } |
| 503 | |
| 504 | func TestFloatSetRat(t *testing.T) { |
| 505 | for _, want := range []string{ |
| 506 | "0", |
| 507 | "1", |
| 508 | "-1", |
| 509 | "1234567890", |
| 510 | "123456789012345678901234567890", |
| 511 | "123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890", |
| 512 | "1.2", |
| 513 | "3.14159265", |
| 514 | // TODO(gri) expand |
| 515 | } { |
| 516 | var x Rat |
| 517 | _, ok := x.SetString(want) |
| 518 | if !ok { |
| 519 | t.Errorf("invalid fraction %s", want) |
| 520 | continue |
| 521 | } |
| 522 | f := NewFloat(0, 1000, 0) // set a high precision - TODO(gri) find a cleaner way |
| 523 | f.SetRat(&x) |
| 524 | got := f.Format('g', 100) |
| 525 | if got != want { |
| 526 | t.Errorf("got %s (%s); want %s", got, f.Format('p', 0), want) |
| 527 | } |
| 528 | } |
Robert Griesemer | bd275b2 | 2014-12-08 14:36:39 -0800 | [diff] [blame] | 529 | } |
| 530 | |
| 531 | // Selected precisions with which to run various tests. |
| 532 | var precList = [...]uint{1, 2, 5, 8, 10, 16, 23, 24, 32, 50, 53, 64, 100, 128, 500, 511, 512, 513, 1000, 10000} |
| 533 | |
| 534 | // Selected bits with which to run various tests. |
| 535 | // Each entry is a list of bits representing a floating-point number (see fromBits). |
| 536 | var bitsList = [...][]int{ |
| 537 | {}, // = 0 |
| 538 | {0}, // = 1 |
| 539 | {1}, // = 2 |
| 540 | {-1}, // = 1/2 |
| 541 | {10}, // = 2**10 == 1024 |
| 542 | {-10}, // = 2**-10 == 1/1024 |
| 543 | {100, 10, 1}, // = 2**100 + 2**10 + 2**1 |
| 544 | {0, -1, -2, -10}, |
| 545 | // TODO(gri) add more test cases |
| 546 | } |
| 547 | |
| 548 | // TestFloatAdd tests Float.Add/Sub by comparing the result of a "manual" |
| 549 | // addition/subtraction of arguments represented by bits lists with the |
| 550 | // respective floating-point addition/subtraction for a variety of precisions |
| 551 | // and rounding modes. |
| 552 | func TestFloatAdd(t *testing.T) { |
| 553 | for _, xbits := range bitsList { |
| 554 | for _, ybits := range bitsList { |
| 555 | // exact values |
| 556 | x := fromBits(xbits...) |
| 557 | y := fromBits(ybits...) |
| 558 | zbits := append(xbits, ybits...) |
| 559 | z := fromBits(zbits...) |
| 560 | |
| 561 | for i, mode := range [...]RoundingMode{ToZero, ToNearestEven, AwayFromZero} { |
| 562 | for _, prec := range precList { |
Robert Griesemer | bd275b2 | 2014-12-08 14:36:39 -0800 | [diff] [blame] | 563 | got := NewFloat(0, prec, mode) |
| 564 | got.Add(x, y) |
| 565 | want := roundBits(zbits, prec, mode) |
| 566 | if got.Cmp(want) != 0 { |
| 567 | t.Errorf("i = %d, prec = %d, %s:\n\t %s %v\n\t+ %s %v\n\t= %s\n\twant %s", |
| 568 | i, prec, mode, x, xbits, y, ybits, got, want) |
| 569 | return |
| 570 | } |
| 571 | |
Robert Griesemer | bd275b2 | 2014-12-08 14:36:39 -0800 | [diff] [blame] | 572 | got.Sub(z, x) |
| 573 | want = roundBits(ybits, prec, mode) |
| 574 | if got.Cmp(want) != 0 { |
Robert Griesemer | f4a2617 | 2015-01-26 16:08:51 -0800 | [diff] [blame] | 575 | t.Errorf("i = %d, prec = %d, %s:\n\t %s %v\n\t- %s %v\n\t= %s\n\twant %s", |
| 576 | i, prec, mode, z, zbits, x, xbits, got, want) |
Robert Griesemer | bd275b2 | 2014-12-08 14:36:39 -0800 | [diff] [blame] | 577 | } |
| 578 | } |
| 579 | } |
| 580 | } |
| 581 | } |
| 582 | } |
| 583 | |
| 584 | // TestFloatAdd32 tests that Float.Add/Sub of numbers with |
| 585 | // 24bit mantissa behaves like float32 addition/subtraction. |
| 586 | func TestFloatAdd32(t *testing.T) { |
Robert Griesemer | 3acb9fd | 2015-01-23 21:40:35 -0800 | [diff] [blame] | 587 | // TODO(gri) fix test for 32bit platforms |
| 588 | if _W == 32 { |
| 589 | return |
| 590 | } |
| 591 | |
Robert Griesemer | bd275b2 | 2014-12-08 14:36:39 -0800 | [diff] [blame] | 592 | // chose base such that we cross the mantissa precision limit |
| 593 | const base = 1<<26 - 0x10 // 11...110000 (26 bits) |
| 594 | for d := 0; d <= 0x10; d++ { |
| 595 | for i := range [2]int{} { |
| 596 | x0, y0 := float64(base), float64(d) |
| 597 | if i&1 != 0 { |
| 598 | x0, y0 = y0, x0 |
| 599 | } |
| 600 | |
| 601 | x := new(Float).SetFloat64(x0) |
| 602 | y := new(Float).SetFloat64(y0) |
| 603 | z := NewFloat(0, 24, ToNearestEven) |
| 604 | |
| 605 | z.Add(x, y) |
| 606 | got, acc := z.Float64() |
| 607 | want := float64(float32(y0) + float32(x0)) |
| 608 | if got != want || acc != Exact { |
| 609 | t.Errorf("d = %d: %g + %g = %g (%s); want %g exactly", d, x0, y0, got, acc, want) |
| 610 | } |
| 611 | |
| 612 | z.Sub(z, y) |
| 613 | got, acc = z.Float64() |
| 614 | want = float64(float32(want) - float32(y0)) |
| 615 | if got != want || acc != Exact { |
| 616 | t.Errorf("d = %d: %g - %g = %g (%s); want %g exactly", d, x0+y0, y0, got, acc, want) |
| 617 | } |
| 618 | } |
| 619 | } |
| 620 | } |
| 621 | |
| 622 | // TestFloatAdd64 tests that Float.Add/Sub of numbers with |
| 623 | // 53bit mantissa behaves like float64 addition/subtraction. |
| 624 | func TestFloatAdd64(t *testing.T) { |
| 625 | // chose base such that we cross the mantissa precision limit |
| 626 | const base = 1<<55 - 0x10 // 11...110000 (55 bits) |
| 627 | for d := 0; d <= 0x10; d++ { |
| 628 | for i := range [2]int{} { |
| 629 | x0, y0 := float64(base), float64(d) |
| 630 | if i&1 != 0 { |
| 631 | x0, y0 = y0, x0 |
| 632 | } |
| 633 | |
| 634 | x := new(Float).SetFloat64(x0) |
| 635 | y := new(Float).SetFloat64(y0) |
| 636 | z := NewFloat(0, 53, ToNearestEven) |
| 637 | |
| 638 | z.Add(x, y) |
| 639 | got, acc := z.Float64() |
| 640 | want := x0 + y0 |
| 641 | if got != want || acc != Exact { |
Robert Griesemer | f4a2617 | 2015-01-26 16:08:51 -0800 | [diff] [blame] | 642 | t.Errorf("d = %d: %g + %g = %g (%s); want %g exactly", d, x0, y0, got, acc, want) |
Robert Griesemer | bd275b2 | 2014-12-08 14:36:39 -0800 | [diff] [blame] | 643 | } |
| 644 | |
| 645 | z.Sub(z, y) |
| 646 | got, acc = z.Float64() |
| 647 | want -= y0 |
| 648 | if got != want || acc != Exact { |
Robert Griesemer | f4a2617 | 2015-01-26 16:08:51 -0800 | [diff] [blame] | 649 | t.Errorf("d = %d: %g - %g = %g (%s); want %g exactly", d, x0+y0, y0, got, acc, want) |
Robert Griesemer | bd275b2 | 2014-12-08 14:36:39 -0800 | [diff] [blame] | 650 | } |
| 651 | } |
| 652 | } |
| 653 | } |
| 654 | |
| 655 | func TestFloatMul(t *testing.T) { |
| 656 | } |
| 657 | |
| 658 | // TestFloatMul64 tests that Float.Mul/Quo of numbers with |
| 659 | // 53bit mantissa behaves like float64 multiplication/division. |
| 660 | func TestFloatMul64(t *testing.T) { |
Robert Griesemer | 9f22de7 | 2015-01-28 17:11:15 -0800 | [diff] [blame] | 661 | for _, test := range []struct { |
Robert Griesemer | bd275b2 | 2014-12-08 14:36:39 -0800 | [diff] [blame] | 662 | x, y float64 |
| 663 | }{ |
| 664 | {0, 0}, |
| 665 | {0, 1}, |
| 666 | {1, 1}, |
| 667 | {1, 1.5}, |
| 668 | {1.234, 0.5678}, |
| 669 | {2.718281828, 3.14159265358979}, |
| 670 | {2.718281828e10, 3.14159265358979e-32}, |
| 671 | {1.0 / 3, 1e200}, |
Robert Griesemer | 9f22de7 | 2015-01-28 17:11:15 -0800 | [diff] [blame] | 672 | } { |
Robert Griesemer | bd275b2 | 2014-12-08 14:36:39 -0800 | [diff] [blame] | 673 | for i := range [8]int{} { |
| 674 | x0, y0 := test.x, test.y |
| 675 | if i&1 != 0 { |
| 676 | x0 = -x0 |
| 677 | } |
| 678 | if i&2 != 0 { |
| 679 | y0 = -y0 |
| 680 | } |
| 681 | if i&4 != 0 { |
| 682 | x0, y0 = y0, x0 |
| 683 | } |
| 684 | |
| 685 | x := new(Float).SetFloat64(x0) |
| 686 | y := new(Float).SetFloat64(y0) |
| 687 | z := NewFloat(0, 53, ToNearestEven) |
| 688 | |
| 689 | z.Mul(x, y) |
| 690 | got, _ := z.Float64() |
| 691 | want := x0 * y0 |
| 692 | if got != want { |
| 693 | t.Errorf("%g * %g = %g; want %g", x0, y0, got, want) |
| 694 | } |
| 695 | |
| 696 | if y0 == 0 { |
| 697 | continue // avoid division-by-zero |
| 698 | } |
| 699 | z.Quo(z, y) |
| 700 | got, _ = z.Float64() |
| 701 | want /= y0 |
| 702 | if got != want { |
| 703 | t.Errorf("%g / %g = %g; want %g", x0*y0, y0, got, want) |
| 704 | } |
| 705 | } |
| 706 | } |
| 707 | } |
| 708 | |
| 709 | func TestIssue6866(t *testing.T) { |
| 710 | for _, prec := range precList { |
| 711 | two := NewFloat(2, prec, ToNearestEven) |
| 712 | one := NewFloat(1, prec, ToNearestEven) |
| 713 | three := NewFloat(3, prec, ToNearestEven) |
| 714 | msix := NewFloat(-6, prec, ToNearestEven) |
| 715 | psix := NewFloat(+6, prec, ToNearestEven) |
| 716 | |
| 717 | p := NewFloat(0, prec, ToNearestEven) |
| 718 | z1 := NewFloat(0, prec, ToNearestEven) |
| 719 | z2 := NewFloat(0, prec, ToNearestEven) |
| 720 | |
| 721 | // z1 = 2 + 1.0/3*-6 |
| 722 | p.Quo(one, three) |
| 723 | p.Mul(p, msix) |
| 724 | z1.Add(two, p) |
| 725 | |
| 726 | // z2 = 2 - 1.0/3*+6 |
| 727 | p.Quo(one, three) |
| 728 | p.Mul(p, psix) |
| 729 | z2.Sub(two, p) |
| 730 | |
| 731 | if z1.Cmp(z2) != 0 { |
| 732 | t.Fatalf("prec %d: got z1 = %s != z2 = %s; want z1 == z2\n", prec, z1, z2) |
| 733 | } |
| 734 | if z1.Sign() != 0 { |
| 735 | t.Errorf("prec %d: got z1 = %s; want 0", prec, z1) |
| 736 | } |
| 737 | if z2.Sign() != 0 { |
| 738 | t.Errorf("prec %d: got z2 = %s; want 0", prec, z2) |
| 739 | } |
| 740 | } |
| 741 | } |
| 742 | |
| 743 | func TestFloatQuo(t *testing.T) { |
| 744 | // TODO(gri) make the test vary these precisions |
| 745 | preci := 200 // precision of integer part |
| 746 | precf := 20 // precision of fractional part |
| 747 | |
| 748 | for i := 0; i < 8; i++ { |
| 749 | // compute accurate (not rounded) result z |
| 750 | bits := []int{preci - 1} |
| 751 | if i&3 != 0 { |
| 752 | bits = append(bits, 0) |
| 753 | } |
| 754 | if i&2 != 0 { |
| 755 | bits = append(bits, -1) |
| 756 | } |
| 757 | if i&1 != 0 { |
| 758 | bits = append(bits, -precf) |
| 759 | } |
| 760 | z := fromBits(bits...) |
| 761 | |
| 762 | // compute accurate x as z*y |
| 763 | y := new(Float).SetFloat64(3.14159265358979323e123) |
| 764 | |
| 765 | x := NewFloat(0, z.Precision()+y.Precision(), ToZero) |
| 766 | x.Mul(z, y) |
| 767 | |
| 768 | // leave for debugging |
| 769 | // fmt.Printf("x = %s\ny = %s\nz = %s\n", x, y, z) |
| 770 | |
| 771 | if got := x.Accuracy(); got != Exact { |
| 772 | t.Errorf("got acc = %s; want exact", got) |
| 773 | } |
| 774 | |
| 775 | // round accurate z for a variety of precisions and |
| 776 | // modes and compare against result of x / y. |
| 777 | for _, mode := range [...]RoundingMode{ToZero, ToNearestEven, AwayFromZero} { |
| 778 | for d := -5; d < 5; d++ { |
| 779 | prec := uint(preci + d) |
| 780 | got := NewFloat(0, prec, mode).Quo(x, y) |
| 781 | want := roundBits(bits, prec, mode) |
| 782 | if got.Cmp(want) != 0 { |
| 783 | t.Errorf("i = %d, prec = %d, %s:\n\t %s\n\t/ %s\n\t= %s\n\twant %s", |
| 784 | i, prec, mode, x, y, got, want) |
| 785 | } |
| 786 | } |
| 787 | } |
| 788 | } |
| 789 | } |
| 790 | |
Robert Griesemer | f083a0e | 2015-02-04 17:17:38 -0800 | [diff] [blame] | 791 | // TestFloatQuoSmoke tests all divisions x/y for values x, y in the range [-n, +n]; |
| 792 | // it serves as a smoke test for basic correctness of division. |
| 793 | func TestFloatQuoSmoke(t *testing.T) { |
| 794 | n := 1000 |
| 795 | if testing.Short() { |
| 796 | n = 10 |
| 797 | } |
| 798 | |
| 799 | const dprec = 3 // max. precision variation |
| 800 | const prec = 10 + dprec // enough bits to hold n precisely |
| 801 | for x := -n; x <= n; x++ { |
| 802 | for y := -n; y < n; y++ { |
| 803 | if y == 0 { |
| 804 | continue |
| 805 | } |
| 806 | |
| 807 | a := float64(x) |
| 808 | b := float64(y) |
| 809 | c := a / b |
| 810 | |
| 811 | // vary operand precision (only ok as long as a, b can be represented correctly) |
| 812 | for ad := -dprec; ad <= dprec; ad++ { |
| 813 | for bd := -dprec; bd <= dprec; bd++ { |
| 814 | A := NewFloat(a, uint(prec+ad), 0) |
| 815 | B := NewFloat(b, uint(prec+bd), 0) |
| 816 | C := NewFloat(0, 53, 0).Quo(A, B) // C has float64 mantissa width |
| 817 | |
| 818 | cc, acc := C.Float64() |
| 819 | if cc != c { |
| 820 | t.Errorf("%g/%g = %s; want %.5g\n", a, b, C.Format('g', 5), c) |
| 821 | continue |
| 822 | } |
| 823 | if acc != Exact { |
| 824 | t.Errorf("%g/%g got %s result; want exact result", a, b, acc) |
| 825 | } |
| 826 | } |
| 827 | } |
| 828 | } |
| 829 | } |
| 830 | } |
| 831 | |
Robert Griesemer | f77696a | 2015-02-09 16:59:31 -0800 | [diff] [blame] | 832 | func TestFloatCmp(t *testing.T) { |
| 833 | // TODO(gri) implement this |
| 834 | } |
| 835 | |
Robert Griesemer | bd275b2 | 2014-12-08 14:36:39 -0800 | [diff] [blame] | 836 | // normBits returns the normalized bits for x: It |
| 837 | // removes multiple equal entries by treating them |
| 838 | // as an addition (e.g., []int{5, 5} => []int{6}), |
| 839 | // and it sorts the result list for reproducible |
| 840 | // results. |
| 841 | func normBits(x []int) []int { |
| 842 | m := make(map[int]bool) |
| 843 | for _, b := range x { |
| 844 | for m[b] { |
| 845 | m[b] = false |
| 846 | b++ |
| 847 | } |
| 848 | m[b] = true |
| 849 | } |
| 850 | var z []int |
| 851 | for b, set := range m { |
| 852 | if set { |
| 853 | z = append(z, b) |
| 854 | } |
| 855 | } |
| 856 | sort.Ints(z) |
| 857 | return z |
| 858 | } |
| 859 | |
| 860 | func TestNormBits(t *testing.T) { |
Robert Griesemer | 9f22de7 | 2015-01-28 17:11:15 -0800 | [diff] [blame] | 861 | for _, test := range []struct { |
Robert Griesemer | bd275b2 | 2014-12-08 14:36:39 -0800 | [diff] [blame] | 862 | x, want []int |
| 863 | }{ |
| 864 | {nil, nil}, |
| 865 | {[]int{}, []int{}}, |
| 866 | {[]int{0}, []int{0}}, |
| 867 | {[]int{0, 0}, []int{1}}, |
| 868 | {[]int{3, 1, 1}, []int{2, 3}}, |
| 869 | {[]int{10, 9, 8, 7, 6, 6}, []int{11}}, |
Robert Griesemer | 9f22de7 | 2015-01-28 17:11:15 -0800 | [diff] [blame] | 870 | } { |
Robert Griesemer | bd275b2 | 2014-12-08 14:36:39 -0800 | [diff] [blame] | 871 | got := fmt.Sprintf("%v", normBits(test.x)) |
| 872 | want := fmt.Sprintf("%v", test.want) |
| 873 | if got != want { |
| 874 | t.Errorf("normBits(%v) = %s; want %s", test.x, got, want) |
| 875 | } |
| 876 | |
| 877 | } |
| 878 | } |
| 879 | |
| 880 | // roundBits returns the Float value rounded to prec bits |
| 881 | // according to mode from the bit set x. |
| 882 | func roundBits(x []int, prec uint, mode RoundingMode) *Float { |
| 883 | x = normBits(x) |
| 884 | |
| 885 | // determine range |
| 886 | var min, max int |
| 887 | for i, b := range x { |
| 888 | if i == 0 || b < min { |
| 889 | min = b |
| 890 | } |
| 891 | if i == 0 || b > max { |
| 892 | max = b |
| 893 | } |
| 894 | } |
| 895 | prec0 := uint(max + 1 - min) |
| 896 | if prec >= prec0 { |
| 897 | return fromBits(x...) |
| 898 | } |
| 899 | // prec < prec0 |
| 900 | |
| 901 | // determine bit 0, rounding, and sticky bit, and result bits z |
| 902 | var bit0, rbit, sbit uint |
| 903 | var z []int |
| 904 | r := max - int(prec) |
| 905 | for _, b := range x { |
| 906 | switch { |
| 907 | case b == r: |
| 908 | rbit = 1 |
| 909 | case b < r: |
| 910 | sbit = 1 |
| 911 | default: |
| 912 | // b > r |
| 913 | if b == r+1 { |
| 914 | bit0 = 1 |
| 915 | } |
| 916 | z = append(z, b) |
| 917 | } |
| 918 | } |
| 919 | |
| 920 | // round |
| 921 | f := fromBits(z...) // rounded to zero |
| 922 | if mode == ToNearestAway { |
| 923 | panic("not yet implemented") |
| 924 | } |
| 925 | if mode == ToNearestEven && rbit == 1 && (sbit == 1 || sbit == 0 && bit0 != 0) || mode == AwayFromZero { |
| 926 | // round away from zero |
| 927 | f.Round(f, prec, ToZero) // extend precision // TODO(gri) better approach? |
| 928 | f.Add(f, fromBits(int(r)+1)) |
| 929 | } |
| 930 | return f |
| 931 | } |
| 932 | |
| 933 | // fromBits returns the *Float z of the smallest possible precision |
| 934 | // such that z = sum(2**bits[i]), with i = range bits. |
| 935 | // If multiple bits[i] are equal, they are added: fromBits(0, 1, 0) |
| 936 | // == 2**1 + 2**0 + 2**0 = 4. |
| 937 | func fromBits(bits ...int) *Float { |
| 938 | // handle 0 |
| 939 | if len(bits) == 0 { |
| 940 | return new(Float) |
| 941 | // z.prec = ? |
| 942 | } |
| 943 | // len(bits) > 0 |
| 944 | |
| 945 | // determine lsb exponent |
| 946 | var min int |
| 947 | for i, b := range bits { |
| 948 | if i == 0 || b < min { |
| 949 | min = b |
| 950 | } |
| 951 | } |
| 952 | |
| 953 | // create bit pattern |
| 954 | x := NewInt(0) |
| 955 | for _, b := range bits { |
| 956 | badj := b - min |
| 957 | // propagate carry if necessary |
| 958 | for x.Bit(badj) != 0 { |
| 959 | x.SetBit(x, badj, 0) |
| 960 | badj++ |
| 961 | } |
| 962 | x.SetBit(x, badj, 1) |
| 963 | } |
| 964 | |
| 965 | // create corresponding float |
| 966 | z := new(Float).SetInt(x) // normalized |
| 967 | z.setExp(int64(z.exp) + int64(min)) |
| 968 | return z |
| 969 | } |
| 970 | |
| 971 | func TestFromBits(t *testing.T) { |
Robert Griesemer | 9f22de7 | 2015-01-28 17:11:15 -0800 | [diff] [blame] | 972 | for _, test := range []struct { |
Robert Griesemer | bd275b2 | 2014-12-08 14:36:39 -0800 | [diff] [blame] | 973 | bits []int |
| 974 | want string |
| 975 | }{ |
| 976 | // all different bit numbers |
Robert Griesemer | f4a2617 | 2015-01-26 16:08:51 -0800 | [diff] [blame] | 977 | {nil, "0"}, |
Robert Griesemer | 9f22de7 | 2015-01-28 17:11:15 -0800 | [diff] [blame] | 978 | {[]int{0}, "0x.8p1"}, |
| 979 | {[]int{1}, "0x.8p2"}, |
| 980 | {[]int{-1}, "0x.8p0"}, |
| 981 | {[]int{63}, "0x.8p64"}, |
| 982 | {[]int{33, -30}, "0x.8000000000000001p34"}, |
| 983 | {[]int{255, 0}, "0x.8000000000000000000000000000000000000000000000000000000000000001p256"}, |
Robert Griesemer | bd275b2 | 2014-12-08 14:36:39 -0800 | [diff] [blame] | 984 | |
| 985 | // multiple equal bit numbers |
Robert Griesemer | 9f22de7 | 2015-01-28 17:11:15 -0800 | [diff] [blame] | 986 | {[]int{0, 0}, "0x.8p2"}, |
| 987 | {[]int{0, 0, 0, 0}, "0x.8p3"}, |
| 988 | {[]int{0, 1, 0}, "0x.8p3"}, |
| 989 | {append([]int{2, 1, 0} /* 7 */, []int{3, 1} /* 10 */ ...), "0x.88p5" /* 17 */}, |
| 990 | } { |
Robert Griesemer | bd275b2 | 2014-12-08 14:36:39 -0800 | [diff] [blame] | 991 | f := fromBits(test.bits...) |
Robert Griesemer | 4c91c0d | 2015-01-30 15:57:38 -0800 | [diff] [blame] | 992 | if got := f.Format('p', 0); got != test.want { |
Robert Griesemer | bd275b2 | 2014-12-08 14:36:39 -0800 | [diff] [blame] | 993 | t.Errorf("setBits(%v) = %s; want %s", test.bits, got, test.want) |
| 994 | } |
| 995 | } |
| 996 | } |