0
点赞
收藏
分享

微信扫一扫

dnan的好处2


恕我直言,这是更好的方法,甚至不是​​异常​​​,而是​​错误​​​.
只要你有​​​NaN​​​值,程序就是​​无用和损坏​​​的.
只要​​​变量​​​变为​​NaN​​​,就应该抛它,而不仅是在操作时.
如下成立时它应该抛:
1,初化值为​​​NaN​​​并在操作中使用
2,在初化外,置值为​​​NaN​​​ 3,从函数返回​​NaN​​ 这解决所有问题,因为:
你永远不会在​​整个​​程序中传播​​NaN​​值,从而​​更易​​追踪它.
​NaN​​严格告诉你,在使用​​某些值​​前,是错误的
无法​​有效​​地解决它,即你​​必须​​实际修复所有​​NaN​​.

D允许使用​​std.math.hardware.FloatingPointControl​​​接口启用​​浮点异常​​​.
当然,这些是​​​硬件​​​异常,因此你获得​​SIGFPE​​​而不是带​​回溯的抛错误​​​.要转换为D错误,需要安装​​信号​​​处理器,就像​​etc.linux.memoryerror​​​那样(或​​Windows​​上的等价物)

可惜,似乎在实践中不管用,因为仅在创建​​NaN​​​时,而不是在​​传播​​​时触发​​"无效"​​​浮点异常.由于是在​​编译时​​​而不是运行时创建默认初化​​float/double​​​变量的初始​​NaN​​​值,因此不会​​触发异常​​​.
示例:

import std.math.hardware;

float div(float x, float y)
{
return x / y;
}

void main()
{
FloatingPointControl fpctrl;
fpctrl.enableExceptions(FloatingPointControl.severeExceptions);

float f = float.nan; // ok -无异常
float g = div(0.0f, 0.0f); // SIGFPE崩溃.
}

​NaN​​​总是错误的.​​0.0​​​无处不在.如果从不​​查看输出​​​,则都不会​​注意​​​到​​其中错误​​​.
你需要分析数据流.我没有把​​​DFA​​​放在前端,因为这会使它​​变慢​​​而无好处.
不必害怕在​​​输出​​​中获得​​NaN​​​.相反应该​​很高兴​​​,因为你​​*知道*​​​有​​错误​​​.
D是帮助程序员创建​​​正确,健壮和无错误​​​程序的工具.
​​​检查整​​

你正在推广使用​​结构初值​​​作为​​特征​​​,而不是​​基本类型的初值​​​.
​​​不同​​​在它必须为​​有意​​​设置的​​字段​​​值,并且仅针对​​该字段值​​​.它不是​​默认值​​.

double compute_pop ()
{
double pop;
// 忽略实现,偶遇nan
pop = sqrt (-1.);
pop += 0.;
return pop;
}

int main ()
{
auto pop = compute_pop ();
if (pop < .5)
writeln ("不下雨");
else
writeln ("会下雨");
return 0;
}

前几天我玩​​isNaN​​​.用它来检查​​访问函数​​​中的​​初化​​​,来缓存​​昂贵计算​​​.在注意到​​发布版本​​​出现​​故障​​​前,这非常有效.过了一段时间,我才发现​​ldc​​​为发布版本,提供了​​fastmath​​​选项,它假定没有​​NaN​​​,而这导致​​isNaN​​​错误工作.
示例:

import std;
void main()
{
assert(isNaN(double.nan));
}

用​​--ffast-math -O​​​选项结合​​ldc​​​编译.
​​​isnan​​实现:

bool isNaN(X)(X x) @nogc @trusted pure nothrow
if (isFloatingPoint!(X))
{
version (all)
{
return x != x;
}
else
{
/*
历史背景保存的代码.至少在英特尔,简单的测试`x!=x`使用一条在一条指令中运行循环的`(ucomiss/ucomisd)`专用指令.`80`位和`128`位的代码更大,但仍小于下面基于整数的方法
*/
// 略...
}
}

这不仅与​​Walter​​​的理解相悖,而且与​​IEEE754​​​标准相悖.这是一篇​​更详细​​​文章:​​小心快速数学​​​ 具有快速数学的​​LLVM​​假定所有​​浮点​​操作数都是​​有限​​的,即可在​​编译时​​优化​​x!=x​​为​​false​​.足够​​聪明​​的​​优化器​​,如果识别出​​NaN​​的位模式,原则上可优化​​检查位模式​​.

​UDA​​​等的​​好处​​​之一是,可用它们来选择​​LLVM​​​可执行的​​特定优化​​​,而无需选择​​明显危险​​​的优化.
​​​1​​​,​​2​​​,​​3​​​​不要滥用异常​​​​0<=NaN​​.确实,有时0是相等的.但它​​*不可能*​​更好.
顺便,​​十六进制​​数据没有​​NaN​​值.但经常初化它为:​​0xDEADBEEF​​ 这在​​野外​​不太可能.因此,当转储​​十六进制​​数据且有​​DEADBEEF​​时,表明有​​未初化​​数据.
我既用它在返回给调用者前,初化​​malloc​​的数据,并为其设置​​释放​​后数据.它在清理​​未初化​​的​​分配数据​​和​​释放后使用​​错误方面​​非常有效​​.使用​​0x00​​远没有它有效.


举报

相关推荐

0 条评论