blob: e4c2e1ad99d5b1e8b5eb8b9d0d2145e4f9bfccb2 [file] [log] [blame]
Robert Griesemerbd275b22014-12-08 14:36:39 -08001// 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
5package big
6
7import (
8 "fmt"
Robert Griesemer15594df2015-02-05 17:21:48 -08009 "math"
Robert Griesemerbd275b22014-12-08 14:36:39 -080010 "sort"
11 "strconv"
Robert Griesemerf77696a2015-02-09 16:59:31 -080012 "strings"
Robert Griesemerbd275b22014-12-08 14:36:39 -080013 "testing"
14)
15
Robert Griesemer15594df2015-02-05 17:21:48 -080016func 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 Griesemerf77696a2015-02-09 16:59:31 -080070func 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
85func 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).
106func feq(x, y *Float) bool {
107 return x.Cmp(y) == 0 && x.neg == y.neg
108}
109
110func 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
135func 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
164func 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
189func TestFloatIsInf(t *testing.T) {
Robert Griesemer15594df2015-02-05 17:21:48 -0800190 // TODO(gri) implement this
191}
192
Robert Griesemerbd275b22014-12-08 14:36:39 -0800193func 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
201func toBinary(x int64) string {
202 return strconv.FormatInt(x, 2)
203}
204
205func 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.
260func TestFloatRound(t *testing.T) {
Robert Griesemer9f22de72015-01-28 17:11:15 -0800261 for _, test := range []struct {
Robert Griesemerbd275b22014-12-08 14:36:39 -0800262 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 Griesemer9f22de72015-01-28 17:11:15 -0800336 } {
Robert Griesemerbd275b22014-12-08 14:36:39 -0800337 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.
360func 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
374func TestFloatSetUint64(t *testing.T) {
Robert Griesemer9f22de72015-01-28 17:11:15 -0800375 for _, want := range []uint64{
Robert Griesemerbd275b22014-12-08 14:36:39 -0800376 0,
377 1,
378 2,
379 10,
380 100,
381 1<<32 - 1,
382 1 << 32,
383 1<<64 - 1,
Robert Griesemer9f22de72015-01-28 17:11:15 -0800384 } {
Robert Griesemeracfe3a52015-02-06 16:51:00 -0800385 var f Float
386 f.SetUint64(want)
Robert Griesemerbd275b22014-12-08 14:36:39 -0800387 if got := f.Uint64(); got != want {
Robert Griesemeracfe3a52015-02-06 16:51:00 -0800388 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 Griesemerbd275b22014-12-08 14:36:39 -0800400 }
401 }
402}
403
404func TestFloatSetInt64(t *testing.T) {
Robert Griesemer9f22de72015-01-28 17:11:15 -0800405 for _, want := range []int64{
Robert Griesemerbd275b22014-12-08 14:36:39 -0800406 0,
407 1,
408 2,
409 10,
410 100,
411 1<<32 - 1,
412 1 << 32,
413 1<<63 - 1,
Robert Griesemer9f22de72015-01-28 17:11:15 -0800414 } {
Robert Griesemerbd275b22014-12-08 14:36:39 -0800415 for i := range [2]int{} {
416 if i&1 != 0 {
417 want = -want
418 }
Robert Griesemeracfe3a52015-02-06 16:51:00 -0800419 var f Float
420 f.SetInt64(want)
Robert Griesemerbd275b22014-12-08 14:36:39 -0800421 if got := f.Int64(); got != want {
Robert Griesemeracfe3a52015-02-06 16:51:00 -0800422 t.Errorf("got %#x (%s); want %#x", got, f.Format('p', 0), want)
Robert Griesemerbd275b22014-12-08 14:36:39 -0800423 }
424 }
425 }
Robert Griesemeracfe3a52015-02-06 16:51:00 -0800426
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 Griesemerbd275b22014-12-08 14:36:39 -0800437}
438
439func TestFloatSetFloat64(t *testing.T) {
Robert Griesemer9f22de72015-01-28 17:11:15 -0800440 for _, want := range []float64{
Robert Griesemerbd275b22014-12-08 14:36:39 -0800441 0,
442 1,
443 2,
444 12345,
445 1e10,
446 1e100,
447 3.14159265e10,
448 2.718281828e-123,
449 1.0 / 3,
Robert Griesemer15594df2015-02-05 17:21:48 -0800450 math.Inf(-1),
451 math.Inf(0),
452 -math.Inf(1),
Robert Griesemer9f22de72015-01-28 17:11:15 -0800453 } {
Robert Griesemerbd275b22014-12-08 14:36:39 -0800454 for i := range [2]int{} {
455 if i&1 != 0 {
456 want = -want
457 }
Robert Griesemeracfe3a52015-02-06 16:51:00 -0800458 var f Float
459 f.SetFloat64(want)
Robert Griesemerbd275b22014-12-08 14:36:39 -0800460 if got, _ := f.Float64(); got != want {
Robert Griesemer4c91c0d2015-01-30 15:57:38 -0800461 t.Errorf("got %g (%s); want %g", got, f.Format('p', 0), want)
Robert Griesemerbd275b22014-12-08 14:36:39 -0800462 }
463 }
464 }
Robert Griesemeracfe3a52015-02-06 16:51:00 -0800465
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 Griesemerbd275b22014-12-08 14:36:39 -0800476}
477
478func TestFloatSetInt(t *testing.T) {
Robert Griesemeracfe3a52015-02-06 16:51:00 -0800479 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
504func 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 Griesemerbd275b22014-12-08 14:36:39 -0800529}
530
531// Selected precisions with which to run various tests.
532var 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).
536var 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.
552func 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 Griesemerbd275b22014-12-08 14:36:39 -0800563 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 Griesemerbd275b22014-12-08 14:36:39 -0800572 got.Sub(z, x)
573 want = roundBits(ybits, prec, mode)
574 if got.Cmp(want) != 0 {
Robert Griesemerf4a26172015-01-26 16:08:51 -0800575 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 Griesemerbd275b22014-12-08 14:36:39 -0800577 }
578 }
579 }
580 }
581 }
582}
583
584// TestFloatAdd32 tests that Float.Add/Sub of numbers with
585// 24bit mantissa behaves like float32 addition/subtraction.
586func TestFloatAdd32(t *testing.T) {
Robert Griesemer3acb9fd2015-01-23 21:40:35 -0800587 // TODO(gri) fix test for 32bit platforms
588 if _W == 32 {
589 return
590 }
591
Robert Griesemerbd275b22014-12-08 14:36:39 -0800592 // 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.
624func 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 Griesemerf4a26172015-01-26 16:08:51 -0800642 t.Errorf("d = %d: %g + %g = %g (%s); want %g exactly", d, x0, y0, got, acc, want)
Robert Griesemerbd275b22014-12-08 14:36:39 -0800643 }
644
645 z.Sub(z, y)
646 got, acc = z.Float64()
647 want -= y0
648 if got != want || acc != Exact {
Robert Griesemerf4a26172015-01-26 16:08:51 -0800649 t.Errorf("d = %d: %g - %g = %g (%s); want %g exactly", d, x0+y0, y0, got, acc, want)
Robert Griesemerbd275b22014-12-08 14:36:39 -0800650 }
651 }
652 }
653}
654
655func TestFloatMul(t *testing.T) {
656}
657
658// TestFloatMul64 tests that Float.Mul/Quo of numbers with
659// 53bit mantissa behaves like float64 multiplication/division.
660func TestFloatMul64(t *testing.T) {
Robert Griesemer9f22de72015-01-28 17:11:15 -0800661 for _, test := range []struct {
Robert Griesemerbd275b22014-12-08 14:36:39 -0800662 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 Griesemer9f22de72015-01-28 17:11:15 -0800672 } {
Robert Griesemerbd275b22014-12-08 14:36:39 -0800673 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
709func 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
743func 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 Griesemerf083a0e2015-02-04 17:17:38 -0800791// 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.
793func 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 Griesemerf77696a2015-02-09 16:59:31 -0800832func TestFloatCmp(t *testing.T) {
833 // TODO(gri) implement this
834}
835
Robert Griesemerbd275b22014-12-08 14:36:39 -0800836// 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.
841func 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
860func TestNormBits(t *testing.T) {
Robert Griesemer9f22de72015-01-28 17:11:15 -0800861 for _, test := range []struct {
Robert Griesemerbd275b22014-12-08 14:36:39 -0800862 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 Griesemer9f22de72015-01-28 17:11:15 -0800870 } {
Robert Griesemerbd275b22014-12-08 14:36:39 -0800871 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.
882func 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.
937func 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
971func TestFromBits(t *testing.T) {
Robert Griesemer9f22de72015-01-28 17:11:15 -0800972 for _, test := range []struct {
Robert Griesemerbd275b22014-12-08 14:36:39 -0800973 bits []int
974 want string
975 }{
976 // all different bit numbers
Robert Griesemerf4a26172015-01-26 16:08:51 -0800977 {nil, "0"},
Robert Griesemer9f22de72015-01-28 17:11:15 -0800978 {[]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 Griesemerbd275b22014-12-08 14:36:39 -0800984
985 // multiple equal bit numbers
Robert Griesemer9f22de72015-01-28 17:11:15 -0800986 {[]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 Griesemerbd275b22014-12-08 14:36:39 -0800991 f := fromBits(test.bits...)
Robert Griesemer4c91c0d2015-01-30 15:57:38 -0800992 if got := f.Format('p', 0); got != test.want {
Robert Griesemerbd275b22014-12-08 14:36:39 -0800993 t.Errorf("setBits(%v) = %s; want %s", test.bits, got, test.want)
994 }
995 }
996}