2009-06-13 11 views
42

Pomyślałem więc, że liczby ujemne, gdy mod'ed powinny być wprowadzane do dodatniej przestrzeni ... I cant get to się stało w Objective-CWeird Objective-C Mod Zachowanie dla liczb ujemnych

Spodziewam się następująco:

-1 % 3 = 2 
0 % 3 = 0 
1 % 3 = 1 
2 % 3 = 2 

Ale się tym

-1 % 3 = -1 
0 % 3 = 0 
1 % 3 = 1 
2 % 3 = 2 

Dlaczego to jest i czy istnieje obejście tego problemu?

+0

Clojure to pierwszy język, w którym udało mi się zmodyfikować. Yay! –

+2

@ToddOwen: Python to również dobrze – Claudiu

+0

@Todd, Lisp ma oba. – Pacerier

Odpowiedz

53
result = n % 3; 
if(result < 0) result += 3; 

Nie wykonuj dodatkowych operacji modowych, jak sugerują inne odpowiedzi. Są bardzo drogie i niepotrzebne.

+1

Czy to zależy od procesora, czy warunki warunkowe są lepsze czy gorsze od modulo? – Nosredna

+2

Nigdy nie widziałem procesora, w którym podział lub modulo nie jest najwolniejszą operacją. Sprawdzanie ujemnych redukuje do testowania wartości bitu, więc jest to zwykle jedna z najszybszych instrukcji. – UncleO

+0

Tak. To chyba prawda. Myślę, że w Core Duo Intels podział to około 15-17 cykli. Widzę, jak wiele osób próbuje obecnie unikać rozgałęzień. Ale z modem gałąź jest prawdopodobnie warta zachodu. – Nosredna

4

Liczyłam liczbę dodatnią, jak również, ale uważam, że ten, z normą ISO/IEC 14882: 2003: języki programowania - C++ 5.6.4 (znajduje się w Wikipedia article on the modulus operation):

Operator binarny% daje resztę z dzielenia pierwszego wyrażenia przez sekundę. .... Jeśli oba argumenty są nieujemne, to pozostałe są nieujemne; jeśli nie, znak reszty jest zdefiniowany w implementacji

+1

Brawura dla niejasnych specyfikacji. : | – devios1

14

W C i Objective-C operatorzy dzielenia i modulowania wykonują obcięcie w kierunku zera. a/b jest floor(a/b), jeśli a/b > 0, w przeciwnym razie jest ceiling(a/b), jeśli a/b < 0. Zawsze jest tak, że a == (a/b) * b + (a % b), o ile oczywiście b wynosi 0. W konsekwencji, positive % positive == positive, positive % negative == positive, negative % positive == negative i negative % negative == negative (możesz opracować logikę dla wszystkich 4 przypadków, chociaż jest to trochę trudne).

+2

+1 dla _why_. –

0

Do reszty można wybrać dwie opcje, a znak zależy od języka. ANSI C wybiera znak dywidendy. Podejrzewam, że właśnie dlatego widzisz, że Objective-C również to robi. See the wikipedia entry as well.

4

Jeśli to będzie zachowanie, a wiesz, że tak będzie, to dla m % n = r wystarczy użyć r = n + r. Jeśli nie masz pewności, co się tutaj stanie, skorzystaj z opcji r = r % n.

Edit: Podsumowując, należy r = (n + (m % n)) % n

+1

Jeśli właśnie powiedziałeś, że powinien zrobić (-1 + 3)% 3 = 2, zgadzam się. :-) – Nosredna

+1

Powiedziałbym, że zrobić (3 + (-1% 3))% 3 == (3 + (-1))% 3 == (2% 3) == 2 – maxwellb

+0

Gotcha. Dobre. Można to zrobić także warunkowo (jeśli lub trójskładnikowo). – Nosredna

1

JavaScript robi to, too. Zostałem złapany przez to kilka razy. Pomyśl o tym jako o odbiciu wokół zera, a nie o kontynuacji.

8

Jeśli n ma ograniczony zasięg, możesz uzyskać pożądany wynik, dodając znaną stałą wielokrotność liczby 3, która jest większa niż bezwzględna wartość minimum.

Na przykład, jeśli n jest ograniczony do -1000..2000, a następnie można użyć wyrażenia:

result = (n+1002) % 3; 

