Могут ли эквивалентные выражения давать разные результаты с плавающей точкой? - PullRequest
1 голос
/ 16 ноября 2010

Обсуждение этого ответа только что заставило меня задуматься о равенстве и эквивалентности чисел с плавающей точкой. Я знаю, что числа с плавающей запятой не всегда могут быть представлены точно. Вопрос в том, существуют ли математически эквивалентные выражения, которые будут давать разные результаты при использовании арифметики с плавающей запятой? Можете привести пример?

Редактировать: Позвольте мне быть более ясным. Мне известно, что один и тот же код с разными компиляторами или разными машинами может давать разные результаты. То, что я ищу, - это два математически эквивалентных выражения, которые я могу сравнить в моем интерпретаторе Python / программе на C ++ / что угодно и получить неожиданный результат.

Ответы [ 3 ]

3 голосов
/ 16 ноября 2010

существуют ли математически эквивалентные выражения, которые будут давать разные результаты при использовании арифметики с плавающей точкой?

Абсолютно.Фактически, вы должны ожидать, что это будет происходить чаще, чем нет.

Даже один и тот же код может давать разные результаты на разных машинах или компиляторах.

Можете ли вы привести пример?

Конечно.Этот код Java должен повторять два разных результата:

public strictfp class Test {
    public static void main(String[] args) throws Exception {
        float a = 0.7f;
        float b = 0.3f;
        float c = 0.1f;

        float r1 = ((a * b) * c);
        float r2 = (a * (b * c));

        System.out.println(r1);
        System.out.println(r2);
    }
}
2 голосов
/ 16 ноября 2010

Да, сравните, например,

x = (a * b) / c;

с

x = a * (b / c);

Вот пример на C, который демонстрирует это:

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

int main(void)
{
    double a, b, c, x1, x2;

    a = sqrt((double)rand());
    b = sqrt((double)rand());
    c = sqrt((double)rand());

    x1 = (a * b) / c;
    x2 = a * (b / c);

    printf("a = %.20f\n", a);
    printf("b = %.20f\n", b);
    printf("c = %.20f\n", c);
    printf("x1 = %.20f\n", x1);
    printf("x2 = %.20f\n", x2);
    printf("x1 - x2 = %.20f\n", x1 - x2);

    return 0;
}

Для меня это дает следующие результаты:

$ gcc -O3 -Wall math.c -o math
$ ./math
a = 129.64181424216494065149
b = 16807.00000000000000000000
c = 40282.13093916457728482783
x1 = 54.09073256970189902404
x2 = 54.09073256970190612947
x1 - x2 = -0.00000000000000710543
$ 

(Core i7, gcc 4.0.1, Mac OS X 10.6)

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

0 голосов
/ 16 ноября 2010

Я бы попробовал с умножением и сложением:

в псевдокоде

float x = 1/7;
float y = x * 4;
float z = x + x + x + x;
if (y != z) {
    printf("oh noes!\n");
}
...