ghci: inconsistent return values for succ

Greetings, Absolutely brand new to Haskell. Taking ghci v7.10.2 out for a spin, and I find I get inconsistent return values for succ n: ghci> succ 3.14 4.1400000000000001 for example instead of the expected 4.14 succ 2.14 and 4.14 give the expected results. but succ 2.14 returns 2.1399999999999997. This anomalous behavior runs through the range of n.nn; in the n.01 range, for example, 16.01 and 63.01 return wonky results per above. I tested this on Windows and Linux (various flavors) and I get the same results there and in the interactive test code space on haskell.org. I'm not familiar enough with the language, yet, to go debugging this on my own, but it would seem to be at least a problem with how succ is implemented, if not how values are handled in general.....which could potentially be bad if you were trying to do anything requiring precise calculations....

On Sat, Oct 17, 2015 at 7:17 PM, Frothy Bits
Greetings,
Absolutely brand new to Haskell. Taking ghci v7.10.2 out for a spin, and I find I get inconsistent return values for succ n:
ghci> succ 3.14 4.1400000000000001
for example instead of the expected 4.14
This is pretty standard for today's floating point hardware in CPU's. It's not a Haskell thing. It comes up in C and Python too - that is, in pretty much anything that uses hardware floating point. If you need precision, try an integral type or a rational. -- Dan Stromberg

@ Dan Stromberg: Thanks, understood.
On Sat, Oct 17, 2015 at 7:17 PM, Frothy Bits
Greetings,
Absolutely brand new to Haskell. Taking ghci v7.10.2 out for a spin, and I find I get inconsistent return values for succ n:
ghci> succ 3.14 4.1400000000000001
for example instead of the expected 4.14
succ 2.14 and 4.14 give the expected results. but succ 2.14 returns 2.1399999999999997. This anomalous behavior runs through the range of n.nn; in the n.01 range, for example, 16.01 and 63.01 return wonky results per above.
I tested this on Windows and Linux (various flavors) and I get the same results there and in the interactive test code space on haskell.org.
I'm not familiar enough with the language, yet, to go debugging this on my own, but it would seem to be at least a problem with how succ is implemented, if not how values are handled in general.....which could potentially be bad if you were trying to do anything requiring precise calculations....

@ Kostiantyn: Thank you.
Is the behavior I'm seeing actually related to a bug in parsec?
http://stackoverflow.com/questions/29820870/floating-point-numbers-precision...
Yes or no, why wouldn't it be the default behavior of ghc to load the
Decimal package?
OTOH, the current default floating point behavior certainly got me thinking
and digging:
http://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html
On Sat, Oct 17, 2015 at 7:48 PM, Frothy Bits
@ Dan Stromberg: Thanks, understood.
On Sat, Oct 17, 2015 at 7:17 PM, Frothy Bits
wrote: Greetings,
Absolutely brand new to Haskell. Taking ghci v7.10.2 out for a spin, and I find I get inconsistent return values for succ n:
ghci> succ 3.14 4.1400000000000001
for example instead of the expected 4.14
succ 2.14 and 4.14 give the expected results. but succ 2.14 returns 2.1399999999999997. This anomalous behavior runs through the range of n.nn; in the n.01 range, for example, 16.01 and 63.01 return wonky results per above.
I tested this on Windows and Linux (various flavors) and I get the same results there and in the interactive test code space on haskell.org.
I'm not familiar enough with the language, yet, to go debugging this on my own, but it would seem to be at least a problem with how succ is implemented, if not how values are handled in general.....which could potentially be bad if you were trying to do anything requiring precise calculations....

