github.com/cockroachdb/apd/v3@v3.2.0/gda_test.go (about) 1 // Copyright 2016 The Cockroach Authors. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 12 // implied. See the License for the specific language governing 13 // permissions and limitations under the License. 14 15 package apd 16 17 import ( 18 "bufio" 19 "bytes" 20 "flag" 21 "fmt" 22 "io" 23 "os" 24 "path/filepath" 25 "sort" 26 "strconv" 27 "strings" 28 "sync" 29 "testing" 30 "time" 31 ) 32 33 const testDir = "testdata" 34 35 var ( 36 flagFailFast = flag.Bool("fast", false, "stop work after first error; disables parallel testing") 37 flagIgnore = flag.Bool("ignore", false, "print ignore lines on errors") 38 flagNoParallel = flag.Bool("noparallel", false, "disables parallel testing") 39 flagTime = flag.Duration("time", 0, "interval at which to print long-running functions; 0 disables") 40 ) 41 42 type TestCase struct { 43 Precision int 44 MaxExponent, MinExponent int 45 Rounding string 46 Extended, Clamp bool 47 48 ID string 49 Operation string 50 Operands []string 51 Result string 52 Conditions []string 53 } 54 55 func (tc TestCase) HasNull() bool { 56 if tc.Result == "#" { 57 return true 58 } 59 for _, o := range tc.Operands { 60 if o == "#" { 61 return true 62 } 63 } 64 return false 65 } 66 67 func (tc TestCase) SkipPrecision() bool { 68 switch tc.Operation { 69 case "tosci", "toeng", "apply": 70 return false 71 default: 72 return true 73 } 74 } 75 76 func ParseDecTest(r io.Reader) ([]TestCase, error) { 77 scanner := bufio.NewScanner(r) 78 tc := TestCase{ 79 Extended: true, 80 } 81 var err error 82 var res []TestCase 83 84 for scanner.Scan() { 85 text := scanner.Text() 86 // TODO(mjibson): support these test cases 87 if strings.Contains(text, "#") { 88 continue 89 } 90 line := strings.Fields(strings.ToLower(text)) 91 for i, t := range line { 92 if strings.HasPrefix(t, "--") { 93 line = line[:i] 94 break 95 } 96 } 97 if len(line) == 0 { 98 continue 99 } 100 if strings.HasSuffix(line[0], ":") { 101 if len(line) != 2 { 102 return nil, fmt.Errorf("expected 2 tokens, got %q", text) 103 } 104 switch directive := line[0]; directive[:len(directive)-1] { 105 case "precision": 106 tc.Precision, err = strconv.Atoi(line[1]) 107 if err != nil { 108 return nil, err 109 } 110 case "maxexponent": 111 tc.MaxExponent, err = strconv.Atoi(line[1]) 112 if err != nil { 113 return nil, err 114 } 115 case "minexponent": 116 tc.MinExponent, err = strconv.Atoi(line[1]) 117 if err != nil { 118 return nil, err 119 } 120 case "rounding": 121 tc.Rounding = line[1] 122 case "version": 123 // ignore 124 case "extended": 125 tc.Extended = line[1] == "1" 126 case "clamp": 127 tc.Clamp = line[1] == "1" 128 default: 129 return nil, fmt.Errorf("unsupported directive: %s", directive) 130 } 131 } else { 132 if len(line) < 5 { 133 return nil, fmt.Errorf("short test case line: %q", text) 134 } 135 tc.ID = line[0] 136 tc.Operation = line[1] 137 tc.Operands = nil 138 var ops []string 139 line = line[2:] 140 for i, o := range line { 141 if o == "->" { 142 tc.Operands = ops 143 line = line[i+1:] 144 break 145 } 146 o = cleanNumber(o) 147 ops = append(ops, o) 148 } 149 if tc.Operands == nil || len(line) < 1 { 150 return nil, fmt.Errorf("bad test case line: %q", text) 151 } 152 tc.Result = strings.ToUpper(cleanNumber(line[0])) 153 tc.Conditions = line[1:] 154 res = append(res, tc) 155 } 156 } 157 if err := scanner.Err(); err != nil { 158 return nil, err 159 } 160 return res, nil 161 } 162 163 func cleanNumber(s string) string { 164 if len(s) > 1 && s[0] == '\'' && s[len(s)-1] == '\'' { 165 s = s[1 : len(s)-1] 166 s = strings.Replace(s, `''`, `'`, -1) 167 } else if len(s) > 1 && s[0] == '"' && s[len(s)-1] == '"' { 168 s = s[1 : len(s)-1] 169 s = strings.Replace(s, `""`, `"`, -1) 170 } 171 return s 172 } 173 174 // Copy ioutil.ReadDir to avoid staticcheck warning on go1.19 and above. Replace 175 // with a call to os.ReadDir when we remove support for go1.15 and below. 176 func ReadDir(dirname string) ([]os.FileInfo, error) { 177 f, err := os.Open(dirname) 178 if err != nil { 179 return nil, err 180 } 181 list, err := f.Readdir(-1) 182 f.Close() 183 if err != nil { 184 return nil, err 185 } 186 sort.Slice(list, func(i, j int) bool { return list[i].Name() < list[j].Name() }) 187 return list, nil 188 } 189 190 func TestParseDecTest(t *testing.T) { 191 files, err := ReadDir(testDir) 192 if err != nil { 193 t.Fatal(err) 194 } 195 for _, fi := range files { 196 t.Run(fi.Name(), func(t *testing.T) { 197 f, err := os.Open(filepath.Join(testDir, fi.Name())) 198 if err != nil { 199 t.Fatal(err) 200 } 201 defer f.Close() 202 _, err = ParseDecTest(f) 203 if err != nil { 204 t.Fatal(err) 205 } 206 }) 207 } 208 } 209 210 var GDAfiles = []string{ 211 "abs", 212 "add", 213 "base", 214 "compare", 215 "comparetotal", 216 "divide", 217 "divideint", 218 "exp", 219 "ln", 220 "log10", 221 "minus", 222 "multiply", 223 "plus", 224 "power", 225 "powersqrt", 226 "quantize", 227 "randoms", 228 "reduce", 229 "remainder", 230 "rounding", 231 "squareroot", 232 "subtract", 233 "tointegral", 234 "tointegralx", 235 236 // non-GDA tests 237 "cuberoot-apd", 238 } 239 240 func TestGDA(t *testing.T) { 241 var buf bytes.Buffer 242 fmt.Fprintf(&buf, "%10s%8s%8s%8s%8s%8s%8s\n", "name", "total", "success", "fail", "ignore", "skip", "missing") 243 for _, fname := range GDAfiles { 244 succeed := t.Run(fname, func(t *testing.T) { 245 path, tcs := readGDA(t, fname) 246 gdaTest(t, path, tcs) 247 }) 248 if !succeed && *flagFailFast { 249 break 250 } 251 } 252 } 253 254 func (tc TestCase) Run(c *Context, done chan error, d, x, y *Decimal) (res Condition, err error) { 255 switch tc.Operation { 256 case "abs": 257 res, err = c.Abs(d, x) 258 case "add": 259 res, err = c.Add(d, x, y) 260 case "compare": 261 res, err = c.Cmp(d, x, y) 262 case "cuberoot": 263 res, err = c.Cbrt(d, x) 264 case "divide": 265 res, err = c.Quo(d, x, y) 266 case "divideint": 267 res, err = c.QuoInteger(d, x, y) 268 case "exp": 269 res, err = c.Exp(d, x) 270 case "ln": 271 res, err = c.Ln(d, x) 272 case "log10": 273 res, err = c.Log10(d, x) 274 case "minus": 275 res, err = c.Neg(d, x) 276 case "multiply": 277 res, err = c.Mul(d, x, y) 278 case "plus": 279 res, err = c.Add(d, x, decimalZero) 280 case "power": 281 res, err = c.Pow(d, x, y) 282 case "quantize": 283 res, err = c.Quantize(d, x, y.Exponent) 284 case "reduce": 285 _, res, err = c.Reduce(d, x) 286 case "remainder": 287 res, err = c.Rem(d, x, y) 288 case "squareroot": 289 res, err = c.Sqrt(d, x) 290 case "subtract": 291 res, err = c.Sub(d, x, y) 292 case "tointegral": 293 res, err = c.RoundToIntegralValue(d, x) 294 case "tointegralx": 295 res, err = c.RoundToIntegralExact(d, x) 296 297 // Below used only in benchmarks. Tests call it themselves. 298 case "comparetotal": 299 x.CmpTotal(y) 300 case "tosci": 301 _ = x.String() 302 303 default: 304 done <- fmt.Errorf("unknown operation: %s", tc.Operation) 305 } 306 return 307 } 308 309 // BenchmarkGDA benchmarks a GDA test. It should not be used without specifying 310 // a sub-benchmark to run. For example: 311 // go test -run XX -bench GDA/squareroot 312 func BenchmarkGDA(b *testing.B) { 313 for _, fname := range GDAfiles { 314 b.Run(fname, func(b *testing.B) { 315 type benchCase struct { 316 tc TestCase 317 ctx *Context 318 ops [2]*Decimal 319 } 320 _, tcs := readGDA(b, fname) 321 bcs := make([]benchCase, 0, len(tcs)) 322 Loop: 323 for _, tc := range tcs { 324 if GDAignore[tc.ID] || tc.Result == "?" || tc.HasNull() { 325 continue 326 } 327 switch tc.Operation { 328 case "apply", "toeng": 329 continue 330 } 331 bc := benchCase{ 332 tc: tc, 333 ctx: tc.Context(b), 334 } 335 for i, o := range tc.Operands { 336 d, _, err := NewFromString(o) 337 if err != nil { 338 continue Loop 339 } 340 bc.ops[i] = d 341 } 342 bcs = append(bcs, bc) 343 } 344 345 // Translate inputs and outputs to Decimal vectors. 346 op1s := make([]Decimal, len(bcs)) 347 op2s := make([]Decimal, len(bcs)) 348 res := make([]Decimal, b.N*len(bcs)) 349 for i, bc := range bcs { 350 op1s[i].Set(bc.ops[0]) 351 if bc.ops[1] != nil { 352 op2s[i].Set(bc.ops[1]) 353 } 354 } 355 356 b.ResetTimer() 357 for i := 0; i < b.N; i++ { 358 for j, bc := range bcs { 359 // Ignore errors here because the full tests catch them. 360 _, _ = bc.tc.Run(bc.ctx, nil, &res[i*len(bcs)+j], &op1s[j], &op2s[j]) 361 } 362 } 363 }) 364 } 365 } 366 367 func readGDA(t testing.TB, name string) (string, []TestCase) { 368 path := filepath.Join(testDir, name+".decTest") 369 f, err := os.Open(path) 370 if err != nil { 371 t.Fatal(err) 372 } 373 defer f.Close() 374 tcs, err := ParseDecTest(f) 375 if err != nil { 376 t.Fatal(err) 377 } 378 return path, tcs 379 } 380 381 func (tc TestCase) Context(t testing.TB) *Context { 382 rounding := Rounder(tc.Rounding) 383 if _, ok := roundings[rounding]; !ok { 384 t.Fatalf("unsupported rounding mode %s", tc.Rounding) 385 } 386 c := &Context{ 387 Precision: uint32(tc.Precision), 388 MaxExponent: int32(tc.MaxExponent), 389 MinExponent: int32(tc.MinExponent), 390 Rounding: rounding, 391 Traps: 0, 392 } 393 return c 394 } 395 396 func gdaTest(t *testing.T, path string, tcs []TestCase) { 397 for _, tc := range tcs { 398 tc := tc 399 succeed := t.Run(tc.ID, func(t *testing.T) { 400 if *flagTime > 0 { 401 timeDone := make(chan struct{}, 1) 402 go func() { 403 start := time.Now() 404 for { 405 select { 406 case <-timeDone: 407 return 408 case <-time.After(*flagTime): 409 fmt.Println(tc.ID, "running for", time.Since(start)) 410 } 411 } 412 }() 413 defer func() { timeDone <- struct{}{} }() 414 } 415 defer func() { 416 if t.Failed() { 417 if *flagIgnore { 418 tc.PrintIgnore() 419 } 420 } 421 }() 422 if GDAignore[tc.ID] { 423 t.Skip("ignored") 424 } 425 if tc.HasNull() { 426 t.Skip("has null") 427 } 428 switch tc.Operation { 429 case "toeng", "apply": 430 t.Skip("unsupported") 431 } 432 if !*flagNoParallel && !*flagFailFast { 433 t.Parallel() 434 } 435 // helpful acme address link 436 t.Logf("%s:/^%s ", path, tc.ID) 437 t.Logf("%s %s = %s (%s)", tc.Operation, strings.Join(tc.Operands, " "), tc.Result, strings.Join(tc.Conditions, " ")) 438 t.Logf("prec: %d, round: %s, Emax: %d, Emin: %d", tc.Precision, tc.Rounding, tc.MaxExponent, tc.MinExponent) 439 operands := make([]*Decimal, 2) 440 c := tc.Context(t) 441 var res, opres Condition 442 opctx := c 443 if tc.SkipPrecision() { 444 opctx = opctx.WithPrecision(1000) 445 opctx.MaxExponent = MaxExponent 446 opctx.MinExponent = MinExponent 447 } 448 for i, o := range tc.Operands { 449 d, ores, err := opctx.NewFromString(o) 450 expectError := tc.Result == "NAN" && strings.Join(tc.Conditions, "") == "conversion_syntax" 451 if err != nil { 452 if expectError { 453 // Successfully detected bad syntax. 454 return 455 } 456 switch tc.Operation { 457 case "tosci": 458 // Skip cases with exponents larger than we will parse. 459 if strings.Contains(err.Error(), "value out of range") { 460 return 461 } 462 } 463 testExponentError(t, err) 464 if tc.Result == "?" { 465 return 466 } 467 t.Logf("%v, %v, %v", tc.Result, tc.Conditions, tc.Operation) 468 t.Fatalf("operand %d: %s: %+v", i, o, err) 469 } else if expectError { 470 t.Fatalf("expected error, got %s", d) 471 } 472 operands[i] = d 473 opres |= ores 474 } 475 switch tc.Operation { 476 case "power": 477 tmp := new(Decimal).Abs(operands[1]) 478 // We don't handle power near the max exp limit. 479 if tmp.Cmp(New(MaxExponent, 0)) >= 0 { 480 t.Skip("x ** large y") 481 } 482 if tmp.Cmp(New(int64(c.MaxExponent), 0)) >= 0 { 483 t.Skip("x ** large y") 484 } 485 case "quantize": 486 if operands[1].Form != Finite { 487 t.Skip("quantize requires finite second operand") 488 } 489 } 490 var s string 491 // Fill d with bogus data to make sure all fields are correctly set. 492 d := &Decimal{ 493 Form: -2, 494 Negative: true, 495 Exponent: -6437897, 496 } 497 // Use d1 and d2 to verify that the result can be the same as the first and 498 // second operand. 499 var d1, d2 *Decimal 500 d.Coeff.SetInt64(9221) 501 start := time.Now() 502 defer func() { 503 t.Logf("duration: %s", time.Since(start)) 504 }() 505 506 done := make(chan error, 1) 507 var err error 508 go func() { 509 switch tc.Operation { 510 case "tosci": 511 s = operands[0].String() 512 // non-extended tests don't retain exponents for 0 513 if !tc.Extended && operands[0].IsZero() { 514 s = "0" 515 } 516 // Clear d's bogus data. 517 d.Set(operands[0]) 518 // Set d1 to prevent the result-equals-operand check failing. 519 d1 = d 520 case "comparetotal": 521 var c int 522 c = operands[0].CmpTotal(operands[1]) 523 d.SetInt64(int64(c)) 524 default: 525 var wg sync.WaitGroup 526 wg.Add(2) 527 // Check that the result is correct even if it is either argument. Use some 528 // go routines since we are running tc.Run three times. 529 go func() { 530 d1 = new(Decimal).Set(operands[0]) 531 tc.Run(c, done, d1, d1, operands[1]) 532 wg.Done() 533 }() 534 go func() { 535 if operands[1] != nil { 536 d2 = new(Decimal).Set(operands[1]) 537 tc.Run(c, done, d2, operands[0], d2) 538 } 539 wg.Done() 540 }() 541 res, err = tc.Run(c, done, d, operands[0], operands[1]) 542 wg.Wait() 543 } 544 done <- nil 545 }() 546 select { 547 case err := <-done: 548 if err != nil { 549 t.Fatal(err) 550 } 551 case <-time.After(time.Second * 20): 552 t.Fatalf("timeout") 553 } 554 if d.Coeff.Sign() < 0 { 555 t.Fatalf("negative coeff: %s", d.Coeff.String()) 556 } 557 // Make sure the bogus Form above got cleared. 558 if d.Form < 0 { 559 t.Fatalf("unexpected form: %#v", d) 560 } 561 // Verify the operands didn't change. 562 for i, o := range tc.Operands { 563 v := newDecimal(t, opctx, o) 564 if v.CmpTotal(operands[i]) != 0 { 565 t.Fatalf("operand %d changed from %s to %s", i, o, operands[i]) 566 } 567 } 568 // Verify the result-equals-operand worked correctly. 569 if d1 != nil && d.CmpTotal(d1) != 0 { 570 t.Errorf("first operand as result mismatch: got %s, expected %s", d1, d) 571 } 572 if d2 != nil && d.CmpTotal(d2) != 0 { 573 t.Errorf("second operand as result mismatch: got %s, expected %s", d2, d) 574 } 575 if !GDAignoreFlags[tc.ID] { 576 var rcond Condition 577 for _, cond := range tc.Conditions { 578 switch cond { 579 case "underflow": 580 rcond |= Underflow 581 case "inexact": 582 rcond |= Inexact 583 case "overflow": 584 rcond |= Overflow 585 case "subnormal": 586 rcond |= Subnormal 587 case "division_undefined": 588 rcond |= DivisionUndefined 589 case "division_by_zero": 590 rcond |= DivisionByZero 591 case "division_impossible": 592 rcond |= DivisionImpossible 593 case "invalid_operation": 594 rcond |= InvalidOperation 595 case "rounded": 596 rcond |= Rounded 597 case "clamped": 598 rcond |= Clamped 599 600 case "invalid_context": 601 // ignore 602 603 default: 604 t.Fatalf("unknown condition: %s", cond) 605 } 606 } 607 608 switch tc.Operation { 609 case "tosci": 610 // We only care about the operand flags for the string conversion operations. 611 res |= opres 612 } 613 614 t.Logf("want flags (%d): %s", rcond, rcond) 615 t.Logf("have flags (%d): %s", res, res) 616 617 // TODO(mjibson): after upscaling, operations need to remove the 0s added 618 // after the operation is done. Since this isn't happening, things are being 619 // rounded when they shouldn't because the coefficient has so many trailing 0s. 620 // Manually remove Rounded flag from context until the TODO is fixed. 621 res &= ^Rounded 622 rcond &= ^Rounded 623 624 switch tc.Operation { 625 case "log10": 626 // TODO(mjibson): Under certain conditions these are exact, but we don't 627 // correctly mark them. Ignore these flags for now. 628 // squareroot sometimes marks things exact when GDA says they should be 629 // inexact. 630 rcond &= ^Inexact 631 res &= ^Inexact 632 } 633 634 // Don't worry about these flags; they are handled by GoError. 635 res &= ^SystemOverflow 636 res &= ^SystemUnderflow 637 638 if (res.Overflow() || res.Underflow()) && (strings.HasPrefix(tc.ID, "rpow") || 639 strings.HasPrefix(tc.ID, "powr")) { 640 t.Skip("overflow") 641 } 642 643 // Ignore Clamped on error. 644 if tc.Result == "?" { 645 rcond &= ^Clamped 646 res &= ^Clamped 647 } 648 649 if rcond != res { 650 if tc.Operation == "power" && (res.Overflow() || res.Underflow()) { 651 t.Skip("power overflow") 652 } 653 t.Logf("got: %s (%#v)", d, d) 654 t.Logf("error: %+v", err) 655 t.Errorf("expected flags %q (%d); got flags %q (%d)", rcond, rcond, res, res) 656 } 657 } 658 659 if tc.Result == "?" { 660 if err != nil { 661 return 662 } 663 t.Fatalf("expected error, got %s", d) 664 } 665 if err != nil { 666 testExponentError(t, err) 667 if tc.Operation == "power" && (res.Overflow() || res.Underflow()) { 668 t.Skip("power overflow") 669 } 670 t.Fatalf("%+v", err) 671 } 672 switch tc.Operation { 673 case "tosci", "toeng": 674 if strings.HasPrefix(tc.Result, "-NAN") { 675 tc.Result = "-NaN" 676 } 677 if strings.HasPrefix(tc.Result, "-SNAN") { 678 tc.Result = "-sNaN" 679 } 680 if strings.HasPrefix(tc.Result, "NAN") { 681 tc.Result = "NaN" 682 } 683 if strings.HasPrefix(tc.Result, "SNAN") { 684 tc.Result = "sNaN" 685 } 686 expected := tc.Result 687 // Adjust 0E- or -0E- tests to match PostgreSQL behavior. 688 // See: https://github.com/cockroachdb/cockroach/issues/102217. 689 if pos, neg := strings.HasPrefix(expected, "0E-"), strings.HasPrefix(expected, "-0E-"); pos || neg { 690 startIdx := 3 691 if neg { 692 startIdx = 4 693 } 694 p, err := strconv.ParseInt(expected[startIdx:], 10, 64) 695 if err != nil { 696 t.Fatalf("unexpected error converting int: %v", err) 697 } 698 expected = "" 699 if neg { 700 expected = "-" 701 } 702 expected += "0." + strings.Repeat("0", int(p)) 703 } 704 if !strings.EqualFold(s, expected) { 705 t.Fatalf("expected %s, got %s", expected, s) 706 } 707 return 708 } 709 r := newDecimal(t, testCtx, tc.Result) 710 var equal bool 711 if d.Form == Finite { 712 // Don't worry about trailing zeros being inequal in CmpTotal. 713 equal = d.Cmp(r) == 0 && d.Negative == r.Negative 714 } else { 715 equal = d.CmpTotal(r) == 0 716 } 717 if !equal { 718 t.Logf("want: %s", tc.Result) 719 t.Logf("got: %s (%#v)", d, d) 720 // Some operations allow 1ulp of error in tests. 721 switch tc.Operation { 722 case "exp", "ln", "log10", "power": 723 nc := c.WithPrecision(0) 724 nc.Sub(d, d, r) 725 if d.Coeff.Cmp(bigOne) == 0 { 726 t.Logf("pass: within 1ulp: %s, %s", d, r) 727 return 728 } 729 } 730 t.Fatalf("unexpected result") 731 } else { 732 t.Logf("got: %s (%#v)", d, d) 733 } 734 }) 735 if !succeed { 736 if *flagFailFast { 737 break 738 } 739 } 740 } 741 } 742 743 func (tc TestCase) PrintIgnore() { 744 fmt.Printf(" \"%s\": true,\n", tc.ID) 745 } 746 747 var GDAignore = map[string]bool{ 748 // Invalid context 749 "expx901": true, 750 "expx902": true, 751 "expx903": true, 752 "expx905": true, 753 "lnx901": true, 754 "lnx902": true, 755 "lnx903": true, 756 "lnx905": true, 757 "logx901": true, 758 "logx902": true, 759 "logx903": true, 760 "logx905": true, 761 "powx4001": true, 762 "powx4002": true, 763 "powx4003": true, 764 "powx4005": true, 765 766 // NaN payloads with weird digits 767 "basx725": true, 768 "basx745": true, 769 770 // NaN payloads 771 "cotx970": true, 772 "cotx973": true, 773 "cotx974": true, 774 "cotx977": true, 775 "cotx980": true, 776 "cotx983": true, 777 "cotx984": true, 778 "cotx987": true, 779 "cotx994": true, 780 781 // too large exponents, supposed to fail anyway 782 "quax525": true, 783 "quax531": true, 784 "quax805": true, 785 "quax806": true, 786 "quax807": true, 787 "quax808": true, 788 "quax809": true, 789 "quax810": true, 790 "quax811": true, 791 "quax812": true, 792 "quax813": true, 793 "quax814": true, 794 "quax815": true, 795 "quax816": true, 796 "quax817": true, 797 "quax818": true, 798 "quax819": true, 799 "quax820": true, 800 "quax821": true, 801 "quax822": true, 802 "quax861": true, 803 "quax862": true, 804 "quax866": true, 805 806 // TODO(mjibson): fix tests below 807 808 // overflows to infinity 809 "powx4125": true, 810 "powx4145": true, 811 812 // exceeds system overflow 813 "expx291": true, 814 "expx292": true, 815 "expx293": true, 816 "expx294": true, 817 "expx295": true, 818 "expx296": true, 819 820 // inexact zeros 821 "addx1633": true, 822 "addx1634": true, 823 "addx1638": true, 824 "addx61633": true, 825 "addx61634": true, 826 "addx61638": true, 827 828 // should be -0E-398, got -1E-398 829 "addx1613": true, 830 "addx1614": true, 831 "addx1618": true, 832 "addx61613": true, 833 "addx61614": true, 834 "addx61618": true, 835 836 // extreme input range, but should work 837 "sqtx8636": true, 838 "sqtx8644": true, 839 "sqtx8646": true, 840 "sqtx8647": true, 841 "sqtx8648": true, 842 "sqtx8650": true, 843 "sqtx8651": true, 844 } 845 846 var GDAignoreFlags = map[string]bool{ 847 // unflagged clamped 848 "sqtx9024": true, 849 "sqtx9025": true, 850 "sqtx9026": true, 851 "sqtx9027": true, 852 "sqtx9038": true, 853 "sqtx9039": true, 854 "sqtx9040": true, 855 "sqtx9045": true, 856 }