F#+网络,使用System.Math.Floor函数计算错误 [英] F#+.Net, calculation error using the System.Math.Floor function

查看:127
本文介绍了F#+网络,使用System.Math.Floor函数计算错误的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这里有一个功能我写信给打印在F#中一个浮点数每个数字:

here's a function I wrote to print every digit of a float number in F#:

let rec TestFloor (fnum:float) =
    let floor = System.Math.Floor(fnum)
    printfn "fnum:%f floor:%f" fnum floor
    if floor > 0.0 then TestFloor((fnum - floor) * 10.0)

但无论如何,结果是陌生的,例如:

Anyway the result is strange, for example:

> TestFloor 1.23;;
fnum:1.230000 floor:1.000000
fnum:2.300000 floor:2.000000
**fnum:3.000000 floor:2.000000**
fnum:10.000000 floor:9.000000
fnum:10.000000 floor:9.000000
fnum:10.000000 floor:9.000000
fnum:10.000000 floor:9.000000
fnum:10.000000 floor:9.000000
fnum:10.000000 floor:9.000000
fnum:10.000000 floor:9.000000
fnum:10.000000 floor:9.000000
fnum:9.999998 floor:9.000000
fnum:9.999982 floor:9.000000
fnum:9.999822 floor:9.000000
...

在第四行的3.0楼原来是2.0这是奇怪。下面的计算都去错了。我不知道发生了什么呢?

At the fourth line the floor of 3.0 turned out to be 2.0 which is strange. The following computations are all going wrong. I'm wondering what's happening there?

谢谢!

编辑2

@ sepp2k

这是使用%.30f后的结果:

This is the result after using %.30f:

> TestFloor 1.23;;
fnum:1.230000000000000000000000000000 floor:1.000000000000000000000000000000
fnum:2.300000000000000000000000000000 floor:2.000000000000000000000000000000
**fnum:3.000000000000000000000000000000 floor:2.000000000000000000000000000000**
fnum:9.999999999999980000000000000000 floor:9.000000000000000000000000000000
fnum:9.999999999999820000000000000000 floor:9.000000000000000000000000000000
fnum:9.999999999998220000000000000000 floor:9.000000000000000000000000000000
fnum:9.999999999982240000000000000000 floor:9.000000000000000000000000000000
fnum:9.999999999822360000000000000000 floor:9.000000000000000000000000000000

正如你可以在第四行 FNUM 看到的是 3.00 ... 地板值为 2.00 ..

修改3 - 解决

感谢大家,现在我明白这个问题是关于什么的。

Thank you all, now I understand what the problem is about.

推荐答案

这只是你与浮点运算的四舍五入问题之一。你会发现其重新presentation是2.99999 ......可能无限重复。以printfn明确的调用此舍入到预期的重新presentation,但地板还是认为这是2.99999 ...

This is just one of those rounding issues you get with floating point arithmetic. You will find its representation is 2.99999... probably infinitely recurring. The call to printfn clearly rounds this up to the expected representation, but floor still sees this as 2.99999...

这是问题正是那种小数类型的存在来解决,因此,如果我们重写使用十进制,我们得到正确的结果:

This is exactly the sort of problem that the decimal type exists to solve, so if we rewrite to use decimal, we obtain the correct result:

let rec TestFloor dnum =
    let fl = floor dnum
    printfn "fnum:%f floor:%f" dnum fl
    if fl > 0.0M then TestFloor((dnum - fl) * 10.0M)

这给了:

> TestFloor 1.23M;;
fnum:1.230000 floor:1.000000
fnum:2.300000 floor:2.000000
fnum:3.000000 floor:3.000000
fnum:0.000000 floor:0.000000
val it : unit = ()

当然,你也可以使用float坚持,但增加了一个非常小的公差值,以确保这些角落案件总是一点点高于预期值,而不是只是一个小的下方,如:

Of course, you can stick with float, but add a very small tolerance value to ensure that these corner cases are always just a little above the expected value, rather than just a little below, eg:

let rec TestFloor fnum =
    let fl = floor (fnum + 0.00000000001)
    printfn "fnum:%f floor:%f" fnum fl
    if fl > 0.0 then TestFloor((fnum - fl) * 10.0)

其中给出了上述相同的结果。

Which gives the same result as above.

这篇关于F#+网络,使用System.Math.Floor函数计算错误的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