Is the behavior I'm seeing actually related to a bug in parsec?
No, I don't think GHC relies on parsec at all.
Yes or no, why wouldn't it be the default behavior of ghc to load the Decimal package?
Decimal is very inefficient, because it's implemented as a pair of
numbers: Word8 to describe a position of a dot, and Integer to describe
number itself. E.g., (3.14 :: Decimal) is the same as directly writing
(Decimal 2 314).
Integer, unlike Int and Double, is very inefficient for computation-heavy
code.
Interesting find!
Ghc (its base library) provides Data.Fixed [0] module with similar purposes
to Decimal. Initially I couldn't recommend it, since I thought it has the
same Double-related behavior, but when I digged into it now, I found out
that it's probably a bug (or a "feature") in "succ" implementation:
λ succ (3.14 :: Fixed E12)
3.140000000001
λ (3.14 :: Fixed E12) + 1
4.140000000000
So, if you don't want to use Decimal, you can just use Data.Fixed (I find
Decimal a bit more elegant though).
[0]: https://hackage.haskell.org/package/base-4.8.1.0/docs/Data-Fixed.html
On Sun, Oct 18, 2015 at 6:57 PM, Frothy Bits
@ Kostiantyn: Thank you.
Is the behavior I'm seeing actually related to a bug in parsec?
http://stackoverflow.com/questions/29820870/floating-point-numbers-precision...
Yes or no, why wouldn't it be the default behavior of ghc to load the Decimal package?
OTOH, the current default floating point behavior certainly got me thinking and digging:
http://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html
On Sat, Oct 17, 2015 at 7:48 PM, Frothy Bits
wrote: @ Dan Stromberg: Thanks, understood.
On Sat, Oct 17, 2015 at 7:17 PM, Frothy Bits
wrote: Greetings,
Absolutely brand new to Haskell. Taking ghci v7.10.2 out for a spin, and I find I get inconsistent return values for succ n:
ghci> succ 3.14 4.1400000000000001
for example instead of the expected 4.14
succ 2.14 and 4.14 give the expected results. but succ 2.14 returns 2.1399999999999997. This anomalous behavior runs through the range of n.nn; in the n.01 range, for example, 16.01 and 63.01 return wonky results per above.
I tested this on Windows and Linux (various flavors) and I get the same results there and in the interactive test code space on haskell.org.
I'm not familiar enough with the language, yet, to go debugging this on my own, but it would seem to be at least a problem with how succ is implemented, if not how values are handled in general.....which could potentially be bad if you were trying to do anything requiring precise calculations....
_______________________________________________ Beginners mailing list Beginners@haskell.org http://mail.haskell.org/cgi-bin/mailman/listinfo/beginners

@ Kostiantyn: Thank you again for the links to Decimal and Data.Fixed
@ Iustin: You're absolutely correct, I was abusing succ. I blame myself.
@ Rein: Thank you, I'd previously shared the goldberg paper; it's
illuminating.
Fwiw, prior to adventures with succ, I'd noticed that simple operations on
certain simple real numbers would give "exciting" results. (Undoubtedly, I
should have just gone with that instead of posting about succ; apologies
again for confusing Iustin.)
ghci> map (+ 0.01)[0.01,0.02 .. 1.00]
for example, gave me a nice list of visually stimulating values for the
reasons Rein and Kostiantyn pointed out. With succ, I wondered what I
would see if I did something "wrong." My assumption was that it would
flail and give me an error message, something along the lines of "Fool,
that is not the proper way to succ. Go play with natural numbers." That
I'd get occasionally expected values with either the above or succ
was.....peculiar, until reading Kostiantyn's replies and finding and
reading the Goldberg paper, not to mention having a "Forth moment" and
remembering scaled integer......
I (foolishly or not) made the assumption that Haskell would do something
different with floats "out of the box." I do realize the same issues are
inherent in other languages, but I wondered if it might be "smart,"
recognize I was calculating with real numbers and automagically either load
what I needed or point me in that direction. That said, I really
appreciate Rein's reply and recognize that picking Double for the extended
default rules is "a good choice."
Anyway, after loading Data.Fixed, this produces reasonable output:
ghci> map (+ (0.01 :: Fixed E2)) [0.01,0.02 .. 1.01]
Back to reading and learning by cutting myself. Thanks again all.
On Sun, Oct 18, 2015 at 8:57 AM, Frothy Bits
@ Kostiantyn: Thank you.
Is the behavior I'm seeing actually related to a bug in parsec?
http://stackoverflow.com/questions/29820870/floating-point-numbers-precision...
Yes or no, why wouldn't it be the default behavior of ghc to load the Decimal package?
OTOH, the current default floating point behavior certainly got me thinking and digging:
http://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html
On Sat, Oct 17, 2015 at 7:48 PM, Frothy Bits
wrote: @ Dan Stromberg: Thanks, understood.
On Sat, Oct 17, 2015 at 7:17 PM, Frothy Bits
wrote: Greetings,
Absolutely brand new to Haskell. Taking ghci v7.10.2 out for a spin, and I find I get inconsistent return values for succ n:
ghci> succ 3.14 4.1400000000000001
for example instead of the expected 4.14
succ 2.14 and 4.14 give the expected results. but succ 2.14 returns 2.1399999999999997. This anomalous behavior runs through the range of n.nn; in the n.01 range, for example, 16.01 and 63.01 return wonky results per above.
I tested this on Windows and Linux (various flavors) and I get the same results there and in the interactive test code space on haskell.org.
I'm not familiar enough with the language, yet, to go debugging this on my own, but it would seem to be at least a problem with how succ is implemented, if not how values are handled in general.....which could potentially be bad if you were trying to do anything requiring precise calculations....

