Версия для печати

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

Дата: 2016-06-30

Добавлено: komatic

Тема: SCL



real



Работая в контроллере с числами в формате 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<>DW#16#0) OR ((fraction_1 = DW#16#0) AND (fraction_2 <> 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 > 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 <> DW#16#0) OR (fraction_2 <> 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

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







real







Просмотров: 3267

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

Добавлен: Василий    Дата: 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

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

Добавить комментарий

Ваше имя:

Текст комментария (4000 max):

Введите сумму с картинки: