tricu

A lazy functional language based on Tree Calculus
Log | Files | Refs | README | LICENSE

float_aligned_quantize_test.py (3150B)


      1 #!/usr/bin/env python3
      2 from bisect import bisect_left
      3 from fractions import Fraction
      4 import math
      5 import struct
      6 import sys
      7 import unittest
      8 
      9 from float_aligned_quantize import cases, exact, nearest
     10 from float_quantize import BIAS, dyadic, value
     11 
     12 
     13 class FarAlignmentTests(unittest.TestCase):
     14     def test_exhaustive_small_precision_midpoint_classes(self):
     15         checked=0
     16         for p in range(2,6):
     17             lo,hi=2**(p-1),2**p-1
     18             values=[dyadic(m,-6) for m in range(lo)]
     19             values += [dyadic(m,e) for e in range(-6,4) for m in range(lo,hi+1)]
     20             virtual=dyadic(2**p,3)
     21             def rounded(x):
     22                 i=bisect_left(values,x)
     23                 if i==len(values):
     24                     return i if x >= (values[-1]+virtual)/2 else i-1
     25                 if values[i]==x or i==0: return i
     26                 below,above=x-values[i-1],values[i]-x
     27                 return i-1 if below<above or (below==above and (i-1)%2==0) else i
     28             for a in range(lo,hi+1):
     29                 for b in range(lo,hi+1):
     30                     for gap in range(p+2,p+5):
     31                         for e in range(-p-7,6):
     32                             for sign in [-1,1]:
     33                                 actual=dyadic(a,e)+sign*dyadic(b,e-gap)
     34                                 surrogate=dyadic(8*a+sign,e-3)
     35                                 self.assertEqual(rounded(actual),rounded(surrogate))
     36                                 checked+=1
     37         self.assertGreater(checked,30000)
     38 
     39     def test_discarding_residual_does_not_preserve_midpoints(self):
     40         add=(1177,55,2**52,2**52)
     41         sub=(1178,55,3*2**51,2**52)
     42         self.assertEqual(nearest(exact(add)),(1,True,True))
     43         self.assertEqual(nearest(dyadic(add[2],add[0]-BIAS))[0],0)
     44         self.assertEqual(nearest(exact(sub,True)),(1,True,True))
     45         self.assertEqual(nearest(dyadic(sub[2],sub[0]-BIAS))[0],2)
     46 
     47     def test_threshold_is_strict(self):
     48         # At gap 54 the decrement can exceed the midpoint below a power of two.
     49         row=(2252,54,2**52,2**53-1)
     50         self.assertEqual(nearest(exact(row,True))[0],0x3fefffffffffffff)
     51         self.assertEqual(nearest(dyadic(8*row[2]-1,row[0]-BIAS-3))[0],0x3ff0000000000000)
     52 
     53     def test_surrogate_on_full_binary64_far_corpus(self):
     54         for scale,gap,a,b in cases():
     55             if gap<55: continue
     56             for sub in [False,True]:
     57                 self.assertEqual(nearest(exact((scale,gap,a,b),sub)),
     58                                  nearest(dyadic(8*a+(-1 if sub else 1),scale-BIAS-3)))
     59 
     60     @unittest.skipUnless(sys.float_info.radix==2 and sys.float_info.mant_dig==53,
     61                          'requires binary64 Python floats')
     62     def test_exact_fraction_oracle_against_host(self):
     63         for row in cases():
     64             for sub in [False,True]:
     65                 x=exact(row,sub)
     66                 try: f=float(x)
     67                 except OverflowError: f=math.inf
     68                 bits=int.from_bytes(struct.pack('>d',f),'big')
     69                 inexact=math.isinf(f) or value(bits)!=x
     70                 self.assertEqual(nearest(x),(bits,inexact,inexact and bits<2**52))
     71 
     72 
     73 if __name__=='__main__': unittest.main()