1

I have a very strange issue using the Javascript remainder (or Modulus) operator.

I have a requirement to get the entire width of a board (excluding margins) and then make sure the setWidth value fits directly into the area left.

This means that in the example below the remainder when area is divided by setWidth the result should be 0.

Javascript Code :

var totalWidth = parseFloat('519');
var setWidth = parseFloat('101.6');
var leftMargin = parseFloat('11');
var rightMargin = parseFloat('0');

var area = (totalWidth - leftMargin) - rightMargin;    
console.log('area : ' + area);
//Incorrect Value given...
var modVal = area % setWidth;
console.log('modVal : ' + modVal);
//Correct value of 5...
var divisionVal = area / setWidth;
console.log('divisionVal : ' + divisionVal);

The reason I am parsing the values from strings is because they are actually retrieved from textboxes on the page.

In my Example JSFiddle I have two different examples, one works as I expect, but the other does not. The only difference is the numbers.

In my example above the values should be as follows :

area = (519 - 11) - 0; //Should be 508 (and is)
modVal = 508 % 101.6; //Should be 0 (But isn't for some unknown reason)
divisionVal = 508 / 101.6; //Should be 5 (and is)

If anyone can explain to me why one of my examples works and the other doesn't then I'd be happy to hear it. But at the moment I just cannot understand why this doesn't work...

Any ideas?

Nunners
  • 3,047
  • 13
  • 17

2 Answers2

3

modVal gives 2.842170943040401e-14 here, which is 0.00000000000002842170943040401 which is about as close to 0 as you're gonna get with floating point.

Floating point arithmetic can be strange or hard to deal with. Make sure you're well informed.

Halcyon
  • 57,230
  • 10
  • 89
  • 128
  • Any suggestions on a way to handle this? I can't get around using decimal values. – Nunners Oct 30 '13 at 17:19
  • How do you want it handled? If you know the precision you can multiply by `10*n` and do integer arithmetic. You can also change comparison with zero to `-e < result < e` where `e` is a very small number. – Halcyon Oct 30 '13 at 17:24
  • Thanks for your help, I'll probably use the integer arithmetic option, I don't think our precision requirement will be too difficult with this. – Nunners Oct 30 '13 at 17:44
0

Floating-point % in JavaScript is pretty bizarre:

In the remaining cases, where neither an infinity, nor a zero, nor NaN is involved, the floating-point remainder r from a dividend n and a divisor d is defined by the mathematical relation r = n − (d × q) where q is an integer that is negative only if n/d is negative and positive only if n/d is positive, and whose magnitude is as large as possible without exceeding the magnitude of the true mathematical quotient of n and d. r is computed and rounded to the nearest representable value using IEEE 754 round-to-nearest mode.

So here, 519 / 101.6 is a little over 5 (it's between 5 and 6). Thus, the integer "q" in this case is 5, and 101.6 * 5 is 508 (almost). The result of the subtraction is 11.000000000000028.

Pointy
  • 405,095
  • 59
  • 585
  • 614
  • So if we swap this to be 508 / 101.6 = 5. Why exactly does 508 % 101.6 come out as a 0.00... value? And if that is by design is there a reasonable way to handle this? – Nunners Oct 30 '13 at 17:18
  • @Nunners well the remainder after dividing 508 by 101.6 is (almost) zero. The paragraph I quoted is from the spec, so yes it's by design. What you get from the `%` with floating-point numbers is the remainder after an *integer* division. – Pointy Oct 30 '13 at 20:52