Mój kolega natknął się na metodę wyprowadzania liczb zmiennoprzecinkowych za pomocą bitów lub:
var a = 13.6 | 0; //a == 13
Rozmawialiśmy o tym i zastanawialiśmy się nad kilkoma rzeczami.
- Jak to działa? Nasza teoria była taka, że użycie takiego operatora rzutuje liczbę na liczbę całkowitą, usuwając w ten sposób część ułamkową
- Czy ma to jakieś zalety w stosunku do robienia
Math.floor
? Może to trochę szybciej? (gra słów nie przeznaczona) - Czy ma to jakieś wady? Może w niektórych przypadkach to nie działa? Klarowność jest oczywista, ponieważ musieliśmy to rozgryźć i cóż, piszę to pytanie.
Dzięki.
javascript
floating-point
bit-manipulation
Alex Turpin
źródło
źródło
3000000000.1 | 0
ocenia na -1294967296. Tak więc tej metody nie można zastosować do obliczania pieniędzy (szczególnie w przypadkach, gdy mnożymy przez 100, aby uniknąć liczb dziesiętnych).0.1 + 0.2 == 0.3
w konsoli JavaScript. Jeśli Twój język to obsługuje, powinieneś użyć typu dziesiętnego. Jeśli nie, zamiast tego przechowuj centy.Odpowiedzi:
Wszystkie operacje bitowe oprócz prawego przesunięcia bez znaku
>>>
, działają na 32-bitowych liczbach całkowitych ze znakiem. Zatem użycie operacji bitowych przekształci liczbę zmiennoprzecinkową w liczbę całkowitą.http://jsperf.com/or-vs-floor/2 wydaje się nieco szybszy
Math.floor(NaN) === NaN
podczas gdy(NaN | 0) === 0
źródło
Math.floor(NaN) === NaN
, że(NaN | 0) === 0
. Ta różnica może być ważna w niektórych aplikacjach.asm.js
(gdzie po raz pierwszy się o tym dowiedziałam). Jest szybszy, jeśli bez żadnego innego powodu, ponieważ nie wywołuje funkcji naMath
obiekcie, funkcji, którą można w dowolnym momencie zastąpić jak wMath.floor = function(...)
.(value | 0) === value
może być użyty do sprawdzenia, czy wartość jest w rzeczywistości liczbą całkowitą i tylko liczbą całkowitą (jak w kodzie źródłowym Elm @ połączonymi oszustami). Ifoo = foo | 0
może być użyty do wymuszenia dowolnej wartości na liczbę całkowitą (gdzie liczby 32-bitowe są obcinane, a wszystkie nie-liczby stają się 0).Jest to obcięcie w przeciwieństwie do podłogi. Odpowiedź Howarda jest w pewnym sensie poprawna; Dodałbym jednak, że
Math.floor
robi dokładnie to, co powinien, w odniesieniu do liczb ujemnych. Matematycznie taka jest podłoga.W przypadku opisanym powyżej programista był bardziej zainteresowany obcięciem lub całkowitym odcięciem dziesiętnego. Chociaż zastosowana przez nich składnia przesłania fakt, że przekształcają zmiennoprzecinkowe na int.
źródło
Math.floor(8589934591.1)
daje oczekiwany wynik,8589934591.1 | 0
NIE .W ECMAScript 6 odpowiednikiem
|0
jest Math.trunc , co powinienem powiedzieć:źródło
Math.trunc()
praca z liczbą wyższą lub równą 2 ^ 31 i| 0
nie działaTwój pierwszy punkt jest poprawny. Liczba jest rzutowana na liczbę całkowitą, a zatem usuwane są wszystkie cyfry dziesiętne. Zauważ, że
Math.floor
zaokrągla do następnej liczby całkowitej w kierunku minus nieskończoności, a zatem daje inny wynik, gdy zostanie zastosowany do liczb ujemnych.źródło
JavaScript reprezentuje
Number
jako zmiennoprzecinkowe liczby 64-bitowe Double Precision .Math.floor
działa z tą myślą.Operacje bitowe działają w 32-bitowych podpisane liczb całkowitych. 32-bitowe liczby całkowite ze znakiem używają pierwszego bitu jako ujemnego znacznika, a pozostałe 31 bitów to liczba. Z tego powodu, minimalna i maksymalna liczba dozwolonych 32-bitowych liczb ze znakami wynosi odpowiednio -2 147 483 648 i 2147483647 (0x7FFFFFFFF).
Więc kiedy to robisz
| 0
, zasadniczo to robisz& 0xFFFFFFFF
. Oznacza to, że każda liczba reprezentowana jako 0x80000000 (2147483648) lub wyższa zwróci liczbę ujemną.Na przykład:
Również. Operacje bitowe nie „piętrzą”. Oni obciąć , który jest taki sam jak powiedzenie, że zaokrąglanie najbliżej
0
. Po przejściu do liczb ujemnychMath.floor
zaokrągla się w dół, a bitowe zaczyna zaokrąglać w górę .Jak powiedziałem wcześniej,
Math.floor
jest bezpieczniejszy, ponieważ działa z liczbami zmiennoprzecinkowymi 64-bitowymi. Bitowe jest szybsze , tak, ale ograniczone do 32-bitowego podpisanego zakresu.Podsumowując:
0 to 2147483647
.-2147483647 to 0
.-2147483648
i większych niż2147483647
.Jeśli naprawdę chcesz poprawić wydajność i użyć obu:
Tylko dodanie
Math.trunc
działa jak operacje bitowe. Możesz to zrobić:źródło
Specyfikacja mówi, że jest konwertowany na liczbę całkowitą:
Wydajność: zostało to wcześniej przetestowane w jsperf .
Uwaga: usunięto martwy link do specyfikacji
źródło