checking decimal floating point number - javascript

Normally we expect 0.1+0.2===0.3 to be true. But it is not what javascript will result. As javascript displays decimal floating point number but stores binary floating point number internally. So this returns false.
If we use chrome developer tool console, we'll get the following result:
0.1+0.2;//0.30000000000000004
0.1+1-1;//0.10000000000000009
0.1 + 0.2 === 0.3 ;// returns false but we expect to be true.
0.1+1-1===0.1;//returns false
Due to rounding errors, as a best practice we should not compare non-integers directly. Instead, take an upper bound for rounding errors into consideration. Such an upper bound is called a machine epsilon.
And here is the epsilon method:
var eps = Math.pow(2,-53);
function checkEq(x,y){
return Math.abs(x - y) < eps;
}
Now, if we check it returns true.
checkEq(0.1+0.2,0.3);// returns true
checkEq(0.1+1-1,0.1);//returns true
It's okay and fine. But if I check this:
checkEq(0.3+0.6,0.9);// returns false
Which is not okay and not as what we expect.
So, how should we do to return the correct results?
What I've tried to solve this is like this:
var lx,ly,lxi,lyi;
function isFloating(x){
return x.toString().indexOf('.');
}
function checkEq(x,y){
lxi = x.toString().length - x.toString().indexOf('.') - 1;
lyi = y.toString().length - y.toString().indexOf('.') - 1;
lx = isFloating(x) > -1 ? lxi : 0;
ly = isFloating(y) > -1 ? lyi : 0;
return x.toFixed(lx) - y.toFixed(ly)===0;
}
Now, fixed. And it results fine if I check like this:
checkEq(0.3,0.3); //returns true
But the following returns false
checkEq(0.3+0.6,0.9)
As here first it's value is stored in binaray floating point number and then returning decimal floating point number after calculating.
So now, how can I set toFixed() method for each input like in checkEq(0.3+0.6,0.9) 0.3.toFixed(lx) and 0.6.toFixed(lx) and then only add:
var lx,ly,lxi,lyi;
function isFloating(x){
return x.toString().indexOf('.');
}
function checkEq(x,y){
x = x.toString().split(/\+ | \- | \/ | \ | \\ */);
y = x.toString().split(/\+ | \- | \/ | \ | \\*/);
for(var i=0;i<x.length,y.length;i++){
//here too I may be wrong...
lxi = x[i].toString().length - x[i].toString().indexOf('.') - 1;
lyi = y[i].toString().length - y[i].toString().indexOf('.') - 1;
// particularly after this would wrong...
lx = isFloating(x[i]) > -1 ? lxi : 0;
ly = isFloating(y[i]) > -1 ? lyi : 0;
//And, here I'm stucked too badly...
//take splitted operators to calculate:
//Ex- '0.3 + 1 - 1'
// Number('0.3').toFixed(1) + Number('1').toFixed(0) - Number('1').toFixed(0)
//But careful, we may not know how many input will be there....
}
//return x.toFixed(lx) - y.toFixed(ly)===0;
}
Other answers are also welcome but helping me with my code is greatly appreciated.

Perhaps you should try out some existing JS Math library such as bignumber.js, which supports arbitrary-precision arithmetic. Implementing everything from scratch will be rather time consuming and tedious.
Example
0.3+0.6 //0.8999999999999999
x = new BigNumber('0.3') // "0.3"
y = new BigNumber('0.6') // "0.6"
z = new BigNumber('0.9') // "0.9"
z.equals(x.plus(y)) // true

