问题标签 [x87]
For questions regarding programming in ECMAScript (JavaScript/JS) and its various dialects/implementations (excluding ActionScript). Note JavaScript is NOT the same as Java! Please include all relevant tags on your question; e.g., [node.js], [jquery], [json], [reactjs], [angular], [ember.js], [vue.js], [typescript], [svelte], etc.
floating-point - 80 位扩展精度数据类型的应用/好处是什么?
是的,我的意思是说80-bit。那不是笔误...
我在浮点变量方面的经验总是涉及 4 字节的倍数,比如单数(32 位)、双数(64 位)和长双数(我曾见过它被称为 96 位或 128 位)。这就是为什么当我在编写一些代码以读取和写入AIFF(音频交换文件格式)文件时遇到80 位扩展精度数据类型时有点困惑:选择了扩展精度变量来存储采样音轨的速率。
当我浏览 Wikipedia 时,我发现上面的链接以及IEEE 754-1985 标准摘要中的 80 位格式的简要说明(但不在IEEE 754-2008 标准摘要中)。似乎在某些架构上“扩展”和“长双”是同义词。
我没有遇到的一件事是使用扩展精度数据类型的特定应用程序(当然,AIFF 文件采样率除外)。这让我想知道:
- 有没有人遇到过扩展精度对于某些编程应用程序是必要/有益的情况?
- 80 位浮点数的好处是什么,除了明显的“它比 double 精度高一点,但比 long double 的大多数实现少字节”?
- 它的适用性正在减弱吗?
x86 - x87 相对于 SSE 的优势
我知道 x87 具有更高的内部精度,这可能是人们看到的它与 SSE 操作之间的最大区别。但我不得不怀疑,使用 x87 还有其他好处吗?我有-mfpmath=sse
在任何项目中自动输入的习惯,我想知道我是否遗漏了 x87 FPU 提供的任何其他内容。
c++ - 信号 NaN 的用处?
我最近阅读了大量有关 IEEE 754 和 x87 架构的内容。我正在考虑在我正在处理的一些数字计算代码中使用 NaN 作为“缺失值”,我希望使用信号NaN 可以让我在我不想的情况下捕获浮点异常继续“缺失值”。相反,我会使用安静的 NaN 来允许“缺失值”通过计算传播。但是,信号 NaN 不起作用,因为我认为它们会基于它们上存在的(非常有限的)文档。
这是我所知道的摘要(所有这些都使用 x87 和 VC++):
- _EM_INVALID(IEEE“无效”异常)控制 x87 在遇到 NaN 时的行为
- 如果 _EM_INVALID 被屏蔽(异常被禁用),则不会生成异常并且操作可以返回安静的 NaN。涉及信号 NaN 的操作不会导致抛出异常,但会转换为安静的 NaN。
- 如果 _EM_INVALID 未屏蔽(启用异常),则无效操作(例如 sqrt(-1))会导致抛出无效异常。
- x87从不生成信号 NaN。
- 如果 _EM_INVALID 未屏蔽,则任何使用信号 NaN(甚至用它初始化变量)都会导致抛出无效异常。
标准库提供了一种访问 NaN 值的方法:
和
问题是我认为信号 NaN 没有任何用处。如果 _EM_INVALID 被屏蔽,它的行为与安静的 NaN 完全相同。由于没有 NaN 可与任何其他 NaN 进行比较,因此没有逻辑差异。
如果 _EM_INVALID未被屏蔽(启用了异常),则甚至无法使用信号 NaN 初始化变量:
double dVal = std::numeric_limits<double>::signaling_NaN();
因为这会引发异常(信号 NaN 值被加载到 x87 寄存器中以将其存储到内存地址)。
您可能会像我一样认为以下内容:
- 掩码 _EM_INVALID。
- 用信号 NaN 初始化变量。
- Unmask_EM_INVALID。
但是,步骤 2 会导致信号 NaN 转换为安静的 NaN,因此后续使用它不会导致抛出异常!所以WTF?!
信号 NaN 是否有任何用途或目的?我知道最初的意图之一是用它初始化内存,以便可以捕获使用未初始化的浮点值。
有人可以告诉我我是否在这里遗漏了什么吗?
编辑:
为了进一步说明我希望做的事情,这里有一个例子:
考虑对数据向量(双精度数)执行数学运算。对于某些操作,我希望允许向量包含“缺失值”(假设这对应于电子表格列,例如,其中一些单元格没有值,但它们的存在很重要)。对于某些操作,我不想让向量包含“缺失值”。如果集合中存在“缺失值”,也许我想采取不同的行动——也许执行不同的操作(因此这不是处于无效状态)。
这个原始代码看起来像这样:
请注意,每次循环迭代都必须执行“缺失值”检查。虽然我理解在大多数情况下,sqrt
函数(或任何其他数学运算)可能会掩盖此检查,在某些情况下操作最少(可能只是加法)并且检查成本很高。更不用说“缺失值”会使合法的输入值失效,并且如果计算合法地到达该值(尽管它可能不太可能)可能会导致错误。此外,为了在技术上正确,用户输入数据应根据该值进行检查,并应采取适当的措施。我发现这个解决方案不优雅并且在性能方面不太理想。这是对性能至关重要的代码,我们绝对没有并行数据结构或某种数据元素对象的奢侈。
NaN 版本如下所示:
现在消除了显式检查,应该提高性能。我认为如果我可以在不接触 FPU 寄存器的情况下初始化向量,这一切都会奏效......
此外,我会想象sqrt
对 NaN 进行任何自尊的实施检查并立即返回 NaN。
delphi - System.Move 中的内存损坏由于更改了 8087CW 模式 (png + stretchblt)
我有一个奇怪的内存损坏问题。经过几个小时的调试和尝试,我想我找到了一些东西。
例如:我做了一个简单的字符串赋值:
但是,结果有时会变成:
因此,_ 被一个 0 字节替换。
我在 System.Move 函数中看到过这种情况发生过一次(复制很棘手,取决于时间),当时它使用 FPU 堆栈(fild,fistp)进行快速内存复制(如果要移动 9 到 32 个字节):
使用 FPU 视图和 2 个内存调试视图(Delphi -> View -> Debug -> CPU -> Memory)我看到它出错了......曾经......但是无法重现......
今天早上我读到了一些关于 8087CW 模式的内容,是的,如果将其更改为 $27FI,则会导致内存损坏!通常是 $133F:
$133F 和 $027F 之间的区别在于 $027F 将 FPU 设置为执行不太精确的计算(限制为 Double 而不是 Extended)和不同的 infiniti 处理(用于较旧的 FPU,但不再使用)。
好的,现在我找到了原因,但没有找到时间!
我通过一个简单的检查改变了我的AsmProfiler的工作(所以在进入和离开时检查所有功能):
我“分析”了一些单元和 dll 和宾果游戏(见堆栈):
所以它发生在 StretchBlt...
现在做什么?是 Windows 的错误,还是 PNG 中的错误(包含在 D2007 中)?或者 System.Move 函数不是故障安全的?
注意:简单地尝试重现是行不通的:
它似乎更具异国情调......但是通过'Get8087CW = $27F'上的debugbreak,我可以在另一个字符串上重现它:FPU part 1: FPU part 2: FPU part 3: FPU Final:损坏!:
注意 2:也许 FPU 堆栈必须在 System.Move 中清除?
floating-point - x87 中的扩展(80 位)双浮点,而不是 SSE2 - 我们不会错过吗?
我今天正在阅读有关研究人员发现 NVidia 的 Phys-X 库使用 x87 FP 与 SSE2的文章。显然,这对于速度胜过精度的并行数据集来说不是最理想的。但是,文章作者继续引用:
英特尔在 2000 年底推出 P4 后开始不鼓励使用 x87。自 2003 年 K8 以来,AMD 弃用了 x87,因为 x86-64 是在 SSE2 支持下定义的;威盛的 C7 自 2005 年起就支持 SSE2。在 64 位版本的 Windows 中,x87 在用户模式下被弃用,在内核模式下完全被禁止。自 2005 年以来,业内几乎所有人都推荐 SSE 而不是 x87,并且没有理由使用 x87,除非软件必须在嵌入式 Pentium 或 486 上运行。
我想知道这一点。我知道 x87 在内部使用 80 位扩展双精度来计算值,而 SSE2 没有。这对任何人都没有关系吗?这对我来说似乎很奇怪。我知道当我对平面中的点、线和多边形进行计算时,在进行减法时值可能会出乎意料地错误,并且由于缺乏精度,区域可能会塌陷并且线会相互混叠。我想,使用 80 位值与 64 位值会有所帮助。
这是不正确的吗?如果没有,如果 x87 被淘汰,我们可以使用什么来执行扩展的双 FP 操作?
assembly - 我应该使用哪些指令进行浮点运算?
我对在 x86 汇编中处理浮点数的x87 指令有些熟悉。然而,我在某处读到这些已经很少使用了。(并且不允许在 64 位 Windows 驱动程序中使用)[ 1 ]
如果是这种情况,我应该使用什么说明?我看到了一些关于 SSE 的东西,但除非我弄错了,否则这些指令是最近添加的,并且不会在旧芯片上可用。(如 Pentium II 等)
我应该使用哪些说明?
assembly - 为什么这个简单的程序会输出这么多字符?
这是我的简短汇编程序:
该程序应该做的是打印 5.5,但它会打印:
-4101885043414705786563701568963176764603483495211119243453355953219830430011006780068899468997203661787555969981250050126586203424320244681571103387315766489883301796219461838644670607029711305942610787622864198879363376953745160639821663444829839767678538571371627347101810056161000273217639447052410683392.000000
我到底做错了什么?代码将两个参数推送到printf()
然后调用它。没什么复杂的。
更新:我认为我已经解决了这个问题还为时过早。我已经更新了代码。
assembly - 从 FPU 堆栈中删除某些内容的最简单方法
我最近在 FPU 堆栈溢出方面遇到了一些麻烦。我设法将其追溯到一个有缺陷的库函数,该函数每次调用时都会将垃圾值推送到 FPU 堆栈上,并且从不清理它。
幸运的是,这很容易重现,我确切地知道是什么条件造成的。我可以将一个内联 ASM 块放入调用该例程的例程中,以将顶部值从 FPU 堆栈中弹出……除非我不太清楚该写什么。我的 ASM-fu 还算中规中矩,但没那么强。
那么,假设它是垃圾数据并且我不关心该值,那么在 x86 程序集中摆脱 FPU 堆栈上的最高值的最简单方法是什么?
floating-point - 找到接近浮点数之间的“离散”差异
假设我有两个浮点数x
和y
,它们的值非常接近。
在计算机上可以表示离散数量的浮点数,因此我们可以按升序枚举它们:f_1, f_2, f_3, ...
. 我希望在此列表中找到 和 的距离x
(y
即它们是 1、2、3,... 还是n
离散的步长?)
+-*/
是否可以仅使用算术运算( )而不查看二进制表示来做到这一点?我主要对它在 x86 上的工作方式感兴趣。
下面的近似值是否正确,假设那个y > x
和那个x
和y
只有几个步骤(比如,< 100)相隔?(可能不是 ...)
这里eps
表示机器 epsilon。(机器 epsilon 是 1.0 和下一个最小浮点数之间的差。)
c - 如何使用内联汇编指定立即浮点数?
当我尝试编译此代码时:
我收到此错误:
为什么这不起作用?为什么我不能将数字“150”压入堆栈以进行浮点运算?