Есть ли ошибка в контролируемом округлении с использованием `exp`? - PullRequest
3 голосов
/ 11 марта 2020

Я наблюдаю неправильное поведение округления (IMO) на некоторых платформах следующим образом:

Рассчитайте значение log(2) в режимах округления до FE_DOWNWARD и FE_UPWARD (см. <fenv.h>). Во всех случаях, которые я видел, результат округления в меньшую сторону меньше результата округления в большую сторону, чего я и ожидал (результат неточный).

Теперь, используя те же режимы округления, вызовите exp с каждый результат. Поскольку exp монотонно увеличивается (наклон составляет ~ 2 в интересующей области), я ожидаю, что эти результаты будут еще дальше друг от друга. Но на некоторых протестированных платформах два результата из exp эквивалентны.

Вот простая тестовая программа:

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

int main(void) {
  fesetround(FE_DOWNWARD);
  double xlo = log(2);
  double xxlo = exp(xlo);
  printf("xlo=%.16e xxlo=%.16e\n",xlo,xxlo);

  fesetround(FE_UPWARD);
  double xhi = log(2);
  double xxhi = exp(xhi);
  printf("xhi=%.16e xxhi=%.16e\n",xhi,xxhi); 

  printf("Delta x=%.16e\n",xhi-xlo);
  if (xxlo == xxhi) 
    printf("FAIL\n");
  else 
    printf("Delta xx=%.16e\n",xxhi-xxlo);

  return 0;
}

Один (хороший) результат на Xeon E5520 @ 2,27 ГГц:

xlo=6.9314718055994528e-01 xxlo=1.9999999999999997e+00
xhi=6.9314718055994540e-01 xxhi=2.0000000000000005e+00
Delta x=1.1102230246251566e-16
Delta xx=6.6613381477509393e-16

Другие процессоры, прошедшие тестирование: AMD Ryzen 9 3950X, Intel i7-5557U, Intel i7-3770, Intel m7-6Y75.

Но, как сообщается, пара потерпела неудачу (xxlo == xxhi): Intel E5-2650 и AMD EPY C 7401, по совпадению оба компьютера серверного класса. У меня нет прямого доступа к ним, но запуск теста на https://repl.it/languages/c также дает сбой:

clang version 7.0.0-3~ubuntu0.18.04.1 (tags/RELEASE_700/final)
 clang-7 -pthread -lm -o main main.c
 ./main
xlo=6.93147180559945286e-01 xxlo=2.00000000000000000e+00
xhi=6.93147180559945398e-01 xxhi=2.00000000000000000e+00
Delta x=1.11022302462515655e-16
FAIL

Меня не очень интересует фактическая точность результатов, но больше в относительных значениях. Так я что-то упустил, или это просто неправильно? И если это неправильно, это ошибка аппаратного округления или проблемы с математическими библиотеками программного обеспечения, или даже компилятор / настройки? Я также заинтересован в получении каких-либо результатов от выполнения простого теста, чтобы увидеть, можно ли сделать какие-либо дополнительные выводы из этих данных.

Ответы [ 2 ]

0 голосов
/ 26 марта 2020

@ Рик Джеймс

Я согласен с вашим диагнозом. Вот вывод из моей исходной программы с дополнительными операторами печати, предоставляющими шестнадцатеричные данные. Я не очень C программист, так что если это не то, что вы просили, будьте более откровенны.

xlo=6.9314718055994528e-01 xxlo=2.0000000000000000e+00
xlo=0x1.62e42fefa39efp-1 xxlo=0x1p+1
xhi=6.9314718055994540e-01 xxhi=2.0000000000000000e+00
xhi=0x1.62e42fefa39fp-1 xxhi=0x1p+1
Delta x=1.1102230246251566e-16
Delta x=0x1p-53
FAIL
0 голосов
/ 25 марта 2020

Спред (от округления к округлению) увеличивается производной функции. Таким образом, если ваша исходная граница равна 1ULP, я ожидаю, что exp (x) при 2.0 будет иметь спред 3. Это (оригинальный спред) * (производная) + 1. +1 означает, что вы делаете еще один округление и округление.

Если производная равна 2,5, я ожидаю, что разброс выпуска будет между 3 и 4.

Пожалуйста, укажите шестнадцатеричное число для чисел; это должно быть решающим, избегая преобразований bin <-> de c (которые, по-видимому, также ошибочны на некоторых машинах). несовместимое аппаратное обеспечение, следовательно, несовершенная реализация IEEE.

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

...