I think you should take a little larger value for epsilon.
You can also have a look at math.js: the comparison functions of math.js also check for near equality. Comparison is explained here:
http://mathjs.org/docs/datatypes/numbers.html#comparison
So you can do:
math.equal(0.1 + 0.2, 0.3); // true
math.equal(0.3 + 0.6, 0.9); // true
even better, math.js has support for bignumbers (see docs), so you can do:
math.equal(math.bignumber(0.1) + math.bignumber(0.2), math.bignumber(0.3);
or using the expression parser:
math.config({number: 'bignumber'});
math.eval('0.1 + 0.2'); // returns BigNumber 0.3, not 0.30000000000000004
math.eval('0.1 + 0.2 == 0.3'); // returns true

Discontinuous functions such as equality (but also floor and ceil) are badly affected by rounding errors, and taking an epsilon into account may work in some cases, but may also give an incorrect answer (e.g. abs(x-y) < eps may return true while the exact value of x and y are really different); you should do an error analysis to make sure that it is OK. There is no general way to solve the problem in floating point: this depends on your application. If your inputs are decimal numbers and you just use addition, subtraction and multiplication, a decimal floating-point arithmetic may be OK if the precision is large enough so that all your data can be represented exactly. You can also use a rational arithmetic, such as big-rational (not tried).

Related

Is it possible to generate an integer by using Math.random()*80 in JavaScript?

I know even if it can, the probability would be really small but is it theoretically possible?
According to the ECMAScript standard, there is only one number type: the double-precision 64-bit binary format IEEE 754 value (number between -(253 -1) and 253 -1). There is no specific type for integers.
So, are there any IEEE 754 numbers that become integer when multiplied by 80?
80 = 2*2*2*2*5. Since the value is stored using binary fractions, the numbers n/16, where n is in the range [1-15] can all be represented exactly. They also become an integer when multiplied by 80.
So there are at least 15 different values that will result in an integer when multiplied by 80.
Can the random number generator actually produce any of these values? I cannot say. That would depend on the javascript implementation.
... ? Yes :
You want an integer between 0 and 80 ?
var my_integer = parseInt (""+ 80 * Math.random());
EDIT You can also round it (floor,ceil) down & up:
Floor does, e.g. : 76,8=>76
var my_integer = Math.floor( parseInt (""+ 80 * Math.floor()));
Ceil does, e.g. : 76,8=>77
var my_integer = Math.ceil(parseInt (""+ 80 * Math.ceil()));
Yes it's possible. From node console:
> for(var i = 0; i < 1000000000; i++) {
... var rn = Math.random() * 80
... if(rn == Math.round(rn)) {
..... console.log('success')
..... break
..... }
... }
success
undefined
>

How can I check that a bit is set (without bitwise operation)?

Looking at the int 44 — I need Math.CEIL (log(2) 44) of binary places to represent 44.
(answer is 6 places)
6 places :
___ ___ ___ ___ ___ ___
32 16 8 4 2 1
But how can I check that (for example) the bit of 8 is checked or not ?
A simple solution will be do to :
((1<<3) & 44)>0 so this will check if the bit is set.
But please notice that behind the scenes the computer translates 44 to its binary representation and just check if bit is set via bitwise operation.
Another solution is just to build the binary myself via toString(2) or mod%2 in a loop
Question
Mathematically Via which formula, I can test if n'th bit is set ?
(I would prefer a non loop operation but pure single math phrase)
Divide by the value of the bit that you want to check
and test if the first bit is set (this can be tested with x mod 2 == 1)
Math expression:
floor(value/(2^bitPos)) mod 2 = 1
As JS function:
function isSet(value, bitPos) {
var result = Math.floor(value / Math.pow(2, bitPos)) % 2;
return result == 1;
}
Note: bitPos starts with 0 (bit representing the nr 1)
The 'bit' (actually any base) value of an indexed number index in a value val in base base can in general be calculated as
val = 1966;
index = 2;
base = 10;
alert (Math.floor(val/Math.pow(base,index)) % base);
result: 9
val = 44;
index = 3;
base = 2;
alert (Math.floor(val/Math.pow(base,index)) % base);
result: 1 (only 0 and 1 are possible here – the range will always be 0..base-1).
The combination of Math.floor (to coerce to an integer in Javascript) and Math.pow is kind of iffy here. Even in integer range, Math.pow may generate a floating point number slightly below the expected 'whole' number. Perhaps it is safer to always add a small constant:
alert (Math.floor(0.1+val/Math.pow(base,index)) % base);
You can simply check if the bit at the position is set to 1.
function isBitSet(no, index) {
var bin = no.toString(2);
// Convert to Binary
index = bin.length - index;
// Reverse the index, start from right to left
return bin[index] == 1;
}
isBitSet(44, 2); // Check if second bit is set from left
DEMO

Simple movement calculation gives wrong result

I have this function.
Calculations.add(this, //CONTEXT
function () { //CALUCATE
this.position.x += (this.movementSpeed.x / 10);
},
function () { //HAVE CALCULATED
return (this.position.x === (tempX + this.movementSpeed.x));
}
);
I have run the result, but sometime the result is wrong. Cause I know that if it calculate 10 times, then the the HAVE CALCULATED whould be true.
But sometimes it never is... And that kills my app.
Let us say that the result should give 138, then after the calculation it give me 138.000000000006 which is not 138 and the HAVE CALCULATED is false..
How can I manage this= I can't use round, because it should be able to return 138.5, if the end-result is that.
Hope you understand my question.
Always floating point = comparisons should be done like this:
Math.abs( a - b ) < 1e-6
where 1e-6 is an arbitrary error threshold that you determine in advance
You should never compare floating point values this way. (The link from Waleed Khan in the comments gives a good explanation why this happens)
Instead you can do something like this to check equality of a and b:
if (a < b + 0.0001 && a > b - 0.0001) {
// values are "equal"
}
You could round to a certain number of digits, from another answer on SO use something like this:
function roundNumber(n, digits) {
var multiple = Math.pow(10, digits);
return Math.round(n * multiple) / multiple;;
}
This way you do not require fancy comparisons.

How do I convert an integer to a float in JavaScript?

I've got an integer (e.g. 12), and I want to convert it to a floating point number, with a specified number of decimal places.
Draft
function intToFloat(num, decimal) { [code goes here] }
intToFloat(12, 1) // returns 12.0
intToFloat(12, 2) // returns 12.00
// and so on…
What you have is already a floating point number, they're all 64-bit floating point numbers in JavaScript.
To get decimal places when rendering it (as a string, for output), use .toFixed(), like this:
function intToFloat(num, decPlaces) { return num.toFixed(decPlaces); }
You can test it out here (though I'd rename the function, given it's not an accurate description).
toFixed(x) isn't crossed browser solution.
Full solution is following:
function intToFloat(num, decPlaces) { return num + '.' + Array(decPlaces + 1).join('0'); }
If you don't need (or not sure about) fixed number of decimal places, you can just use
xAsString = (Number.isInteger(x)) ? (x + ".0") : (x.toString());
This is relevant in those contexts like, you have an x as 7.0 but x.toString() will give you "7" and you need the string as "7.0". If the x happens to be a float value like say 7.1 or 7.233 then the string should also be "7.1" or "7.233" respectively.
Without using Number.isInteger() :
xAsString = (x % 1 === 0) ? (x + ".0") : (x.toString());

Javascript: Comparing two float values [duplicate]

This question already has answers here:
Javascript float comparison
(2 answers)
Closed 6 months ago.
I have this JavaScript function:
Contrl.prototype.EvaluateStatement = function(acVal, cfVal) {
var cv = parseFloat(cfVal).toFixed(2);
var av = parseFloat(acVal).toFixed(2);
if( av < cv) // do some thing
}
When i compare float numbers av=7.00 and cv=12.00 the result of 7.00<12.00 is false!
Any ideas why?
toFixed returns a string, and you are comparing the two resulting strings. Lexically, the 1 in 12 comes before the 7 so 12 < 7.
I guess you want to compare something like:
(Math.round(parseFloat(acVal)*100)/100)
which rounds to two decimals
Compare float numbers with precision:
var precision = 0.001;
if (Math.abs(n1 - n2) <= precision) {
// equal
}
else {
// not equal
}
UPD:
Or, if one of the numbers is precise, compare precision with the relative error
var absoluteError = (Math.abs(nApprox - nExact)),
relativeError = absoluteError / nExact;
return (relativeError <= precision);
The Math.fround() function returns the nearest 32-bit single precision float representation of a Number.
And therefore is one of the best choices to compare 2 floats.
if (Math.fround(1.5) < Math.fround(1.6)) {
console.log('yes')
} else {
console.log('no')
}
>>> yes
// More examples:
console.log(Math.fround(0.9) < Math.fround(1)); >>> true
console.log(Math.fround(1.5) < Math.fround(1.6)); >>> true
console.log(Math.fround(0.005) < Math.fround(0.00006)); >>> false
console.log(Math.fround(0.00000000009) < Math.fround(0.0000000000000009)); >>> false
Comparing floats using short notation, also accepts floats as strings and integers:
var floatOne = 2, floatTwo = '1.456';
Math.floor(floatOne*100) > Math.floor(floatTwo*100)
(!) Note: Comparison happens using integers. What actually happens behind the scenes: 200 > 145
Extend 100 with zero's for more decimal precision. For example use 1000 for 3 decimals precision.
Test:
var floatOne = 2, floatTwo = '1.456';
console.log(Math.floor(floatOne*100), '>', Math.floor(floatTwo*100), '=', Math.floor(floatOne*100) > Math.floor(floatTwo*100));
Comparing of float values is tricky due to long "post dot" tail of the float value stored in the memory. The simplest (and in fact the best) way is: to multiply values, for reducing known amount of post dot digits to zero, and then round the value (to rid of the tail).
Obviously both compared values must be multiplied by the same rate.
F.i.: 1,234 * 1000 gives 1234 - which can be compared very easily. 5,67 can be multiplied by 100, as for reducing the float comparing problem in general, but then it couldn't be compared to the first value (1,234 vel 1234). So in this example it need to be multiplied by 1000.
Then the comparition code could look like (in meta code):
var v1 = 1.234;
var v2 = 5.67;
if (Math.round(v1*1000) < Math.round(v2*1000)) ....

Categories

Resources