显然F#/ BCL浮点错误

Tea*_*Dev 2 .net f# base-class-library

以下是FSI:

> System.Math.Round(0.2916, 2);;
val it : float = 0.29
> it * 100.;;
val it : float = 29.0
> int it;;
val it : int = 28
Run Code Online (Sandbox Code Playgroud)

结果与我尝试的任何地方相同 - 编译的F#3.1/.NET 4.0应用程序,Visual Studio 2013和2015中的FSI,.NET Fiddle,@ fsibot ....

当然这是某个地方的错误,不是吗?这里发生了什么?

Tom*_*cek 5

这就是浮点数的工作原理.输出中显示为29的数字实际上略小于29(因为浮点数不精确):

> (System.Math.Round(0.2916, 2) * 100.0) - 29.0;;
val it : float = -3.552713679e-15
Run Code Online (Sandbox Code Playgroud)

  • 值得一提的是,当读取/写入磁盘作为字符串浮动时,很容易因精度损失而烧毁..NET支持浮点数的往返格式化,因此转换为人类可读字符并解析回位的位将产生完全相同的位.请参阅Round Trip("R")格式说明符,此处:https://msdn.microsoft.com/en-us/library/dwhawy9k(v = vs1010).aspx (2认同)

Jak*_*rtz 5

float是二进制浮点数据类型.并非所有十进制浮点值都可以精确表示为二进制浮点.29实际上FSI显示的是什么28.999999999999996.

如果要存储精确的十进制浮点值,请使用decimal数据类型(以制作数字decimal而不是float添加m到数字 - 例如0.2916m).

> System.Math.Round(0.2916m, 2);;
val it : decimal = 0.29M
> it * 100m;;
val it : decimal = 29.00M
> int it;;
val it : int = 29
Run Code Online (Sandbox Code Playgroud)


Fun*_*l_S 5

你可以改变像Matlab这样的F#FSI漂亮打印机"格式长"

fsi.AddPrinter( fun (x:float) -> sprintf "%26.16e" x);;
Run Code Online (Sandbox Code Playgroud)

FSI输出

System.Math.Round( 0.2916, 2)   //  2.8999999999999998e-001

1./3.                           // 3.3333333333333331e-001
Run Code Online (Sandbox Code Playgroud)