Odpowiedzi:
Dla pewnej liczby y
i dzielnika x
oblicz iloraz ( quotient
) i resztę ( remainder
) jako:
var quotient = Math.floor(y/x);
var remainder = y % x;
floor
i %
razem nie jest spójne w ten sposób. Albo użyj trunc
zamiast floor
(umożliwiając w ten sposób ujemne resztki), albo użyj odejmowania, aby otrzymać resztę ( rem = y - div * x
).
rem
tak, można dostać iloraz div
szybciej bez podłogi: (y - rem) / x
. 2. Nawiasem mówiąc, operacja modulo według zalecanej definicji Donalda Knutha (dzielnik znaków dopasowania, a nie reszta, tj. Moduł euklidesowy, ani znak dywidendy znaków JavaScript) jest tym, co możemy zakodować w JavaScript jako function mod (a, n) { return a % n + (Math.sign(a) !== Math.sign(n) ? n : 0); }
.
Nie jestem ekspertem od operatorów bitowych, ale oto inny sposób na uzyskanie całej liczby:
var num = ~~(a / b);
Działa to również poprawnie dla liczb ujemnych, a Math.floor()
zaokrągla w niewłaściwym kierunku.
To również wydaje się poprawne:
var num = (a / b) >> 0;
a/b | 0
~~int
, int | 0
I int >> 0
nie zmienia Pierwszym argumentem, ale sprawiają, że integralną część interpretera przechodzi do operatora.
floor
prawie nie krąży w złym kierunku, biorąc pod uwagę jego nazwę - po prostu nie w kierunku, który ludzie na ogół chcą!
a = 12447132275286670000; b = 128
Math.floor(a/b)
-> 97243220900677100
i ~~(a/b)
-> -1231452688
.
~~(5/2) --> 2
jak to robi (5/2)>>0 --> 2
, ale ~~(5/2) + 1 --> 3
jednocześnie ~~(5/2)>>0 + 1 --> 1
. ~~
jest dobrym wyborem, ponieważ pierwszeństwo jest bardziej odpowiednie.
Zrobiłem kilka testów prędkości w Firefoksie.
-100/3 // -33.33..., 0.3663 millisec
Math.floor(-100/3) // -34, 0.5016 millisec
~~(-100/3) // -33, 0.3619 millisec
(-100/3>>0) // -33, 0.3632 millisec
(-100/3|0) // -33, 0.3856 millisec
(-100-(-100%3))/3 // -33, 0.3591 millisec
/* a=-100, b=3 */
a/b // -33.33..., 0.4863 millisec
Math.floor(a/b) // -34, 0.6019 millisec
~~(a/b) // -33, 0.5148 millisec
(a/b>>0) // -33, 0.5048 millisec
(a/b|0) // -33, 0.5078 millisec
(a-(a%b))/b // -33, 0.6649 millisec
Powyższe opiera się na 10 milionach prób dla każdego.
Wniosek: Użyj (a/b>>0)
(lub (~~(a/b))
lub (a/b|0)
), aby osiągnąć około 20% przyrost wydajności. Należy także pamiętać, że są one niezgodne z Math.floor
kiedy a/b<0 && a%b!=0
.
Math.floor
wielu innych funkcji API i kto wie, ile funkcji API, lub poznanie ~
operatora (bitowego-nie) i tego, jak działają operacje bitowe w JS, a następnie zrozumienie efektu podwójnej tyldy?
Math.floor
lepiej to zrozumieją . A nawet jeśli nie, ten jest dostępny w Google.
ES6 wprowadza nową Math.trunc
metodę. Pozwala to naprawić odpowiedź @ MarkElliot, aby działała również dla liczb ujemnych:
var div = Math.trunc(y/x);
var rem = y % x;
Zauważ, że Math
metody mają przewagę nad operatorami bitowymi, ponieważ pracują z liczbami powyżej 2 31 .
18014398509481984 == 18014398509481985
.
~~(x/y)
. Potrzebujesz obsługi większej liczby podpisanych do 54 bitów? Użyj, Math.trunc
jeśli go masz, lub w Math.floor
inny sposób (popraw dla liczb ujemnych). Potrzebujesz obsługi nawet większych liczb? Użyj biblioteki dużej liczby.
divmod
, możesz zaimplementować go jako taki:function divmod(x, y) { var div = Math.trunc(x/y); var rem = x % y; return [div, rem]; }
var remainder = x % y;
return (x - remainder) / y;
Math.trunc
:). Sprawdziłem za pomocą 100,3; -100,3; 100, -3 i -100, -3. Oczywiście minęło wiele czasu od twojego komentarza i rzeczy się zmieniają.
Zwykle używam:
const quotient = (a - a % b) / b;
const remainder = a % b;
To chyba nie jest najbardziej elegancki, ale działa.
Możesz użyć tej funkcji, parseInt
aby uzyskać obcięty wynik.
parseInt(a/b)
Aby uzyskać resztę, użyj operatora mod:
a%b
parseInt ma pewne pułapki z łańcuchami, aby uniknąć użycia parametru radix z bazą 10
parseInt("09", 10)
W niektórych przypadkach ciąg znaków reprezentujący liczbę może być notacją naukową, w tym przypadku parsowanie spowoduje niepoprawny wynik.
parseInt(100000000000000000000000000000000, 10) // 1e+32
W wyniku tego wywołanie wygeneruje 1.
parseInt
w miarę możliwości należy tego unikać. Oto ostrzeżenie Douglasa Crockforda: „Jeśli pierwszym znakiem ciągu jest 0, to łańcuch jest przetwarzany w podstawie 8 zamiast w podstawie 10. W bazie 8, 8 i 9 nie są cyframi, więc parsuj („ 08 ”) i parsuj („09”) dają wynik 0. Błąd ten powoduje problemy w programach, które analizują daty i godziny. Na szczęście parseInt może przyjąć parametr radix, więc parseInt („08”, 10) daje 8. Zalecam, abyś zawsze podaj parametr radix. ” archive.oreilly.com/pub/a/javascript/excerpts/…
parseInt
należy go unikać; po prostu trzeba pamiętać o kilku problemach. Musisz zdawać sobie sprawę z tych rzeczy i być przygotowanym na poradzenie sobie.
parseInt
z argumentem liczbowym. parseInt
ma analizować ciągi częściowo numeryczne, a nie obcinać liczby.
JavaScript oblicza na podstawie dolnej liczby liczb ujemnych i pozostałej liczby niecałkowitej, zgodnie z ich matematycznymi definicjami.
FLOOR jest zdefiniowany jako „największa liczba całkowita mniejsza niż parametr”, a zatem:
REMAINDER jest zdefiniowany jako „pozostały” podziału (arytmetyka euklidesowa). Gdy dywidenda nie jest liczbą całkowitą, iloraz zwykle nie jest również liczbą całkowitą, tzn. Nie ma reszty, ale jeśli iloraz jest zmuszony do bycia liczbą całkowitą (i tak się dzieje, gdy ktoś próbuje uzyskać resztę lub moduł liczba zmiennoprzecinkowa), oczywiście pozostanie „liczba całkowita”.
JavaScript oblicza wszystko zgodnie z oczekiwaniami, więc programista musi uważnie zadawać właściwe pytania (a ludzie powinni uważać, aby odpowiedzieć na to, co jest zadawane!) Pierwsze pytanie Yarina brzmiało NIE „jaki jest całkowity podział X na Y”, ale: zamiast tego „CAŁA liczba przypadków, gdy dana liczba całkowita PRZEJDZIE DO INNEJ”. W przypadku liczb dodatnich odpowiedź jest taka sama dla obu, ale nie dla liczb ujemnych, ponieważ podział na liczby całkowite (dywidenda przez dzielnik) będzie -1 mniejszy niż czas, w którym liczba (dzielnik) „przechodzi” na inną (dywidenda). Innymi słowy, FLOOR zwróci poprawną odpowiedź dla liczb całkowitych liczb ujemnych, ale Yarin o to nie pytał!
gammax odpowiedział poprawnie, że kod działa zgodnie z zapytaniem Yarina. Z drugiej strony, Samuel się myli, chyba nie zrobił matematyki, bo inaczej zobaczyłby, że to działa (nie powiedział też, jaki był dzielnik jego przykładu, ale mam nadzieję, że tak było 3):
Reszta = X% Y = -100% 3 = -1
GoesInto = (X - pozostały) / Y = (-100 - -1) / 3 = -99 / 3 = -33
Nawiasem mówiąc, przetestowałem kod w przeglądarce Firefox 27.0.1, działał on zgodnie z oczekiwaniami, z liczbami dodatnimi i ujemnymi, a także z wartościami niecałkowitymi, zarówno dla dywidendy, jak i dzielnika. Przykład:
-100,34 / 3,57: GoesInto = -28, reszta = -0,3800000000000079
Tak, zauważyłem, że jest tam problem z precyzją, ale nie miałem czasu go sprawdzić (nie wiem, czy to problem z Firefoksem, Windows 7 lub z FPU mojego procesora). W przypadku pytania Yarina, które dotyczy tylko liczb całkowitych, kod gammax działa doskonale.
Obliczanie liczby stron można wykonać w jednym kroku: Math.ceil (x / y)
Komentarz Alexa Moore-Niemiego jako odpowiedź:
Dla rubyistów tutaj z Google w poszukiwaniu divmod
, możesz zaimplementować go jako taki:
function divmod(x, y) {
var div = Math.trunc(x/y);
var rem = x % y;
return [div, rem];
}
Wynik:
// [2, 33]
divmod
używa dzielnika dzielonego ( Math.floor
), który różni się od skróconego dzielenia ( Math.trunc
), gdy występują liczby ujemne. Tak jest w przypadku pakietu NPMdivmod
, Rubydivmod
, SWI-Prologdivmod
i prawdopodobnie wielu innych implementacji.
divmod
istnieje, ponieważ wykonuje się go dwa razy szybciej niż osobne obliczenie dwóch operacji. Zapewnienie takiej funkcji bez tej korzyści w zakresie wydajności może być mylące.
Jeśli dzielisz tylko potęgami dwóch, możesz użyć operatorów bitowych:
export function divideBy2(num) {
return [num >> 1, num & 1];
}
export function divideBy4(num) {
return [num >> 2, num & 3];
}
export function divideBy8(num) {
return [num >> 3, num & 7];
}
(Pierwszy to iloraz, drugi to reszta)
function divideByPowerOf2(num, exponent) { return [num >> exponent, num & ((1 << exponent) - 1)]; }
.
Możesz użyć trójskładnika, aby zdecydować, jak obsługiwać dodatnie i ujemne wartości całkowite.
var myInt = (y > 0) ? Math.floor(y/x) : Math.floor(y/x) + 1
Jeśli liczba jest dodatnia, wszystko jest w porządku. Jeśli liczba jest ujemna, dodaje 1, ponieważ Math.floor obsługuje negatywy.
To zawsze skróci się do zera. Nie jestem pewien, czy jest za późno, ale oto:
function intdiv(dividend, divisor) {
divisor = divisor - divisor % 1;
if (divisor == 0) throw new Error("division by zero");
dividend = dividend - dividend % 1;
var rem = dividend % divisor;
return {
remainder: rem,
quotient: (dividend - rem) / divisor
};
}
Jeśli musisz obliczyć resztę dla bardzo dużych liczb całkowitych, których środowisko wykonawcze JS nie może reprezentować jako takie (każda liczba całkowita większa niż 2 ^ 32 jest reprezentowana jako liczba zmiennoprzecinkowa, a zatem traci precyzję), musisz zrobić jakąś sztuczkę.
Jest to szczególnie ważne przy sprawdzaniu wielu przypadków cyfr czekowych, które są obecne w wielu przypadkach naszego codziennego życia (numery kont bankowych, karty kredytowe, ...)
Przede wszystkim potrzebujesz numeru jako łańcucha (w przeciwnym razie straciłeś już precyzję, a reszta nie ma sensu).
str = '123456789123456789123456789'
Teraz musisz podzielić sznurek na mniejsze części, wystarczająco małe, aby konkatenacja każdej pozostałej części i kawałka sznurka mieściła się w 9 cyfrach.
digits = 9 - String(divisor).length
Przygotuj wyrażenie regularne, aby podzielić ciąg
splitter = new RegExp(`.{1,${digits}}(?=(.{${digits}})+$)`, 'g')
Na przykład, jeśli digits
jest to 7, wyrażenie regularne to
/.{1,7}(?=(.{7})+$)/g
Odpowiada niepustemu podciągowi o maksymalnej długości 7, po którym następuje ( (?=...)
jest to znak z wyprzedzeniem) liczba znaków, która jest wielokrotnością liczby 7. „g” powoduje, że wyrażenie przechodzi przez cały ciąg, nie zatrzymując się przy pierwszym dopasowaniu.
Teraz przekonwertuj każdą część na liczbę całkowitą i oblicz resztę przez reduce
(dodając poprzednią resztę - lub 0 - pomnożoną przez prawidłową moc 10):
reducer = (rem, piece) => (rem * Math.pow(10, digits) + piece) % divisor
Działa to z powodu algorytmu reszty „odejmowania”:
n mod d = (n - kd) mod d
który pozwala zastąpić dowolną „początkową część” dziesiętnej reprezentacji liczby jej pozostałą częścią, bez wpływu na końcową resztę.
Ostateczny kod wyglądałby następująco:
function remainder(num, div) {
const digits = 9 - String(div).length;
const splitter = new RegExp(`.{1,${digits}}(?=(.{${digits}})+$)`, 'g');
const mult = Math.pow(10, digits);
const reducer = (rem, piece) => (rem * mult + piece) % div;
return str.match(splitter).map(Number).reduce(reducer, 0);
}
3.5 % 2
ocenia na 1.5. Upewnij się, że