如何批量随机化布尔值

How to randomize booleans in bulk

我想随机化纯 swift 中的 10,000 个布尔值,然后得到所有为真值的总和。

如果你不需要保存你的布尔值

var sum = 0
for i in 1...10000{
   if(arc4random_uniform(2) == 1)
      sum++
}

如果你确实想保存它们

var sum = 0
var boolArrays = []
for i in 1...10000{
   if(arc4random_uniform(2) == 1){
      sum++
      boolArray.addObject(true)
   }
   else{
       boolArray.addObject(false)
   }
}

可以使用reduce()函数方便地计算总和:

/// Return the result of repeatedly calling `combine` with an
/// accumulated value initialized to `initial` and each element of
/// `sequence`, in turn.
func reduce<S : SequenceType, U>(sequence: S, initial: U, combine: (U, S.Generator.Element) -> U) -> U

如果您只对总和感兴趣:

let sum = reduce(0 ..< 10000, 0) { (sum, _) in sum + Int(arc4random_uniform(2)) }

如果需要布尔数组和求和:

let bools = map (0 ..< 10000) { _ in arc4random_uniform(2) == 1 }
let sum = reduce(bools, 0) { [=12=] + Int() }

更新: 正如 Zaph 在下面建议的那样,应该利用来自 arc4random... 函数减少函数调用次数。这将是

let numberOfInt32 = 10000 / 32
let remainingBits = 10000 % 32

let sum = reduce(0 ..< numberOfInt32, 0) { (sum, _) in sum + NumberOfSetBits(arc4random()) }
    + NumberOfSetBits(arc4random_uniform(UInt32(1 << remainingBits)))

其中NumberOfSetBits()计算设置位的数量并且是 到 Swift 的翻译:

func NumberOfSetBits(var i : UInt32) -> Int {
    i = i - ((i >> 1) & 0x55555555)
    i = (i & 0x33333333) + ((i >> 2) & 0x33333333)
    return Int((((i + (i >> 4)) & 0x0F0F0F0F) &* 0x01010101) >> 24)
}

(另见 同时发布...)

arc4random_uniform() will return a uniformly distributed random number less than upper_bound.

var countTrue : Int = 0
var countFalse : Int = 0
for i in 1 ... 10000 {
    if (arc4random_uniform(2) == 1) {
         countTrue++
    } else {
         countFalse++
    }
}

NSLog("count true: \(countTrue), count false: \(countFalse)")

我建议在 10,000/8 个字节上使用 arc4random_buf,然后应用横向加法(或 "Hamming Weight")来总结该系列字节中的所有位,一个 int (32 位)一次。有关汉明权重的良好伪代码,请参阅 。

这应该比任何包含随机函数的循环结构更快更清晰。

如果您不需要实际的布尔值,总和服从 N=10000p=1/2 的二项分布。对于那么大的 N,它与平均值为 N*p 且方差为 N*p*(1-p)(对应于标准差 50)的高斯几乎没有区别,四舍五入到最接近的整数。可以使用Box-Muller方法生成标准法线,缩放比例如下:

import Cocoa

let uniform_denom = UInt32(RAND_MAX) + 1

func u0_1() -> Double {
  var num = arc4random_uniform(uniform_denom)
  return Double(num) / Double(uniform_denom)
}

func gaussian() -> (Double, Double) {
  var d = sqrt(-2.0 * log(u0_1()))
  var theta = 2.0 * M_PI * u0_1()
  return (d * cos(theta), d * sin(theta))  // 2-tuple of std normals
}

var sum = 5000 + Int(round(50.0 * gaussian().0))  // scale to mean = 5000, std-dev = 50