float_working_test.py (3509B)
1 #!/usr/bin/env python3 2 import hashlib 3 import os 4 from pathlib import Path 5 import subprocess 6 import unittest 7 8 from float_working import cases, groups, chain_oracle, working_parts 9 from float_finite import finite_value, special_words 10 from float_ieee import SIGN, INF, QNAN, QUIET, OPS, oracle, nan, class_words, dyadic 11 12 13 def reconstruct(parts): 14 kind,negative,scale,m=parts 15 if kind==0:word=0 16 elif kind==2:word=INF 17 elif kind==3:word=INF|m 18 elif scale>=1230:word=((scale-1229)<<52)|(m-2**52) 19 else:word=m>>(1230-scale) 20 return word|(SIGN if negative else 0) 21 22 23 def host_trace(reference): 24 rows=[];expected=[] 25 for initial,pool,steps in cases(): 26 word=initial 27 for op,index in steps: 28 rows.append(f'{op} {word:016x} {pool[index]:016x}\n') 29 ok,(word,flags)=oracle(word,pool[index],OPS[op]);assert ok 30 expected.append((word,flags)) 31 raw=''.join(rows).encode() 32 result=subprocess.run([str(reference)],input=raw,capture_output=True,check=True,timeout=60) 33 lines=result.stdout.splitlines();assert len(lines)==len(expected) 34 for line,(word,flags) in zip(lines,expected): 35 actual,raised=line.split();actual=int(actual,16);raised=int(raised) 36 assert raised==sum(int(f)<<i for i,f in enumerate(flags)) 37 if nan(word):assert nan(actual) and actual&QUIET 38 else:assert actual==word 39 return dict(checked_steps=len(expected),input_sha256=hashlib.sha256(raw).hexdigest(), 40 output_sha256=hashlib.sha256(result.stdout).hexdigest(), 41 reference_sha256=hashlib.sha256(Path(reference).read_bytes()).hexdigest()) 42 43 44 class WorkingTests(unittest.TestCase): 45 def test_decode_encode_and_finite_invariant(self): 46 words=special_words()+class_words()+[chain_oracle(row)[0] for row in cases()] 47 for word in words: 48 parts=working_parts(word);kind,sign,s,m=parts 49 self.assertEqual(reconstruct(parts),word) 50 if kind==1: 51 self.assertEqual(m.bit_length(),53) 52 self.assertTrue(1178<=s<=3275) 53 self.assertEqual((-1 if sign else 1)*dyadic(m,s-2304),finite_value(word)) 54 if s<1230:self.assertEqual(m%(1<<(1230-s)),0) 55 elif kind in [0,2]:self.assertEqual((s,m),(0,0)) 56 else:self.assertTrue(0<m<2**52) 57 58 def test_far_branch_bound(self): 59 for lower in range(1178,3276): 60 for gap in [55,56,127,2097]: 61 dominant=lower+gap 62 if dominant<=3275:self.assertGreaterEqual(dominant,1233) 63 64 def test_no_fused_precision(self): 65 row=(0x3ff0000000000000,[0x3ca0000000000000],[(0,0)]*2) 66 self.assertEqual(chain_oracle(row),(0x3ff0000000000000,(False,False,False,False,True))) 67 68 def test_empty_preserves_signaling_payload(self): 69 for word in [SIGN,INF|1,SIGN|QNAN|123]: 70 self.assertEqual(chain_oracle((word,[],[])),(word,(False,)*5)) 71 self.assertEqual(reconstruct(working_parts(word)),word) 72 73 def test_pool_reuse_is_not_numeric_change(self): 74 g=groups() 75 self.assertEqual([chain_oracle(r) for r in g['affine-reuse-16']], 76 [chain_oracle(r) for r in g['affine-unique-16']]) 77 78 @unittest.skipUnless(os.environ.get('TRICU_FLOAT_HOST'),'set TRICU_FLOAT_HOST to C fenv reference') 79 def test_steps_against_c_fenv(self): 80 self.assertGreater(host_trace(os.environ['TRICU_FLOAT_HOST'])['checked_steps'],14000) 81 82 83 if __name__=='__main__':unittest.main()