floatRange gives unexpected results
Here's the signature for floatRange
in base/GHC/Float.hs
:
-- | a constant function, returning the lowest and highest values
-- the exponent may assume
floatRange :: a -> (Int,Int)
And here are the results for Float
and Double
:
>>> floatRange (undefined :: Float)
(-125,128)
>>> floatRange (undefined :: Double)
(-1021, 1024)
This is quite surprising to me given the documentation for the function. Single-precision floating-point numbers have a maximum exponent of 127
and a minimum exponent of -126
(-149
for subnormalized floats). Double-precision floating-point numbers have a maximum exponent of 1023
and a minimum exponent of -1022
(-1074
for subnormalized doubles). This means either the documentation is faulty or the implementation is.
Tracking this down the issue seems to be the definition of the constants in base/includes/ieee-flpt.h
:
/* Minimum int x such that FLT_RADIX**(x-1) is a normalised float */
#if !defined(FLT_MIN_EXP)
# define FLT_MIN_EXP (-125)
#endif
And similar for the other constants, truncated:
# define FLT_MAX_EXP 128
# define DBL_MIN_EXP (-1021)
# define DBL_MAX_EXP 1024
As the comment for FLT_MIN_EXP
states, these numbers are all shifted by 1 in the direction of positive infinity. I have no idea why this is.
The definitions for floatRange
for Float
, respectively Double
are as follows:
floatRange _ = (FLT_MIN_EXP, FLT_MAX_EXP) -- ditto [ditto refers to "from float.h", which doesn't exist and should probably be "ieee-flpt.h"]
floatRange _ = (DBL_MIN_EXP, DBL_MAX_EXP) -- ditto
So if floatRange
is supposed to do what I think it should and what its documentation says it does either these constants or the implementations of floatRange
for Float
and Double
need to change.