Что вы используете для представления с фиксированной точкой в ​​C++?

Я ищу стандарт с фиксированной точкой для финансовых данных. Знаете ли вы, что стоит попробовать? Есть ли у вас какой-либо опыт работы с этими самодельными классами с фиксированной точкой?

странно, что вопросы не по теме разрешены, когда есть награда.

AndersK 10.01.2014 15:42

Взгляните на Образец денег Мартина Фаулера!

πάντα ῥεῖ 14.01.2014 01:11

@claptrap В частности, объясните здесь off-topic (не видно близких голосов). Я знаю, что вы имеете в виду, но OP, похоже, ищет стандартные решения, а их нет (AFAIR). Может быть, некоторые идиомы С ++ 11 могут помочь ...

πάντα ῥεῖ 14.01.2014 01:14

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

πάντα ῥεῖ 14.01.2014 01:19

@ πάνταῥεῖ не по теме в смысле поиска инструмента / библиотеки, но когда установлена ​​награда, вы не можете проголосовать за ее закрытие - вот почему нет закрытых голосов. неважно, что бы ни летало на твоей лодке.

AndersK 14.01.2014 04:48

Вы пробовали делать всю свою математику целыми числами и просто делить на 100 на самом последнем этапе? (этого можно избежать даже с помощью форматированных строк)

GMasucci 14.01.2014 17:04

@GMasucci, похоже, для моего случая это было бы лучшим решением. но мне нужно реализовать "делить", "умножать" и т. д.

Oleg Vazhnev 16.01.2014 17:20

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

GMasucci 16.01.2014 19:24

привет еще раз, извиняюсь, у меня не было времени добраться до моего ПК, чтобы закодировать это, однако есть несколько библиотек, которые могут вам помочь: например, trenki.net/content/view/17/1 - довольно хорошо оснащенная библиотека и отличное место для начала. Я займусь кодом на этой неделе. Я так понимаю, скорость - это фактор? Также с какими максимальными (+/-) значениями вы могли бы работать?

GMasucci 21.01.2014 13:29

@GMasucci: Здесь много места для ошибок с умножением, делением, вводом, выводом и преобразованиями. Лучше завернуть в класс. Как ... небольшая библиотека с фиксированной точкой.

Mooing Duck 15.03.2014 00:18
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
21
10
4 310
7

Ответы 7

У доктора Добба есть статья о возможной реализации арифметического типа с фиксированной точкой в ​​C++. Проверьте это.

Это ЕДИНСТВЕННЫЙ ответ здесь, в котором есть код, который может хранить доллары как центы.

Mooing Duck 14.03.2014 20:16

IBM decNumber ++

похоже, что decNumber ++ - это все с плавающей точкой, а не с фиксированной точкой.

Ben Collins 24.09.2009 23:20

Ой. Финансовые системы сложны, ваша основная проблема не в математике с фиксированной точкой, а в ошибках округления.

У вас может быть хорошая электронная таблица, полная разнообразных расчетов со скидками по типу клиента и с учетом НДС. Вы подсчитываете сумму, представляете ее бухгалтеру, и он говорит, что все значения неверны. Причина: вывод может быть сформирован только с двумя десятичными знаками, но внутренне значение имеет все десятичные разряды типа float или double. и они складываются.

Вам нужно знать свои финансовые показатели и решить, где будут базовые значения. То есть, какие значения будут проверять бухгалтеры (да, это требует деловых знаний, за исключением «сложной» части).

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

Быстрое и грязное решение для N десятичных знаков: ((double) ((int) (Значение * N * 10.0))) / 10.0

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

Ваше «Быстрое и грязное решение для N десятичных знаков» должно включать 10 ^ N.

Tom Sirgedas 11.03.2011 19:44

«Ваша основная проблема не в математике с фиксированной запятой, проблема в ошибках округления». Проблема в ошибках округления. решение - математика с фиксированной запятой

Mooing Duck 14.03.2014 20:05

Я использую свой урок математики с фиксированной точкой. Он разработан, чтобы стать более или менее заменой поплавкам / дублерам. http://codef00.com/coding

РЕДАКТИРОВАТЬ: Кстати, я бы лично не использовал для этой цели класс с фиксированной точкой. Вместо этого я бы просто сохранил количество центов (или десятых долей цента, или сотых долей цента, если необходимо). А просто посчитайте прямо с этим. Затем я бы соответствующим образом масштабировал значение при отображении для пользователей.

если class добавляет накладные расходы? не лучше ли использовать такие макросы, как здесь eli.thegreenplace.net/files/prog_code/fixnum.cpp.txt?

Oleg Vazhnev 10.01.2014 13:06

какие накладные расходы, по вашему мнению, может добавить класс? Как вы думаете, почему макросы могут быть быстрее?

Fabio Fracassi 10.01.2014 14:08

@EvanTeran: Я тоже однажды написал класс с фиксированной точкой, но отказался от него, когда кто-то заметил, что a*b/c - это обычная операция, при которой и ваш, и мой код добавляют ненужные накладные расходы, что нетривиально исправлено.

