2013-05-31 2 views
0

Я столкнулся с очень странным фактом об округлении float и преобразовании в int.math.h default rounding mode not clear

Как указано здесь: http://www.gnu.org/software/libc/manual/html_node/Rounding.html

Округление до ближайшего представимому значения по умолчанию режим округления. Но, похоже, это не так.

Так что я создал эту простую программу:

#include <fenv.h> 
#include <stdio.h> 

int a; 
double b; 

main() { 
    b=1.3; a=b; printf("%f %d\n",b,a); 
    b=1.8; a=b; printf("%f %d\n",b,a); 
    b=-1.3; a=b; printf("%f %d\n",b,a); 
    b=-1.8; a=b; printf("%f %d\n",b,a); 
    printf("%d %d %d\n",fegetround(),FE_TONEAREST,FE_TOWARDZERO); 
} 

Программа была составлена ​​с GCC-4.7 (Debian), Cygwin GCC и Visual Studio. Результат был таким же, изменилось только определение FE_TOWARDZERO.

Выход программы:

1.300000 1 
1.800000 1 
-1.300000 -1 
-1.800000 -1 
0 0 3072 

Таким образом, мы можем ясно видеть, что режим округления устанавливается на FE_TONEAREST (по умолчанию) во всех протестированных компиляторов, но все они округление к нулю.

Почему?

PS: Да, я могу использовать Math.round(), но мне интересно, почему это происходит.

ответ

0

Хорошо, я нашел вопрос, почему это происходит. Как указано здесь:

http://software.intel.com/en-us/articles/fast-floating-point-to-integer-conversions

в главе

A Closer Look at Float-to-Int Conversions 

Проблема с литьем из чисел с плавающей точкой в ​​32-битном целые стебли от стандарта ANSI C, в котором говорится преобразование должно выполняться путем обрезания дробной части числа и сохранения целочисленного результата. Из-за этого всякий раз, когда компилятор Microsoft Visual C++ 6.0 встречает (int) или (long) , он вставляет вызов функции времени выполнения _ftol C. Эта функция изменяет режим округления с плавающей запятой на «усечение», выполняет преобразование, а затем сбрасывает режим округления до своего исходного состояния перед отливом.

2

Поскольку режим округления применяется к функциям округления с плавающей запятой. Преобразование в int всегда усекает.

+0

Я не понимаю. Я могу использовать Math.round(), ceil() или floor(), когда хочу округлить с плавающей запятой. Или я вижу это неправильно? – Mihalko

+1

@Mihalko Вы не понимаете, что 'int a = (int) aFloat;' и 'int a = round (aFloat);' не совпадают. –

+0

, но режим округления в сопроцессоре FP используется при литье float в int. В любом случае, я нашел ответ здесь: http://software.intel.com/en-us/articles/fast-floating-point-to-integer-conversions в главе «Более внимательный взгляд на конверсии Float-to-Int « – Mihalko