Что делать с производительностью Java BigDecimal? - PullRequest
58 голосов
/ 04 марта 2009

Я пишу приложения для торговли валютой, чтобы жить, поэтому мне приходится работать с денежными значениями (обидно, что у Java все еще нет десятичного типа с плавающей запятой и нет ничего, чтобы поддерживать денежные вычисления произвольной точности). "Используйте BigDecimal!" - Вы могли бы сказать. Я делаю. Но теперь у меня есть некоторый код, где производительность является проблемой, а BigDecimal более чем в 1000 раз (!) Медленнее, чем double примитивы.

Расчеты очень просты: система вычисляет a = (1/b) * c много раз (где a, b и c - значения с фиксированной точкой). Проблема, однако, заключается в этом (1/b). Я не могу использовать арифметику с фиксированной точкой, потому что нет фиксированной точки. И BigDecimal result = a.multiply(BigDecimal.ONE.divide(b).multiply(c) не только уродлив, но и вяло медленен.

Что я могу использовать для замены BigDecimal? Мне нужно как минимум 10-кратное увеличение производительности. В остальном я нашел превосходную библиотеку JScience , которая имеет арифметику произвольной точности, но она даже медленнее, чем BigDecimal.

Есть предложения?

Ответы [ 20 ]

1 голос
/ 04 марта 2009

1 / b также не совсем представимо с BigDecimal. См. Документацию по API, чтобы понять, как округляется результат.

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

1 голос
/ 18 июня 2012

Я знаю, что пишу в очень старой теме, но это была первая тема, найденная Google. Рассмотрите возможность перемещения ваших расчетов в базу данных, из которой вы, вероятно, берете данные для обработки. Также я согласен с Гаретом Дэвисом, который написал:

. В большинстве болотных веб-приложений накладные расходы на доступ к jdbc и доступ к другой сети ресурсы затопляют любую выгоду от очень быстрой математики.

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

1 голос
/ 04 мая 2011

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

Расчет bigdeciaml также дает больше / меньше копейки, рассмотрим случай 100/3.

0 голосов
/ 27 апреля 2017

На 64-битной JVM создание BigDecimal, как показано ниже, делает его примерно в 5 раз быстрее:

BigDecimal bd = new BigDecimal(Double.toString(d), MathContext.DECIMAL64);
0 голосов
/ 12 сентября 2013

Commons Math - Математическая библиотека Apache Commons

http://mvnrepository.com/artifact/org.apache.commons/commons-math3/3.2

Согласно моему собственному сравнительному анализу для моего конкретного случая использования, он в 10 - 20 раз медленнее, чем в два раза (намного лучше, чем в 1000 раз) - в основном для сложения / умножения. После бенчмаркинга другого алгоритма, который имел последовательность дополнений и возведения в степень, снижение производительности было немного хуже: 200x - 400x. Так что это выглядит довольно быстро для + и *, но не для exp и log.

Commons Math - это библиотека легких, автономных математических и статистических компонентов, предназначенных для решения не самых распространенных проблем. доступно на языке программирования Java или Commons Lang.

Примечание. API защищает конструкторы для принудительного использования фабричного шаблона, присваивая имя фабрике DfpField (а не несколько более интуитивно понятному DfpFac или DfpFactory). Таким образом, вы должны использовать

new DfpField(numberOfDigits).newDfp(myNormalNumber)

для создания экземпляра Dfp, тогда вы можете позвонить .multiply или что-то еще по этому поводу. Я думал, что упомяну это, потому что это немного сбивает с толку.

0 голосов
/ 04 марта 2009

Возможна ли JNI? Возможно, вам удастся восстановить некоторую скорость и потенциально использовать существующие нативные библиотеки с фиксированной точкой (может быть, даже некоторые SSE * тоже хорошо)

Возможно http://gmplib.org/

0 голосов
/ 30 октября 2010

Кажется, самое простое решение - использовать BigInteger вместо long для реализации решения Песто. Если это кажется грязным, было бы легко написать класс, который упаковывает BigInteger, чтобы скрыть точность настройки.

0 голосов
/ 04 марта 2009

Можете ли вы дать более глубокое понимание цели расчета?

То, с чем вы имеете дело, - это компромисс между скоростью и точностью. Насколько велика будет потеря точности, если вы переключитесь на примитив?

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

Возможно, вы можете позволить пользователю быстро просмотреть результат, используя double, а затем запросить более точное значение, используя BigDecimal, если они пожелают?

0 голосов
/ 11 марта 2009

Подобная проблема была в системе торговли акциями еще в 99 году. В самом начале разработки мы решили, чтобы каждое число в системе было представлено как длинное, умноженное на 1000000, таким образом, 1,3423 было 1342300L. Но основным драйвером для этого был отпечаток стопы памяти, а не прямолинейная производительность.

Одно слово предостережения, я бы не стал делать это снова сегодня, если бы не был действительно уверен, что математические показатели были сверхкритическими. В большинстве болотных стандартных веб-приложений накладные расходы на доступ к jdbc и доступ к другим сетевым ресурсам сводят на нет все преимущества очень быстрой математики.

0 голосов
/ 04 марта 2009

Может быть, вам стоит изучить десятичную арифметику с аппаратным ускорением?

http://speleotrove.com/decimal/

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...