Pull to refresh

Comments 20

Что есть "огрубления результатов в operator std::string() const" ?

Если результат произведения дробной части на вес разряда не помещается в uint64_t, то происходит вот это

while ((std::numeric_limits<uint64_t>::max() / current_fraction) < current_unit)
            {
                uint8_t least_bit = current_fraction & least_bit_mask;
                current_unit /= 5;
                current_fraction = (current_fraction + least_bit)/ 2;
            }

С фиксированной запятой, а не точкой

А BCD в C++ уже отменили? Насколько помню, арифметика с фиксированной точкой реализуется через BCD.

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

а) не отменили, не знаю кто так реализовывает - будет неудобно

б) при работе с каким-нить int и его переполнением компилятор вам ничего не скажет, во всяком, без включения санитайзеров, я тоже решил так не делать - можно ли это сделать? конечно, и не особо сложно

не отменили, не знаю кто так реализовывает - будет неудобно

Дело в том, что современные процессоры, если не ошибаюсь, BCD арифметику поддерживают.

Насчет "кто" - например, IBM. Тип DecimalT<n,m>, совпадающий с SQL типом DECIMAL(N,M) реализован именно через BCD.

И это будет ничуть не неудобнее, чем вот это все вот что выше.

при работе с каким-нить int и его переполнением компилятор вам ничего не скажет

Вы считаете это нормальным? Я - нет. Потому что результат дальнейших вычислений становится некорректным, а вы про это знать не знаете.

А поскольку fixed point широко используется в финансовых расчетах, к вам очень быстро придут с претензией - "у меня на счете должно быть 1 000 000 000 а по факту всего 1 000 - где остальное?" И там "компилятор мне ничего не сказал" за отмазку не сканает, поверьте...

а) если вы хорошо разбирайтесь в теме - давайте ссылки где написано, что этот Decimal реализован через BCD. Подозреваю, что там сделано так из-за изначальной заточенности именно под десятичную систему счисления, я себе таких ограничений не ставил. Современные процессоры обычную двоичную арифметику, тоже поддерживают, кстати

б) проблема мне понятная и известная, но выберите за базовый тип достаточно жирный что б избежать переполнения

в) статья носит иллюстративный характер, главный посыл: "есть double/float они не очевидные и сложно устроены, а смотрите как можно было б"

если вы хорошо разбирайтесь в теме - давайте ссылки где написано, что этот Decimal реализован через BCD

Я в этой систем работаю. IBM i.

Чтобы понять как это работает, достаточно посмотреть что такое BCD и что такое packed decimal у IBM (это тот самый DECIMAL в SQL, _DecimalT<> в C++) Улавливаете сходство (мягко говоря)?

Современные процессоры обычную двоичную арифметику, тоже поддерживают, кстати

Речь о том, для современного процессора вы можете написать реализацию, которая будет работать с фиксированной точкой (BCD) без конвертаций туда-сюда, на уровне инструкций процессора.

Т.е. не эмуляцию, а полноценную реализацию. Что и реализовано у IBM (правда, мы не с x86 работаем, а с рисковыми Power процессорами - подозреваю, что там возможности процессора по работе с BCD побогаче). Т.е. там нет каких-то специальных библиотек. Все это поддерживается на уровне "машинных инструкций" (низкоуровневые примитивные команды)

Там, кстати, еще есть полезные вещи - операции с округлением. Скажем, есть у вас есть два переменных:

A типа decimal(5.3)

и

B типа decimal(4,2)

Так вот, если A = 3.245, то присвоение B = A без округления даст B = 3.24, а присвоение с округлением - B = 3.25

проблема мне понятная и известная, но выберите за базовый тип достаточно жирный что б избежать переполнения

Переполнение - нештатная ситуация. И может возникнуть вне зависимости от жирноты базового типа.

Вопрос в том - заметите вы его сразу, или потащите кривой результат дальше с видом что "так и надо"?

То, как это сделано в С++ не отмазка. Там много чего оставлено на усмотрение конечного разработчика.

