2012-03-26 2 views
3

I ', попробовав этот простой код. Это показывает первые 10 целых чисел, которые не могут быть представлены в поплавка:(float) литье не работает

int main(){ 
    int i, cont=0; 
    float f; 
    double di, df; 
    for(i=10000000, f=i; i<INT_MAX; i++, f=i, df=f, di=((float)i)){ 
    if(i!=f){ 
     printf("i=%d f=%.2f df=%.2lf di=%.2lf\n", i, f, df, di); 
     if(cont++==10) return 0; 
    } 
    } 
    return 1; 
} 

ди является двойной переменной, но я установить его на (флоат) я, поэтому она должна быть равна DF, но это не.

Например, число 16777217 представлено как 16777216 от е и ф.р., но ди еще 16777217, не обращая внимания на отливку (поплавок).

Как это возможно?

** Я использую это: GCC (Ubuntu 4.4.3-4ubuntu5) 4.4.3

+1

Какая платформа и версия компилятора? – sarnold

+3

Почему вы используете такой оператор запятой? Нет абсолютно никакой необходимости и добавляет ненужные вопросы сложности, подобные этому. – Joe

+0

Вам не нужно указывать '% lf'. Просто '% f' в порядке, и это означает' double'. –

ответ

2

Относится к вашему вопросу 6.3.1.8:2 в the C99 standard:

Значения с плавающей операнды и результаты плавающих выражений могут быть представлены в большей точности и дальности, чем , которые требуются по типу; типы не изменяются.

и, в частности, сноски 52:

Отлитые и операторы присваивания по-прежнему требуется выполнять свои заданные преобразования, как описано в 6.3.1.4 и 6.3.1.5.

Чтение сноски, я бы сказал, что вы определили ошибку в своем компиляторе.

Возможно, вы определили две ошибки в вашем компиляторе: сравнение между поплавками (см. Правила продвижения на той же странице стандарта), поэтому оно всегда должно быть ложным. Хотя в этом последнем случае я считаю, что компилятору может быть разрешено использовать более крупный тип для сравнения на 6.3.1.8-2, возможно, сравнивая сравнение с (double)i!=(double)f и, таким образом, иногда это правда. Параграф 6.3.1.8-2 - это абзац в стандарте, который я больше всего ненавижу, и я все еще пытаюсь понять строгий псевдоним.

+0

Большое спасибо. Я думаю, что вы правы, и в компиляторе есть ошибка (или функция?), Так как i! = F сравнивается между двойниками вместо поплавков. – salteador

+0

Это очень давняя известная ошибка в gcc, которую разработчики имеют мало, чтобы исправить, потому что она умеренно вредит производительности для людей, которые не заботятся о правильности.Если вы не заботитесь о том, чтобы ваша программа несовместима со старым процессором, вы можете исправить проблему с помощью '-msse' (используйте SSE вместо FPU для с плавающей запятой). Обратите внимание, что на платформах, отличных от x86 (и, возможно, m68k?), Проблема не существует. –

+0

@R ..: Если они хотят максимизировать производительность без учета правильности, почему бы просто не вернуть все вычисления с плавающей запятой 42.0? Разве это не будет быстрее, чем притворяться математикой? Это хорошо для IMHO для компилятора, чтобы выполнять такие вещи, как 'f4 = f1 + f2 + f3;' используя 80-битный расширенный формат, а не 32-битный формат для промежуточных значений *, если он согласован в обработке таких вещей *, но если сравнения и отливки не выполняются на правильных типах, они бессмысленны, а «скорость» не имеет значения. – supercat

2

Это сообщение объясняет, что происходит:

http://www.exploringbinary.com/when-floats-dont-behave-like-floats/

В основном дополнительная точность может быть сохранена на компьютере, для различных оценок экспрессии, делая то, что было бы равными поплавки не равны.

+0

Большое спасибо. Я не знал этого;) – salteador

+0

Стандарт требует отбрасывания, чтобы отбросить лишнюю точность. GCC просто сломан в этом отношении, и это известная проблема. Проблема может быть частично дополнена опцией '-ffloat-store', но это только фиксирует присвоения, а не отбрасывает. –

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