float_alignment_test.py (2306B)
1 #!/usr/bin/env python3 2 """Independent small-precision exhaustion and binary64 alignment boundaries.""" 3 import unittest 4 import random 5 import sys 6 from float_alignment import exact_round, expected 7 8 9 class AlignmentTests(unittest.TestCase): 10 def test_far_threshold_exhaustive_small_precisions(self): 11 for p in range(2,7): 12 lo,hi = 1 << (p-1),(1 << p)-1 13 for a in range(lo,hi+1): 14 for b in range(lo,hi+1): 15 for gap in range(p+2,p+6): 16 for sign in [-1,1]: 17 self.assertEqual(exact_round((a << gap)+sign*b,p),(gap,a,True)) 18 19 def test_one_less_is_not_safe_for_subtraction(self): 20 for p in range(2,54): 21 lo = 1 << (p-1) 22 gap = p+1 23 # At the binade boundary the spacing below is half that above. 24 self.assertEqual(exact_round((lo << gap)-lo,p),(gap,lo,True)) 25 self.assertEqual(exact_round((lo << gap)-(lo+1),p), 26 (gap-1,(1 << p)-1,True)) 27 28 def test_cancellation_and_exact_add(self): 29 lo = 1 << 52 30 self.assertEqual(expected(lo,lo,0,True),(0,0,False)) 31 self.assertEqual(expected(lo+1,lo,0,True),(0,1,False)) 32 self.assertEqual(expected(lo,lo,0),(1,lo,False)) 33 34 @unittest.skipUnless(sys.float_info.radix == 2 and sys.float_info.mant_dig == 53, 35 'requires a binary64 Python float host') 36 def test_oracle_against_host_integer_rounding(self): 37 rng = random.Random(5355) 38 for _ in range(512): 39 a,b = sorted([rng.randrange(2**52,2**53) for _ in range(2)], reverse=True) 40 gap = rng.randrange(61) 41 for sign in [-1,1]: 42 n = (a << gap)+sign*b 43 cut,m,inexact = exact_round(n) 44 rounded = int(float(n)) 45 self.assertEqual(m << cut, rounded) 46 self.assertEqual(inexact, rounded != n) 47 48 def test_real_exponent_extremes(self): 49 lo,hi = 1 << 52,(1 << 53)-1 50 for gap in [55,56,1022,1074,2046,2097]: 51 for a,b in [(lo,lo),(lo,hi),(hi,lo),(hi,hi)]: 52 for subtract in [False,True]: 53 self.assertEqual(expected(a,b,gap,subtract),(gap,a,True)) 54 55 56 if __name__ == '__main__': 57 unittest.main()