Can it calculate 1/3 exactly? You can in trinary: It's 0.1.
Binary, decimal, trinary, or any other numbering system is no more accurate or "exact" than any other. They all have fractions that they cannot represent.
"Computers can only natively store integers, so they need some way of representing decimal numbers"
Technically, [digital] computers only natively "store" high and low voltages. The interpretation of a sequence of those signals as "integers" is entirely up to you.
In all seriousness, representing integers is not a given either (e.g. two's complement vs one's complement, BCD, bignum, sparse integers, etc.). If you are going down in abstraction levels to describe floating point representation, you should not just call integers "native" blindly.
Furthermore, floating point is not the only way to represent computation involving real values. It is indeed possible to represent computation on real values symbolically in many cases and lazily compute arbitrary precision results for output-printing purposes.
Technically, much storage does not need voltage being high or low either. Pits burned with lasers, and magnetic changes are also common ways to store stuff that don't involve voltage in the stored state.
Here you can see python has a fractions.Fraction type which can be used for rational number arithmetic.
Here we see that python has a nice behaviour for when printing floats.
>>> print(0.1 + 0.2)
0.3
Here is a common error where people feed the input of Fraction (and Decimal) with a float. Even though you use the Fraction here it still carries the floating point error through.
Here is the Decimal type which does not have this float problem. Some people have argued (including myself) that Decimal should be used by python instead of float. Since this is much friendlier to people doing things like adding these numbers together.
This is a good case for macros in Python, actually. Fraction('0.1') is usually what you want, so Fraction(0.1) should mean just that and if you do want the current behaviour, Fraction(float(0.1)) would do it. Same for Fraction(17/3) for example.
> Technically, [digital] computers only natively "store" high and low voltages. The interpretation of a sequence of those signals as "integers" is entirely up to you.
And then there's MLC NAND flash which stores bit sequences as different voltage levels within the same cell.
That depends on the number you want to represent. Some values can be represented exactly, others with varying degrees of precision because of the difference between what is actually stored and what you wanted to store. This will collapse a number of values into the same precision 'bucket'.
What is continuous or precise depends on the base you use. I can't think of any example in base 2, but I believe in base 3 you could represent numbers that have infinite digits in base 10.
If I'm not mistaken, 0.3333... would be 0.1 and 0.6666... would be 0.2. It probably gets nasty for a lot of simple base 10 numbers, so it isn't a good solution.
That's valid, but I was going for an ELI5 style explanation of a concept that surprised and confused me at the time. If you want to provide a better one, I'm happy to merge any pull requests.
when you aim for reddit style stuff like "ELI5", don't be surprised if HN tears you up. reddit likes things to be cool and cliquey. we like things to be correct.
Of course you can always (use numbers), but then you have to use (/ 1 20) and (/ 2 10). "0.3" is still considered "inexact", because of the decimal point. I don't like this - finite decimals are perfectly rational numbers and trivially convertible, why can't the interpreter treat them as such?
I suspect in many instances it's down to the method doing the printing being "helpful". The page documents this behaviour with Python. I've never specifically used C#, but it seems to default to the "G" format[1], the alternative "R" format shows the expected result. You can play around with it here: http://ideone.com/hxD96J
Printing out is kind of a misleading check here, maybe a better idea would be to test equality with the constant 0.3. Of course the site is just a neat illustration and not a technical whitepaper.
Yes, I agree this page is misleading. It makes it look like C# is using rational numbers instead of floating point. In fact the "G" format defaults to 15 digits of precision for doubles, which is few enough to avoid ugly strings in many simple situations, but not all:
The printing routine. Internally, none of them can store 0.3 in a floating point variable because it is impossible to do so in exponential notation with base 2 (which is what IEE 754 uses).
Some languages may optionally use an exact representation (e.g., Scheme or Python), but that's not the general case.
Here is the part that made me understand it all: "Floating-point representations have a base (which is always assumed to be even) and a precision p. If = 10 and p = 3, then the number 0.1 is represented as 1.00 × 10-1. If = 2 and p = 24, then the decimal number 0.1 cannot be represented exactly, but is approximately 1.10011001100110011001101 × 2-4."
"In current versions, Python displays a value based on the shortest decimal fraction that rounds correctly back to the true binary value, resulting simply in ‘0.1’."
As illumen pointed out, Python has also got fractions.
For things like Pi however, there is no exact numerical representation and you'd probably want sympy or something similar.
Sure. But the inability to represent 1/3 in decimal is just the same as inability to represent 1/10 in binary. The binary case just seems different because we are using a foreign base (decimal) literal "0.1" to express the binary number.
I'm not sure what was the intended message of the table of examples. It is possible in many languages to get both types of ASCII representations for floating point: a nice human-readable 0.3 and the technically correct 0.30000000000000004. But some examples seem artificially biased towards one or the other. Only for Python both variants are shown. And then some examples use decimal representations, which are not floating point at all.
For instance, in Perl "print 0.1+0.2" will give you "0.3" just like in Python, while the printf format shown here will give you the non-rounded representation. And there are of-course decimal and rational number packages for Perl as well.
Errr that's exactly what the page implies; it does not say nor imply "those that display .3 are doing it correctly internaly".
One of the cardinal rule of floating point in computing is that you never do direct comparison between values, whatever the language, so your test should never ever be used.
That doesn't mean a language cannot be allowed to infer what the correct display of a floating point value should be.
> For what its worth, perl6 passes this test with flying colours.
Do we really expect calculations on floating point numbers to be the same as calcualtions with real numbers?
The only problem I see is that often the floating point format is not specified properly. When one writes "0.3", what does it actually mean? Does the format the compiler uses internally conform to IEEE 754? Is it 32bit, 64bit, 80bit or something else?
In other words, there are about 5648798746465 possible interpretations of the "(\+|-|)[0-9]+.[0-9]+" format, and the problem is with mismatched assumptions ("of course I'm using the One Correct Interpretation, like everyone else!").
The only problem I see is that often the floating point format is not specified properly. When one writes "0.3", what does it actually mean?
It's perfectly well-specified. If you are using double-precision floating point, "0.3" means 0x3fd3333333333333 (as bits), or 0.299999999999999988897769753748434595763683319091796875 (as an exact number: the closest representable number to 0.3).
Most languages do (though implementation bugs are common—plenty of languages where 64-bit precision is required actually end up being implemented in such a way that 80-bit precision is used on x86).
That said, a lot of low-level languages don't: C doesn't guarantee this, for example. C doesn't even mandate IEEE 754, and it merely requires that "float" is a subset of the values of "double" which is itself a subset of the values of "long double".
Perl 6 doesn't use IEEE 754 by default at all. It internally stores decimal literals as rational numbers, with numerator and denominator in separate fields, and it only resolves back to a decimal number when you convert it to a string.
But these numbers are perfectly computable! Sure they cannot be represented in the commonly used binary implementation of floating point numbers, but that doesn't mean computers cannot operate with these numbers at all.
Well, they can't be specified as IEEE 754 floats. A computer can still use those numbers in the form of decimal fixed-point or numerator-denominator formats.
>There are three binary floating-point basic formats (encoded with 32, 64 or 128 bits) and two decimal floating-point basic formats (encoded with 64 or 128 bits)
Of course they do, just not a binary floating point representation. They can be represented with decimal floating point just fine and there are plenty of programs and libraries that can do this.
One it so use fixed point decimal with a 1/100 scaling instead of floating point. So yes, integers and then you shift the decimal point when you output.
But you have to watch out for interest calculations, you might earn a fraction of a penny on a daily basis but over a year it adds up and you can't throw away that accuracy.
So you might do all math as floating point, but with pennies instead of dollars.
Or you can do Binary Coded Decimal, which stores each group of decimal number after the decimal point exactly, in many ways it similar to fixed point decimal, since it is a fixed point.
Do they do USD interest calculations in something smaller than 1/10000 (decimill I think)?
The issue with BCD would be data store support and CPU support right? Do CPUs support doing math directly with BCD values and does your DB support doing math directly with BCD values?
In any case, using floating point for any currency calculations is a huge no-no, even though a lot of things do it anyway.
I work with Magento daily and all their currency math uses PHP floats and the rounding errors drive me bonkers.
"Finance" uses lots of different things. Sometimes it uses symbolic math; sometimes it uses binary floating point, sometimes it uses decimal floating point, sometimes it uses arbitrary precision decimals or rationals, sometimes it uses integers in the smallest unit of concern for the application.
> printing the number might just cut off the digits at some point.
I'm not sure, but I think it's not really about cutting off the digits (although that's the effect it has). At least with python, I think what happens is:
* repr gives you the decimal number with the exact value of the floating-point number, i.e. 0.30000000000000004
* print gives you the least-precise decimal number whose closest floating-point representation is equal to the floating-point number
That is, there are (infinitely) many decimal numbers such that the closest floating-point representation has the value 0.30000000000000004. One of these decimal numbers is 0.3, and of all such decimal numbers, this has the fewest digits. So that's the one that gets printed.
Someone pointed out that this isn't correct, and then deleted their comment. (?)
I now think the behiviour I ascribed to print, is actually what repr does. I'm not sure about print, but I guess it is just rounding to a certain number of places.
There's some discussion here: https://docs.python.org/3.1/tutorial/floatingpoint.html. Basically: eval(repr(x)) == x is guaranteed, and some attempt is made to give the shortest such string representation for Python 3.1+ (and 2.7?), but it's not guaranteed on all platforms.
In this case, that was deliberate. I was using it to show the exact decimal value of the floating point approximations to decimal numbers, not to do decimal arithmetic.
What does it mean to "pass" this test? Just that the software is massaging its output to match human expectations rather than giving the most accurate (if not the prettiest) answer?
> Just adding 0.1 to 0.2 in the language of your choice can be misleading because printing the number might just cut off the digits at some point.
It's amazing that someone went to the trouble to register a custom domain for this and put up a nicely formatted page, yet doesn't explain the above: that it's not (just) a matter of representation, but printing precision.
That's interesting, I had no idea. There's probably a way more detailed Rosetta Code style project that could cover all these nuances, but for a single page demo, there's only so much detail I can get into before it would be more confusing than helpful.
If you'd like to flesh out the perl section a bit though, maybe include the differences between 5 and 6, I'd be happy to merge a pull request.
You've had a perl6 pull request outstanding for a while. The differences are far too big to list simply though. Ultimately Perl6 uses Rationals by default, not Floats.
> For what its worth, perl6 passes this test with flying colours.
This is because Perl 6 decimal literals are stored in a built-in rational type called Rat, which internally stores numbers as ratios between integers. So that 0.1, 0.2, 0.3 are internally stored as the tuples (1,10), (2,10), and (3,10), and the decimal value you see is just the string representation and not the actual internal value.
If you want your decimal literal to be floating-point (called Num in Perl 6), you want to add e0 to the end.
I would like to see a language use decimal by default. Under the hood, it could use floating point for certain types of calculations where less precision is required. If I want to know the answer to 0.2 + 0.1, chances are I want the answer to be 0.3. If I'm writing performance-sensitive code, maybe I can drop down a level and opt for float(0.2) + float(0.1). Are any languages doing this currently?
Perl 6 uses rationals by default. They have the advantages of being base-agnostic, able to accurately represent any recurring digit expansion accurately regardless of eventual base, and also faster (since, especially if you normalize (convert to lowest terms) lazily, most operations are just a few integer instructions with no branching, looping, or bit-twiddling involved).
Scheme has rationals, but decimal literals aren't rational by default. You have to type #e in front of it, or express it as a fraction.
It really ought to be fixed at the implementation level (how much stuff would it really break if floatin point errors went away?), but failing that I'd love a macro that did it for me. I can't figure out how to write one robustly.
For C# i see a different behaviour as in his example.
double test = 0.1 + 0.2; //will be 0.30000000000000004 if you check in the Debugger
Debug.Print(test.ToString());//will print 0.3
Don't be ridiculous. It's perfectly fine if you know what you're doing. For example, when you have a limited selection of floats (e.g. hashtable keys, or only numbers between 0 and 100, accurate to 1 decimal) - in these cases, strings would work just as well, but floats are more efficient (and compare correctly).
You've just redefined your problem to using floats as the underlying representation. In that case you don't even need floats...
In most other cases the correct way is to check if the absolute value of the difference between one value and another is smaller than some arbitrary cut-off, a small number typically denoted with 'epsilon'.
Until your code gets ported to a platform where float == double and it turns out the algo feeding your clever efficient comparison delivers slightly different values that previously collapsed into the same bucket. Relying on the particulars of an underlying representation requires deep knowledge of how those particulars are implemented (and I would happily agree with you that such knowledge is a requirement but more often than not when you come across a float comparison with equality you're looking at a bug. That you're the exception to the rule is fine with me, you seem to know what you're doing so don't take it personal).
The real problem is: most people don't have deep knowledge of how those details are implemented and take 'equality' for granted, especially if the visual representation of the numbers they are comparing tells them they should be equal which is not always the case.
The old adage goes: if you need floating point you don't understand your problem :)
The comment that sparked this sub-thread is a nice illustration of what can and does go wrong.
In Haskell/GHC it depends on what representation you chose. Default is Double, which exhibits this problem. But if I force it to Float I get the 'correct' result. Or if I use the 'Scientific' data type (which has arbitrary precision). Just like 'Int' vs 'Integer', where the former is restricted by the machine's word size, while the later is unbounded.
So effectively, in Haskell, it's both and neither.
A Float will round, as expected.
A double will return the correct value as it, should.
Shouldn't the Scientific, if it has arbitrary precision, arrive at the correct value too?
Clearly the only logical conclusion is that the Glasgow compiler, at its roots, virtualizes the entire quantum mechanics model as a compilation step, enabling superposition-as-a-feature.
My futile attempts at humour aside, this is quite an interesting thing to know and exactly the kind of intricate little detail I was hoping for.
The Scientific type does arrive at the correct value. 0.3 is the correct answer, and Scientific gives it to you. I don't know why you would expect something else from a type which implements arbitrary precision arithmetic.
Its important to understand that 0.1 + 0.2 is actually 0.3, and Scientific is giving the correct answer.
The Haskell type annotations aren't casting values that are interpreted as binary floating point (as might be the case in some languages), it is instructing the compiler how to treat the literals. Scientific is arbitrary precision decimal, so it can exactly represent 0.1 and 0.2, and return the exact result 0.3, rather than representing 0.1 and 0.2 as binary floating point approximations, adding them, and then producing some decimal approximation of the binary floating point result when asked.
For those that arrive at the right answer, is it by mathematical correctness in the implementation or by rounding down?
i.e. Which are right and which are flukey in their wrongness?
Under any other circumstance I wouldn't care about this pointless detail, but seeing as how this is the top post on the front page, I'd like an excruciatingly detailed investigation please.
Don't make me not get round to doing it myself, sir.
If you want PHP to print it like the other languages you have to set the output precision high enough. The default, as you mentioned, is 14 but if you set it to 17 then you get the 'correct' output.
All of them may be correct as typically, multiple 'answers' can be correct. One could argue that given a number, one should print the shortest string that round-trips to that number, but that may mean that one prints "0.3" while the 'real' value is closer to 0.30000000000000004 or 0.29999999999999998 (a representation that one of the algorithms in the above paper gives) or possibly even equal to it.
Also, some of them may be incorrect for backwards compatibility reasons. In the eyes of some, that makes them correct again.
Floating point is (usually) about "closest representable value". That is, the normal floats form a finite subset of the real numbers, and a calculation like x + y will pick the closest element to the true result.
In this case, adding the closest floating point value to "0.1" (0x1999999999999a / 2^56) and the closest one to "0.2" (0x1999999999999a / 2^55) gives
(Rational numbers with a denominator that's a power of two have a finite decimal representation, and that's the full one for this number.)
However, when printing, one is either interested in a close-enough rounded value (e.g. like some languages print 0.3 by default, or how %.3f will explicitly limit to 3 digits), or an exact representation. The exact representation should be round-trippable, so when you read it back in, you get exactly the same value. In practice this means printing a float z as a decimal value such that the closest float to the exact decimal value (i.e. as a real number) is z. Obviously the full string above works because it is exact, but it is nice to be as short as possible. In this case, the floats immediately before and after our number are exactly
In some cases, string conversion is different, and the same calculation is going on, but the output is different.
In some cases, the internal representation isn't binary floating point at all, so the errors resulting from approximating an exact decimal with a binary float don't occur.
The Common Lisp version is slightly misleading because computations are made by default with single-float types, whereas there is also short-float, double-float and long-float.
default for READ-DEFAULT-FLOAT-FORMAT is implementation dependent and can be changed by user.
In CL type float has subtypes single-float, double-float, short-float, and long-float. "Any two of them must be either disjoint types or the same type; if the same type, then any other types between them in the above ordering must also be the same type. For example, if the type single-float and the type long-float are the same type, then the type double-float must be the same type also."
If there is only one float representation it has to be `(typep x 'single-float)` but if the internal representation is different (double-float for example) it can be all of the types. At least this is how I understand the spec.
Indeed. Note also that there are recommended minimum precisions and exponent sizes, which are followed in practice by CL implementations. That means that if double and long are the same type, the precision and size is at least the one recommended for long-float.
253 comments
[ 4.3 ms ] story [ 113 ms ] threadhttp://www.smbc-comics.com/?id=2999
So it seems SQL does not give access to the secret robot Internet...
Binary, decimal, trinary, or any other numbering system is no more accurate or "exact" than any other. They all have fractions that they cannot represent.
Technically, [digital] computers only natively "store" high and low voltages. The interpretation of a sequence of those signals as "integers" is entirely up to you.
In all seriousness, representing integers is not a given either (e.g. two's complement vs one's complement, BCD, bignum, sparse integers, etc.). If you are going down in abstraction levels to describe floating point representation, you should not just call integers "native" blindly.
Furthermore, floating point is not the only way to represent computation involving real values. It is indeed possible to represent computation on real values symbolically in many cases and lazily compute arbitrary precision results for output-printing purposes.
Here you can see python has a fractions.Fraction type which can be used for rational number arithmetic.
Here we see the floating point behaviour. Here we see that python has a nice behaviour for when printing floats. Here is a common error where people feed the input of Fraction (and Decimal) with a float. Even though you use the Fraction here it still carries the floating point error through. Here is the Decimal type which does not have this float problem. Some people have argued (including myself) that Decimal should be used by python instead of float. Since this is much friendlier to people doing things like adding these numbers together.Are you sure?
And then there's MLC NAND flash which stores bit sequences as different voltage levels within the same cell.
If I'm not mistaken, 0.3333... would be 0.1 and 0.6666... would be 0.2. It probably gets nasty for a lot of simple base 10 numbers, so it isn't a good solution.
also we don't have 5 year olds.
http://www.dec64.com/
Printing out is kind of a misleading check here, maybe a better idea would be to test equality with the constant 0.3. Of course the site is just a neat illustration and not a technical whitepaper.
[1] https://msdn.microsoft.com/en-us/library/dwhawy9k(v=vs.110).... and https://msdn.microsoft.com/en-us/library/3hfd35ad(v=vs.110)....
> Console.WriteLine((.1 + .2)-.3); > Result: 5.55111512312578E-17
Some languages may optionally use an exact representation (e.g., Scheme or Python), but that's not the general case.
https://docs.python.org/2/tutorial/floatingpoint.html#tut-fp...
Quote:
"In current versions, Python displays a value based on the shortest decimal fraction that rounds correctly back to the true binary value, resulting simply in ‘0.1’."
For instance, in Perl "print 0.1+0.2" will give you "0.3" just like in Python, while the printf format shown here will give you the non-rounded representation. And there are of-course decimal and rational number packages for Perl as well.
One of the cardinal rule of floating point in computing is that you never do direct comparison between values, whatever the language, so your test should never ever be used. That doesn't mean a language cannot be allowed to infer what the correct display of a floating point value should be.
Here's an example using perl5:
perl -e 'print 0.1+0.2' yields '0.3', which looks OK, however
perl -e 'print 0.1+0.2-0.3' reveals '5.55111512312578e-17'
So, it's better to print the result of 0.1+0.2-0.3
For what its worth, perl6 passes this test with flying colours.
Do we really expect calculations on floating point numbers to be the same as calcualtions with real numbers?
The only problem I see is that often the floating point format is not specified properly. When one writes "0.3", what does it actually mean? Does the format the compiler uses internally conform to IEEE 754? Is it 32bit, 64bit, 80bit or something else?
It's perfectly well-specified. If you are using double-precision floating point, "0.3" means 0x3fd3333333333333 (as bits), or 0.299999999999999988897769753748434595763683319091796875 (as an exact number: the closest representable number to 0.3).
But why should it do so? Do all languages specify the details of how floating point input is handled by the compiler/interpreter?
That said, a lot of low-level languages don't: C doesn't guarantee this, for example. C doesn't even mandate IEEE 754, and it merely requires that "float" is a subset of the values of "double" which is itself a subset of the values of "long double".
>There are three binary floating-point basic formats (encoded with 32, 64 or 128 bits) and two decimal floating-point basic formats (encoded with 64 or 128 bits)
It's very commonly used in finance, for example.
[0] : https://en.wikipedia.org/wiki/Binary-coded_decimal
One it so use fixed point decimal with a 1/100 scaling instead of floating point. So yes, integers and then you shift the decimal point when you output.
But you have to watch out for interest calculations, you might earn a fraction of a penny on a daily basis but over a year it adds up and you can't throw away that accuracy.
So you might do all math as floating point, but with pennies instead of dollars.
Or you can do Binary Coded Decimal, which stores each group of decimal number after the decimal point exactly, in many ways it similar to fixed point decimal, since it is a fixed point.
The issue with BCD would be data store support and CPU support right? Do CPUs support doing math directly with BCD values and does your DB support doing math directly with BCD values?
In any case, using floating point for any currency calculations is a huge no-no, even though a lot of things do it anyway.
I work with Magento daily and all their currency math uses PHP floats and the rounding errors drive me bonkers.
Perhaps surprisingly to some, x86 has instructions for BCD manipulation at the CPU level. Legacy.
https://books.google.ch/books?id=SPXHAgAAQBAJ&pg=PA44&lpg=PA...
Finance is a big domain.
I'm not sure, but I think it's not really about cutting off the digits (although that's the effect it has). At least with python, I think what happens is:
* repr gives you the decimal number with the exact value of the floating-point number, i.e. 0.30000000000000004
* print gives you the least-precise decimal number whose closest floating-point representation is equal to the floating-point number
That is, there are (infinitely) many decimal numbers such that the closest floating-point representation has the value 0.30000000000000004. One of these decimal numbers is 0.3, and of all such decimal numbers, this has the fewest digits. So that's the one that gets printed.
I now think the behiviour I ascribed to print, is actually what repr does. I'm not sure about print, but I guess it is just rounding to a certain number of places.
It's amazing that someone went to the trouble to register a custom domain for this and put up a nicely formatted page, yet doesn't explain the above: that it's not (just) a matter of representation, but printing precision.
If you'd like to flesh out the perl section a bit though, maybe include the differences between 5 and 6, I'd be happy to merge a pull request.
This is because Perl 6 decimal literals are stored in a built-in rational type called Rat, which internally stores numbers as ratios between integers. So that 0.1, 0.2, 0.3 are internally stored as the tuples (1,10), (2,10), and (3,10), and the decimal value you see is just the string representation and not the actual internal value.
If you want your decimal literal to be floating-point (called Num in Perl 6), you want to add e0 to the end.
To wit:
perl6 -e 'say 0.1+0.2-0.3' reveals '0'
perl6 -e 'say 0.1e0+0.2e0-0.3e0' reveals '5.55111512312578e-17'
So, Scheme?
It really ought to be fixed at the implementation level (how much stuff would it really break if floatin point errors went away?), but failing that I'd love a macro that did it for me. I can't figure out how to write one robustly.
What you really want, I think, is rationals by default, as in Perl 6.
a := .1; b := .2
fmt.Println(a+b) returns 0.30000000000000004
fmt.Println(.1+.2) returns 0.3
Even worse, this persists into comparisons:
c := .3
a+b == c returns false
.1+.2 == c returns true
It's not a particularly big issue, mostly, but I'm sure it's confused someone before now, and will do so again.
Demo code: http://play.golang.org/p/FOv0JQRQJN
https://blog.golang.org/constants
In most other cases the correct way is to check if the absolute value of the difference between one value and another is smaller than some arbitrary cut-off, a small number typically denoted with 'epsilon'.
The real problem is: most people don't have deep knowledge of how those details are implemented and take 'equality' for granted, especially if the visual representation of the numbers they are comparing tells them they should be equal which is not always the case.
The old adage goes: if you need floating point you don't understand your problem :)
The comment that sparked this sub-thread is a nice illustration of what can and does go wrong.
A Float will round, as expected.
A double will return the correct value as it, should.
Shouldn't the Scientific, if it has arbitrary precision, arrive at the correct value too?
Clearly the only logical conclusion is that the Glasgow compiler, at its roots, virtualizes the entire quantum mechanics model as a compilation step, enabling superposition-as-a-feature.
My futile attempts at humour aside, this is quite an interesting thing to know and exactly the kind of intricate little detail I was hoping for.
Tip of the hat, friend.
The Haskell type annotations aren't casting values that are interpreted as binary floating point (as might be the case in some languages), it is instructing the compiler how to treat the literals. Scientific is arbitrary precision decimal, so it can exactly represent 0.1 and 0.2, and return the exact result 0.3, rather than representing 0.1 and 0.2 as binary floating point approximations, adding them, and then producing some decimal approximation of the binary floating point result when asked.
For those that arrive at the right answer, is it by mathematical correctness in the implementation or by rounding down?
i.e. Which are right and which are flukey in their wrongness?
Under any other circumstance I wouldn't care about this pointless detail, but seeing as how this is the top post on the front page, I'd like an excruciatingly detailed investigation please.
Don't make me not get round to doing it myself, sir.
http://lxr.php.net/xref/PHP_5_4/Zend/zend_operators.c#2142
The "mathematically" correct answer is 0.30000000000000004 according to the IEEE-754 spec.
https://3v4l.org/TRcJB
http://php.net/manual/en/ini.core.php#ini.precision
All of them may be correct as typically, multiple 'answers' can be correct. One could argue that given a number, one should print the shortest string that round-trips to that number, but that may mean that one prints "0.3" while the 'real' value is closer to 0.30000000000000004 or 0.29999999999999998 (a representation that one of the algorithms in the above paper gives) or possibly even equal to it.
Also, some of them may be incorrect for backwards compatibility reasons. In the eyes of some, that makes them correct again.
And don't get round to not doing it yourself :-)
It helped me a lot when started learning.
Not that other spreadsheets (LibreOffice, Apple's Numbers) are better: They also use binary floating-point data types instead of a decimal one.
In this case, adding the closest floating point value to "0.1" (0x1999999999999a / 2^56) and the closest one to "0.2" (0x1999999999999a / 2^55) gives
which is exactly (Rational numbers with a denominator that's a power of two have a finite decimal representation, and that's the full one for this number.)However, when printing, one is either interested in a close-enough rounded value (e.g. like some languages print 0.3 by default, or how %.3f will explicitly limit to 3 digits), or an exact representation. The exact representation should be round-trippable, so when you read it back in, you get exactly the same value. In practice this means printing a float z as a decimal value such that the closest float to the exact decimal value (i.e. as a real number) is z. Obviously the full string above works because it is exact, but it is nice to be as short as possible. In this case, the floats immediately before and after our number are exactly
So, only printing up to the first 4 is enough to uniquely identify our float: it is the closest one.The 0.2999* float is slightly interesting: it is the closest float to 0.3, and most environments will print "0.3" in exact mode.
There's a lot of trickery/research around printing[1] and operating on floats: rounding things correctly can be highly non-trivial[2].
[1]: e.g. http://www.cs.indiana.edu/~dyb/pubs/FP-Printing-PLDI96.pdf
[2]: https://en.wikipedia.org/wiki/Rounding#Table-maker.27s_dilem...
Are you telling me they implement their own version of the IEEE float standard? Surely that way madness lies.
In some cases, the internal representation isn't binary floating point at all, so the errors resulting from approximating an exact decimal with a binary float don't occur.
In CL type float has subtypes single-float, double-float, short-float, and long-float. "Any two of them must be either disjoint types or the same type; if the same type, then any other types between them in the above ordering must also be the same type. For example, if the type single-float and the type long-float are the same type, then the type double-float must be the same type also."
If there is only one float representation it has to be `(typep x 'single-float)` but if the internal representation is different (double-float for example) it can be all of the types. At least this is how I understand the spec.
http://clhs.lisp.se/Body/v_rd_def.htm#STread-default-float-f...
http://clhs.lisp.se/Body/t_float.htm#float
http://clhs.lisp.se/Body/t_short_.htm
https://www.youtube.com/watch?v=k12BJGSc2Nc