Jak to się dzieje w poniższym fragmencie
int a = 7;
int b = 3;
double c = 0;
c = a / b;
c
kończy się na wartości 2 zamiast 2,3333, jak można by się spodziewać. Jeśli a
i b
są podwojone, odpowiedź brzmi 2.333. Ale na pewno c
skoro już jest podwójna, powinna była działać z liczbami całkowitymi?
Więc dlaczego int/int=double
nie działa?
c++
variables
double
integer-division
Jahoe
źródło
źródło
Odpowiedzi:
Dzieje się tak, ponieważ używasz wersji dzielenia liczb całkowitych
operator/
, która zajmuje 2int
sekundy i zwracaint
. Aby użyćdouble
wersji, która zwraca adouble
, co najmniej jeden zint
s musi być jawnie rzutowany na plikdouble
.źródło
a
ib
abydouble
po prostu dla jasności, ale to naprawdę nie ma znaczenia.static_cast<>
zawsze wydawało mi się rozwlekłe. W przypadku pierwotnych, nie ma naprawdę żadnego niebezpieczeństwa dostaniastatic_cast<>
ireinterpret_cast<>
pomieszane.static_cast
i zamiast tego używać rzutowania w stylu C. Nie ma tu żadnej korzyści z używania rzutowań w stylu C ++ i zaśmiecają kod o wiele bardziej niż rzutowania w stylu C. Rzutowanie arytmetyczne jest dokładnie tym kontekstem, w którym rzuty w stylu C są doskonale odpowiednie i właściwie bardziej odpowiednie niż inne rzuty.double(b)
. Nie zawsze zdają sobie sprawę, że jest to konwersja, ponieważ wygląda to tak samo, jak jawne wywołanie konstruktora.Oto ona:
a) Dzielenie dwóch
int
s powoduje zawsze dzielenie liczb całkowitych. Więc wynikiema/b
w Twoim przypadku może być tylko plikint
.Jeśli chcesz zachować
a
ib
jakoint
s, ale w pełni je podzielić, musisz rzucić przynajmniej jedną z nich na podwojenie:(double)a/b
luba/(double)b
lub(double)a/(double)b
.b)
c
jestdouble
, więc może przyjąć takieint
wartości w ASSIGNMENT: theint
automatycznie przekształca siędouble
i przypisanec
.c) Pamiętaj, że przy przypisywaniu najpierw
=
obliczane jest wyrażenie po prawej stronie (zgodnie z regułą (a) powyżej i bez uwzględnienia zmiennej po lewej stronie=
), a następnie przypisywane do zmiennej po lewej stronie=
(zgodnie z ( b) powyżej). Myślę, że to uzupełnia obraz.źródło
Z nielicznymi wyjątkami (przychodzi mi do głowy tylko jeden), C ++ określa całe znaczenie wyrażenia (lub wyrażenia podrzędnego) na podstawie samego wyrażenia. Nie ma znaczenia, co zrobisz z wynikami wyrażenia. W twoim przypadku w wyrażeniu
a / b
nie madouble
w zasięgu wzroku; wszystko jestint
. Więc kompilator używa dzielenia liczb całkowitych. Dopiero po uzyskaniu wyniku rozważa, co z nim zrobić i konwertuje go nadouble
.źródło
&funcname
zależy od typu, na który ją rzutujesz.c
jestdouble
zmienną, ale przypisywana jejint
wartość jest wartością, ponieważ wynika z dzielenia dwóchint
s, co daje „dzielenie całkowite” (porzucenie reszty). Więc to, co dzieje się w linii,c=a/b
jesta/b
jest oceniane, tworząc tymczasowy typint
c
po konwersji na typdouble
.Wartość
a/b
jest określana bez odniesienia do kontekstu (przypisanie dodouble
).źródło
Kiedy dzielisz dwie liczby całkowite, wynik będzie liczbą całkowitą, niezależnie od tego, że przechowujesz ją w liczbie podwójnej.
źródło
W języku C ++ na wynik podwyrażenia nigdy nie ma wpływu otaczający kontekst (z nielicznymi wyjątkami). To jedna z zasad, których język dokładnie przestrzega. Wyrażenie
c = a / b
zawiera niezależne wyrażenie podrzędnea / b
, które jest interpretowane niezależnie od wszystkiego poza tym podwyrażeniem. Język nie obchodzi, że później przypiszesz wynik do plikudouble
.a / b
jest dzieleniem całkowitym. Cokolwiek innego nie ma znaczenia. Zobaczysz przestrzeganie tej zasady w wielu rogach specyfikacji języka. To trochę jak działa C ++ (i C).Jednym z przykładów wyjątku, o którym wspomniałem powyżej, jest przypisanie / inicjalizacja wskaźnika funkcji w sytuacjach przeciążenia funkcji
Jest to jeden kontekst, w którym lewa strona przypisania / inicjalizacji wpływa na zachowanie prawej strony. (Ponadto inicjalizacja odniesienia do tablicy zapobiega zanikowi typu tablicy, co jest kolejnym przykładem podobnego zachowania). We wszystkich innych przypadkach prawa strona całkowicie ignoruje lewą stronę.
źródło
/
Operatora może być używany do dzielenia liczby całkowitej lub zmiennoprzecinkowej podziału. Dajesz mu dwa operandy całkowite, więc wykonuje dzielenie całkowitoliczbowe, a następnie wynik jest zapisywany jako podwójny.źródło
Jest to technicznie zależne od języka, ale prawie wszystkie języki traktują ten temat tak samo. Gdy występuje niezgodność typów między dwoma typami danych w wyrażeniu, większość języków będzie próbować rzutować dane po jednej stronie
=
aby dopasować dane po drugiej stronie, zgodnie z zestawem wstępnie zdefiniowanych reguł.Podczas dzielenia dwóch liczb tego samego typu (liczby całkowite, liczby podwójne itp.) Wynik będzie zawsze tego samego typu (więc „int / int” zawsze da w wyniku int).
W tym przypadku masz,
double var = integer result
który rzuca wynik w postaci liczby całkowitej na podwójny po obliczeniu, w którym to przypadku dane ułamkowe są już utracone. (większość języków wykonuje to rzutowanie, aby zapobiec niedokładnościom typu bez zgłaszania wyjątku lub błędu).Jeśli chcesz, aby wynik był podwójny, będziesz chciał stworzyć sytuację, w której masz
double var = double result
Najłatwiej to zrobić, wymuszając podwojenie wyrażenia po prawej stronie równania:
c = a/(double)b
Dzielenie liczby całkowitej i podwójnej spowoduje rzutowanie liczby całkowitej na podwójną (zwróć uwagę, że podczas obliczeń matematycznych kompilator często „upcast” do najbardziej specyficznego typu danych, aby zapobiec utracie danych).
Po upcastingu
a
skończy się jako dublet, a teraz masz podział na dwie pary. Stworzy to pożądany podział i przypisanie.PONOWNIE, proszę zauważyć, że jest to specyficzne dla języka (i może nawet być specyficzne dla kompilatora), jednak prawie wszystkie języki (z pewnością wszystkie te, które przychodzą mi do głowy) traktują ten przykład identycznie.
źródło
Ważną rzeczą jest to, że jeden z elementów obliczeń powinien być typu float-double. Następnie, aby uzyskać podwójny wynik, musisz rzucić ten element, jak pokazano poniżej:
lub c = a / static_cast (b);
Lub możesz go utworzyć bezpośrednio:
Zauważ, że jeden z elementów obliczenia musi mieć „.0”, aby wskazać podział typu float-double przez liczbę całkowitą. W przeciwnym razie, mimo że zmienna c będzie podwójna, wynik również będzie równy zero.
źródło