Как проверить число REAL на допустимость применения в дальнейших расчетах? (update)

По просьбе наших посетителей, данный материал перенесен с сайта plc4good.org.ua, в связи с полной его потерей. Всё возражения принимаются через форму обратной связи.

plc4good.org.ua/view_post.php?id=222

Работая в контроллере с числами в формате REAL, выход обрабатываемых данных за допустимый диапазон – это не единственная неприятность которая может произойти.
Хорошая традиция проверять данные перед использованием, особенно если они получены от соседних систем.

Update: после правки совпали контрольные суммы у базового варианта.
Добавлен вариант проверки из комментария.

Имея жестко описанную (стандарт IEEE 754) структуру, в вычислениях могут использоваться только нормализованные числа.
Рассмотренная функция позволяет определить вид проверяемого числа:
– нормализованное (нет ошибки)
– бесконечность
– денормализованное
– не число (NaN)

Вспомним как устроены числа типа REAL.

real
Структура числа

real
Диапазоны

Функция входит в библиотеку BASIS LIBRARY V8.0 пакета PCS 7

real
Описание блока в Function Manual

Name: FC260
Symbolic Name: ChkREAL
Symbol Comment: Check infinite values
Family: @SYSTEM
Version: 5.0
Author: DRIVER80
Last modified: 02/08/2011

 

{
Scl_ResetOptions ,
Scl_OverwriteBlocks:=           ‘y’ ,
Scl_GenerateReferenceData :=    ‘y’ ,
Scl_S7ServerActive:=            ‘n’ ,
Scl_CreateObjectCode:=          ‘y’ ,
Scl_OptimizeObjectCode:=        ‘y’ ,
Scl_MonitorArrayLimits:=        ‘n’ ,
Scl_CreateDebugInfo :=          ‘n’ ,
Scl_SetOKFlag:=                 ‘n’ ,
Scl_SetMaximumStringLength:=    ‘254’
}
FUNCTION FC1260 : REAL
TITLE =‘Check infinite values’
AUTHOR  : DRIVER80
FAMILY  : ‘@SYSTEM’
NAME    : ChkREAL
VERSION : ‘5.0’
//reversed

VAR_INPUT
In            : REAL,        //The real value to be checked
END_VAR
VAR_OUTPUT
ErrNum        : INT,         //error number: 0=no error/1=infinity/2=denormal/3=NaN
END_VAR
VAR_TEMP
theREAL       : REAL,
theREAL_dw AT theREAL : DWORD,
exponent      : DWORD,       //Bit 23 – 30,
fraction_1    : DWORD,       //Bit 22, most significant bit
fraction_2    : DWORD,       //Bit  0 – 21
END_VAR
BEGIN

ErrNum:=0,
theREAL:=In,
exponent:=theREAL_dw AND DW#16#7F800000,
fraction_1:=theREAL_dw AND DW#16#400000,
fraction_2:=theREAL_dw AND DW#16#3FFFFF,
FC1260:=theREAL,

IF exponent = DW#16#7F800000
THEN
IF (fraction_1&lt,&gt,DW#16#0) OR ((fraction_1 = DW#16#0) AND (fraction_2 &lt,&gt, DW#16#0))
THEN
ErrNum:=3,              //3=NaN
OK:=false,
ELSIF (fraction_1 = DW#16#0) AND (fraction_2 = DW#16#0)
THEN
ErrNum:=1,          //1=infinity
IF theREAL &gt, 0.000000e+000 THEN FC1260:=3.402822e+038, ELSE FC1260:=-3.402822e+038, END_IF,
END_IF,
ELSIF (exponent = DW#16#0) AND ((fraction_1 &lt,&gt, DW#16#0) OR (fraction_2 &lt,&gt, DW#16#0))
THEN
ErrNum:=2,              //2=denormal
FC1260:=0.000000e+000,
END_IF,

END_FUNCTION

 

real
Block checksum оригинального и восстановленного блока совпадает.

Пример использования:

Ti:=ChkREAL(In :=Ti,ErrNum :=nTiErr),      // check if time is good number       

IF nTiErr = 1 OR nTiErr = 3 THEN ErrorNum:=33, ELSE ErrorNum:=0, END_IF,

 

Альтернативный вариант от Василия:

FUNCTION_BLOCK FB32 //Фильтр NaN и Inf для чисел REAL.
TITLE = ‘Фильтр NaN Inf’,

VAR_INPUT //Входные переменные, сохраняемые.
X:REAL:=0.0, //Вход.
END_VAR

VAR_OUTPUT //Выходные переменные, сохраняемые.
Y:REAL:=0.0, //Выход.
END_VAR

//Алгоритм.
//Если Y=(NaN или Inf или -Inf) то Y=0 иначе Y=X.
//DW#16#7F800000=DW#2#01111111_10000000_00000000_00000000
//Стандарт IEEE 754.
IF ((REAL_TO_DWORD(X) AND DW#16#7F800000) = DW#16#7F800000) THEN
Y:=0.0,
ELSE
Y:=X,
END_IF,

END_FUNCTION_BLOCK

real
И еще два ‘бюджетных’ варианта, выведенных из предложенного в комментариях,
для тех кто не любит лишних блоков в проекте.

Комментарии к материалу

Добавлен: Василий Дата: 2016-06-29

Предлагаю альтернативный вариант. Менее функциональный но более удобный и тестированный.
Эффективно борется с NaN и Inf.
FUNCTION_BLOCK FB32 //Фильтр NaN и Inf для чисел REAL.
TITLE = ‘Фильтр NaN Inf’,
VAR_INPUT //Входные переменные, сохраняемые.
X:REAL:=0.0, //Вход.
END_VAR
VAR_OUTPUT //Выходные переменные, сохраняемые.
Y:REAL:=0.0, //Выход.
END_VAR
//Алгоритм.
//Если Y=(NaN или Inf или -Inf) то Y=0 иначе Y=X.
//DW#16#7F800000=DW#2#01111111_10000000_00000000_00000000
//Стандарт IEEE 754.
IF ((REAL_TO_DWORD(X) AND DW#16#7F800000) = DW#16#7F800000)
THEN
Y:=0.0,
ELSE
Y:=X,
END_IF,
END_FUNCTION_BLOCK

Добавлен: komatic Дата: 2016-06-30

Спасибо за вариант. Добавил его в материал.

Комментарии: 15Активность: 54691
0 0 голоса

Оцените статью!

guest
0 Комментарий
Межтекстовые Отзывы
Посмотреть все комментарии