尽管有尾调用位置但仅在 64 位中发生堆栈溢出 [英] Stack overflow despite tail call position but only in 64-bit

查看:21
本文介绍了尽管有尾调用位置但仅在 64 位中发生堆栈溢出的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

源自这个问题,我有这个小小的 F# 代码(​​github) 根据正态分布生成随机值:

Originated from this question, I have this little F# code (github) to generate random values according to a normal distribution:

// val nextSingle : (unit -> float32)
let nextSingle =
    let r = System.Random()
    r.NextDouble >> float32

// val gauss : (float32 -> float32 -> seq<float32>)
let gauss mean stdDev =
    let rec gauss ready = seq {
        match ready with
        | Some spare ->
            yield spare * stdDev + mean
            yield! gauss None
        | _ ->
            let rec loop () =
                let u = nextSingle() * 2.f - 1.f
                let v = nextSingle() * 2.f - 1.f
                let s = pown u 2 + pown v 2
                if s >= 1.f || s = 0.f then loop() else
                u, v, s
            let u, v, s = loop()
            let mul = (*)(sqrt(-2.f * log s / s))
            yield mul u * stdDev + mean
            yield! mul v |> Some |> gauss
    }
    gauss None

对我来说,这似乎应该只在尾调用位置调用自身,因此在启用 TCO 时永远不会导致 StackOverflowException.但在运行 64 位确实.它在运行 32 位(即项目设置中的首选 32 位"复选框)时不会.

To me it seems that this should only call itself in tail call position, ergo never cause a StackOverflowException when TCO is enabled. But it does when running 64-bit. It does not when running 32-bit (i.e. "Prefer 32-bit" checkbox in project settings).

我使用的是 .NET Framework 4.5.2 和 F# 4.4.0.0.

I'm using .NET Framework 4.5.2 and F# 4.4.0.0.

有人可以解释导致问题的原因吗?

Can somebody explain what is causing the problem?

推荐答案

看起来像是编译器的序列表达式编译机制中的错误.这是一个简化的重现:

Looks like a bug in the compiler's sequence expression compilation mechanism. Here's a simplified repro:

let rec loop r = seq {
    if r > 0 then
        let rec unused() = unused()
        yield r
        yield! loop r
}

printfn "%i" (Seq.nth 10000000 (loop 1))

显然,未使用的递归定义的存在不应该影响这是否会产生堆栈溢出,但确实如此.

Obviously the presence of the unused recursive definition shouldn't affect whether this generates a stack overflow, but it does.

这篇关于尽管有尾调用位置但仅在 64 位中发生堆栈溢出的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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