Forum Moderators: open
var tot = Number(g1.value) + Number(g2.value) + Number(g3.value);
Everything is wonderful, except when g1.value = 4.8 and g2.value = 7.6 (or the reverse).
The result is 12.39, not 12.4
Any other decimal works correctly, and if I add any value in g3 > 0 it works correctly.
What's up with that? I checked it in various places and it's always those pairs of floats.
Weren't those numbers engraved on the Hatch?
The binary floating-point format used by most computers can not "exactly" represent "simple" base-10 numbers i.e. 0.1 ... 0.9.
Floating-point arithmetic only creates the illusion of an infinity of real numbers into/within/out-from a machine that can only work with a finite set of numbers, i.e. IEEE 754 standard double precision (2^53).
* Therefore, just inputting such numbers can cause rounding errors.
* In calculations floating-point results used directly in subsequent operation(s) can actually cause error accummulation. Branching statements, i.e. if - then, are especially prone to significant error.
* Care must also be used in the use of equations as there is a loss of basic arithmetic properties with floating-point operations:
(0.1 + 0.2) + 0.3 is not equal to 0.1 + (0.2 + 0.3).
Change the order and the result changes (not usually much but no longer equal).
That is why, for example, different browsers can appear to render different <div> or page widths - they processed the floating-point numbers in a different order and got differing results.
Many accurracy critical operations require specific rounding on each input and on each result prior to subsequent calculation(s).
The input sequence is (almost) as important as the input values.
Basically the way Javascript handles floating point numbers is system dependent: it depends on the processor running the JS. The only way I've found around this with any reliability is to do some goofy hoop-jumping by multiplying everything X 100 within an int function then dividing by 100 when you're done, as in:
subtotal = int((q.value*(p.value * 100))+(ship.value * 100));
total += subtotal;
subtotal = subtotal/100;
total = total/100;
...where q is an integer quantity and p, ship are assumed to be decimal values. Follows is often a routine to chop off excess decimal places as well.
Granted this is a workaround, but have searched long and hard on this one and the consensus seems to be that those who are well versed in programming know what the problem is, just very few solid solutions are offered. Hopefully someone will chime in, or this one goes on my list of questions only to be answered when I pass into the nether. :-)
those who are well versed in programming know what the problem is
I don't really belong in that group. It happens because a number that can be precisely finitely represented in one base cannot necessarily in another, without reference to fractions.
[blue]0.1[/blue] in base [red]3[/red] = 1*3-1
= 1/3
= 0.3333333..etc
..so it has no finite decimal representation.
We, of course, are dealing with conversions to a from decimal to binary, and precision can be lost, I suppose, in either direction.
I can't be relied upon for a foolproof solution though. My mind boggles too, and I haven't done enough reading. Some language have classes like
Rational to deal with this kind of thing, which store numbers as arrays of integers. It would probably be overkill for us to build our own JS-version. the way Javascript handles floating point numbers is system dependent
This shouldn't be the case, since (as iamlost says) JS numbers should all be kept according to the IEEE standard. But if you have experienced otherwise I certainly won't argue against it.
I think, when it comes to currency input¦output, then multiplying by 100 may not be such a bad idea. It needn't be so goofy, you could just consider that you are working in cents¦pence¦öre¦ringgit (after rounding to the nearest). Convert back to Dollars etc for output.
Working with money gets us off the hook a little, because we at least know the level of precision required. Internal rounding errors will always be far smaller than need be worried about if working in cents.
I don't know a general solution to the initial problem though - in the case of a plain number calculator, for eg.
The Last Word on this kind of thing is, perhaps, Dr John Stockton. It's all here:
[merlyn.demon.co.uk...]
>> [merlyn.demon.co.uk...]
[merlyn.demon.co.uk...]
..but you might have made it to nether before you have time to digest it all.
Stockton makes for more heavy reading, bookmark +3. :-)
My problems with this come and go, and picked up the system-dependent comment from a very good explanation I read once (which of course, is long lost now.) Perhaps there was no truth to it, but it sure **seemed** the editor knew what they were talking about.
I also had a programmer friend explain this abberation to me (which has been called a "feature" in many documents,) and have been to many documents involving floating point precision. Most of them boggle the mind and barely hang on the edge of my understanding. :-)
The problem is the largest use of Javascript never requires anything beyond the second digit, yet the floating point precision to the nth decimal place reaches out to stick it's finger in our two-digit-after pies. An example I found this AM (link excluded for tos so just quoting here:)
The script is supposed to just take the calendar price ($24.88)
multiply it by the number of calendars ordered and then add
shipping. Since calendars are only ordered in round numbers and
shipping is only 2 decimals, there should never be more than 2
decimal places and I'm stumped as to why it's giving me a
$29.2299 instead of $29.23.
Floating point precision strikes again. We know the "why", just what ta' do about it! :-)
If I could ask one thing of Javascript, it would be
myNum = parseDigits((q*price),2);
Similar to perl's sprintf, although sprintf produces a string, perl easly interprets it as a number.