Удивительные вычисления в C12

Clarion, Clarion 7

Модератор: Дед Пахом

Правила форума
При написании вопроса или обсуждении проблемы, не забывайте указывать версию Clarion который Вы используете.
А так же пользуйтесь спец. тегами при вставке исходников!!!
Ответить
Аватара пользователя
Игорь Столяров
Ветеран движения
Сообщения: 8234
Зарегистрирован: 07 Июль 2005, 10:19
Откуда: г. Ростов-на-ДоМу
Благодарил (а): 34 раза
Поблагодарили: 105 раз

Удивительные вычисления в C12

Сообщение Игорь Столяров »

Всем привет !

Ко мне пришла бухгалтер с калькулятором ... и мне стало стыдно.
Показываю концептуальный пример.

Код: Выделить всё

  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 и т.д.

Кто-нибудь может объяснить этот результат ? :shock:

P/S: Кстати, это ошибка всплыла при работе с эквайрингом Сбера. :(
Последний раз редактировалось Игорь Столяров 24 Октябрь 2025, 8:30, всего редактировалось 1 раз.
За теми, кто отстал, не возвращаться ! 🏴‍☠️ Кодекс
FromSPB
Новичок
Сообщения: 9
Зарегистрирован: 30 Ноябрь 2024, 21:31
Поблагодарили: 1 раз

Удивительные вычисления в C12

Сообщение 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.
Аватара пользователя
Игорь Столяров
Ветеран движения
Сообщения: 8234
Зарегистрирован: 07 Июль 2005, 10:19
Откуда: г. Ростов-на-ДоМу
Благодарил (а): 34 раза
Поблагодарили: 105 раз

Удивительные вычисления в C12

Сообщение Игорь Столяров »

FromSPB писал(а): 24 Октябрь 2025, 0:22 DECIMAL 2.01 -> REAL 2.0099999999999997E+0
Вот только на входе в процедуру параметр равен именно 2.01, а не 2.009999 ...
И тогда каким счастливым случаем данное правило преобразования не распространяется на 1.01 / 3.01 и т.д. ?
Очень хотелось бы проверить этот концепт на C11.1 - у меня есть подозрение, что проблема появилась именно в C12. :(
За теми, кто отстал, не возвращаться ! 🏴‍☠️ Кодекс
FromSPB
Новичок
Сообщения: 9
Зарегистрирован: 30 Ноябрь 2024, 21:31
Поблагодарили: 1 раз

Удивительные вычисления в C12

Сообщение 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 до ближайшего целого", т.е. отбрасывание дробной части.
Аватара пользователя
Игорь Столяров
Ветеран движения
Сообщения: 8234
Зарегистрирован: 07 Июль 2005, 10:19
Откуда: г. Ростов-на-ДоМу
Благодарил (а): 34 раза
Поблагодарили: 105 раз

Удивительные вычисления в C12

Сообщение Игорь Столяров »

FromSPB писал(а): 24 Октябрь 2025, 3:23Вы не правы.
OK ! Давайте скажем так: это значение которое я вижу.
Значит ещё и неправильно работает преобразование REAL -> STRING показывая значение отличное от реального. :(

Спасибо за объяснения. Жаль нет нормального доступа к ClaHUB - там любят такие "особенности". :D
У нас тут тоже как-то обсуждался "прекрасный" базовый тип REAL, который есть во всех драйверах БД Clarion.
Я всегда избегал работу с этим гом-ом в финансах, но попался на передаче суммы как параметра по значению. :D

Понятно, что для REAL нужно корректировать точность через ROUND при делении или умножении на дробь.
Хотя это ещё тот аттракцион ... Но ошибка при умножении на 100, да ещё через раз - это как назвать без мата .... ?!

ВОТ ИМЕННО ПОЭТОМУ Я ВСЕГДА РЕКОМЕНДУЮ ИЗБЕГАТЬ ИСПОЛЬЗОВАНИЕ ЧУЖОГО ЗАКРЫТЫТОГО КОДА В CLARION !
За теми, кто отстал, не возвращаться ! 🏴‍☠️ Кодекс
Аватара пользователя
finsoftrz
✯ Ветеран ✯
Сообщения: 5531
Зарегистрирован: 06 Ноябрь 2014, 12:48
Благодарил (а): 18 раз
Поблагодарили: 77 раз

Удивительные вычисления в C12

Сообщение finsoftrz »

На С6.3 аналогично воспроизводится.
Насчет использования real/long почитайте статью Руденко (есть на этом сайте) про сравнение скорости работы с этими базовыми типами и decimal. Тогда, возможно, поймете, почему другие используют real, а не decimal. В финансах. :lol:
C6/C12, ШВС, tps/btrieve.
Аватара пользователя
Игорь Столяров
Ветеран движения
Сообщения: 8234
Зарегистрирован: 07 Июль 2005, 10:19
Откуда: г. Ростов-на-ДоМу
Благодарил (а): 34 раза
Поблагодарили: 105 раз

Удивительные вычисления в C12

Сообщение Игорь Столяров »

finsoftrz писал(а): 24 Октябрь 2025, 8:02 про сравнение скорости работы с этими базовыми типами и decimal
Мне как-то на эти выигрыши микросекунд с болтом, если потом приходит бухгалтер
и говорит что у неё не сходится оборот за день и платежи через банк. Честно.

Что бы не втягиваться в спор с описаниями совдеповских времён я отправлю Вам
небольшой фрагмент переписки в личку. Посмотрите пожалуйста.
За теми, кто отстал, не возвращаться ! 🏴‍☠️ Кодекс
Аватара пользователя
finsoftrz
✯ Ветеран ✯
Сообщения: 5531
Зарегистрирован: 06 Ноябрь 2014, 12:48
Благодарил (а): 18 раз
Поблагодарили: 77 раз

Удивительные вычисления в C12

Сообщение finsoftrz »

Если в примере написать lSumma = round(rSumma,0.01) * 100, то результат будет 2.1. Или вместо decimal использовать real, тоже все норм.
Вообще говоря, неявные преобразования несут в себе опасность.
C6/C12, ШВС, tps/btrieve.
Аватара пользователя
finsoftrz
✯ Ветеран ✯
Сообщения: 5531
Зарегистрирован: 06 Ноябрь 2014, 12:48
Благодарил (а): 18 раз
Поблагодарили: 77 раз

Удивительные вычисления в C12

Сообщение finsoftrz »

Игорь Столяров писал(а): 24 Октябрь 2025, 8:13
finsoftrz писал(а): 24 Октябрь 2025, 8:02 про сравнение скорости работы с этими базовыми типами и decimal
Мне как-то на эти выигрыши микросекунд с болтом, если потом приходит бухгалтер
и говорит что у неё не сходится оборот за день и платежи через банк. Честно.

Что бы не втягиваться в спор с описаниями совдеповских времён я отправлю Вам
небольшой фрагмент переписки в личку. Посмотрите пожалуйста.
Речь про разницу в скорости на 2 порядка. При большом объеме вычислений это набегает.
К бухгалтеру имеет отношение не real, а то, что его неправильно использовали и попали на грабли при неявном преобразовании типов.
C6/C12, ШВС, tps/btrieve.
Аватара пользователя
Игорь Столяров
Ветеран движения
Сообщения: 8234
Зарегистрирован: 07 Июль 2005, 10:19
Откуда: г. Ростов-на-ДоМу
Благодарил (а): 34 раза
Поблагодарили: 105 раз

Удивительные вычисления в C12

Сообщение Игорь Столяров »

finsoftrz писал(а): 24 Октябрь 2025, 8:18 попали на грабли при неявном преобразовании типов
Я бы согласился с Вами, если бы на входе в тестовую процедуру увидел значение
переменной REAL = 2.009999 ... но ошибки неявного преобразования я не вижу.

Мне уже посоветовали все операции с REAL делать через класс, который будет округлять результат.
Тогда там и останется "выигрыш скорости на 2 порядка". Проще этот гомно-тип данных вообще не использовать в Clarion. :(
За теми, кто отстал, не возвращаться ! 🏴‍☠️ Кодекс
Аватара пользователя
finsoftrz
✯ Ветеран ✯
Сообщения: 5531
Зарегистрирован: 06 Ноябрь 2014, 12:48
Благодарил (а): 18 раз
Поблагодарили: 77 раз

Удивительные вычисления в C12

Сообщение finsoftrz »

Игорь Столяров писал(а): 24 Октябрь 2025, 8:27
finsoftrz писал(а): 24 Октябрь 2025, 8:18 попали на грабли при неявном преобразовании типов
Я бы согласился с Вами, если бы на входе в тестовую процедуру увидел значение
переменной REAL = 2.009999 ... но ошибки неявного преобразования я не вижу.

Мне уже посоветовали все операции с REAL делать через класс, который будет округлять результат.
Тогда там и останется "выигрыш скорости на 2 порядка". Проще этот гомно-тип данных вообще не использовать в Clarion. :(
Зачем класс? Лучше простые функции в общей библиотеке. У меня таких несколько. В том числе и для округлений 0.55 по российскому правилу (обсуждали уже).
C6/C12, ШВС, tps/btrieve.
Аватара пользователя
Дед Пахом
Старичок
Сообщения: 3345
Зарегистрирован: 07 Июль 2005, 16:51
Откуда: Москва, Россия
Благодарил (а): 20 раз
Поблагодарили: 56 раз
Контактная информация:

Удивительные вычисления в C12

Сообщение Дед Пахом »

С уважением, ДП
Аватара пользователя
finsoftrz
✯ Ветеран ✯
Сообщения: 5531
Зарегистрирован: 06 Ноябрь 2014, 12:48
Благодарил (а): 18 раз
Поблагодарили: 77 раз

Удивительные вычисления в C12

Сообщение finsoftrz »

Игорю настолько не понравилось им же и предложенное вводить штуки с 3 знаками после точки, что он теперь, похоже, стал кг и метры вводить как целые числа. :lol:
C6/C12, ШВС, tps/btrieve.
Ответить