118 votes

Tronquer (ne pas arrondir) les nombres décimaux en javascript

J'essaie de tronquer les nombres décimaux en décimales. Quelque chose comme ça:

 5.467   -> 5.46  
985.943 -> 985.94
 

toFixed(2) fait la bonne chose mais arrondit la valeur. Je n'ai pas besoin que la valeur soit arrondie. J'espère que cela est possible en javascript.

76voto

Nick Knowlson Points 2715

Dogbert la réponse est bonne, mais si votre code peut avoir à traiter avec des nombres négatifs, Math.floor par lui-même peut donner des résultats inattendus.

E. g. Math.floor(4.3) = 4, mais Math.floor(-4.3) = -5

Utiliser une fonction d'assistance comme celui-ci, au lieu d'obtenir des résultats cohérents:

truncateDecimals = function (number) {
    return Math[number < 0 ? 'ceil' : 'floor'](number);
};

// Applied to Dogbert's answer:
var a = 5.467;
var truncated = truncateDecimals(a * 100) / 100; // = 5.46

Voici un moyen plus pratique version de cette fonction:

truncateDecimals = function (number, digits) {
    var multiplier = Math.pow(10, digits),
        adjustedNum = number * multiplier,
        truncatedNum = Math[adjustedNum < 0 ? 'ceil' : 'floor'](adjustedNum);

    return truncatedNum / multiplier;
};

// Usage:
var a = 5.467;
var truncated = truncateDecimals(a, 2); // = 5.46

// Negative digits:
var b = 4235.24;
var truncated = truncateDecimals(b, -2); // = 4200

Si ce n'est pas le comportement souhaité, insérer un appel à Math.abs sur la première ligne:

var multiplier = Math.pow(10, Math.abs(digits)),

EDIT: shendz souligne à juste titre que l'utilisation de cette solution avec a = 17.56 , à tort, produisent 17.55. Pour en savoir plus sur le pourquoi de ce phénomène, lire Ce que Chaque Ordinateur Scientifique Doit Savoir à Propos de l'Arithmétique à virgule Flottante. Malheureusement, l'écriture d'une solution qui élimine toutes les sources de virgule flottante d'erreur est assez délicat avec javascript. Dans une autre langue que vous souhaitez utiliser des entiers, ou peut-être un type Décimal, mais avec javascript...

Cette solution doit être précis à 100%, mais il sera également plus lente:

function truncateDecimals (num, digits) {
    var numS = num.toString(),
        decPos = numS.indexOf('.'),
        substrLength = decPos == -1 ? numS.length : 1 + decPos + digits,
        trimmedResult = numS.substr(0, substrLength),
        finalResult = isNaN(trimmedResult) ? 0 : trimmedResult;

    return parseFloat(finalResult);
}

Pour ceux qui ont besoin de vitesse, mais aussi d'éviter les erreurs en virgule flottante, essayez quelque chose comme BigDecimal.js. Vous pouvez trouver d'autres javascript BigDecimal des bibliothèques DONC, la question: "Est-il une bonne Javascript BigDecimal bibliothèque?" et voici un bon billet de blog à propos des bibliothèques mathématiques pour Javascript

57voto

kirilloid Points 7139

upd :

Donc, après tout, les bugs arrondis vous hanteront toujours, peu importe la difficulté avec laquelle vous essayez de les compenser. Il faut donc s'attaquer au problème en représentant les nombres exactement en notation décimale.

 Number.prototype.toFixedDown = function(digits) {
    var re = new RegExp("(\\d+\\.\\d{" + digits + "})(\\d)"),
        m = this.toString().match(re);
    return m ? parseFloat(m[1]) : this.valueOf();
};

[   5.467.toFixedDown(2),
    985.943.toFixedDown(2),
    17.56.toFixedDown(2),
    (0).toFixedDown(1),
    1.11.toFixedDown(1) + 22];

// [5.46, 985.94, 17.56, 0, 23.1]
 

Ancienne solution sujette aux erreurs basée sur la compilation des autres ':

 Number.prototype.toFixedDown = function(digits) {
  var n = this - Math.pow(10, -digits)/2;
  n += n / Math.pow(2, 53); // added 1360765523: 17.56.toFixedDown(2) === "17.56"
  return n.toFixed(digits);
}
 

38voto

Dogbert Points 44003
var a = 5.467;
var truncated = Math.floor(a * 100) / 100; // = 5.46

21voto

RichardTheKiwi Points 58121

Vous pouvez corriger l'arrondi en soustrayant 0,5 pour toFixed, par exemple

 (f - 0.005).toFixed(2)
 

19voto

ruffin Points 1906

Envisager de prendre avantage de la double tilde: ~~.

Prendre le numéro. Multiplier par chiffres significatifs après la virgule, de sorte que vous pouvez tronquer à zéro des lieux avec ~~. Divisez-le multiplicateur de retour. Le Profit.

function truncator(numToTruncate, intDecimalPlaces) {    
    var numPower = Math.pow(10, intDecimalPlaces); // "numPowerConverter" might be better
    return ~~(numToTruncate * numPower)/numPower;
}

J'essaie de résister à l'emballage de la ~~ appel à des parens; ordre des opérations à faire que de travailler correctement, je crois.

alert(truncator(5.1231231, 1)); // is 5.1

alert(truncator(-5.73, 1)); // is -5.7

alert(truncator(-5.73, 0)); // is -5

JSFiddle lien.

EDIT: en Regardant en arrière, je l'ai involontairement également traité les affaires de tour à gauche de la décimale ainsi.

alert(truncator(4343.123, -2)); // gives 4300.

La logique est un peu loufoque à la recherche pour cette utilisation, et peuvent bénéficier d'un rapide refactoriser. Mais il fonctionne encore. Mieux de la chance que de bien.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X