(self)
| 645 | @unittest.skipIf(HAVE_DOUBLE_ROUNDING, |
| 646 | "fsum is not exact on machines with double rounding") |
| 647 | def testFsum(self): |
| 648 | # math.fsum relies on exact rounding for correct operation. |
| 649 | # There's a known problem with IA32 floating-point that causes |
| 650 | # inexact rounding in some situations, and will cause the |
| 651 | # math.fsum tests below to fail; see issue #2937. On non IEEE |
| 652 | # 754 platforms, and on IEEE 754 platforms that exhibit the |
| 653 | # problem described in issue #2937, we simply skip the whole |
| 654 | # test. |
| 655 | |
| 656 | # Python version of math.fsum, for comparison. Uses a |
| 657 | # different algorithm based on frexp, ldexp and integer |
| 658 | # arithmetic. |
| 659 | from sys import float_info |
| 660 | mant_dig = float_info.mant_dig |
| 661 | etiny = float_info.min_exp - mant_dig |
| 662 | |
| 663 | def msum(iterable): |
| 664 | """Full precision summation. Compute sum(iterable) without any |
| 665 | intermediate accumulation of error. Based on the 'lsum' function |
| 666 | at https://code.activestate.com/recipes/393090-binary-floating-point-summation-accurate-to-full-p/ |
| 667 | |
| 668 | """ |
| 669 | tmant, texp = 0, 0 |
| 670 | for x in iterable: |
| 671 | mant, exp = math.frexp(x) |
| 672 | mant, exp = int(math.ldexp(mant, mant_dig)), exp - mant_dig |
| 673 | if texp > exp: |
| 674 | tmant <<= texp-exp |
| 675 | texp = exp |
| 676 | else: |
| 677 | mant <<= exp-texp |
| 678 | tmant += mant |
| 679 | # Round tmant * 2**texp to a float. The original recipe |
| 680 | # used float(str(tmant)) * 2.0**texp for this, but that's |
| 681 | # a little unsafe because str -> float conversion can't be |
| 682 | # relied upon to do correct rounding on all platforms. |
| 683 | tail = max(len(bin(abs(tmant)))-2 - mant_dig, etiny - texp) |
| 684 | if tail > 0: |
| 685 | h = 1 << (tail-1) |
| 686 | tmant = tmant // (2*h) + bool(tmant & h and tmant & 3*h-1) |
| 687 | texp += tail |
| 688 | return math.ldexp(tmant, texp) |
| 689 | |
| 690 | test_values = [ |
| 691 | ([], 0.0), |
| 692 | ([0.0], 0.0), |
| 693 | ([1e100, 1.0, -1e100, 1e-100, 1e50, -1.0, -1e50], 1e-100), |
| 694 | ([1e100, 1.0, -1e100, 1e-100, 1e50, -1, -1e50], 1e-100), |
| 695 | ([2.0**53, -0.5, -2.0**-54], 2.0**53-1.0), |
| 696 | ([2.0**53, 1.0, 2.0**-100], 2.0**53+2.0), |
| 697 | ([2.0**53+10.0, 1.0, 2.0**-100], 2.0**53+12.0), |
| 698 | ([2.0**53-4.0, 0.5, 2.0**-54], 2.0**53-3.0), |
| 699 | ([1./n for n in range(1, 1001)], |
| 700 | float.fromhex('0x1.df11f45f4e61ap+2')), |
| 701 | ([(-1.)**n/n for n in range(1, 1001)], |
| 702 | float.fromhex('-0x1.62a2af1bd3624p-1')), |
| 703 | ([1e16, 1., 1e-16], 10000000000000002.0), |
| 704 | ([1e16-2., 1.-2.**-53, -(1e16-2.), -(1.-2.**-53)], 0.0), |
nothing calls this directly
no test coverage detected