2015-03-23 6 views

ответ

3

Сумма может быть удобно, вычисленной с 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)) } 

Если вам нужен массив Bool и сумму:

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

Update: Как Zaph предлагается ниже, следует использовать все 32 бита из в 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() подсчитывает количество установленных битов и является перевод https://stackoverflow.com/a/109025/1187415 Свифта:

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) 
} 

(Смотрите также Rikkle's answer , который был отправлен в то же время ...)

+0

Остается одна проблема, 10 000 звонков в arc4random_uniform за короткое время вполне могут подавить возможности генерации криптографически случайных чисел. Просто использование arc4random() и использование всех 32-бит поможет избежать этой потенциальной проблемы, уменьшив количество вызовов в 32 раза. – zaph

+1

@ Zaph: спасибо за отзыв, я попытался реализовать ваше предложение. На сумму 10 000 случайных бит это сокращает время от 8 мс до 0,3 мс на моем компьютере. Использование arc4random_buf, предложенное Риккле в его ответе, может быть даже быстрее. –

2

Если вам не нужно, чтобы сохранить booleand

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) 
    } 
} 
+1

Не используйте 'случайным образом()' это не случайно, вместо этого использовать 'arc4random()' или в данном случае 'arc4random_uniform (2) '. Кроме того, 'random()' без семени будет повторять каждую привязку, в которой запускается программа. – zaph

+0

Спасибо, вы правы ... Отредактировано – Miknash

+0

забыли удалить его, arc4random) uniform (n) создаст случайное число в диапазоне от 0 до n-1. Еще раз спасибо – Miknash

1

arc4random_uniform() возвратит равномерно распределенное случайное число меньше, чем верхняя граница.

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)") 
2

Я предложил бы использовать arc4random_buf на число 10000/8 байт, то, применяя боковое дополнение (или «Хэмминга Вес»), чтобы суммировать все биты в этой последовательности байтов, один междунар (32 бита) за раз. См. https://stackoverflow.com/a/109025/1401029 для хорошего псевдокода Хэмминга.

Это должно быть значительно быстрее и чище, чем любая конструкция цикла, которая включает в себя случайную функцию внутри него.

+0

После прочтения вашего ответа я также предположил, что вызов arc4random_buf() один раз (в буфере размером 10 000/8) быстрее, чем вызов arc4random() 10 000/32 раза. Я сделал простой бенчмарк сейчас и интересно, оказалось, что практически нет разницы в сроках. –

+0

Интересно! Таким образом, версия буфера mosty проходит через int32-версию. Тем не менее, оба они, вероятно, намного быстрее, чем arc4random_uniform(), чтобы получить значение 0/1 на каждом бите. – Rikkles

+0

О, я только что видел ваш комментарий выше, который сокращает время на 25x между битом и словом. Хорошо :) – Rikkles

0

Если вам не нужны фактические булевы, сумма имеет биномиальное распределение с N=10000 и p=1/2. Для этого большого N это в значительной степени неотличимо от гауссова со средним значением N*p и дисперсией N*p*(1-p) (что соответствует стандартным отклонениям 50), округленным до ближайшего целого. Вы можете создавать стандартные нормалей с помощью метода Бокса-Мюллера, и масштаб следующим образом:

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 
Смежные вопросы