@Magda Pietrzykowska: Operator rzutowania nie działa tak jak Ci się wydaje.
Nawet gdyby tak działał - to niewiele by to zmieniło w Twoim programie.
To są przykłady, które pokazuję na jednym z pierwszych wykładów z podstaw programowania - mam nadzieję, że pomogą Ci to zrozumieć.
Co wypisze ten program ?
Kopiuj
int main()
{
int a;
a = 1 / 3;
cout << a << endl;
}
Przewiń na dół jak już zdecydujesz:
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
Oczywiście zero.
Pytanie - dlaczego ?
Przewiń na dół jak już zdecydujesz:
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
Nie, przyczyną nie jest to, że zmienna a jest typu int (być może się pomyliłem, ale zgaduję Twoją odpowiedź na podstawie statystyki odpowiedzi moich studentów ;) ). Zobacz - jeśli zmienię na float to nadal wynikiem będzie zero!
Kopiuj
int main()
{
float a;
a = 1 / 3;
cout << a << endl;
}
W obu wypadkach program wypisze zero, bo zapis c++ a = 1 / 3;
oznacza tak naprawdę DWIE operacje:
- obliczenie wartości wyrażenia
1/3
- wstawienie obliczonej wartości do zmiennej
a
Teraz pytanie - jak komputer liczy wartość wyrażenia typu 1/3
? W przypadku operatorów arytmetycznych możemy mieć do czynienia z jedną z trzech "podstawowych" sytuacji:
a) oba operandy są liczbami całkowitymi
b) oba operandy są liczbami zmiennoprzecinkowymi
c) jeden operand jest liczbą całkowitą a drugi - zmiennoprzecinkową
W sytuacji a) i b) - kompilator ma "łatwe" zadanie - po prostu bezpośrednio "zleca" wykonanie operacji procesorowi. Procesor posiada osobne instrukcje i wewnętrzne struktury służące do obsługi liczb całkowitych i zmiennoprzecinkowych. W przypadku gdy wykonujemy operację na liczbach całkowitych - jest ona w całości wykonywana przez "całkowitoliczbową" część procesora. W efekcie - wynikiem będzie tylko i wyłącznie liczba całkowita.
Gdyby oba operandy były zmiennoprzecinkowe - wynik byłby zmiennoprzecinkowy.
Jeśli jeden z operandów jest liczbą całkowitą a drugi zmiennoprzecinkową - kompilator ma "problem", bo procesor nie posiada bezpośrednio instrukcji pozwalających na wykonanie takich operacji. W tej sytuacji konieczne jest wykonanie konwersji, tak żeby oba operandy miały ten sam typ. W przypadku C/C++ kompilator wykona niejawną konwersję argumentu całkowitoliczbowego do typu zmiennoprzecinkowego.
W przypadku dzielenia 1 / 3
mamy do czynienia z przypadkiem a) - wynikiem będzie zatem zero i NIC WIĘCEJ. To nie będzie jedna trzecia zaokrąglona do liczby całkowitej, to nie będzie "zero i jeden reszty" - to będzie tylko i wyłącznie zero.
I teraz to zero wstawiamy do zmiennej "a". Jeśli zmienna a jest typu int - to komputer po prostu wstawi do niej obliczony wynik (zero całkowitoliczbowe).
Gdyby zmienna a była typu float, to komputer najpierw wykona niejawną konwersję tego "całkowitego" zera do zera zmiennoprzecinkowego.
Jeśli chcesz mieć "dobry" wynik, to musisz zrobić dwie rzeczy
- zadeklarować zmienną w której przechowywany będzie wynik jako float/double
- zmusić kompilator do wykonania operacji "zmiennoprzecinkowo"
Jak to zrobić ? Na przykład poprzez wymuszenie konwersji jednego z operandów do typu zmiennoprzecinkowego
Kopiuj
int main()
{
float a;
a = 1.0 / 3; // OK, dzielenie double/int --> kompilator zrobi z tego double/double, potem przekonwertuje wynik na float i wstawi go do a
a = static_cast<float> ( 1 ) / 3; // OK, jawnie konwertujemy wartość 1 na typ float, w efekcie mamy float/int, kompilator zrobi z tego float/float
a = static_cast<float> ( 1 / 3 ); // ŹLE - tu konwertujemy wynik działania a nie jeden z operandów.
}
Pomijając to wszystko co do tej pory napisałem - zapis
Kopiuj
static_cast<float> ( a );
nie ma większego "sensu". On nie służy do zmiany typu zmiennej, tylko (tak jak napisał Ci to @twonek) wyciąga wartość ze zmiennej "a" i konwertuje ją na float. Jest to jednak wartość "tymczasowa" - zniknie jeśli natychmiast jej nie zapamiętasz lub nie użyjesz w jakimś wyrażeniu.
Przy okazji z ciekawości zapytam - jak sądzisz - co wyświetli ten program (odpowiedz bez kompilowania i uruchamiania) ?
Kopiuj
int main()
{
int x = 2;
int y = 3 * x;
x = 5;
cout << y << endl;
}