How to multiply in Javascript? problems with decim

2020-02-18 20:49发布

问题:

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?

回答1:

.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


回答2:

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+$/,'');



回答3:

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.



回答4:

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:

  • https://github.com/MikeMcl/big.js
  • https://github.com/MikeMcl/bignumber.js/


回答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


回答6:

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>



回答7:

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



回答8:

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



回答9:

Just try

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

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



回答10:

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



回答11:

You could do

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

223.2 === total;          // true
223.2 === 0.1*2232.00;    // false


回答12:

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>



回答13:

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.