Swift 中的进位乘法

Multiply-with-carry in Swift

以下代码片段直接翻译multiply-with-carry algorithm which can be found in various places (I took this one作为参考。

public class MultiplyWithCarryRandomGenerator
{

 struct Static {
    static var m_w:UInt = 521748629
    static var m_z:UInt = 762436069
 }

 class var m_w:UInt{get{return Static.m_w } set{Static.m_w = newValue}};
 class var m_z:UInt{get{return Static.m_z } set{Static.m_z = newValue}};

 private class func GetUint()->UInt
 {
    m_z = 36969 * (m_z & 65535) + (m_z >> 16);
    m_w = 18000 * (m_w & 65535) + (m_w >> 16);
    return (m_z << 16) + m_w;
 }

 public class func GetUniform()->Double
 {
    return   ((Double(GetUint()) + 1.0) * 2.32830643545449e-10);
 }
}

在 XCode 游乐场内,均匀分布保持在 0 到 40K 之间,而它应该在区间 (0,1) 内。 我的代码中是否存在明显错误或 iOS、游乐场...的人工产物?

C#(该示例的语言)和 Swift 之间有两个差异导致了此问题。第一个是 C# uint 是一个 32 位无符号整数,而 Swift 中的 UInt 是一个与它正在执行的系统体系结构匹配的无符号整数,这意味着今天大多数情况下 UInt 是 64 位无符号整数。由于代码中的所有常量都面向 32 位,只需将所有 UInt 声明更改为 UInt32 即可完成一半。

第二个区别是,在 C# 中使用无符号整数时,加法运算会自动溢出,而在 Swift 中,溢出会崩溃。您还没有看到问题,因为您使用的是具有 64 位数据类型的 32 位常量,但是在切换到 UInt32 之后,您将开始在这一行溢出时崩溃:

return (m_z << 16) + m_w;

Swift 提供了一组备用运算符,以 & 为前缀,它默默地允许溢出——在该行中使用 &+ 解决了问题:

return (m_z << 16) &+ m_w;

现在你得到了你想要的图表: