IEEE754 标准定义了两类 NaN:安静 NaN(QNaN)和信令 NaN(SNaN)。当 SNaN 加载到浮点寄存器时,浮点单元会引发异常。
QNaN 可通过名为的常量用于 Delphi 代码NaN
声明于Math
。该常数的定义是:
const
NaN = 0.0 / 0.0;
我希望能够使用类似的东西来声明一个信号 NaN 常量,但还没有找到一种方法来做到这一点。
天真地你可能会写这样的代码:
function SNaN: Double;
begin
PInt64(@Result)^ := $7FF7FFFFFFFFFFFF;//this bit pattern specifies an SNaN
end;
但是浮点返回值的 ABI 意味着将 SNaN 加载到浮点寄存器中以便可以返回它。自然,这会导致异常,从而违背了目的。
所以你会被引导编写这样的代码:
procedure SetToSNaN(out D: Double);
begin
PInt64(@D)^ := $7FF7FFFFFFFFFFFF;
end;
现在,这可行,但非常不方便。假设您需要将 SNaN 传递给另一个函数。理想情况下你想写:
Foo(SNaN)
但你必须这样做:
var
SNaN: Double;
....
SetToSNaN(SNaN);
Foo(SNaN);
那么,在建立之后,这是问题。
有什么办法可以写x := SNaN
并有浮点变量x
分配一个信号 NaN 值?
这个声明在编译时解决了这个问题:
const
iNaN : UInt64 = $7FF7FFFFFFFFFFFF;
var
SNaN : Double absolute iNaN;
编译器仍然会处理SNaN
作为常数。
尝试赋值给SNaN
会给出编译时错误:E2064 Left side cannot be assigned to
.
procedure DoSomething( var d : Double);
begin
d := 2.0;
end;
SNaN := 2.0; // <-- E2064 Left side cannot be assigned to
DoSomething( SNaN); // <--E2197 Constant object cannot be passed as var parameter
WriteLn(Math.IsNaN(SNaN)); // <-- Writes "true"
你应该有编译器指令吗$WRITEABLECONSTS ON
(or $J+
),这可以暂时关闭以确保不改变SNaN
.
{$IFOPT J+}
{$DEFINE UNDEFWRITEABLECONSTANTS}
{$J-}
{$ENDIF}
const
iNaN : UInt64 = $7FF7FFFFFFFFFFFF;
var
SNaN : Double ABSOLUTE iNaN;
{$IFDEF UNDEFWRITEABLECONSTANTS}
{$J+}
{$ENDIF}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)