[C++] Pytanie dotyczące inicjalizacji i konwersji

Zainteresował mnie taki kod:

float wartosc = 10.5;

Deklaruję tu zmienną float i dokonuje jej inicjalizacji. Liczba 10.5 jest typu double. Czy konwersja liczby na float jest wykonana w momencie kompilacji czy za każdym razem w działającej aplikacji. Czy wydajniej będzie:

float wartosc = 10.5f;

?

Skąd taki pomysł, że 10.5 jest double? Skoro definiujesz ją jako float, to jest float.

Float są mniejsze (4bajty, double 8bajtów), a co zatem idzie, szybsze, ale mają mniejszy zakres od double.

Konwersja jest podczas kompilacji. Więc oba kody zostaną skompilowane do tych samych komend asemblera.

Typ jest potrzebny po to,aby kompilator wiedział,ile pamięci ma być przydzielone i jak ma być reprezentowana liczba

jeśli dasz typ float to on przydzieli ilość bajtów dla float,konwersja jest w czasie kompilacji,bo są to zmienne stałe w pamięci,istnieją od początku do końca programu lub funkcji w której są zawarte,innym typem zmiennych są zmienne dynamiczne - wskazniki z charakterystycznymi gwiazdkami,gdzie przy pomocy operatora new można dynamicznie przydzielać i zwalniać pamięć w czasie wykonywania programu

Owszem, kompilator poradzi sobie z dopasowaniem typu float<->double, ale to wcale nie znaczy, że 10.5 i 10.5f są równoważne, bo nie zawsze kompilator może dokonać konwersji bez efektów ubocznych (i czasami tej konwersji nie dokona). Poniżej kod Bar i Baz nie jest równoważny (bo nie powinien):

float Bar(float f)

{

    return f * 11.45f;

}


float Baz(float f)

{

    return f * 11.45;

}


int wmain(int argc, WCHAR *argv[])

{

    UNREFERENCED_PARAMETER(argc);

    UNREFERENCED_PARAMETER(argv);


    float f1 = 10.512f;

    float rf1 = Bar(f1);

    float rf2 = Baz(f1);


    wprintf(L"%f %f %f\n", f1, rf1, rf2);

        return 0;

}

Jeśli ktoś ma wątpliwości, oto wynik z VC++:

__real@4026e66660000000 DQ 04026e66660000000r	; 11.45

...

?Bar@@YAMM@Z PROC ; Bar, COMDAT

...

	fld	DWORD PTR _f$[ebp]

	fmul	QWORD PTR __real@4026e66660000000

	fstp	DWORD PTR tv67[ebp]

	fld	DWORD PTR tv67[ebp]

...


__real@4026e66666666666 DQ 04026e66666666666r	; 11.45

...

?Baz@@YAMM@Z PROC ; Baz, COMDAT

...

	fld	DWORD PTR _f$[ebp]

	fmul	QWORD PTR __real@4026e66666666666

	fstp	DWORD PTR tv67[ebp]

	fld	DWORD PTR tv67[ebp]

Wyraźnie widać, że obie stałe mają odmienną precyzję, tak jak powinny. Dzieje się tak gdy na stałej wykonywana jest operacja arytmetyczna i może prowadzić do odmiennych wyników.

10.512000 120.362396 120.362404

W przypadku prostej inicjalizacji (przeważnie) nie ma problemu, ale pisanie “skąd taki pomysł, że 10.5 jest double?” świadczy o drobnych brakach w wiedzy. Zresztą w podanym wyżej przypadku, przy kompilacji z /W4, kompilator nie plułby się bez powodu, prawda?

warning C4244: 'return' : conversion from 'double' to 'float', possible loss of data