I need to determine if a floating point number is a multiple of another floating point number using JavaScript.
I’ve read some other questions about floating point numbers and I’ve learned that they don’t work correctly with the modulo operator (%). I’ve also read that you can convert the floating point numbers to integers by multiplying by 10/100/1000, etc, but this doesn’t work correctly in all cases.
Example:
var A = 25.13;
var B = .0001;
var Value = A*1e5;
var Step = B*1e5;
// Is Value a multiple of Step?
if(0 === (Value % Step)) {
// Do something
}
In this case, Value is a multiple of Step and it works correctly. But what about:
var A = 2.2;
var B = .0001;
It should be a valid multiple, but instead we get:
220000.00000000003 % 10 = 2.9103830456733704e-11
There’s an erroneous 3 in the 11th decimal position. I thought I could correct the problem with rounding with toFixed(), by doing:
var Value = (A*1e5).toFixed(10);
var Step = (B*1e5).toFixed(10);
But if you do:
var A = 45436212356482;
var B = .0001;
You get:
4543621235648200192.0000000000 % 10.0000000000=2
It’s a valid multiple, but it thinks it isn’t.
With:
var A = 45436212546522156.45621565421;
var B = .0001;
This is not a valid multiple, but it thinks it is:
4.543621254652216e+21 % 10.0000000000=0
Is there a clever trick for determining if one floating point is a multiple of another? Or is this impossible?
UPDATE:
The goal is to restrict a number entered by a user (either integer or decimal) to certain increments.
- If the Increment is 1, the user can enter 1,2,3,4,etc.
- If the Increment is .5, the user can enter .5,1,1.5,2,2.5, etc.
- If the Increment is .0002, the user can enter 1,1.001,1.0004,1.0006, but not 1.0001
From a logic perspective, a given value is or is not a valid multiple of a given increment.
Given your last two examples, with 4543621235648200192 and such, it seems you want to accept numbers that are integer multiples of .0001 and reject those that are not and you want to do this not using .0001 but using a variable that contains the floating-point value nearest .0001.
In general, that is impossible. There is no way for an algorithm to “know” that .0001 was intended when you pass it something else.
If you restrict the problem more, a solution might be possible. For example, it is possible (perhaps not easy) to answer this question: Is the floating-point value X the floating-point value nearest to an integer multiple of .0001? (In other words, is there an integer k such that multiplying .0001 by k and rounding to the nearest floating-point value produces exactly X?)
So, to get a solution, you need to describe your goal further. Do you want solutions for arbitrary values of Step or just certain values? Since binary floating-point cannot represent Step precisely enough, do you have some other way to describe it? E.g., will it always be a multiple of .0001? Is the Value you want to accept as a multiple always the binary floating-point number nearest an exact mathematical multiple, or might it have additional errors?