| 882 | @unittest.skipIf(HAVE_DOUBLE_ROUNDING, |
| 883 | "hypot() loses accuracy on machines with double rounding") |
| 884 | def testHypotAccuracy(self): |
| 885 | # Verify improved accuracy in cases that were known to be inaccurate. |
| 886 | # |
| 887 | # The new algorithm's accuracy depends on IEEE 754 arithmetic |
| 888 | # guarantees, on having the usual ROUND HALF EVEN rounding mode, on |
| 889 | # the system not having double rounding due to extended precision, |
| 890 | # and on the compiler maintaining the specified order of operations. |
| 891 | # |
| 892 | # This test is known to succeed on most of our builds. If it fails |
| 893 | # some build, we either need to add another skipIf if the cause is |
| 894 | # identifiable; otherwise, we can remove this test entirely. |
| 895 | |
| 896 | hypot = math.hypot |
| 897 | Decimal = decimal.Decimal |
| 898 | high_precision = decimal.Context(prec=500) |
| 899 | |
| 900 | for hx, hy in [ |
| 901 | # Cases with a 1 ulp error in Python 3.7 compiled with Clang |
| 902 | ('0x1.10e89518dca48p+29', '0x1.1970f7565b7efp+30'), |
| 903 | ('0x1.10106eb4b44a2p+29', '0x1.ef0596cdc97f8p+29'), |
| 904 | ('0x1.459c058e20bb7p+30', '0x1.993ca009b9178p+29'), |
| 905 | ('0x1.378371ae67c0cp+30', '0x1.fbe6619854b4cp+29'), |
| 906 | ('0x1.f4cd0574fb97ap+29', '0x1.50fe31669340ep+30'), |
| 907 | ('0x1.494b2cdd3d446p+29', '0x1.212a5367b4c7cp+29'), |
| 908 | ('0x1.f84e649f1e46dp+29', '0x1.1fa56bef8eec4p+30'), |
| 909 | ('0x1.2e817edd3d6fap+30', '0x1.eb0814f1e9602p+29'), |
| 910 | ('0x1.0d3a6e3d04245p+29', '0x1.32a62fea52352p+30'), |
| 911 | ('0x1.888e19611bfc5p+29', '0x1.52b8e70b24353p+29'), |
| 912 | |
| 913 | # Cases with 2 ulp error in Python 3.8 |
| 914 | ('0x1.538816d48a13fp+29', '0x1.7967c5ca43e16p+29'), |
| 915 | ('0x1.57b47b7234530p+29', '0x1.74e2c7040e772p+29'), |
| 916 | ('0x1.821b685e9b168p+30', '0x1.677dc1c1e3dc6p+29'), |
| 917 | ('0x1.9e8247f67097bp+29', '0x1.24bd2dc4f4baep+29'), |
| 918 | ('0x1.b73b59e0cb5f9p+29', '0x1.da899ab784a97p+28'), |
| 919 | ('0x1.94a8d2842a7cfp+30', '0x1.326a51d4d8d8ap+30'), |
| 920 | ('0x1.e930b9cd99035p+29', '0x1.5a1030e18dff9p+30'), |
| 921 | ('0x1.1592bbb0e4690p+29', '0x1.a9c337b33fb9ap+29'), |
| 922 | ('0x1.1243a50751fd4p+29', '0x1.a5a10175622d9p+29'), |
| 923 | ('0x1.57a8596e74722p+30', '0x1.42d1af9d04da9p+30'), |
| 924 | |
| 925 | # Cases with 1 ulp error in version fff3c28052e6b0 |
| 926 | ('0x1.ee7dbd9565899p+29', '0x1.7ab4d6fc6e4b4p+29'), |
| 927 | ('0x1.5c6bfbec5c4dcp+30', '0x1.02511184b4970p+30'), |
| 928 | ('0x1.59dcebba995cap+30', '0x1.50ca7e7c38854p+29'), |
| 929 | ('0x1.768cdd94cf5aap+29', '0x1.9cfdc5571d38ep+29'), |
| 930 | ('0x1.dcf137d60262ep+29', '0x1.1101621990b3ep+30'), |
| 931 | ('0x1.3a2d006e288b0p+30', '0x1.e9a240914326cp+29'), |
| 932 | ('0x1.62a32f7f53c61p+29', '0x1.47eb6cd72684fp+29'), |
| 933 | ('0x1.d3bcb60748ef2p+29', '0x1.3f13c4056312cp+30'), |
| 934 | ('0x1.282bdb82f17f3p+30', '0x1.640ba4c4eed3ap+30'), |
| 935 | ('0x1.89d8c423ea0c6p+29', '0x1.d35dcfe902bc3p+29'), |
| 936 | ]: |
| 937 | x = float.fromhex(hx) |
| 938 | y = float.fromhex(hy) |
| 939 | with self.subTest(hx=hx, hy=hy, x=x, y=y): |
| 940 | with decimal.localcontext(high_precision): |
| 941 | z = float((Decimal(x)**2 + Decimal(y)**2).sqrt()) |