Mooing Duck 14.03.2014 00:15

@ Mooing duck: да, оператор деления, как правило, сложно сделать эффективно: - /.

Evan Teran 14.03.2014 17:36

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

Mooing Duck 14.03.2014 20:08

@MooingDuck: Вы можете разделить биты как хотите, но фиксированная точка в целом (как концепция) должна использовать приближение для вещей, которые не являются степенью двойки. Лучший способ обрабатывать доллары - хранить количество центов (или доли цента, если необходимо), а затем масштабировать до долларов по мере необходимости во время отображения. Например, 1234,56 доллара будет сохранено как uint64_t cents = 123456;. Это позволит избежать проблем с округлением и точностью. В общем, если вы используете фиксированную точку для хранения денежных ценностей, вы используете неправильный инструмент для работы.

Evan Teran 14.03.2014 22:21

@EvanTeran: Фиксированная точка в общем случае НЕТ должна использовать приближения для вещей, не являющихся степенью двойки. Это можно сделать с любой произвольной базой. Я сделал это, и на этой странице есть один ответ. Класс внутри имеет uint64_t numerator = 123456;. Концепция фиксированной точки заключается в хранении числителя дроби с фиксированным знаменателем. Если знаменатель представляет собой степень двойки, есть много интересных хитростей, которые делают это быстрее, но в них нет необходимости.

Mooing Duck 14.03.2014 22:30

@MooingDuck: Решение доктора Добба не совсем то, что я имел в виду, когда сказал «фиксированная точка», но я понимаю, что вы имеете в виду. В их реализации точка счисления фиксируется не битом, а десятичной цифрой. Это именно то, что я предположил, они просто скрыли детали в классе. В любом случае вы все равно столкнетесь с ошибками округления, только для разных значений. Например, как бы вы представили (1/3) доллара? Та же проблема, только в другой базе

Evan Teran 14.03.2014 22:44

@EvanTeran: Поскольку (1/3) доллара не является реальной возможной стоимостью, я не вижу необходимости хранить его. Он хранит только возможные значения. 33 цента, с остатком 67 центов.

Mooing Duck 14.03.2014 22:45

@MooingDuck, значит, вы никогда не планируете использовать деление в своей системе? Вы просто складываете и вычитаете значения? Если да, то зачем возиться с классом, почему бы просто не использовать uint64_t напрямую и не сказать: «Это сколько у вас центов»? (затем масштабирование во время отображения пользователю).

Evan Teran 14.03.2014 22:47

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

Evan Teran 14.03.2014 22:49

@EvanTeran: Он полностью поддерживает деление и всегда дает результат в центах. Другие ответы возвращают ответы в 128-й доле доллара или хуже. Преобразования в другие типы и обратно действительно требуют умножения или деления. Хуже того, умножение требует деления и наоборот. Да, это делает его медленнее, однако он сохраняет мой, основную причину фиксированной точки: точность и без странных округлений. Для скорости используйте внутреннюю базу, которая является степенью двойки, и оптимизатор сделает это так же быстро, как эти менее общие ответы. Мы используем класс, чтобы правильно получать ввод-вывод, преобразование и умножение

Mooing Duck 14.03.2014 22:57

@MooingDuck: я хочу сказать, что если вы вводите деление, вы воля также получаете ошибки округления в базе 10. Просто разные ошибки округления. Единственный способ избежать их - запретить деление ... Это не просто такие вещи, как (1/3) доллара. Что-то столь же простое, как .25, разделенное на 2 для двух человек, приведет к потере цента. Как я уже сказал, единственный способ избежать этой проблемы - не допустить разделения.

Evan Teran 15.03.2014 00:01

@EvanTeran: Проблема не в том, что происходит округление, округление будет происходить всегда, точка. Итак, когда вы делаете деление, а затем используете вычитание, чтобы вычислить остаток. $ 1,25 / 2 -> 0,62 и 0,63. Это не математика с фиксированной точкой, это тип Любые. Кроме поплавков, потому что с поплавками он не работает. Это почему я использую фиксированную точку.

Mooing Duck 15.03.2014 00:09

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

Mooing Duck 15.03.2014 00:16

Я думаю, что было бы более разумно иметь возможность поддерживать дробные центы до определенного количества цифр, так что ответ будет по 0,625 доллара каждая. Но вы, очевидно, разрешаете выплату только целых центов. Таким образом, никто не получит бесплатных полцента и никого не украдут полцента. Кто в вашей системе получает полцента бонуса? Он должен куда-то пойти, потому что, если вы просто «уроните» их, это может привести к огромному расхождению с реальными долларами. (И тогда вы попадаете в начальный сюжет Superman III :-P).

Evan Teran 15.03.2014 00:21

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

Evan Teran 15.03.2014 00:24

