浮点数

lua-users home
wiki

简介

偶尔,Lua 邮件列表上会有人问类似这样的问题:“在整数应用中使用浮点运算是否可以?” 本讨论旨在消除这些疑虑,但不会误解实际存在的问题。

浮点数作为 Lua 中唯一的数值类型,主要问题在于 **大多数程序员不理解浮点数**。浮点数比整数(定点数)复杂得多。大多数程序员对浮点数的认知模型是,运算结果有时会存在非常小的误差。因此,人们会感到不安。但这种认知模型是错误的;将浮点运算建模为“正确答案 + 噪声”是错误的,尤其是在处理最常见的浮点类型 IEEE-754 时。

解决这个问题的方案是教育。在文档、网站、常见问题解答、维基百科等中,应该更多地强调双精度浮点数的基本整数向后兼容行为。

在继续之前,需要注意的是,尽管浮点数通常用作 Lua 中的数值类型,但 Lua 并不依赖于浮点数,而是可以编译成任何数值类型,例如单精度浮点数、整数,甚至一些非常不熟悉的数值表示[*5]。当然,例如除法的语义在使用整数数值类型编译 Lua 时会发生显著变化,但在嵌入式处理器上,这可能不会让人感到意外。[*1] ARM、Coldfire 和各种嵌入式 MIPS 版本都没有 FPU,但它们被 _非常_ 广泛使用。[*2]

精度

如果您有一台正常、现代(2000 年)的台式电脑,那么您拥有 IEEE 754 双精度浮点数。[*4]

以下是关于 (IEEE 754) 64 位双精度浮点数 (“double”) 与 32 位整数的一些要点

总结:从精度、范围和“向后兼容性”的角度来看,64 位精度浮点运算优于 32 位整数运算。不过请参阅注意事项部分。

算术运算

IEEE 754 标准定义了基本的数学运算,包括 + - * (乘法) / (除法),以产生尽可能接近精确数学答案的结果。特别是,如果答案可以精确地表示为双精度浮点数,那么该结果就是答案;否则,有两个最接近精确答案的双精度浮点数(一个略高于,一个略低于),根据舍入模式选择其中一个。

对于涉及整数的运算,大多数运算都是精确的。如果我计算 2+5,那么因为精确的数学答案是 7,这也是 IEEE 754 的答案。

性能

大型 CPU

关于性能,大多数现代台式机 CPU 现在可以像整数一样快或更快地处理双精度浮点数。这包括现代 MIPS R5000 和现代 PPC 700 及更高版本。常见的 FPU 操作的吞吐量为一个时钟周期。加减比较乘法。(更好的是,乘加指令可能只在 FPU 中实现一个时钟周期的吞吐量,使其比 ALU 中的整数乘加更快。多标量架构和 SIMD 可以进一步提高浮点数性能。但这可能与 Lua 无关。)通常,浮点数乘法比整数乘法更快(因为浮点数乘法使用得更频繁,CPU 设计人员在优化该路径方面投入了更多精力)。浮点数除法可能很慢(通常超过 10 个周期),但整数除法也是如此。

诚然,英特尔的奔腾设计排名第三(因为它只有很少的 FP 寄存器)。但英特尔正在迎头赶上。

唯一剩下的性能问题是浮点数到整数的转换。无论你是否喜欢,内存加载指令都使用地址和字节偏移量(即两个整数值)进行操作。因此,如果 CPU 的浮点数到整数转换性能很差,使用浮点数而不是整数的任何性能优势都将付诸东流。一些说法指出,浮点数到整数的转换会对性能产生毁灭性的影响 [1]。(对于 gcc-3.4 和大约 2006 年的 AMD 处理器,这个问题已经不存在,但请自行测试。从该链接编译基准测试很容易。)

内存

对于使用这些现代高端台式机 CPU 的用户来说,唯一剩下的主要潜在问题是内存带宽和内存使用。由于 Lua 中这些对象的单元(联合结构)大小,这些考虑实际上是无关紧要的。

关于这一点的硬数据会很好,例如在各种(或一种)架构下配置单精度和双精度浮点数的适当联合的 sizeof()

-- 在 8 字节结构对齐的世界中,它们实际上并不占用更多空间,但是如果由于 FP 数字的大小,对象结构的大小超过 64 位,那么大小问题就变得非常重要。FP 数字在 CPU 缓存中也占用更多空间 - 不仅仅是寄存器会受到影响。 -- ChuckAdams

小型 CPU

有一些用户使用的是旧的、更小的或嵌入式 CPU,它们没有浮点数、没有 64 位浮点数、CPU 模拟浮点数或硬件浮点数速度很慢。这些包括 80386、68040、ARM 等。希望 luaconfig.h 功能可以满足他们的需求。

总结:大约在 2001 年,您平均入门级的 10 美元 CPU 芯片能够以与整数运算一样快和一样精确的速度(甚至更快)计算 64 位双精度数。使用这些 CPU 的用户在 Lua 中仅使用双精度浮点数不会付出任何代价,并且可能会获得好处。使用较小芯片的用户可能被迫在 Lua 中仅使用整数运算。

-- 正如下面所述,大多数 ARM 芯片(最广泛使用的嵌入式 CPU 之一)没有硬件浮点支持。这意味着每次在 int 和 float 之间的转换,以及每次算术运算,都是一个函数调用(通常是内联的)。双精度数更糟糕。当您考虑对 NaN 和非规格化数字的检查时,与整数相比,开销相当大(是的,我已经分析过)。--BenStJohn?

虽然 Lua 的数字类型可以构建为整数,但在使用之前建议进行分析,因为(即使在仅整数的处理器上)速度提升可能不像想象的那么大,而丢失浮点数可能会使某些操作变得更加复杂。还要注意 Lua 5.3 内置了显式整数支持。

eLua http://www.eluaproject.net/ 是 Lua 的一个分支,用于一些微控制器,它有一个可选的整数构建。但是,需要注意的是,标准 Lua 也非常容易在 ARM7TDMI 等内核上构建 - 因为源代码是标准 C。如果需要,可以应用整数更改。

注意事项

您的里程可能会有所不同。示例原因

参考资料

这些没有特别的顺序

-- MartinHollis(原作者)

脚注/评论


最近更改 · 偏好设置
编辑 · 历史记录
最后编辑于 2017 年 11 月 2 日下午 11:58 GMT (差异)