Smalltalk中rounded函数原理及千分位舍入异常问题咨询
Smalltalk中rounded函数原理及千分位舍入问题解析
一、rounded函数的工作原理
rounded方法用于将数值四舍五入到最近的整数,核心实现逻辑如下:
rounded "Answer an Integer nearest to receiver" ^(self + (self sign * 0.5)) truncated
具体执行步骤:
- 通过
self sign获取当前数值的符号:正数返回1,负数返回-1,0返回0 - 用符号值乘以0.5,得到与原数同符号的偏移量(0.5或-0.5)
- 将原数加上该偏移量后,调用
truncated方法截断小数部分(向零取整),最终得到最接近原数的整数
示例:
- 正数1.4:
1.4 + 0.5 = 1.9,truncated后得到1 - 正数1.6:
1.6 + 0.5 = 2.1,truncated后得到2 - 负数-1.4:
-1.4 + (-0.5) = -1.9,truncated后得到-1 - 负数-1.6:
-1.6 + (-0.5) = -2.1,truncated后得到-2
二、将小数舍入到千分位(3位小数)的方法
常规实现方式
先将数值放大1000倍,调用rounded取整后再缩小1000倍:
roundedToThreeDecimals ^(self * 1000) rounded / 1000
若环境支持,也可直接使用roundTo:方法指定精度:
self roundTo: 0.001
三、测试异常情况分析
相关代码片段
调用者方法
cbPrintPercentageString ^AbtpercentageConverter new primObjectToPrint: self
被调用者方法
primObjectToPrint: anInput ^(super primObjectToPrint: anInput*100), '%'
测试案例
- 输入1:
anInput: 0.014545(Float类型)
计算:0.014545 * 100 = 1.4545,舍入到3位小数后输出1.455%,符合预期 - 输入2:
anInput: 0.018045(Float类型)
计算:0.018045 * 100 = 1.8045,预期舍入结果为1.805%,但实际输出1.804%
异常原因
问题源于Float类型的精度限制:十进制小数0.018045无法被二进制浮点数精确表示,实际存储的数值略小于理论值1.8045(如1.804499999999999...),舍入时被判定为小于1.8045,最终得到1.804。
解决方法
- 改用Decimal类型:Decimal可精确表示十进制小数,避免二进制浮点数的精度误差
- 精度修正:若必须使用Float,可在舍入前添加极小偏移量(如1e-8)修正精度,但需谨慎使用,避免引入新误差
内容的提问来源于stack exchange,提问作者lahari chinthapula
相关产品推荐
相关产品推荐

