Frage

Ich habe gehört, dass Sie könnte rechten verschieben, um eine Zahl von 0,5 anstelle von Math.floor (). Ich beschloss, seine Grenzen zu überprüfen, um sicherzustellen, dass es ein geeigneter Ersatz war, so überprüfte ich die folgenden Werte und bekam folgende Ergebnisse in Google Chrome:


2.5 >> .5 == 2;
2.9999 >> .5 == 2;
2.999999999999999 >> .5 == 2;  // 15 9s
2.9999999999999999 >> .5 == 3;  // 16 9s

Nach einiger Fummelei, fand ich heraus, dass der höchstmögliche Wert von zwei, das, wenn sie von 0,5 nach rechts verschoben, 2 ergeben würde, ist 2.9999999999999997779553950749686919152736663818359374999999¯ (mit den 9 Wiederholung) in Chrome und Firefox. Die Zahl ist 2.9999999999999997779¯ im Internet Explorer.

Meine Frage ist: Was ist die Bedeutung der Zahl .0000000000000007779553950749686919152736663818359374? Es ist eine sehr seltsame Zahl, und es reizte wirklich meine Neugier.

Ich habe versucht, eine Antwort oder zumindest eine Art von Mustern zu finden, aber ich denke, mein Problem liegt in der Tatsache, dass ich wirklich nicht verstehen, die bitweise Operation. Ich verstehe die Idee im Prinzip, aber von 0,5 ein Bitsequenz Verschiebung macht keinen Sinn überhaupt zu mir. Jede Hilfe ist willkommen.

Für die Aufzeichnung der seltsame Ziffernfolge ändert sich mit 2 ^ x. Die höchstmögliche Werte der folgenden Nummern, die noch richtig gestutzt:

for 0: 0.9999999999999999444888487687421729788184165954589843749¯
for 1: 1.9999999999999999888977697537484345957636833190917968749¯
for 2-3: x+.99999999999999977795539507496869191527366638183593749¯
for 4-7: x+.9999999999999995559107901499373838305473327636718749¯
for 8-15: x+.999999999999999111821580299874767661094665527343749¯
...and so forth
War es hilfreich?

Lösung

Eigentlich sind beenden Sie einfach bis machen einen Boden () auf dem ersten Operanden, ohne dass Gleitkommaoperationen geht. Da die Verschiebung nach links und rechten Shift-Bit-Operationen nur dann Sinn, mit ganzzahligen Operanden machen, wird der JavaScript-Engine, die zwei Operanden ganze Zahlen Umwandlung zuerst:

2.999999 >> 0.5

Wird:

Math.floor(2.999999) >> Math.floor(0.5)

Was wiederum ist:

2 >> 0

Verschiebung um 0 Bits bedeuten „nicht tun, eine Verschiebung“ und daher am Ende mit dem ersten Operanden auf, einfach abgeschnitten auf eine ganze Zahl.

Die Spider Quellcode hat:

