LINUX.ORG.RU

Математика с фиксированной запятой для C++20

 


0

3

Посоны,

Мы тут сделали библиотеку для математики с фиксированной запятой на С++. Вот так работает:

const auto x = fixed::make::p<2>(1, 11);

Это число с двумя десятичными знаками после запятой представляющее 1.11.

const auto y = fixed::make::p<1>(1, 0);

Это число с одним десятичным знаком после запятой, представляющее 1.0.

const auto z = x + y;

Это сумма двух чисел.

А вот это ошибка компиляции:

fixed::make::p<3, uint8_t>((uint8_t)0, 0);

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

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

Во время выполнения, переполнение тоже контролируется, все операции возвращают std::optional который при переполнении будет пустым.

Библиотека спроектирована так чтобы ни один бит информации ни при каких манипуляциях не терялся бы, либо если бит надо потерять, то это надо сделать явно и число станет неточным, на что тоже есть признак, который можно проверить вызвав fixed::is_accurate(x), и если какие-то биты были потеряны, то функция вернёт false.

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

Ссылка: https://bitbucket.org/alekseyt/fixed

Более полный пример использования: https://bitbucket.org/alekseyt/fixed/src/master/examples/basic.cpp

Заранее спасибо.



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

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

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

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

Вы не поняли суть его вопроса …

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

Фиксированная запятая, а не точка. Способ записи не имеет значения. Если твоё имя записать на иврите – побежишь обрезание делать?

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

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

Деньги счёт любят.

anonymous
()

Зачем нужна целая библиотека?
Не достаточно ли одной функции округления?

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

Тады seq выдает запятые и дальше atof ломается.

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

Тебе сказали – не хочешь, не проверяй, это не исключительная ситуация.

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

это не исключительная ситуация

Нет, исключительная.

Исключения – тормозное дерьмо

Нет. Исключения тормозные на unhappy path, на happy path они буквально бесплатны. Unhappy path нас не волнует, потому что переполнение возникает редко.

Переполнение есть и в обычной арифметике

И?

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

арифметику больших чисел

Где ты увидел арифметику больших чисел? У ТС просто фикснум. Т.е по сути обычное целое + позиция точки.

Это не так работает

Это так работает.

no-such-file ★★★★★
()

Заранее спасибо.

Мне кажется - Вы трошки запоздали. Ieee754 уже стандартизировал Decimal64/128, и все кому нужно уже всё написали, подозреваю что эффективней вашей библиотечки.

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

Аэрокос, - это и есть говножелезки, особенно государственный.

Но BCD там нахрен не нужно.

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

Считать деньги.

Я не очень понимаю, там разве точность плавает?

Всё сложно, особенно с криптой.

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

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

В Haskell есть

Prelude> import Data.Ratio
Prelude Data.Ratio> 2%3 - 1%2
1 % 6
Waterlaz ★★★★★
()
Ответ на: комментарий от shkolnick-kun

Всё верно, fixed - это целые завёрнутые в обработку ошибок и контроль точности вычислений. Внутреннее представление по-умолчанию - это int64_t.

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

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

Огород городится для того чтобы ни одна ошибка не прошла незамеченной и на каждом этапе можно было бы определить точны ли вычисления

Вы на asm смотрели? Проблема не в том чтобы это сделать «правильно», проблема в том чтобы сделать это «быстро и правильно».

и если нет, то на каком этапе потерялась точность.

Я могу поинтересоваться - зачем? «Целевая аудитория», так скажем?

bugfixer ★★★★★
()
Ответ на: комментарий от shkolnick-kun

Для фиата целых хватит за глаза.

Там же не только с количеством копеек нужно работать, есть еще курсы валют, форвардные ставки, бумаги дешевле 1 копейки…

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

Там же не только с количеством копеек

Могу только предложить купить аж целый один биткоин. Ага. «Интов хватит всем».

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

Хорошо, про optional-аргументы мне не подумалось. Но если optional и так уже везде проник, может и не нужно выставлять наружу отдельно fixed, а выставить optional<fixed>? Все равно без него нельзя, а auto в коде будет меньше.

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

Огород городится для того чтобы ни одна ошибка не прошла незамеченной и на каждом этапе можно было бы определить точны ли вычисления

А для вашего fixed::p<4> вы будете тестировать 10**4 входных значений, чтобы быть на 100% уверенными? Такие вещи лучше проверять аналитически.

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

Не погружался глубоко в эту тему, но как же оно все страшно выглядит… Если использование optional не требует специального синтаксиса и у нас все переменные в него завернуты, то чем это лучше исключений? Если требует специального синтаксиса, то прощайте шаблоны.

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

auto в коде будет меньше.

Это минус, а не плюс.

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

Не знаю, вроде нет причин не выставлять наружу fixed::p - это «родной» интерфейс, но результатом операции будет optional<fixed::p> из-за потенциального переполнения, поэтому операторы поддерживают вариант с optional<fixed::p> для удобства.

Наверное немного запутанно, но по другому пока не получилось срастить. В принципе fixed::make::p() тоже возвращает optional<fixed::p> поэтому про варианты операций без optional<> можно на какое-то время забыть, для простоты, но они там есть если понадобятся.

В С++20 для auto можно указывать концепции чтобы было понятнее:

const fixed::detail::is_optional_p auto x = fixed::make::p<2>(0, 0);
const fixed::detail::is_fixed_p auto y = *fixed::make::p<2>(0, 0);
aleksey_tulinov
() автор топика
Ответ на: комментарий от Zeta_Gundam

то чем это лучше исключений?