@EvanTeran: (A) Ваш код с фиксированной точкой не может точно хранить 80 центов, не теряя доли цента, с количеством бит Любые. Не критикуйте меня за округление полцента: P (B) Ваш код с фиксированной точкой действительно имеет деления, они просто замаскированы за сдвигами и побитовыми операциями. (C) Все, что может делать ваш побитовый код, может делать и универсальный базовый класс с фиксированной точкой с той же точностью точно, и я был бы удивлен, если бы была разница в производительности. Общая версия просто предлагает пользователю больше возможностей.

Mooing Duck 27.03.2014 23:20

@MooingDuck, (A) Я знаю ограничение моего класса с фиксированной точкой, поэтому я рекомендовал хранить значение в виде простого целого числа в центах (или десятых долях цента). Кроме того, Я вообще не разбивал твой код, я просто указывал, что у них есть аналогичные недостатки, когда дело доходит до разделения. (B) Я знаю, что в моем коде есть разделы ... Я написал это. Я бы по-прежнему не рекомендовал фиксированную точку для финансовых расчетов. Внесенные крошечные ошибки составят заметную сумму.

Evan Teran 29.03.2014 21:00

@MooingDuck, (C) Кажется, у вас сложилось впечатление, что для этой цели я бы выбрал свой класс с фиксированной точкой вместо вашего. Я бы не стал, потому что не стал бы использовать ни один из них. Это неподходящий инструмент для работы. Идеальное решение - просто использовать int64_t и сказать: «Это ваша тысячная цента» (или что-то в этом роде). В общем случае легко получить правильный ответ, особенно если вы можете использовать избегать разделения в своем коде. (деление - это единственное место, где независимо от того, что вы делаете, вы получите округление и / или усечение).

Evan Teran 29.03.2014 21:01

@EvanTeran: За исключением умножения, ввода, вывода, преобразований ... У нас есть решение для такого рода проблем на C++. Заворачиваем вещи в класс. Имя этого класса: fixed_point<100000>.

Mooing Duck 29.03.2014 22:23

ISO определил десятичное расширение для C, TR 24732 и C++, TR 24733. Они доступны за деньги на Веб-сайт ISO. Это еще не часть опубликованного стандарта C++. GCC предоставляет встроенные типы и библиотечная реализация этого. Другая реализация - доступно от Intel. Самым последним толчком к включению этого в C++ является здесь.

gcc «используйте систему счисления десяти», поэтому я предполагаю, что он разработан для accuracy, но мне нужна производительность, поэтому, вероятно, мне нужна реализация с системой счисления два. Кажется, что реализация Intel является "плавающей точкой", когда я ищу реализацию с фиксированной точкой, чтобы иметь лучшую производительность.

Oleg Vazhnev 10.01.2014 16:02

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

Mooing Duck 14.03.2014 20:15

64-битного типа int должно хватить для представления всех финансовых значений в центах.

Вам просто нужно быть осторожным, чтобы правильно округлить проценты для некоторого определения правильный.

См. Также stackoverflow.com/questions/61872/….

lhf 10.01.2014 16:11

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

Oleg Vazhnev 10.01.2014 16:13

@lhf: Здесь есть нечто большее, чем просто "осторожность" с округлением. А именно, правильное умножение и деление намного сложнее, чем простое умножение и определение. Кроме того, есть очевидные дыры в типах во время преобразования и ввода-вывода. Лучше всего завернуть в класс.

Mooing Duck 27.03.2014 23:22

Пытаюсь ответить прямо

У Маркуса Тренквальдера есть тот, который поддерживает некоторые математические функции - http://www.trenki.net/content/view/17/1/:

The library consists of various functions for dealing with fixed point numbers (multiplication, division, inversion, sin, cos, sqrt, rsqrt). It also contains a C++ wrapper class which can be used to simplify working with fixed points numbers greatly. I used this fixed point number class in conjunction with my vector_math library to obtain a fixed point vector math library. Doing so made the 3D computations a lot faster compared to the floating point version.

Автор не забыл сказать, что его платформа не поддерживает операции с плавающей запятой, поэтому он и сделал это. Также обратите внимание, что это для 3D-рендеринга, вопрос был для финансовые данные, и нам нужна хорошая библиотека математических функций ....

IEEE 754-2008 Спецификация десятичной арифметики с плавающей запятой, предназначенная для финансовых приложений.

Это похоже на устоявшийся способ обработки финансовых данных с хорошей поддержкой (со стороны Intel и IEEE) - http://software.intel.com/en-us/articles/intel-decimal-floating-point-math-library

Цитировать:

IEEE 754-2008 Decimal Floating-Point Arithmetic specification, aimed at financial applications, especially in cases where legal requirements make it necessary to use decimal, and not binary floating-point arithmetic (as computation performed with binary floating-point operations may introduce small, but unacceptable errors).

Это фиксированная точка НЕТ, но я подумал, что это очень полезно для людей, ищущих ответ на этот вопрос.

На самом деле, глядя на код Маркуса Тренквальдера, кажется, что он не может обрабатывать базисы без степени двойки, такие как доллары США в центах.

Mooing Duck 14.03.2014 20:12

Другие вопросы по теме