2016-12-20 15 views
13

Wyrażenie -1 % 7 w JavaScript daje mi jako wynik -1. Podczas gdy w Pythonie i Haskell, znalazłem wynik jako 6.Wynik -1% 7 różni się w javascript (-1) i python (6)

Czy ktoś może wyjaśnić, dlaczego obaj mają różne zachowania? Który jest prawidłowy?

+0

dla Pythona, zobacz http://python-history.blogspot.de/2010/08/why-pythons-integer-division-floors.html – georg

+0

Zobacz [ ten artykuł] (http://yourdailygeekery.com/2011/06/28/modulo-of-negative-numbers.html), aby uzyskać więcej informacji na temat różnych zachowań w niektórych językach. –

Odpowiedz

2

Obie są poprawne. Niektóre języki zwracają pozytywne liczby modulo, podczas gdy inne zachowują swój znak.

Możesz po prostu dodać moduł do swojej zmiennej, aby uzyskać liczbę dodatnią lub sprawdzić, czy liczba jest dodatnia lub ujemna przed wykonaniem działania modułu i poprawić wynik po przełączeniu między tymi dwoma.


Pseudokod przekonwertować a%b między dwoma:

w języku gdzie -1%7 == -1, możesz to zrobić, aby uzyskać liczbę dodatnią:

((a%b)+b) % b 

A w języku gdzie -1%7 == 6 można zrobić Aby uzyskać wersję podpisaną:

if a < 0: 
    return (a%b)-b 
else: 
    return a%b 
+1

Żadne z tych fragmentów kodu nie jest poprawne ... pierwsze powinno być prawdopodobnie '((a) b) + b)% b' (lub' if a <0: return (a% b) + b else: return a% b' jeśli wolisz warunkowy moduł), a drugi 'if a <0: return (a% b) -b else: zwraca% b'. –

+0

@DanielWagner dobry połów, jestem zbyt przyzwyczajony, aby nie martwić się o przepełnienie. Drugi był odwrócony. –

3

Oba są poprawne, po prostu używają różnych konwencji dotyczących obsługi negatywnych argumentów. W przypadku liczb dodatnich konwencje są zbieżne, ale w przypadku liczb ujemnych nie. W języku Python a % b zawsze ma ten sam znak, co b.

W dalszej części użyję notacji Python, gdzie // służy do dzielenia liczby całkowitej.

Niech

q, r = a // b, a % b 

Następnie

a == q * b + r 

musi być prawdziwe w każdym języku (zakładając a i b są liczbami całkowitymi, przy b nie równe zeru). Sposób postępowania z resztą musi być zgodny z konwencją stosowaną do podziału całkowitoliczbowego. W języku Python podział całkowity to podział pięter, tzn. Wynik jest zaokrąglany w kierunku ujemnej nieskończoności. W niektórych innych językach używa się zaokrąglania w kierunku zera. W niektórych językach można uzyskać dowolną konwencję, którą zdecydował się wdrożyć producent procesora, więc ten sam kod uruchamiany na innym sprzęcie może dawać różne wyniki. Jak możesz sobie wyobrazić, może to być nieco denerwujące. :)

1

Obie są poprawne.

Aby wykonać inne odpowiedzi, można również rozważyć funkcję divmod w Pythonie:

