How to multiply in Javascript? problems with decimals
Asked Answered
D

14

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?

Dyeline answered 23/1, 2013 at 22:22 Comment(3)
This may be the answer you are looking for: #1459133Jessamine
Or more information dealing with rounding numbers in javascriptAnchorage
possible duplicate of Is floating point math broken?Mcroberts
D
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
Diaz answered 29/7, 2015 at 15:5 Comment(1)
Note, .toFixed(n) results in a string not a decimal value... so using + or += will concatenate, not add to the variablePallet
H
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+$/,'');

Hyperdulia answered 23/1, 2013 at 22:25 Comment(2)
You probably will also want to .replace(/.$/, '') after .replace(/0+$/, '') to get rid of any trailing decimal point if there is one.Rat
The .replace(/.$/, '') wont work try using .replace(/\.$/, '')Intolerant
M
7

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.

Mistiemistime answered 23/1, 2013 at 22:24 Comment(2)
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.Dyeline
You can do it safely as it is. This is the way floating-point numbers are in JS, MSVC++ float or double too.Bryon
D
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:

Dyeline answered 23/1, 2013 at 22:55 Comment(1)
bignumber.js is now on the jsdelivr CDNCamphor
L
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
Lolly answered 19/10, 2018 at 18:53 Comment(0)
T
4

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).

Thatch answered 13/12, 2018 at 15:26 Comment(0)
M
3

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

Malta answered 23/1, 2013 at 22:25 Comment(1)
#588504Malta
S
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>
Shipshape answered 5/7, 2017 at 13:51 Comment(0)
B
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

Braud answered 10/3, 2016 at 12:15 Comment(1)
credits to Mike Samuel from post [link] (#10455018) for the decimalPlaces functionBraud
H
1

Just try

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

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

Helgahelge answered 17/7, 2017 at 13:46 Comment(1)
It doesn't work properly Eg. take x = 0.041Watchcase
U
0

You could do

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

223.2 === total;          // true
223.2 === 0.1*2232.00;    // false
Utoaztecan answered 23/1, 2013 at 22:43 Comment(0)
M
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>
Mazza answered 4/11, 2016 at 21:16 Comment(0)
S
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.

Sain answered 16/1, 2018 at 9:29 Comment(1)
It doesn't works: 32.09 * 100 = 3209.0000000000005 100 / (1 / 32.09) = 3209.0000000000005Lolly
R
-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;
};
Riesman answered 27/2, 2020 at 18:12 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.