2010-06-21 9 views
9

In php, abbiamo number_format(). Passando un valore come ad esempio:javascript arrotondare correttamente fino a due decimali, impossibile?

number_format(3.00 * 0.175, 2); 

rendimenti 0.53, che è quello che mi aspetterei.

Tuttavia, in JavaScript utilizzando toFixed()

var num = 3.00 * 0.175; 
num.toFixed(2); 

rendimenti 0,52.

Ok, quindi forse toFixed non è quello che voglio ... Forse qualcosa di simile ...

var num = 3.17 * 0.175; 
var dec = 2; 
Math.round(Math.round(num * Math.pow(10, dec + 1))/Math.pow(10, 1))/Math.pow(10,dec); 

No, che non funziona neanche. Restituirà 0,56.

Come posso ottenere una funzione number_format in JavaScript che non fornisce una risposta errata?

In realtà ho trovato un'implementazione di number_format per js, http://phpjs.org/functions/number_format, ma soffre dello stesso problema.

Cosa sta succedendo qui con l'arrotondamento di JavaScript? Cosa mi manca?

+1

In PHP, si sta facendo 3.00 * 0.175, nel proprio JavaScript 3.17 * 0.175 .. –

+0

Lauri: 3,17 * 0,175 deve restituire 0,55, non 0,56, che è il problema. – Gabe

+0

Benvenuti in Stack Overflow, ottima prima domanda. –

risposta

12

JavaScript funziona male con i numeri in virgola mobile (come fanno molte altre lingue).

Quando eseguo

3.000 * 0.175 

Nel mio browser, ricevo

0.5249999999999999 

che non arrotondare fino a 0.525 con Math.round. Per aggirare questo problema, è necessario moltiplicare entrambi i lati fino a quando non si ottiene che siano interi (relativamente facile, sapendo che alcuni trucchi aiutano però).

Quindi, per fare questo si può dire qualcosa di simile:

function money_multiply (a, b) { 
    var log_10 = function (c) { return Math.log(c)/Math.log(10); }, 
     ten_e = function (d) { return Math.pow(10, d); }, 
     pow_10 = -Math.floor(Math.min(log_10(a), log_10(b))) + 1; 
    return ((a * ten_e(pow_10)) * (b * ten_e(pow_10)))/ten_e(pow_10 * 2); 
} 

Questo può sembrare tipo di funky, ma ecco qualche pseudo-codice:

get the lowest power of 10 of the arguments (with log(base 10)) 
add 1 to make positive powers of ten (covert to integers) 
multiply 
divide by conversion factor (to get original quantities) 

Spero che questo è quello che stai cercando per. Ecco un esempio di esecuzione:

3.000 * 0.175 
0.5249999999999999 

money_multiply(3.000, 0.175); 
0.525 
+0

Grazie, sì questo è esattamente quello che mi mancava. La matematica in virgola mobile mi ha confuso :) – Bob

+0

Sì, ho dovuto usare la conoscenza del liceo/college per questo, ahahah. –

+0

btw, capito Math.log è la base di e, non 10, corretto per riferimento futuro –

0

Perché non hai appena utilizzato Math.round(num * Math.pow(10, dec))/Math.pow(10, dec))?

EDIT: Vedo, il problema è che 3 * 0.175 ti dà 0,52499999999999991, che ti porta a volere un ulteriore arrotondamento. Forse solo l'aggiunta di una piccola quantità avrebbe funzionato:

Math.round(num * Math.pow(10, dec) + 0.000000001)/Math.pow(10, dec))

+0

In realtà l'ho provato, ma ha anche restituito risultati errati. E.g 3,00 * 0,175 = 0,52. L'espressione che ho usato è stato un bizzarro tentativo di cercare di costringerlo a dare la risposta giusta, ma non ha funzionato :) – Bob

3

La funzione toFixed funziona correttamente. Tronca oltre la quantità specificata di cifre della frazione.

1

Penso che il problema riscontrato sia con la matematica in virgola mobile rispetto all'arrotondamento stesso.

Utilizzando la console firebug per il test, registrare il risultato di 3.00 * 0.175 dato 0.524999.... Quindi arrotondare questo numero è in realtà corretto.

Non so se esiste una buona soluzione al problema, ma secondo la mia esperienza quando si lavora con la valuta: è più semplice lavorare nell'unità più piccola (centesimi) e quindi convertire per la visualizzazione.

0

So che questo è vecchio ma questo è il modo in cui risolvo solitamente un problema di arrotondamento. Questo può essere messo in una funzione facilmente, ma per ora ho appena messo in vars semplici per adesso. Se questo non funziona potresti usare money_format() o number_format() come inizio da php.js (maggiori informazioni di seguito).

var n = (3.00 * 0.175); 
n = Math.round(n * Math.pow(10, 3))/Math.pow(10, 3); 
Math.round(n*100)/100; 

esce a 0,53 (0,5249999999999999)

var n = (3.00 * 0.175); 
n = Math.round(n * Math.pow(10, 3))/Math.pow(10, 3); 
Math.round(n*100)/100; 

esce a 0,56 (0,55475)

Sembra inoltre che il php.js pronti contro termine viene mantenuto su GitHub https://github.com/kvz/phpjs quindi se non c'è una funzione che non sta funzionando correttamente può essere presentato un problema.

Comunque capito queste informazioni possono aiutare qualcuno che cerca in seguito.

3

Perché tutti i poteri ?? Perché non basta aggiungere un po 'less than 1/2 a cent e round:

(3.00 * 0.175 + 0.0049).toFixed(2)

mai avuto alcun commercialisti lamentano l'uscita.

+0

L'approccio di mezzo penny sembra sempre di arrotondare. Dato che mi piacerebbe arrotondare a metà, meno della metà, ho confrontato una serie di numeri contro [mozilla] (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/round). Ecco un confronto dei risultati. [Violino] (https://jsfiddle.net/ledlogic/24a9tkrz/). – ledlogic