2015-05-14 7 views
7

che sto affrontando un problema con la funzione Math.floor di javascript per lo scenario di seguito:problema Javascript Math.floor tra specifico intervallo di numeri

1) dal valore betwwen 8192 e 10484,

if I type 8192.8 -> The Math.floor converts it into 8192.79 

    if I type 8192.88 -> The Math.floor converts it into 8192.87 

    if I type 8192.3 -> The Math.floor converts it into 8192.29 

Stranamente è che, tranne nell'intervallo sopra indicato, la funzione funziona correttamente.

HTML: 
<div data-bind="text: popIncrease"></div> 
<input type="text" data-bind="value: userInput, valueUpdate: 'afterkeydown'" /> 

Javascript: 

var ViewModel = function() { 
var _self = this; 
_self.userInput = ko.observable(); 
_self.popIncrease = ko.computed(function() { 

     return parseFloat((Math.floor(_self.userInput() * 100)/100)).toFixed(2); 
}); 
}; 

ko.applyBindings(new ViewModel()); 

jsfiddle: https://jsfiddle.net/91z5bdy4/1/

Quando ho cambiato 100 con 1000 ha risolto l'errore, ma non capisco il motivo per cui questo è accaduto al primo posto?

+3

possibile duplicato di [Is matematica in virgola mobile rotta?] (http://stackoverflow.com/questions/588004/is-floating-point-math-broken) – suish

+0

In realtà non ha nulla fare con knockout o jquery. Cosa stai cercando di fare? Sembra che tu voglia arrotondare un numero a 2 cifre decimali, quindi visualizzarlo con 2 posizioni decimali. Il passaggio di un numero a * parseFloat * è ridondante (è già un numero). Un'espressione non dovrebbe essere racchiusa tra parentesi quadre come '((...))', un set è ridondante. Perché non 'return parseFloat (_self.userInput()). ToFixed (2)'? – RobG

+0

8192,8 * 100 === 819279,999999999, buona fortuna con aritmetica in virgola mobile. – floribon

risposta

0

L'ordine del piano/analisi sembra fuori posto per me.

Prova:

return Math.floor(parseFloat(_self.userInput())).toFixed(2); 

Anche se essere consapevoli che 1,999999999999999999999999999999 dà 2.00 utilizzando il sopra; questo perché i numeri in virgola mobile non sono in grado di rappresentare tutti i valori con precisione.

+0

1.999999999 restituisce 2.00 perché '.toFixed (2)' arrotonda a due cifre decimali. Ci sono problemi con la precisione in virgola mobile, ma il tuo esempio non è dove entra in gioco. – jfriend00

+0

@ jfriend00 Probabilmente ha più a che fare con 'parseFloat (" 1.9999999999999999999999999 ") === 2' è' true'. – Paul

+0

@ Paul-and '(1.999) .toFixed (2) === '2.00''. ;-) – RobG

1

Si può solo passare a questo:

return parseFloat(_self.userInput()).toFixed(2); 

versione del jsFiddle di lavoro: https://jsfiddle.net/jfriend00/5rLL04Lk/


Oppure, se si vuole risolvere alcune delle idiosincrasie di .toFixed(), è possibile utilizzare this:

return (Math.round(_self.userInput() * 100)/100).toFixed(2); 

Lavoro jsFiddle: https://jsfiddle.net/jfriend00/xx2aj2L0/

Questa soluzione supera tutti e tre i casi di test.

+0

Tranne che l'arrotondamento in * toFixed * è buggy ... '(3.335) .toFixed (2)' fornisce '3.33' dove potrebbe essere previsto '3.34'. – RobG

+0

@RobG - ha offerto un'altra soluzione che funziona attorno alla stranezza '.toFixed (2)'. – jfriend00

+0

Ovviamente c'è ancora l'antico bug nell'implementazione di IE in * toFixed * (jScript 5.8), ma forse è stato risolto ora. ;-) – RobG

1

Non è il Math.floor() che causa il problema, è l'inesattezza dell'aritmetica in virgola mobile. Quando moltiplichi 8192.8 per 100, ottieni 819279.9999999999.

Forse si dovrebbe solo manipolare come una stringa:

function floorString(str) { 
    var pos = str.indexOf('.'); 
    return (pos >= 0) ? ((str + '00').slice(0, pos + 3)) : (str + '.00'); 
} 

jsfiddle

+0

E l'arrotondamento avviene ...? – RobG

+1

@RobG - Sto interpretando male la domanda? Sembra che l'OP stia solo troncando il numero, non arrotondando. –

+0

No, lo sono. :-) Supponevo che l'OP stesse cercando di arrotondare il numero, non solo di troncarlo in 2 punti. – RobG

0

un altro senza l'utilizzo di una funzione Math (2 linee senza formattazione)

function floorString(str) { 
    var matches = str.match(/([\d]+(\.[\d]{0,2}))/); 
    return matches === null || matches[2].length === 1 ? 
      (str + ".00").replace("..", ".") : 
      matches[2].length < 3 ? 
       matches[0] + "00".substr(3 - matches[2].length) : 
       matches[0]; 
}