[Haskell-cafe] Problems with truncate big float values in Haskell
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
λ> 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