Подтвердить что ты не робот

Легкий Java Decimal Class

Я рассматриваю возможность записи двух ограниченных прецизионных альтернатив BigDecimal, а именно DecimalInt и DecimalLong. Они могли бы иметь дело с числами внутри реальных границ int и long с произвольным числом десятичных знаков, которые были бы созданы как в изменяемой, так и неизменной форме. Мой план состоит в том, чтобы сделать поддержку DecimalInt +/- 999,999,999 до +/- 0,999999999 и DecimalLong той же, но с до 18 цифрами.

Это можно было бы сделать, сохранив десятичное число с цифрой 0-9 для DecimalInt и 0-18 для DecimalLong вместе с фактическим значением, сохраненным как масштабированный int или long. Обычное использование было бы для небольшого количества десятичных знаков, например, для денег и цен на акции, обычно в 2-4 десятичных разряда.

Существенными требованиями являются (a) бережливый след (2 класса, плюс OverflowException) и (b) полная поддержка всех основных операций плюс вся математика, которая имеет смысл.

Поход по результатам не возвращал никаких очевидных ударов - все они, казалось, относились к произвольным десятичным знакам.

Мои вопросы: это уже сделано? Существуют ли скрытые тонкости в этом, почему это еще не сделано? Кто-нибудь слышал слухи о Java, поддерживающие десятичный тип, например DotNet.

EDIT: это отличается от BigDecimal, потому что он должен быть (a) чертовски более эффективным, чтобы не иметь дело с массивом ints, и (b) он не будет обертывать BigInteger, поэтому он будет более компактным по памяти и (c) он будет иметь изменяемый вариант, поэтому он будет быстрее и там. В итоге - меньше накладных расходов для простых случаев использования, таких как "Я хочу хранить баланс банка без накладных расходов BigDecimal и неточности двойного".

EDIT: Я намереваюсь выполнять всю математику с использованием int или long, чтобы избежать классической проблемы: 1586.60-708.75 = 877.8499999999999 вместо 877.85

4b9b3361

Ответ 1

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

Чтобы использовать ваш пример: для любого финансового приложения сохранение нескольких десятков байтов - это беспроблемная и ограниченная точность разрыва сделки (цены на акции у меня обычно составляют 2-4 цифры в США, но если вы хотите иметь дело с развивающимися рынками вы столкнетесь с валютами с безудержной инфляцией, где 15-значная сумма покупает вам половину буханки хлеба).

В принципе, это звучит как еще один случай преждевременной оптимизации.

Ответ 2

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

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

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

System.out.printf("%.2f%n", 1586.60-708.75);

печатает

877.85

Ответ 3

Если вы сосредоточены на переносных устройствах, посмотрите Real. Реальный позволяет точность числа, которое должно быть установлено от 0 до 16. Оно предназначено для мобильных телефонов MIDP.

Также представляем интерес для библиотеки конструктивных реал. Это не легкий, но.

В отношении приведенного ниже комментария вы можете не использовать Apache Commons Math Library для работы с фракциями? Есть ли причина, по которой это не сработает?

Ответ 4

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

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

Ответ 5

Мне кажется, что если вам нужна произвольная точность, вам понадобится число бит w90 для представления мантиссы. Это означает, что для мантиссы потребуется какая-то стратегия распределения массивов. Вы можете создать свой собственный здесь, но BigInteger делает это достаточно эффективно и работает

Вам нужно указать, какое наименьшее (ненулевое) значение вам нужно представлять. Это будет 10 ^ - (2 ^ n), где n + 1 - количество бит, которое вы выделяете экспоненте. С BigDecimal это 10 ^ - (2 ^ 31). Вы можете использовать произвольный размерный показатель, но этого диапазона должно быть достаточно для кого-либо.

Итак, вам нужно неограниченное целое число мантиссы, чтобы дать вам произвольную точность и показатель фиксированного размера, в зависимости от того, каким вы хотите иметь минимальное представляемое значение. По существу это BigDecimal; единственное изменение - вы будете использовать какой-то более мелкий объект, а не int, используемый BigDecimal. Я бы сомневался, стоит ли экономия на площади. Я бы подумал, что BigDecimal будет делать то, что вам нужно, с едва ли не больше использования памяти, чем любое решение, которое вы создаете сами.

Конечно, вы можете выбрать максимальное количество значимых цифр, которые вам понадобятся; то вам нужно фиксированное хранилище по размеру как для мантиссы, так и для экспоненты, а также для хранения гораздо меньше. Просто используйте фиксированное число длин в мантиссе.