首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >fmod fmod返回c++ (0.0,1.0)的NaN

fmod fmod返回c++ (0.0,1.0)的NaN
EN

Stack Overflow用户
提问于 2016-06-03 21:00:01
回答 2查看 419关注 0票数 1

我遇到了一个非常奇怪的情况:在我正在开发的一个多线程应用程序中,在某个代码点,fmod(x,y)返回-1.#IND00,而double x = 0.0double y = 1.0返回。当然,我仔细检查了xy的值。更奇怪的是,如果我在f=fmod(x,y);行之前添加一个虚拟测试代码行f=fmod(0.0,1.0);,那么fmod(x,y)会像预期的那样返回0.0

该应用程序是使用多线程Runtime库构建的。(VS2005)原因可能是什么?

编辑1:经过几个小时的进一步研究,我发现它与FPU状态寄存器有关。当零除异常标志被设置时,它返回-1.#IND00,否则返回正确的0.0值。我还是不知道这是怎么回事。我的代码并没有扰乱FPU状态寄存器,但它是关于一个插件的,所以我无法控制插件主机正在做什么。但是,即使设置了零分频异常标志,为什么这里的fmod denom值= 1.0会有所不同。这是fmod实现中的一个bug吗?有人听说过这样的bug吗?这快把我逼疯了。

编辑2:我非常确定这是VS2005中CRT lib的64位fmod实现中的一个错误。当FPU状态寄存器DivByZero标志在调用fmod时已经被触发时,这会产生错误的结果。我很乐意通过一些测试代码100%地证明这一点,但我不能用VS2005做x64的内联汇编,以便用FPU强制除以0,这将设置该标志,然后我将调用fmod。

EN

回答 2

Stack Overflow用户

发布于 2016-06-04 18:26:04

我可以确认这是VS2005 CRT64位fmod实现中的一个错误。这很容易重复:确保FPU中的DivByZero标志在调用z=fmod(x,y)之前被触发,其中x=0.0和y=1.0,然后z将为NaN,这当然是错误的。

因此,这与多线程无关,也与内存损坏无关。这只是CRT库中一个错误。

我使用VirtualAlloc做了一个小测试应用程序,以便具有一些可执行内存,我将代码字节放在其中,以便在FPU中执行除以0操作,从而提升FPU DivByZero标志。(VS2005不能内联64位汇编代码,因此出现了exe ram技巧)然后我执行了上面提到的fmod函数调用,实际上z显示为-1.#IND00 = NaN。在调试器中仔细检查所有步骤。QED。

我很惊讶,我在www上找不到任何关于CRT bug的东西。我是第一个发现这个CRT错误的人吗?

不管怎么说,问题已经回答了。结论:我将使用fmod的另一个实现。

PS:如果有人想要重复测试,下面是我用来在x86中强制提升DivByZero标志的代码字节:

代码语言:javascript
复制
0xD9,0xEE = fldz
0xD9,0xE8 = fld1
0xD8,0xF1 = fdiv ST(0),ST(1)
0xDD,0xD8 = fstp ST(0) = pop stack
0xDD,0xD8 = fstp ST(0) = pop stack
0xC3 = ret
票数 3
EN

Stack Overflow用户

发布于 2016-06-03 21:20:05

如果使用常量参数,则该值很可能是由编译器硬编码的。所以这段代码实际上并不调用fmod:

代码语言:javascript
复制
f=fmod(0.0,1.0);

取而代之的是分配一个常量浮点值。这就解释了为什么你的虚线会计算出正确的结果。标准/数学库似乎有问题。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/37615096

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档