2013-11-13 4 views
1

Мой учебник - C в миниатюре, ISBN 978-0596006976ошибка округления в GNU C компилятором

Часть отливки, код в примере показывает ошибку округления C:

Код:

#include <stdio.h> 

int 
main() 
{ 
    long l_var = 123456789L; 
    float f_var = l_var; 

    printf("The rounding error (f_var - l_var) is %f\n", f_var - l_var); 

    return 0; 
} 

то выходное значение оно ни с чем, но 0.000000

кажется это не имеет прецизионные проблем при литье тех буквального

с НКУ (V4.4.7) команда

gcc -Wall file.c -o exec 

сделал GNU сделать лучший способ, чтобы обойти проблемы, которая упоминается в этой главе

или только некоторые настройки не строго близко к вопросу округления ошибка?

+0

попытайтесь добавить ключевое слово 'volatile' в' l_var' и 'f_var' – ydroneaud

+5

Как мы должны знать, о чем проблема упоминается в этой главе? – Curd

+0

Это проблема с незарегистрированными переменными, которые тайно имеют более высокую точность, чем поплавки, хранящиеся в памяти? – harold

ответ

4

Я не знаю, что эта глава говорит вам, но:

float f_var = l_var; 

Мы можем сказать, что f_var является (float)l_var. Теперь выражение:

f_var - l_var 

Как это работает на long и float, то long будет преобразовано в float. Таким образом, компилятор будет делать:

f_var - (float)l_var 

который так же, как:

(float)l_var - (float)l_var 

которая равна нулю, независимо от закругления преобразования.

+3

Обратите внимание, что преобразование как 'long', так и' double' перед вычитанием было бы способом исправить это. –

+1

На самом деле, в разделе 'FLT_EVAL_METHOD == 2', я думаю, что' f_var-l_var' эквивалентно '(long double) (float) l_var - (long double) l_var' и, следовательно, может оценивать ненулевой результат. Но самое простое объяснение лучше всего, и ваше объяснение работает, по крайней мере, под 'FLT_EVAL_METHOD == 0'. –

+0

@Pascal Я не знал о [FLT_EVAL_METHOD] (http://en.cppreference.com/w/c/types/limits/FLT_EVAL_METHOD), спасибо. –

2

У меня нет доступа к этой книге.

Я полагаю, что пример пытается сказать вам, что если вы назначаете 32-битное целое число для 32-битного поплавка, вы можете потерять биты из-за усечения (ошибки округления): A 32 bit float has only 23 bit significand и некоторые биты могут быть потеряны во время соответственно.

Очевидно, что пример кода является фиктивным в книге. Вот код, чтобы продемонстрировать ошибку усечения:

#include <stdint.h> 
#include <stdio.h> 

int main() { 

    int32_t l_var = 123456789L; 

    /* 32 bit variable, 23 bit significand, approx. 7 decimals */ 
    float f_var = l_var; 

    double err = (double) f_var - (double) l_var; 

    printf("The rounding error (f_var - l_var) is %f\n", err); 

    return 0; 
} 

Печатается

The rounding error (f_var - l_var) is 3.000000 

на моей машине.

+0

Ясная демонстрация вашего утверждения – ryyker

+0

Я действительно получаю '3.000000' с примером, который он опубликовал. – Justin

0

0 - это значение, которое вы получаете, если оба значения преобразуются в float, вы получите что-то еще, если они будут преобразованы в что-то другое. И в стандарте есть надбавка, чтобы использовать более широкое представление с плавающей запятой, которое требуется типу для вычисления (*). Использование здесь здесь особенно заманчиво, так как результат должен быть преобразован в double для перехода к printf.

Моя версия gcc не использует эту учетную запись при компиляции для x86_64 (-m64 аргумент для gcc), и она использует ее при компиляции для x86 (-m32 аргумент). Это имеет смысл, когда вы знаете, что для 64 бит используется sse-инструкции, которые могут легко выполнять вычисления в float, тогда как при компиляции для 32 бит используется более старая модель стека «8087», которая не может сделать это легко.


(*) Последний пункт 6.2.1.5 в C90, 6.3.1.8/2 в C99, 6.3.1.8/2 в С11. Даю текст последней (как в n1539)

The values of floating operands and of the results of floating expressions may be represented in greater precision and range than that required by the type; the types are not changed thereby.

Как отметил Паскаль Cuoq, начиная с С99, вы можете проверить с FLT_EVAL_METHOD.

Смежные вопросы