web-dev-qa-db-fra.com

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 complète la valeur. Je n'ai pas besoin que la valeur soit arrondie. J'espère que cela est possible en javascript.

63
kcssm

upd :

Donc, après tout, les punaises vous hantent toujours, peu importe les efforts que vous déployez pour les compenser. Par conséquent, le problème devrait être résolu 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 solutions ':

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

La réponse de Dogbert est bonne, mais si votre code doit traiter des nombres négatifs, Math.floor seul peut donner des résultats inattendus.

Par exemple. Math.floor(4.3) = 4, mais Math.floor(-4.3) = -5

Utilisez plutôt une fonction d'assistance comme celle-ci pour 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 une version plus pratique 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érez un appel à Math.abs sur la première ligne:

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

EDIT: shendz souligne correctement que l'utilisation de cette solution avec a = 17.56 produira incorrectement 17.55. Pour en savoir plus sur ce phénomène, lisez Ce que tout informaticien devrait savoir sur l’arithmétique en virgule flottante . Malheureusement, l'écriture d'une solution qui élimine toutes les sources d'erreur en virgule flottante est assez délicate avec JavaScript. Dans une autre langue, vous utiliseriez des entiers ou peut-être un type décimal, mais avec javascript ...

Cette solution devrait être précise à 100%, mais elle 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 qui veulent aussi éviter les erreurs en virgule flottante, essayez quelque chose comme BigDecimal.js . Vous pouvez trouver d'autres bibliothèques BigDecimal javascript dans cette question SO: "Existe-t-il une bonne bibliothèque Javascript BigDecimal?" et voici un bon article sur des bibliothèques de mathématiques pour Javascript

50
Nick Knowlson
var a = 5.467;
var truncated = Math.floor(a * 100) / 100; // = 5.46
26
Dogbert

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

(f - 0.005).toFixed(2)
21
RichardTheKiwi

Considérons profitant du double tilde: ~~) .

Prenez dans le nombre. Multipliez par les chiffres significatifs après la virgule pour que vous puissiez tronquer à zéro avec ~~. Divisez ce multiplicateur en arrière. 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'enveloppe de l'appel ~~ entre parenthèses; L’ordre des opérations devrait permettre que cela fonctionne correctement.

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

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

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

lien JSFiddle .

EDIT: En regardant en arrière, j'ai involontairement également traité des cas pour arrondir à gauche de la virgule.

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

La logique est un peu farfelue à la recherche de cet usage et pourrait bénéficier d'un remaniement rapide. Mais ça fonctionne toujours. Mieux vaut la chance que le bien.

16
ruffin

Je pensais que je donnerais une réponse en utilisant | car c'est simple et fonctionne bien.

truncate = function(number, places) {
  var shift = Math.pow(10, places);

  return ((number * shift) | 0) / shift;
};
9
Daniel X Moore

Belle solution à une ligne:

function truncate (num, places) {
  return Math.trunc(num * Math.pow(10, places)) / Math.pow(10, places);
}

Puis appelez-le avec:

truncate(3.5636232, 2); // returns 3.56
truncate(5.4332312, 3); // returns 5.433
truncate(25.463214, 4); // returns 25.4632
8
MeestorHok

La réponse de @ Dogbert peut être améliorée avec Math.trunc , qui tronque au lieu d'arrondir.

Il y a une différence entre arrondir et tronquer. Truncating est clairement le comportement que cette question cherche. Si j'appelle tronquer (-3,14) et recevoir -4 en retour, je l'appellerais certainement indésirable. - @NickKnowlson 

var a = 5.467;
var truncated = Math.trunc(a * 100) / 100; // = 5.46
var a = -5.467;
var truncated = Math.trunc(a * 100) / 100; // = -5.46
5
zurfyx

Tronquer à l'aide d'opérateurs au niveau des bits:

~~0.5 === 0
~~(-0.5) === 0
~~14.32794823 === 14
~~(-439.93) === -439
4
John Strickler

J'ai trouvé un problème: vu la situation suivante: 2.1 ou 1.2 ou -6.4

Et si vous voulez toujours 3 décimales ou deux ou wharever, alors, vous devez compléter les zéros à droite

// 3 decimals numbers
0.5 => 0.500

// 6 decimals
0.1 => 0.10000

// 4 decimales
-2.1 => -2.1000

// truncate to 3 decimals
3.11568 => 3.115

C'est la fonction fixe de Nick Knowlson

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

    // adds leading zeros to the right
    if (decPos != -1){
        var s = trimmedResult+"";
        decPos = s.indexOf('.');
        var decLength = s.length - decPos;

            while (decLength <= digits){
                s = s + "0";
                decPos = s.indexOf('.');
                decLength = s.length - decPos;
                substrLength = decPos == -1 ? s.length : 1 + decPos + digits;
            };
        finalResult = s;
    }
    return finalResult;
};

https://jsfiddle.net/huttn155/7/

2
juanpscotto

Je pense que cette fonction pourrait être une solution simple:

function trunc(decimal,n=2){
  let x = decimal + ''; // string 
  return x.lastIndexOf('.')>=0?parseFloat(x.substr(0,x.lastIndexOf('.')+(n+1))):decimal; // You can use indexOf() instead of lastIndexOf()
}

console.log(trunc(-241.31234,2));
console.log(trunc(241.312,5));
console.log(trunc(-241.233));  
console.log(trunc(241));

La réponse de @kirilloid semble être la bonne, cependant, le code principal doit être mis à jour. Sa solution ne prend pas en charge les nombres négatifs (ce que quelqu'un a mentionné dans la section commentaire mais n'a pas été mis à jour dans le code principal).

