[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

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

    λ> 10^308 :: Double
    λ> 10^309 :: Double

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)

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

I believe this is all expected behavior.  This article is very helpful
and provides detailed explanations of many related topics:


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 =

    λ> fromInteger biggestFloat :: Float

    λ> fromInteger (succ biggestFloat) :: Float

    λ> truncate (1/0 :: Float)

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

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

    λ> let biggestDouble :: Integer; biggestDouble =

    λ> fromInteger biggestDouble :: Double

    λ> fromInteger (succ biggestDouble) :: Double

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

More information about the Haskell-Cafe mailing list