По просьбе наших посетителей, данный материал перенесен с сайта plc4good.org.ua, в связи с полной его потерей. Всё возражения принимаются через форму обратной связи.
plc4good.org.ua/view_post.php?id=165
Числа с плавающей точкой, на данный момент являются самыми часто используемыми.
В статье, приведены нетрадиционные способы работы с ними.
Введение
Тема чисел с плавающей точкой, оказалась неожиданно очень большой, поэтому в данном материале будут приведены только основные сведения. Для более подробного ознакомления придется изучать другие источники, в основном, конечно, сам стандарт IEEE 754.
В контроллерах фирмы Siemens пока используются только числа одинарной точности (single) размером 4 байта, что несколько сокращает данный обзор.
Начнем со стандарта, который описывает эти числа. Найти его можно на сайте разработчика IEEE.org и скачать для ознакомления 58 страниц pdf, заплатив всего лишь 89 американских рублей… Хм, сильный ход, учитывая, что они являются владельцами патента и вроде как заинтересованы в массовом распространении своих стандартов.
Тем не менее, найти его в интернете довольно легко.
уже не легко, ссылка и материал удален, по причине очень настойчивой просьбы правообладателя.
Теория
Число с плавающей точкой по стандарту IEEE754 выглядит так:
(-1) sign * b exponent * significand
где:
b = radix, 2 или 10 (в нашем случае 2)
s = знак (1 для отрицательных чисел)
significand = мантисса
Всего существует несколько видов чисел с плавающей точкой:
– Нормализованные (normal)
– Денормализованные (subnormal)
– -0 и +0 (отрицательный и положительный ноль)
– NaN (не числа)
Практика
Для начала выделим составляющие числа REAL стандарта IEEE754 (знак, порядок, мантисса)
FUNCTION_BLOCK FB1
TITLE = ‘divide real’
//
// divide real number to part s * m * (2^-23) * (2 ^ e).
//
AUTHOR: ddaVAR_INPUT
in: REAL ,
_in AT in : STRUCT
_dw: DWORD,
END_STRUCT,
END_VARVAR_OUTPUT
s: INT, // sign
e: INT, // order
m: DINT, // mantisa
END_VAR
IF DWORD_TO_BOOL(SHR(in:=_in._dw,n:=31)) THEN s:=-1, ELSE s:=1, END_IF,
e:=DWORD_TO_INT(SHR(in:=_in._dw,n:=23) AND DW#16#FF),
IF e=0 THEN m:=DWORD_TO_DINT(SHL(in:=(_in._dw AND DW#16#7fffff),n:=1)), ELSE m:=DWORD_TO_DINT((_in._dw AND DW#16#7fffff) OR DW#16#800000), END_IF,
e:=e–127,
END_FUNCTION_BLOCK
Проверяем:
Работает!
Пример работы с полем знака
Абсолютное значение числа
Инверсия знака числа
Пример работы с полем порядка
Умножение на два
Деление на два
Пример работы с полем мантиссы
Что-то сделать с мантиссой сложно, да, каждый бит мантиссы имеет числовой вес, но он зависит от значения поля степени. Поэтому просто добавим константу к текущему значению, для демонстрации расчета.
Весовые значения каждого бита в мантиссе
Добавляем константу +2.0
В данном примере добавляется к исходному числу бит 22, весовой коэффициент которого 0.5, порядок исходного числа 2, значит, на самом деле к исходному числу добавляется 0.5*22=2.0
Сравнение
Есть еще один вариант работы с числами с плавающей точкой, нетрадиционными методами, а именно – сравнение. Это можно проделать, основываясь на том факте, что числа, кодированные по стандарту IEEE754 – корректно упорядочены, если их рассматривать как знаковые целые числа.
Сравнение можно существенно упростить, если считать, что величина -0.0 меньше +0.0 (но это не соответствует стандарту IEEE754). Также эти сравнения не работают с неупорядоченными числами типа NaN.
FUNCTION_BLOCK FB100
VAR_INPUT
a: REAL,
_a AT a: STRUCT
dw: DINT,
END_STRUCT,
b: REAL,
_b AT b: STRUCT
dw: DINT,
END_STRUCT,
END_VARVAR_OUTPUT
a_less_b: BOOL,
END_VARIF ((_a.dw>,=0) AND (_a.dw<,_b.dw))
OR
((_a.dw<,0) AND (_a.dw>,_b.dw))
THEN
a_less_b:=true,
ELSE
a_less_b:=false,
END_IF,END_FUNCTION_BLOCK
Советы
Учитывая то, что формат чисел с плавающей точкой, содержит определенные недостатки, при работе с ними необходимо учитывать следующие нюансы:
Стараться работать с числами одних порядков
Здесь погрешность относительно результата составила 800 процентов,
если использовать результат в последующих вычислениях, с числами порядка 101 – будут проблемы.
Сравнивать на равенство правильно, иначе два числа, которые должны быть одинаковы по вычислениям, в результате накапливания погрешности могут не дать необходимого результата.
Где eps допустимая погрешность, обычно максимальное число, которое при добавлении к единице, дает в результате опять единицу.
Посчитаем это значение для контроллеров Siemens.
Значение совпадает с заявленным в стандарте.
Учитывать возможность накопления погрешности при многочисленных вычислениях,
например, если мы возьмем миллион случайных чисел от 0 до 1 и сложим их, мы получим один результат, если мы сначала отсортируем эти же числа и сложим снова, мы получим другой результат, если отсортируем исходный набор в другом порядке и сложим – получим третий результат.
Источники
Забавный материал в духе – Как IEEE754 уничтожит человечество? – yur.ru/science/computer/IEEE754.htm
Хорошее описание с примерами – softelectro.ru/ieee754.html
а также книга ‘Hacker’s Delight’ Henry S. Warren, Jr. 2002 год. Charter 15
Еще хотелось бы в данной статье оценить быстродействие приведенных примеров, но, к сожалению, в данный момент нет доступа к реальному контроллеру, а результаты на симуляторе не внушают доверия. Поэтому статья обновится чуть позже.
Комментарии к материалу
Добавлен: Семён Дата: 2013-04-24
Для S7-1500 ввели формат длинный 64-битный L Real, который решит глюки короткого 32-битного Реала
i053.radikal.ru/1304/0f/6301936a99fe.jpg
Добавлен: Алексей Дата: 2013-12-21
По поводу результата на симуляторе – это вы зря. Он работает на базе WinLC – что есть полный аналог s7-400.
Добавлен: komatic Дата: 2013-12-21
возможно и так, но слова ‘полный аналог’ и ‘есть нюансы’ для меня синонимы 🙂
Добавлен: WarLex Дата: 2014-05-13
почему ограничение формата REAL 3.402823466e+38, Пробовал поставить единицы во всех разрядах ‘e’ не получилось(((
Оцените статью!