2011-07-12 2 views
7

Я пишу (почти) IEEE 854-совместимую реализацию с плавающей запятой в TeX (которая поддерживает только 32-битные целые числа). Этот стандарт определяет только +, -, *, /, сравнение, остаток и sqrt: для этих операций результат должен быть идентичным округлению точного результата до представляемого числа (в соответствии с режимом округления).Стандарт для синуса очень больших чисел

Кажется, я припоминаю, что IEEE указывает, что трансцендентные функции (sin, exp ...) должны давать верные результаты (в стандартном округления до ближайшего режима, они должны вывести один из двух представимых чисел, окружающих точный результат). Вычисление синуса малых чисел довольно просто: сдвиг на кратное 2 * pi, чтобы получить число в диапазоне [0,2 * pi], затем выполните еще одну работу, чтобы уменьшить диапазон до [0, pi/4] , и используйте серию Тейлора.

Теперь предположим, что я хочу вычислить грех (1e300). Для этого мне нужно будет найти 1e300 по модулю 2 * pi. Это требует знать 300 (316?) Десятичных знаков pi, потому что только с 16 десятичными знаками результат не имел бы никакого значения (в частности, он не был бы верным).

Есть ли стандарт на то, что результат sin(1e300) и подобные очень большие числа должны быть?

Что делают другие реализации с плавающей запятой?

+1

+1 Хорошее объяснение интересной проблемы (о которой я раньше не думал) – pavium

ответ

8

Нет стандарта, который требует верного округления трансцендентных функций. IEEE-754 (2008) рекомендует, но не требует, чтобы эти функции были правильно закруглены.

Самые хорошие математические библиотеки стремятся доставить достоверно округленные результаты по всему диапазону (да, даже для огромных входов в sin() и аналогично жестких случаях). Как вы заметили, для этого требуется, чтобы библиотека знала несколько больше цифр π, тогда есть цифры в наибольшем представимом числе. Это называется уменьшением аргумента «бесконечный-пи».

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

Все, что было сказано, существует множество библиотек, которые берут простой путь и используют «конечное пи», которое в основном рассматривает функцию типа sin(), как если бы я было представимым конечным числом. Оказывается, это действительно не вызывает никаких проблем для . Большинство использует и, безусловно, проще реализовать.

+0

«бесконечное сокращение аргументов pi» помогает, когда у вас большие аргументы, но не когда у вас очень * большие аргументы. Это прекрасно для библиотеки, чтобы предположить, что ее входы точны, но когда вход + epsilon == вводит, это уже не имеет значения. – spraff

+1

@spraff: Это не имеет значения * для целей анализа обратной ошибки *. Это имеет значение, когда используются некоторые другие методы анализа ошибок, и это стандарт, на котором хранятся лучшие математические библиотеки. См., Например, K.C. Ng «Хорошо для последнего бит» для обсуждения. –

+0

В третьем абзаце вы можете заметить, что хорошие библиотеки делают это, потому что IEEE-754 (2008) считает числа с плавающей точкой бесконечно точными. Не могли бы вы привести примеры «хороших математических библиотек» по сравнению с теми, «которые делают легкий маршрут»? Я думаю, что это добавит к вашему ответу. Одна из причин, по которой простой маршрут не вызывает больших проблем, заключается в том, что он не нарушает тригонометрические тождества, такие как sin (2x) = 2 * sin (x) * cos (x). –

0

Если вы делаете операции на таком большом количестве, конечно, вы собираетесь бежать из точности:

#include <iostream> 
#include <math.h> 

int main() { 
    long double i = 1; 
    std :: cout << sin (i) << "\n" << sin (i+0.1) << "\n"; 
    i = pow (10, 300); 
    std :: cout << sin (i) << "\n" << sin (i+0.1); 
} 

Выход:

0,841471

0,891207

-0.817882

-0.81788

Если вы не можете точно представлять входы, вы не можете точно представлять выходы. Вычитание pi*pow(10,int(log_10(n/pi)) или что-то еще хуже для «маленького» n, но когда n становится достаточно большим, вы просто добавляете шум к шуму, и это уже не имеет значения.

+2

Или, проще говоря, '1e300 + 2pi' =' 1e300 - 2pi' = '1e300', поэтому возможное точное значение, представленное '1e300' может иметь любую ценность как« грех »? –

+1

@Damien_The_Unbeliever Когда '1e300' округляется до ближайшего представляемого значения' double', это округление превышает интервал длины '1e284'. Поэтому, когда мы округляем '1e300' до представляемого« двойника », мы« проходим »очень много периодов длины в 2pi. Поэтому бессмысленно принимать «грех». Тем не менее, математически, после того, как мы округлили аргумент к представимому значению, можно вычислить 'sin' этого точного аргумента. Для этого требуется большая точность вашего представления '2pi'. Как я уже сказал в комментарии к другому ответу, в .NET, 'Sin (1e300) == 1e300'. –

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