#include
#include
int main() {
std::cout 0.30000000000000004
121–130 of 140 posts
Re: 0.30000000000000004
#122Earlier quoted context omitted.
That particular example happens to work, but 1/7 + 1/7 != 2/7. DecFP is not magic. You still need to know that you're dealing with limited precision numbers under the hood.
You are right, that example doesn't work. I thought the rounding and normalization described in the standard may fix all these cases by itself but there I was wrong. But at least all problems that could happen on a financial application are solved with decimal floating points (where you will only want to use rationals in finite decimal form like 0.01) And even your example can be made working pretty easily: #include…
You still get cancellation if the magnitudes differ by large enough an amount. This is a problem inherent to floating point arithmetic, using a decimal format instead of binary does not save you from that.
Re: 0.30000000000000004
#123 float foo = 0.3; // warning: invalid binary float value
float bar = 0.3f; // ok, converts into nearest bin float
decimal qux = 0.3m; // ok
decimal feh = 0.3; // why not; will be exactly 0.3
All in all, languages go for decimal floats by default but then the implicit conversions ruin it for everybody who's still learning.Re: 0.30000000000000004
#124It's actually pretty simple. When you have a base 10 system (like ours), it can only express fractions that use a prime factor of the base. In a way, not so simple (obvious to you? not to me)
"Moving the decimal point divides by 10. You can ONLY make fractions of 10 via the decimal point."
That plus a couple examples should do fine.
No need to mention prime numbers. No need to use variables.
Re: 0.30000000000000004
#125PS. It says: Console.WriteLine("{0:R}", .1 + .2);
But when you do .1 + .2 it is 0.3 :) . With the 0:R he actually converts it to double which give the false result
Re: 0.30000000000000004
#126Here's something that would probably help lessen the confusion: don't allow or atleast warn about implicit conversions in binary floats in source code literals. float foo = 0.3; // warning: invalid binary float value float bar = 0.3f; // ok, converts into nearest bin float decimal qux = 0.3m; // ok decimal feh = 0.3; // why not; will be exactly 0.3 All in all, languages go for decimal floats by default but then the i…
Re: 0.30000000000000004
#127Earlier quoted context omitted.
Yeah, it's unfortunately not the fastest algorithm known, despite what was originally thought, but it is still the fastest accurate one.
Grisu isn't accurate?
Grisu is accurate, but not always optimal. However, it figures out when that happens and lets you bail out to a slower algorithm when that happens. If you want full speed you should use Grisu, and then use Errol as a bailout.
A bit more context: there are 3 important properties when printing floating-point numbers.
- accurateness: you want the printed number to read back to the same number.
- shortness: often you want the shortest decimal representation: "0.3" and not "0.2999999999999999889". The latter is more precise, but reads back to the same number as "0.3".
- closeness: given two decimal representations of the same length, you prefer the one that is closer to the actual number.
I call the combination of these three properties "optimal".
Note that shortness and closeness are not always crucial. For example, a json-encoder could easily drop those, if the encoding is faster without them. Also, some languages drop shortness in favor of printing something closer to the input.
Grisu always produces accurate results. However, it sometimes can't tell if it already has the shortest and closest number. However (by being conservative) it can tell the user when that happens. In that case, one can fall back to another complete algorithm.
The double-conversion library (http://github.com/google/double-conversion) does exactly that. It uses the slower bignum algorithm in these cases.
Re: 0.30000000000000004
#128Once I wrote a library for double-to-string conversion and vice versa, which handles such roundings nicely: https://github.com/mkupchik/dconvstr Key idea is not just to map binary floating point value X to a decimal floating point value Y, but instead (in extended precision, with 64-bit mantissa) compute an interval of decimal floating point values [Y1, Y2] which maps back to X (in standard precision, with 53-bit man…
The state-of-the-art is the Errol algorithm of Adrysco, Jhala and Lerner (2016), which is proven to be always correct: https://cseweb.ucsd.edu/~lerner/papers/fp-printing-popl16.pd...
Grisu is also proven to be always correct. As mentioned in another comment: you have to define "correct". Grisu is always accurate, but may bail out if you need the shortest or closest result.
Basically: Grisu will always print a number that reads back to the input. However, it may not be able to print the shortest or closest number (when two decimal outputs have the same shortest length). In that case, it knows this, though, and can tell the user.
I would say that the combination of Grisu and Errol is currently the state of the art.
Errol is not the fastest, nor is it (afaik) proven to always return the closest result.
However, combining Grisu with Errol (as fallback) would probably yield the fastest complete algorithm.
Re: 0.30000000000000004
#129Once I wrote a library for double-to-string conversion and vice versa, which handles such roundings nicely: https://github.com/mkupchik/dconvstr Key idea is not just to map binary floating point value X to a decimal floating point value Y, but instead (in extended precision, with 64-bit mantissa) compute an interval of decimal floating point values [Y1, Y2] which maps back to X (in standard precision, with 53-bit man…
That's basically how Gay's dtoa works, and you'll find it copied into many projects—Python, for example, uses it for repr(). http://www.netlib.org/fp/dtoa.c
It's based on http://florian.loitsch.com/publications/dtoa-pldi2010.pdf
I'm obviously biased, but I think the API is easier, and the algorithm is faster.
However, it's in C++ (which might not suit your needs), and it requires more code (especially with the precomputed constants).
Re: 0.30000000000000004
#130Earlier quoted context omitted.
> Imagine a contract which says the contract partner receives e.g. 0.001% of the total revenue for the fiscal year (which could be 10bn Euros) I'm imagining it, and I don't see why storage or computation time would be major obstacles to a calculation you run once a year. Use whatever big integers you want? Suppose we dedicated one $100 hard drive (per year!) to storing all the relevant data. I feel like there would b…
But which advantage would this have over using IEEE 754-2008 decimal floating point numbers?