On Sun, Oct 18, 2015 at 10:57 PM, Frothy Bits
Is the behavior I'm seeing actually related to a bug in parsec?
If you're interested in digging deeper, I'd say look at the output, not the input end. Almost certainly the machine floating-point double for 3.14 and (3.14+1.0) are identical across ghc, C, and python. What's not identical is how different languages choose to display 4.14. C and python do some display rounding so you don't see the issue. The display algorithm in Haskell probably goes for the simple, naive approach. -- Kim-Ee

That said, I really appreciate Rein's reply and recognize that picking Double for the extended default rules is "a good choice."
To follow up a bit, the reason that it's a good choice is pragmatic: we
usually prefer to work with such numbers using native floating point math
for speed rather than using rational or computable real or other
representations which are more accurate but many orders of magnitude
slower. If I said 3.5 + 1 in any general purpose language, I would be
surprised if it did anything other than an immediate floating point
calculation, and so it is (by default) in Haskell.
If we want another representation then we must reach for it, but we don't
need to reach very far.
On Sun, Oct 18, 2015 at 10:05 PM Kim-Ee Yeoh
On Sun, Oct 18, 2015 at 10:57 PM, Frothy Bits
wrote: Is the behavior I'm seeing actually related to a bug in parsec?
If you're interested in digging deeper, I'd say look at the output, not the input end. Almost certainly the machine floating-point double for 3.14 and (3.14+1.0) are identical across ghc, C, and python.
What's not identical is how different languages choose to display 4.14.
C and python do some display rounding so you don't see the issue. The display algorithm in Haskell probably goes for the simple, naive approach.
-- Kim-Ee _______________________________________________ Beginners mailing list Beginners@haskell.org http://mail.haskell.org/cgi-bin/mailman/listinfo/beginners

If you use Decimal package [0], you can have what you want:
λ succ (3.14 :: Decimal)
4.14
[0]: https://hackage.haskell.org/package/Decimal
On Sun, Oct 18, 2015 at 5:17 AM, Frothy Bits
Greetings,
Absolutely brand new to Haskell. Taking ghci v7.10.2 out for a spin, and I find I get inconsistent return values for succ n:
ghci> succ 3.14 4.1400000000000001
for example instead of the expected 4.14
succ 2.14 and 4.14 give the expected results. but succ 2.14 returns 2.1399999999999997. This anomalous behavior runs through the range of n.nn; in the n.01 range, for example, 16.01 and 63.01 return wonky results per above.
I tested this on Windows and Linux (various flavors) and I get the same results there and in the interactive test code space on haskell.org.
I'm not familiar enough with the language, yet, to go debugging this on my own, but it would seem to be at least a problem with how succ is implemented, if not how values are handled in general.....which could potentially be bad if you were trying to do anything requiring precise calculations....
_______________________________________________ Beginners mailing list Beginners@haskell.org http://mail.haskell.org/cgi-bin/mailman/listinfo/beginners

On 2015-10-17 19:17:04, Frothy Bits wrote:
Greetings,
Absolutely brand new to Haskell. Taking ghci v7.10.2 out for a spin, and I find I get inconsistent return values for succ n:
ghci> succ 3.14 4.1400000000000001
for example instead of the expected 4.14
Separately from the technical implementation of succ for floating point numbers, does it actually make sense to ask for the successor of a non-integral value? There must be some reason why Float and Double implement the Enum class, but I can't understand in what sense (mathematically) are real numbers enumerable. confused, iustin

This has nothing to do with Parsec or Decimal. Two things are happening: First, the type of the literal 3.14 is Fractional a => a. GHCi's extended default rules [1] pick Double as the default for Fractional. (This is a good choice.) Second, the closest number to 4.14 that is reresentable as a Double is 4.1400000000000001. This is an inherent limitation of the representation used. This effects every use of floating point numbers in every programming language, and every programmer should understand this. See [2] for more information. For an exact result, you can provide a different type for your Fractional literal that is capable of representing the result exactly:
succ 3.14 :: Rational
207 % 50
There must be some reason why Float and Double implement the Enum class, but I can't understand in what sense (mathematically) are real numbers enumerable
You're absolutely right. It is, at best, a kludge and has no mathematical justification. [1] https://downloads.haskell.org/~ghc/latest/docs/html/users_guide/interactive-... [2] https://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html
participants (6)
-
Dan Stromberg
-
Frothy Bits
-
Iustin Pop
-
Kim-Ee Yeoh
-
Kostiantyn Rybnikov
-
Rein Henrichs