169 похожих чатов

Во блин, так здесь еще и мне вам самые азы

объяснять придется... 🧐
Есть целочисленные типы - инты. В финансах в здравом уме их никто не юзает кроме как в качестве идентификаторов, т.к. постоянно нужно вылавливать копейки.
Есть числа с плавающей точкой. С ними почти все хорошо, можно ловить и микро и нано-копейки, только есть одна беда:
#include <stdio.h>

int main(int argc, char const *argv[])
{
float a = 0.1 + 0.1 + 0.1;

if(a == 0.3) printf("a равно 0.3\n");
else printf("a не равно 0.3\n");

return 0;
}
Что выдаст? По логите true, на практике хрен там! И в паскале тоже самое, только проверил:
program Project1;
var
a : real;
begin
a := 0.1 + 0.1 + 0.1;
if a = 0.3 then begin
writeln('Равно.');
end
else begin
writeln('Не равно!');
end;
end.
Это специфика чисел с плавающей точкой. И что бы не стрелять себе по ногам придумали сложные/составные числовые типы. В базах это number в оракле, numeric в постгресе, money в mysql и ms sql и т.д..
И currency как раз тоже такой тип, проверил:
program Project1;
var
a : Currency;
begin
a := 0.1 + 0.1 + 0.1;
if a = 0.3 then begin
writeln('Равно.');
end
else begin
writeln('Не равно!');
end;
end.
Но такие типы считаются медленно, поэтому в базах при длительных расчетах иногда преобразовываем данные к флотам, считаем, затем обратно к денежным.

50 ответов

105 просмотров

медленно работает bigint/bigfloat - где кол-во разрядов может быть оч большим/меняться, из-за чего подсчеты происходят "софтверно", с fixed-point же нет проблем - для процессора это как работа с обычными интами, ток на переводе - туда - обратно - деление/умножение.

А конкретно к какому сообщению или заявлению оппонируешь этим сообщением? Так-то ок. Познавательно. Что-то и новое узнал. Хотя с финансовыми программами дела не имел )

так паскалевское Currency и есть число с фиксированной точкой, в чём проблема?

Звездочка U1202D, сообщения читаешь или только себя?)

Igor
так паскалевское Currency и есть число с фиксирова...

Проблема только одна - она (точка) очень фиксированная. Всегда 4 знака после запятой. Если вдруг понадобится точнее - тады ой.

𒀭- Автор вопроса
Peter
медленно работает bigint/bigfloat - где кол-во раз...

Все почти верно, только наоборот. В этом можете сами спокойно убедиться, набросал для постгреса: do $$ declare t_start timestamp; t_stop timestamp; --my_number double precision; my_number numeric; begin t_start := clock_timestamp(); for i in 1 .. 100000 loop begin my_number := random(); /**** Здесь математические операции. ****/ exception when others then my_number := 0.0; end; end loop; t_stop := clock_timestamp(); raise notice '%s', (t_stop - t_start); end $$; Числа с плавающей точкой считаются в РАЗЫ быстрее чисел с фиксированной. И арифметика чисел с фиксированной точкой реализуется софтверно, можете в этом убедиться заглянув в исходники любой СУБД.

𒀭- Автор вопроса
Renat Suleymanov
А конкретно к какому сообщению или заявлению оппон...

Извиняюсь, если кого-то задел чрезмерным квантором, я не со зла)

Люблю такие очевидные споры, а тут еще и Си-шник) Просто пишешь функцию и используешь) const eqPrecision = 0.0000000001; function FloatEqual(AVal1,AVal2:Extended;APrec:Extended):boolean; begin result := Abs(AVal1-AVal2)<=APrec; end;

𒀭- Автор вопроса
Катерина Свиридова
Люблю такие очевидные споры, а тут еще и Си-шник) ...

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

На си это решается сравнением с константой которая представляет собой погрешность. Думаю в Паскале имеется такая же. К тому же для финансов есть Currency, который хранится в Int64, но представляется действительным

𒀭- Автор вопроса
Kirill Filippenok
На си это решается сравнением с константой которая...

