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

Clarion, Clarion 7

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

Правила форума
При написании вопроса или обсуждении проблемы, не забывайте указывать версию Clarion который Вы используете.
А так же пользуйтесь спец. тегами при вставке исходников!!!
Ответить
Аватара пользователя
Игорь Столяров
Ветеран движения
Сообщения: 8231
Зарегистрирован: 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 или присвоить значение внутри функции,
то результат будет правильный: 2.01 -> 201 -> 201. Ошибка вернётся на числе 6.01 и т.д.

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

P/S: Кстати, это ошибка всплыла при работе с эквайрингом Сбера. :(
За теми, кто отстал, не возвращаться ! 🏴‍☠️ Кодекс
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.
Аватара пользователя
Игорь Столяров
Ветеран движения
Сообщения: 8231
Зарегистрирован: 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 до ближайшего целого", т.е. отбрасывание дробной части.
Ответить