mailr2716 - /1.2/float.py


Others Months | Index by Date | Thread Index
>>   [Date Prev] [Date Next] [Thread Prev] [Thread Next]

Header


Content

Posted by garyt on October 31, 2006 - 12:31:
Author: varioustoxins
Date: Tue Oct 31 12:31:13 2006
New Revision: 2716

URL: http://svn.gna.org/viewcvs/relax?rev=2716&view=rev
Log:
tidied code and added comments,  code is now 4 space indented

task 3621 https://gna.org/task/?3621

Modified:
    1.2/float.py

Modified: 1.2/float.py
URL: 
http://svn.gna.org/viewcvs/relax/1.2/float.py?rev=2716&r1=2715&r2=2716&view=diff
==============================================================================
--- 1.2/float.py (original)
+++ 1.2/float.py Tue Oct 31 12:31:13 2006
@@ -30,24 +30,24 @@
     
     ieee-74 uses special bit patterns to represent the following states or 
classes 
     of ieee floating point numbers (ieee-class)
-      +-nan  - not a number (e.g. 0.0/0.0)
-      inf    - positive or negative infinity (1.0/0.0)
-      +-zero - zero maybe positive or negative under ieee-754
+        +-nan  - not a number (e.g. 0.0/0.0)
+        inf    - positive or negative infinity (1.0/0.0)
+        +-zero - zero maybe positive or negative under ieee-754
         
     this module provides functions for working with python floats and their 
     special values, if they contain ieee-754 formatted values. Specifically
-     - pack and unpack a list of bytes representing an ieee-754 double to a 
python 
-       float (takes care of little endian/big endian issues)
-     - get the sign bit of a python float
-     - check the ordering of python floats allowing for nans (nans cannot 
normally 
-       be compared)
-     - check if a value is finite (as opposed to nan or inf)
-     - copy the sign of one float to another irrespective of if it's 
ieee-class 
-     - check if a float is denormalised (and might be about to underflow)
-     - check the ieee-class of a python float (nan, pos-inf, 
neg-inf,pos-zero, 
-       neg-zero,...)
-     - check that the current python float implmentations uses ieee-754 
doubles
-     
+        - pack and unpack a list of bytes representing an ieee-754 double to 
a python 
+        float (takes care of little endian/big endian issues)
+        - get the sign bit of a python float
+        - check the ordering of python floats allowing for nans (nans cannot 
normally 
+        be compared)
+        - check if a value is finite (as opposed to nan or inf)
+        - copy the sign of one float to another irrespective of if it's 
ieee-class 
+        - check if a float is denormalised (and might be about to underflow)
+        - check the ieee-class of a python float (nan, pos-inf, 
neg-inf,pos-zero, 
+        neg-zero,...)
+        - check that the current python float implmentations uses ieee-754 
doubles
+        
     It also provides constants containg specific bit patterns for nan and 
+-inf as 
     these values cannot be generated from strings via the constructor 
float(x) 
     with some compiler implementations (typically older microsoft windows 
compilers)
@@ -56,43 +56,43 @@
     in the draft python PEP 754 'IEEE 754 Floating Point Special Values'
     
     notes:
-      1. binary data is docuemented as binary strings e.g. 0xF0 = 0b11110000
-      2. the module doesn't support all the functions recommened by 
ieee-754, 
-         the following features are missing
-           a. control of exception and rounding modes
-           b. scalb (y, N)
-           c. logb (x)
-           d. nextafter(x,y)
-           e. next towards
-      3. division by zero currently (python 2.5) raises excaption and the 
-         resulting inf/nan cannot be propogated
-      4. a second module ieeefloatcapabilities (currently incomplete) 
-         provides tests of the capabilites of a floating point implementation
-         on a specific python platform 
-      5. development and conventions on byte order come from a little endian
-         (intel) platform
-      6. to reduce overheads all functions that take python float arguments 
do 
-         _no type_ conversion thus if other numeric types are passed the 
functions
-         will raise exceptions, (I am not sure this is the best behaviour 
however,
-         as python functions should be polymorphic...)
-      7. in most cases conversion to c code for performance reasons would be 
trivial
-         
+        1. binary data is docuemented as binary strings e.g. 0xF0 = 
0b11110000
+        2. the module doesn't support all the functions recommened by 
ieee-754, 
+            the following features are missing
+            a. control of exception and rounding modes
+            b. scalb (y, N)
+            c. logb (x)
+            d. nextafter(x,y)
+            e. next towards
+        3. division by zero currently (python 2.5) raises excaption and the 
+            resulting inf/nan cannot be propogated
+        4. a second module ieeefloatcapabilities (currently incomplete) 
+            provides tests of the capabilites of a floating point 
implementation
+            on a specific python platform 
+        5. development and conventions on byte order come from a little 
endian
+            (intel) platform
+        6. to reduce overheads all functions that take python float 
arguments do 
+            _no type_ conversion thus if other numeric types are passed the 
functions
+            will raise exceptions, (I am not sure this is the best behaviour 
however,
+            as python functions should be polymorphic...)
+        7. in most cases conversion to c code for performance reasons would 
be trivial
+            
     ieee-754 double format:
         63 sign bit
         62-52 exponent (offset by 1023 value - field-1023
         51-0 mantissa each bit n counts as 1/2^n, running from 1/2 which is 
the
-             most significant bit to 1/2^51, The 1/0 bit is defined by the 
-             exponent field if it has any bits set if it has bits set then 
-             precede the mantissa with a 1 (normalised otherwise procede it 
by 
-             a 0 (denormalised)
+                most significant bit to 1/2^51, The 1/0 bit is defined by 
the 
+                exponent field if it has any bits set if it has bits set 
then 
+                precede the mantissa with a 1 (normalised otherwise procede 
it by 
+                a 0 (denormalised)
         
         
     todo:
-      unit test suite
-      test under windows
-      test under a solaris sparc box (big endian)
-      add example ieee double
-      check byte/nibble atributions
+        unit test suite
+        test under windows
+        test under a solaris sparc box (big endian)
+        add example ieee double
+        check byte/nibble atributions
 '''
 from struct import pack,unpack
 import sys
@@ -149,35 +149,37 @@
     '''
     
     result = None
+    
+    # check finite 
     if isFinite(float):
-      positive = isPositive(float)
-      denormalised = isDenormalised(float)
-      if denormalised(float):
-        if isZero():
-          if positive:
-            result  = CLASS_POS_ZERO
-          else:
-            result = CLASS_NEG_ZERO
-        else:
-          if positive:
-            result = CLASS_POS_DENORMAL
-          else:
-            result = CLASS_NEG_DENORMAL
-      else:
-        if positive:
-          result  = CLASS_POS_NORMAL
-        else:
-          result = CLASS_NEG_NORMAL
+         # check and store is positive
+         positive = isPositive(float)
+         if isZero():
+            if positive:
+                result = CLASS_POS_ZERO
+            else:
+                result = CLASS_NEG_ZERO
+         elif isDenormalised(float):
+            if positive:
+                result = CLASS_POS_DENORMAL
+            else:
+                result = CLASS_NEG_DENORMAL
+         else:
+            if positive:
+                result  = CLASS_POS_NORMAL
+            else:
+                result = CLASS_NEG_NORMAL
     else:    
-      if isNaN(float):
-        # we don't currently test the type of nan signalling vs quiet
-        result  = CLASS_QUIET_NAN
-      elif isPosInf(float):
-        result  = CLASS_POS_INF
-      elif isNegInf(float):
-        result  = CLASS_NEG_INF
-
-      
+        if isNaN(float):
+            # we don't currently test the type of nan signalling vs quiet
+            # so we always assume a quiet nan
+            result  = CLASS_QUIET_NAN
+        elif isPosInf(float):
+            result  = CLASS_POS_INF
+        elif isNegInf(float):
+            result  = CLASS_NEG_INF
+   
+        
 
 def packBytesAsPyFloat(bytes):
     ''' pack 8 bytes into a python float 
@@ -191,12 +193,16 @@
         returns -- a python float
         
         throws -- an Exception if bytes contains < 8 bytes
-                  type of exception not determined
-    '''
-     
+                    type of exception not determined
+    '''
+    # pack bytes into binary string    
     doubleString=pack('8B',*bytes)
+    
+    #change byte order to little endian by reversing string
     if sys.byteorder == 'big':
         doubleString = doubleString[::-1]
+    
+    # unpack binary string to a python float 
     return unpack('d',doubleString)[0]
 
 
@@ -241,11 +247,15 @@
     if not isinstance(obj,float):
         raise TypeError('the object recieved wasn\'t a float, type was: %s' 
% type(obj))
     
+    # pack float into binary string
     packed =pack('d',obj)
+    
+    #change byte order to little endian by reversing string
     if sys.byteorder == 'big':
-       packed = packed[::-1]
+        packed = packed[::-1]
+    
     return packed
-     
+        
 def floatAsByteArray(obj):
     ''' unpack a python float as a list of 8 bytes
         
@@ -259,8 +269,15 @@
         throws --  throws an exception if obj is not composed of 8 bytes
                     
     '''
-    return list(unpack('8B',floatToBinaryString(obj)))
-  
+    #unpack bytes to a binary string (takes care of byte order)
+    binaryString = floatToBinaryString(obj)
+    
+    # convert the binary string to an array of 8 bytes
+    bytes = unpack('8B',binaryString)
+    
+    #convert bytes to a list for ease of editing
+    return list(bytes)
+    
 
     
 def getSignBit(obj):
@@ -269,12 +286,16 @@
         obj -- a python float object
         
         returns -- the floats sign bit, this has the value 1 if the float is 
-                   negative otherwise 0 (positive)
+                    negative otherwise 0 (positive)
         
         throws -- throws a TypeError if the the input object isn't a python 
float
-                   
+                    
     ''' 
+    
+    # unpack float to bytes
     unpacked = floatAsByteArray(obj) 
+    
+    # grab last byte and check if sign bit is set
     return unpacked[7]  & SIGNBIT
 
 def isPositive(obj):
@@ -285,14 +306,14 @@
         returns -- True if the float is positive otherwise False
         
         throws -- throws a TypeError if the the input object isn't a python 
float
-                   
+                    
     ''' 
-    unpacked = floatAsByteArray(obj) 
+    
     if getSignBit(obj):
         return False
     else:
         return True
-      
+        
 def isNegative(obj):
     ''' test if a a pyhton float 64 bit ieee-74 double is negative
         
@@ -318,8 +339,12 @@
         throws -- throws a TypeError if the the input objects aren't a 
python floats
                     
     '''
+    
+    # check to see if objects are nans
     nanTest1 = isNaN(obj1)
     nanTest2 = isNaN(obj2)
+    
+    # if either object is a nan we are unordered
     if nanTest1 or nanTest2:
         return True
     else:
@@ -337,9 +362,10 @@
         throws -- throws a TypeError if the the input object isn't a python 
float
                     
     '''
+    
     result = True
     if isNaN(obj):
-      result = False
+        result = False
     if isInf(obj):
         result =  False
 
@@ -356,26 +382,32 @@
         toDouble --  the python float to copy the sign bit to
         
         throws -- throws a TypeError if toDouble isn't a python float or if
-                  fromNumber can't be converted to a float
-        
-    '''
+                    fromNumber can't be converted to a float
+        
+    '''
+    
+    #convert first number to a float so as to use facilities
     fromNumber = float(fromNumber)
+    
+    # check signs of numbers
     fromIsPositive =  isPositive(fromNumber)
     toIsPositive = isPositive(toDouble)
+    
+    # convert the float to an array of 8 bytes
     toBytes = floatAsByteArray(toDouble)
+    
     if  not toIsPositive  and  fromIsPositive:
-        toBytes[7] &= 0x7F
+        # unset the sign bit of the number
+        toBytes[7] &= EXPONENT_SIGN_MASK
+        
     elif toIsPositive and  not fromIsPositive:
-         toBytes[7] = toBytes[7] + 128
+        # set the sign bit 
+        toBytes[7] = toBytes[7] + 0x80
+    
+    #repack bytes to float
     return packBytesAsPyFloat(toBytes)
     
-    
- 
-
-
-
-
-  
+
 def isDenormalised(obj):
     ''' check to see if a python float is denormalised
     
@@ -388,15 +420,22 @@
         result -- True if the number is denormalised
         
         throws -- throws a TypeError if toDouble isn't a python float or if
-                  obj isn't a float
-    '''
+                    obj isn't a float
+    '''
+    
+    result = True
+    # check to see if the exponent is all zeros (a denorm doesn't have a 
+    # finite exponent) Note we ignore the sign of the float
     if not isExpAllZeros(obj):
-        return False
-    manBytes = getMantissaBytes(obj)
-    for byte in manBytes:
-        if byte > 0:
-            return True
-    return False
+        result = False
+ 
+        # check to see if this is zero (which is in some ways a special 
+        # class of denorm... but isn't counted in this case) 
+        # if it isn't zero it must be a 'general' denorm  
+        if isZero(obj):
+            result = False
+                
+    return result
 
 
 
@@ -418,11 +457,15 @@
         throws -- throws a TypeError if obj isn't a python float 
         
     '''
-    unpacked = floatToBinaryString(obj)
-    bytes = list(unpack('8B',unpacked))
+    
+    # unpack float to bytes
+    bytes = floatAsByteArray(obj)
+    
+    # mask out overlap from exponent
     bytes[6] = bytes[6] & MANTISSA_NIBBLE_MASK
-    bytes=bytes[:7]
-    return bytes
+    
+    # remove the exponent bytes that can be removed
+    return bytes[:7]
 
 def getExponentBytes(obj):
     ''' get the 2 bytes that makeup the exponent of a float 
@@ -440,13 +483,17 @@
         throws -- throws a TypeError if obj isn't a python float        
     '''
     
-    unpacked = floatToBinaryString(obj)
-    bytes = list(unpack('8B',unpacked))
+    # unpack float to bytes
+    bytes = floatAsByteArray(obj)
+    
+    # mask out the ovberlap with the mantissa
     bytes[6] = bytes[6] & EXPONENT_NIBBLE_MASK
+    
+    # mask out the sign bit 
     bytes[7] = bytes[7] & EXPONENT_SIGN_MASK
-    bytes=bytes[6:]
-    
-    return bytes 
+    
+    # remove the mantissa bytes that can be removed
+    return bytes[6:] 
 
 
 
@@ -460,10 +507,16 @@
         
         throws -- throws a TypeError if obj isn't a python float 
     '''
+    result = True
+    
+    # get the exponent as a byte array porperly masked
     expBytes = getExponentBytes(obj)
+    
+    # check to see if any of the bytes in the exponent are not zero
     if expBytes[0] > 0 or  expBytes[1] > 0:
-        return False
-    return True
+        result = False
+        
+    return result
 
 def isMantissaAllZeros(obj):
     ''' check if the bits of the mantissa of a float is zero
@@ -474,14 +527,19 @@
     
     throws -- throws a TypeError if obj isn't a python float 
     '''
+    result = True
+    
+    # get the mantissa as a byte array properly masked
     mantissaBytes = getMantissaBytes(obj)
-    result  =  True
+    
+    # check if any of the mantissa bytes are greater than zero
     for byte in mantissaBytes:
         if byte != 0:
             result = False 
             break
+        
     return result
-  
+    
 def isExpAllOnes(obj):
     ''' check if the bits of the exponent of a floatis all 1 bits
     
@@ -491,10 +549,17 @@
         
         throws -- throws a TypeError if obj isn't a python float 
     '''    
+    
+    result = False
+    
+    # get the exponent as a byte array properly masked
     expBytes = getExponentBytes(obj)
+    
+    # check against masks to see if all the correct bits are set  
     if expBytes[0] == EXPONENT_ALL_ONES_BYTE_0 and  expBytes[1] == 
EXPONENT_ALL_ONES_BYTE_1:
-        return True
-    return False    
+        result  =  True
+    
+    return result    
 
 def isNaN(obj):
     ''' check to see if a python float is an ieee-754 double not a number 
(nan)
@@ -505,17 +570,29 @@
         
         throws -- throws a TypeError if obj isn't a python float     
     '''
-
+    
+    # bad result for code checking
+    result = None
+    
+    # check to see if exponent is all ones (excluding sign bit)
+    # if exponent is not all ones this can't be a NaN
     if not isExpAllOnes(obj):
-        return False
-    manBytes = getMantissaBytes(obj)
-    manNan = False
-    for byte in manBytes[:6]:
-        if byte > 0:
-            manNan = True
-    if (manBytes[6] & MANTISSA_NIBBLE_MASK) > 0:
-        manNan = True
-    return manNan
+        result =  False
+    else:
+        # get the mantissa as a byte array properly masked
+        manBytes = getMantissaBytes(obj)
+        
+        # check if any of the unmasked mantissa bytes are not zero
+        # to be a NaN the mantissa must be non zero
+        for byte in manBytes:
+            if byte > 0:
+                result = True
+                break
+        # todo NOT NEEDED, UNITTEST!!!!
+        # check to see if the mantissa nibble that overlaps with the 
+        #if (manBytes[6] & MANTISSA_NIBBLE_MASK) > 0:
+        #    result = True
+    return result
 
 def isInf(obj): 
     ''' check to see if a python float is an infinity 
@@ -528,10 +605,20 @@
         
         throws -- throws a TypeError if obj isn't a python float     
     '''    
+    # bad result for code checking
+    result = None
+    
+    # check to see if exponent is all ones (excluding sign bit)
+    # if exponent is not all ones this can't be a Inf    
     if not isExpAllOnes(obj):
-        return False
+        result =  False
+    
+    # get the mantissa as a byte array properly masked    
     manBytes = getMantissaBytes(obj)
-    for i,byte in enumerate(manBytes):
+    
+    for byte in manBytes:
+        #check if any of the unmasked mantissa bytes are zero
+        # to be a NaN the mantissa must be zero
         if byte > 0:
             return False
     return True
@@ -559,9 +646,9 @@
     '''
         
     return isInf(obj) and not isPositive(obj)   
-  
-
-    
-
-
-
+    
+
+    
+
+
+




Related Messages


Powered by MHonArc, Updated Tue Oct 31 13:20:04 2006