That decimal literals represent binary floating point numbers is defined by the language, not the hardware.
I consider it a basic point of language design literacy that exact decimal literals without some other indicators should not represent an inexact type that isn't designed to represent decimal data.
Infuriatingly, very few languages get that right. But perl 6 isn't unique in doing so; Scheme had been doing it right for decades.
(Actually, Scheme doesn't quite get this right: decimals are inexact by default and only rationals expressed as divisions of integers are exact, though it is less cumbersome to specify an exact decimal than in most popular language -- its a literal modifier, not a function call.)
The use of an annotative '#e' to get an exact number contrasts with Perl 6's choices for the default interpretation of number literals. The Perl 6 choice adopts scientific notation to correspond to floats:
While defaulting to floats for rational numbers may be the default for many languages, it is by no means the only way to store them, which is why we're talking about them. In Perl 6 they are often stored as a numerator and denominator within the Rat type, and converted for display.
How come a LISP allows you to write 1/10 instead of (/ 1 10)? Is it a special case for entering fractions, or does Racket allow arbitrary arithmetic expressions with infix operators?
I've loved lisp's power since I first encountered it in the early 80s and also admired the great care put in to various aspects of Common Lisp (which is mentioned as the foundation for scheme's number decisions). Great stuff and still very relevant.
> Floats are storage formats for approximations of numbers. Floats are, by definition, not relevant if one wants to store an exact number exactly.
Floats can store integer values exactly up to an upper limit (2^24 IIRC), which is often useful. And they can store binary fractions exactly up to a point.
No number representation can represent all numbers exactly. Each can store some subset of all numbers exactly.
Fwiw I can't tell if you're being pedantic for fun or not. I'm going to stick with fun...
> Floats can store integer values exactly up to an upper limit (2^24 IIRC)
You're right, for relatively small integers of 8 digits or so.
Here's a fun place to note that on the machine I just tried the Rakudo Perl 6 compiler will happily exactly store integers with hundreds of thousands of digits.
> which is often useful.
As in you've written such code in dozens of programs?
> And [floats] can store binary fractions exactly up to a point.
0.1 is already "past" that point which is even less impressive than 8 digit integers.
> No number representation can represent all numbers exactly. Each can store some subset of all numbers exactly.
Well duh. No computer can compute all computable things. Each can compute some things. My machine became unhappy when I asked it to store a number that would require a terabyte of RAM. Are these sorts of thing really worth mentioning when the starting point is just 0.1 + 0.2 == 0.3?
> You're right, for relatively small integers of 8 digits or so.
For doubles (more common than floats) it is up to 2^53, which is quite a usable range.
> As in you've written such code in dozens of programs?
As in every JavaScript program ever written that uses a for loop and integer indices does this.
> 0.1 is already "past" that point which is even less impressive than 8 digit integers.
0.1 is not a binary fraction. A binary fraction can be expressed in the form a/2^b for some a and b.
Decimal representations have the same limitation (can only express decimal fractions), it just seems more exact because we write numbers in decimal.
> Are these sorts of thing really worth mentioning when the starting point is just 0.1 + 0.2 == 0.3?
It's worth mentioning when you say untrue things like "Floats are, by definition, not relevant if one wants to store an exact number exactly." Double precision floating point has more exact integer range than int32.
I think you guys are arguing at cross-purposes. I'm not sure anyone is arguing that an integer is better than a double for integer representation, but that storing a pair of numeric values (whether they be integers or floating point of some type) allows for more natural expression of numeric values in a high level language, with more fidelity.
> > Floats are, by definition, not relevant if one wants to store an exact number exactly.
> Floats can store integer values exactly up to an upper limit (2^24 IIRC), which is often useful. And they can store binary fractions exactly up to a point.
If you have some knowledge about the number you are storing, such as that it is an integer, then you can use the fact that floats can represent integers exactly to large values. If you need a general purpose numeric type of which you can't assume it's an integer, and it needs to be stored exactly, then I think it's valid to say that floating point numbers are not relevant, at least not as the entirely of the underlying storage container.
> No number representation can represent all numbers exactly. Each can store some subset of all numbers exactly.
Yes. So we are talking about storage mechanisms that allow for more fidelity than plain floats and doubles can achieve.
If you search back to the comment that started this subthread you'll find it began:
"Try 0.1 + 0.2 == 0.3 in some other language, then try it in Perl 6."
Do you agree with all of the next sentence or not? Please start with a plain yes or no before getting in to details.
The three individual literal decimal numbers shown above are not integers, they're not binary fractions, they're not floats, they are rational numbers, they are exact numbers, they are easily stored exactly on a computer, and whether or not they are stored exactly on a computer is a choice made by a programming language.
No, because I think that "easily stored on a computer" is too vague and reductive.
I apologize if I have been too unclear about my point. My point is that your position is unfair. Your position seems to be that rational arithmetic is an obvious choice that other languages have been too lazy or stupid to adopt as their default. My point is that rational arithmetic is a fine choice for many things, but it is not a strict improvement over other number representations. Yes it can handle 0.1 + 0.2 = 0.3, but your implied conclusion that it is an obvious "default" choice is not accurate. It is not as perfect, and floating point is not as bad, as you seem to think.
Yes, doubles have lots of values they can't represent perfectly, but so do rationals. Like sqrt(2), sin(1), pi, or any calculations involving numbers like these.
Yes rationals can represent lots of numbers perfectly, but if you're keeping everything exact these can start to take lots of memory. Some slides I found about Perl 6 indicate that Rat values lose precision if the denominator gets too big, to avoid using too much memory. If this is true, the Rat type shouldn't be thought of as an "exact" type any more than double -- it could cease to be exact even if you stay away from inherently non-rational number like I listed above.
What I'm disagreeing with overall is the dichotomy you are trying to create of: double=approximate, Perl 6 number=exact. Neither of those are really very true. There are cases where double is exact and cases where Perl 6 is not exact.
> "easily stored on a computer" is too vague and reductive.
Fwiw, from the compiler source code:
my role Rational[::NuT, ::DeT] does Real {
has NuT $.numerator;
has DeT $.denominator;
> Your position seems to be that rational arithmetic is an obvious choice
Yes. Rational storage and rational arithmetic is an obvious choice for storing and processing rational numbers. (Alongside the other obvious choice -- using floats.)
> other languages have been too lazy or stupid
I'm extolling what I consider a minor Perl 6 virtue. Where have I been negative toward other languages?
> rational arithmetic is a fine choice for ...
... doing rational arithmetic.
> it is not a strict improvement over other number representations.
For representing Integers? Sure. Irrationals? Agreed. Complex numbers? Gotchya. Number crunching where absolute exactness is not necessary? Use floats.
But if exactness is required and a formula only involves rational numbers (and integers) then rational storage and processing is a strict improvement over use of floats.
> [rationals are] not as perfect, and floating point is not as bad, as you seem to think.
When did I suggest floats are bad? The general number type in Perl 6 is a float. Floats are awesome! But floats are by design not exact for arbitrary rational numbers. Their awesomeness derives directly from them being inexact in this way.
When did I suggest storing rationals is perfect? They use up more memory than floats and processing can become pathologically slow if the denominators get big enough. This problem derives directly from them being exact.
> doubles have lots of values they can't represent perfectly, but so do rationals. Like sqrt(2), sin(1), pi
Those are explicitly defined in mathematics as numbers that are not rational. Rational storage and arithmetic is for representing and processing numbers that are rational!
One can't exactly store an irrational number. The Perl 6 compiler defines a constant for the irrational number `pi`:
my constant pi = 3.14159_26535_89793_238e0;
The 'e0' on the end means that `pi` is stored as a float.
> Some slides I found about Perl 6 indicate that Rat values lose precision if the denominator gets too big, to avoid using too much memory.
The numerator of a default rational (a non-parameterized Rat) can be arbitrarily large but if the denominator exceeds 64 bits (20 decimal digits) then the compiler converts the number to a float.
If you don't like that then you can use a rational with a larger denominator, with the extreme being a FatRat that has an arbitrary sized denominator as well as arbitrary sized numerator.
> If this is true, the Rat type shouldn't be thought of as an "exact" type any more than double
I think that view misses something very important. This is indeed where the discussion could get interesting. We shall see. It seems we needed to get past a lot of misunderstanding first.
> What I'm disagreeing with overall is the dichotomy you are trying to create of: double=approximate, Perl 6 number=exact.
I've never said that. What I have said is that, for storing and processing rational numbers, doubles are approximate (and they are); that it's possible to be exact instead (and it is); and that Perl 6 returns True for the expression `0.1 + 0.2 == 0.3` because by default it processes rationals as exact rationals.
> There are cases where double is exact
Not for rational numbers (I'm ignoring silly examples like 1/1 and others that happen to work out because the denominator and numerators are powers of two or whatever).
> and cases where Perl 6 is not exact.
Not for rational numbers, if you choose to have them be exact.
> Floats are storage formats for approximations of numbers. Floats are, by definition, not relevant if one wants to store an exact number exactly.
This is setting up a dichotomy of float=approximate, and the implied contrast is that Perl 6 rationals are exact.
Float is "by definition, not relevant if one wants to store an exact number exactly."
You didn't say "an exact rational," you said "an exact number." Your implication is that other representations are relevant if one wants to store an exact number exactly. You don't say rational, so you imply that other representations can represent an arbitrary number exactly.
If you try to advertise Perl 6 as "exact", in comparison to those messy floats, you're going to get people who are very unhappy when they find out that 2pi / 2 isn't exactly pi.
And you're also shortchanging people who use eg. JavaScript doubles as exact integer indices every day. X/1 isn't a "silly" case, integers are extremely relevant across all kinds of calculations.
People who want to truly understand this landscape need to understand the contrasts between various number representations and the pros and cons of each. No representation can represent every real number perfectly, so everyone is going to run up against inexactness in their calculations unless they know how to restrict the domain of their calculations to numbers that can be perfectly represented with their chosen number representation.
> You didn't say "an exact rational," you said "an exact number."
You were right the first time you said that. You're still right. I immediately said as much in my first response to you. I don't understand what more you could want. :<
I do know what I want. I would like you to acknowledge that you are basically ignoring the direct context of my commentary, namely chubot's "0.1 can't be represented exactly [using a computer]" and natch's "wtf" about `0.1 + 0.2 == 0.3`.)
> If you try to advertise Perl 6 as "exact"
That would be absurd.
> integers are extremely relevant across all kinds of calculations.
In the context of discussing rational storage and arithmetic, integers seem to me to be primarily relevant to the extent one is talking of numerators and denominators and primarily irrelevant to the extent one is talking about floats. Do you disagree?
> People who want to truly understand this landscape need to understand the contrasts between various number representations and the pros and cons of each.
Sure.
But one has to start somewhere within a confusing landscape and try not to get lost by paying attention to details that don't yet matter. In this case natch started with the issue of exact rational calculation, chubot's wording suggested that rationals couldn't ever be stored accurately on a computer, and I tried to get floats out of the conversation until we'd cleared that confusion up. But you immediately took issue with me omitting a qualification that I thought obvious from context ("rationals"), then followed that by ignoring (afaict) my acknowledgement of your correction, and then we ended up here, with disappointingly little light shone on the very issue we both find interesting. :<
Perhaps our exchange was entirely futile. Who knows? And maybe we'll meet again and do better. Here's hoping. :)
> A language storing big numbers in non-native formats, like your Rakudo example, is irrelevant to the parent's point.
I thought being able to store an up to 8 digit integer in a float was an interesting tidbit. I already knew it but others might not. However, it was also completely irrelevant to a discussion of why 0.1 + 0.2 equals 0.3 in Perl 6 and, imo, even to my (slight over) emphasis that a float is for (efficient) storage and processing of approximations, not exact numbers.
> 0.1 isn't past any "point" (whatever that means).
Precisely. I was directly responding to "And [floats] can store binary fractions exactly up to a point." What does that mean? "up to a point" is highly ambiguous. The fact that 0.1 isn't stored exactly is completely unambiguous.
> It just isn't representable without recurrence in base 2 much like 1/3 isn't in base 10.
So what? It is representable without recurrence in a pair of base 2 numbers, eg 1 (numerator) and 11 (denominator) for 1/3.
> Your post could do without 'duh'
OK. I considered that and thought it was OK, all things considered, given that it wasn't prominent and succinctly expressed my reaction. But I hear you that even such a gentle 'duh' is problematic and will be even more careful about how I express myself at HN in future.
> and the like as well.
Would you be willing to be specific? While I recognize the 'duh' is edgy, I've reread the rest of what I wrote and don't understand what you think I got wrong.
> I consider it a basic point of computer literacy to understand this.
Yes, but just because fractional notation defaults to a floating point representation in most languages does not mean that the option of defaulting to decimal/rational notation at the language level should be ruled out generally.
And this is how they work: they're binary, not decimal. Computers are binary, not decimal. 0.1 can't be represented exactly as binary.
Python has a decimal type, if that's what you want: https://docs.python.org/2/library/decimal.html
I consider it a basic point of computer literacy to understand this.