2012-03-19 18 views
10

ten zachowuje się jak chcieliśmy:Dlaczego (1/2) * x różni się od 0,5 * x?

double t = r[1][0] * .5; 

Ale tego nie robi:

double t = ((1/2)*r[1][0]); 

r jest 2-D wektora.

Pomyślnie o możliwości. Czy to dlatego, że (1/2) jest uważany za int i (1/2) == 0?

+55

Dlaczego podstawowy problem dotyczy głosowania typu integer vs float? – tbert

+29

Nie tylko podstawowe, ale OP już znał odpowiedź, ale jej nie próbował. Głosowanie jest tak przypadkowe w SO ... –

+4

Dostaje dodatkowe gałki oczne, ponieważ jest to "gorące pytanie" w StackExchange. Dodatkowe gałki oczne = dodatkowe głosy. –

Odpowiedz

58

Czy to dlatego, że (1/2) jest uważane za int i (1/2) == 0?

Tak, oba te literały są typu int więc wynik będzie typu int, a wynik jest 0.

Zamiast zrobić jedną z tych literałów float lub double i ty” ll skończyć z pływającym wyniku punktowego 0.5, tj

double t = ((1.0/2)*r[1][0]);

Ponieważ 1.0 jest typu double, int 2 zostanie awansowany na double, a wynikiem będzie double.

14

Zapis ten zamiast:

double t = ((1/2.0)*r[1][0]); 

1/2 jest podział całkowitą, a wynik jest 0.

1/2.0 to dzielenie zmiennoprzecinkowe (z wartościami double po zwykłych konwersjach arytmetycznych), a jego wynikiem jest 0.5.

5

Ponieważ 1/2 to podział /int/int. Oznacza to, że niezależnie od wyniku będzie cokolwiek po usunięciu przecinka dziesiętnego (obcięte). Więc 1/2 = 0,5 = 0.

Normalnie zawsze napisać pierwszy numer w double: 1.0/2 ... ..

Jeśli zrobisz to pierwsza liczba a double następnie wszystkie pozostałe obliczenia są wykonywane tylko double.

+0

Nie musi być * pierwszą liczbą *, tylko jedną z nich przynajmniej. – Marlon

+0

Po prostu nawyku używania pierwszego numeru jako float, wtedy nie napotkasz niespodzianek. Innym dobrym zwyczajem jest rozpoczynanie od 1.0 * .... – AgA

+2

. Zauważ, że w '2.0 * x + (7/5)', pierwsza liczba to "podwójna" i problem z OP wciąż jest obecny. –

2
double t = r[1][0] * .5; 

odpowiada:

double t = ((1/2f)*r[1][0]); 

a nie:

double t = ((1/2)*r[1][0]); 

powodu utraty części dziesiętnych, gdy tymczasowy wynikiem 1/2 jest przechowywana w zmiennej int.

Jako wytyczną gdy istnieje podział i istnieje możliwość odpowiedzi będącego liczbą rzeczywistą, nie używaj int lub uczynić jeden z argumentów float lub double lub użyj cast.

1

Zamiast tego można napisać 1.0/2.0. 1/2 wyświetla to zachowanie, ponieważ zarówno akt mianowania, jak i licznik są typu integer, a zmienna typu integer dzielona przez inną zmienną typu integer jest zawsze skracana do liczby całkowitej.

0

Nie mogę zasłużyć lub podważyć standard pytania, ale wydaje mi się, że to bardzo ważna kwestia. Zakładamy, że kompilator będzie robił pranie dla nas przez cały czas, ale czasami będzie to that is not true.

Czy istnieje sposób na uniknięcie tej sytuacji?

Possibly

LUB

ważniejsze znając monster (C, C++), jak większość ludzi podkreślić powyżej

chciałbym wiedzieć, czy istnieją inne sposoby śledzenia tych " kwestie skracania "w czasie kompilacji

+0

Co powiesz na znajomość języka i testowanie kodu? –

+0

@ JonathonReinhart nie kłóci się o to :) Ale moim zdaniem jest to nadmierna inżynieria i nieoczekiwane (w sensie matematycznym). Nauczysz się czegoś od drugiej lub trzeciej klasy i nagle niektórzy inżynierowie kompilatorów decydują się zmienić logikę matematyczną ... .. a komputery są dla ludzi, a nie odwrotnie. Ludzkie nawyki są trudne do zmiany. Po prostu skromna opinia :) – sakhunzai

Powiązane problemy