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


(przemekKK) #1

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;

?


(Kanaliaon) #2

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.


([alex]) #3

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


(Johny) #4

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


(Ryan) #5

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