Mise à jour de cette solution complète et testée:

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

Exemple d'utilisation:

var x = 3.1415629;
Logger.log(x.toFixedDown(2)); //or use whatever you use to log

Violon: Numéro JS Arrondi vers le bas

PS: Pas assez de pension pour commenter cette solution.

1
function toFixed(number, digits) {
    var reg_ex = new RegExp("(\\d+\\.\\d{" + digits + "})(\\d)")
    var array = number.toString().match(reg_ex);
    return array ? parseFloat(array[1]) : number.valueOf()
}

var test = 10.123456789
var __fixed = toFixed(test, 6)
console.log(__fixed)
// => 10.123456
1
Flavio

Lodash a quelques méthodes d’utilité Math qui peuvent arrondir , étage et ceil un nombre avec une précision décimale donnée. Cela laisse les zéros à la fin.

Ils adoptent une approche intéressante en utilisant l’exposant d’un nombre. Cela évite apparemment les problèmes d'arrondi.

(Remarque: func est Math.round ou ceil ou floor dans le code ci-dessous)

// Shift with exponential notation to avoid floating-point issues.
var pair = (toString(number) + 'e').split('e'),
    value = func(pair[0] + 'e' + (+pair[1] + precision));

pair = (toString(value) + 'e').split('e');
return +(pair[0] + 'e' + (+pair[1] - precision));

Lien vers le code source

1
Matthias Dailey

Voici une fonction simple mais pratique pour tronquer les nombres jusqu'à 2 décimales.

           function truncateNumber(num) {
                var num1 = "";
                var num2 = "";
                var num1 = num.split('.')[0];
                num2 = num.split('.')[1];
                var decimalNum = num2.substring(0, 2);
                var strNum = num1 +"."+ decimalNum;
                var finalNum = parseFloat(strNum);
                return finalNum;
            }
1
RohannG

Le type résultant reste un numéro ... 

/* Return the truncation of n wrt base */
var trunc = function(n, base) {
    n = (n / base) | 0;
    return base * n;
};
var t = trunc(5.467, 0.01);
1
Bob Lyon

Celui qui marque comme solution est la meilleure solution que j’ai trouvée jusqu’à aujourd’hui, mais qui pose un grave problème avec 0 (par exemple, 0.toFixedDown (2) donne -0,01). Je suggère donc d'utiliser ceci:

Number.prototype.toFixedDown = function(digits) {
  if(this == 0) {
    return 0;
  }
  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);
}
1
Sebastián Rojas

J'ai écrit une réponse en utilisant une méthode plus courte. Voici ce que je suis venu avec

function truncate(value, precision) {
    var step = Math.pow(10, precision || 0);
    var temp = Math.trunc(step * value);

    return temp / step;
}

La méthode peut être utilisée comme si

truncate(132456.25456789, 5)); // Output: 132456.25456
truncate(132456.25456789, 3)); // Output: 132456.254
truncate(132456.25456789, 1)); // Output: 132456.2   
truncate(132456.25456789));    // Output: 132456

Ou, si vous voulez une syntaxe plus courte, ici vous allez

function truncate(v, p) {
    var s = Math.pow(10, p || 0);
    return Math.trunc(s * v) / s;
}
1
Majd Alhayek
Number.prototype.trim = function(decimals) {
    var s = this.toString();
    var d = s.split(".");
    d[1] = d[1].substring(0, decimals);
    return parseFloat(d.join("."));
}

console.log((5.676).trim(2)); //logs 5.67
1
Max Zlotskiy
Number.prototype.truncate = function(places) {
  var shift = Math.pow(10, places);

  return Math.trunc(this * shift) / shift;
};
0
Dercni

Voici mon point de vue sur le sujet:

convert.truncate = function(value, decimals) {
  decimals = (decimals === undefined ? 0 : decimals);
  return parseFloat((value-(0.5/Math.pow(10, decimals))).toFixed(decimals),10);
};

C'est juste une version légèrement plus élaborée de

(f - 0.005).toFixed(2)
0
opensas

Voici ce que j'utilise:

var t = 1;
for (var i = 0; i < decimalPrecision; i++)
    t = t * 10;

var f = parseFloat(value);
return (Math.floor(f * t)) / t;
0
Steve

juste pour signaler une solution simple qui a fonctionné pour moi

convertissez-le en chaîne puis regex-le ...

var number = 123.45678;
var number_s = '' + number;
var number_truncated_s = number_s.match(/\d*\.\d{4}/)[0]
var number_truncated = parseFloat(number_truncated_s)

Il peut être abrégé en

var number_truncated = parseFloat(('' + 123.4568908).match(/\d*\.\d{4}/)[0])
0
Sergio Campamá

Voici un code ES6 qui fait ce que vous voulez

const truncateTo = (unRouned, nrOfDecimals = 2) => {
      const parts = String(unRouned).split(".");

      if (parts.length !== 2) {
          // without any decimal part
        return unRouned;
      }

      const newDecimals = parts[1].slice(0, nrOfDecimals),
        newString = `${parts[0]}.${newDecimals}`;

      return Number(newString);
    };

// your examples 

 console.log(truncateTo(5.467)); // ---> 5.46

 console.log(truncateTo(985.943)); // ---> 985.94

// other examples 

 console.log(truncateTo(5)); // ---> 5

 console.log(truncateTo(-5)); // ---> -5

 console.log(truncateTo(-985.943)); // ---> -985.94

0
Cristian Sima