Module float
[hide private]
[frames] | no frames]

Source Code for Module float

  1  ############################################################################### 
  2  #                                                                             # 
  3  # Copyright (C) 2006  Gary S Thompson (see https://gna.org/users for contact  # 
  4  #                                      details)                               # 
  5  #                                                                             # 
  6  # This file is part of the program relax.                                     # 
  7  #                                                                             # 
  8  # relax is free software; you can redistribute it and/or modify               # 
  9  # it under the terms of the GNU General Public License as published by        # 
 10  # the Free Software Foundation; either version 2 of the License, or           # 
 11  # (at your option) any later version.                                         # 
 12  #                                                                             # 
 13  # relax is distributed in the hope that it will be useful,                    # 
 14  # but WITHOUT ANY WARRANTY; without even the implied warranty of              # 
 15  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the               # 
 16  # GNU General Public License for more details.                                # 
 17  #                                                                             # 
 18  # You should have received a copy of the GNU General Public License           # 
 19  # along with relax; if not, write to the Free Software                        # 
 20  # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA   # 
 21  #                                                                             # 
 22  ############################################################################### 
 23   
 24  ''' ieeefloat a set of functions for dealing with ieee-754 float objects 
 25   
 26      On most platforms Python uses ieee-754 double objects of length 64 bits to  
 27      represent floats (some architectures such as older crays and vaxes don't).  
 28      Thus an ieee-754 double is the implementation of a python float object on 
 29      most platforms. 
 30       
 31      ieee-74 uses special bit patterns to represent the following states or classes  
 32      of ieee floating point numbers (ieee-class) 
 33          +-nan  - not a number (e.g. 0.0/0.0) 
 34          inf    - positive or negative infinity (1.0/0.0) 
 35          +-zero - zero maybe positive or negative under ieee-754 
 36           
 37      this module provides functions for working with python floats and their  
 38      special values, if they contain ieee-754 formatted values. Specifically 
 39          - pack and unpack a list of bytes representing an ieee-754 double to a python  
 40          float (takes care of little endian/big endian issues) 
 41          - get the sign bit of a python float 
 42          - check the ordering of python floats allowing for nans (nans cannot normally  
 43          be compared) 
 44          - check if a value is finite (as opposed to nan or inf) 
 45          - copy the sign of one float to another irrespective of if it's ieee-class  
 46          - check if a float is denormalised (and might be about to underflow) 
 47          - check the ieee-class of a python float (nan, pos-inf, neg-inf,pos-zero,  
 48          neg-zero,...) 
 49          - check that the current python float implmentations uses ieee-754 doubles 
 50           
 51      It also provides constants containg specific bit patterns for nan and +-inf as  
 52      these values cannot be generated from strings via the constructor float(x)  
 53      with some compiler implementations (typically older microsoft windows compilers) 
 54       
 55      As a convenience the names of functions and constants conform to those defined  
 56      in the draft python PEP 754 'IEEE 754 Floating Point Special Values' 
 57       
 58      notes: 
 59          1. binary data is docuemented as binary strings e.g. 0xF0 = 0b11110000 
 60          2. the module doesn't support all the functions recommened by ieee-754,  
 61              the following features are missing 
 62              a. control of exception and rounding modes 
 63              b. scalb (y, N) 
 64              c. logb (x) 
 65              d. nextafter(x,y) 
 66              e. next towards 
 67          3. division by zero currently (python 2.5) raises excaption and the  
 68              resulting inf/nan cannot be propogated 
 69          4. a second module ieeefloatcapabilities (currently incomplete)  
 70              provides tests of the capabilites of a floating point implementation 
 71              on a specific python platform  
 72          5. development and conventions on byte order come from a little endian 
 73              (intel) platform 
 74          6. to reduce overheads all functions that take python float arguments do  
 75              _no type_ conversion thus if other numeric types are passed the functions 
 76              will raise exceptions, (I am not sure this is the best behaviour however, 
 77              as python functions should be polymorphic...) 
 78          7. in most cases conversion to c code for performance reasons would be trivial 
 79               
 80      ieee-754 double format: 
 81          63 sign bit 
 82          62-52 exponent (offset by 1023 value - field-1023 
 83          51-0 mantissa each bit n counts as 1/2^n, running from 1/2 which is the 
 84                  most significant bit to 1/2^51, The 1/0 bit is defined by the  
 85                  exponent field if it has any bits set if it has bits set then  
 86                  precede the mantissa with a 1 (normalised otherwise procede it by  
 87                  a 0 (denormalised) 
 88           
 89           
 90      todo: 
 91          unit test suite 
 92          test under windows 
 93          test under a solaris sparc box (big endian) 
 94          add example ieee double 
 95          check byte/nibble atributions 
 96  ''' 
 97  from struct import pack,unpack 
 98  import sys 
 99   
