Код:
FUNCTION_BLOCK FB_RealToWords_IEEE754
VAR_INPUT
InputReal : REAL;
END_VAR
VAR_OUTPUT
WordHigh : WORD; // Биты 31-16
WordLow : WORD; // Биты 15-0
StatusCode : INT; // 0: Normal, 1: Zero, 2: Infinity, 3: NaN
END_VAR
VAR
Sign : BOOL;
AbsValue : REAL;
Exponent : INT;
Mantissa : DINT;
BiasedExp : BYTE;
SignBit : DINT;
TempDword : DINT;
i : INT;
Fraction : REAL;
ScaledMant : REAL;
END_VAR
// ============================================================================
// ШАГ 1: Обработка особых случаев (до математических операций)
// ============================================================================
// Проверка на NaN (NaN != NaN по стандарту IEEE 754)
IF (InputReal <> InputReal) THEN
// NaN: Exponent = 255 (16#FF), Mantissa != 0
SignBit := 0; // Для NaN знак обычно игнорируем
BiasedExp := 255;
Mantissa := 16#00400000; // Quiet NaN (старший бит мантиссы = 1)
StatusCode := 3;
// Сборка DWORD
TempDword := SHL(SignBit, 31) OR SHL(BiasedExp, 23) OR Mantissa;
WordHigh := DWORD_TO_WORD(SHR(TempDword, 16));
WordLow := DWORD_TO_WORD(TempDword);
RETURN;
END_IF;
// Проверка на бесконечность (через сравнение с максимальным REAL)
// Примечание: в некоторых реализациях потребуется флаг от переполнения
IF (InputReal > 3.40282347E+38) OR (InputReal < -3.40282347E+38) THEN
// Infinity: Exponent = 255, Mantissa = 0
SignBit := 1;
BiasedExp := 255;
Mantissa := 0;
StatusCode := 2;
TempDword := SHL(SignBit, 31) OR SHL(BiasedExp, 23) OR Mantissa;
WordHigh := DWORD_TO_WORD(SHR(TempDword, 16));
WordLow := DWORD_TO_WORD(TempDword);
RETURN;
END_IF;
// ============================================================================
// ШАГ 2: Извлечение знака
// ============================================================================
IF InputReal < 0.0 THEN
Sign := TRUE;
SignBit := 1;
AbsValue := -InputReal; // Сохраняем абсолютное значение
ELSIF InputReal > 0.0 THEN
Sign := FALSE;
SignBit := 0;
AbsValue := InputReal;
ELSE
// Случай нуля (+0.0 или -0.0)
// Для сохранения знака -0.0 проверяем 1.0/InputReal
IF (1.0 / InputReal) < 0.0 THEN
Sign := TRUE;
SignBit := 1;
ELSE
Sign := FALSE;
SignBit := 0;
END_IF;
// Zero: Exponent = 0, Mantissa = 0
BiasedExp := 0;
Mantissa := 0;
StatusCode := 1;
TempDword := SHL(SignBit, 31) OR SHL(BiasedExp, 23) OR Mantissa;
WordHigh := DWORD_TO_WORD(SHR(TempDword, 16));
WordLow := DWORD_TO_WORD(TempDword);
RETURN;
END_IF;
// ============================================================================
// ШАГ 3: Нормализация числа (находим экспоненту без LOG)
// ============================================================================
Exponent := 0;
Fraction := AbsValue;
// Если число >= 2.0, делим на 2 пока не попадём в диапазон [1.0, 2.0)
WHILE Fraction >= 2.0 DO
Fraction := Fraction * 0.5; // Деление на 2
Exponent := Exponent + 1;
END_WHILE;
// Если число < 1.0, умножаем на 2 пока не попадём в диапазон [1.0, 2.0)
WHILE Fraction < 1.0 DO
Fraction := Fraction * 2.0;
Exponent := Exponent - 1;
END_WHILE;
// Теперь Fraction в диапазоне [1.0, 2.0), Exponent - порядок числа
// ============================================================================
// ШАГ 4: Вычисление смещённой экспоненты (Bias = 127)
// ============================================================================
BiasedExp := BYTE_OF(Exponent + 127);
// Проверка на переполнение/исчезновение экспоненты
IF BiasedExp >= 255 THEN
// Переполнение -> Infinity
BiasedExp := 255;
Mantissa := 0;
StatusCode := 2;
TempDword := SHL(SignBit, 31) OR SHL(BiasedExp, 23) OR Mantissa;
WordHigh := DWORD_TO_WORD(SHR(TempDword, 16));
WordLow := DWORD_TO_WORD(TempDword);
RETURN;
ELSIF BiasedExp <= 0 THEN
// Исчезновение -> Denormal или Zero
BiasedExp := 0;
// Для денормализованных чисел нужна дополнительная обработка
Mantissa := 0;
StatusCode := 1;
TempDword := SHL(SignBit, 31) OR SHL(BiasedExp, 23) OR Mantissa;
WordHigh := DWORD_TO_WORD(SHR(TempDword, 16));
WordLow := DWORD_TO_WORD(TempDword);
RETURN;
END_IF;
// ============================================================================
// ШАГ 5: Извлечение мантиссы (23 бита)
// ============================================================================
// Fraction сейчас в диапазоне [1.0, 2.0)
// Убираем ведущую 1 (она неявная в IEEE 754)
Fraction := Fraction - 1.0; // Теперь [0.0, 1.0)
// Преобразуем дробную часть в 23-битную мантиссу
// Умножаем на 2^23 = 8388608
ScaledMant := Fraction * 8388608.0;
Mantissa := DINT_OF(ScaledMant + 0.5); // Округление
// Ограничиваем мантиссу 23 битами (маска 16#007FFFFF)
Mantissa := Mantissa AND 16#007FFFFF;
// ============================================================================
// ШАГ 6: Сборка 32-битного представления
// ============================================================================
// Формат: [Sign:1][Exponent:8][Mantissa:23]
// Бит 31: Знак
// Биты 30-23: Экспонента
// Биты 22-0: Мантисса
TempDword := 0;
// Добавляем бит знака (бит 31)
IF SignBit = 1 THEN
TempDword := TempDword OR 16#80000000;
END_IF;
// Добавляем экспоненту (биты 30-23)
TempDword := TempDword OR SHL(DINT_OF(BiasedExp), 23);
// Добавляем мантиссу (биты 22-0)
TempDword := TempDword OR Mantissa;
// ============================================================================
// ШАГ 7: Разделение на два WORD
// ============================================================================
WordHigh := DWORD_TO_WORD(SHR(TempDword, 16)); // Старшие 16 бит
WordLow := DWORD_TO_WORD(TempDword); // Младшие 16 бит
StatusCode := 0; // Normal
END_FUNCTION_BLOCK