-1

Consider this javascript that rounds to the nearest tenth, then totals the numbers together.

var log = function(key, value) {
  var li = document.createElement("li");
  li.appendChild(document.createTextNode(key + " = " + value)); 
  document.getElementById("results").appendChild(li); 
  };

var number1 = Math.round(10*33.333)/10; // gives 33.3
var number2 = Math.round(10*33.333)/10; // gives 33.3
var number3 = Math.round(10*33.333)/10; // gives 33.3

var totalOfAllNumbers = number1 + number2 + number3; //gives 99.89999999999999?

var totalOfAllRealNumbers = 33.3 + 33.3 + 33.3; //gives 99.9?

log("number1", number1);
log("number2", number2);
log("number3", number3);
log("totalOfAllNumbers", totalOfAllNumbers);
<ul id="results"></ul>

The numbers appear to be rounded, but the total doesn't add up to 99.9? Why?

What is the difference between the number entered as 33.3 manually, and the result of a division? Are they different types?

simbolo
  • 7,279
  • 6
  • 56
  • 96
  • strange is if i try to add `number1+number2`, it gives 66.6!.. – Rakesh_Kumar Jan 27 '15 at 02:39
  • Yeh weird huh, only goes wrong adding any 3rd result. The linked answer also doesn't mention a solution, or indicate why the numbers being output don't appear to be floating numbers. I.e. what is the difference between `33.3` typed manually and the `33.3` calculated by the number1 formula. – simbolo Jan 27 '15 at 02:43
  • Floating point math is based on a binary fraction system, not a base 10 fraction system. Values that are simple fractions in decimal notation, like `0.3`, are **repeating** fractions in binary notation. – Pointy Jan 27 '15 at 02:44
  • I guess what I am asking @Pointy is why is a hard-coded 33.3 treated different from the 33.3 generated from a division? – simbolo Jan 27 '15 at 02:57
  • You really need to use a tool that lets you see what the underlying binary representations are. The problem lies in round-off errors that simply happen as part of the operations of turning the decimal expression `33.3` or any numbers, and subsequent division operations. – Pointy Jan 27 '15 at 03:05
  • Even converting the result of a division to a string then back to an integer doesn't seem to work either. Stuck with using JavaScript only. It's very strange, – simbolo Jan 27 '15 at 03:08

1 Answers1

0

I hate to give a flippant response, but it gives that rounding error number "because JavaScript".

A slightly less flippant answer is that the engine tries to guess (as described by ECMA spec) the type at each step of the addition and somewhere in the type guessing algorithm, it guesses it's a double instead of a float (or vice versa) and that's when you see this type of precision loss. If numerical accuracy are critical to you, I suggest using a different programming language with saner and more predictable number types.

Edit:

For example consider python 2.7:

>>> a = round(10*33.333, 2)/10
>>> b = round(10*33.333, 2)/10
>>> c = round(10*33.333, 2)/10
>>> a + b + c
99.999

Or ruby:

2.1.2 :001 > a = (10*33.333).round(2)/10
 => 33.333
2.1.2 :002 > b = (10*33.333).round(2)/10
 => 33.333
2.1.2 :003 > c = (10*33.333).round(2)/10
 => 33.333
2.1.2 :004 > a + b + c
 => 99.999
rdodev
  • 3,164
  • 3
  • 26
  • 34
  • 1
    It's not **JavaScript**, it's binary floating-point math. – Pointy Jan 27 '15 at 03:03
  • "*[because] the engine tries to guess the type*". Not even close, [*Type*](http://ecma-international.org/ecma-262/5.1/#sec-8) is irrelevant. "The engine" does exactly what IEE 754 says it should do, otherwise it isn't compliant with ECMA-262. – RobG Jan 27 '15 at 03:46
  • The same wonderful spec that allows for type coercion and goofy stuff like '2' + 2 = '22' and '22' - 0 = 22. – rdodev Jan 27 '15 at 12:43
  • @Pointy it absolutely is floating point math, what I'm positing that JS is not very good at it. Try the same math in, say, python or ruby and you'll get the _expected_ result. – rdodev Jan 27 '15 at 12:55
  • @rodev JavaScript uses IEEE 754 math, and it's not any worse at that than any other language (or hardware implementation). – Pointy Jan 27 '15 at 15:10
  • see examples provided above @pointy – rdodev Jan 27 '15 at 19:11
  • @rdodev type `3*Math.round(10*33.333 * 100)/1000` into your browser console and you'll get the same answer. – Pointy Jan 27 '15 at 20:35
  • @poity but that's not the problem at all. You are restating the problem. When adding the three intermediate results is when it trips. In fact JS can't even do integer math very good. – rdodev Jan 28 '15 at 00:20