我计算总和并将其放入我在 Coldfusion 中使用 POI 库生成的 Excel 工作表中。由于 Java 库需要类型化的变量,我总是称之为setCellValue( JavaCast( "float", myVar ) )
。我被.03
意识到了一个舍入错误。比通常知道的铸造后漂浮的差异要大得多。
<cfset s = 601761.66>
<cfoutput>
#s#<br>
#JavaCast( "float", s )#<br>
#LSNumberFormat( JavaCast( "float", s ), ".0000000" )#<br><br>
</cfoutput>
- 第一行打印
601761.66
- 第二轮
601761.7
- 然而,第三个打印:
601761,6875000
等于601761,69
并且比我输入的值大.03
。
我知道,LSNumberFormat
返回一个字符串。我叫它只是为了比较。POI似乎存储浮点值,Excel最终像LSNumberFormat一样显示该值。
如何将一个值传递给setCellValue
,该值与我的值非常接近,以至于至少十进制后的第二个数字被正确舍入?
简短回答:
使用双精度类型而不是浮点型,即javacast("double", value)
更长的答案:
Cell.setCellValue() 方法实际上需要 Double 类型(不是 Float)。Double 也是 CF 用于大多数数值运算和函数的。将 Float 传递到这些方法中时,它会隐式转换为 Double。该转换(间接)导致意外结果。
原因是浮点型和双精度型都是近似类型。但是,Double 具有更高的精度:
float:float数据类型是单精度32位IEEE 754浮点数。
双精度:双精度数据类型是双精度64位IEEE 754浮点数。
所以正如这个线程指出的(强调我的):
这就是为什么"601761.66">这并不是说你实际上获得了额外的精度 - 而是 浮点数没有准确代表您的目标数字 原来。双精度准确表示原始浮点数; toString 显示已经存在的"额外"数据。 ...[当转换为双精度时,它]将具有完全相同的值,但是当您将其转换为字符串时,它将"相信"它精确到更高的精度,因此不会尽早四舍五入,并且您将看到已经存在的"额外数字",但对您隐藏
和"601761.6875"在转换为浮点数时似乎四舍五入为"601761.7",但在转换为双精度时显示预期。
<cfscript>
value1 = "601761.66";
value2 = "601761.6875";
WriteOutput("<br>[Float] "& value1 &" = "& javacast("float", value1));
WriteOutput("<br>[Float] "& value2 &" = "& javacast("float", value2));
WriteOutput("<br>[Float=>Double] "& value1 &" = "& javacast("double", javacast("float", value1)));
WriteOutput("<br>[Double] "& value1 &" = "& javacast("double", value1));
WriteOutput("<br>[Double] "& value2 &" = "& javacast("double", value2));
</cfscript>
输出:
[Float] 601761.66 = 601761.7
[Float] 601761.6875 = 601761.7
[Float=>Double] 601761.66 = 601761.6875
[Double] 601761.66 = 601761.66
[Double] 601761.6875 = 601761.6875
注意:CF 使用 Float.toString() 和 Double.ToString() 通过 cfoutput/writeOutput/cfdump 显示值。