[Haskell-cafe] Problems with truncate big float values in Haskell

Manuel Gómez targen at gmail.com
Thu Jan 5 19:32:30 UTC 2017


On Thu, Jan 5, 2017 at 2:18 PM Henson <jfsihenson at gmail.com> wrote:
> I have one Rational number (3 + sqrt 5) and I need get the last three
> digits from integral part of that number.

But that number is irrational, not rational.  The Haskell sqrt
function from the Prelude is a method of the Floating class, so it
works by default on the Double type, which is a floating point number
type with a fixed-size finite representation that approximates real
numbers with varying precision over a limited range.

> The question is the number is arbitrary and that number always is power
> of n and n is between 2(Two) and 2000000000(Two billions).
>
> I have attempted that on ghci for various values and get same result
> with different powers:
>
> let x = (truncate ((3 + sqrt 5) ^ 2000000)) `mod` 1000 and result is 216.
>
> let y = (truncate ((3 + sqrt 5) ^ 20000000)) `mod` 1000 and result is 216.
>
> let w = (truncate ((3 + sqrt 5) ^ 200000000)) `mod` 1000 and result is 216.
>
> let z = (truncate ((3 + sqrt 5) ^ 2000000000)) `mod` 1000 and result is 216.
>
> The result is same for all:
>
> 216, and is incorrect because any that expressions have one exclusive value.

The Double type has a special value, Infinity, to represent (roughly)
numbers too large to represent otherwise.  You can get at it with a
zero division:

    λ> 1/0 :: Double
    Infinity

You can also get it with computations resulting in numbers too large
to represent otherwise:

    λ> 10^308 :: Double
    1.0000000000000006e308
    λ> 10^309 :: Double
    Infinity

The truncate method of the RealFrac class applied to this Infinity
value can convert it to the smallest Integer value that is represented
as Infinity when converted to Double:

    λ> truncate (1/0 :: Double)
    179769313486231590772930519078902473361797697894230657273430081157732675805500963132708477322407536021120113879871393357658789768814416622492847430639474124377767893424865485276302219601246094119453082952085005768838150682342462881473913110540827237163350510684586298239947245938479716304835356329624224137216

Indeed, the last three digits of the decimal representation of that
number are 216.  The immediately preceding Integer is indeed converted
to a non-Infinity Double value:

    λ> fromInteger (pred (truncate (1/0 :: Double))) :: Double
    1.7976931348623157e308

I believe this is all expected behavior.  This article is very helpful
and provides detailed explanations of many related topics:
https://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html


---


While playing around with this, I discovered a curious difference
between Float and Double.  The smallest Integer that does not yield
Infinity on conversion to Float is not anywhere close to the value of
the expression «truncate (1/0 :: Float) :: Integer»:

    λ> let biggestFloat :: Integer; biggestFloat =
340282356779733661637539395458142568447

    λ> fromInteger biggestFloat :: Float
    3.4028235e38

    λ> fromInteger (succ biggestFloat) :: Float
    Infinity

    λ> truncate (1/0 :: Float)
    340282366920938463463374607431768211456

    λ> truncate (1/0 :: Float) - biggestFloat
    10141204801825835211973625643009

With Double, «truncate (1/0 :: Double)» is indeed the immediate
successor of the largest Integer not converted to Infinity:

    λ> let biggestDouble :: Integer; biggestDouble =
179769313486231590772930519078902473361797697894230657273430081157732675805500963132708477322407536021120113879871393357658789768814416622492847430639474124377767893424865485276302219601246094119453082952085005768838150682342462881473913110540827237163350510684586298239947245938479716304835356329624224137215

    λ> fromInteger biggestDouble :: Double
    1.7976931348623157e308

    λ> fromInteger (succ biggestDouble) :: Double
    Infinity

    λ> truncate (1/0 :: Double) - biggestDouble
    1


More information about the Haskell-Cafe mailing list