44

I'm needing to create a random bool value in my game, in Swift.

It's basically, if Yes (or 1), spawn one object, if No (or 0), spawn the other.

So far, looking at this question and a similar one on here, I found this:

let randomSequenceNumber = Int(arc4random_uniform(2)) 

Now it works, but it seems bias to 0 to me... like ridiculously bias...

This is how I'm then using the value:

if(randomSequenceNumber == 0) //spawn object A else //spawn object B 

Is there a better way to implement this using a random bool value? That isn't bias to a certain value?

Update

Bit of an experiment to see how many 1's vs 0's were were generated in 10,000 calls:

func experiment() { var numbers: [Int] = [] var tester: Int = 0 var sum = 0 for i in 0...10000 { tester = Int(arc4random_uniform(2)) numbers.append(tester) print(i) } for number in numbers { sum += number } print("Total 1's: ", sum) } Test 1: Console Output: Total 1's: 4936 Test 2: Console Output: Total 1's: 4994 Test 3: Console Output: Total 1's: 4995 
7
  • I tried using that function in a playground by counting the number of zero and one results for 10,000 calls. I definitely don't see the bias you're experiencing. (More like +/- 1.2% either direction) Are there any other conditions in your app that could be influencing the result? Commented Dec 12, 2015 at 15:24
  • Really? Maybe it just seems bias then... maybe, it's not random enough (or evenly distributed enough) if you know what I mean :( Commented Dec 12, 2015 at 15:37
  • Try it! See if you get the same result in your environment. Commented Dec 12, 2015 at 15:42
  • 1
    what did you expect? let imagine that you have a function which gives you sequence true, false, true, false, ......... true and false will be 'perfectly' distributed, but unfortunately NOT randomly!! your test has no value to see, if arc4random_uniform is really good or not for your application. generally there is a lot of criteria, some of them could be very specific to the problem which should be solved. Commented Dec 12, 2015 at 19:16
  • 1
    i try to explain you, that even thought you run it 10000 times, you can not expect that you will receive 5000 true and 5000 false. what you want is probability of 50% in every single call of you function. Commented Dec 13, 2015 at 6:55

3 Answers 3

92

Xcode 10 with Swift 4.2

Looks like Apple  engineers are listening

let randomBool = Bool.random() 
Sign up to request clarification or add additional context in comments.

Comments

57
import Foundation func randomBool() -> Bool { return arc4random_uniform(2) == 0 } for i in 0...10 { print(randomBool()) } 

for more advanced generator the theory is available here

for basic understanding of Bernoulli (or binomial) distribution check here

4 Comments

This is nicer code for sure, so I've changed mine to let randomSequenceNumber = Int(arc4random_uniform(2)) == 0 ? true: false
up to you, creating an Int is not necessary at all ... the distribution is good enough for almost any application. if you are still not happy with it, check the theory from the link i provide for you
Oh I read somewhere it's good practice to cast to int to remove absolute bias-ness. Either way, definitely better way. I will indeed check that document. Thank you for posting.
The random result in for statement is NOT random, it's up to the time/mini-seconds.
17
extension Bool { static func random() -> Bool { return arc4random_uniform(2) == 0 } } // usage: Bool.random() 

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.