Страница 1 из 1
Удивительные вычисления в C12
Добавлено: 23 Октябрь 2025, 23:38
Игорь Столяров
Всем привет !
Ко мне пришла бухгалтер с калькулятором ... и мне стало стыдно.
Показываю концептуальный пример.
Код: Выделить всё
Map
MyTest(Real rSumma)
end
dSumma Decimal(10,2)
Code
dSumma = 2.01
!dSumma = 3.01 <- 1-е решение вопроса
MyTest(dSumma)
MyTest Procedure(Real rSumma)
lSumma Long
Code
!rSumma = 2.01 <- 2-е решение вопроса
lSumma = rSumma * 100
Message(rSumma & ' -> ' & rSumma * 100 & ' -> ' & lSumma)
В этом примере будет результат: 2.01 -> 201 -> 200, т.е. единица теряется при присвоении.
Но самое интересное, что если указать сумму 3.01 или присвоить значение внутри функции,
то результат будет правильный: 3.01 -> 301 -> 301. Ошибка вернётся на числе 6.01 и т.д.
Кто-нибудь может объяснить этот результат ?
P/S: Кстати, это ошибка всплыла при работе с эквайрингом Сбера.

Удивительные вычисления в C12
Добавлено: 24 Октябрь 2025, 0:22
FromSPB
DECIMAL 2.01 -> REAL 2.0099999999999997E+0
(REAL 2.0099999999999997E+0) * 100 -> REAL 200.99999999999997E+0
REAL 200.99999999999997E+0 -> LONG 200
В Clarion конвертация REAL -> LONG производится отбрасыванием дробной части. Надо использовать ROUND, либо не переходить от DECIMAL к REAL.
Удивительные вычисления в C12
Добавлено: 24 Октябрь 2025, 2:25
Игорь Столяров
FromSPB писал(а): 24 Октябрь 2025, 0:22
DECIMAL 2.01 -> REAL 2.0099999999999997E+0
Вот только на входе в процедуру параметр равен именно 2.01, а не 2.009999 ...
И тогда каким счастливым случаем данное правило преобразования не распространяется на 1.01 / 3.01 и т.д. ?
Очень хотелось бы проверить этот концепт на C11.1 - у меня есть подозрение, что проблема появилась именно в C12.

Удивительные вычисления в C12
Добавлено: 24 Октябрь 2025, 3:23
FromSPB
Игорь Столяров писал(а): 24 Октябрь 2025, 2:25
Вот только на входе в процедуру параметр равен именно 2.01, а не 2.009999 ...
Вы не правы.
Игорь Столяров писал(а): 24 Октябрь 2025, 2:25
И тогда каким счастливым случаем данное правило преобразования не распространяется на 1.01 / 3.01 и т.д. ?
Числа с плавающей точкой представляются как
x*2^e, где
e - целое число в диапазоне -1022..+1023, а
x - сумма чисел, равных 0 или неположительной степени 2 от 0 до -52. С учетом ограничений на разрядность мантиссы и экспоненты, определяемых форматом чисел с плавающей точкой, не все числа могут быть представлены точно: какие-то представляются точно, какие-то становятся больше, какие-то - меньше. 2.01 становится меньше.
Игорь Столяров писал(а): 24 Октябрь 2025, 2:25
Очень хотелось бы проверить этот концепт на C11.1 - у меня есть подозрение, что проблема появилась именно в C12.
Это появилось году в 1986, когда из 4 допустимых процессорами с архитектурой x86/x64 вариантов округления для преобразования REAL->LONG в Clarion был выбран вариант "округление в направлении 0 до ближайшего целого", т.е. отбрасывание дробной части.
Удивительные вычисления в C12
Добавлено: 24 Октябрь 2025, 7:12
Игорь Столяров
FromSPB писал(а): 24 Октябрь 2025, 3:23Вы не правы.
OK ! Давайте скажем так: это значение которое я вижу.
Значит ещё и неправильно работает преобразование REAL -> STRING показывая значение отличное от реального.
Спасибо за объяснения. Жаль нет нормального доступа к ClaHUB - там любят такие "особенности".
У нас тут тоже как-то обсуждался "прекрасный" базовый тип REAL, который есть во всех драйверах БД Clarion.
Я всегда избегал работу с этим гом-ом в финансах, но попался на передаче суммы как параметра по значению.
Понятно, что для REAL нужно корректировать точность через ROUND при делении или умножении на дробь.
Хотя это ещё тот аттракцион ... Но ошибка при умножении на 100, да ещё через раз - это как назвать без мата .... ?!
ВОТ ИМЕННО ПОЭТОМУ Я ВСЕГДА РЕКОМЕНДУЮ ИЗБЕГАТЬ ИСПОЛЬЗОВАНИЕ ЧУЖОГО ЗАКРЫТЫТОГО КОДА В CLARION !
Удивительные вычисления в C12
Добавлено: 24 Октябрь 2025, 8:02
finsoftrz
На С6.3 аналогично воспроизводится.
Насчет использования real/long почитайте статью Руденко (есть на этом сайте) про сравнение скорости работы с этими базовыми типами и decimal. Тогда, возможно, поймете, почему другие используют real, а не decimal. В финансах.