Оверхед постоянный, но статически известный – в отличие от бесплатного happy path и довольно тормозного и непредсказуемого по цене unhappy path в текущей реализации исключений в С++. Не требуют аллокаций. Заставляют выполнять проверку значения на корректность или явно игнорировать ее.

edit: а, по ссылке еще и исключительно для shared_ptr<optional<T>> – ничем не лучше.

Если требует специального синтаксиса

Не требует. По ссылке используется синтаксис для корутин. Проблема там в другом – использование co_* операторов в функции превращает ее в корутину и накладывает на нее достаточно неприятные ограничения, раздувает код и в целом вносит накладные расходы.

Очень надеюсь на внесение детерминированных исключений в ближайших стандартах С++.

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

Не уверен, что правильно понял вопрос. 10**4 входных значений точно тестироваться не будут. Для целого типа во время компиляции вычисляется максимальная десятичная экспонента которая может быть в нём представлена, для uint8_t это 100, а для десятичной точности 4 это 10000. 100 < 10000, значит в uint8_t нельзя представить число с четырьмя десятичными знаками.

Точность теряется только в определённых случаях, например когда число с двумя десятичными знаками 1.11 преобразуется в число с одним десятичным знаком 1.1, 0.01 тут теряется, значит результат не точный.

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

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

Проверяй флаг, если хочешь знать.

Нет, исключительная.

У-у. Штатная. Читать научись.

Unhappy path нас не волнует, потому что переполнение возникает редко.

Переполнение может быть штатным случаем. Не надо со своими рамками лезть, убогими.

И?

И это не повод для тормозных исключений.

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

Проверяй флаг, если хочешь знать.

На каждое использованное число (в том числе промежуточные результаты вычислений) вносить дополнительное ветвление? Нет, спасибо.

Переполнение может быть штатным случаем.

Нет, в данном случае не может.

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

Исключения для слабых умом. Спасибо что доказали.

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

На каждое использованное число (в том числе промежуточные результаты вычислений) вносить дополнительное ветвление? Нет, спасибо.

Да, а есть варианты? Кроме тормозных исключений?

Нет, в данном случае не может.

Каком данном? Вашем вооброжаемом?

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

Вы перечислили фигню с плавающей запятой. А речь про фиксированную.

Поверх этого нормальные люди fixed и делают. До тех пор пока это возможно.

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

Не, братан, фиксированная делается поверх целого. Плавающая даёт ошибки вычисления из-за своих особенностей. Гугл: какой-то брит, какой-то банк, числа с плавающей запятой, сел за мошенничество.

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

Возьмем умножение. У вас глубоко в недрах алгоритма перемножилось 0.1 и 0.01, результат помещается в p<4>, тестирование завершается успешно. Потом вы отправляете свой софт на марсианскую биржу, и там перемножают 0.01 и 0.001, по модели распространились «неточные» числа. Тогда в чем заключается гарантия, которую вы получили от тестирования?

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

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

Вы перечислили фигню с плавающей запятой. А речь про фиксированную.

Поверх этого нормальные люди fixed и делают. До тех пор пока это возможно.

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

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

Не, братан

Гхм, мы на брудершафт пили?

фиксированная делается поверх целого.

Так или иначе - да. Только int128 в стандарт не завезли пока (но скоро, я думаю). А 64 по факту хватает «впритык», что называется.

Плавающая даёт ошибки вычисления из-за своих особенностей.

Расскажите мне.

Гугл: какой-то брит, какой-то банк, числа с плавающей запятой, сел за мошенничество

Слава богу - не я ;)

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

Гхм, мы на брудершафт пили?

В твоём любимом гей-клубе.

Так или иначе - да. Только int128 в стандарт не завезли пока (но скоро, я думаю). А 64 по факту хватает «впритык», что называется.

Если не лезть в крипту, где uint256 для Эфира, например. Т.е. decimal(38,18) кажется. Да и с фиатом сомнения есть.

Расскажите мне.

Нет.

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

Поправлюсь - если оно когда и будет воплощено «в железе»

Где есть целые, там есть и фиксированная запятая. Всё уже давно воплощено. А преобразование – отдельная тема. Т.к. плавающая сразу при преобразовании выдаст ошибку размером с число.

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

В твоём любимом гей-клубе.

Какие глубокие познания. «Владимир» за вами уже выехал.

Если не лезть в крипту, где uint256 для Эфира, например.

Вы не в теме. Однозначно.

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

Где есть целые, там есть и фиксированная запятая. Всё уже давно воплощено.

Внимание - вопрос! А к чему очередной велосипед?

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

Если не лезть в крипту, где uint256 для Эфира, например.

Вы не в теме. Однозначно.

Бред.

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

Внимание - вопрос! А к чему очередной велосипед?

Внимание ответ. Спросите у ТС.

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

Каком данном

В данном случае с optional.

Да, а есть варианты

Да есть, нужно сделать Inf числом (т.е. сущностью того же типа), как в IEEE. Без всяких optional.

no-such-file ★★★★★
()
Ответ на: комментарий от bugfixer

Внимание - вопрос! А к чему очередной велосипед?

Судя по постам ТС он разработал API, для работы с а-ля бухгалтерскими алгоритмами …
В чем изюминка то API?
То что округление в коде не нужно делать и следить за точностью вычисления выражений? …

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

То что округление в коде не нужно делать и следить за точностью вычисления выражений? …

Нет! Изюминка в том, что это «чудо-юдо» каким то образом ещё и работает, и даже что то делает.

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

Судя по постам ТС он разработал API, для работы с а-ля бухгалтерскими алгоритмами …

Q26.6 используется в TrueType, а может даже во всех SFNT-шрифтах. Для вычисления кривых и всего этого вот. Бухгалтеры могу и на счётах посчитать просто.

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