Javascript: formattazione di un numero arrotondato in N decimali


104

in JavaScript, il modo tipico per arrotondare un numero a N cifre decimali è qualcosa del tipo:

function roundNumber(num, dec) {
  return Math.round(num * Math.pow(10, dec)) / Math.pow(10, dec);
}

Tuttavia, questo approccio arrotonderà a un massimo di N cifre decimali mentre voglio sempre arrotondare a N cifre decimali. Ad esempio "2.0" verrebbe arrotondato a "2".

Qualche idea?


9
normalmente, potresti usare toFixed()( developer.mozilla.org/En/Core_JavaScript_1.5_Reference/… ), ma è bacato in IE: stackoverflow.com/questions/661562/… ; dovrai scrivere la tua versione ...
Christoph

1
@hoju - forse cambia la risposta accettata - La risposta di David è corretta per IE8 +, mentre la risposta accettata ha alcuni bug seri su tutti i browser.
robocat

@robocat: dici sul serio?
Guffa

Risposte:


25

Questo non è un problema di arrotondamento, è un problema di visualizzazione. Un numero non contiene informazioni sulle cifre significative; il valore 2 è uguale a 2.0000000000000. È quando trasformi il valore arrotondato in una stringa che devi fargli visualizzare un certo numero di cifre.

Potresti semplicemente aggiungere zeri dopo il numero, qualcosa come:

var s = number.toString();
if (s.indexOf('.') == -1) s += '.';
while (s.length < s.indexOf('.') + 4) s += '0';

(Si noti che ciò presuppone che le impostazioni internazionali del client utilizzino il punto come separatore decimale, il codice necessita di ulteriore lavoro per funzionare per altre impostazioni.)


3
toFixed è bacato..per esempio il decimale: 1.02449999998 se dec.toFixed (4) => 1.0244. Dovrebbe essere invece 1.0245.
Bat_Programmer

2
@deepeshk Ma quale sarebbe il problema utilizzando toFixed()per riempire i decimali alla fine, dopo l'arrotondamento?
pauloya

10
@deepeshk in quale browser? Ho appena provato in Chrome 17 e 1.02449999998.toFixed(4)ritorna correttamente 1.0245.
Matt Ball

3
@MarkTomlin: Allora sembra che tu abbia una stringa invece di un numero.
Guffa

1
.toFixed () funziona brillantemente nei browser moderni (ho testato Chrome, Firefox, IE11, IE8). @Bat_Programmer - chiarisci quali browser ritieni abbiano quel bug.
robocat

243

Penso che ci sia un approccio più semplice a tutti quelli dati qui, ed è il metodo Number.toFixed()già implementato in JavaScript.

scrivi semplicemente:

var myNumber = 2;

myNumber.toFixed(2); //returns "2.00"
myNumber.toFixed(1); //returns "2.0"

eccetera...


Dove viene menzionato, hoju? Ho esaminato altre risposte e non ho trovato nessuno che abbia segnalato che la funzione toFixed è difettosa. Grazie
David

@ David: è menzionato in un commento alla risposta, per esempio.
Guffa

13
attenzione: toFixed()restituisce una stringa.
Jordan Arseno

2
@JordanArseno questo può essere risolto usando parseInt (myNumber.toFixed (intVar)); per restituire un valore intero o parseFloat (myNumber.toFixed (floatVar)); per restituire un float se l'utente ha posizioni decimali.
Stephen Romero

50

Ho trovato un modo. Questo è il codice di Christoph con una correzione:

function toFixed(value, precision) {
    var precision = precision || 0,
        power = Math.pow(10, precision),
        absValue = Math.abs(Math.round(value * power)),
        result = (value < 0 ? '-' : '') + String(Math.floor(absValue / power));

    if (precision > 0) {
        var fraction = String(absValue % power),
            padding = new Array(Math.max(precision - fraction.length, 0) + 1).join('0');
        result += '.' + padding + fraction;
    }
    return result;
}

Leggi i dettagli sulla ripetizione di un carattere usando un costruttore di array qui se sei curioso di sapere perché ho aggiunto il "+ 1".


Passare un valore di 708.3333333333333 con una precisione di 2 o 3 si traduce in un valore di ritorno di 708,00 per me. Ho bisogno di questo per 2 cifre decimali, in Chrome e IE 9 .toFixed (2) ha soddisfatto le mie esigenze.
alan

questo non è un modo comune, ad esempio, toFixed (16.775, 2) restituisce 16.77. Converti un numero in String e poi converti è l'unico modo.
autostrada

2
C'è un bug con questo metodo: toFixed (-0.1111, 2) restituisce 0.11, cioè il segno negativo è perso.
Matt

Funziona alla grande, tranne per il fatto che ho aggiunto parseFloat (risultato) alla fine. Merita una modifica.
Artur Barseghyan

16

C'è sempre un modo migliore per fare le cose.

var number = 51.93999999999761;

Vorrei ottenere una precisione di quattro cifre: 51,94

basta fare:

number.toPrecision(4);

il risultato sarà: 51.94


2
E se aggiungi 100? È necessario cambiarlo in number.toPrecision (5)?
JohnnyBizzle

