Extra functions on the built-in
float similar to those on
>>> from floatextras import * >>> f = -123.456 >>> as_tuple(f) FloatTuple(sign=1, digits=(1, 1, 1, 0, 1, 1, 0, 1, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 1, 0, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 0, 1, 1, 1), exponent=6) >>> sign, digits, exponent = as_tuple(f) >>> from_tuple((0, digits, exponent+1)) 246.912 >>> next_minus(f) -123.45600000000002 >>> next_plus(f) -123.45599999999999 >>> next_toward(f, 0) -123.45599999999999 >>> float_difference(1, next_minus(next_minus(1))) 2 >>> qnan2 = make_nan(2) >>> isnan(qnan2) True >>> isqnan(qnan2) True >>> issnan(qnan2) False >>> nan_payload(qnan2) 2 >>> isqnan(float('nan')) True >>> nan_payload(float('nan')) 0
have the same effect as the corresponding methods on
Decimal objects, but for values of the builtin
from_tuple is equivalent to the
Decimal constructor from
float_difference function is an inverse
you how many times you'd need to call
g to get
nan functions are utility functions to construct and examine NaN
values with specific payloads.
direct argument to most functions can be used to force
the module to use
ctypes to reinterpret-cast the bits of the
value as stored, instead of encoding it portably using the
struct module. On almost all platforms, this will give the
same results; on platforms that don't natively use IEEE floats,
or store them in a different byte order than the primary byte order,
this will instead give the wrong results (but that may be useful
to check for while experimenting).
Differences from Decimal
A fixed-size binary float is of course not identical to an arbitrary-size decimal float. That means the tuple representation is significantly different. In particular:
Decimal is stored as an integer plus an exponent, with separate
special exponents for infinity, quiet NaN, and signaling NaN (
float is stored as a fraction between 1 and 2, with the leading 1
implicit, plus an exponent, with a single special exponent for
infinity and both NaNs (1024, which is infinity if all digits are 0,
otherwise NaN, quiet if the first digit is 1) and another one for zero
and denormal values (-1023, which is treated as -1022 but without the
implicit leading 1 on the fraction).
The differences are easier to see through experimentation than explanation (which is partly why this module exists).
Decimal type represents an IEEE 854-1987 decimal float, and
it comes with a number of handy operations for exploring the details of
that representation, like the
next_plus family and
as_tuple. And sometimes these operations are useful beyond
exploration—e.g., to test whether the result of an algorithm is within
1 ulp of the expected result.
However, while the built-in
float type nearly always represents
an IEEE 754-1985 binary float, for which the same operations would be
handy, they aren't included.
Of course it's possible to get the bits of a
float and operator on
them manually, as explained in IEEE Floats and Python, it isn't
nearly as convenient.
So, this module provides similar functions for