LINUX.ORG.RU

Хочу портировать System.Decimal в Java

 , ,


0

1

Нужен нормальный класс для работы с деньгами, но BigDecimal избыточен, в том числе для хранения в оперативке и в БД. Посмотрел javamoney FastMoney - он убог на нем дальше фиата не уедешь (да и то с натяжкой), а мне нужно ещё битки и прочие эфиры (18 знаков после запятой) калькулировать.

И тут глянул C# System.Decimal - подходит идеально. Единственно смутило, что вся реализация вынесена в Си. Но там я глянул, вроде ничего сверхъестественного или JIT шарпа настолько убог, что решили не рисковать?

В общем, жду напутствия, может я какой велосипед изобретаю?

★★★★★

Последнее исправление: foror (всего исправлений: 2)

Единственно смутило, что вся реализация вынесена в Си

Возможно ли оформить этот код в библиотеку, дёргая его потом через какой-нибудь JNI?

И лучше переписать всё с С на Java, раз там нет ничего сверхъестественного?

EXL ★★★★★
()

BigDecimal избыточен, в том числе для хранения в оперативке и в БД.

А что именно не так? Тем более в БД хранится ровно так, как напишешь сериализатор.

мне нужно ещё битки и прочие эфиры (18 знаков после запятой)

Да, тут лучше что-то своё и создать наверное, раз производительность критична.

Но там я глянул, вроде ничего сверхъестественного или JIT шарпа настолько убог, что решили не рисковать?

Очень может быть, что дело ни разу не в JIT, а в том же самом, из-за чего вам может не нравиться java.math.BigDecimal, нагрузка на сборщик мусора из-за куча ненужных часто лишних объектов.

BattleCoder ★★★★★
()
Ответ на: комментарий от BattleCoder

Очень может быть, что дело ни разу не в JIT, а в том же самом, из-за чего вам может не нравиться java.math.BigDecimal, нагрузка на сборщик мусора из-за куча ненужных часто лишних объектов.

Никаких проблем с BigDecimal нет и быть не может. Вся криптография в жаве на BigInteger написана, а она крайне критична к времени выполнения. В BigInteger по сути то же, что в BigDecimal. Там всё отшлифовано настолько, что разве что GMP-биндинги смогут сравниться, думаю, их ищущий тоже найдёт, если это нужно.

Legioner ★★★★★
()
Ответ на: комментарий от EXL

Возможно ли оформить этот код в библиотеку, дёргая его потом через какой-нибудь JNI?

Можно, но проще на джаве запилить.

foror ★★★★★
() автор топика
Ответ на: комментарий от BattleCoder

А что именно не так? Тем более в БД хранится ровно так, как напишешь сериализатор.

BigDecimal медленней на порядок, занимает под 32 байта на значение. А в System.Decimal четко 16 байт из 4 интов. И не надо писать сериализатор, опять же место можно сэкономить, когда у тебя миллиарды подобных объектов.

нагрузка на сборщик мусора из-за куча ненужных часто лишних объектов.

В том то и дело, там только битовые и арифметические операции над интами 32 битными.

foror ★★★★★
() автор топика
Последнее исправление: foror (всего исправлений: 2)
Ответ на: комментарий от Legioner

Никаких проблем с BigDecimal нет и быть не может. Вся криптография в жаве на BigInteger написана, а она крайне критична к времени выполнения.

А кто тебе сказал, что она быстрая? BigInteger немного проще BigDecimal, но вот последний на порядок будет медленнее 128 битного флоата. Просто уже из того, что бесплатно ты не заполучишь универсальную точность. А так есть тесты и примеры.

foror ★★★★★
() автор топика
Последнее исправление: foror (всего исправлений: 1)
Ответ на: комментарий от Legioner

Ты странное что-то выдаешь. BigDecimal и BigInteger - 2 разных класса. Это далеко не одно и тоже.

crutch_master ★★★★★
()

Используй long и не выпендривайся.

cocucka ★★★★☆
()

Так, а чего-то не врубаюсь, мне тут говорили C# открыт во все поля и мелкомягкие теперь белые и пушистые. А я банально не могу найти реализацию Decimal.cpp из mscorlib не от Васянов. Где оно официально лежит? На джаве такой херни нету.

foror ★★★★★
() автор топика
Ответ на: комментарий от foror

