On 11/13/06, Gary S. Thompson <garyt@xxxxxxxxxxxxxxx> wrote:
edward.dauvergne@xxxxxxxxx wrote:
>Author: bugman
>Date: Sat Nov 11 10:57:35 2006
>New Revision: 2801
>
>URL: http://svn.gna.org/viewcvs/relax?rev=2801&view=rev
>Log:
>Two functions for converting a string bit pattern to a float and a number of
IEEE-754 constants.
>
>The fucntions 'bitpatternToFloat()' and 'bitpatternToInt()' have been added
to 'float.py'. The
>first converts a 64 bit IEEE-754 bit pattern in the form of a string into a
64 bit Python float.
>The second converts an arbitrary bit pattern into its integer
representation. By looping over each
>8 characters of the string (1 byte), 'bitpatternToFloat()' calls
'bitpatternToInt()' to create an
>array of integers. Then 'packBytesAsPyFloat()' is called to convert the
byte array into the float.
>These two functions convert between big and little endian when necessary.
>
>
Nice functions! However, I would suggest that these should go in utility
functions or the test suite.... I am trying to keep float.py as the
bare minimum file for testing floating point numbers and floating point
constants
I agree - these string to float conversions are auxiliary to intended
purpose of the IEEE-754 module. Unfortunately as you hadn't committed
the utility function code yet - I wasn't able to put the functions
there :).
How would you like to design the ieee754 module? Have you searched
for documentation describing how to create standard Python modules,
i.e. the format and structure of the modules? Should the utility
functions be part of the module? Or should the be their own module?
The 'bitpatternToFloat()' function I added is 100% specific to
IEEE-754 though. Do you think it would be a good idea, for future
Python inclusion and to improve on 'fpconst', to create a module which
includes as many IEEE-754 related functions as possible?
A couple of other matters as well
1. the constants are not much use at the end of the file as if anything
else in the file wants to refer to them they won't be able to
I didn't expect anything in 'float.py' to use them. I just expanded
the constants proposed in PEP-754
(http://www.python.org/dev/peps/pep-0754/) into a complete list of all
the IEEE-754 special numbers. That was pretty simple to do. They can
be imported into the unit tests as an accurate replacement for
FLOAT_EPSILON, etc. Their main usage would be by the users of the
module.
2. I was thinking of a test case with random numbers in the exponent of
the nan and then reporting what the bit pattern that failed was....
You mean mantissa? The three NaN just give the users of the module a
few different NaN numbers to play with. I can't stand the way I've
named them though!
3. I was also thinking of having test caseswith minimum and maximum bit
patterns e.g. max denorm min denorm nan with highest mantissa bit set
nan with smallest mantissa bit set etc
These can still be pre-defined constants within the ieee754 module for
others to use. We may as well give the users of the module access to
a complete series of ieee754 special numbers, including the limits.
Essentially I have added all of the 64 bit special values discussed in
the current Wikipedia article http://en.wikipedia.org/wiki/IEEE-754.
>By passing big-endian 64 bit patterns to the 'bitpatternToFloat()' function,
the following IEEE-754
>constants are defined:
> PosZero:
0000000000000000000000000000000000000000000000000000000000000000
> NegZero:
1000000000000000000000000000000000000000000000000000000000000000
> PosEpsilonDenorm:
0000000000000000000000000000000000000000000000000000000000000001
> NegEpsilonDenorm:
1000000000000000000000000000000000000000000000000000000000000001
> PosEpsilonNorm:
0000000000010000000000000000000000000000000000000000000000000001
> NegEpsilonNorm:
1000000000010000000000000000000000000000000000000000000000000001
> PosMax:
0111111111101111111111111111111111111111111111111111111111111111
> NegMin:
1111111111101111111111111111111111111111111111111111111111111111
> PosInf:
0111111111110000000000000000000000000000000000000000000000000000
> NegInf:
1111111111110000000000000000000000000000000000000000000000000000
> PosNaN_A:
0111111111110000000000000000000000000000001000000000000000000000
> NegNaN_A:
1111111111110000000000000000000000000000001000000000000000000000
> PosNaN_B:
0111111111110000000000000000011111111111111111111110000000000000
> NegNaN_B:
1111111111110000000000000000011111111111111111111110000000000000
> PosNaN_C:
0111111111110101010101010101010101010101010101010101010101010101
> NegNaN_C:
1111111111110101010101010101010101010101010101010101010101010101
> PosNaN = PosNaN_C
> NegNaN = NegNaN_C
>
>
>
I have some code that reads and displays these as octes which makes life
easier...
11111111 11110101 01010101 01010101 01010101 01010101 01010101 01010101
I don't know if the spaces help much. As the mantissa is from 0-51,
the exponent from 52-62, and the sign bit is at position 63, wouldn't
the best place for spaces be to separate out the components of the
IEEE-754 float, e.g.:
1 1111111111 10101010101010101010101010101010101010101010101010101
ieee754 doesn't seem to be an octet based system.
>+def bitpatternToFloat(string, endian='big'):
>+ """Convert a 64 bit IEEE-754 ascii bit pattern into a 64 bit Python
float.
>+
>+ @param string: The ascii bit pattern repesenting the IEEE-754 float.
>+ @type string: str
>+ @param endian: The endianness of the bit pattern (can be 'big' or
'little').
>+ @type endian: str
>+ @return: The 64 bit float corresponding to the IEEE-754 bit
pattern.
>+ @returntype: float
>+ @raise: TypeError if 'string' is not a string, the length of
the 'string' is not 64, or
>+ if 'string' does not consist solely of the characters '0' and '1'.
>+ """
>+
>+ # Test that the bit pattern is a string.
>+ if type(string) != str:
>+ raise TypeError, "The string argument '%s' is not a string." %
string
>
>
I think this is to restrictive opther things can act as sequences...
Feel free to remove the test. I can see how it would be restrictive.
>+ # Test the length of the bit pattern.
>+ if len(string) != 64:
>+ raise TypeError, "The string '%s' is not 64 characters long." %
string
>+
>+ # Test that the string consists solely of zeros and ones.
>+ for char in string:
>+ if char not in ['0', '1']:
>+ raise TypeError, "The string '%s' should be composed solely of the
characters '0' and '1'." % string
>+
>+ # Reverse the byte order as neccessary.
>+ if endian == 'big' and sys.byteorder == 'little':
>+ string = string[::-1]
>+ elif endian == 'little' and sys.byteorder == 'big':
>+ string = string[::-1]
>+
>
>
this could be better written as
# Reverse the byte order as neccessary.
if endian != sys.byteorder:
string = string[::-1]
Good point. Again feel free to make the modification.
and then add an assert effectivley of the form endian..tolower() in
('little','big')
Is this necessary? If the user supplies dud arguments, I'm not sure
what to do. There should be Python standards for standard Python
modules somewhere which say how to properly handle incorrect user
input.
Edward