Может ли cos (a) когда-либо равняться 0 в плавающей точке - PullRequest
6 голосов
/ 31 июля 2011

Учитывая, что PI / 2 никогда не может быть точно представлен в плавающей точке, можно ли с уверенностью предположить, что cos (a) никогда не сможет вернуть точный ноль?

Если это так, то следующее псевдо-код никогда не войдет в блок (и его можно безопасно удалить):

...
y = h/cos(a);
if (!isfinite(a))
{
  // handle infinite y
}

Ответы [ 3 ]

7 голосов
/ 01 августа 2011

За исключением нуля, значение двойной точности, наиболее близкое к кратному π / 2, равно 6381956970095103 * 2 ^ 797, что равно:

(an odd integer) * π/2 + 2.983942503748063...e−19

Таким образом, для всех значений x двойной точности мы имеем ограничение:

|cos(x)| >= cos(2.983942503748063...e−19)

Обратите внимание, что это ограничение математически точного значения, а не значения, возвращаемого библиотечной функцией cos. На платформе с качественной математической библиотекой эта оценка достаточно хороша, и мы можем сказать, что cos(x) не равно нулю для любой двойной точности x. Фактически, оказывается, что это не уникально, чтобы удвоить; это свойство сохраняется для всех базовых типов IEEE-754, если cos точно округлено.

Однако это не означает, что это никогда не может произойти на платформе, в которой реализована исключительно плохая реализация тригонометрического сокращения аргументов.

Что еще более важно, важно отметить, что в вашем примере y может быть бесконечным без cos(a), равным нулю:

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

int main(int argc, char *argv[]) {
    double a = 0x1.6ac5b262ca1ffp+849;
    double h = 0x1.0p1022;
    printf("cos(a) = %g\n", cos(a));
    printf("h/cos(a) = %g\n", h/cos(a));
    return 0;
}

скомпилируйте и запустите:

scanon$ clang example.c && ./a.out
cos(a) = -4.68717e-19
h/cos(a) = -inf
4 голосов
/ 31 июля 2011

Ноль является одним из нескольких значений, которые могут быть представлены точно.Многие системы имеют справочную таблицу для общих значений sin и cos, поэтому немыслимо, что может быть возвращен ровно ноль.

Но перед выполнением деления безопаснее использовать дельта-сравнение:

if (Abs(cos(a)) < 0.0000001)
{

}
0 голосов
/ 31 июля 2011

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

...