PageRenderTime 28ms CodeModel.GetById 13ms app.highlight 12ms RepoModel.GetById 1ms app.codeStats 0ms

/lib/fpconst.py

https://bitbucket.org/cistrome/cistrome-harvard/
Python | 163 lines | 155 code | 0 blank | 8 comment | 0 complexity | 6c9460f9c3f7f06480b46d6282505b01 MD5 | raw file
  1"""Utilities for handling IEEE 754 floating point special values
  2
  3This python module implements constants and functions for working with
  4IEEE754 double-precision special values.  It provides constants for
  5Not-a-Number (NaN), Positive Infinity (PosInf), and Negative Infinity
  6(NegInf), as well as functions to test for these values.
  7
  8The code is implemented in pure python by taking advantage of the
  9'struct' standard module. Care has been taken to generate proper
 10results on both big-endian and little-endian machines. Some efficiency
 11could be gained by translating the core routines into C.
 12
 13See <http://babbage.cs.qc.edu/courses/cs341/IEEE-754references.html>
 14for reference material on the IEEE 754 floating point standard.
 15
 16Further information on this package is available at
 17<http://www.analytics.washington.edu/statcomp/projects/rzope/fpconst/>.
 18
 19Author:    Gregory R. Warnes <gregory_r_warnes@groton.pfizer.com>
 20Date::     2003-04-08
 21Copyright: (c) 2003, Pfizer, Inc.
 22"""
 23
 24__version__ = "0.7.0"
 25ident = "$Id: fpconst.py,v 1.12 2004/05/22 04:38:17 warnes Exp $"
 26
 27import struct, operator
 28
 29# check endianess
 30_big_endian = struct.pack('i',1)[0] != '\x01'
 31
 32# and define appropriate constants
 33if(_big_endian): 
 34    NaN    = struct.unpack('d', '\x7F\xF8\x00\x00\x00\x00\x00\x00')[0]
 35    PosInf = struct.unpack('d', '\x7F\xF0\x00\x00\x00\x00\x00\x00')[0]
 36    NegInf = -PosInf
 37else:
 38    NaN    = struct.unpack('d', '\x00\x00\x00\x00\x00\x00\xf8\xff')[0]
 39    PosInf = struct.unpack('d', '\x00\x00\x00\x00\x00\x00\xf0\x7f')[0]
 40    NegInf = -PosInf
 41
 42def _double_as_bytes(dval):
 43    "Use struct.unpack to decode a double precision float into eight bytes"
 44    tmp = list(struct.unpack('8B',struct.pack('d', dval)))
 45    if not _big_endian:
 46        tmp.reverse()
 47    return tmp
 48
 49##
 50## Functions to extract components of the IEEE 754 floating point format
 51##
 52
 53def _sign(dval):
 54    "Extract the sign bit from a double-precision floating point value"
 55    bb = _double_as_bytes(dval)
 56    return bb[0] >> 7 & 0x01
 57
 58def _exponent(dval):
 59    """Extract the exponentent bits from a double-precision floating
 60    point value.
 61
 62    Note that for normalized values, the exponent bits have an offset
 63    of 1023. As a consequence, the actual exponentent is obtained
 64    by subtracting 1023 from the value returned by this function
 65    """
 66    bb = _double_as_bytes(dval)
 67    return (bb[0] << 4 | bb[1] >> 4) & 0x7ff
 68
 69def _mantissa(dval):
 70    """Extract the _mantissa bits from a double-precision floating
 71    point value."""
 72
 73    bb = _double_as_bytes(dval)
 74    mantissa =  bb[1] & 0x0f << 48
 75    mantissa += bb[2] << 40
 76    mantissa += bb[3] << 32
 77    mantissa += bb[4]
 78    return mantissa 
 79
 80def _zero_mantissa(dval):
 81    """Determine whether the mantissa bits of the given double are all
 82    zero."""
 83    bb = _double_as_bytes(dval)
 84    return ((bb[1] & 0x0f) | reduce(operator.or_, bb[2:])) == 0
 85
 86##
 87## Functions to test for IEEE 754 special values
 88##
 89
 90def isNaN(value):
 91    "Determine if the argument is a IEEE 754 NaN (Not a Number) value."
 92    return (_exponent(value)==0x7ff and not _zero_mantissa(value))
 93
 94def isInf(value):
 95    """Determine if the argument is an infinite IEEE 754 value (positive
 96    or negative inifinity)"""
 97    return (_exponent(value)==0x7ff and _zero_mantissa(value))
 98
 99def isFinite(value):
100    """Determine if the argument is an finite IEEE 754 value (i.e., is
101    not NaN, positive or negative inifinity)"""
102    return (_exponent(value)!=0x7ff)
103
104def isPosInf(value):
105    "Determine if the argument is a IEEE 754 positive infinity value"
106    return (_sign(value)==0 and _exponent(value)==0x7ff and \
107            _zero_mantissa(value))
108
109def isNegInf(value):
110    "Determine if the argument is a IEEE 754 negative infinity value"
111    return (_sign(value)==1 and _exponent(value)==0x7ff and \
112            _zero_mantissa(value))
113
114##
115## Functions to test public functions.
116## 
117
118def test_isNaN():
119    assert( not isNaN(PosInf) )
120    assert( not isNaN(NegInf) )
121    assert(     isNaN(NaN   ) )
122    assert( not isNaN(   1.0) )
123    assert( not isNaN(  -1.0) )
124
125def test_isInf():
126    assert(     isInf(PosInf) )
127    assert(     isInf(NegInf) )
128    assert( not isInf(NaN   ) )
129    assert( not isInf(   1.0) )
130    assert( not isInf(  -1.0) )
131
132def test_isFinite():
133    assert( not isFinite(PosInf) )
134    assert( not isFinite(NegInf) )
135    assert( not isFinite(NaN   ) )
136    assert(     isFinite(   1.0) )
137    assert(     isFinite(  -1.0) )
138
139def test_isPosInf():
140    assert(     isPosInf(PosInf) )
141    assert( not isPosInf(NegInf) )
142    assert( not isPosInf(NaN   ) )
143    assert( not isPosInf(   1.0) )
144    assert( not isPosInf(  -1.0) )
145
146def test_isNegInf():
147    assert( not isNegInf(PosInf) )
148    assert(     isNegInf(NegInf) )
149    assert( not isNegInf(NaN   ) )
150    assert( not isNegInf(   1.0) )
151    assert( not isNegInf(  -1.0) )
152
153# overall test
154def test():
155    test_isNaN()
156    test_isInf()
157    test_isFinite()
158    test_isPosInf()
159    test_isNegInf()
160    
161if __name__ == "__main__":
162    test()
163