- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我的一位同事发现 Delphi 编译的 Win32 和 Win64 代码在处理 NaN 的方式上存在差异。以下面的代码为例。当以 32 位编译时,我们没有收到任何消息,但当以 64 位编译时,我们得到两个比较都返回 true。
program TestNaNs;
{$APPTYPE CONSOLE}
{$R *.res}
uses
System.SysUtils,
System.Math;
var
nanDouble: Double;
zereDouble: Double;
nanSingle: Single;
zeroSingle: Single;
begin
SetExceptionMask(exAllArithmeticExceptions);
nanSingle := NaN;
zeroSingle := 0.0;
if nanSingle <> zeroSingle then
WriteLn('nanSingle <> zeroSingle');
nanDouble := NaN;
zereDouble := 0.0;
if nanDouble <> zereDouble then
WriteLn('nanDouble <> zeroDouble');
ReadLn;
end.
我对 IEEE 标准的理解是 <> 应该返回 true,但所有其他操作应该返回 false。所以在这种情况下,看起来 64 位版本是正确的,而 32 位版本是错误的。两者生成的代码与64位版本生成的SSE代码有很大不同。
对于 32 位:
TestNaNs.dpr.21: if nanSingle <> zeroSingle then
0041A552 D905E01E4200 fld dword ptr [$00421ee0]
0041A558 D81DE41E4200 fcomp dword ptr [$00421ee4]
0041A55E 9B wait
0041A55F DFE0 fstsw ax
0041A561 9E sahf
0041A562 7419 jz $0041a57d
对于 64 位:
TestNaNs.dpr.21: if nanSingle <> zeroSingle then
000000000042764E F3480F5A05C9ED0000 cvtss2sd xmm0,qword ptr [rel $0000edc9]
0000000000427657 F3480F5A0DC4ED0000 cvtss2sd xmm1,qword ptr [rel $0000edc4]
0000000000427660 660F2EC1 ucomisd xmm0,xmm1
0000000000427664 7A02 jp Project63 + $68
0000000000427666 7420 jz Project63 + $88
我的问题是这样的。这是 Delphi 编译器的问题还是 Intel CPU 的问题?
最佳答案
IEEE 754 标准定义了浮点计算的算术格式、运算、舍入规则、异常(exception)等。 Delphi 编译器在可用的硬件单元之上实现浮点运算。对于 32 位 Windows 编译器,这是 x87 单元,对于 64 位 Windows 编译器,这是 SSE 单元。这两个硬件单元均符合 IEEE 754 标准。
您观察到的差异出现在语言实现级别。让我们更详细地看看这两个版本。
比较语句编译为:
TestNaNs.dpr.19: if nanDouble <> zeroDouble then0041C4C8 DD05C03E4200 fld qword ptr [$00423ec0]0041C4CE DC1DC83E4200 fcomp qword ptr [$00423ec8]0041C4D4 9B wait 0041C4D5 DFE0 fstsw ax0041C4D7 9E sahf 0041C4D8 7419 jz $0041c4f3
英特尔软件开发人员手册指出,无序比较由标志 C3、C2 和 C0 设置为 1 表示。完整表格如下:
Condition C3 C2 C0ST(0) > Source 0 0 0ST(0) < Source 0 0 1ST(0) = Source 1 0 0Unordered 1 1 1
当您在调试器下检查 FPU 时,您可以看到情况就是如此。
0041C4D5 DFE0 fstsw ax0041C4D7 9E sahf 0041C4D8 7419 jz $0041c4f3
这会将 FPU 状态寄存器中的各个位传输到 CPU 标志中,有关标志所在位置的准确详细信息,请参阅手册。如果设置了 ZF,则会进行分支。 ZF 的值来自 C3 FPU 标志,从上表中读取,该标志是为无序情况设置的。
事实上,整个分支代码可以用伪代码表示为:
jump if C3 = 1
因此,查看上表,很明显,如果其中一个操作数是 NaN,则任何浮点相等比较都会计算为相等。
比较语句编译为:
TestNaNs.dpr.19: if nanDouble <> zeroDouble then0000000000428EB8 F20F100548E50000 movsd xmm0,qword ptr [rel $0000e548]0000000000428EC0 660F2E0548E50000 ucomisd xmm0,qword ptr [rel $0000e548]0000000000428EC8 7A02 jp TestNaNs + $5C0000000000428ECA 7420 jz TestNaNs + $7C
比较由ucomisd
指令执行。手册给出了这个伪代码:
RESULT ← UnorderedCompare(SRC1[63:0] <> SRC2[63:0]) {(* Set EFLAGS *)CASE (RESULT) OF GREATER_THAN: ZF, PF, CF ← 000; LESS_THAN: ZF, PF, CF ← 001; EQUAL: ZF, PF, CF ← 100; UNORDERED: ZF, PF, CF ← 111;ESAC;OF, AF, SF ← 0;
请注意,在此指令中,ZF、PF 和 CF 标志与 x87 单元上的 C3、C2 和 C0 标志完全相同。
分支由以下代码处理:
0000000000428EC8 7A02 jp TestNaNs + $5C0000000000428ECA 7420 jz TestNaNs + $7C
请注意,首先测试奇偶校验标志 PF(jp
指令),然后测试零标志 ZF(jz
指令)。因此,编译器发出了代码来处理无序情况(即操作数之一是 NaN)。这首先由 jp
处理。一旦处理完毕,编译器就会检查零标志 ZF,当且仅当两个操作数相等时才设置该标志(因为 NaN 已被处理)。
不同的行为是由于不同的编译器在如何实现比较运算符方面采取了不同的选择。在这两种情况下,硬件均符合 IEEE 754 标准,并且完全能够按照标准的规定比较 NaN。
我最好的猜测是,32 位编译器的决定是很久以前做出的。其中一些决定值得怀疑。在我看来,与 NaN 操作数的相等比较应该评估不等于,而不管其他操作数如何。通过保持向后兼容性的愿望感受到的历史的重量意味着这些有问题的决定从未得到解决。
最近,当 64 位编译器创建时,Embarcadero 工程师决定纠正其中一些错误。他们大概觉得突破新架构让他们可以自由地这样做。
在理想情况下,通过设置编译器开关,可以将 32 位编译器配置为与 64 位编译器具有相同的行为方式。
关于delphi - Win32 和 Win64 中 exAllArithmeticExceptions 的结果不一致,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46897007/
在项目属性窗口的应用程序选项卡和启动对象组合框中,我无法看到我的 win 表单以将其中一个设置为启动对象。 它出什么问题了? 最佳答案 开通 Program.cs启动项目的文件(在解决方案中选择为启动
我的问题是,当我得到正确的数字时,python 脚本结束,但不打印:你赢了! import random number = random.randint(1,100) # This part work
我使用 Eclipse 开发了一个 Java 应用程序。我使用的电脑操作系统是Win Vista。我在 Win XP 计算机上使用此应用程序时遇到问题。我发现的问题是: 如果在我的代码中我使用以下几行
显然,这将打印出石头/剪刀/布获胜或平局。 实现“石头胜剪刀——计算机胜!”这样的结果的最佳方式是什么?等等? var userChoice = prompt("Do you choose rock,
我正在开发一个使用HttpWebRequest将请求发送到另一台服务器的ASP.NET Web应用程序。它通过HTTPS发送请求,并且远程服务器需要客户端证书。该请求在.NET应用程序中失败,显然无法
我正在 WIn XP 上使用 VC6 开发应用程序。使用 GetKeyBoardLayoutList() 和 GetLocalInfo() API 从系统检索默认输入语言列表。 代码如下。 `UINT
我在 WPF 中创建了一个无边框窗口。我已经编写了一个事件来最大化窗口,但是在最大化时,部分窗口有时会隐藏在任务栏后面,片刻之后会出现在任务栏顶部。 如何确保窗口每次都保持在任务栏的顶部?以下是我实现
我开始制作 3d 游戏。然后我停了一段时间并安装了win7。现在我想继续研究它只是为了发现代码卡住了!在 XP 上,我将 View 渲染到窗体上。并且游戏循环和所有游戏形式都在同一个线程上运行! 这在
main() { int *p; free(p); } 此代码在 Win 2K 中崩溃。但不知何故不会在 Win Xp 中崩溃!知道为什么吗? 编辑:是的。这是一个错误,不应该被写入。更多
我在我的应用程序中使用 libeay32.dll/ssleay32.dll 库来支持 https。库在 Windows 7 上成功加载(不是通过我的应用程序,通过 Qt 库),但是我在 Windows
在源代码下方添加了新的详细信息。 有一个问题是 Delphi,其中 Internet 代码可在 Win 10 上运行,但不能在 Win 7 上运行。我正在尝试将一个小项目连接到 haveibeenpw
我在 Win 7 上为 Perfmon 创建了 xml 模板。我能够导入它并运行它 - 一切正常。现在,当我将此 xml 复制到 Win 2008 R2 计算机并尝试将其导入到 perfmon 中时,
我在使用标准数据驱动的 Winform 应用程序时遇到了一个有趣的问题。 该应用程序最初是在 Windows 7 和 Visual Studio 2010 上开发的。然后我用 Windows 8 和
我有一个在 Windows 7(64 位)上编写的程序,可以在我的计算机上正确编译和运行。 但在其他计算机上(特别是在 Windows 8(64 位)上)该程序无法运行。当我尝试运行它时,它说我的程序
将现有的基于 Vb6.0 win 的应用程序转换为基于 c# win 的应用程序的最快方法是什么? 最佳答案 核心语言如此不同,我不得不说从头开始,只复制复杂的代码位。如果您从头开始,您将不必处理所有
我正在处理 IE 11 在 Windows 8 和 Windows 8.1 上的奇怪行为。我正在固定定位元素内的元素位置。而且它变得很奇怪。当我用开发工具检查它时它在正确的位置,但在视觉上它完全在不同
将使用 Java x32 在 eclipse x32 上创建的项目导入到使用 java x64 的 eclipse x64 上有哪些挑战? 最佳答案 Java 是跨平台的,所以你应该不会有任何问题。
鉴于 l 是一个整数列表并且 win 是一个整数,下面的代码生成一个列表 lpadded: lpadded = win // 2 * [-1] + l + win // 2 * [-1] 在 lpad
我有一个适用于 Windows Phone 8.1 的应用程序及其 UWP 版本。我想在 Windows 中更改应用程序的背景时动态更改它。 用例是: 启动应用,背景主题为深色。 按下手机上的主页按钮
不完全确定我是否已经解决了这个问题,但这是我所看到的以及我认为正在发生的事情。 我有一个主要用 C 编写的 Win32 程序,它加载一个 C++ DLL。该 DLL 通过 COM 对象将数据从 C 程
我是一名优秀的程序员,十分优秀!