Math 冷融圆函数

Math 冷融圆函数,math,coldfusion,rounding,Math,Coldfusion,Rounding,今天,我在ColdFusion 9,10,11圆形函数中遇到了意外行为或缺乏知识。下面是我的场景 轮数(28.5)-->预期结果为29次 四舍五入(0.285*100)--->结果为28,不符合要求 四舍五入(precisionEvaluate(0.285*100))-->使用precisionEvaluate的结果是29 四舍五入(评估(0.285*100))-->使用评估结果为29 这不是大小数,为什么我需要使用precisionEvaluate或对数字求值? 在进一步的研究中,我发现了更有

今天,我在ColdFusion 9,10,11圆形函数中遇到了意外行为或缺乏知识。下面是我的场景

轮数(28.5)-->预期结果为29次
四舍五入(0.285*100)--->结果为28,不符合要求
四舍五入(precisionEvaluate(0.285*100))-->使用precisionEvaluate的结果是29
四舍五入(评估(0.285*100))-->使用评估结果为29
这不是大小数,为什么我需要使用precisionEvaluate或对数字求值?

在进一步的研究中,我发现了更有趣的行为
四舍五入(0.285*100)结果是28——为什么?我期待着29——
四舍五入(0.295*100)结果为30----正确
四舍五入(0.275*100)结果为28----正确
四舍五入(0.185*100)结果为19----正确
四舍五入(0.385*100)结果是39----正确


0.285*100有什么大不了的?不是小数的精度,而是底层浮点在Java中的存储方式。这表明:

<cfoutput>
<cfloop array="#[0.275,0.285,0.295]#" index="s">
#s.getClass().getName()#
<cfset f1 = s + 0>
#f1.getClass().getName()#
#f1.toString()#
<cfset f2 = f1*100>
#f2.toString()#
#round(f2)#<br>
</cfloop>
</cfoutput>

#s、 getClass().getName()#
#f1.getClass().getName()#
#f1.toString()#
#f2.toString()#
#圆形(f2)#
输出:

java.lang.String java.lang.Double 0.275 27.500000000000004 28

java.lang.String java.lang.Double 0.285 28.49999999996 28

java.lang.String java.lang.Double 0.295 29.5 30

我只能假设,在执行
时,在引擎盖下,CF在从字符串转换为浮点时使用了更好的精度,因为这里没有不可靠的舍入。然而,在执行乘法步骤之后,我们得到了一个精度错误。28.5最终只差28.5,所以将轮数改为28而不是29。这只是一个二进制分数的算术问题


顺便说一句,0.285没有什么特别的。许多数字都受到类似的影响(看看0.005到5.05之间的范围)。您恰好选择了一组不存在的(0.285除外)。

precisionEvaluate()用于“修复”该问题,这表明该问题是隐式浮点问题。CF将十进制数从非类型特定变量转换为浮点,然后再转换为浮点,从而导致与该操作相关的不精确性。这是无类型语言的缺点。@MarkAKruger感谢您的及时回复,我完全理解非类型变量的问题。为什么不使用圆(0.385*100)和仅使用圆(0.285*100)的圆(0.185*100)!我不确定,这也让我抓伤了头——但在引擎盖下,缺乏精确性可能与数字的大小有关——数字越小,可能性越大。这是我的猜测,如果我完全错了,我也不会感到惊讶(哈)。但我很有信心精度仍然是个问题。0.1425*1000的四舍五入怎么样?它正好是0.285的一半,因此在浮点表示法中应该有相同的尾数啊,我在cflive.net上试过了,它运行正常。然而,0.145*100也被破坏了。这与CFML是松散类型无关,@MarkAKruger。这只是二进制需要如何处理分数,以及分数的算术如何放大误差。这与其说是一个实际的意外问题,不如说是一个CFML隐藏的问题。@Adam,我感谢你花时间和精力来解释这一点。如果是二元分数算术问题,你不认为这应该得到解决吗?我所做的唯一变通方法是使用precisionEvaluate。我的客户是金融机构,每一分钱都很重要。我通过余额报告发现这个问题,我正在比较不同后端之间的值。我会用NetIt来测试这个,这不是CF的问题,只是“东西是如何工作的”。
27.500000000000004
值是这些操作的Java结果;CF只是报告Java告诉它的内容。问题更多的是CF隐藏了它,所以当事情似乎出了“问题”时,它会让人感到“惊讶”。浮点运算本质上是不准确的,二进制分数更是如此。把它们放在一起。。。嗯:你看你得到了什么。(编辑)浮点运算本质上是不准确的。。这就是为什么。如果需要这种精度,则必须使用更精确的类型,如
BigDecimal
,正如您所发现的,
PrecisionEvaulate()
为您提供了这种类型。请注意不要将precisionEvatate()的结果与任何其他运算符混合,即
+-/*
,否则CF将再次隐式将其转换回Double。