BigDecimal медленней на порядок, занимает под 32 байта на значение. А в System.Decimal четко 16 байт из 4 интов.

Так в Java заголовки объектов [url=https://www.baeldung.com/java-memory-layout]в принципе жирные[/url]:

For normal objects in Java, represented as instanceOop, the object header consists of mark and klass words plus possible alignment paddings. After the object header, there may be zero or more references to instance fields. So, that’s at least 16 bytes in 64-bit architectures because of 8 bytes of the mark, 4 bytes of klass, and another 4 bytes for padding.

А System.Decimal — структурка, value type без жирного заголовка, вот тебе и 16 байт разницы.

Напишешь ты свой класс с четырьмя интами? 16 байт на инты + 16 байт — заголовок. Те же 32 байта. И чего?

Для библиотечного BigDecimal хотя бы есть шанс наличия специальных оптимизаций в JVM.

korvin_ ★★★★★
()
Последнее исправление: korvin_ (всего исправлений: 1)
Ответ на: комментарий от korvin_

Причем тут джава заголовки, в джаве «со дня на день» ValueType в preview вылезет с primitive классами и ваши шарпы по итогу будут не нужны вообще.

Для библиотечного BigDecimal хотя бы есть шанс наличия специальных оптимизаций в JVM.

Нет там специальных оптимизаций. Есть тесты https://github.com/m-vokhm/Quadruple - вот здесь один Васян написал свой 128 битный тип с плавающей запятой и он тупо в 4-10 раз быстрее BigDecimal.

foror ★★★★★
() автор топика
Последнее исправление: foror (всего исправлений: 1)
Ответ на: комментарий от foror

в джаве «со дня на день» ValueType в preview вылезет с primitive классами

Ну вот когда вылезет, тогда и. Посмотрим ещё насколько они и вправду будут value и primitive.

ваши шарпы

Не наши.

тип с плавающей запятой.

Ясно понятно. Ну используй long, как уже предложили выше, например, класс с двумя полями: значение в «копейках» + ссылка на объект валюты, в котором есть коэффициент для приведения к «рублям». Либо класс с тремя тремя полями: копейки, коэффициент, ссылка на валюту, чтоб не ходить по ссылке за коэффициентом при расчётах/конверсиях и т.п.

Если не хватает одного лонга для этих ваших битков, используй два.

korvin_ ★★★★★
()
Последнее исправление: korvin_ (всего исправлений: 1)
Ответ на: комментарий от korvin_

Если не хватает одного лонга для этих ваших битков, используй два.

Зачем мне изобретать велосипед? Вот уже есть System.Decimal с 4-ми интами, полностью реализован и оттестирован в компаниях. Я лишь спрашиваю, может что упустил и на джаве есть готовый, оттестированный его аналог. Но похоже нет, уже весь инет перерыл.

foror ★★★★★
() автор топика

system.Decimal

аналога я в своё время не нашёл. если битки не укладываются в JSR 354: Money and Currency ( javamoney.org ) , а BigDecimal не подходит по скорости (а он на многие порядки медленнее, чем простой double), то скорее всего нужон велосипед.

пс. как я понимаю, микрософтовский decimal появился вследствие позиционирования .net, как финансового инструмента, microsoft .net на всякие биржи и финансовые анализаторы двигал очень активно и даже как я понимаю в этом преуспел. java туды никто не продвигал, так что в этом плане у неё всё грустно.

vtVitus ★★★★★
()
Последнее исправление: vtVitus (всего исправлений: 1)
Ответ на: комментарий от PhysShell

Неа, там должен быть как минимум метод FCallMultiply, над которым в шарпе обертка. Вот оно https://github.com/Unity-Technologies/SimpleUIDemo/blob/master/Tiny3D/Library/DotsRuntimeBuild/artifacts/Stevedore/il2cpp/libil2cpp/icalls/mscorlib/System/Decimal.cpp Но я не могу понять где официальный источник. На гитхабе ещё под сотню Васянов имеют подобные сырцы. Но я хотел бы портировать с официального репа в идеале.

foror ★★★★★
() автор топика
Ответ на: комментарий от iZEN

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

foror ★★★★★
() автор топика
Ответ на: комментарий от hummer

Ещё пишут на c, c++, php, go, python и прочем говне и не жалуются. Но это не значит, что все ок.

foror ★★★★★
() автор топика
Ответ на: комментарий от hummer

Просто нормальные поцоны испокон веков использовали long для этого, а бигдецимал для ленивых хипстерков

anonymous
()
Ответ на: комментарий от foror

Объём памяти должен быть ровно такой, какой необходим для выбранной точности. А про производительность ты откуда взял? Сам замерял или прочитал где и можешь ссылкой поделиться?

hummer
()
Ответ на: комментарий от hummer

Я замерял. Сравнивал с double на разных операциях медленнее в сотни, а иногда в тыщи раз (в своё время). По сравнению с с/c++ long проседания я думаю будут космические. Я кстати видел в продаже библиотеку для денег с сишной (правда ещё для 32битной java) частью, там декларировался выигрыш в производительности от 100 до 10000 раз. Ссылок миллион например https://stackoverflow.com/revisions/3111cc09-2ac5-44f8-9c00-1ecfaab165e2/view-source да ты и сам их можешь налепить и проверить.

vtVitus ★★★★★
()
Ответ на: комментарий от vtVitus

Сравнивал с double на разных операциях медленнее в сотни, а иногда в тыщи раз

Но такое сравнение некорректное. Сравнивать нужно не с double, а с каким-то другим аналогом для вычислений произвольной точности.

hummer
()
Последнее исправление: hummer (всего исправлений: 1)
Ответ на: комментарий от hummer

Про сотни и тысячи раз, это наверное трындеж, но разица на порядок конечно есть

Бенчмаркалось так https://pastebin.com/JSbcpbCA

Не претендую на качественный бенчмарк, но порядок цифр он позволяет оценить

Без форков, т.к. целый час ждать результата мне было лень

# JMH version: 1.28
# VM version: JDK 11.0.11, OpenJDK 64-Bit Server VM, 11.0.11+9-LTS
Benchmark                                       Mode  Cnt     Score    Error  Units
BigDecimalBenchmark.testBigDecimalMath          avgt    5  1051.169 ± 87.081  ns/op
BigDecimalBenchmark.testBigDecimalMathWithEval  avgt    5  1325.847 ± 76.865  ns/op
BigDecimalBenchmark.testDoubleMath              avgt    5    31.036 ±  0.516  ns/op
BigDecimalBenchmark.testQuadruple               avgt    5   159.997 ±  0.670  ns/op

double в 40 раз быстрее BigDecimal (кто бы сомневался)

А квадрупль в 8 раз быстрее BigDecimal

Стоит ли заменять условно стабильную и оттестированную библиотеку для арифметики на собственный велосипед для укорения в 8-40 раз операций с деньгами? пусть решает каждый для себя сам

Для любого биллинга, как по мне, это все экономия на спичках. Для HFT - наверное важно. Но писать HFT под Hotspot - это такая себе идея, а как будет себя вести BigDecimal на Azul Zing и ему подобных - в глаза их не видел

А если подрезюмировать, то да, если заменить BigInteger+int на bool+int+long+long то производительность возростает драматически.

Приблизительно так же реализовано и в CoreCLR, который фигурировал в этом треде. Сравнимо ли это с BigDecimal - нет. Стоит ли бесконечная точность x10 оверхеда(а наверное на add/sub будет еще больше, я в тест намеренно засунул div), тут уже решать потребителю.

anonymous
()
Ответ на: комментарий от anonymous

Но писать HFT под Hotspot - это такая себе идея

угу https://github.com/LMAX-Exchange/disruptor

да и бенчить надо допустим расчет коммисии биржевой в wei.

этоже бабки какой дабл, вся бухгалтерия разъедется, лол.

drsm ★★
()
Последнее исправление: drsm (всего исправлений: 1)

Начинаю потихоньку портировать и сразу натолкнулся на конструкцию: *(uint*)&f >> 23 аналог в джаве Float.floatToRawIntBits(f) >> 23 Но есть нюанс, существует еще floatToIntBits(float) разница между ними:

Returns a representation of the specified floating-point value according to the IEEE 754 floating-point "single format" bit layout, **preserving Not-a-Number (NaN) values.**

Я выбрал с preserving Not-a-Number (NaN) values. или мой выбор неверен?

foror ★★★★★
() автор топика
Ответ на: комментарий от EXL

На текущий момент BigDecimal джавовский складывает int-ы быстрее на 30%, long-и в 2 раза быстрее. Но на сложении double-ов проигрывает в 10-15 раз портированому Decimal.

foror ★★★★★
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.