views:

190

answers:

4

There is some problem, i can't understand anyway.

look at this code please


<script type="text/javascript">
function math(x)
{
 var y;
 y = x*10;
 alert(y);
}

</script>
<input type="button" onclick="math(0.011)">

What must be alerted after i click on button? i think 0.11, but no, it alerts 0.10999999999999999 explain please this behavior. thanks in advance

+5  A: 

this is because you are dealing with floating point, and this is the expected behavior of floating point math.

what you need to do is format that number.

see this java explanation which also applies here if you want to know why this is happening.

in javascript all numbers are represented as 64bit floats, so you will run into this sort of thing often.

the quick overview of that article is that floating point tries to represent a range of values larger then would fit in 64bits, therefor there is going to be some imprecise representation, and this is what you are seeing.

mkoryak
i don't understand
Syom
that was quick, you read the entire article?
mkoryak
Also see http://en.wikipedia.org/wiki/Floating_point#Accuracy_problems
jball
@mkoryak no yet i just can't understand why the number changes when it represented as 32bit float? i'll read now, i think i understand:)
Syom
ok. i undestand why. but how to solve it?
Syom
In javascript, all numbers are represented in **64** bit floating point.
Stephen Canon
+1  A: 

With floating point number you get a representation of the number you try to encode. Mostly it is a number that is very close the the original number. More information on encoding/storing floating point numbers can be found here.

Note: If you show the value of x, it still shows 0.011 because JavaScript has not yet decided what variable type x has. But after multiplying it with 10 the type got set to floating point (it is the only possibility) and the round error shows.

Veger
+1  A: 

You can try to fix the nr of decimals with this one:

// fl is a float number with some nr of decimals
// d is how many decimals you want
function dec(fl, d) {
  var p = Math.pow(10, d);
  return Math.round(fl*p)/p;
}

Ex:

var n = 0.0012345;
console.log(dec(n,6)); // 0.001235
console.log(dec(n,5)); // 0.00123
console.log(dec(n,4)); // 0.0012
console.log(dec(n,3)); // 0.001

It works by first multiplying the float with 10^3 (1000) for three decimals, or 10^2 (100) for two decimals. Then do round on that and divide it back to original size.
Math.pow(10, d) makes 10^d (means that d will give us 1000).

In your case, do alert(dec(y,2));, it should work.

npup
no, it doesn't work. it 'eats' the lust number.but you help me, i just need to use this, lookfunction dec(fl, d) { var p = Math.pow(10, d); var c = fl*p*10/p; alert(c);}and when i call math(0.011,3), it works!!! thanks
Syom
So this doesn't alert "0.11" for you? Strange. Works for me :) function math(x) { var y = x*10; alert(dec(y,2));}function dec(fl, d) { var p = Math.pow(10, d); return Math.round(fl*p)/p;}math(0.011);
npup
your function returns 0.01. and it's expected:)
Syom
I beg your pardon, but it returns 0.01 if you feed it (0.011,2). But in your function called math, you ultimately feed it 0.11 (10*0.011) and whatever decimal limiter you want (and you said you wanted 2). And that returns 0.11.I think you mixed up calling your original "math" function and the one i provided a little.
npup
+7  A: 

Ok. Let me try to explain it.

The basic thing to remember with floating point numbers is this: They occupy a limited amount of bits and try to represent the original number using base-2 arithmetic.

As you know, in base-2 arithmetic integers are represented by the powers of 2 that they contain. Thus, 6 would be represented as 4 + 2, ie. in binary as 110.

In order to understand how fractional numbers are represented, you have to think about how we represent fractional numbers in our decimal system. The fractional part of numbers (for example 0.11) is represented as multiples of inverse powers of 10 (since the base is 10). Thus 0.11 is actually 1/10 + 1/100. As you can appreciate, this is not powerful enough to represent all fractional numbers in a limited number of digits. For example, 1/3 would be 0.333333.... in a never ending fashion. If we had only 32 digits of space to write the number down, we would end up having only an approximation to the original number, 0.33333333333333333333333333333333. This number, for example, would give 0.99999999999999999999999999999999 if it was multiplied by 3 and not 1 as you would have expected.

The situation is similar in base-2. Each fractional number would be represented as multiples of inverse powers of 2. Thus 0.75 (in decimal) (ie 3/4) would be represented as 1/2 + 1/4, which would mean 0.11 (in base-2). Just as base 10 is not capable enough to represent every fractional number in a finite manner, base-2 cannot represent all fractional numbers given a limited amount of space.

Now, try to represent 0.11 in base-2; you start with 11/100 and try to find an inverse power of 2 that is just less than this number. 1/2 doesn't work, 1/4 neither, nor does 1/8. 1/16 fits the bill, so you mark a 1 in the 4th place after the decimal point and subtract 1/16 from 11/100. You are left with 19/400. Now try to find the next power of 2 that fits the description. 1/32 seems to be that one, mark the 5th place after the point and subtract 1/32 from 19/400, you get 13/800. Next one is 1/64 and you are left with 1/1600 thus the next one is all the way up at 1/2048, etc. etc. Thus we got as far as 0.00011100001 but it goes on and on; and you will see that there always is a fraction remaining. Now, I didn't go through the whole calculation, but after you have put in 32 binary digits after the dot you will still probably have some fraction left (and this is assuming that all of the 32 bits of space is spent representing the decimal part, which it is not). Thus, I am sure you can appreciate that the resulting number might differ from its actual value by some amount.

In your case, the difference is 0.00000000000000001 which is 1/100000000000000000 = 1/10^17 and I am sure that you can see why you might have that.

paracycle
thanks very much:)
Syom
I am glad it helped. Good luck.
paracycle