Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/fsharp/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
.net F#和#x2B;。Net,使用System.Math.Floor函数计算错误_.net_F# - Fatal编程技术网

.net F#和#x2B;。Net,使用System.Math.Floor函数计算错误

.net F#和#x2B;。Net,使用System.Math.Floor函数计算错误,.net,f#,.net,F#,下面是我编写的一个函数,用于打印F#中浮点数的每个数字: 无论如何,结果是奇怪的,例如: > 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 fn

下面是我编写的一个函数,用于打印F#中浮点数的每个数字:

无论如何,结果是奇怪的,例如:

> 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,这很奇怪。下面的计算都出错了。我想知道那里发生了什么事

谢谢


编辑2

@sepp2k

这是使用%.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…
,而
floor
值是
2.00…


编辑3-已解决


谢谢大家,现在我明白了问题所在。

大概
fnum
的值类似于
2。999999999999999
printfn
在显示时将其四舍五入为3.0。尝试使用
%.30f
而不是
%f

来增加显示的位数
fnum
的值大概是
2.999999999999999
printfn
在显示时将其四舍五入为3.0。尝试使用
%.30f
而不是
%f

来增加显示的位数。这只是浮点运算中的舍入问题之一。你会发现它的表示是2.99999。。。可能无限重复。对printfn的调用显然将这一点归纳为预期的表示,但floor仍然认为这是2.99999

这正是decimal类型要解决的问题,因此,如果我们重写为使用decimal,我们将获得正确的结果:

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,但要添加一个非常小的公差值,以确保这些转角情况始终略高于预期值,而不是略低于预期值,例如:

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)

这与上面给出的结果相同。

这只是浮点运算中的舍入问题之一。你会发现它的表示是2.99999。。。可能无限重复。对printfn的调用显然将这一点归纳为预期的表示,但floor仍然认为这是2.99999

这正是decimal类型要解决的问题,因此,如果我们重写为使用decimal,我们将获得正确的结果:

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,但要添加一个非常小的公差值,以确保这些转角情况始终略高于预期值,而不是略低于预期值,例如:

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)

它给出了与上面相同的结果。

即使你得到了3.00000。。。在最大十进制精度下,可能仍然存在舍入。别忘了值是以二进制存储的,打印时总是需要四舍五入(从二进制到十进制)。 答案是,虽然您的值打印为3.0000…,但实际上小于3。增加更多的小数位数并不能解决这个问题

考虑以下代码:

> let num = 3.0 - 2.**(-51.);;
> printfn "%.30f" num;;
3.000000000000000000000000000000
> floor num;;
val it : float = 2.0

即使你得到30万。。。在最大十进制精度下,可能仍然存在舍入。别忘了值是以二进制存储的,打印时总是需要四舍五入(从二进制到十进制)。 答案是,虽然您的值打印为3.0000…,但实际上小于3。增加更多的小数位数并不能解决这个问题

考虑以下代码:

> let num = 3.0 - 2.**(-51.);;
> printfn "%.30f" num;;
3.000000000000000000000000000000
> floor num;;
val it : float = 2.0

好的,下面是使用%.30f:>TestFloor 1.23;得到的结果;;fnum:123000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000。。。如您所见,当fnum=3.00…,地板为2.00…。@Eric.By:然后尝试更多数字。好的,下面是使用%.30f:>TestFloor 1.23;;得到的结果;;fnum:123000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000。。。正如你所看到的,当fnum=3.00…,地板是2.00…。@Eric.By:然后尝试更多的数字。谢谢Chris,现在我明白了怎么做和为什么了!谢谢克里斯,现在我明白了怎么做,为什么了!