[Python-checkins] python/dist/src/Lib/test test_struct.py,1.14,1.14.12.1

tim_one@users.sourceforge.net tim_one@users.sourceforge.net
Thu, 20 Mar 2003 10:31:30 -0800


Update of /cvsroot/python/python/dist/src/Lib/test
In directory sc8-pr-cvs1:/tmp/cvs-serv6172/Lib/test

Modified Files:
      Tag: release22-maint
	test_struct.py 
Log Message:
SF bug 705836: struct.pack of floats in non-native endian order

pack_float, pack_double, save_float:  All the routines for creating
IEEE-format packed representations of floats and doubles simply ignored
that rounding can (in rare cases) propagate out of a long string of
1 bits.  At worst, the end-off carry can (by mistake) interfere with
the exponent value, and then unpacking yields a result wrong by a factor
of 2.  In less severe cases, it can end up losing more low-order bits
than intended, or fail to catch overflow *caused* by rounding.


Index: test_struct.py
===================================================================
RCS file: /cvsroot/python/python/dist/src/Lib/test/test_struct.py,v
retrieving revision 1.14
retrieving revision 1.14.12.1
diff -C2 -d -r1.14 -r1.14.12.1
*** test_struct.py	15 Sep 2001 02:35:15 -0000	1.14
--- test_struct.py	20 Mar 2003 18:30:52 -0000	1.14.12.1
***************
*** 394,395 ****
--- 394,441 ----
  
  test_p_code()
+ 
+ 
+ ###########################################################################
+ # SF bug 705836.  "<f" and ">f" had a severe rounding bug, where a carry
+ # from the low-order discarded bits could propagate into the exponent
+ # field, causing the result to be wrong by a factor of 2.
+ 
+ def test_705836():
+     import math
+ 
+     for base in range(1, 33):
+         # smaller <- largest representable float less than base.
+         delta = 0.5
+         while base - delta / 2.0 != base:
+             delta /= 2.0
+         smaller = base - delta
+         # Packing this rounds away a solid string of trailing 1 bits.
+         packed = struct.pack("<f", smaller)
+         unpacked = struct.unpack("<f", packed)[0]
+         # This failed at base = 2, 4, and 32, with unpacked = 1, 2, and
+         # 16, respectively.
+         verify(base == unpacked)
+         bigpacked = struct.pack(">f", smaller)
+         verify(bigpacked == string_reverse(packed),
+                ">f pack should be byte-reversal of <f pack")
+         unpacked = struct.unpack(">f", bigpacked)[0]
+         verify(base == unpacked)
+ 
+     # Largest finite IEEE single.
+     big = (1 << 24) - 1
+     big = math.ldexp(big, 127 - 23)
+     packed = struct.pack(">f", big)
+     unpacked = struct.unpack(">f", packed)[0]
+     verify(big == unpacked)
+ 
+     # The same, but tack on a 1 bit so it rounds up to infinity.
+     big = (1 << 25) - 1
+     big = math.ldexp(big, 127 - 24)
+     try:
+         packed = struct.pack(">f", big)
+     except OverflowError:
+         pass
+     else:
+         TestFailed("expected OverflowError")
+ 
+ test_705836()