27

I was wondering how can I subtract two negative Floating-Point numbers in javascript. I tried:

alert(-0.2-0.1);

and the result is -0.30000000000000004. Am I doing something wrong? What do I have to do to get -0.3 ?

mskfisher
  • 3,291
  • 4
  • 35
  • 48
Teneff
  • 30,564
  • 13
  • 72
  • 103

6 Answers6

30

No, nothing wrong with your code, most decimal fractions cannot be represented exactly in binary, use

number.toFixed(x)

Where x is the number of decimals you want and number is the result of the subtraction.

Alberto Zaccagni
  • 30,779
  • 11
  • 72
  • 106
  • I don't like toFixed() because it will pad unwanted trailing 0s, see [toFixed()](http://www.w3schools.com/jsref/jsref_tofixed.asp). – daalbert May 17 '11 at 08:49
  • 1
    Your answer is preposterous, how could this be a limitation with binary? – RonSper Aug 13 '14 at 20:55
  • 1
    An external resource for more explanation: http://floating-point-gui.de/ – Taylan Jan 01 '18 at 11:24
  • what if you not know how many decimal precisions you need. the subtraction results could vary. – Yash Oct 28 '21 at 04:31
6

Another possible solution might be this:

Number((-0.2-0.1).toFixed(x))

Where x should be the tolerance in decimals you'd like.

Running this with an x of 16, gives me an output of -0.3.

-0.3 === Number((-0.2-0.1).toFixed(16)) // true, and also with every 0 < x < 16

Let me know.

Cristian Douce
  • 3,148
  • 1
  • 16
  • 17
2

The reason of your problem is explained here: Why does modulus operator return fractional number in javascript?

A possible solution could be:

<script type="text/javascript">
var result = (-20-10)/100;
alert("My result is "+result);
</script>
Community
  • 1
  • 1
Fabrizio D'Ammassa
  • 4,729
  • 25
  • 32
2

You are doing nothing wrong, what you are seeing is the side effect of computers storing numbers in base 2. In base 10, 1/3 can't be precisely represented: .33333333 (with a bar over the 3). The same is true for 1/10 and 1/5 in base 2 or binary. The answer you see is merely the result of a rounding error. If you are working with money, it is often advised to just store values as cents to avoid some floating point errors.

As far as fixing the result you can do something like:

var SIGDIG= 100000000;
alert( Math.floor((-0.2-0.1)*SIGDIG)/SIGDIG );
daalbert
  • 1,465
  • 9
  • 7
1

toFixed() is what you must be looking for.

E.g

number.toFixed(x); 

where x is the number of digits after the decimal point. It is optional with default value of 0.

More here : Javascript Number.toFixed() Method

Saurabh Gokhale
  • 53,625
  • 36
  • 139
  • 164
-2

Javascript uses IEEE 754 that is designed to balance the need for accuracy and limitations of computer hardware.

it's still subject to limitations and can lead to rounding errors and imprecise calculations in some cases.

a simplified example will be

> 0.05 - 0.02
< 0.030000000000000002 // this is the result!!!

the result is unexpected and this I call bug and makes arithmetic operations on floating-point useless.

you can work around the problem as suggested with toFixed but this will require you to know the number of digits after decimal point in advance and toFixed returns a string.

if you dont know the number of digits after decimal point in advance, here how the problem can be solved:

const getLongestDecimalLength = ( ...numbers ) => numbers.reduce( ( previousLength, number ) => {
  const numberParts = number.toString().split( '.' );
  if ( numberParts.length <= 1 ) return previousLength;
  return numberParts[ 1 ].length > previousLength ? numberParts[ 1 ].length : previousLength;
    }, 0 );

const price = 0.05;
const tax = 0.02;
const decimalLength = getLongestDecimalLength(price, tax);
const cost = parseFloat((price - tax).toFixed(decimalLength)); // 0.03
Moh
  • 87
  • 2
  • 4
  • That's not a bug – Paul-Marie Jan 02 '23 at 13:48
  • It is not a bug, and floating-point arithmetic operations are not useless. Floating-point operations, like any tool, must be used properly, and with knowledge of their limitations. And one facet of using computer floating point properly is to not expect it to round the same way that a decimal calculator would. – Steve Summit Feb 18 '23 at 15:04