машина эпсилон — длинный двойной в стек переполнение

Я хотел рассчитать на машине Эпсилон, наименьшее возможное число e это дает 1 + e > 1 используя разные типы данных C ++: float, double а также long double,

Вот мой код:

#include <cstdio>

template<typename T>
T machineeps() {

T epsilon = 1;
T expression;

do {
epsilon = epsilon / 2;
expression = 1 + epsilon;
} while(expression > 1);

return epsilon;
}

int main() {
auto epsf = machineeps<float>();
auto epsd = machineeps<double>();
auto epsld = machineeps<long double>();

std::printf("epsilon float: %22.17e\nepsilon double: %22.17e\nepsilon long double: %Le\n", epsf, epsd, epsld);

return 0;
}

Но я получаю этот странный вывод:

epsilon float: 5.96046447753906250e-008
epsilon double: 1.11022302462515650e-016
epsilon long double: -0.000000e+000

Значения для float а также double это то, что я ожидал, но я не могу объяснить long double поведение.

Может кто-нибудь сказать мне, что пошло не так?

0

Решение

Я не могу воспроизвести ваши результаты. Я получил:

эпсилон длинный двойной: 5.421011e-20

В любом случае, по логике, код должен выглядеть примерно так:

template<typename T>
T machineeps() {
T epsilon = 1, prev;
T expression;

do {

prev = epsilon;
epsilon = epsilon / 2;
expression = 1 + epsilon;

} while (expression > 1);

return prev;  // <-- `1+prev` yields a result different from one
}

На моей платформе это производит значения, подобные std::numeric_limits::epsilon:

epsilon float: 1.19209289550781250e-07

двойной эпсилон: 2.22044604925031308e-16

эпсилон длинный двойной: 1.084202e-19

(обратите внимание на другой порядок величины)

1

Другие решения

Здесь происходит несколько вещей.

Во-первых, математика с плавающей точкой часто выполняется с максимально доступной точностью, независимо от фактического объявленного типа переменной с плавающей точкой. Так, например, арифметика на floats обычно выполняется с точностью 80 бит на оборудовании Intel (Java изначально запретил это, требуя, чтобы вся математика с плавающей точкой выполнялась с точной точностью типа; это убивало производительность с плавающей точкой, и они быстро отказались от этого правила). Предполагается, что при сохранении результата вычисления с плавающей запятой значение будет усечено до соответствующего типа, но по умолчанию большинство компиляторов игнорируют это. Вы можете сказать своему компилятору не допускать этого; переключатель для этого зависит от компилятора. Как и вы, вы не можете рассчитывать на результат, который рассчитывается здесь.

Во-вторых, цикл в коде заканчивается, когда значение 1 + epsilon является не больше 1, поэтому возвращаемое значение будет меньше, чем истинное значение эпсилона.

В-третьих, в сочетании со вторым некоторые реализации с плавающей запятой не имеют субнормальных значений; как только показатель степени станет меньше, чем наименьшее из представленных значений, значение будет равно 0. Это может быть тем, что вы видите здесь с long double значение. IEEE с плавающей точкой обрабатывает нули менее резко — как только вы достигнете минимального показателя, меньшие значения постепенно теряют точность. Существует довольно много значений между наименьшим нормированным значением и 0.

0

По вопросам рекламы ammmcru@yandex.ru
Adblock
detector