У меня есть куча чисел с плавающей запятой (двойники Java), большинство из которых очень близки к 1, и мне нужно перемножить их вместе как часть более крупного вычисления. Мне нужно сделать это часто.
Проблема в том, что у двойников Java нет проблем с такими числами, как:
0.0000000000000000000000000000000001 (1.0E-34)
они не могут представлять что-то вроде:
1.0000000000000000000000000000000001
Следовательно, я быстро теряю точность (для двойников Java предел составляет около 1.0000000000000001).
Я думал просто хранить числа с вычтенной 1, поэтому, например, 1,0001 будет храниться как 0,0001, но проблема в том, что для их повторного умножения мне нужно добавить 1, и в этот момент я теряю точность.
Чтобы решить эту проблему, я мог бы использовать BigDecimals для выполнения вычислений (преобразовать в BigDecimal, добавить 1,0, затем умножить), а затем преобразовать обратно в двойные числа, но у меня есть серьезные опасения по поводу последствий этого для производительности.
Может ли кто-нибудь увидеть способ сделать это, избегая использования BigDecimal?
Изменить для ясности: это крупномасштабный совместный фильтр, в котором используется алгоритм оптимизации градиентного спуска. Точность является проблемой, потому что часто совместный фильтр имеет дело с очень небольшими числами (например, вероятность того, что человек нажмет на рекламу продукта, которая может составлять 1 из 1000 или 1 из 10000).
Скорость является проблемой, потому что совместный фильтр должен быть обучен на десятках миллионов точек данных, если не больше.