我正在为一种基于 LLVM 的小型编程语言编写数学函数,我目前对如何实现常见的舍入函数 floor、ceil 和 round(甚至)感到困惑。首先是因为我还没有找到这些函数的任何算法描述,其次是因为我不熟悉 LLVM 具有哪些功能。四舍五入。
能够正确舍入负数是必须的,而不是舍入到特定精度。四舍五入到整数值就可以了。简单地指出可以从 LLVM 位码中使用的任何现有实现也将起作用。
我正在为一种基于 LLVM 的小型编程语言编写数学函数,我目前对如何实现常见的舍入函数 floor、ceil 和 round(甚至)感到困惑。首先是因为我还没有找到这些函数的任何算法描述,其次是因为我不熟悉 LLVM 具有哪些功能。四舍五入。
能够正确舍入负数是必须的,而不是舍入到特定精度。四舍五入到整数值就可以了。简单地指出可以从 LLVM 位码中使用的任何现有实现也将起作用。
您将要从LLVM 语言参考手册开始。
您可以从按照这些思路实现trunc( )
类似的东西开始(警告,实际上不要使用它;它只是作为示例,并不正确。请参阅下面的讨论):
define float @trunc(float %x) {
%rounded = fptosi float %x to i32
%asFloat = sitofp i32 %rounded to float
ret float %asFloat
}
该fptosi ... to ...
指令被记录为根据舍入到零舍入模式将浮点值舍入为整数值。该sitofp ... to ...
指令将该值转换回要返回的浮点值。
但是,这种实现存在问题;阅读我链接到的语言参考,“fptosi ... to ...
如果舍入到最接近的整数的结果不能适合目标类型,则行为未定义。”
不过,这很容易解决,因为所有足够大的浮点数都已经是整数,不需要四舍五入;如果 的绝对值x
大于或等于 2^23,则可以只返回 x 本身。
(这都是单精度;对于双精度,您可能想要使用i64
,并且您需要使用 2^52 的阈值)
对于其他操作,如floor
和round
,您可以从 开始trunc
,然后检查残差x - trunc(x)
并相应地调整结果。
或者,您可以调用您的主机平台的 C 库,其中已经包含这些函数。这是许多编程语言采用的方法。
如果您查看 Google 代码搜索,会有一些结果。链接示例假定 IEEE 浮点数。通常,普通 PC 的编译器只是编译floor
为浮点指令。例如,最初的 387 算术处理器具有FPREM
或多或少地完成您需要的部分的指令floor
。
我通过以下方式为浮点向量实现了下限:“截断”值 x,然后比较 x 和 trunc(x)。如果 trunc(x)>x,则减 1,因为 floor(x) 必须始终最多为 x。我已经在 Haskell 中对此进行了编码。我不知道,这是否对你有帮助。请参阅http://code.haskell.org/~thielema/llvm-extra/src/LLVM/Extra/Vector.hs中的 floorLogical
舍入到偶数通常很昂贵,而且没有多大用处。我只是使用地板(x + 0.5)。SSE4.1中还有roundss、roundps等。