2013-12-18 7 views

Odpowiedz

14

Może to mieć znaczenie. Dla example:

int i = (1 << 24) + 3; 

printf("%d\n", (int)(i * 0.6)); // 10066331 
printf("%d\n", (int)(i * 0.6f)); // 10066332 

Powodem jest to, że obliczenia na pierwszy odbywa się w podwójnej precyzji, ten ostatni w pojedynczej precyzji. Pojedyncza precyzja nie może reprezentować wszystkich liczb całkowitych większych niż 1 << 24.

Innym example (dzięki uprzejmości @EricPostpischil w komentarzach poniżej):

int i = 100; 

printf("%d\n", (int)(i * 0.29)); // 28 
printf("%d\n", (int)(i * 0.29f)); // 29 

Tu powodem jest to, że wynik pośredni w przypadku podwójnej precyzji spadnie nieco poniżej 29 lat, a więc jest obcięty do 28 .

Więc sugerowałbym pozwalając podwójnej precyzji (czyli z pominięciem f/F) (a następnie przy użyciu round() zamiast polegać na niejawny obcięcia), chyba że masz dobry powód, aby zrobić inaczej.

+1

Mniejszy przykład i przypadek, w którym użycie 'double' prowadzi do mniej dokładnego wyniku, jest takie, że' int i = 100 * .29f; 'tworzy 29, podczas gdy' int i = 100 * .29; 'tworzy 28 (używając IEEE -754 binarny zmiennoprzecinkowy). –

+0

@EricPostpischil: Oh to interesujące. Skąd ta rozbieżność? Ani jedno, ani podwójne nie może dokładnie odpowiadać 0,29; czy jeden kwantyzuje w górę, a drugi w dół? –

+0

+1, ale pytanie: Czy kompilator _nie ma_, ale nie jest wymagany_, aby wykonać obliczenia z matematyki wyższej precyzji? Tak więc odpowiedź może być taka sama? – chux

5

Urządzenie F nie jest wymagane w tym konkretnym przypadku. Wszystko, co robi, to określ stałą jako typ float zamiast typu double.

1

Pierwszy mówi, i zmniejsza się

i [int] = 100 [int] * 0.6 [double] 
i [int] = 100.0 [double] * 0.6 [double] 
i [int] = 60.0 [double] 

Drugi mówi

i [int] = 100 [int] * 0.6 [float] 
i [int] = 100.0 [float] * 0.6 [float] 
i [int] = 60.0 [float] 

Obie są tak samo skuteczne, chyba że specjalnie dbać o obrocie vs. podwójnej precyzji.

1

W systemach wbudowanych różnica może być znacząca poza precyzją również w czasie wykonywania. sufiks f sprawia, że ​​liczba jest stałą zmiennoprzecinkową w przeciwieństwie do stałej zmiennoprzecinkowej podwójnej precyzji, jak już zauważyli inni.

Jeśli wszystkie operandy są zmiennoprzecinkowe, operacja matematyczna będzie wykonywana przy użyciu zmiennoprzecinkowej pojedynczej precyzji. Jeśli procesor ma jednostkę zmiennoprzecinkową z pojedynczą precyzją, obliczenia mogą z niej korzystać (w zależności od opcji kompilatora).

Jeśli z drugiej strony dowolny argument jest podwójny, obliczenia odbywają się z podwójną precyzją. Jeśli procesor ma tylko jedną dokładną jednostkę FPU, oznacza to, że obliczenia zostaną wykonane przy użyciu biblioteki SW. Czas wykonania danego kodu w takim przypadku będzie kilkakrotnie dłuższy.

Przykładem takiego procesora jest ARM Cortex-M4F.

Podobny, ale nie tak radykalny efekt różnicowy występuje w przypadku braku FPU. Wszystkie operacje zmiennoprzecinkowe używają biblioteki sw. Podwójna precyzja zajmie więcej czasu.

+0

+1 Dla aspektów osadzonych. W środowisku osadzonym, którego użyłem, zmiennoprzecinkowe i podwójne były takie same, stąd "podwójne" trwało tyle samo co 'float'. – chux

Powiązane problemy