Given a Float
or Double
, how can I get the next-larger or -smaller one of it? In other words, how do I perform equivalent functionality to C++'s std::nextafter
functions? For example, given 0 :: Float
, I'd want to get 1.40129846432481707092372958328991613128026194187651577175706828388979108268586060148663818836212158203125e-45
(which show
s as 1.0e-45
) as the next-larger one, and given 1 :: Float
, I'd want to get 0.999999940395355224609375
(which show
s as 0.99999994) as the next-smaller one. If possible, I'd like to know how to do this myself in Haskell, rather than just doing it with a third-party library (I'm fine with something in base
though) or by using the FFI to call that C++ function.
The workhorse for converting from integral types is fromIntegral , which will convert from any Integral type into any Num eric type (which includes Int , Integer , Rational , and Double ): fromIntegral :: (Num b, Integral a) => a -> b.
Haskell has two types for floating-point numbers, namely Float (single-precision) and Double (double-precision). Floating-point numbers can be represented in two ways. First, using a decimal point: 2.0 33.873 -8.3377. Second, by means of the so-called scientific notation: 33.61e6 3.7e-2 -3.7e2.
A floating point type variable is a variable that can hold a real number, such as 4320.0, -3.33, or 0.01226. The floating part of the name floating point refers to the fact that the decimal point can “float”; that is, it can support a variable number of digits before and after the decimal point.
This algorithm was stolen from mail.haskell.org/pipermail/haskell/2003-October/012931.html
import GHC.Float
nextafter1 :: Float -> Float
nextafter1 0 = 0
nextafter1 x | GHC.Float.isNaN x = x
nextafter1 x | GHC.Float.isInfinite x = x
nextafter1 x = try (abs x)
where try d = let d1 = d/2
in if x + d1 == x then improve d1 d else try d1
improve a b = let middle = (a+b)/2
in if middle == b || middle == a
then x + b
else if x + middle > x
then improve a middle
else improve middle b
You can make use of the succIEEE :: IEEE a => a -> a
function that will, for a type that belongs to the IEEE
typeclass (Float
, Double
, CFloat
and CDouble
belong to this typeclass) calculate the next representable number. Or as specified in the documentation:
Return the next largest IEEE value (Infinity and NaN are unchanged).
For example:
Prelude Numeric.IEEE> succIEEE 0
5.0e-324
Prelude Numeric.IEEE> succIEEE 1
1.0000000000000002
Prelude Numeric.IEEE> succIEEE 0 :: Float
1.0e-45
Prelude Numeric.IEEE> succIEEE 1 :: Float
1.0000001
Prelude Numeric.IEEE> succIEEE (0 :: Float) == 1.40129846432481707092372958328991613128026194187651577175706828388979108268586060148663818836212158203125e-45
True
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With