Понимаете, автор не работал с системами IBM и с SQL тоже не каждый день работает, я предположил почему там используют BCD - в принципе, идея интересная (может я её даже реализую). Но очевидно, это не является каким-то единственно верным и божественным вариантом реализации. Далее, этот код не взят из какого-либо продукта, буду я контролировать переполнения или нет - мое дело, как автора, если вам хочется - скопируйте исходники и добавьте контроль переполнений.

Ну вообще я привык что когда что-то делается, оно делается под конкретные сценарии использования. А не "вааще шоб было".

Пример сценария я привел - работа с БД (поддержка типа DECIMAL в БД) и финансовые расчеты. Возможно, есть еще какие-то сценарии с которыми я лично не сталкивался.

Но если понятны сценарии, тогда можно уже рисовать как удобные для потенциальных сценариев API, так и эффективную в рамках данного сценария реализацию.

И да, мне хочется. Не то чтобы хочется, мне это необходимо чтобы (как писал выше) не иметь потенциальных проблем с клиентами банка (репутационные риски, жалобы и риски нежелательного внимания со стороны регулятора, штрафы и т.п.) Но, слава богу, у меня все это есть - я (мы) работаю с языком, где поддержка такой арифметики нативна - я языке есть соответствующие типы и все операции с ними (и в реализации С/С++ на этой платформе есть _Decimal для С и _DecimalT<n,p> для С++). И там да, переполнение всегда вызывает системное исключение, которое можно легко перехватить и обработать (а не обработаешь - ну упадет, оставив дампы и записи в joblog - будет "дефект промсреды").

Самое главное, какая производительность этого дела? Сравнима ли она с double, float? Было бы интересно это увидеть, иначе смысл этого всего немного теряется. И насколько быстро растёт погрешность, например, при выполнении редукции по сумме скажем 1000000 чисел?

Смотрите, замеров нету, но это в целом не очень простое дело, ведь вопрос на какой платформе мерить. Насчёт погрешностей - при суммировании их быть не может - может быть переполнение, но погрешности именно при суммировании взяться неоткуда. Но она может быть на умножение или делении.

не такое уж и сложное дело, берем обычный процессор, который у вас есть, далее пишем какой-нибудь не сложный вычислительный код и смотрим, сколько нужно времени для double, сколько для предложенной реализации. Если окажется, что предложенная реализация быстрее, но при этом выдает приемлемую точность, то можно было бы попробовать использовать этот тип в более серьезных приложениях. У меня интерес есть к этому, так как в CFG коде не всегда можно "нормально" перейти с FP64 на FP32, если бы получилось что то интересное с предложенным кодом, то можно было бы попробовать использовать его, так как точности в FP32 не всегда хватает.

Опробовать можно на методе Якоби, например, хотя бы на последовательной реализации. Например, на таком коде, нужно только выкинуть наши директивы распараллеливания, если смущают, а так - ни будут проигнорированы. http://dvmh-server.ddns.net:3000/Alexander_KS/SAPFOR/src/branch/master/dvm/tools/tester/trunk/test-suite/Performance/jac3d.cdv

Идея интереснная - конструктив, если руки дойдут - померю, не обещаю, что конкретно на вашем коде

Самое главное, какая производительность этого дела? Сравнима ли она с double, float?

Производительность в каких приложениях?

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

Второй аспект - работа с БД. Там есть типы DECIMAL и NUMERIC. С фиксированной точкой. Широко используются в финансовых расчетах.

Если вам удастся хорошо реализовать "нативную" арифметику с этими типами, то производительность "на круг" будет выше - вам не потребуется каждый раз при чтении из БД конвертировать эти типы в плавающую точку, потом заморачиваться с ошибками округления, а потом конвертировать обратно чтобы записать в БД.

Т.е. вся эта история делается под конкретные сценарии.

Посмотрел тесты - прикольно, надо попробовать, не знал, что такое есть

У нас в коболе все флоаты это инт128 + точность. Если операция над числами разной точности, то конвертируем в максимальную из них. Числа максимум в 31 символ, но никто пока не жаловался

А где сейчас ещё используется Кобол?

Банки, биржи, страховые, почты. Многие достаточно старые компании, которым нужна фиксированная точка

Reuters reported in 2017 that 43% of banking systems still used COBOL with over 220 billion lines of COBOL code in use

Sign up to leave a comment.

Articles