如何使信号NaN容易使用? [英] How can I make signaling NaNs easy to work with?
问题描述
QNaN通过名为<$ c $的常量可用于Delphi代码在 Math
中声明的c> NaN 。该常量的定义是:
const
NaN = 0.0 / 0.0;
我想要使用类似的东西来声明一个常数,这是一个信号NaN,但是还没有找到一种办法。
你可以写这段代码:
函数SNaN:Double;
begin
PInt64(@Result)^:= $ 7FF7FFFFFFFFFFFF; //这个位模式指定一个SNaN
end;
但ABI的浮点返回值意味着SNaN加载到浮点寄存器,以便它可以返回。当然,这导致了一个例外,而不是打破目的。
所以,你可以这样编写代码:
程序SetToSNaN(out D:Double);
begin
PInt64(@D)^:= $ 7FF7FFFFFFFFFFFF;
结束
现在,这是有效的,但这是非常不方便的。假设您需要将SNaN传递给另一个功能。理想情况下,您想写:
Foo(SNaN)
,而您必须这样做:
var
SNaN:双
....
SetToSNaN(SNaN);
Foo(SNaN);
所以,建立之后,这里是问题。
有没有办法写入 x:= SNaN
并将浮点变量 x
一个值是一个信号NaN?
此声明在编译时解决:
const
iNaN:UInt64 = $ 7FF7FFFFFFFFFFFF;
var
SNaN:Double absolute iNaN;
编译器仍将 SNaN
视为
尝试将值分配给 SNaN
会给出编译时错误: E2064左侧无法分配给
。
程序DoSomething(var d:Double);
begin
d:= 2.0;
结束
SNaN:= 2.0; // < - E2064左侧不能分配给
DoSomething(SNaN); //< - E2197常量对象不能作为var参数
WriteLn(Math.IsNaN(SNaN))传递; //< - 写true
如果您有编译器指令 $ WRITEABLECONSTS ON
(或 $ J +
),这可以暂时关闭,以确保不会更改 SNaN
{$ IFOPT J +}
{$ DEFINE UNDEFWRITEABLECONSTANTS}
{$ J - }
{$ ENDIF}
const
iNaN:UInt64 = $ 7FF7FFFFFFFFFFFF;
var
SNaN:Double ABSOLUTE iNaN;
{$ IFDEF UNDEFWRITEABLECONSTANTS}
{$ J +}
{$ ENDIF}
The IEEE754 standard defines two classes of NaN, the quiet NaN, QNaN, and the signaling NaN, SNaN. When an SNaN is loaded into a floating point register, an exception is raised by the floating point unit.
QNaN is available to Delphi code through the constant named NaN
that is declared in Math
. The definition of that constant is:
const
NaN = 0.0 / 0.0;
I would like to be able to use something similar to declare a constant that is a signaling NaN, but have not yet found a way to do that.
Naively you might write this code:
function SNaN: Double;
begin
PInt64(@Result)^ := $7FF7FFFFFFFFFFFF;//this bit pattern specifies an SNaN
end;
But the ABI for floating point return values means that the SNaN is loaded into a floating point register so that it can be returned. Naturally that leads to an exception which rather defeats the purpose.
So you are then led to writing code like this:
procedure SetToSNaN(out D: Double);
begin
PInt64(@D)^ := $7FF7FFFFFFFFFFFF;
end;
Now, this works, but it's very inconvenient. Suppose you need to pass an SNaN to another function. Ideally you would like to write:
Foo(SNaN)
but instead you have to do this:
var
SNaN: Double;
....
SetToSNaN(SNaN);
Foo(SNaN);
So, after the build-up, here's the question.
Is there any way to write x := SNaN
and have the floating point variable x
assigned a value that is a signaling NaN?
This declaration solves it at compile time:
const
iNaN : UInt64 = $7FF7FFFFFFFFFFFF;
var
SNaN : Double absolute iNaN;
The compiler still treats the SNaN
as a constant.
Trying to assign a value to SNaN
will give a compile time error: 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"
Should you have the compiler directive $WRITEABLECONSTS ON
(or $J+
), this could be turned off temporarily to ensure not altering SNaN
.
{$IFOPT J+}
{$DEFINE UNDEFWRITEABLECONSTANTS}
{$J-}
{$ENDIF}
const
iNaN : UInt64 = $7FF7FFFFFFFFFFFF;
var
SNaN : Double ABSOLUTE iNaN;
{$IFDEF UNDEFWRITEABLECONSTANTS}
{$J+}
{$ENDIF}
这篇关于如何使信号NaN容易使用?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!