Здесь я рассказал о странной причуде языка C, с которой столкнулся в своей практике. В данной теме попытаюсь описать ещё об один "косяк", который может привести к некорректному результату, когда надеешься на правильную работу кода.
Итак, имеем следующий код:
#include <stdio.h>
int main()
{
float a = 1.005, b = 1000;
int c = a*b;
printf("%d\n", c);
return 0;
}
Компилируя этот код gcc 4.1.1, получаю 1004. Возникает вопрос - откуда такой странный результат? Даже это
int c = (float)(a*b);
также не даёт правильного результата. Оказалось, что старый стандарт языка C C89 ничего не регламентировал о способах работы с вещественными числами. Да ещё когда появилось расширение SSE, компиляторы начали считать смешенным образом - как посчитается быстрее, что-то на FPU, что-то на SSE.
В новом стандарте языка C C99 появилась некоторая определенность. Компилятор должен выставить значение макроса FLT_EVAL_METHOD (заголовочный файл float.h) в 0, 1, 2 для способа, которым он считает. Итак, 0 - всё считать так, как написано; 1 - float на самом деле считать в double и затем конвертировать обратно во float; 2 - всё считать в long double, конвертируя во float или double в конце вычислений соответственно.
Теперь, чтобы заставить считать прогу так, как надо, нужно собирать её
gcc proga.c -msse
Только после этого у меня в консоль вывелось число 1005. Чтобы была поддержка макроса FLT_EVAL_METHOD, используем директиву -std=c99.
Выдержка из мана по gcc (по поводу ключей -mmmx -msse -m3dnow):
These switches enable or disable the use of built-in functions that allow direct access to the MMX, SSE and 3Dnow extensions of the instruction set.
О ключе -mfpmath:
To have SSE/SSE2 instructions generated automatically from floating-point code, see -mfpmath=sse.
-mfpmath может принимать ещё значения "387" и "sse,387".