Маленькая засада с вещественными числами
5 (1)
Маленькая засада с вещественными числами ( fplab 04.02.2015 10:55 )
5(1)Следующий код
VAR a, b, z; a = 0.7; b = 0.1; z = INT ((a + b) * 10); MSGBOX (z);
выводит на экран 7, хотя, очевидно, должно быть 8. Причина - в представлении чисел. Достаточно чуточку изменить
VAR a, b, z; a = 0.7000000001; b = 0.1; z = INT ((a + b) * 10); MSGBOX (z);
и тогда все нормально - выводится 8.
Будьте внимательны, коллеги :)
>> ОтветитьОчень старые грабли, поддержка советует NUMERIC, т.е. a = $0.7; b = $0.1; ( OldFox 04.02.2015 12:01 )
5(1)Цитата:
Почему выражение println (int(100 * 1.13)); дает в результате 112?
это проблема не RSL, поскольку аналогичный пример на Си тоже дает 112, это всемирный заговор машин. :)
А точнее - особенности представления вещественных чисел в информационно-вычислительных системах.
http://www.delphikingdom.com/asp/viewitem.asp?catalogid=374
Когда Вы, выполняя подобные вычисления, не определяете тип, то число 1.13 по умолчанию считается типом DOUBLE.
Внутри процессорных обработок, при работе с вещественными числами, число 1.13 представляется в двоичной системе в виде степеней двойки.
О том, как это делается, можно почитать по ссылке http://vestikinc.narod.ru/AB/ni_bin.htm
целая часть - это 1 * 2^0
дробная часть
0,13 * 2 = 0,26
0,26 * 2 = 0,52
0,52 * 2 = 1,04
0,04 * 2 = 0,08
0,08 * 2 = 0,16
0,16 * 2 = 0,32
0,32 * 2 = 0,64
0,64 * 2 = 1,28
0,28 * 2 = 0,56
0,56 * 2 = 1,12
Можно продолжать дальше до бесконечности. Это повлияет в результате на точность, но для того, чтобы проиллюстрировать картину, уже достаточно.
В итоге, в двоичной системе это число будет представлено как 1,0010000101.
Если теперь перевести это число обратно в десятичную систему, то переводиться оно будет по такой схеме:
1 * 2^0 + 0 * 2^-1 + 0 * 2^-2 + 1 * 2^-3 + 0 * 2^-4 + 0 * 2^-5 + 0 * 2^-6 + 0 * 2^-7 + 1 * 2^-8 + 0 * 2^-9 + 1 * 2^-10 = 1 + 1 * 2^-3 + 1 * 2^-8 + 1 * 2^-10 = 1 + 0.125 + 0.00390625 + 0.0009765625 = 1.1298828125.
При бОльшей степени точности получится 1,1299999999999, что при умножении на 100 и отбрасывании дробной части как раз и дает 112.
В RSL эта проблема решена для типов NUMERIC и MONEY. Тип DOUBLE не дает достаточной точности при вычислениях.
Поэтому, во-первых, объявляйте все переменные, с которыми Вы работаете, а во-вторых, работайте с типом NUMERIC.
>> ОтветитьОчень старые грабли, поддержка советует NUMERIC, т.е. a = $0.7; b = $0.1; ( OldFox 04.02.2015 12:01 )
5(1)Цитата:
Почему выражение println (int(100 * 1.13)); дает в результате 112?
это проблема не RSL, поскольку аналогичный пример на Си тоже дает 112, это всемирный заговор машин. :)
А точнее - особенности представления вещественных чисел в информационно-вычислительных системах.
http://www.delphikingdom.com/asp/viewitem.asp?catalogid=374
Когда Вы, выполняя подобные вычисления, не определяете тип, то число 1.13 по умолчанию считается типом DOUBLE.
Внутри процессорных обработок, при работе с вещественными числами, число 1.13 представляется в двоичной системе в виде степеней двойки.
О том, как это делается, можно почитать по ссылке http://vestikinc.narod.ru/AB/ni_bin.htm
целая часть - это 1 * 2^0
дробная часть
0,13 * 2 = 0,26
0,26 * 2 = 0,52
0,52 * 2 = 1,04
0,04 * 2 = 0,08
0,08 * 2 = 0,16
0,16 * 2 = 0,32
0,32 * 2 = 0,64
0,64 * 2 = 1,28
0,28 * 2 = 0,56
0,56 * 2 = 1,12
Можно продолжать дальше до бесконечности. Это повлияет в результате на точность, но для того, чтобы проиллюстрировать картину, уже достаточно.
В итоге, в двоичной системе это число будет представлено как 1,0010000101.
Если теперь перевести это число обратно в десятичную систему, то переводиться оно будет по такой схеме:
1 * 2^0 + 0 * 2^-1 + 0 * 2^-2 + 1 * 2^-3 + 0 * 2^-4 + 0 * 2^-5 + 0 * 2^-6 + 0 * 2^-7 + 1 * 2^-8 + 0 * 2^-9 + 1 * 2^-10 = 1 + 1 * 2^-3 + 1 * 2^-8 + 1 * 2^-10 = 1 + 0.125 + 0.00390625 + 0.0009765625 = 1.1298828125.
При бОльшей степени точности получится 1,1299999999999, что при умножении на 100 и отбрасывании дробной части как раз и дает 112.
В RSL эта проблема решена для типов NUMERIC и MONEY. Тип DOUBLE не дает достаточной точности при вычислениях.
Поэтому, во-первых, объявляйте все переменные, с которыми Вы работаете, а во-вторых, работайте с типом NUMERIC.
>> ОтветитьСпасибо ( fplab 04.02.2015 12:34 )
5(1)Да я то в курсе. А вот коллега, недавно столкнувшийся с этим, попался.
И совершенно верно, что RSL тут не причем - "это все придумал Черчилль в восемнадцатом году" :)
>> Ответить
или вместо Int( иcпользовать int(round( ( OldFox 04.02.2015 12:11 )
5(1)z = INT( ROUND( ((a + b) * 10), 0) ) ;
>> Ответитьа как в рс отбросить только копейки? ( KaMPiLeR 14.10.2016 13:06 )
5(1)a=$47000; b=69.5434; c=int(a/b); println(c);
int - округляет епрст. round и floor тоже.
нужно чтоб получилось 675, ну а в идеале - чтоб и сотые мог отбросить и получилось - 675,83 ))
>> ОтветитьRound ( Максим 17.10.2016 10:22 )
5(1)мдя уж - спасибо - в доке только два параметра ( KaMPiLeR 17.10.2016 10:35 )
5(1)откуда третий взяли и какие значения может принимать?
а то реализовал через отбрасывание строки ))
>> ОтветитьЯзык_RSL.pdf ( Максим 17.10.2016 10:45 )
5(1)Not specified
>> Ответитьспасибо )) ( KaMPiLeR 17.10.2016 11:02 )
5(1)старая версия была доки
>> Ответитьверсия ( skameykin22 07.11.2016 10:15 )
5(1)Да, внимательность не повредит.
>> Ответить