Upewnij maksymalna plus Twój stały nie wyleje kiedy sumowane.

1

Dlaczego: ponieważ jest to sposób, w jaki operator mod jest określony w standardzie C (Pamiętaj, że Objective-C jest rozszerzeniem C). To dezorientuje większość ludzi, których znam (jak ja), ponieważ jest to zaskakujące i trzeba o tym pamiętać.

Co do obejścia: użyłbym uncleo.

+0

Tak, mylące, podobnie jak odejmij na osi Y, aby iść w górę. Tylko jedna z tych preferencji na początku projektantów języka. Irytujące na początku; prawdopodobnie przydatne później. W rzeczywistości założyłbym się, że mod działający w ten sposób miał wielką użyteczność, gdy programiści musieli zaprojektować kompaktowe funkcje, aby obniżyć swoje bajty w swoich programach, z tego samego powodu, dla którego tablice zaczynają się od indeksu 0, a nie indeksu 1, sprawiły, że matematyka była bardziej zwarta –

7

Mamy problem Język:

 
math-er-says: i take this number plus that number mod other-number 
code-er-hears: I add two numbers and then devide the result by other-number 
code-er-says: what about negative numbers? 
math-er-says: WHAT? fields mod other-number don't have a concept of negative numbers? 
code-er-says: field what? ... 
  • osoba matematyki w tej rozmowie mówi o robi matematyki w okrągłej osi liczbowej. Jeśli odejmiesz od dołu, zawijasz się do góry.
  • Osoba kodu mówi o operatorze, który oblicza pozostałą część.

W tym przypadku potrzebujesz operatora mod matematycznego i masz do dyspozycji pozostałą funkcję. możesz przekształcić pozostały operator w operatora mod matematycznego, sprawdzając, czy spadłeś z dołu za każdym razem, gdy odejmujesz.

+0

liczby naturalne definiują podział tak, aby (n + d)/d == (n/d) +1. Te same liczby rzeczywiste. Liczby rzeczywiste również wspierają - (n/d) == (- n)/d, ale liczby naturalne nie. Możliwe jest, że liczby całkowite obsługują jeden aksjomat lub drugi, ale nie oba. Podczas gdy język programowania mógłby utrzymać pierwszy aksjomat liczb całkowitych, a niektórzy to robią, twórcy FORTRAN zdecydowali się na wsparcie drugiego, a wiele innych języków poszło w jego ślady. – supercat

0

Nie tylko skrypt java, prawie wszystkie języki pokazuje złą odpowiedź” co coneybeare powiedział jest poprawna, kiedy mamy mode'd musimy dostać pozostałą reszta jest niczym innym, który pozostaje po podziale i powinno być dodatnia ....

Jeśli sprawdzenie linii numer można zrozumieć, że

ja również zmierzyć się z tym samym problemem w VB, a i to mnie na siłę dodać dodatkową kontrolę jak jeśli wynik jest negatywny musimy dodać dzielnik do wyniku

1

Odpowiedź UncleO jest prawdopodobnie bardziej niezawodna, ale jeśli chcesz zrobić to w jednym wierszu i masz pewność, że wartość ujemna nie będzie bardziej negatywna niż pojedyncza iteracja mod (na przykład jeśli jesteś tylko co najwyżej kiedykolwiek odjęcie wartości mod w dowolnym momencie) można uprościć do jednego wyrażenia:

int result = (n + 3) % 3; 

Ponieważ robisz mod tak, dodając 3 do wartości początkowej nie ma wpływu chyba n jest ujemny (ale nie mniej niż -3), w którym to przypadku wynik jest oczekiwanym dodatnim modułem.

0

Zamiast a%b

użytkowania: a-b*floor((float)a/(float)b)

czekasz pozostałą i używanego modulo. W matematyce są to te same rzeczy, w C są różne. GNU-C ma Rem() i Mod(), cel-c ma tylko mod(), więc będziesz musiał użyć powyższego kodu do symulacji funkcji rem (która jest taka sama jak mod w świecie matematyki, ale nie w programowaniu świat [przynajmniej w przypadku większości języków])


Należy również pamiętać, że można w tym celu zdefiniować łatwe w użyciu makro.

#define rem(a,b) ((int)(a-b*floor((float)a/(float)b)))

Następnie można po prostu użyć rem(-1,3) w kodzie i to powinno działać dobrze.

Powiązane problemy