2010-11-16 9 views
10

Próbuję obliczyć niektóre liczby w aplikacji na iPhone'a.Objective-C Integer arithmetic

int i = 12; 
int o = (60/(i * 50)) * 1000; 

byłoby oczekiwać, O, przewidzianym do 100 (to milisekundy) w tym przykładzie, ale ma wartość 0 jak pokazano przez NSLog (@ "% D", o).

ta równa jest 0.

int o = 60/(i * 50) * 1000; 

ta równa 250.000, która jest prosta matematyka lewej do prawej.

Co tu lata nad moją głową?

dzięki,
Nick

+3

Zobacz [C problem - wynik podziału zawsze wynosi zero ] (http://stackoverflow.com/questions/2345902/c-problem-division-result-is-always-zero). –

Odpowiedz

19

W celu C / wykonuje dzielenie całkowitej argumentów całkowitych, tak 4/5 jest obcinany 0, 3/2, jest obcinana do 1, i tak dalej. Prawdopodobnie chcesz rzucić niektóre z twoich liczb na formularze zmiennoprzecinkowe przed wykonaniem podziału.

Występują również problemy z priorytetem. W wyrażeniu

60/(i * 50) * 1000 

wyrażenie w nawiasach oblicza pierwszy, więc 60 jest podzielony przez 600, który wytwarza wynik 0.

60/i * 50 * 1000 

pierwsza operacja polega na podzieleniu przez 12, 60, co daje wynik 5, a następnie przeprowadzane są multiplikacje.

+3

C też, oczywiście. Arytmetyka w Objective-C jest identyczna z arytmetyką w C. :) –

+6

Ściśle mówiąc, wynik nie jest zaokrąglany, jest obcięty. – Dima

+1

Cóż, obcięcie to forma zaokrąglania (w kierunku zera), więc ... tak. –

4

Liczba całkowita podzielona przez liczbę całkowitą jest liczbą całkowitą.

więc 60/600 nie jest 0.1, jest to 0.

Prześlij (lub zadeklaruj) pewne rzeczy jako float.

+1

Przesyłanie lub wprowadzanie niejawnej konwersji na 'float' lub' double' to ** nie ** sposób na ocenę wyrażeń całkowitych. W systemach bez zmiennoprzecinkowego punktu IEEE może to dawać bardzo fałszywe wyniki (C prawie nie wymaga wymagań co do jakości implementacji zmiennoprzecinkowej), a nawet z zmiennoprzecinkowym punktem IEEE, możesz uzyskać błędy z powodu utraty precyzji z liczbami całkowitymi zbyt dużymi, aby zmieścić się w używany typ zmiennoprzecinkowy. Prawidłowym rozwiązaniem problemu OP jest po prostu uproszczenie algebraiczne wyrażenia. –

1

To robi całkowitą matematykę. 60/(12 * 50) wynosi 0,1, obcina do 0.

Powinien działać, jeśli wymusisz zmiennoprzecinkowe, a następnie powrócisz do liczby całkowitej.

int o = (int)(60.0/((double) i/50.0) * 1000.0; 

Prawdopodobnie nie jest to konieczne, aby wszystko było podwójne.

+1

Przesyłanie lub wprowadzanie niejawnej konwersji na wartość 'float' lub' double' jest ** nie ** sposobem oceny wyrażeń liczb całkowitych. Zobacz mój komentarz na odpowiedź Dave'a. –

0

Postanowieniem pierwszeństwa, operacja:

60/(12 * 50) 

jest wykonywana przed pomnożenie przez 1000.

Ta wartość jest mniejsza niż 1 i jest przesyłana do int, która obcina ją do 0. I 0 razy cokolwiek jest 0.

Użyj float lub najpierw pomnóż przez 1000, aby upewnić się, że nie kończysz z propagowaniem w swoich obliczeniach wartości 0.

0

Wszystkie operacje w wyrażeniu są wykonywane w arytmetyce całkowitej, co oznacza, że ​​ułamkowa część każdego wyniku pośredniego jest obcięta. Oznacza to, że jeśli podzielisz mniejszą liczbę całkowitą o większą liczbę całkowitą, zawsze otrzymasz 0.

Aby uzyskać pożądany wynik, musisz albo upewnić się, że operacje są wykonywane w określonej kolejności, albo musisz użyć pływaków. Na przykład wynikiem

int o = (60.0/(i * 50.0)) * 1000.0; 

powinna być o = 100.

3

Wymienić:

int o = (60/(i * 50)) * 1000; 

z:

int o = 1200/i; 
+1

Kimkolwiek jest downworter, proszę wyjaśnij sobie. W przeciwieństwie do innych odpowiedzi, ta odpowiedź podaje dokładną liczbę całkowitą obciętą wyniku obliczeń, bez żadnych przypadków narożnych z powodu przepełnienia lub utraty precyzji. O ile mogę powiedzieć, jest to jedyna poprawna odpowiedź tutaj. –

0

Myślę, że trzeba użyć zamiast unosić się tutaj int. Będzie działać tak, jak chcesz! Daje ci również odpowiedź w postaci dziesiętnej.

+0

Podczas gdy 'float' będzie działał, to nie rozwiązuje problemu nieporozumienia, które spowodowało problem w pierwszej kolejności! – Andrew