40

i've the following code in Javascript:

var m1 = 2232.00;
var percent = (10/100);
var total = percent*m1;
alert(total);

The problem is that the variable "total" gives me "223.20000000000002" and it should be "223.2", what should i do to get the correct value?

gustavomanolo
  • 787
  • 1
  • 9
  • 18
  • 5
    This may be the answer you are looking for: http://stackoverflow.com/questions/1458633/elegant-workaround-for-javascript-floating-point-number-problem – Dimitry Jan 23 '13 at 22:27
  • Or more information dealing with [rounding numbers in javascript](http://stackoverflow.com/questions/246193/how-do-i-round-a-number-in-javascript) – radical7 Jan 23 '13 at 22:28
  • 1
    possible duplicate of [Is floating point math broken?](http://stackoverflow.com/questions/588004/is-floating-point-math-broken) –  Jul 29 '15 at 15:07

14 Answers14

31

.toFixed() is best solution.It will keep only two digits after dot.

Exp 1:

var value = 3.666;
value.toFixed(2); //Output : 3.67

Exp 2:

var value = 3.0000;
value.toFixed(2); //Output : 3.00
Malik Khalil
  • 6,454
  • 2
  • 39
  • 33
  • 3
    Note, `.toFixed(n)` results in a **string** not a decimal value... so using `+` or `+=` will concatenate, not add to the variable – freefaller Nov 07 '18 at 16:35
8

You can't get the exact value. This is the fundamental problem with floating-point numbers.

You can force a fixed number of decimal numbers with toFixed:

alert(total.toFixed(2));

However, keep in mind that this will leave trailing zeroes, which you might not want. You can remove them with .replace(/0+$/,'');

Web_Designer
  • 72,308
  • 93
  • 206
  • 262
Niet the Dark Absol
  • 320,036
  • 81
  • 464
  • 592
6

If you are trying to display this number, you could convert to a string with toFixed(1). If you do this, keep track of the types because you can't then multiply the string with another number.

If you are going to use it in another computation you could truncate it to one decimal place:

Math.round( total * 10 ) / 10

However, as pointed out by various people, the inexact value is just the way floating point numbers are.

See the questions linked in the comments for more good information.

WildCrustacean
  • 5,896
  • 2
  • 31
  • 42
  • the fact is that i don't need to convert this value to String because i need to use the variable "total" to multiply with another one. – gustavomanolo Jan 23 '13 at 22:25
  • You can do it safely as it is. This is the way floating-point numbers are in JS, MSVC++ float or double too. – Kitet Jan 23 '13 at 22:28
5

I found the answer using the following pages, thanks to Dimitry:

Floating-point cheat sheet for JavaScript

I decided to use the following clases because i need the exact values of the operations and they're related to money operations:

Community
  • 1
  • 1
gustavomanolo
  • 787
  • 1
  • 9
  • 18
5

The operator "*" and "/" do not work perfectly always, for example:

32.09 * 100 = 3209.0000000000005
100 / (1 / 32.09) = 3209.0000000000005

Solution:

One solution, the easy one, to have decimals is useing .toFixed(2) where "2" is the number of decimal digits that you want. But you have to take into account this return you a String, and it rounds the value.

45.6789.toFixed(2) —> "45.68" as String

Other option, the most complete, is using .toLocaleString that converts the number properly to the country code that you want. You can set a pair of params to fix the decimals values always to 2. This also returns you a String:

(654.3453).toLocaleString(
  'en-US',
  {minimumFractionDigits: 2, maximumFractionDigits: 2},
) —> "654.35" as String

If you need it as a Number, you can wrap it into Number( ... ) :

Number((654.3453).toLocaleString(
  'en-US',
  {minimumFractionDigits: 2, maximumFractionDigits: 2},
)) —> 654.35 as Number

If you only want a no decimal number, use one of this methods to be sure that the result is without decimals.

Math.trunc(32.09); —> 32 as Number  
(32.09).toFixed(0); —> “32” as String
32.09 | 0; —> 32 as Number
DrWaky
  • 1,165
  • 8
  • 7
3

total.toFixed(2) may help. But note that the total variable be will typecasted into a string.

Web_Designer
  • 72,308
  • 93
  • 206
  • 262
srijan
  • 1,504
  • 1
  • 13
  • 24
3

This can be done well with an external library called decimal.js that provides a Decimal type for JavaScript. It's also available for Node on npm. Below is an example that replicates the original example from gustavomanolo using decimal.js.

// Decimal type provided by decimal.js (http://mikemcl.github.io/decimal.js/)
var m1 = new Decimal( 2232.00 );
var percent = new Decimal( 10/100 );
var total = m1.mul(percent);
console.log( 'Total:', total );
<script src="https://cdnjs.cloudflare.com/ajax/libs/decimal.js/7.2.3/decimal.min.js"></script>
Kevinleary.net
  • 8,851
  • 3
  • 54
  • 46
3

I ended up with the following solution:

function decimalmultiply(a, b) {
    return parseFloat((a * b).toFixed(12));
}

10.50*30.45=319.72499999999997
decimalmultiply(10.50,30.45)=319.725

This method returns a number, not a string, without truncating significant decimals (up to 12).

Erik123
  • 201
  • 1
  • 2
  • 8
2

Here is a work around solution for multiplication of floating numbers. It's pretty simple but works for me. You figure out how many decimals the numbers have with this function.

function decimalPlaces(num) {
    var match = (''+num).match(/(?:\.(\d+))?(?:[eE]([+-]?\d+))?$/);
    if (!match) { return 0; }
    return Math.max(
        0,
        // Number of digits right of decimal point.
        (match[1] ? match[1].length : 0)
        // Adjust for scientific notation.
        - (match[2] ? +match[2] : 0));
}

And then for your final answer "total" you do

total = total.toFixed(decimalPlaces(a)+decimalPlaces(b));

where a,b are your numbers

PetrosM
  • 251
  • 3
  • 15
  • credits to Mike Samuel from post [link] (http://stackoverflow.com/questions/10454518/javascript-how-to-retrieve-the-number-of-decimals-of-a-string-number) for the decimalPlaces function – PetrosM Mar 10 '16 at 12:25
1

Just try

var x = 0.07;
console.log((x+1)*100 - 100);

now, replace the value of x for the other values ;-)

Andre Figueiredo
  • 12,930
  • 8
  • 48
  • 74
rubens21
  • 743
  • 5
  • 13
0

You could do

var total = +(percent*m1).toPrecision(15);

223.2 === total;          // true
223.2 === 0.1*2232.00;    // false
MikeM
  • 13,156
  • 2
  • 34
  • 47
0

If you are using Angular, I made a component for this.

Install with bower

bower install angular-floating-point --save

Usage

var pretty = floatingPoint.makePretty(6.1*6);

Here is a demo -> https://mattspaulding.github.io/angular-floating-point
Here is source -> https://github.com/mattspaulding/angular-floating-point

Try it yourself with this snippet below.

 angular.module('myApp', ['floatingPoint'])
  .controller('myCtrl', function ($scope, floatingPoint) {

      $scope.calculate = function () {
        $scope.result =$scope.num0*$scope.num1;
        $scope.prettyResult=floatingPoint.makePretty($scope.result)
      }

      $scope.num0=6.1;
      $scope.num1=6;
      $scope.calculate();

    });
 
<html>

<head>
  <title>My Angular App</title>
  <script src='//code.jquery.com/jquery-latest.min.js'></script>
  <script src="//ajax.googleapis.com/ajax/libs/angularjs/1.4.5/angular.min.js"></script>
  <!-- Latest compiled and minified CSS -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">

<!-- Optional theme -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap-theme.min.css" integrity="sha384-rHyoN1iRsVXV4nD0JutlnGaslCJuC7uwjduW9SVrLvRYooPp2bWYgmgJQIXwl/Sp" crossorigin="anonymous">

<!-- Latest compiled and minified JavaScript -->
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js" integrity="sha384-Tc5IQib027qvyjSMfHjOMaLkfuWVxZxUPnCJA7l2mCWNIpG9mGCD8wGNIcPD7Txa" crossorigin="anonymous"></script>
<script src="https://rawgit.com/mattspaulding/angular-floating-point/master/dist/angular-floating-point.min.js"></script>
</head>

<body ng-app="myApp" ng-controller="myCtrl">
    <div class="row" style="padding-top: 10px;text-align:center">
      <label>(try me) ==> </label>
      <input ng-model="num0" ng-change="calculate()" style="width:100px; height:30px">
      X
      <input ng-model="num1" ng-change="calculate()" style="width:100px; height:30px">
    </div>
    <div class="row" style="padding-top: 50px;">
      <div class="col-xs-6">
        <label style="float: right;">Ugly calculation:</label>
      </div>
      <div class="col-xs-6">
        <label style="float: left;">{{result}}</label>
      </div>
    </div>
    <div class="row" style="padding-top: 20px;">
      <div class="col-xs-6">
        <label style="float: right;"><span style="color:blue">Angular Floating Point</span> calculation:</label>
      </div>
      <div class="col-xs-6">
        <label style="float: left;">{{prettyResult}}</label>
      </div>
    </div>

</body>
Matt
  • 33,328
  • 25
  • 83
  • 97
0

I found a very simple solution. The * operator is a bit broken when it comes to decimal numbers, but the / operator is not. A multiplication can be easily transformed into a division since a • b = a / (1/b)

function times(a, b) { return a/(1/b) }

Just replace percent * m1 with times(percent, m1).

Update: It doesn't work all the times.

Stefan Octavian
  • 593
  • 6
  • 17
-1

I hope this helps... it took me a while to get there but it kinda does the trick.

Number.prototype.CountDecimals = function () {
  if (Math.floor(this.valueOf()) === this.valueOf())
    return 0;
  return this.toString().split(".")[1].length || 0;
};

String.prototype.PadRight = function (fullLength, character) {
  if (String.isNullOrEmpty(this.toString()) || String.isNullOrEmpty(character))
    return this.toString();
  var value = this.toString();
  while (value.length < fullLength)
    value += character;
  return value;
};

var Multiply = function () {
  var maxNumberOfDecimals = 0;
  for (var i = 0; i < arguments.length; i++) {
    var decimals = arguments[i].CountDecimals();
    if (decimals > maxNumberOfDecimals)
      maxNumberOfDecimals=decimals;
  }
  var results = 1;
  for (var j = 0; j < arguments.length; j++) {
    var arg = arguments[j];
    arg = arg * parseFloat('1'.PadRight(maxNumberOfDecimals + 1, '0'));
    results = results * arg;
  }
  var divisor = parseFloat('1'.PadRight((maxNumberOfDecimals * arguments.length) +1, '0'));
  return results / divisor;
};