Weź dwie (nie złożone) Numery jako argumenty i zwraca parę liczb składających się z ich iloraz i resztę przy użyciu całkowitą podział. W przypadku mieszanych typów argumentów obowiązują reguły dla binarnych operatorów arytmetycznych. Dla liczb całkowitych wynik jest taki sam jak (a // b, a % b). W przypadku liczb zmiennoprzecinkowych wynikiem jest (q, a % b), gdzie q jest zwykle math.floor(a/b), ale może być o 1 mniejszy.W każdym razie q * b + a % b jest bardzo zbliżone do i, jeśli a % b jest niezerowe, ma ten sam znak co b i 0 <= abs(a % b) < abs(b).

>>> divmod(-1, 7) 
(-1, 6) 
+0

Dziękuję za wzmiankę o tym, że Python pozwala operandom float na '//' i '%'. FWIW, 'a // b, a% b' może być szybszy niż' divmod (a, b) 'ze względu na dodatkowy narzut wywołania funkcji vs używania operatorów, chociaż' divmod' nie jest tak powolny jak wywołanie funkcji napisane w Pythonie. –

+0

@ PM2Ring nie są operatorami w Pythonie tylko działa z alternatywną składnią? Nie sądzę, że jakikolwiek nowoczesny język z dobrą optymalizacją ma nieuniknioną karę za wydajność w używaniu wywołań funkcji, nawet ponad wbudowanymi operatorami - jeśli funkcja jest dość prosta, i tak zostanie ona zainspirowana. – leftaroundabout

+0

@leftaroundabout Nie, ponieważ wywołanie funkcji wywołuje nowy obiekt [frame] (http://stackoverflow.com/a/38938014/4014959), aby kod funkcji mógł działać we własnym zakresie. Ramka jest pełnoprawnym obiektem w języku Python, więc dodatkowe obciążenie to coś więcej niż wywołanie funkcji C. Optymalizator Pythona jest dość prosty, nie zawiera wbudowanych wywołań funkcji. Wszystkie poprzednie uwagi dotyczą standardowego CPython, szczegóły mogą się różnić w przypadku innych implementacji. –

6

Zamierzam dać nieco inną odpowiedź. Jak powiedzieli inni, funkcje mogą robić, co je zdefiniujesz, i m - x = -x mod m. Jako preludium, zauważę, że Haskell ma dwie funkcje "mod", mod i rem, które różnią się tylko tym aspektem. Możesz zrobić przypadek, że najlepiej jest matematycznie wpisać mod. Numer rem odpowiada temu, co uzyskasz na procesorze x86. W rzeczywistości jest trzecia, euklidesowa, która może być jeszcze lepsza i opisana przez Raymonda Boute w The Euclidean Definitions of the Functions Div and Mod. Trzeci formularz zawsze zwraca dodatni moduł. (Istnieją w rzeczywistości co najmniej dwa inne opcje, które można wybrać.)

Definicja Javascript jest tym, co można uzyskać z większości kodów maszynowych mod. W tym sensie może być lepszym rozwiązaniem, ponieważ mogłoby to zwiększyć jego skuteczność. Matematycznie, definicja Haskella i Pythona jest lepsza niż JavaScript. Istnieje również trzecia definicja, która może być nieco lepsza.

Jedną z kluczowych właściwości, które posiadają definicje euklidesa i Haskella/Pythona jest x mod m = y mod m, co odpowiada x = y mod m, której nie ma definicja Javascript. Możesz zweryfikować, obliczając 6 % 7 w JavaScript.

1

Nazwa % oznacza różnych operatorów w JavaScript i w języku Python.

W języku JavaScript nazwa % oznacza operatora Remainder. Dokumentacja wskazuje już różnicę między resztą i operacją modulo:

Reszta operator zwraca resztę pozostałą, gdy jeden operand jest podzielony przez drugi operand. Zawsze przyjmuje znak dywidendy, a nie dzielnik. Używa wbudowanej funkcji modulo do wygenerowania wyniku, który jest całkowitą pozostałością podziału var1 przez var2 - na przykład - var1 modulo var2. Istnieje propozycja, aby uzyskać rzeczywistego operatora modulo w przyszłej wersji ECMAScript, z tą różnicą, że wynik operatora modulo przyjąłby znak dzielnika, a nie dywidendy.

(Nacisk przeze mnie)

W przeciwieństwie do tego: W Pythonie, że % oznacza operatora modulo. Dokumentacja zawiera również oświadczenie o znaku:

Operator % (modulo) pozostawia resztę z podziału pierwszego argumentu na sekundę. Argumenty numeryczne są najpierw konwertowane na typ wspólny. Argument zero-zero podnosi wyjątek ZeroDivisionError. [...] Operator modulo zawsze daje wynik z tym samym znakiem, co jego drugi operand (lub zero); bezwzględna wartość wyniku jest ściśle mniejsza niż bezwzględna wartość drugiego argumentu [2].

(Nacisk przeze mnie)