|
16 | 16 | INF = float('inf') |
17 | 17 | NINF = float('-inf') |
18 | 18 | FLOAT_MAX = sys.float_info.max |
| 19 | +FLOAT_MIN = sys.float_info.min |
19 | 20 |
|
20 | 21 | # detect evidence of double-rounding: fsum is not always correctly |
21 | 22 | # rounded on machines that suffer from double rounding. |
@@ -720,16 +721,71 @@ def testGcd(self): |
720 | 721 | self.assertEqual(gcd(MyIndexable(120), MyIndexable(84)), 12) |
721 | 722 |
|
722 | 723 | def testHypot(self): |
723 | | - self.assertRaises(TypeError, math.hypot) |
724 | | - self.ftest('hypot(0,0)', math.hypot(0,0), 0) |
725 | | - self.ftest('hypot(3,4)', math.hypot(3,4), 5) |
726 | | - self.assertEqual(math.hypot(NAN, INF), INF) |
727 | | - self.assertEqual(math.hypot(INF, NAN), INF) |
728 | | - self.assertEqual(math.hypot(NAN, NINF), INF) |
729 | | - self.assertEqual(math.hypot(NINF, NAN), INF) |
730 | | - self.assertRaises(OverflowError, math.hypot, FLOAT_MAX, FLOAT_MAX) |
731 | | - self.assertTrue(math.isnan(math.hypot(1.0, NAN))) |
732 | | - self.assertTrue(math.isnan(math.hypot(NAN, -2.0))) |
| 724 | + from decimal import Decimal |
| 725 | + from fractions import Fraction |
| 726 | + |
| 727 | + hypot = math.hypot |
| 728 | + |
| 729 | + # Test different numbers of arguments (from zero to five) |
| 730 | + # against a straightforward pure python implementation |
| 731 | + args = math.e, math.pi, math.sqrt(2.0), math.gamma(3.5), math.sin(2.1) |
| 732 | + for i in range(len(args)+1): |
| 733 | + self.assertAlmostEqual( |
| 734 | + hypot(*args[:i]), |
| 735 | + math.sqrt(sum(s**2 for s in args[:i])) |
| 736 | + ) |
| 737 | + |
| 738 | + # Test allowable types (those with __float__) |
| 739 | + self.assertEqual(hypot(12.0, 5.0), 13.0) |
| 740 | + self.assertEqual(hypot(12, 5), 13) |
| 741 | + self.assertEqual(hypot(Decimal(12), Decimal(5)), 13) |
| 742 | + self.assertEqual(hypot(Fraction(12, 32), Fraction(5, 32)), Fraction(13, 32)) |
| 743 | + self.assertEqual(hypot(bool(1), bool(0), bool(1), bool(1)), math.sqrt(3)) |
| 744 | + |
| 745 | + # Test corner cases |
| 746 | + self.assertEqual(hypot(0.0, 0.0), 0.0) # Max input is zero |
| 747 | + self.assertEqual(hypot(-10.5), 10.5) # Negative input |
| 748 | + self.assertEqual(hypot(), 0.0) # Negative input |
| 749 | + self.assertEqual(1.0, |
| 750 | + math.copysign(1.0, hypot(-0.0)) # Convert negative zero to positive zero |
| 751 | + ) |
| 752 | + |
| 753 | + # Test handling of bad arguments |
| 754 | + with self.assertRaises(TypeError): # Reject keyword args |
| 755 | + hypot(x=1) |
| 756 | + with self.assertRaises(TypeError): # Reject values without __float__ |
| 757 | + hypot(1.1, 'string', 2.2) |
| 758 | + |
| 759 | + # Any infinity gives positive infinity. |
| 760 | + self.assertEqual(hypot(INF), INF) |
| 761 | + self.assertEqual(hypot(0, INF), INF) |
| 762 | + self.assertEqual(hypot(10, INF), INF) |
| 763 | + self.assertEqual(hypot(-10, INF), INF) |
| 764 | + self.assertEqual(hypot(NAN, INF), INF) |
| 765 | + self.assertEqual(hypot(INF, NAN), INF) |
| 766 | + self.assertEqual(hypot(NINF, NAN), INF) |
| 767 | + self.assertEqual(hypot(NAN, NINF), INF) |
| 768 | + self.assertEqual(hypot(-INF, INF), INF) |
| 769 | + self.assertEqual(hypot(-INF, -INF), INF) |
| 770 | + self.assertEqual(hypot(10, -INF), INF) |
| 771 | + |
| 772 | + # If no infinity, any NaN gives a Nan. |
| 773 | + self.assertTrue(math.isnan(hypot(NAN))) |
| 774 | + self.assertTrue(math.isnan(hypot(0, NAN))) |
| 775 | + self.assertTrue(math.isnan(hypot(NAN, 10))) |
| 776 | + self.assertTrue(math.isnan(hypot(10, NAN))) |
| 777 | + self.assertTrue(math.isnan(hypot(NAN, NAN))) |
| 778 | + self.assertTrue(math.isnan(hypot(NAN))) |
| 779 | + |
| 780 | + # Verify scaling for extremely large values |
| 781 | + fourthmax = FLOAT_MAX / 4.0 |
| 782 | + for n in range(32): |
| 783 | + self.assertEqual(hypot(*([fourthmax]*n)), fourthmax * math.sqrt(n)) |
| 784 | + |
| 785 | + # Verify scaling for extremely small values |
| 786 | + for exp in range(32): |
| 787 | + scale = FLOAT_MIN / 2.0 ** exp |
| 788 | + self.assertEqual(math.hypot(4*scale, 3*scale), 5*scale) |
733 | 789 |
|
734 | 790 | def testLdexp(self): |
735 | 791 | self.assertRaises(TypeError, math.ldexp) |
|
0 commit comments