Ахренеть! Вот это лажа. Я сразу и не заметил что 4 знака только после запятой. И чо, решения из коробки нет?

𒀭
Ахренеть! Вот это лажа. Я сразу и не заметил что 4...

https://www.freepascal.org/docs-html/rtl/sysutils/tsinglehelper.epsilon.html

Kirill Filippenok
https://www.freepascal.org/docs-html/rtl/sysutils/...

забавно, это не epsilon, это денормализованное фуфло

Kirill Filippenok
Может объясните?

точность single примерно 7-8 знаков, поэтому eps обычно берут типа 1e-7 . минимальное нормально представимое число примерно 1e-38. 1e-45 это денормализованое fp число, которое вообще в зависимости от настроек процессора може вызватть исключение или незаметно превратиться в 0.

Kirill Filippenok
Может объясните?

Будешь платить налоги, там объяснят) Сильно захотелось пошутить

𒀭
Ахренеть! Вот это лажа. Я сразу и не заметил что 4...

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

𒀭
Все почти верно, только наоборот. В этом можете са...

Речь шла о pascal/c и тд, о программах, что там неверчено в конкретной бд - я не знаю. К слову тест фигня - мерит скорость «рандома», как самой медленной операции тут.

𒀭- Автор вопроса
Peter
Речь шла о pascal/c и тд, о программах, что там не...

Там коммент специально добавил: /**** Здесь математические операции. ****/ Добавляйте туда какие хотите матоперации над переменной my_number и смотрите производительность.

