Является ли реализация функции exp () с плавающей запятой в cmath эквивалентной усеченному разложению в ряд Тейлора очень высокого порядка? Один из возможных источников ошибки, о котором мы должны помнить, это конечность числа битов, представляющих ответ.
Является ли реализация функции exp () с плавающей запятой в cmath эквивалентной усеченному разложению в ряд Тейлора очень высокого порядка?
Эквивалент? Да. Это потому, что любая достойная реализация exp()
имеет ошибку половины ULP (единицы наименьшей точности) или около того. Игнорируя проблемы с арифметикой конечной точности, всегда можно построить усеченный ряд Тейлора, который делает то же самое.
Тем не менее, нет достойной реализации exp()
будет использовать расширение Тейлора. Это будет очень-очень медленно и не достигнет желаемой точности. Это было бы совершенно глупой реализацией. Намного лучше использовать тот факт, что между двумяИкс и еИкс и тот факт, что 2Икс довольно легко вычислить, учитывая почти универсальную степень 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. Если х довольно мало, то результат равен 0.
Пусть k = round (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 это не так.