(self)
| 686 | @unittest.skipIf(HAVE_DOUBLE_ROUNDING, |
| 687 | "fsum is not exact on machines with double rounding") |
| 688 | def testFsum(self): |
| 689 | # math.fsum relies on exact rounding for correct operation. |
| 690 | # There's a known problem with IA32 floating-point that causes |
| 691 | # inexact rounding in some situations, and will cause the |
| 692 | # math.fsum tests below to fail; see issue #2937. On non IEEE |
| 693 | # 754 platforms, and on IEEE 754 platforms that exhibit the |
| 694 | # problem described in issue #2937, we simply skip the whole |
| 695 | # test. |
| 696 | |
| 697 | # Python version of math.fsum, for comparison. Uses a |
| 698 | # different algorithm based on frexp, ldexp and integer |
| 699 | # arithmetic. |
| 700 | from sys import float_info |
| 701 | mant_dig = float_info.mant_dig |
| 702 | etiny = float_info.min_exp - mant_dig |
| 703 | |
| 704 | def msum(iterable): |
| 705 | """Full precision summation. Compute sum(iterable) without any |
| 706 | intermediate accumulation of error. Based on the 'lsum' function |
| 707 | at https://code.activestate.com/recipes/393090-binary-floating-point-summation-accurate-to-full-p/ |
| 708 | |
| 709 | """ |
| 710 | tmant, texp = 0, 0 |
| 711 | for x in iterable: |
| 712 | mant, exp = math.frexp(x) |
| 713 | mant, exp = int(math.ldexp(mant, mant_dig)), exp - mant_dig |
| 714 | if texp > exp: |
| 715 | tmant <<= texp-exp |
| 716 | texp = exp |
| 717 | else: |
| 718 | mant <<= exp-texp |
| 719 | tmant += mant |
| 720 | # Round tmant * 2**texp to a float. The original recipe |
| 721 | # used float(str(tmant)) * 2.0**texp for this, but that's |
| 722 | # a little unsafe because str -> float conversion can't be |
| 723 | # relied upon to do correct rounding on all platforms. |
| 724 | tail = max(len(bin(abs(tmant)))-2 - mant_dig, etiny - texp) |
| 725 | if tail > 0: |
| 726 | h = 1 << (tail-1) |
| 727 | tmant = tmant // (2*h) + bool(tmant & h and tmant & 3*h-1) |
| 728 | texp += tail |
| 729 | return math.ldexp(tmant, texp) |
| 730 | |
| 731 | test_values = [ |
| 732 | ([], 0.0), |
| 733 | ([0.0], 0.0), |
| 734 | ([1e100, 1.0, -1e100, 1e-100, 1e50, -1.0, -1e50], 1e-100), |
| 735 | ([1e100, 1.0, -1e100, 1e-100, 1e50, -1, -1e50], 1e-100), |
| 736 | ([2.0**53, -0.5, -2.0**-54], 2.0**53-1.0), |
| 737 | ([2.0**53, 1.0, 2.0**-100], 2.0**53+2.0), |
| 738 | ([2.0**53+10.0, 1.0, 2.0**-100], 2.0**53+12.0), |
| 739 | ([2.0**53-4.0, 0.5, 2.0**-54], 2.0**53-3.0), |
| 740 | ([1./n for n in range(1, 1001)], |
| 741 | float.fromhex('0x1.df11f45f4e61ap+2')), |
| 742 | ([(-1.)**n/n for n in range(1, 1001)], |
| 743 | float.fromhex('-0x1.62a2af1bd3624p-1')), |
| 744 | ([1e16, 1., 1e-16], 10000000000000002.0), |
| 745 | ([1e16-2., 1.-2.**-53, -(1e16-2.), -(1.-2.**-53)], 0.0), |
nothing calls this directly
no test coverage detected