以下代码段是multiply-with-carry algorithm的直接翻译,可以在各个地方找到(我以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工具,操场上是否有明显的错误??
答案 0 :(得分:2)
导致此问题的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;
现在你得到了你希望的图表: