Ошибка в моем коде с плавающей запятой или gcc? - PullRequest
4 голосов
/ 14 апреля 2011

Следующий код работает, как и ожидалось, для меня под 64-битными, но не работает под 32-битными при -O2 и -O3, ожидаемый вывод равен 1.1, в системах с ошибками выводит 1.0.Я пытаюсь установить, является ли это ошибкой в ​​моем коде (делающем некоторые неверные предположения о том, как работает float) или в GCC.Если это в моем коде, как же я могу исправить это?

#include <math.h>
#include <stdio.h>


int f(double x) {
    return isinf(1.0 / x);
}

int m_isinf(double x) {
    return x != 0 && x * 0.5 == x;
}

int g(double x) {
    return m_isinf(1.0 / x);
}

double values[] = {
    5.5e-309,
    -1.0
};

int main() {
    int i;
    for (i = 0; values[i] != -1.0; i++) {
        printf("%d\n", f(values[i]));
        printf("%d\n", g(values[i]));
    }
    return 0;
}

Ответы [ 4 ]

3 голосов
/ 14 апреля 2011

Выражение может быть оценено с большей точностью, чем тип. В вашей 32-битной сборке компилятор, вероятно, использует двойной бит длиной 80 бит (который больше не используется в 64 битах) для оценки x != 0 && x * 0.5 == x.

(GCC знает проблемы с этими правилами, оценивая их с большей точностью в контексте, где это невозможно).

6.3.1.8 / 2 в C99 (6.2.1.5 в C90 эквивалентно):

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

В соответствующей реализации:

int m_isinf(double x) {
    double const half_x = x * 0.5;
    return x != 0 && half_x == x;
}

должно работать. Но ошибка gcc (http://gcc.gnu.org/bugzilla/show_bug.cgi?id=323 посмотрите на количество дубликатов) часто мешает этому работать. В отчете об ошибках есть обходной путь.

2 голосов
/ 14 апреля 2011

По сути, использование сравнения равенства для чисел с плавающей и двойной точностью - верный путь к неожиданному поведению.

1 голос
/ 14 апреля 2011

Вы можете проверить значение напрямую, например:

#include <math.h>

int isinf(double d) {
  union {
    unsigned long long l;
    double d;
  } u;
  u.d=d;
  return (u.l==0x7FF0000000000000ll?1:u.l==0xFFF0000000000000ll?-1:0);
}

Предоставлено dietlibc

0 голосов
/ 09 октября 2012

Посмотрите на это для управления с плавающей запятой http://cibak.web.cern.ch/cibak/pval/valid.html

...