Domanda

Perché 49.90 % 0.10 in JavaScript ritorno 0.09999999999999581? Mi aspettavo che fosse 0.

È stato utile?

Soluzione

A causa JavaScript utilizza matematica in virgola mobile, che sempre porta a errori di arrotondamento.

Se avete bisogno di un risultato esatto con due decimali, si moltiplicano i tuoi numeri con 100 prima dell'operazione e poi dividere di nuovo in seguito:

var result = ( 4990 % 10 ) / 100;

rotonda, se necessario.

Altri suggerimenti

Numero di Javascript sta usando "IEEE doppia precisione" per memorizzare i valori. Essi sono in grado di memorizzare tutti i numeri decimali esattamente. Il risultato non è zero perché di arrotondamento errore quando si converte il numero decimale in binario.

49.90 = 49.89999999999999857891452848...
 0.10 =  0.10000000000000000555111512...

Così piano (49.90 / 0.10) è solo 498, e il resto sarà 0,09,999 mila ....


Sembra che si stanno usando numeri di immagazzinare quantità di dollari. non farlo , come operazioni in virgola mobile diffondere e amplificare l'errore di arrotondamento. Memorizzare il numero come numero di centesimi , invece. Integer può essere rappresentato esattamente, e 4990 % 10 restituirà 0.

mi limiterò a lasciare questo qui per riferimento futuro, ma qui è una comoda funzione che può gestire più precisamente Resto (dal JS non ha un operatore modulo ) coinvolge galleggianti.

  function floatSafeRemainder(val, step){
    var valDecCount = (val.toString().split('.')[1] || '').length;
    var stepDecCount = (step.toString().split('.')[1] || '').length;
    var decCount = valDecCount > stepDecCount? valDecCount : stepDecCount;
    var valInt = parseInt(val.toFixed(decCount).replace('.',''));
    var stepInt = parseInt(step.toFixed(decCount).replace('.',''));
    return (valInt % stepInt) / Math.pow(10, decCount);
  }

