Arrotondare al massimo a 2 cifre decimali (solo se necessario)

Mi piacerebbe arrotondare al massimo 2 posizioni decimali, ma solo se necessario .

Ingresso:

10 1.7777777 9.1 

Produzione:

 10 1.78 9.1 

Come posso farlo in JavaScript ?

Usa Math.round(num * 100) / 100

Se il valore è un tipo di testo:

 parseFloat("123.456").toFixed(2); 

Se il valore è un numero:

 var numb = 123.23454; numb = numb.toFixed(2); 

C’è un lato negativo che valori come 1.5 daranno “1.50” come output. Una correzione suggerita da @minitech:

 var numb = 1.5; numb = +numb.toFixed(2); // Note the plus sign that drops any "extra" zeroes at the end. // It changes the result (which is a string) into a number again (think "0 + foo"), // which means that it uses only as many digits as necessary. 

Sembra che Math.round sia una soluzione migliore. Ma non è! In alcuni casi NON arrotonda correttamente:

 Math.round(1.005 * 1000)/1000 // Returns 1 instead of expected 1.01! 

toFixed () inoltre NON arrotonderà correttamente in alcuni casi (testato in Chrome v.55.0.2883.87)!

Esempi:

 parseFloat("1.555").toFixed(2); // Returns 1.55 instead of 1.56. parseFloat("1.5550").toFixed(2); // Returns 1.55 instead of 1.56. // However, it will return correct result if you round 1.5551. parseFloat("1.5551").toFixed(2); // Returns 1.56 as expected. 1.3555.toFixed(3) // Returns 1.355 instead of expected 1.356. // However, it will return correct result if you round 1.35551. 1.35551.toFixed(2); // Returns 1.36 as expected. 

Immagino, questo è perché 1.555 è in realtà qualcosa come float 1.55499994 dietro le quinte.

La soluzione 1 consiste nell’utilizzare uno script con l’algoritmo di arrotondamento richiesto, ad esempio:

 function roundNumber(num, scale) { if(!("" + num).includes("e")) { return +(Math.round(num + "e+" + scale) + "e-" + scale); } else { var arr = ("" + num).split("e"); var sig = "" if(+arr[1] + scale > 0) { sig = "+"; } return +(Math.round(+arr[0] + "e" + sig + (+arr[1] + scale)) + "e-" + scale); } } 

https://plnkr.co/edit/uau8BlS1cqbvWPCHJeOy?p=preview

La soluzione 2 è di evitare calcoli front-end e di ottenere valori arrotondati dal server di back-end.

Puoi usare

 function roundToTwo(num) { return +(Math.round(num + "e+2") + "e-2"); } 

L’ho trovato su MDN . La loro strada evita il problema con 1.005 che è stato menzionato .

 roundToTwo(1.005) 1.01 roundToTwo(10) 10 roundToTwo(1.7777777) 1.78 roundToTwo(9.1) 9.1 roundToTwo(1234.5678) 1234.57 

La risposta di MarkG è corretta. Ecco un’estensione generica per qualsiasi numero di posizioni decimali.

 Number.prototype.round = function(places) { return +(Math.round(this + "e+" + places) + "e-" + places); } 

Uso:

 var n = 1.7777; n.round(2); // 1.78 

Test unitario:

 it.only('should round floats to 2 places', function() { var cases = [ { n: 10, e: 10, p:2 }, { n: 1.7777, e: 1.78, p:2 }, { n: 1.005, e: 1.01, p:2 }, { n: 1.005, e: 1, p:0 }, { n: 1.77777, e: 1.8, p:1 } ] cases.forEach(function(testCase) { var r = testCase.n.round(testCase.p); assert.equal(r, testCase.e, 'didn\'t get right number'); }); }) 

Si può usare .toFixed(NumberOfDecimalPlaces) .

 var str = 10.234.toFixed(2); // => '10.23' var number = Number(str); // => 10.23 

