Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I get the floating-point number immediately before/after a given number in Haskell?

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 shows as 1.0e-45) as the next-larger one, and given 1 :: Float, I'd want to get 0.999999940395355224609375 (which shows 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.

like image 897
Joseph Sible-Reinstate Monica Avatar asked Sep 29 '19 01:09

Joseph Sible-Reinstate Monica


People also ask

What does fromIntegral do in Haskell?

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.

What is a floating-point number in Haskell?

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.

What is a floating-point number variable?

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.


2 Answers

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
like image 37
Garrison Avatar answered Sep 19 '22 17:09

Garrison


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
like image 98
Willem Van Onsem Avatar answered Sep 17 '22 17:09

Willem Van Onsem