tricu

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

float_quantize_test.py (2460B)


      1 #!/usr/bin/env python3
      2 import math
      3 import struct
      4 import sys
      5 import unittest
      6 
      7 from float_alignment import exact_round
      8 from float_quantize import BIAS, INF, MAX, cases, near_cases, dyadic, oracle, value
      9 
     10 
     11 class QuantizerTests(unittest.TestCase):
     12     def test_zero_and_subnormal_halfway(self):
     13         self.assertEqual(oracle(0,0),(0,False,False))
     14         self.assertEqual(oracle(1,BIAS-1075),(0,True,True))
     15         self.assertEqual(oracle(3,BIAS-1075),(2,True,True))
     16         self.assertEqual(oracle(1,BIAS-1074),(1,False,False))
     17 
     18     def test_transition_uses_tininess_after_rounding(self):
     19         self.assertEqual(oracle(2**53-1,BIAS-1075),(2**52,True,False))
     20         self.assertEqual(oracle(2**52-1,BIAS-1074),(2**52-1,False,False))
     21 
     22     def test_overflow_halfway(self):
     23         self.assertEqual(oracle(2**53-1,BIAS+971),(MAX,False,False))
     24         self.assertEqual(oracle(2**54-1,BIAS+970),(INF,True,False))
     25         self.assertEqual(oracle((2**54-1)*2-1,BIAS+969),(MAX,True,False))
     26 
     27     def test_double_rounding_in_both_directions(self):
     28         for n,wrong in [(2**54+5,2**51),(2**54+11,2**51+2)]:
     29             scale=BIAS-1077
     30             self.assertEqual(oracle(n,scale),(2**51+1,True,True))
     31             cut,m,_=exact_round(n)
     32             self.assertEqual(oracle(m,scale+cut)[0],wrong)
     33 
     34     def test_cancellation_normalization(self):
     35         self.assertEqual(oracle(1,BIAS-52),(971 << 52,False,False))
     36         self.assertEqual(oracle(1,BIAS-1074),(1,False,False))
     37         self.assertEqual(oracle(2**52,BIAS-1074),(1 << 52,False,False))
     38 
     39     def test_equivalent_exact_coordinates(self):
     40         for n,scale in cases()[::13]:
     41             for shift in [1,52,107]:
     42                 if scale >= shift:
     43                     self.assertEqual(oracle(n,scale),oracle(n << shift,scale-shift))
     44 
     45     @unittest.skipUnless(sys.float_info.radix==2 and sys.float_info.mant_dig==53,
     46                          'requires binary64 Python floats')
     47     def test_exact_fraction_conversion_and_flags(self):
     48         rows=cases()+[((a << gap)+sign*b,scale) for scale,gap,a,b in near_cases() for sign in [-1,1]]
     49         for n,scale in rows:
     50             x=dyadic(n,scale-BIAS)
     51             try: f=float(x)
     52             except OverflowError: f=math.inf
     53             bits=int.from_bytes(struct.pack('>d',f),'big')
     54             inexact=math.isinf(f) or value(bits)!=x
     55             self.assertEqual(oracle(n,scale),(bits,inexact,inexact and bits < 2**52))
     56 
     57 
     58 if __name__=='__main__': unittest.main()