Un preciso metodo di arrotondamento. Fonte: Mozilla

 (function(){ /** * Decimal adjustment of a number. * * @param {String} type The type of adjustment. * @param {Number} value The number. * @param {Integer} exp The exponent (the 10 logarithm of the adjustment base). * @returns {Number} The adjusted value. */ function decimalAdjust(type, value, exp) { // If the exp is undefined or zero... if (typeof exp === 'undefined' || +exp === 0) { return Math[type](value); } value = +value; exp = +exp; // If the value is not a number or the exp is not an integer... if (isNaN(value) || !(typeof exp === 'number' && exp % 1 === 0)) { return NaN; } // Shift value = value.toString().split('e'); value = Math[type](+(value[0] + 'e' + (value[1] ? (+value[1] - exp) : -exp))); // Shift back value = value.toString().split('e'); return +(value[0] + 'e' + (value[1] ? (+value[1] + exp) : exp)); } // Decimal round if (!Math.round10) { Math.round10 = function(value, exp) { return decimalAdjust('round', value, exp); }; } // Decimal floor if (!Math.floor10) { Math.floor10 = function(value, exp) { return decimalAdjust('floor', value, exp); }; } // Decimal ceil if (!Math.ceil10) { Math.ceil10 = function(value, exp) { return decimalAdjust('ceil', value, exp); }; } })(); 

Esempi:

 // Round Math.round10(55.55, -1); // 55.6 Math.round10(55.549, -1); // 55.5 Math.round10(55, 1); // 60 Math.round10(54.9, 1); // 50 Math.round10(-55.55, -1); // -55.5 Math.round10(-55.551, -1); // -55.6 Math.round10(-55, 1); // -50 Math.round10(-55.1, 1); // -60 Math.round10(1.005, -2); // 1.01 -- compare this with Math.round(1.005*100)/100 above // Floor Math.floor10(55.59, -1); // 55.5 Math.floor10(59, 1); // 50 Math.floor10(-55.51, -1); // -55.6 Math.floor10(-51, 1); // -60 // Ceil Math.ceil10(55.51, -1); // 55.6 Math.ceil10(51, 1); // 60 Math.ceil10(-55.59, -1); // -55.5 Math.ceil10(-59, 1); // -50 

Nessuna delle risposte trovate qui è corretta . @stinkycheeseman ha chiesto di arrotondare , tutti voi arrotondato il numero.

Per arrotondare, usa questo:

 Math.ceil(num * 100)/100; 

Questa domanda è complicata.

Supponiamo di avere una funzione, roundTo2DP(num) , che accetta un float come argomento e restituisce un valore arrotondato a 2 posizioni decimali. A cosa dovrebbe valere ciascuna di queste espressioni?

  • roundTo2DP(0.014999999999999999)
  • roundTo2DP(0.0150000000000000001)
  • roundTo2DP(0.015)

La risposta “ovvia” è che il primo esempio dovrebbe arrotondare a 0,01 (perché è più vicino a 0,01 che a 0,02) mentre gli altri due dovrebbero arrotondare a 0,02 (perché 0,0150000000000000001 è più vicino a 0,02 che a 0,01 e perché 0,015 è esattamente a metà strada tra loro e c’è una convenzione matematica che tali numeri vengono arrotondati).

Il roundTo2DP , che potresti aver indovinato, è che roundTo2DP non può essere implementato per dare quelle risposte ovvie, perché tutti e tre i numeri passati sono lo stesso numero . I numeri in virgola mobile binari IEEE 754 (il tipo utilizzato da JavaScript) non possono rappresentare esattamente la maggior parte dei numeri non interi, quindi tutti i tre valori letterali numerici sopra riportati vengono arrotondati a un numero in virgola mobile valido nelle vicinanze. Questo numero, come accade, è esattamente

0,01499999999999999944488848768742172978818416595458984375

che è più vicino a 0,01 che a 0,02.

Puoi vedere che tutti e tre i numeri sono uguali nella console del browser, nella shell del nodo o in altri interpreti JavaScript. Basta confrontarli:

 > 0.014999999999999999 === 0.0150000000000000001 true 

Quindi quando scrivo m = 0.0150000000000000001 , il valore esatto di m cui ottengo è più vicino a 0.01 che a 0.02 . Eppure, se converto m in una stringa …

 > var m = 0.0150000000000000001; > console.log(String(m)); 0.015 > var m = 0.014999999999999999; > console.log(String(m)); 0.015 

… Ottengo 0,015, che dovrebbe arrotondare a 0,02, e che non è notoriamente il numero di 56 decimali che ho detto prima che tutti questi numeri erano esattamente uguali a. Quindi cos’è la magia oscura?

La risposta può essere trovata nella specifica ECMAScript, nella sezione 7.1.12.1: ToString applicato al tipo Numero . Qui vengono stabilite le regole per convertire alcuni numeri m in una stringa. La parte fondamentale è il punto 5, in cui viene generato un intero s le cui cifre saranno utilizzate nella rappresentazione String di m :

sia n , k , e s siano interi tali che k ≥ 1, 10 k -1s <10 k , il valore numerico per s × 10 nk sia m , e k sia il più piccolo ansible. Si noti che k è il numero di cifre nella rappresentazione decimale di s , che s non è divisibile per 10 e che la cifra meno significativa di s non è necessariamente determinata in modo univoco da questi criteri.

La parte chiave qui è il requisito che ” k è il più piccolo ansible”. Ciò che tale requisito equivale a è un requisito che, dato un numero m , il valore di String(m) deve avere il minor numero ansible di cifre pur soddisfacendo il requisito di Number(String(m)) === m . Poiché sappiamo già che 0.015 === 0.0150000000000000001 , ora è chiaro il motivo per cui String(0.0150000000000000001) === '0.015' deve essere vero.

Naturalmente, nessuna di queste discussioni ha risposto direttamente a ciò che roundTo2DP(m) dovrebbe restituire. Se il valore esatto di m è 0,01499999999999999944488848768742172978818416595458984375, ma la sua rappresentazione di stringa è ‘0,015’, qual è la risposta corretta – matematicamente, praticamente, filosoficamente o altro – quando lo arrotondiamo a due cifre decimali?

Non esiste un’unica risposta corretta a questo. Dipende dal tuo caso d’uso. Probabilmente vorresti rispettare la rappresentazione String e arrotondare verso l’alto quando:

  • Il valore rappresentato è intrinsecamente discreto, ad esempio una quantità di valuta in una valuta con 3 decimali come i dinari. In questo caso, il valore reale di un numero come 0,015 è 0,015 e la rappresentazione 0,0149999999 … che ottiene in virgola mobile binario è un errore di arrotondamento. (Naturalmente, molti sostengono, ragionevolmente, che si dovrebbe usare una libreria decimale per gestire tali valori e non rappresentarli mai come numeri in virgola mobile binari in primo luogo.)
  • Il valore è stato digitato da un utente. In questo caso, di nuovo, il numero decimale esatto inserito è più “vero” della rappresentazione in virgola mobile binario più vicina.

D’altra parte, probabilmente si desidera rispettare il valore in virgola mobile binario e arrotondare verso il basso quando il valore è da una scala intrinsecamente continua, ad esempio, se si tratta di una lettura da un sensore.

Questi due approcci richiedono un codice diverso. Per rispettare la rappresentazione String del Numero, possiamo (con un po ‘di codice ragionevolmente sottile) implementare il nostro arrotondamento che agisce direttamente sulla rappresentazione String, cifra per cifra, usando lo stesso algoritmo che avresti usato a scuola quando è stato insegnato come arrotondare i numeri. Di seguito è riportato un esempio che rispetta il requisito dell’OP di rappresentare il numero in 2 posizioni decimali “solo quando necessario” eliminando gli zero finali dopo il punto decimale; puoi, naturalmente, aver bisogno di adattarlo alle tue esigenze precise.

 /** * Converts num to a decimal string (if it isn't one already) and then rounds it * to at most dp decimal places. * * For explanation of why you'd want to perform rounding operations on a String * rather than a Number, see http://stackoverflow.com/a/38676273/1709587 * * @param {(number|string)} num * @param {number} dp * @return {string} */ function roundStringNumberWithoutTrailingZeroes (num, dp) { if (arguments.length != 2) throw new Error("2 arguments required"); num = String(num); if (num.indexOf('e+') != -1) { // Can't round numbers this large because their string representation // contains an exponent, like 9.99e+37 throw new Error("num too large"); } if (num.indexOf('.') == -1) { // Nothing to do return num; } var parts = num.split('.'), beforePoint = parts[0], afterPoint = parts[1], shouldRoundUp = afterPoint[dp] >= 5, finalNumber; afterPoint = afterPoint.slice(0, dp); if (!shouldRoundUp) { finalNumber = beforePoint + '.' + afterPoint; } else if (/^9+$/.test(afterPoint)) { // If we need to round up a number like 1.9999, increment the integer // before the decimal point and discard the fractional part. finalNumber = Number(beforePoint)+1; } else { // Starting from the last digit, increment digits until we find one // that is not 9, then stop var i = dp-1; while (true) { if (afterPoint[i] == '9') { afterPoint = afterPoint.substr(0, i) + '0' + afterPoint.substr(i+1); i--; } else { afterPoint = afterPoint.substr(0, i) + (Number(afterPoint[i]) + 1) + afterPoint.substr(i+1); break; } } finalNumber = beforePoint + '.' + afterPoint; } // Remove trailing zeroes from fractional part before returning return finalNumber.replace(/0+$/, '') } 

Esempio di utilizzo:

 > roundStringNumberWithoutTrailingZeroes(1.6, 2) '1.6' > roundStringNumberWithoutTrailingZeroes(10000, 2) '10000' > roundStringNumberWithoutTrailingZeroes(0.015, 2) '0.02' > roundStringNumberWithoutTrailingZeroes('0.015000', 2) '0.02' > roundStringNumberWithoutTrailingZeroes(1, 1) '1' > roundStringNumberWithoutTrailingZeroes('0.015', 2) '0.02' > roundStringNumberWithoutTrailingZeroes(0.01499999999999999944488848768742172978818416595458984375, 2) '0.02' > roundStringNumberWithoutTrailingZeroes('0.01499999999999999944488848768742172978818416595458984375', 2) '0.01' 

La funzione sopra riportata è probabilmente quella che si desidera utilizzare per evitare che gli utenti possano mai verificare che i numeri inseriti non vengano arrotondati correttamente.

(In alternativa, si potrebbe anche provare la libreria round10 che fornisce una funzione che si comporta in modo simile con un’implementazione completamente diversa.)

Ma cosa succede se si ha il secondo tipo di numero – un valore preso da una scala continua, dove non c’è motivo di pensare che le rappresentazioni decimali approssimate con meno cifre decimali siano più accurate di quelle con più? In tal caso, non vogliamo rispettare la rappresentazione String, perché quella rappresentazione (come spiegato nella specifica) è già sorta di arrotondamento; non vogliamo commettere l’errore di dire “0,014999999 … 375 round fino a 0,015, che arrotonda fino a 0,02, quindi 0,014999999 … 375 round fino a 0,02”.

Qui possiamo semplicemente usare il metodo built-in toFixed . Si noti che chiamando Number() sulla String restituita toFixed , otteniamo un Numero la cui rappresentazione di Stringa non ha zero finali (grazie al modo in cui JavaScript calcola la rappresentazione String di un Numero, discussa in precedenza in questa risposta).

 /** * Takes a float and rounds it to at most dp decimal places. For example * * roundFloatNumberWithoutTrailingZeroes(1.2345, 3) * * returns 1.234 * * Note that since this treats the value passed to it as a floating point * number, it will have counterintuitive results in some cases. For instance, * * roundFloatNumberWithoutTrailingZeroes(0.015, 2) * * gives 0.01 where 0.02 might be expected. For an explanation of why, see * http://stackoverflow.com/a/38676273/1709587. You may want to consider using the * roundStringNumberWithoutTrailingZeroes function there instead. * * @param {number} num * @param {number} dp * @return {number} */ function roundFloatNumberWithoutTrailingZeroes (num, dp) { var numToFixedDp = Number(num).toFixed(dp); return Number(numToFixedDp); } 

Considerare .toFixed() e .toPrecision() :

http://www.javascriptkit.com/javatutors/formatnumber.shtml

Ecco un modo semplice per farlo:

 Math.round(value * 100) / 100 

Potresti voler andare avanti e creare una funzione separata per farlo per te:

 function roundToTwo(value) { return(Math.round(value * 100) / 100); } 

Quindi devi semplicemente passare il valore.

Potresti potenziarlo per arrotondare a qualsiasi numero arbitrario di decimali aggiungendo un secondo parametro.

 function myRound(value, places) { var multiplier = Math.pow(10, places); return (Math.round(value * multiplier) / multiplier); } 
 +(10).toFixed(2); // = 10 +(10.12345).toFixed(2); // = 10.12 (10).toFixed(2); // = 10.00 (10.12345).toFixed(2); // = 10.12 

Dovresti usare:

 Math.round( num * 100 + Number.EPSILON ) / 100 

Nessuno sembra essere a conoscenza di Number.EPSILON .

Vale anche la pena notare che questa non è una stranezza JavaScript, come hanno affermato alcune persone.

Questo è semplicemente il modo in cui i numeri in virgola mobile funzionano in un computer. Come il 99% dei linguaggi di programmazione, JavaScript non ha numeri in virgola mobile fatti in casa ; per questo si basa sulla CPU / FPU. Un computer usa il binario e, in binario, non ci sono numeri come 0.1 , ma una semplice approssimazione binaria per quello. Perché? Per lo stesso motivo di 1/3 non può essere scritto in decimale: il suo valore è 0,33333333 … con un numero infinito di tre.

Ecco come Number.EPSILON . Quel numero è la differenza tra 1 e il numero successivo esistente nei numeri in virgola mobile a doppia precisione. Ecco fatto: non c’è numero tra 1 e 1 + Number.EPSILON .

MODIFICARE:

Come richiesto nei commenti, chiariamo una cosa: l’aggiunta di Number.EPSILON è rilevante solo quando il valore da arrotondare è il risultato di un’operazione aritmetica, poiché può ingoiare delta di errore in virgola mobile.

Non è utile quando il valore proviene da una fonte diretta (es .: letterale, input dell’utente o sensore).

2017
Basta usare il codice nativo .toFixed()

 number = 1.2345; number.toFixed(2) // "1.23" 

Se è necessario essere severi e aggiungere cifre solo se necessario, è ansible utilizzare replace

 number = 1; // "1" number.toFixed(5).replace(/\.?0*$/g,''); 

Prova questa soluzione leggera :

 function round(x, digits){ return parseFloat(x.toFixed(digits)) } round(1.222, 2) ; // 1.22 round(1.222, 10) ; // 1.222 

There are a couple of ways to do that. For people like me, the Lodash’s variant

 function round(number, precision) { var pair = (number + 'e').split('e') var value = Math.round(pair[0] + 'e' + (+pair[1] + precision)) pair = (value + 'e').split('e') return +(pair[0] + 'e' + (+pair[1] - precision)) } 

Uso:

 round(0.015, 2) // 0.02 round(1.005, 2) // 1.01 

If your project uses jQuery or lodash, you can also find proper round method in the libraries.

Update 1

I removed the variant n.toFixed(2) , because it is not correct. Thank you @avalanche1

MarkG and Lavamantis offered a much better solution than the one that has been accepted. It’s a shame they don’t get more upvotes!

Here is the function I use to solve the floating point decimals issues also based on MDN . It is even more generic (but less concise) than Lavamantis’s solution:

 function round(value, exp) { if (typeof exp === 'undefined' || +exp === 0) return Math.round(value); value = +value; exp = +exp; if (isNaN(value) || !(typeof exp === 'number' && exp % 1 === 0)) return NaN; // Shift value = value.toString().split('e'); value = Math.round(+(value[0] + 'e' + (value[1] ? (+value[1] + exp) : exp))); // Shift back value = value.toString().split('e'); return +(value[0] + 'e' + (value[1] ? (+value[1] - exp) : -exp)); } 

Use it with:

 round(10.8034, 2); // Returns 10.8 round(1.275, 2); // Returns 1.28 round(1.27499, 2); // Returns 1.27 round(1.2345678e+2, 2); // Returns 123.46 

Compared to Lavamantis’s solution, we can do…

 round(1234.5678, -2); // Returns 1200 round("123.45"); // Returns 123 

For me Math.round() was not giving correct answer. I found toFixed(2) works better. Below are examples of both:

 console.log(Math.round(43000 / 80000) * 100); // wrong answer console.log(((43000 / 80000) * 100).toFixed(2)); // correct answer 
 var roundUpto = function(number, upto){ return Number(number.toFixed(upto)); } roundUpto(0.1464676, 2); 

toFixed(2) here 2 is number of digits upto which we want to round this num.

This may help you:

 var result = (Math.round(input*100)/100); 

for more information, you can have a look at this link

Math.round(num) vs num.toFixed(0) and browser inconsistencies

If you are using lodash library, you can use the round method of lodash like following.

 _.round(number, precision) 

Per esempio:

 _.round(1.7777777, 2) = 1.78 

Easiest way:

+num.toFixed(2)

It converts it to a string, and then back into an integer / float.

Here is a prototype method:

 Number.prototype.round = function(places){ places = Math.pow(10, places); return Math.round(this * places)/places; } var yournum = 10.55555; yournum = yournum.round(2); 

It may work for you,

 Math.round(num * 100)/100; 

to know the difference between toFixed and round. You can have a look at Math.round(num) vs num.toFixed(0) and browser inconsistencies .

If you happen to already be using the d3 library, they have a powerful number formatting library: https://github.com/mbostock/d3/wiki/Formatting

Rounding specifically is here: https://github.com/mbostock/d3/wiki/Formatting#d3_round

In your case, the answer is:

 > d3.round(1.777777, 2) 1.78 > d3.round(1.7, 2) 1.7 > d3.round(1, 2) 1 

One way to achieve such a rounding only if necessary is to use Number.prototype.toLocaleString() :

 myNumber.toLocaleString('en', {maximumFractionDigits:2, useGrouping:false}) 

This will provide exactly the output you expect, but as strings. You can still convert those back to numbers if that’s not the data type you expect.

A simpler ES6 way is

 const round = (x, n) => parseFloat(Math.round(x * Math.pow(10, n)) / Math.pow(10, n)).toFixed(n); 

This pattern also returns the precision asked for.

ex:

 round(44.7826456, 4) // yields 44.7826 round(78.12, 4) // yields 78.1200 

Use something like this “parseFloat(parseFloat(value).toFixed(2))”

 parseFloat(parseFloat("1.7777777").toFixed(2))-->1.78 parseFloat(parseFloat("10").toFixed(2))-->10 parseFloat(parseFloat("9.1").toFixed(2))-->9.1 

I’ll add one more approach to this.

 number = 16.6666666; console.log(parseFloat(number.toFixed(2))); "16.67" number = 16.6; console.log(parseFloat(number.toFixed(2))); "16.6" number = 16; console.log(parseFloat(number.toFixed(2))); "16" 

.toFixed(2) returns a string with exactily 2 decimal points, that may or may not be trailing zeros. Doing a parseFloat() will eliminate those trailing zeros.

This is the simplest, more elegant solution (and I am the best of the world;):

 function roundToX(num, X) { return +(Math.round(num + "e+"+X) + "e-"+X); } //roundToX(66.66666666,2) => 66.67 //roundToX(10,2) => 10 //roundToX(10.904,2) => 10.9 

Since ES6 there is a ‘proper’ way (without overriding statics and creating workarounds) to do this by using toPrecision

 var x = 1.49999999999; console.log(x.toPrecision(4)); console.log(x.toPrecision(3)); console.log(x.toPrecision(2)); var y = Math.PI; console.log(y.toPrecision(6)); console.log(y.toPrecision(5)); console.log(y.toPrecision(4)); var z = 222.987654 console.log(z.toPrecision(6)); console.log(z.toPrecision(5)); console.log(z.toPrecision(4));