将 LREAL 转换为二进制并将其解释为以 10 为基数的 LINT
Converting LREAL to binary and interpreting it as base 10 LINT
运行这里是“CODESYS V3.5 SP16”,我正在尝试实现
中提到的hashcode算法
Best implementation for hashCode method for a collection
并且必须构建我自己的解决方案来复制 Java 的 Float.floatToIntBits(f)
,从而产生以下功能
FUNCTION F_lrealToLintBits : LINT
VAR_INPUT
lrVal : LREAL;
END_VAR
VAR
arrBytes : ARRAY[0..7] OF BYTE; // LREAL contains 64 bits and each byte contains 8 bits
pVal : POINTER TO LREAL := ADR(arrBytes);
diIndx : DINT;
uiExpt : UINT := 0; // exponent goes from 0 to 63
END_VAR
pVal^ := lrVal; // maps LREAL to array of bytes
// little endian? cause it seems that least significant bit is at lowest address
FOR diIndx := LOWER_BOUND(arrBytes, 1) TO UPPER_BOUND(arrBytes, 1) BY 1 DO
// bit access seems to be manual only so no loops
IF arrBytes[diIndx].0 THEN
F_lrealToLintBits := F_lrealToLintBits + LREAL_TO_LINT(EXPT(2, uiExpt));
END_IF
uiExpt := uiExpt + 1; // have to increment exponent after every bit
IF arrBytes[diIndx].1 THEN
F_lrealToLintBits := F_lrealToLintBits + LREAL_TO_LINT(EXPT(2, uiExpt));
END_IF
uiExpt := uiExpt + 1; // have to increment exponent after every bit
IF arrBytes[diIndx].2 THEN
F_lrealToLintBits := F_lrealToLintBits + LREAL_TO_LINT(EXPT(2, uiExpt));
END_IF
uiExpt := uiExpt + 1; // have to increment exponent after every bit
IF arrBytes[diIndx].3 THEN
F_lrealToLintBits := F_lrealToLintBits + LREAL_TO_LINT(EXPT(2, uiExpt));
END_IF
uiExpt := uiExpt + 1; // have to increment exponent after every bit
IF arrBytes[diIndx].4 THEN
F_lrealToLintBits := F_lrealToLintBits + LREAL_TO_LINT(EXPT(2, uiExpt));
END_IF
uiExpt := uiExpt + 1; // have to increment exponent after every bit
IF arrBytes[diIndx].5 THEN
F_lrealToLintBits := F_lrealToLintBits + LREAL_TO_LINT(EXPT(2, uiExpt));
END_IF
uiExpt := uiExpt + 1; // have to increment exponent after every bit
IF arrBytes[diIndx].6 THEN
F_lrealToLintBits := F_lrealToLintBits + LREAL_TO_LINT(EXPT(2, uiExpt));
END_IF
uiExpt := uiExpt + 1; // have to increment exponent after every bit
IF arrBytes[diIndx].7 THEN
F_lrealToLintBits := F_lrealToLintBits + LREAL_TO_LINT(EXPT(2, uiExpt));
END_IF
uiExpt := uiExpt + 1; // have to increment exponent after every bit
END_FOR
首先,我想知道在某些库中是否已经存在这样的函数?
我查看了很多地方,包括 OSCAT“Basic, 3.31”库,但找不到任何类似的东西(即使是一组我可以链接在一起的函数也可以)。
其次,位访问只能手动完成吗?
我更愿意使用循环,但似乎这不可能?如果数组中的数据类型从 BYTE
变为其他类型(例如 DWORD
),是否有较少的复制和粘贴访问位的方法涉及自动检测位数?
潜在替代方案
似乎这是联合派上用场的地方,如 https://forge.codesys.com/forge/talk/Engineering/thread/02a65a50b2/#e5f4/1911/c524 中所述,如果值不是来自外部来源(即无需检查字节顺序),Float.floatToIntBits(f)
会像
一样简单
TYPE
U_lrealToRawLintBits :
UNION
lrVal : LREAL;
liVal : LINT;
END_UNION
END_TYPE
// supposed to replicate floatToIntBits() in Java at
// https://github.com/openjdk/jdk/blob/739769c8fc4b496f08a92225a12d07414537b6c0/src/java.base/share/classes/java/lang/Float.java#L775
FUNCTION F_lrealToLintBits : LINT
VAR_INPUT
lrVal : LREAL;
END_VAR
VAR
uLrealToLintBits : U_lrealToRawLintBits; // for interpreting LREAL as base 10 LINT
END_VAR
IF FPU.IsLRealPosInfinity(lrVal) THEN
F_lrealToLintBits := 2139095040; // corresponds to 0x7f800000
ELSIF FPU.IsLRealNegInfinity(lrVal) THEN
F_lrealToLintBits := 4286578688; // corresponds to 0xff800000
ELSIF FPU.IsLRealNaN(lrVal) THEN
F_lrealToLintBits := 2143289344; // corresponds to 0x7fc00000
ELSE
uLrealToLintBits.lrVal := lrVal;
F_lrealToLintBits := uLrealToLintBits.liVal;
END_IF
我认为您要实现的目标是将 LREAL 作为输入,但其中的位实际上是 LINT 的位,但进行了字节交换。
如果是这样,应该有更直接的解决方案。这是一个例子:
FUNCTION lreal_to_int64 : LINT
VAR_INPUT
value: LREAL;
value_is_little_endian: BOOL;
END_VAR
VAR
no_swap: BOOL;
source_bytes, target_bytes: POINTER TO BYTE;
value_as_lint: POINTER TO LINT;
END_VAR
{IF defined (IsLittleEndian)}
no_swap := value_is_little_endian;
{ELSE}
no_swap := NOT value_is_little_endian;
{END_IF}
IF
no_swap
THEN
value_as_lint := ADR(value);
lreal_to_int64 := value_as_lint^;
RETURN;
END_IF
target_bytes := ADR(lreal_to_int64);
source_bytes := ADR(value);
target_bytes[0] := source_bytes[7];
target_bytes[1] := source_bytes[6];
target_bytes[2] := source_bytes[5];
target_bytes[3] := source_bytes[4];
target_bytes[4] := source_bytes[3];
target_bytes[5] := source_bytes[2];
target_bytes[6] := source_bytes[1];
target_bytes[7] := source_bytes[0];
当然可以使用按位运算符以编程方式访问位。尝试这样的事情。
FUNCTION get_bit : BOOL
VAR_INPUT
value: LWORD;
bit_position: USINT;
END_VAR
VAR
shifted: LWORD;
END_VAR
shifted := SHR(value, bit_position);
get_bit := shifted.0;
运行这里是“CODESYS V3.5 SP16”,我正在尝试实现
中提到的hashcode算法Best implementation for hashCode method for a collection
并且必须构建我自己的解决方案来复制 Java 的 Float.floatToIntBits(f)
,从而产生以下功能
FUNCTION F_lrealToLintBits : LINT
VAR_INPUT
lrVal : LREAL;
END_VAR
VAR
arrBytes : ARRAY[0..7] OF BYTE; // LREAL contains 64 bits and each byte contains 8 bits
pVal : POINTER TO LREAL := ADR(arrBytes);
diIndx : DINT;
uiExpt : UINT := 0; // exponent goes from 0 to 63
END_VAR
pVal^ := lrVal; // maps LREAL to array of bytes
// little endian? cause it seems that least significant bit is at lowest address
FOR diIndx := LOWER_BOUND(arrBytes, 1) TO UPPER_BOUND(arrBytes, 1) BY 1 DO
// bit access seems to be manual only so no loops
IF arrBytes[diIndx].0 THEN
F_lrealToLintBits := F_lrealToLintBits + LREAL_TO_LINT(EXPT(2, uiExpt));
END_IF
uiExpt := uiExpt + 1; // have to increment exponent after every bit
IF arrBytes[diIndx].1 THEN
F_lrealToLintBits := F_lrealToLintBits + LREAL_TO_LINT(EXPT(2, uiExpt));
END_IF
uiExpt := uiExpt + 1; // have to increment exponent after every bit
IF arrBytes[diIndx].2 THEN
F_lrealToLintBits := F_lrealToLintBits + LREAL_TO_LINT(EXPT(2, uiExpt));
END_IF
uiExpt := uiExpt + 1; // have to increment exponent after every bit
IF arrBytes[diIndx].3 THEN
F_lrealToLintBits := F_lrealToLintBits + LREAL_TO_LINT(EXPT(2, uiExpt));
END_IF
uiExpt := uiExpt + 1; // have to increment exponent after every bit
IF arrBytes[diIndx].4 THEN
F_lrealToLintBits := F_lrealToLintBits + LREAL_TO_LINT(EXPT(2, uiExpt));
END_IF
uiExpt := uiExpt + 1; // have to increment exponent after every bit
IF arrBytes[diIndx].5 THEN
F_lrealToLintBits := F_lrealToLintBits + LREAL_TO_LINT(EXPT(2, uiExpt));
END_IF
uiExpt := uiExpt + 1; // have to increment exponent after every bit
IF arrBytes[diIndx].6 THEN
F_lrealToLintBits := F_lrealToLintBits + LREAL_TO_LINT(EXPT(2, uiExpt));
END_IF
uiExpt := uiExpt + 1; // have to increment exponent after every bit
IF arrBytes[diIndx].7 THEN
F_lrealToLintBits := F_lrealToLintBits + LREAL_TO_LINT(EXPT(2, uiExpt));
END_IF
uiExpt := uiExpt + 1; // have to increment exponent after every bit
END_FOR
首先,我想知道在某些库中是否已经存在这样的函数?
我查看了很多地方,包括 OSCAT“Basic, 3.31”库,但找不到任何类似的东西(即使是一组我可以链接在一起的函数也可以)。
其次,位访问只能手动完成吗?
我更愿意使用循环,但似乎这不可能?如果数组中的数据类型从 BYTE
变为其他类型(例如 DWORD
),是否有较少的复制和粘贴访问位的方法涉及自动检测位数?
潜在替代方案
似乎这是联合派上用场的地方,如 https://forge.codesys.com/forge/talk/Engineering/thread/02a65a50b2/#e5f4/1911/c524 中所述,如果值不是来自外部来源(即无需检查字节顺序),Float.floatToIntBits(f)
会像
TYPE
U_lrealToRawLintBits :
UNION
lrVal : LREAL;
liVal : LINT;
END_UNION
END_TYPE
// supposed to replicate floatToIntBits() in Java at
// https://github.com/openjdk/jdk/blob/739769c8fc4b496f08a92225a12d07414537b6c0/src/java.base/share/classes/java/lang/Float.java#L775
FUNCTION F_lrealToLintBits : LINT
VAR_INPUT
lrVal : LREAL;
END_VAR
VAR
uLrealToLintBits : U_lrealToRawLintBits; // for interpreting LREAL as base 10 LINT
END_VAR
IF FPU.IsLRealPosInfinity(lrVal) THEN
F_lrealToLintBits := 2139095040; // corresponds to 0x7f800000
ELSIF FPU.IsLRealNegInfinity(lrVal) THEN
F_lrealToLintBits := 4286578688; // corresponds to 0xff800000
ELSIF FPU.IsLRealNaN(lrVal) THEN
F_lrealToLintBits := 2143289344; // corresponds to 0x7fc00000
ELSE
uLrealToLintBits.lrVal := lrVal;
F_lrealToLintBits := uLrealToLintBits.liVal;
END_IF
我认为您要实现的目标是将 LREAL 作为输入,但其中的位实际上是 LINT 的位,但进行了字节交换。
如果是这样,应该有更直接的解决方案。这是一个例子:
FUNCTION lreal_to_int64 : LINT
VAR_INPUT
value: LREAL;
value_is_little_endian: BOOL;
END_VAR
VAR
no_swap: BOOL;
source_bytes, target_bytes: POINTER TO BYTE;
value_as_lint: POINTER TO LINT;
END_VAR
{IF defined (IsLittleEndian)}
no_swap := value_is_little_endian;
{ELSE}
no_swap := NOT value_is_little_endian;
{END_IF}
IF
no_swap
THEN
value_as_lint := ADR(value);
lreal_to_int64 := value_as_lint^;
RETURN;
END_IF
target_bytes := ADR(lreal_to_int64);
source_bytes := ADR(value);
target_bytes[0] := source_bytes[7];
target_bytes[1] := source_bytes[6];
target_bytes[2] := source_bytes[5];
target_bytes[3] := source_bytes[4];
target_bytes[4] := source_bytes[3];
target_bytes[5] := source_bytes[2];
target_bytes[6] := source_bytes[1];
target_bytes[7] := source_bytes[0];
当然可以使用按位运算符以编程方式访问位。尝试这样的事情。
FUNCTION get_bit : BOOL
VAR_INPUT
value: LWORD;
bit_position: USINT;
END_VAR
VAR
shifted: LWORD;
END_VAR
shifted := SHR(value, bit_position);
get_bit := shifted.0;