Использование Math.exp() в Javascript с BigDecimal для больших чисел с плавающей запятой

Я пытаюсь выполнить следующий расчет в Javascript:

e^x / (1 + e^x)

где x — длинное число с плавающей запятой.

В этом случае мне требуется точность не менее 10-го знака после запятой.

Я использовал BigDecimal для точной обработки чисел с плавающей запятой, т.к. предлагается в Руководстве по операциям с плавающей запятой.

Моя первая попытка:

var foo = new BigDecimal(myVeryLongFloatingPoint)
var bar = Math.exp(foo);
var spam = bar.divide(bar.add(new BigDecimal("1")));

привело к ошибке (где xxxxx — число с плавающей запятой):

TypeError: Object xxxxx has no method 'add'

Поэтому я попытался преобразовать bar в объект BigDecimal:

var foo = new BigDecimal(myVeryLongFloatingPoint)
var bar = new BigDecimal(Math.exp(foo));
var spam = bar.divide(bar.add(new BigDecimal("1")));

что, в свою очередь, приводит к ошибке (где xxxxx - число с плавающей запятой):

BigDecimal(): Not a number: xxxxx

Где я ошибаюсь?

Является ли это разумным подходом к обработке такого рода вычислений с плавающей запятой, когда требуется высокая степень точности?


person Kenners    schedule 20.09.2011    source источник
comment
Что не так с использованием обычных (бинарных) поплавков? Если вы получаете переполнение, почему бы не переписать выражение в эквивалентной форме 1 / (1 + e^-x) и использовать его для положительного x?   -  person Mark Dickinson    schedule 20.09.2011
comment
Спасибо, я поиграю с этим.   -  person Kenners    schedule 30.09.2011


Ответы (3)


Вы должны передать строки в BigDecimal:

var bar = new BigDecimal(Math.exp(foo).toString());
person pimvdb    schedule 20.09.2011
comment
Спасибо - это исправило это для меня. - person Kenners; 30.09.2011

Есть несколько математических подходов, которые могут оказаться полезными. Если x положительное и достаточно большое, то вы берете отношение двух больших чисел, и это снизит вашу окончательную точность. Вместо этого вы можете:

  1. Вместо этого используйте 1./(1. + e^(-x)).
  2. Для больших x это приблизительно 1.-e^(-x), и чем больше x, тем лучше приближение (например, если x=100, ваша ошибка будет в 86-м разряде).

(Честно говоря, нужно проверить это, прежде чем использовать его, я просто выхожу из памяти и ничего не записываю, но если это выглядит полезным, я мог бы взять карандаш...)

person tom10    schedule 20.09.2011

Math.exp работает только с обычными числами и не может работать с большими десятичными числами. Math.exp, вероятно, преобразует foo в NaN (или что-то в этом роде), прежде чем продолжить.

Вы должны искать метод возведения в степень внутри вашего класса BigDecimal. Я посмотрел на источник и думаю, что вместо него можно использовать метод BigDecimal.pow.

person hugomg    schedule 20.09.2011