web-dev-qa-db-fra.com

Comment se multiplier en Javascript? problèmes de nombres décimaux

j'ai le code suivant en Javascript:

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

Le problème est que la variable "total" me donne "223.20000000000002" et qu'il devrait être "223.2", que dois-je faire pour obtenir la valeur correcte?

21
gustavomanolo

.toFixed () est la meilleure solution.Il ne conservera que deux chiffres après le point.

Exp 1:

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

Exp 2:

var value = 3.0000;
value.toFixed(2); //Output : 3.00
18
Malik Khalil

Vous ne pouvez pas obtenir la valeur exacte. C'est le problème fondamental des nombres à virgule flottante.

Vous pouvez forcer un nombre fixe de nombres décimaux avec toFixed:

alert(total.toFixed(2));

Toutefois, gardez à l’esprit que cela laissera des zéros, que vous ne voudrez peut-être pas. Vous pouvez les supprimer avec .replace(/0+$/,'');

7
Niet the Dark Absol

J'ai trouvé la réponse en utilisant les pages suivantes, grâce à Dimitry :

Aide-mémoire à virgule flottante pour JavaScript

J'ai décidé d'utiliser les classes suivantes parce que j'ai besoin des valeurs exactes des opérations et qu'elles sont liées aux opérations monétaires:

4
gustavomanolo

Si vous essayez d'afficher ce nombre, vous pouvez convertir une chaîne avec toFixed (1) . Si vous faites cela, gardez une trace des types car vous ne pouvez pas alors multiplier la chaîne avec un autre nombre.

Si vous comptez l'utiliser dans un autre calcul, vous pouvez le tronquer à une décimale:

Math.round( total * 10 ) / 10

Cependant, comme l'ont souligné diverses personnes, la valeur inexacte correspond à la nature des nombres à virgule flottante. 

Voir les questions liées dans les commentaires pour plus d'informations.

4
WildCrustacean

Cela peut être fait avec une bibliothèque externe appelée decimal.js qui fournit un type Decimal pour JavaScript. Il est également disponible pour Node sur NPM. Vous trouverez ci-dessous un exemple qui reproduit l’exemple original de gustavomanolo en utilisant 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>

3
Kevin Leary

total.toFixed(2) peut aider. Mais notez que la variable total be sera transtypée en chaîne.

2
srijan

Voici une solution de contournement pour la multiplication de nombres flottants. C'est assez simple mais ça fonctionne pour moi. Vous déterminez le nombre de décimales des nombres avec cette fonction.

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));
}

Et puis pour votre réponse finale "total" vous faites 

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

où a, b sont tes numéros

2
PetrosM

Les opérateurs "*" et "/" ne fonctionnent pas toujours parfaitement, par exemple:

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

Solution:  

Une solution simple consiste à utiliser .toFixed (2), où "2" correspond au nombre de chiffres décimaux que vous souhaitez. Mais vous devez prendre en compte que cette fonction vous renvoie une chaîne, et elle arrondit la valeur.

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

L’autre option, la plus complète, consiste à utiliser .toLocaleString, qui convertit le nombre correctement en code de pays souhaité. Vous pouvez définir une paire de paramètres pour que les valeurs décimales soient toujours fixées à 2. Cela vous renvoie également une chaîne:

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

Si vous en avez besoin sous forme de nombre, vous pouvez l'envelopper en nombre (...):

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

Si vous souhaitez uniquement un nombre non décimal, utilisez l'une de ces méthodes pour vous assurer que le résultat obtenu est sans décimales.

Math.trunc(32.09); —> 32 as Number  
(32.09).toFixed(0); —> “32” as String
32.09 | 0; —> 32 as Number
1
DrWaky

Juste essayer 

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

remplacez maintenant la valeur de x pour les autres valeurs ;-)

1
rubens21

Vous pourriez faire

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

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

J'ai trouvé une solution très simple. L'opérateur * est un peu cassé lorsqu'il s'agit de nombres décimaux, mais l'opérateur / ne l'est pas. Une multiplication peut être facilement transformée en division puisque a • b = a/(1/b)

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

Il suffit de remplacer percent * m1 par times(percent, m1).

Mise à jour: Cela ne fonctionne pas tout le temps.

0
Stefan Octavian

Si vous utilisez Angular, j'ai créé un composant pour cela.

Installer avec bower

bower install angular-floating-point --save

Usage

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

Voici une démo -> https://mattspaulding.github.io/angular-floating-point
Voici source -> https://github.com/mattspaulding/angular-floating-point

Essayez vous-même avec cet extrait ci-dessous.

 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>

0
Matt

J'ai fini avec la solution suivante: 

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

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

Cette méthode retourne un nombre , et non une chaîne , sans tronquer les décimales significatives (jusqu'à 12).

0
Erik123