Мне нужно вычислить sqrt(1 + (x/2)^2) + x/2
численно для положительного x
. Использование этого выражения напрямую не работает для очень больших значений x
. Как я могу переписать его, чтобы получить более точную оценку?
Точный sqrt(1 + (x/2)^2) + x/2
Ответы (4)
Для очень больших x
вы можете выделить x/2
:
sqrt(1 + (x/2)^2) + x/2
= (x/2) * sqrt( 1/(x/2)^2 + (x/2)^2/(x/2)^2) + x/2
= (x/2) * sqrt( (2/x)^2 + 1 ) + x/2
Для x > 2/sqrt(eps)
квадратный корень фактически будет равен 1, и все ваше выражение упростится до x
. Предполагая, что вам нужно охватить весь диапазон [0, infinity]
, я бы предложил просто разветвиться в этой точке и вернуть x
в этом случае и исходную формулу, иначе:
if x > 2/sqrt(eps) // eps is the machine epsilon of your float type
return x
else
return sqrt(1 + (x/2)^2) + x/2
x
.
- person becko; 25.08.2020
x = 1
?
- person becko; 25.08.2020
(4/x)
может переполниться для очень маленьких x
, поэтому по крайней мере один из них должен учитывать другой sqrt(4)
: sqrt(x) * sqrt((1/x) + x/4) + (x/2)
-- но вам все равно нужно ветвление для 0 (и, возможно, для субнормальных значений) и вы необходимо вычислить два sqrt
(вместо одного), а также один обратный.
- person chtz; 26.08.2020
(4/x)
будет распространять +Inf
в расчет, скажем, на небольшое ниже нормального значение - вопрос явно касается только (x > 0)
.
- person Brett Hale; 26.08.2020
Многие языки программирования предлагают функцию hypot(x,y)
, которая вычисляет sqrt (x*x + y*y)
, избегая при этом переполнения и потери значимости в промежуточных вычислениях. Многие реализации hypot
также вычисляют результат более точно, чем наивное выражение. Эти преимущества достигаются за счет умеренного увеличения времени работы.
С помощью этой функции данное выражение можно записать как hypot (1.0, 0.5*x) + 0.5*x
. Если выбранный вами язык программирования не поддерживает hypot
или эквивалентную функцию, вы можете адаптировать реализацию, которую я предоставил в этом ответе а>.
Примечание. Было отмечено, что выражение, сгенерированное Херби, может не подходить во всех контекстах. В частности, метрики, используемые для улучшения выражения Херби, могут генерировать выражения, которые хуже работают для вашего конкретного сценария. Итак, примите его выход с зерновой солью. Я думаю, вы все еще можете проконсультироваться с Херби, чтобы получить представление, но не используйте его в качестве замены.
Херби (https://herbie.uwplse.org/) рекомендует следующую замену вашего выражения:
Or, in C:
double code(double x) {
return ((double) (((double) sqrt(((double) (1.0 + ((double) pow((x / 2.0), 2.0)))))) + (x / 2.0)));
}
становится:
double code(double x) {
double VAR;
if (((x / 2.0) <= -8569.643649604539)) {
VAR = (1.0 / ((double) ((1.0 / ((double) pow(x, 3.0))) - ((double) (x + (1.0 / x))))));
} else {
double VAR_1;
if (((x / 2.0) <= 7.229769585372425e-11)) {
VAR_1 = ((double) ((x / 2.0) + ((double) sqrt(((double) (1.0 + ((double) pow((x / 2.0), 2.0))))))));
} else {
VAR_1 = ((double) ((x / 2.0) + ((double) (((double) ((1.0 / x) + ((double) (x * 0.5)))) - (1.0 / ((double) pow(x, 3.0)))))));
}
VAR = VAR_1;
}
return VAR;
}
Он генерирует подробный отчет о том, почему он разбивает его на три области. Вывод Herbie может быть довольно трудным для чтения, и, как сообщается, он может быть не лучше, но, возможно, он может обеспечить альтернативное представление.
7.23e-11
выглядит ложным — и действительно, попытка аргумента типа 1e-9
с использованием последней ветки дает что-то близкое к -1e27
, в то время как это должно быть значение, близкое к 1. При предоставлении предварительного условия x>=0
это дает результат, который выглядит более правдоподобным, хотя : ссылка (не уверена, что это стабильная).
- person chtz; 26.08.2020
sqrt(1+x^2) - x
(у которого есть числовые проблемы, которые решаются с помощью 1 / (sqrt(1+x^2) + x)
для положительного x
), дает сумасшедший результат.
- person Mark Dickinson; 26.08.2020
hypot()
Гипотетические функции вычисляют квадратный корень из суммы квадратов x и y без чрезмерного переполнения или потери значимости. Может возникнуть ошибка диапазона.
Затем код может получить лучший результат с hypot(1,x/2) + x/2
;