如何以可移植方式将浮点数精确舍入至指定位数(如6.375转6.37)
如何以可移植方式将浮点数6.375舍入为6.37?
通常大家询问如何将浮点数舍入至指定位数时,常见方案是使用FORMAT:
(format nil "~,2F" 6.376) ==> "6.38"
但要注意,在特定场景下,使用FORMAT进行舍入是依赖于实现的!
根据CLHS文档《22.3.3.1 Tilde F: 固定格式浮点数》中的说明:
当向上舍入和向下舍入产生的打印值与参数的缩放值距离相等时,实现可任选其一。例如,使用格式~4,2F打印参数6.375时,正确结果可为6.37或6.38。
此外,ffloor本身不支持直接对小数点后多位进行舍入。
解决方案
要以可移植方式实现将6.375显式舍入为6.37(即向负无穷方向截断到两位小数),可以通过「缩放数值→向下取整→还原量级」的思路实现:
- 将目标数乘以10的指定小数次幂,把需要保留的小数位转化为整数位(比如两位小数就乘100)
- 使用
ffloor对放大后的数值执行向负无穷方向的取整操作(该行为是标准化的,无实现差异) - 将结果除以之前的缩放倍数,还原到原量级
对应的Lisp代码实现:
(defun floor-to-decimals (num decimals) (let ((scale (expt 10 decimals))) (/ (ffloor (* num scale)) scale))) ;; 调用示例 (floor-to-decimals 6.375 2) ==> 6.37
该方法完全依赖Common Lisp标准定义的行为,可在所有符合标准的实现中得到一致结果。如果需要字符串形式的输出,只需在得到确定数值后再用FORMAT格式化即可,此时不会再出现舍入歧义。
内容的提问来源于stack exchange,提问作者Jérôme Radix
相关产品推荐
相关产品推荐

