1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27 """ieeefloat a set of functions for dealing with IEEE-754 float objects.
28
29 On most platforms Python uses IEEE-754 double objects of length 64 bits to represent floats (some
30 architectures such as older Crays and Vaxes don't). Thus an IEEE-754 double is the implementation
31 of a python float object on most platforms.
32
33 IEEE-74 uses special bit patterns to represent the following states or classes of IEEE floating
34 point numbers (IEEE-class):
35 - +/- NaN: Not a number (e.g. 0.0/0.0).
36 - inf: Positive or negative infinity (1.0/0.0).
37 - +/- zero: Zero maybe positive or negative under IEEE-754.
38
39 This module provides functions for working with python floats and their special values, if they
40 contain IEEE-754 formatted values. Specifically:
41 - Pack and unpack a list of bytes representing an IEEE-754 double to a python float (takes care
42 of little endian/big endian issues).
43 - Get the sign bit of a python float.
44 - Check the ordering of python floats allowing for NaNs (NaNs cannot normally be compared).
45 - Check if a value is finite (as opposed to NaN or inf).
46 - Copy the sign of one float to another irrespective of if it's IEEE-class.
47 - Check if a float is denormalised (and might be about to underflow).
48 - Check the IEEE-class of a python float (NaN, pos-inf, neg-inf, pos-zero, neg-zero, ...).
49 - Check that the current python float implementations uses IEEE-754 doubles.
50
51 It also provides constants containg specific bit patterns for NaN and +-inf as these values cannot
52 be generated from strings via the constructor float(x) with some compiler implementations (typically
53 older Microsoft Windows compilers).
54
55 As a convenience the names of functions and constants conform to those defined in the draft python
56 PEP 754 'IEEE 754 Floating Point Special Values'.
57
58 Notes:
59 1. Binary data is documented as binary strings e.g. 0xF0 = 0b11110000.
60 2. The module doesn't support all the functions recommended by IEEE-754, the following features
61 are missing:
62 - Control of exception and rounding modes.
63 - scalb(y, N).
64 - logb(x).
65 - nextafter(x,y).
66 - Next towards.
67 3. Division by zero currently (python 2.5) raises exception and the resulting inf/NaN cannot be
68 propogated.
69 4. A second module ieeefloatcapabilities (currently incomplete) provides tests of the
70 capabilities of a floating point implementation on a specific python platform.
71 5. Development and conventions on byte order come from a little endian (Intel) platform.
72 6. To reduce overheads all functions that take python float arguments do _no type_ conversion
73 thus if other numeric types are passed the functions will raise exceptions, (I am not sure
74 this is the best behaviour however, as python functions should be polymorphic...).
75 7. In most cases conversion to C code for performance reasons would be trivial.
76
77 IEEE-754 double format:
78 - 63 sign bit.
79 - 62-52 exponent (offset by 1023 value - field-1023).
80 - 51-0 mantissa each bit n counts as 1/2^n, running from 1/2 which is the most significant bit
81 to 1/2^51, The 1/0 bit is defined by the exponent field if it has any bits set if it has bits
82 set then precede the mantissa with a 1 (normalised otherwise precede it by a 0 (denormalised).
83
84
85 Todo:
86 - Unit test suite.
87 - Test under Windows.
88 - Test under a Solaris Sparc box (big endian).
89 - Add example IEEE double.
90 - Check byte/nibble attributions.
91 """
92 from struct import pack, unpack
93 import sys
94
95
96 SIGNBIT = 0x80
97 """Bit pattern for the sign bit in byte 8 0b00000001 of a IEEE-754 double."""
98
99
100 EXPONENT_ALL_ONES_BYTE_1 = 0x7F
101 """Value of the first byte (byte 8) in the mantissa of a IEEE-754 double that is all ones
102 (0b11111110)."""
103
104 EXPONENT_ALL_ONES_BYTE_0 = 0xF << 4
105 """Value of the second byte (byte 7) in the mantissa of a IEEE-754 double that is all ones
106 (0b00001111)."""
107
108
109 MANTISSA_NIBBLE_MASK=0x0F
110 """Mask to select the bits from the first nibble of byte 7 of an IEEE-754 which is part of the
111 mantissa (0b00001111)."""
112
113 EXPONENT_NIBBLE_MASK=0xF0
114 """Mask to select the bits from the second nibble of byte 7 of an IEEE-754 which is part of the
115 exponent (0b11110000)."""
116
117
118 EXPONENT_SIGN_MASK= 0x7F
119 """Mask to select only bits from byte 8 of an IEEE-754 double that are not part of the sign bit
120 (0b11111110)."""
121
122 """Classes of floating point numbers."""
123 CLASS_POS_INF = 1
124 CLASS_NEG_INF = 2
125 CLASS_POS_NORMAL = 4
126 CLASS_NEG_NORMAL = 8
127 CLASS_POS_DENORMAL = 16
128 CLASS_NEG_DENORMAL = 32
129 CLASS_QUIET_NAN = 64
130 CLASS_SIGNAL_NAN = 128
131 CLASS_POS_ZERO = 256
132 CLASS_NEG_ZERO = 512
133
134
137
138
180
181
183 """Pack 8 bytes into a python float.
184
185 The function is endian aware and the data should be input in little endian format. Thus byte 8
186 contains the most significant bit of the exponent and the sign bit.
187
188 @param bytes: 8 bytes to pack into a python (IEEE 754 double) float.
189 @type bytes: float
190 @return: A python float
191 @rtype: float
192 @raise TypeError: If bytes contains < 8 bytes type of exception not determined.
193 """
194
195
196 doubleString=pack('8B',*bytes)
197
198
199 if sys.byteorder == 'big':
200 doubleString = doubleString[::-1]
201
202
203 return unpack('d', doubleString)[0]
204
205
206 NAN_BYTES = [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0x7F]
207 """Bytes for an arbitary IEEE-754 not a number (NaN) in little endian format
208 0b00000000 00000000 00000000 00000000 00000000 00000000 00011111 11111110."""
209
210
211 INF_BYTES = [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0x7F]
212 """Bytes for IEEE-754 positive infinity (inf) in little endian format
213 0b00000000 00000000 00000000 00000000 00000000 00000000 00001111 11111110."""
214
215
216 nan = packBytesAsPyFloat(NAN_BYTES)
217 """One of a number of possible bit patterns used to represent an IEEE-754 double as a python float.
218 Do not use this value for comparisons of the form x==NaN as it will fail on some platforms use
219 function isNaN instead."""
220
221
222 pos_inf = packBytesAsPyFloat(INF_BYTES)
223 """The value of a positive IEEE-754 double infinity as a python float."""
224
225
226 neg_inf = -1 * pos_inf
227 """The value of a negative IEEE-754 double infinity as a python float."""
228
229
231 """Pack a python float into a binary string.
232
233 This function assumes that the python type float it represents a 64bit double of 8 bytes. This
234 function reverses the resulting string if the current architecture is big endian.
235
236 @param obj: A python float to pack.
237 @type obj: float
238 @return: A string of 8 bytes.
239 @rtype: str
240 @raise TypeError: If the input object isn't a python float.
241 """
242
243 if not isinstance(obj, float):
244 raise TypeError('the object recieved wasn\'t a float, type was: %s' % type(obj))
245
246
247 packed =pack('d', obj)
248
249
250 if sys.byteorder == 'big':
251 packed = packed[::-1]
252
253 return packed
254
255
257 """Unpack a python float as a list of 8 bytes.
258
259 This function assumes that the python type float it represents a 64bit double of 8 bytes.
260
261 @param obj: A python float to unpack.
262 @type obj: float
263 @return: A list of 7 bytes.
264 @rtype: list of str
265 @raise TypeError: If obj is not composed of 8 bytes.
266 """
267
268
269 binaryString = floatToBinaryString(obj)
270
271
272 bytes = unpack('8B', binaryString)
273
274
275 return list(bytes)
276
277
279 """Get the sign bit from a python float.
280
281 @param obj: A python float object.
282 @type obj: float
283 @return: The float's sign bit, this has the value 1 if the float is negative
284 otherwise 0 (positive).
285 @rtype: bit
286 @raise TypeError: If the input object isn't a python float.
287 """
288
289
290 unpacked = floatAsByteArray(obj)
291
292
293 return unpacked[7] & SIGNBIT
294
295
297 """Test if a python float is positive.
298
299 @param obj: A python float object.
300 @type obj: float
301 @return: True if the float is positive otherwise False.
302 @rtype: bool
303 @raise TypeError: If the input object isn't a python float.
304 """
305
306 if getSignBit(obj):
307 return False
308 else:
309 return True
310
311
313 """Test if a python float 64 bit IEEE-74 double is negative.
314
315 @param obj: A python float object.
316 @type obj: float
317 @return: True if the float is negative.
318 @rtype: bool
319 @raise TypeError: If the input object isn't a python float.
320 """
321
322 return not isPositive(obj)
323
324
326 """Test to see if two python float are unordered.
327
328 Float comparison is unordered if either or both of the objects is 'not a number' (NaN).
329
330 @param obj1: A python float object
331 @type obj1: float
332 @param obj2: A python float object
333 @type obj2: float
334 @return: True if one of the args is a NaN.
335 @rtype: bool
336 @raise TypeError: If the input objects aren't python floats.
337 """
338
339
340 nanTest1 = isNaN(obj1)
341 nanTest2 = isNaN(obj2)
342
343
344 if nanTest1 or nanTest2:
345 return True
346 else:
347 return False
348
349
351 """Test to see if a python float is finite.
352
353 To be finite a number mustn't be a NaN or +/- inf. A result of True guarantees that the number
354 is bounded by +/- inf, -inf < x < inf.
355
356 @param obj: A python float object.
357 @type obj: float
358 @return: True if the float is finite.
359 @rtype: bool
360 @raise TypeError: If the input object isn't a python float.
361 """
362
363 result = True
364 if isNaN(obj):
365 result = False
366 if isInf(obj):
367 result = False
368
369
370 return result
371
372
374 """Copy the sign bit from one python float to another.
375
376 This function is class agnostic the sign bit can be copied freely between ordinary floats, NaNs
377 and +/- inf.
378
379 @param fromNumber: The python float to copy the sign bit from.
380 @type fromNumber: float
381 @param toDouble: The python float to copy the sign bit to.
382 @type toDouble: float
383 @raise TypeError: If toDouble isn't a python float or if fromNumber can't be converted to a
384 float.
385 """
386
387
388 fromNumber = float(fromNumber)
389
390
391 fromIsPositive = isPositive(fromNumber)
392 toIsPositive = isPositive(toDouble)
393
394
395 toBytes = floatAsByteArray(toDouble)
396
397 if not toIsPositive and fromIsPositive:
398
399 toBytes[7] &= EXPONENT_SIGN_MASK
400
401 elif toIsPositive and not fromIsPositive:
402
403 toBytes[7] = toBytes[7] + 0x80
404
405
406 return packBytesAsPyFloat(toBytes)
407
408
410 """Check to see if a python float is denormalised.
411
412 Denormalisation indicates that the number has no exponent set and all the precision is in the
413 mantissa, this is an indication that the number is tending to towards underflow.
414
415 @param obj: Python float object to check.
416 @type obj: float
417 @return: True if the number is denormalised.
418 @rtype: bool
419 @raise TypeError: If toDouble isn't a python float or if obj isn't a float.
420 """
421
422 result = True
423
424
425 if not isExpAllZeros(obj):
426 result = False
427
428
429
430
431 if isZero(obj):
432 result = False
433
434 return result
435
436
438 """Get the 7 bytes that makeup the mantissa of float.
439
440 The mantissa is returned as the 7 bytes in the mantissa in little endian order in the 7th byte
441 the 2nd nibble of the byte is masked off as it contains part of the exponent. The second nibble
442 of the 7th byte is therefore always has the value 0x0.
443
444 @param obj: Float object to extract the mantissa from.
445 @type obj: float
446 @return: A list of 7 bytes in little endian order.
447 @rtype: list of 7 bytes
448 @raise TypeError: If obj isn't a python float.
449 """
450
451
452 bytes = floatAsByteArray(obj)
453
454
455 bytes[6] = bytes[6] & MANTISSA_NIBBLE_MASK
456
457
458 return bytes[:7]
459
460
462 """Get the 2 bytes that makeup the exponent of a float.
463
464 The exponent is returned as the 2 bytes in the exponent in little endian order in the 2nd byte
465 the last bit is masked off as this is the sign bit. Therefore all values have the last bit set
466 to zero. In the first byte the first nibble of the byte is also masked off as it contains part
467 of the mantissa and thus always has the value 0x0.
468
469 @param obj: Float object to extract the exponent from.
470 @type obj: float
471 @return: A list of 2 bytes in little endian order.
472 @rtype: list of 2 bytes
473 @raise TypeError: If obj isn't a python float.
474 """
475
476
477 bytes = floatAsByteArray(obj)
478
479
480 bytes[6] = bytes[6] & EXPONENT_NIBBLE_MASK
481
482
483 bytes[7] = bytes[7] & EXPONENT_SIGN_MASK
484
485
486 return bytes[6:]
487
488
490 """Check if the bits of the exponent of a float is zero.
491
492 @param obj: Float object to check exponent for zero value.
493 @type obj: float
494 @return: True if the exponent is zero.
495 @rtype: bool
496 @raise TypeError: If obj isn't a python float.
497 """
498
499 result = True
500
501
502 expBytes = getExponentBytes(obj)
503
504
505 if expBytes[0] > 0 or expBytes[1] > 0:
506 result = False
507
508 return result
509
510
512 """Check if the bits of the mantissa of a float is zero.
513
514 @param obj: Float object to check mantissa for zero value.
515 @type obj: float
516 @return: True if the mantissa is zero.
517 @rtype: bool
518 @raise TypeError: If obj isn't a python float.
519 """
520
521 result = True
522
523
524 mantissaBytes = getMantissaBytes(obj)
525
526
527 for byte in mantissaBytes:
528 if byte != 0:
529 result = False
530 break
531
532 return result
533
534
536 """Check if the bits of the exponent of a float is all 1 bits.
537
538 @param obj: Float object to check exponent for 1 bits.
539 @type obj: float
540 @return: True if all the bits in the exponent are one.
541 @rtype: bool
542 @raise TypeError: If obj isn't a python float.
543 """
544
545 result = False
546
547
548 expBytes = getExponentBytes(obj)
549
550
551 if expBytes[0] == EXPONENT_ALL_ONES_BYTE_0 and expBytes[1] == EXPONENT_ALL_ONES_BYTE_1:
552 result = True
553
554 return result
555
556
558 """Check to see if a python float is an IEEE-754 double not a number (NaN).
559
560 @param obj: Float object to check for not a number.
561 @type obj: float
562 @return: True if object is not a number.
563 @rtype: bool
564 @raise TypeError: If obj isn't a python float.
565 """
566
567
568 result = None
569
570
571
572 if not isExpAllOnes(obj):
573 result = False
574 else:
575
576 manBytes = getMantissaBytes(obj)
577
578
579
580 for byte in manBytes:
581 if byte > 0:
582 result = True
583 break
584
585
586
587
588 return result
589
590
592 """Check to see if a python float is an infinity.
593
594 The check returns true for either positive or negative infinities.
595
596 @param obj: Float object to check for infinity.
597 @type obj: float
598 @return: True if object is an infinity.
599 @rtype: bool
600 @raise TypeError: If obj isn't a python float.
601 """
602
603
604 result = None
605
606
607
608 if not isExpAllOnes(obj):
609 result = False
610 else:
611
612 manBytes = getMantissaBytes(obj)
613
614 for byte in manBytes:
615
616
617 if byte > 0:
618 result = False
619 break
620 result = True
621
622 return result
623
624
626 """Check to see if a python float is positive infinity.
627
628 @param obj: Float object to check for positive infinity.
629 @type obj: float
630 @return: True if object is a positive infinity.
631 @rtype: bool
632 @raise TypeError: If obj isn't a python float.
633 """
634
635 return isInf(obj) and isPositive(obj)
636
637
639 """Check to see if a python float is negative infinity.
640
641 @param obj: Float object to check for negative infinity.
642 @type obj: float
643 @return: True if object is a negative infinity.
644 @rtype: bool
645 @raise TypeError: If obj isn't a python float.
646 """
647
648 return isInf(obj) and not isPositive(obj)
649
650
652 """Convert a 64 bit IEEE-754 ascii bit pattern into a 64 bit Python float.
653
654 @param string: The ascii bit pattern repesenting the IEEE-754 float.
655 @type string: str
656 @param endian: The endianness of the bit pattern (can be 'big' or 'little').
657 @type endian: str
658 @return: The 64 bit float corresponding to the IEEE-754 bit pattern.
659 @returntype: float
660 @raise TypeError: If 'string' is not a string, the length of the 'string' is not 64, or if
661 'string' does not consist solely of the characters '0' and '1'.
662 """
663
664
665 if not isinstance(string, str):
666 raise TypeError("The string argument '%s' is not a string." % string)
667
668
669 if len(string) != 64:
670 raise TypeError("The string '%s' is not 64 characters long." % string)
671
672
673 for char in string:
674 if char not in ['0', '1']:
675 raise TypeError("The string '%s' should be composed solely of the characters '0' and '1'." % string)
676
677
678 if endian == 'big' and sys.byteorder == 'little':
679 string = string[::-1]
680 elif endian == 'little' and sys.byteorder == 'big':
681 string = string[::-1]
682
683
684 bytes = []
685 for i in xrange(8):
686 bytes.append(bitpatternToInt(string[i*8:i*8+8], endian=sys.byteorder))
687
688
689 return packBytesAsPyFloat(bytes)
690
691
693 """Convert a bit pattern into its integer representation.
694
695 @param string: The ascii string repesenting binary data.
696 @type string: str
697 @param endian: The endianness of the bit pattern (can be 'big' or 'little').
698 @type endian: str
699 @return: The integer value.
700 @returntype: int
701 """
702
703
704 if not isinstance(string, str):
705 raise TypeError("The string argument '%s' is not a string." % string)
706
707
708 for char in string:
709 if char not in ['0', '1']:
710 raise TypeError("The string '%s' should be composed solely of the characters '0' and '1'." % string)
711
712
713 if endian == 'big' and sys.byteorder == 'little':
714 string = string[::-1]
715 elif endian == 'little' and sys.byteorder == 'big':
716 string = string[::-1]
717
718
719 int_val = 0
720 for i in xrange(len(string)):
721 if int(string[i]):
722 int_val = int_val + 2**i
723
724
725 return int_val
726
727
728
729
730
731
732
733 PosZero = bitpatternToFloat('0000000000000000000000000000000000000000000000000000000000000000', endian='big')
734 NegZero = bitpatternToFloat('1000000000000000000000000000000000000000000000000000000000000000', endian='big')
735 PosEpsilonDenorm = bitpatternToFloat('0000000000000000000000000000000000000000000000000000000000000001', endian='big')
736 NegEpsilonDenorm = bitpatternToFloat('1000000000000000000000000000000000000000000000000000000000000001', endian='big')
737 PosEpsilonNorm = bitpatternToFloat('0000000000010000000000000000000000000000000000000000000000000001', endian='big')
738 NegEpsilonNorm = bitpatternToFloat('1000000000010000000000000000000000000000000000000000000000000001', endian='big')
739 PosMax = bitpatternToFloat('0111111111101111111111111111111111111111111111111111111111111111', endian='big')
740 NegMin = bitpatternToFloat('1111111111101111111111111111111111111111111111111111111111111111', endian='big')
741 PosInf = bitpatternToFloat('0111111111110000000000000000000000000000000000000000000000000000', endian='big')
742 NegInf = bitpatternToFloat('1111111111110000000000000000000000000000000000000000000000000000', endian='big')
743 PosNaN_A = bitpatternToFloat('0111111111110000000000000000000000000000001000000000000000000000', endian='big')
744 NegNaN_A = bitpatternToFloat('1111111111110000000000000000000000000000001000000000000000000000', endian='big')
745 PosNaN_B = bitpatternToFloat('0111111111110000000000000000011111111111111111111110000000000000', endian='big')
746 NegNaN_B = bitpatternToFloat('1111111111110000000000000000011111111111111111111110000000000000', endian='big')
747 PosNaN_C = bitpatternToFloat('0111111111110101010101010101010101010101010101010101010101010101', endian='big')
748 NegNaN_C = bitpatternToFloat('1111111111110101010101010101010101010101010101010101010101010101', endian='big')
749 PosNaN = PosNaN_C
750 NegNaN = NegNaN_C
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768