switch (op) {
  case JSOP_LSH:
  case JSOP_RSH:
    if (!js_DoubleToECMAInt32(cx, d, &i)) // Same as Math.floor()
        return JS_FALSE;
    if (!js_DoubleToECMAInt32(cx, d2, &j)) // Same as Math.floor()
        return JS_FALSE;
    j &= 31;
    d = (op == JSOP_LSH) ? i << j : i >> j;
    break;

Ihr sehen eine „Aufrunden“ mit bestimmten Zahlen auf die Tatsache zurückzuführen ist, die JavaScript-Engine nicht Dezimalziffern über eine gewisse Präzision verarbeiten kann und somit Ihre Zahl endet immer auf die nächste ganze Zahl aufgerundet wird. Versuchen Sie dies in Ihrem Browser:

alert(2.999999999999999);

Sie werden 2,999999999999999 erhalten. Versuchen Sie nun eine weitere 9 fügt hinzu:

alert(2.9999999999999999);

Sie erhalten eine 3 bekommen.

Andere Tipps

Dies ist möglicherweise die einzige schlechteste Idee, die ich je gesehen habe. Es ist nur möglich Zweck existiert, ist für einen obfusticated Code Contest gewinnen. Es gibt keine Bedeutung für die langen Zahlen Sie auf dem Laufenden - sie sind ein Artefakt der zugrunde liegenden Floating-Point-Implementierung, durch gefilterte Gott weiß, wie viele Zwischenschichten. Bit-Verschiebung durch eine gebrochene Anzahl von Bytes ist verrückt und ich bin überrascht, dass es nicht eine Ausnahme ausgelöst -. Aber das ist Javascript, immer bereit, neu zu definieren „verrückt“

Wenn ich Sie wäre, würde ich vermeiden, jemals dieses „Feature“ mit. Sein einziger Wert ist als eine mögliche Ursache für einen ungewöhnlichen Fehlerzustand. Verwenden Sie Math.floor() und erbarme nächsten Programmierer, der den Code wird beibehalten.


bestätigt ein paar Verdacht hatte ich, als die Frage zu lesen:

  • Rechtsverschiebung jede gebrochene Zahl durch eine gebrochene Zahl x y einfach x, so dass das gleiche Ergebnis wie Math.floor() gestutzt, während gründlich den Leser verwirren.
  • 2,999999999999999777955395074968691915 ... ist einfach die größte Zahl, die von „3“ unterschieden werden kann. Probieren Sie es selbst Auswertung -. Wenn Sie etwas hinzufügen, wird es bis 3. bewerten Dies ist ein Artefakt des Browsers und lokalen Systems Floating-Point-Implementierung

Wenn Sie wollen tiefer gehen, lesen Sie „Was jeder Informatiker wissen sollten über Gleitkommaarithmetik“: http://docs.sun.com/source/806-3568/ncg_goldberg.html

Ich glaube nicht, Ihre Rechtsverschiebung ist relevant. Sie sind einfach über die Auflösung eines double precision floating point konstant.

In Chrome:

var x = 2.999999999999999777955395074968691915273666381835937499999;
var y = 2.9999999999999997779553950749686919152736663818359375;

document.write("x=" + x);
document.write(" y=" + y);

Druckt: x = 2,9999999999999996 y = 3

Versuchen Sie, diese Javascript-out:   alert (parseFloat ( "2,9999999999999997779553950749686919152736663818359374999999"));

Dann versuchen Sie dies:   alert (parseFloat ( "2,9999999999999997779553950749686919152736663818359375"));

Was Sie sehen, ist einfach Floating-Point-Ungenauigkeit. Weitere Informationen darüber finden Sie das zum Beispiel: http://en.wikipedia.org/wiki / FLOATING_POINT # Accuracy_problems .

Das Grundproblem ist, dass die am nächsten, die ein Gleitkommawert zu repräsentieren die zweite Zahl ist bekommen kann größer oder gleich 3 ist, wohingegen die schließt, dass der ein Schwimmer in der ersten Zahl erhalten kann, ist strikt kleiner als drei ist.

Was, warum rechts um 0,5 Verschiebung überhaupt etwas tut, gesund, scheint es, dass 0,5 nur selbst in einen int umgewandelt zu werden (0) vorher. Dann wird der ursprüngliche Schwimmer (2.999 ...) durch Abschneiden in einen int umgewandelt zu werden, wie üblich.

Die Verschiebung nach rechts Operator funktioniert nur auf ganze Zahlen (beiden Seiten). So soll Verschieben nach rechts von 0,5 Bits genau entspricht rechts von 0 Bits zu verschieben. Und die linke Seite auf eine ganze Zahl vor dem Schaltvorgang umgewandelt, das macht das Gleiche wie Math.floor ().

  

Ich vermute, dass die Umwandlung 2,9999999999999997779553950749686919152736663818359374999999   um es aufschlussreich wäre Darstellung binär ist. Es ist wahrscheinlich nur ein bisschen anders   von echten 3.

Gute Vermutung, aber keine Zigarre. Da die doppelte Genauigkeit FP Nummer 53 Bits hat, ist die letzte Nummer vor FP 3 tatsächlich (Exakt): 2,999999999999999555910790149937383830547332763671875

Aber warum ist es 2,9999999999999997779553950749686919152736663818359375

(und dies ist genau, nicht 49999 ...!)

was höher als die letzte darstellbare Einheit? Runden. Die Umwandlungsroutine (String zu Nummer) einfach korrekt die Eingabe der der nächste Gleitkommazahl abzurunden programmiert.

2,999999999999999555910790149937383830547332763671875

....... (Werte zwischen Erhöhen) -> abrunden

2,9999999999999997779553950749686919152736663818359375

....... (Werte zwischen Erhöhen) -> aufrunden bis 3

3

Die Umwandlung Eingang muss volle Genauigkeit verwenden. Wenn die Zahl ist genau die Hälfte zwischen diese beiden Zahlen fp (die 2.9999999999999997779553950749686919152736663818359375) die Rundung hängt von den gefassten Fahnen. Die Standardrunden ist rund um auch, was bedeutet, dass die Zahl auf die nächste gerade Zahl aufgerundet wird.

3 = 11 (binär)

2,999 ... = 10,11111111111 ...... (binär)

Alle Bits gesetzt sind, ist die Zahl immer ungerade. Das bedeutet, dass die genaue Hälfte Zahl aufzurunden, so dass Sie die seltsame ..... 49999 Periode bekommen, weil es kleiner ist als die genaue Hälfte sein muss von 3 unterscheidbar sein.

Ich vermute, dass 2,9999999999999997779553950749686919152736663818359374999999 seine binäre Darstellung Umwandlung wäre aufschlussreich. Es ist wahrscheinlich nur ein bisschen anders als wahr 3.

Und John Antwort hinzuzufügen, die Chancen, dies ist performanter als Math.floor sind verschwindend klein.

Ich weiß nicht, ob JavaScript verwendet Gleitkommazahlen oder eine Art unendlicher Präzision Bibliothek, aber so oder so, sind Sie Rundungsfehler auf einer Operation wie diese erhalten gehen - auch wenn es ziemlich gut definiert.

Es sollte beachtet werden, dass die Zahl“.0000000000000007779553950749686919152736663818359374" sehr wahrscheinlich ist die Epsilon , definiert als "die kleinste Zahl E, so dass (1 + E)> 1 ist."

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top