tricu

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

float_finite_test.py (3621B)


      1 #!/usr/bin/env python3
      2 import math
      3 import struct
      4 import sys
      5 import unittest
      6 
      7 from float_finite import SIGN, LIMIT, MASK, cases, oracle, finite_value, normalized, special_words
      8 from float_quantize import dyadic, BIAS
      9 
     10 
     11 def host_float(bits): return struct.unpack('>d',bits.to_bytes(8,'big'))[0]
     12 def host_bits(x): return int.from_bytes(struct.pack('>d',x),'big')
     13 
     14 
     15 class FiniteTests(unittest.TestCase):
     16     def test_signed_zero_matrix(self):
     17         for a in [0,SIGN]:
     18             for b in [0,SIGN]:
     19                 for sub in [False,True]:
     20                     negative=bool(a) and (bool(b)!=sub)
     21                     self.assertEqual(oracle(a,b,sub),(True,(SIGN if negative else 0,False,False)))
     22 
     23     def test_cancellation_and_zero_identity(self):
     24         for w in special_words():
     25             self.assertEqual(oracle(w,w,True),(True,(0,False,False)))
     26             self.assertEqual(oracle(w,w^SIGN),(True,(0,False,False)))
     27             if w & MASK:
     28                 self.assertEqual(oracle(w,0),(True,(w,False,False)))
     29                 self.assertEqual(oracle(0,w,True),(True,(w^SIGN,False,False)))
     30 
     31     def test_normalization_establishes_invariants(self):
     32         words=special_words()+[sign|2**k for sign in [0,SIGN] for k in range(52)]
     33         for word in words:
     34             sign,scale,m=normalized(word)
     35             self.assertEqual((-1 if sign else 1)*dyadic(m,scale-BIAS),finite_value(word))
     36             if m:
     37                 self.assertTrue(2**52<=m<2**53)
     38                 self.assertTrue(1178<=scale<=3275)
     39             else:self.assertEqual(word & MASK,0)
     40 
     41     def test_subnormal_transition_and_signed_overflow(self):
     42         self.assertEqual(oracle(2**52-1,1),(True,(2**52,False,False)))
     43         self.assertEqual(oracle(2**52,1,True),(True,(2**52-1,False,False)))
     44         self.assertEqual(oracle(SIGN|1,SIGN|1),(True,(SIGN|2,False,False)))
     45         self.assertEqual(oracle(0x7fefffffffffffff,0x7fefffffffffffff),(True,(0x7ff0000000000000,True,False)))
     46         self.assertEqual(oracle(0xffefffffffffffff,0xffefffffffffffff),(True,(0xfff0000000000000,True,False)))
     47 
     48     def test_rejection_and_precedence(self):
     49         for w in [0x7ff0000000000000,0xfff0000000000000,0x7ff0000000000001,0xfff8000000000001]:
     50             self.assertEqual(oracle(w,0),(False,1))
     51             self.assertEqual(oracle(0,w,True),(False,1))
     52             self.assertEqual(oracle(w,LIMIT),(False,2))
     53         self.assertEqual(oracle(2**128,0),(False,2))
     54 
     55     @unittest.skipUnless(sys.float_info.radix==2 and sys.float_info.mant_dig==53 and sys.float_info.rounds==1,
     56                          'requires nearest-rounding binary64 Python floats')
     57     def test_corpus_against_host_and_exact_flags(self):
     58         for a,b in cases():
     59             for sub in [False,True]:
     60                 ok,(bits,inexact,underflow)=oracle(a,b,sub)
     61                 self.assertTrue(ok)
     62                 fa,fb=host_float(a),host_float(b)
     63                 actual=fa-fb if sub else fa+fb
     64                 self.assertEqual(bits,host_bits(actual),(hex(a),hex(b),sub))
     65                 x=finite_value(a)+(-finite_value(b) if sub else finite_value(b))
     66                 self.assertEqual(inexact,math.isinf(actual) or finite_value(bits)!=x)
     67                 # Finite binary64 operands are multiples of the minimum quantum:
     68                 # an add/sub result in the subnormal range is exactly representable.
     69                 self.assertFalse(underflow)
     70 
     71     def test_algebraic_sign_relations(self):
     72         for a,b in cases()[::17]:
     73             self.assertEqual(oracle(a,b),oracle(b,a))
     74             self.assertEqual(oracle(a,b,True),oracle(a,b^SIGN))
     75 
     76 
     77 if __name__=='__main__':unittest.main()