100   
101  SIGNBIT = 0x80  
102  ''' bit pattern for the sign bit in byte 8 0b00000001 of a ieee-754 double''' 
103   
104   
105  EXPONENT_ALL_ONES_BYTE_1 = 0x7F       
106  ''' value of the first byte (byte 8) in the mantisaa of a ieee-754 double that  
107  is all ones (0b11111110) ''' 
108   
109  EXPONENT_ALL_ONES_BYTE_0 = 0xF << 4  
110  ''' value of the second byte (byte 7) in the mantisaa of a ieee-754 double that  
111  is all ones (0b00001111) ''' 
112   
113   
114  MANTISSA_NIBBLE_MASK=0x0F 
115  ''' mask to select the bits from the first nibble of  byte 7 of an ieee-754 
116  which is part of the mantissa (0b00001111)''' 
117   
118  EXPONENT_NIBBLE_MASK=0xF0 
119  ''' mask to select the bits from the second nibble of  byte 7 of an ieee-754 
120  which is part of the exponent (0b11110000)''' 
121   
122   
123  EXPONENT_SIGN_MASK= 0x7F    
124  '''' mask to select only bits from byte 8 of an ieee-754 double that are  
125  not part of the sign bit (0b11111110)''' 
126   
127  ''' classes of floating point numbers''' 
128  CLASS_POS_INF = 1 
129  CLASS_NEG_INF = 2 
130  CLASS_POS_NORMAL = 4 
131  CLASS_NEG_NORMAL = 8 
132  CLASS_POS_DENORMAL = 16 
133  CLASS_NEG_DENORMAL = 32 
134  CLASS_QUIET_NAN =  64 
135  CLASS_SIGNAL_NAN = 128 
136  CLASS_POS_ZERO =  256 
137  CLASS_NEG_ZERO = 512 
138   
139 -def isZero(float):
140 return isMantissaAllZeros(float) and isExpAllZeros(float)
141
142 -def getFloatClass(float):
143 ''' get the ieee-class (nan,inf etc) of apython float 144 145 float - python float object 146 147 result - a ieee class value 148 throws - an exception if float is not a python float object 149 ''' 150 151 result = None 152 153 # check finite 154 if isFinite(float): 155 # check and store is positive 156 positive = isPositive(float) 157 if isZero(float): 158 if positive: 159 result = CLASS_POS_ZERO 160 else: 161 result = CLASS_NEG_ZERO 162 elif isDenormalised(float): 163 if positive: 164 result = CLASS_POS_DENORMAL 165 else: 166 result = CLASS_NEG_DENORMAL 167 else: 168 if positive: 169 result = CLASS_POS_NORMAL 170 else: 171 result = CLASS_NEG_NORMAL 172 else: 173 if isNaN(float): 174 # we don't currently test the type of nan signalling vs quiet 175 # so we always assume a quiet nan 176 result = CLASS_QUIET_NAN 177 elif isPosInf(float): 178 result = CLASS_POS_INF 179 elif isNegInf(float): 180 result = CLASS_NEG_INF 181 return result
182 183
184 -def packBytesAsPyFloat(bytes):
185 ''' pack 8 bytes into a python float 186 187 the function is endian aware and the data should be input in little 188 endian format. Thus byte 8 contains the most significant bit of the 189 exponent and the sign bit 190 191 bytes -- 8 bytes to pack into a python (ieee 754 double) float 192 193 returns -- a python float 194 195 throws -- an Exception if bytes contains < 8 bytes 196 type of exception not determined 197 ''' 198 # pack bytes into binary string 199 doubleString=pack('8B',*bytes) 200 201 #change byte order to little endian by reversing string 202 if sys.byteorder == 'big': 203 doubleString = doubleString[::-1] 204 205 # unpack binary string to a python float 206 return unpack('d',doubleString)[0]
207 208 209 NAN_BYTES = [0x00,0x00,0x00,0x00,0x00,0x00,0xF8,0x7F] 210 ''' bytes for an arbitary ieee-754 not a number (nan) in little endian format 211 0b00000000 00000000 00000000 00000000 00000000 00000000 00011111 11111110 ''' 212 213 214 INF_BYTES = [0x00,0x00,0x00,0x00,0x00,0x00,0xF0,0x7F] 215 ''' bytes for ieee-754 positive infinity (inf) in little endian format 216 0b00000000 00000000 00000000 00000000 00000000 00000000 00001111 11111110 ''' 217 218 219 nan = packBytesAsPyFloat(NAN_BYTES) 220 ''' one of a number of possible bit patterns used to represent an ieee-754 double 221 as a python float. Do not use this value for comparisons of the form x==nan as it 222 will fail on some platforms use function isNaN instead''' 223 224 225 pos_inf = packBytesAsPyFloat(INF_BYTES) 226 ''' the value of a positive ieee-754 double infinity as a python float ''' 227 228 229 neg_inf = -1 * pos_inf 230 ''' the value of a negative ieee-754 double infinity as a python float''' 231 232
233 -def floatToBinaryString(obj):
234 ''' pack a python float into a binary string. 235 236 This function assumes that the python type float it represents a 237 64bit double of 8 bytes. This function reverses the resulting string if 238 the current architecture is big endian. 239 240 obj -- a python float to pack 241 242 returns -- a string of 8 bytes 243 244 throws -- throws a TypeError if the the input object isn't a python float 245 246 ''' 247 if not isinstance(obj,float): 248 raise TypeError('the object recieved wasn\'t a float, type was: %s' % type(obj)) 249 250 # pack float into binary string 251 packed =pack('d',obj) 252 253 #change byte order to little endian by reversing string 254 if sys.byteorder == 'big': 255 packed = packed[::-1] 256 257 return packed
258
259 -def floatAsByteArray(obj):
260 ''' unpack a python float as a list of 8 bytes 261 262 This function assumes that the python type float it represents a 263 64bit double of 8 bytes 264 265 obj -- a python float to unpack 266 267 returns -- a list of 8 bytes 268 269 throws -- throws an exception if obj is not composed of 8 bytes 270 271 ''' 272 #unpack bytes to a binary string (takes care of byte order) 273 binaryString = floatToBinaryString(obj) 274 275 # convert the binary string to an array of 8 bytes 276 bytes = unpack('8B',binaryString) 277 278 #convert bytes to a list for ease of editing 279 return list(bytes)
280 281 282
283 -def getSignBit(obj):
284 ''' get the sign bit from a python float 285 286 obj -- a python float object 287 288 returns -- the floats sign bit, this has the value 1 if the float is 289 negative otherwise 0 (positive) 290 291 throws -- throws a TypeError if the the input object isn't a python float 292 293 ''' 294 295 # unpack float to bytes 296 unpacked = floatAsByteArray(obj) 297 298 # grab last byte and check if sign bit is set 299 return unpacked[7] & SIGNBIT
300
301 -def isPositive(obj):
302 ''' test if a a pyhton float is positive 303 304 obj -- a python float object 305 306 returns -- True if the float is positive otherwise False 307 308 throws -- throws a TypeError if the the input object isn't a python float 309 310 ''' 311 312 if getSignBit(obj): 313 return False 314 else: 315 return True
316
317 -def isNegative(obj):
318 ''' test if a a pyhton float 64 bit ieee-74 double is negative 319 320 obj -- a python float object 321 322 returns -- True if the float is negative 323 324 throws -- tthrows a TypeError if the the input object isn't a python float 325 ''' 326 return not isPositive(obj)
327 328 329
330 -def areUnordered(obj1,obj2):
331 ''' test to see if two python float are unordered 332 333 float comparison is unordered if either or both of the objects is 'not a 334 number' (nan) 335 336 obj1 -- a python float object 337 obj2 -- a python float object 338 339 throws -- throws a TypeError if the the input objects aren't a python floats 340 341 ''' 342 343 # check to see if objects are nans 344 nanTest1 = isNaN(obj1) 345 nanTest2 = isNaN(obj2) 346 347 # if either object is a nan we are unordered 348 if nanTest1 or nanTest2: 349 return True 350 else: 351 return False
352 353
354 -def isFinite(obj):
355 ''' test to see if a python float is finite 356 357 to be finite a number mustn't be a nan or + or - inf a result of True 358 guarantees that the number is bounded by +- inf -inf < x < inf 359 360 obj -- a python float object 361 362 throws -- throws a TypeError if the the input object isn't a python float 363 364 ''' 365 366 result = True 367 if isNaN(obj): 368 result = False 369 if isInf(obj): 370 result = False 371 372 373 return result
374
375 -def copySign(fromNumber,toDouble):
376 ''' copy the sign bit from one python float to another 377 378 this function is class agnostic the sign bit can be copied freely between 379 ordinarys floats nans and +/-inf 380 381 fromDouble -- the python float to copy the sign bit from 382 toDouble -- the python float to copy the sign bit to 383 384 throws -- throws a TypeError if toDouble isn't a python float or if 385 fromNumber can't be converted to a float 386 387 ''' 388 389 #convert first number to a float so as to use facilities 390 fromNumber = float(fromNumber) 391 392 # check signs of numbers 393 fromIsPositive = isPositive(fromNumber) 394 toIsPositive = isPositive(toDouble) 395 396 # convert the float to an array of 8 bytes 397 toBytes = floatAsByteArray(toDouble) 398 399 if not toIsPositive and fromIsPositive: 400 # unset the sign bit of the number 401 toBytes[7] &= EXPONENT_SIGN_MASK 402 403 elif toIsPositive and not fromIsPositive: 404 # set the sign bit 405 toBytes[7] = toBytes[7] + 0x80 406 407 #repack bytes to float 408 return packBytesAsPyFloat(toBytes)
409 410
411 -def isDenormalised(obj):
412 ''' check to see if a python float is denormalised 413 414 denormalisation indicates that the number has no exponent set and all the 415 precision is in the mantissa, this is an indication that the number is 416 tending to towards underflow 417 418 obj -- python float object to check 419 420 result -- True if the number is denormalised 421 422 throws -- throws a TypeError if toDouble isn't a python float or if 423 obj isn't a float 424 ''' 425 426 result = True 427 # check to see if the exponent is all zeros (a denorm doesn't have a 428 # finite exponent) Note we ignore the sign of the float 429 if not isExpAllZeros(obj): 430 result = False 431 432 # check to see if this is zero (which is in some ways a special 433 # class of denorm... but isn't counted in this case) 434 # if it isn't zero it must be a 'general' denorm 435 if isZero(obj): 436 result = False 437 438 return result
439 440 441 442 443 444
445 -def getMantissaBytes(obj):
446 ''' get the 7 bytes that makeup the mantissa of float 447 448 the mantissa is returned as the 7 bytes in the mantissa in little endian order 449 in the 7th byte the 2nd nibble of the byte is masked off as it contains 450 part of the exponent. The second nibble of the 7th byte is therefore always 451 has the value 0x0 452 453 obj -- float object to extract the mantissa from 454 455 returns -- a list of 7 bytes in little endian order 456 457 throws -- throws a TypeError if obj isn't a python float 458 459 ''' 460 461 # unpack float to bytes 462 bytes = floatAsByteArray(obj) 463 464 # mask out overlap from exponent 465 bytes[6] = bytes[6] & MANTISSA_NIBBLE_MASK 466 467 # remove the exponent bytes that can be removed 468 return bytes[:7]
469
470 -def getExponentBytes(obj):
471 ''' get the 2 bytes that makeup the exponent of a float 472 473 the exponent is returned as the 2 bytes in the exponent in little endian order 474 in the 2nd byte the last bit is masked off as this is the sign bit. Ttherefore 475 all values have the last bit set to zero. In the first byte the first nibble of 476 the byte is also masked off as it contains part of the mantissa and thus 477 always has the value 0x0. 478 479 obj -- float object to extract the exponent from 480 481 returns -- a list of 2 bytes in little endian order 482 483 throws -- throws a TypeError if obj isn't a python float 484 ''' 485 486 # unpack float to bytes 487 bytes = floatAsByteArray(obj) 488 489 # mask out the ovberlap with the mantissa 490 bytes[6] = bytes[6] & EXPONENT_NIBBLE_MASK 491 492 # mask out the sign bit 493 bytes[7] = bytes[7] & EXPONENT_SIGN_MASK 494 495 # remove the mantissa bytes that can be removed 496 return bytes[6:]
497 498 499 500
501 -def isExpAllZeros(obj):
502 ''' check if the bits of the exponent of a float is zero 503 504 obj -- float object to check exponent for zero value 505 506 returns -- True if the exponent is zero 507 508 throws -- throws a TypeError if obj isn't a python float 509 ''' 510 result = True 511 512 # get the exponent as a byte array porperly masked 513 expBytes = getExponentBytes(obj) 514 515 # check to see if any of the bytes in the exponent are not zero 516 if expBytes[0] > 0 or expBytes[1] > 0: 517 result = False 518 519 return result
520
521 -def isMantissaAllZeros(obj):
522 ''' check if the bits of the mantissa of a float is zero 523 524 obj -- float object to check mantissa for zero value 525 526 returns -- True if the mantissa is zero 527 528 throws -- throws a TypeError if obj isn't a python float 529 ''' 530 result = True 531 532 # get the mantissa as a byte array properly masked 533 mantissaBytes = getMantissaBytes(obj) 534 535 # check if any of the mantissa bytes are greater than zero 536 for byte in mantissaBytes: 537 if byte != 0: 538 result = False 539 break 540 541 return result
542
543 -def isExpAllOnes(obj):
544 ''' check if the bits of the exponent of a floatis all 1 bits 545 546 obj -- float object to check exponent for 1 bits 547 548 returns -- True if all the bits in the exponent are one 549 550 throws -- throws a TypeError if obj isn't a python float 551 ''' 552 553 result = False 554 555 # get the exponent as a byte array properly masked 556 expBytes = getExponentBytes(obj) 557 558 # check against masks to see if all the correct bits are set 559 if expBytes[0] == EXPONENT_ALL_ONES_BYTE_0 and expBytes[1] == EXPONENT_ALL_ONES_BYTE_1: 560 result = True 561 562 return result
563
564 -def isNaN(obj):
565 ''' check to see if a python float is an ieee-754 double not a number (nan) 566 567 obj -- float object to check for not a number 568 569 returns -- True if object is not a number 570 571 throws -- throws a TypeError if obj isn't a python float 572 ''' 573 574 # bad result for code checking 575 result = None 576 577 # check to see if exponent is all ones (excluding sign bit) 578 # if exponent is not all ones this can't be a NaN 579 if not isExpAllOnes(obj): 580 result = False 581 else: 582 # get the mantissa as a byte array properly masked 583 manBytes = getMantissaBytes(obj) 584 585 # check if any of the unmasked mantissa bytes are not zero 586 # to be a NaN the mantissa must be non zero 587 for byte in manBytes: 588 if byte > 0: 589 result = True 590 break 591 # todo NOT NEEDED, UNITTEST!!!! 592 # check to see if the mantissa nibble that overlaps with the 593 #if (manBytes[6] & MANTISSA_NIBBLE_MASK) > 0: 594 # result = True 595 return result
596
597 -def isInf(obj):
598 ''' check to see if a python float is an infinity 599 600 the check returns true for either positive or negative infinities 601 602 obj -- float object to check for infinity 603 604 returns -- True if object is an infinity 605 606 throws -- throws a TypeError if obj isn't a python float 607 ''' 608 # bad result for code checking 609 result = None 610 611 # check to see if exponent is all ones (excluding sign bit) 612 # if exponent is not all ones this can't be a Inf 613 if not isExpAllOnes(obj): 614 result = False 615 else: 616 # get the mantissa as a byte array properly masked 617 manBytes = getMantissaBytes(obj) 618 619 for byte in manBytes: 620 #check if any of the unmasked mantissa bytes are zero 621 # to be a NaN the mantissa must be zero 622 if byte > 0: 623 result = False 624 break 625 result = True 626 627 return result 628
629 -def isPosInf(obj):
630 ''' check to see if a python float is positive infinity 631 632 obj -- float object to check for positive infinity 633 634 returns -- True if object is a positive infinity 635 636 throws -- throws a TypeError if obj isn't a python float 637 ''' 638 return isInf(obj) and isPositive(obj)
639
640 -def isNegInf(obj):
641 ''' check to see if a python float is negative infinity 642 643 644 obj -- float object to check for negative infinity 645 646 returns -- True if object is a negative infinity 647 648 throws -- throws a TypeError if obj isn't a python float 649 ''' 650 651 return isInf(obj) and not isPositive(obj)
652