Вычисление 1 - sqrt(x) для небольшого аргумента x (~10^-12), аналогично expm1 (в C/C++)

Я читал, что функция expm1 подходит для вычисления 1 - exp( x) для малых x без потери точности из-за усечения 1,0 на ~15 цифрах (для удвоения). Есть ли такая функция для 1 - sqrt(x)? На данный момент я просто использую очень большое разложение Тейлора, потому что мне требуется столько (предпочтительно все) цифр точности, сколько могут предложить двойные/длинные двойные числа.

Редактировать: здесь я сильно запутал свое намерение: я хочу вычислить 1 - sqrt(1-x) для x где-то между 10 ^ -12 и 1.


person zjw518    schedule 20.06.2017    source источник
comment
для вычисления 1 - exp(x)... тогда вы читаете задом наперед :) это для вычисления exp(x) - 1   -  person Cory Kramer    schedule 20.06.2017
comment
Вам бы помог поиск SO: stackoverflow.com/questions/8721022/   -  person duffymo    schedule 20.06.2017
comment
Чем double foo(double x) { return 1 - sqrt(x); } недостаточно для ваших нужд с небольшим x?   -  person chux - Reinstate Monica    schedule 21.06.2017
comment
@duffymo - это было бы потому, что я неправильно сформулировал вопрос. Я имел в виду 1 - sqrt(1-x). Должен ли я повторно опубликовать вопрос или отредактировать этот?   -  person zjw518    schedule 21.06.2017
comment
@ zjw518 Некоторые библиотеки (особенно Boost) предлагают функцию sqrt1pm1(), которая вычисляет sqrt(x+1)-1, что должно подойти для ваших целей, поскольку 1 - sqrt(1-x) = - sqrt1pm1(-x). Вы всегда можете создать разумную реализацию самостоятельно: double sqrt1pm1 (double a) { return a / (1.0 + sqrt (a + 1.0)); }   -  person njuffa    schedule 06.09.2017


Ответы (2)


Вопрос здесь кажется плохо мотивированным. В то время как exp(x) сходится к 1, когда x стремится к 0, это означает, что при той же точности с плавающей запятой exp(x)-1 имеет более значащие цифры, чем exp(x) для малых x, это неверно для sqrt(x) , который сходится к 0, когда x стремится к 0. Другими словами, exp(x)-1 можно сделать немного более точным, чем exp(x) для малых x, но то же самое неверно для 1-sqrt(x) -- что на самом деле ухудшится, поскольку вы переводите его с чего-то около 0 (1e-6) на что-то около 1 (0,999999).

Если, с другой стороны, вы хотите вычислить sqrt(1+x) для очень малого x (как точное измерение sqrt(x) очень близко к x=1), sqrt(1+x)-1 будет более точным вычисления с плавающей запятой. И его ряд Тейлора будет работать очень хорошо; Я нахожу, что для |x| ‹ 1e-9, x/2 - x^2/8 + x^3/16 является хорошим приближением sqrt(1+x)-1 в пределах среднеквадратичной дробной ошибки 3e-29 (с максимальным значением 8e- 29 по краям) -- в два раза больше цифр, чем в двойном. Даже квадратичное приближение, вероятно, достаточно хорошее (примерно с точностью до 20 цифр).

person jwimberley    schedule 20.06.2017
comment
Или вы можете использовать x / (sqrt(1+x) + 1), который алгебраически эквивалентен sqrt(1+x) - 1, но не имеет артефактов отмены для маленьких x. - person Daniel Schepler; 20.06.2017
comment
Вы правы, @jwimberley, я имел в виду 1 - sqrt(1-x). Мое намерение состоит в том, чтобы иметь функцию, которая работает для x от 10 ^ -12 до 1. Я плохо сформулировал вопрос (я запутался, прочитав о expm1). В настоящее время у меня есть ~ 20 терминов в расширении, чтобы быть в безопасности, поэтому я могу переключиться на использование sqrt в x ~ .01 - было бы здорово, если бы существовала функция, которая инкапсулирует это (и, конечно, быстрее). Хотя предложение Даниэля выглядит многообещающе. - person zjw518; 21.06.2017
comment
Вы можете изменить любое из наших предложений в соответствии с вашими целями. @DanielSchepler, вероятно, лучше: просто вычислите -x/(1+sqrt(1-x)) в таком порядке. Это равно x*(1-sqrt(1-x))/(1-(1-x)) = 1-sqrt(1-x), но не зависит от отмены для достижения точности. - person jwimberley; 21.06.2017
comment
(Мой -x в комментарии выше опечатка) - person jwimberley; 21.06.2017

функция expm1 подходит для вычисления 1 - exp(x).

Как можно прочитать в ref:

Для небольших значений величины x expm1 может быть более точным, чем exp(x)-1.


Есть ли такая функция для 1 - sqrt(x)?

Нет, по крайней мере, не в стандартных заголовках.

person gsamaras    schedule 20.06.2017
comment
Обратите внимание, что 1 - exp(x) = - expm1(x), поэтому expm1() на самом деле хорошо подходит для этого вычисления. - person njuffa; 06.09.2017
comment
Вы заявили: это наоборот, что я воспринял как противоречие expm1 .. подходит для вычисления 1 - exp(x). - person njuffa; 06.09.2017
comment
Я знаком с проблемой: постить перед первой чашкой кофе не советую :-) - person njuffa; 06.09.2017