Удивительные вычисления в C12
Добавлено: 24 Октябрь 2025, 8:13
Игорь Столяров
finsoftrz писал(а): 24 Октябрь 2025, 8:02
про сравнение скорости работы с этими базовыми типами и decimal
Мне как-то на эти выигрыши микросекунд с болтом, если потом приходит бухгалтер
и говорит что у неё не сходится оборот за день и платежи через банк. Честно.
Что бы не втягиваться в спор с описаниями совдеповских времён я отправлю Вам
небольшой фрагмент переписки в личку. Посмотрите пожалуйста.
Удивительные вычисления в C12
Добавлено: 24 Октябрь 2025, 8:14
finsoftrz
Если в примере написать lSumma = round(rSumma,0.01) * 100, то результат будет 2.1. Или вместо decimal использовать real, тоже все норм.
Вообще говоря, неявные преобразования несут в себе опасность.
Удивительные вычисления в C12
Добавлено: 24 Октябрь 2025, 8:18
finsoftrz
Игорь Столяров писал(а): 24 Октябрь 2025, 8:13
finsoftrz писал(а): 24 Октябрь 2025, 8:02
про сравнение скорости работы с этими базовыми типами и decimal
Мне как-то на эти выигрыши микросекунд с болтом, если потом приходит бухгалтер
и говорит что у неё не сходится оборот за день и платежи через банк. Честно.
Что бы не втягиваться в спор с описаниями совдеповских времён я отправлю Вам
небольшой фрагмент переписки в личку. Посмотрите пожалуйста.
Речь про разницу в скорости на 2 порядка. При большом объеме вычислений это набегает.
К бухгалтеру имеет отношение не real, а то, что его неправильно использовали и попали на грабли при неявном преобразовании типов.
Удивительные вычисления в C12
Добавлено: 24 Октябрь 2025, 8:27
Игорь Столяров
finsoftrz писал(а): 24 Октябрь 2025, 8:18
попали на грабли при неявном преобразовании типов
Я бы согласился с Вами, если бы на входе в тестовую процедуру увидел значение
переменной REAL = 2.009999 ... но ошибки неявного преобразования я не вижу.
Мне уже посоветовали все операции с REAL делать через класс, который будет округлять результат.
Тогда там и останется "выигрыш скорости на 2 порядка". Проще этот гомно-тип данных вообще не использовать в Clarion.

Удивительные вычисления в C12
Добавлено: 24 Октябрь 2025, 8:36
finsoftrz
Игорь Столяров писал(а): 24 Октябрь 2025, 8:27
finsoftrz писал(а): 24 Октябрь 2025, 8:18
попали на грабли при неявном преобразовании типов
Я бы согласился с Вами, если бы на входе в тестовую процедуру увидел значение
переменной REAL = 2.009999 ... но ошибки неявного преобразования я не вижу.
Мне уже посоветовали все операции с REAL делать через класс, который будет округлять результат.
Тогда там и останется "выигрыш скорости на 2 порядка". Проще этот гомно-тип данных вообще не использовать в Clarion.
Зачем класс? Лучше простые функции в общей библиотеке. У меня таких несколько. В том числе и для округлений 0.55 по российскому правилу (обсуждали уже).