2
Sì. 31.939383.toPrecision (4)> "31.94" / 131.939383.toPrecision (4)> "131.9"
ReSpawN

6

Metodo di arrotondamento simile a PHP

Il codice seguente può essere utilizzato per aggiungere la propria versione di Math.round al proprio spazio dei nomi che accetta un parametro di precisione. A differenza dell'arrotondamento decimale nell'esempio sopra, non esegue alcuna conversione da e verso stringhe e il parametro di precisione funziona allo stesso modo di PHP ed Excel, in cui un 1 positivo arrotonda a 1 cifra decimale e -1 alle decine.

var myNamespace = {};
myNamespace.round = function(number, precision) {
    var factor = Math.pow(10, precision);
    var tempNumber = number * factor;
    var roundedTempNumber = Math.round(tempNumber);
    return roundedTempNumber / factor;
};

myNamespace.round(1234.5678, 1); // 1234.6
myNamespace.round(1234.5678, -1); // 1230

dal riferimento per sviluppatori Mozilla per Math.round ()


2

Si spera che il codice funzioni (non ha fatto molti test):

function toFixed(value, precision) {
    var precision = precision || 0,
        neg = value < 0,
        power = Math.pow(10, precision),
        value = Math.round(value * power),
        integral = String((neg ? Math.ceil : Math.floor)(value / power)),
        fraction = String((neg ? -value : value) % power),
        padding = new Array(Math.max(precision - fraction.length, 0) + 1).join('0');

    return precision ? integral + '.' +  padding + fraction : integral;
}

Il tuo codice ha un bug. Ho provato a Risolto (2.01, 4) e ho ottenuto un risultato di "2.100". Se mai dovessi trovare un modo per risolverlo, lo posterò come risposta a questa domanda.
Elias Zamaria

@ mikez302: il calcolo del padding era sbagliato di uno; dovrebbe funzionare ora, ma sentiti libero di infastidirmi di nuovo se è ancora rotto ...
Christoph

Molto strano. Quando eseguo questa funzione con la console Firebug aperta in Firefox 17, si blocca l'intero browser come se js fosse catturato in un ciclo infinito. Anche se non console.log l'output. Se non ho Firebug attivato il bug non si verifica.
SublymeRick

1
Update, l'ho eseguito in chrome e ottengo: Uncaught RangeError: la dimensione massima dello stack di chiamate è stata superata rispetto alla chiamata della funzione toFixed.
SublymeRick

@SublymeRick: non ho idea del perché questo accada; girato nel buio: prova a rinominare la funzione ...
Christoph

2

Penso che sotto la funzione possa aiutare

function roundOff(value,round) {
   return (parseInt(value * (10 ** (round + 1))) - parseInt(value * (10 ** round)) * 10) > 4 ? (((parseFloat(parseInt((value + parseFloat(1 / (10 ** round))) * (10 ** round))))) / (10 ** round)) : (parseFloat(parseInt(value * (10 ** round))) / ( 10 ** round));
}

utilizzo: roundOff(600.23458,2);tornerà600.23


2

Questo funziona per l'arrotondamento a N cifre (se vuoi solo troncare a N cifre rimuovi la chiamata Math.round e usa quella Math.trunc):

function roundN(value, digits) {
   var tenToN = 10 ** digits;
   return /*Math.trunc*/(Math.round(value * tenToN)) / tenToN;
}

Ho dovuto ricorrere a tale logica in Java in passato quando stavo creando componenti E-Slate per la manipolazione dei dati . Questo da quando ho scoperto che aggiungendo 0.1 molte volte a 0 si otterrebbe una parte decimale inaspettatamente lunga (questo è dovuto all'aritmetica in virgola mobile).

Un commento dell'utente al numero di formato per mostrare sempre 2 cifre decimali chiama questa tecnica di ridimensionamento.

Alcuni menzionano che ci sono casi che non vengono arrotondati come previsto e su http://www.jacklmoore.com/notes/rounding-in-javascript/ viene invece suggerito:

function round(value, decimals) {
  return Number(Math.round(value+'e'+decimals)+'e-'+decimals);
}

btw, POSITS sono promettenti per le future architetture h / w: nextplatform.com/2019/07/08/…
George Birbilis

-2

Se non ti interessa davvero l'arrotondamento, aggiungi semplicemente un toFixed (x) e quindi rimuovi gli 0 finali e il punto se necessario. Non è una soluzione rapida.

function format(value, decimals) {
    if (value) {
        value = value.toFixed(decimals);            
    } else {
        value = "0";
    }
    if (value.indexOf(".") < 0) { value += "."; }
    var dotIdx = value.indexOf(".");
    while (value.length - dotIdx <= decimals) { value += "0"; } // add 0's

    return value;
}

Ho provato format(1.2, 5)e ottenuto 1.2, mentre me lo aspettavo 1.20000.
Elias Zamaria

Scusa @EliasZamaria, all'inizio non l'ho capito. Ho modificato il post. Tieni presente che restituirà "0,0000" quando il valore non è definito.
Juan Carrey
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.