Является ли реализация функции exp() с плавающей запятой в cmath эквивалентной усеченному расширению ряда Тейлора очень высокого порядка? Один из возможных источников ошибки, о котором следует помнить, — это конечность числа битов для представления ответа.
Является ли реализация функции exp() с плавающей запятой эквивалентной расширению усеченного ряда Тейлора?
Ответы (4)
Является ли реализация функции exp() с плавающей запятой в cmath эквивалентной усеченному расширению ряда Тейлора очень высокого порядка?
Эквивалент? Да. Это потому, что любая приличная реализация exp()
имеет ошибку в половину ULP (единица наименьшей точности) или около того. Игнорируя проблемы с арифметикой конечной точности, всегда можно построить усеченный ряд Тейлора, который делает то же самое.
Однако никакая приличная реализация exp()
не будет использовать расширение Тейлора. Это было бы очень-очень медленно и не достигло бы желаемой точности. Это была бы откровенно глупая реализация. Гораздо лучше использовать тот факт, что существует сильная связь между 2x и ex, а также тот факт, что 2x довольно легко вычислить. вычислить, учитывая почти универсальную мощность 2 представления чисел с плавающей запятой.
Это зависит от реализации компилятора, среды выполнения C и процессора. Однако тот, кто вычисляет показатель степени, вряд ли будет использовать разложение Тейлора, поскольку существуют лучшие методы.
Согласно glibc, он может использовать свою собственную реализацию, которая говорит об этом в комментарии (из sysdeps/ieee754/dbl-64/e_exp.c):
/* An ultimate exp routine. Given an IEEE double machine number x */
/* it computes the correctly rounded (to nearest) value of e^x */
Или он может использовать аппаратно поддерживаемые инструкции процессора для вычислений с плавающей запятой, как в x86 FPU. В обоих случаях вы, вероятно, получите правильно округленное значение с полной точностью.
Просто пример того, как вы можете рассчитать exp (x):
Если x достаточно велико, результатом будет +inf. Если x достаточно мал, то результат равен 0.
Пусть k = округлое (x/ln 2). Тогда exp (x) = 2^k * exp (x - k ln 2). 2^k очень легко вычислить. Небольшая проблема состоит в том, чтобы вычислить x - k ln 2 без какой-либо ошибки округления. Это довольно просто: пусть L1 = ln 2 округляется до 35 бит, а L2 = ln 2 - L1. k — небольшое целое число, поэтому k * L1 не имеет ошибки округления, равно как и x — k * L1; затем мы вычитаем k * L2, что мало и, следовательно, имеет небольшую ошибку округления.
Чтобы сделать это быстрее (без деления), вычисляем k = round(x * (1/ln 2)). И мы проверяем, близко ли x к нулю, так что весь расчет не нужен. В любом случае, теперь мы вычисляем exp (x), где результат находится между sqrt (1/2) и sqrt (2).
Вы можете вычислить exp (x), используя полином Тейлора. Вместо этого вы, вероятно, использовали бы полином Чебычева, минимизирующий ошибку отсечки с гораздо более низкой степенью. С некоторой осторожностью вы можете найти многочлен с ошибкой отсечения, существенно меньшей, чем младший бит результата.
Это зависит от того, какую реализацию библиотеки C вы используете. В очень популярном glibc это не так.