JavaCast 慷慨地四舍五入
JavaCast float rounds generously
我计算总和并将它们放入我在 Coldfusion 中使用 POI 库生成的 Excel sheet。由于 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
returns一个字符串。我叫它只是为了比较。 POI 似乎存储浮点值,Excel 最终像 LSNumberFormat 那样显示该值。
如何将一个值传递给 setCellValue
,该值非常接近我的值,至少小数后的第二位数字被正确舍入?
简答:
使用 double 类型而不是 float,即 javacast("double", value)
更长的答案:
Cell.setCellValue() method actually expects type Double (not Float). Double is also what CF uses for most numeric operations and functions。当您将 Float 传递给这些方法时,它会隐式转换为 Double。该转换(间接)导致意外结果。
原因是两者Float and Double are approximate types。但是,Double 具有更高的精度:
float: The float data type is a single-precision 32-bit IEEE 754 floating point. ...
double: The double data type is a double-precision 64-bit IEEE 754 floating point. ...
因此 this thread 指出(强调我的):
It's not that you're actually getting extra precision - it's that the
float didn't accurately represent the number you were aiming for
originally. The double is representing the original float accurately;
toString is showing the "extra" data which was already present.
... [When converted to a double, it] will have exactly the same value, but when you convert it to a string it will "trust" that it's accurate to a higher precision, so won't round off as early, and you'll see the "extra digits" which were already there, but hidden from you
这就是为什么“601761.66”和“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
NB: CF 使用 Float.toString() 和 Double.ToString() 通过 cfoutput/writeOutput/cfdump.
显示值
我计算总和并将它们放入我在 Coldfusion 中使用 POI 库生成的 Excel sheet。由于 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
returns一个字符串。我叫它只是为了比较。 POI 似乎存储浮点值,Excel 最终像 LSNumberFormat 那样显示该值。
如何将一个值传递给 setCellValue
,该值非常接近我的值,至少小数后的第二位数字被正确舍入?
简答:
使用 double 类型而不是 float,即 javacast("double", value)
更长的答案:
Cell.setCellValue() method actually expects type Double (not Float). Double is also what CF uses for most numeric operations and functions。当您将 Float 传递给这些方法时,它会隐式转换为 Double。该转换(间接)导致意外结果。
原因是两者Float and Double are approximate types。但是,Double 具有更高的精度:
float: The float data type is a single-precision 32-bit IEEE 754 floating point. ...
double: The double data type is a double-precision 64-bit IEEE 754 floating point. ...
因此 this thread 指出(强调我的):
It's not that you're actually getting extra precision - it's that the float didn't accurately represent the number you were aiming for originally. The double is representing the original float accurately; toString is showing the "extra" data which was already present. ... [When converted to a double, it] will have exactly the same value, but when you convert it to a string it will "trust" that it's accurate to a higher precision, so won't round off as early, and you'll see the "extra digits" which were already there, but hidden from you
这就是为什么“601761.66”和“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
NB: CF 使用 Float.toString() 和 Double.ToString() 通过 cfoutput/writeOutput/cfdump.
显示值