F#floor函数不能正确舍入?

时间:2017-10-25 20:31:49

标签: math f# floor

我有一个非常奇怪的问题。这是我简单的递归代码:

let float2cfrac x =
    let rec tofloat (lst : int list) (xi : float) =

        let qi = floor xi
        let ri = xi-qi

        printfn "%A %A %A %A" xi qi ri (1.0/ri)
        if ri > (floor 0.0) then          
            tofloat (lst @ [int qi]) (1.0/ri)
        else
            lst
    tofloat [] x

我不会解释我的代码太多,因为我所拥有的问题似乎很基本。 printfn将打印xi和qi,其中qi只是xi的底限。 在查看输出时,看起来一旦软件达到xi的舍入数字,floor函数就会删除1而不是什么都不做。

这是我的数字3.245的输出,它应该在几次计算后完成计算:

float2cfrac 3.245 ;;

3.245 3.0 0.245 4.081632653

4.081632653 4.0 0.08163265306 12.25

12.25 12.0 0.25 4.0

4.0 3.0 1.0 1.0 - 这里搞砸了。 4.0的楼层应该是4,对吧?

1.0 1.0 4.035882739e-12 2.477772682e + 11

2.477772682e + 11 2.477772682e + 11 0.2112731934 4.733208147

4.733208147 4.0 0.7332081468 1.363869188

如果有人对此或某些建议有解释,我们将不胜感激!

2 个答案:

答案 0 :(得分:7)

一个众所周知的问题:浮点数具有有限的精度,因此您通常不能依靠通过不同方法完成的相同计算来产生相同的结果。总会有误差。

必然结果是您无法比较浮点数以获得严格的相等性。你必须把他们的差异与一些非常小的数字进行比较。

答案 1 :(得分:1)

您可以通过不使用浮点数来避免浮点数的数值问题。这里有一个解决方案是将输入表示为有理数,即整数分子和整数分母,然后相应地调整公式。

open System.Numerics

let number2cfrac (xNumerator : int) (xDenominator : int) =
    let rec loop acc (xin : BigInteger) (xid : BigInteger) =
        let qi = xin / xid
        let rin = xin - (qi * xid)
        printfn "%A %A %A %A" (float xin / float xid) qi (float rin / float xid) (float xid / float rin)
        if rin <> BigInteger.Zero then        
            loop (int qi :: acc) xid rin
        else
            List.rev acc
    loop [] (BigInteger(xNumerator)) (BigInteger(xDenominator))

> number2cfrac 3245 1000;;
3.245 3 0.245 4.081632653
4.081632653 4 0.08163265306 12.25
12.25 12 0.25 4.0
4.0 4 0.0 infinity
val it : int list = [3; 4; 12]