𒀭
Там коммент специально добавил: /**** Здесь мате...

Ну отличный тест выходит «напиши сам», можно поверить кто-то не умеет циклом мерять производительность

𒀭- Автор вопроса
Peter
Ну отличный тест выходит «напиши сам», можно повер...

Если в этом проблема, пожалуйста: do $$ declare t_start timestamp; t_stop timestamp; --my_number double precision; my_number numeric; begin t_start := clock_timestamp(); for i in 1 .. 100000 loop begin my_number := random(); my_number := (sin(my_number)*10)^5; my_number := (cos(my_number)*10)^5; my_number := (sin(my_number)*10)^5; my_number := (cos(my_number)*10)^5; exception when others then my_number := 0.0; end; end loop; t_stop := clock_timestamp(); raise notice '%s', (t_stop - t_start); end $$; do $$ declare t_start timestamp; t_stop timestamp; my_number double precision; --my_number numeric; begin t_start := clock_timestamp(); for i in 1 .. 100000 loop begin my_number := random(); my_number := (sin(my_number)*10)^5; my_number := (cos(my_number)*10)^5; my_number := (sin(my_number)*10)^5; my_number := (cos(my_number)*10)^5; exception when others then my_number := 0.0; end; end loop; t_stop := clock_timestamp(); raise notice '%s', (t_stop - t_start); end $$; Вывод: NOTICE: 00:00:02.33767s NOTICE: 00:00:00.34799s Флот отрабатывает в 5 раз быстрее!

𒀭
Если в этом проблема, пожалуйста: do $$ declare ...

эм, в случае numeric 64-бит число перед операцией сначала преобразовывается в плавучку, потом обратно очевидно, это медленнее, чем без преобразований

𒀭- Автор вопроса
Igor
эм, в случае numeric 64-бит число перед операцией ...

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

𒀭- Автор вопроса
Igor
эм, в случае numeric 64-бит число перед операцией ...

Можно написать без преобразований, например так: my_number := random(); for i in 1 .. 10 loop my_number := my_number * my_number; end loop; Тогда результаты вообще офигительные: NOTICE: 00:00:08.095489s NOTICE: 00:00:00.047939s

𒀭
Можно написать без преобразований, например так: ...

что-то тут неправильно умножение занимает пару тактов что в целых числах, что в плавучке, результаты не должны отличаться намного

𒀭- Автор вопроса
Igor
что-то тут неправильно умножение занимает пару так...

Здесь нет целых чисел: https://postgrespro.ru/docs/postgresql/9.6/datatype-numeric

𒀭
Здесь нет целых чисел: https://postgrespro.ru/docs...

а, ну это постгрессовская специфика

𒀭
Здесь нет целых чисел: https://postgrespro.ru/docs...

не понял. а как же '8.1.1. Целочисленные типы'?

𒀭- Автор вопроса
Igor
а, ну это постгрессовская специфика

Уффф... На уровне процессора есть только ДВА типа чисел: целые и числа с плавающей точкой. А вещественные числа с указанной точностью которые есть практически во всех современных ЯП под капотом это массивы байт. Математические операции над ними на уровне процессора все равно сводятся к операциям над целыми числами и числами с плавающей точкой. Но все эти алгоритмы (их дохрена) работают значительно медленнее чем операции непосредственно над целыми числами (интами) и числами с плавающей запятой (флотами). Вот и все премудрости.

𒀭
Уффф... На уровне процессора есть только ДВА типа ...

> А вещественные числа с указанной точностью > которые есть практически во всех современных ЯП > под капотом это массивы байт. Глобально натягиваем сову на глобус на основании одного частного случая? Берем Firebird SQL-server, (версия 3.0) и читаем документацию. Для данных с фиксированной точкой общим является форма декларации, например NUMERIC(p, s). Здесь важно понять, что в этой записи s —это масштаб, а не интуитивно предсказываемое «количество знаков после запятой». Для «визуализации» механизма хранения данных запомните для себя процедуру: • При сохранении в базу данных число умножается на 10s (10 в степени s), превращаясь в целое; • При чтении данных происходит обратное преобразование числа. Способ физического хранения данных в СУБД зависит от нескольких факторов: декларируемой точности, диалекта базы данных, типа объявления. Для третьего диалекта: +----------+-------------------+----------------+ | Точность | Тип данных | Физический тип | +----------+-------------------+----------------+ | 1-4 | NUMERIC | SMALLINT | | 1-4 | DECIMAL | INTEGER | | 5-9 | NUMERIC и DECIMAL | INTEGER | | 10-18 | NUMERIC и DECIMAL | BIGINT | +----------+-------------------+----------------+

𒀭
Ахренеть! Вот это лажа. Я сразу и не заметил что 4...

А решение какой задачи тебе нужно? Чем currency не подходит?

𒀭
Если в этом проблема, пожалуйста: do $$ declare ...

Тест - полная херня. Он тут меряет количество исключений, возникающих при переполнении в зависимости от типа, а не скорость вычислений. А так же касты.

𒀭
Можно написать без преобразований, например так: ...

Сервер Firebird 3.0 +------------------+----+ | Тип данных | ms | +------------------+----+ | smallint | 34 | | integer | 26 | | bigint | 24 | | double precision | 24 | | numeric(18,4) | 24 | +------------------+----+ Типы данных которые занимают 64 бит, ожидаемо работают одинаково. 32 и 16 - несколько медленнее, видимо процу приходиться приводить мелкие типы в 64 бита для АЛУ.

𒀭
Если в этом проблема, пожалуйста: do $$ declare ...

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

𒀭
Уффф... На уровне процессора есть только ДВА типа ...

Какой-то детский сам ей богу, не знать/отрицать фиксированную запятую на интах. Для подсчета денег синусы и тд не нужны - надо складывать, вычитать и умножать, делать - все, тут фиксированная запятая не будет «фатально медленее» флоата.

𒀭
Здесь нет целых чисел: https://postgrespro.ru/docs...

Мдя, вот засада в постгрессе.. Нет нормального типа для денег. Тот нумерик что там сделан - он для астрономических величин, и прям в доке написано что он работает намного медленнее чем все остальное. numeric переменное кол-во байт вещественное число с указанной точностью до 131072 цифр до десятичной точки и до 16383 — после а нормальные целочисленные типы там все без точки. Для нормальной работы видимо нужно врукопашную эмулировать фиксированную точку на bigint.

𒀭- Автор вопроса
Владимир Аксенов
А решение какой задачи тебе нужно? Чем currency не...

» Тест - полная херня. Он тут меряет количество исключений... А слабо добавить переменную-счетчик и посчитать сколько тех исключений прежде чем делать такие утверждения?

𒀭
» Тест - полная херня. Он тут меряет количество ис...

Ну сделай. Само по себе втыкание поглотителя исключений в тест - крайне странное действие. Чел не смог сделать чистый тест что бы переполнение не возникало, и на чистоту теста наплевал. Я когда свой тест писАл - столкнулся с переполнением, и переделал так что бы оно не возникало.

𒀭- Автор вопроса
Владимир Аксенов
> А вещественные числа с указанной точностью > кот...

» Глобально натягиваем сову на глобус на основании одного частного случая? BigInteger/BigDecimal в java/C#, Decimal в Python, Big_Numbers в Ада... » При сохранении в базу данных число умножается на 10s (10 в степени s), превращаясь в целое; При чтении данных происходит обратное преобразование числа. Нууу... И остается вопрос где храним количество знаков на которые сместили.

Владимир Аксенов
Мдя, вот засада в постгрессе.. Нет нормального тип...

Возможно для размеров этого типа, которые помещаются в нативный регистр ЦПУ - он делает по умному и считает их нативно? А всё что вылазит - уже с оверхедом

𒀭
» Глобально натягиваем сову на глобус на основании...

Всмысле? У нас переменная конкретного типа, и в ее объявлении задано, сколько цифр всего и сколько после запятой.

notme
Возможно для размеров этого типа, которые помещают...

В доке про это не упоминается. А как по факту - ХЗ, я не работаю с PG.

𒀭- Автор вопроса
Владимир Аксенов
Ну сделай. Само по себе втыкание поглотителя исклю...

» Само по себе втыкание поглотителя исключений в тест - крайне странное действие. Это странно только для людей у которых плохо с математикой. Действительно можно вывалиться из диапазона если рандом выдаст например 0.00000000000001, потом возьмем синус и возведем в надцатую степень. Вероятность такого случая мизерная, но она есть, я о таких вещах даже не задумываюсь и сразу ловлю исключения.

𒀭
» Само по себе втыкание поглотителя исключений в т...

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

𒀭- Автор вопроса
Михаил Усков
математикой, которая требует особо точных вычислен...

Да меня самого это задолбало! Вроде с числами уже вчера разобрались. Давайте переходить уже к строкам... 😊

𒀭
» Само по себе втыкание поглотителя исключений в т...

Деление на ноль ты так же глушишь через исключения?

𒀭
» Само по себе втыкание поглотителя исключений в т...

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

Похожие вопросы

Обсуждают сегодня

а через ESC-код ?
Alexey Kulakov
29
30500 за редактор? )
Владимир
47
Чёт не понял, я ж правильной функцией воспользовался чтобы вывести отладочную информацию? но что-то она не ловится
notme
18
У меня есть функция где происходит это: write_bit(buffer, 1); write_bit(buffer, 0); write_bit(buffer, 1); write_bit(buffer, 1); write_bit(buffer, 1); w...
~
13
Недавно Google Project Zero нашёл багу в SQLite с помощью LLM, о чём достаточно было шумно в определённых интернетах, которые сопровождались рассказами, что скоро всех "ибешни...
Alex Sherbakov
5
Как передать управляющий символ в открытую через CreateProcess консоль? Собсна, есть процедура: procedure TRedirectThread.WriteData(Data: OEMString); var Written: Cardinal;...
Serjone
6
в JclConsole объявлено так: function CtrlHandler(CtrlType: DWORD): BOOL; stdcall; - где ваше объявление с stdcall? у вас на картинке нет stdcall
Karagy
8
Ребят в СИ можно реализовать ООП?
Николай
33
program test; {$mode delphi} procedure proc(v: int32); overload; begin end; procedure proc(v: int64); overload; begin end; var x: uint64; begin proc(x); end. Уж не знаю...
notme
6
https://github.com/erlang/otp/blob/OTP-27.1/lib/kernel/src/logger_h_common.erl#L174 https://github.com/erlang/otp/blob/OTP-27.1/lib/kernel/src/logger_olp.erl#L76 15 лет назад...
Maksim Lapshin
20
Карта сайта