$(function() {
  
  
  function floatSafeModulus(val, step) {
    var valDecCount = (val.toString().split('.')[1] || '').length;
    var stepDecCount = (step.toString().split('.')[1] || '').length;
    var decCount = valDecCount > stepDecCount ? valDecCount : stepDecCount;
    var valInt = parseInt(val.toFixed(decCount).replace('.', ''));
    var stepInt = parseInt(step.toFixed(decCount).replace('.', ''));
    return (valInt % stepInt) / Math.pow(10, decCount);
  }
  
  
  $("#form").submit(function(e) {
    e.preventDefault();
    var safe = 'Invalid';
    var normal = 'Invalid';
    var var1 = parseFloat($('#var1').val());
    var var2 = parseFloat($('#var2').val());
    if (!isNaN(var1) && !isNaN(var2)) {
      safe = floatSafeModulus(var1, var2);
      normal = var1 % var2
    }
    $('#safeResult').text(safe);
    $('#normalResult').text(normal);
  });
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<form id="form" novalidate>
  <div>
    <input type="number" id="var1">%
    <input type="number" id="var2">
  </div>
  <div>safe: <span id="safeResult"></span><div>
  <div>normal (%): <span id="normalResult"></span></div>
  <input type="submit" value="try it out">
</form>

Causa

virgola mobile non può memorizzare tutti i valori decimali esattamente. Così quando utilizzando formati virgola mobile ci sarà sempre errori di arrotondamento sui valori di ingresso. Gli errori sugli ingressi dei risultati del corso sugli errori sull'uscita. In caso di una funzione discreta o operatore ci può essere una grande differenza sull'uscita intorno al punto in cui la funzione o l'operatore è discreto. L'operatore Modula è discreto e il vostro caso è chiaramente un esempio di questo problema.

ingresso ed uscita per valori a virgola mobile

Così, quando si utilizza le variabili in virgola mobile, si dovrebbe sempre essere consapevoli di questo. E qualunque uscita che si desidera da un calcolo con virgola mobile deve sempre essere formattato / condizionata prima di visualizzare con questo in mente.
Quando sono utilizzati solamente funzioni e operatori continue, arrotondando alla precisione desiderata spesso farà (non troncamento). formattazione standard aspetti utilizzati per carri convertire in stringa di solito fare questo per voi.
Per avere un'uscita corretta sulla base di precisione previsto di ingressi e la precisione di output desiderato, si dovrebbe anche

  • ingressi rotonde alla precisione atteso o assicurarsi che nessun valore possono essere inseriti con maggiore precisione.
  • Inserisci piccolo valore alle uscite prima dell'arrotondamento / formattandoli che è minore o uguale a 1/4 della precisione desiderata e maggiore del massimo errore previsto causati da errori di arrotondamento sull'ingresso e durante il calcolo. Se ciò non è possibile la combinazione della precisione del tipo di dati utilizzato non è sufficiente per fornire la precisione di output desiderato per il calcolo.

Queste 2 cose sono spesso non fatto e in molti casi le differenze causate da non fare loro sono troppo piccoli per essere importante per la maggior parte degli utenti, ma ho già avuto un progetto in cui l'uscita non è stata accettata dagli utenti senza quelle correzioni.

funzioni o operatori (come Modula) discreti

Quando gli operatori discreti o funzioni sono coinvolti, le correzioni in più potrebbe essere richiesto per assicurarsi che l'uscita è come previsto. A completare e l'aggiunta di piccole correzioni prima di arrotondare non può risolvere il problema.
Uno speciale controllo / correzione del risultato dei calcoli intermedi, immediatamente dopo l'applicazione della funzione discreta o l'operatore potrebbe essere necessaria.

caso specifico di questa domanda

In questo caso, ci si aspetta di ingresso con una certa precisione, per cui è possibile uscita corretta per l'impatto di errori di arrotondamento che sono molto più piccola della precisione desiderata.

Se diciamo la precisione del tipo di dati è posta.
Il vostro contributo non sarà memorizzato come i valori di A e B si è entrato, ma come un * (1 +/- e) e b * (1 +/- e)
Il risultato di una divisione a * (1 +/- e) da b * (1 +/- e) comporterebbe (a / b) (1 +/- 2e).
La funzione Modula ha per troncare il risultato e moltiplicare di nuovo. Così il risultato sarà (a / b
b) (1 +/- 3e) = a (1 +/- 3e) con conseguente un errore di un 3e *.
Il mod aggiunge un * e per l'eventuale errore di un 3e * a causa della sottrazione di 2 valori con una possibile errori di un 3e * e * e.
Quindi, si dovrebbe verificare che l'errore totale possibile un 4e * è più piccolo della precisione desiderata e se tale condizione è soddisfatta e differisce risultato non più da b di tale errore massimo possibile, si può tranquillamente sostituirlo con 0.

Meglio evitare che il problema

Spesso è più efficace per evitare questi problemi utilizzando i tipi di dati (interi o formati di punto fisso) per i calcoli come questa che può memorizzare l'ingresso attendere senza errori di arrotondamento. Un esempio di questo è che non si dovrebbe mai usare valori in virgola mobile per i calcoli finanziari.

Date un'occhiata al punti galleggianti ed i suoi svantaggi - un numero come 0.1 non può essere salvato correttamente come virgola mobile, quindi ci sarà sempre tali problemi. Prendete i numeri * 10 o * 100 e fare i calcoli con numeri interi, invece.

http://en.wikipedia.org/wiki/Modulo_operation Non essere arrabbiato modulo viene utilizzato con gli interi ^^ Così galleggiante valori occure alcuni errori.

Questa non è una risposta perfetta, ma funziona.

function format_float_bug(num)
{
   return parseFloat( num.toFixed(15) ); 
} 

è possibile utilizzare come segue,

format_float_bug(4990 % 10);

perché sotto il numero (49,89999999999999857891452848) prima di 15 cifre decimali sono come 9999999

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top