[Python-checkins] python/nondist/sandbox/pickletools pickletools.py,1.2,1.3

tim_one@users.sourceforge.net tim_one@users.sourceforge.net
Sat, 25 Jan 2003 15:44:22 -0800


Update of /cvsroot/python/python/nondist/sandbox/pickletools
In directory sc8-pr-cvs1:/tmp/cvs-serv17068

Modified Files:
	pickletools.py 
Log Message:
Fleshed out the two ways to pickle floats.  It's best not to think too
much about all the ways this can screw up <0.6 wink>.


Index: pickletools.py
===================================================================
RCS file: /cvsroot/python/python/nondist/sandbox/pickletools/pickletools.py,v
retrieving revision 1.2
retrieving revision 1.3
diff -C2 -d -r1.2 -r1.3
*** pickletools.py	25 Jan 2003 22:32:08 -0000	1.2
--- pickletools.py	25 Jan 2003 23:44:19 -0000	1.3
***************
*** 223,226 ****
--- 223,283 ----
                           """)
  
+ 
+ def read_floatnl(f):
+     """
+     >>> import StringIO
+     >>> read_floatnl(StringIO.StringIO("-1.25\\n6"))
+     -1.25
+     """
+     s = read_stringnl(f, decode=False)
+     return float(s)
+ 
+ floatnl = ArgumentDescriptor(
+               name='floatnl',
+               n=None,
+               reader=read_floatnl,
+               doc="""A newline-terminated decimal floating literal.
+ 
+               In general this requires 17 significant digits for roundtrip
+               identity, and pickling then unpickling infinities, NaNs, and
+               minus zero doesn't work across boxes, or on some boxes even
+               on itself (e.g., Windows can't read the strings it produces
+               for infinities or NaNs).
+               """)
+ 
+ def read_float8(f):
+     """
+     >>> import StringIO, struct
+     >>> raw = struct.pack(">d", -1.25)
+     >>> raw
+     '\\xbf\\xf4\\x00\\x00\\x00\\x00\\x00\\x00'
+     >>> read_float8(StringIO.StringIO(raw + "\\n"))
+     -1.25
+     """
+ 
+     data = f.read(8)
+     if len(data) == 8:
+         return _unpack(">d", data)[0]
+     raise ValueError("not enough data in stream to read float8")
+ 
+ 
+ float8 = ArgumentDescriptor(
+              name='float8',
+              n=8,
+              reader=read_float8,
+              doc="""An 8-byte binary representation of a float, big-endian.
+ 
+              The format is unique to Python, and shared with the struct
+              module (format string '>d') "in theory" (the struct and cPickle
+              implementations don't share the code -- they should).  It's
+              strongly related to the IEEE-754 double format, and, in normal
+              cases, is in fact identical to the big-endian 754 double format.
+              On other boxes the dynamic range is limited to that of a 754
+              double, and "add a half and chop" rounding is used to reduce
+              the precision to 53 bits.  However, even on a 754 box,
+              infinities, NaNs, and minus zero may not be handled correctly
+              (may not survive roundtrip pickling intact).
+              """)
+ 
  ##############################################################################
  # Python object descriptors.  The stack used by the pickle machine holds
***************
*** 268,271 ****
--- 325,332 ----
                  doc="A Python integer object, short or long.")
  
+ pyfloat = PythonObject(
+               name='float',
+               obtype=float,
+               doc="A Python float object.")
  
  ##############################################################################
***************
*** 392,395 ****
--- 453,494 ----
        """),
  
+     # Two ways to spell floats.
+ 
+     I(name='FLOAT',
+       code='F',
+       args=[floatnl],
+       stack_before=[],
+       stack_after=[pyfloat],
+       proto=0,
+       doc="""Newline-terminated decimal float literal.
+ 
+       The argument is repr(a_float), and in general requires 17 significant
+       digits for roundtrip conversion to be an identity (this is so for
+       IEEE-754 double precision values, which is what Python float maps to
+       on most boxes).
+ 
+       In general, FLOAT cannot be used to transport infinities, NaNs, or
+       minus zero across boxes (or even on a single box, if the platform C
+       library can't read the strings it produces for such things -- Windows
+       is like that), but may do less damage than BINFLOAT on boxes with
+       greater precision or dynamic range than IEEE-754 double.
+       """),
+ 
+     I(name='BINFLOAT',
+       code='G',
+       args=[float8],
+       stack_before=[],
+       stack_after=[pyfloat],
+       proto=1,
+       doc="""Float stored in binary form, with 8 bytes of data.
+ 
+       This generally requires less than half the space of FLOAT encoding.
+       In general, BINFLOAT cannot be used to transport infinities, NaNs, or
+       minus zero, raises an exception if the exponent exceeds the range of
+       an IEEE-754 double, and retains no more than 53 bits of precision (if
+       there are more than that, "add a half and chop" rounding is used to
+       cut it back to 53 significant bits).
+       """),
+ 
      # XXX opcodes below this point haven't been done yet.
  
***************
*** 449,463 ****
        """),
  
-     I(name='FLOAT',
-       code='F',
-       args=[],
-       stack_before=[],
-       stack_after=[],
-       proto=0,
-       doc="""XXX One-line description goes here.
- 
-       XXX Doc body goes here.
-       """),
- 
      I(name='NONE',
        code='N',
--- 548,551 ----
***************
*** 770,784 ****
      I(name='SETITEMS',
        code='u',
-       args=[],
-       stack_before=[],
-       stack_after=[],
-       proto=0,
-       doc="""XXX One-line description goes here.
- 
-       XXX Doc body goes here.
-       """),
- 
-     I(name='BINFLOAT',
-       code='G',
        args=[],
        stack_before=[],
--- 858,861 ----