Search code examples
linuxswiftserver-side-swift

Swift Linux Generate Random Bool


I am trying to make a static extension of Bool to return a random true/false value whenever called. I am trying to make this work:

static func coinFlip() -> Bool {
    #if os(Linux)
    srand(UInt32(time(nil)))
    let result = Int(random() % 2)
    if result == 0 {
        return false
    } else {
        return true
    }
    #else
    return arc4random_uniform(2) == 0
    #endif
}

I am using this within the scope of a route being called in a Server Side Swift application. Whenever it is called for the first time, it does return a random value, but all subsequent calls to the function in the same scope don't randomize the output. For example:

for _ in 1...5 {
    let coin = Bool.coinFlip()
    if coin == true {
        print("coin flip true")
    } else {
        print("coin flip false")
    }
}

...yields an output of this:

coin flip false
coin flip false
coin flip false
coin flip false
coin flip false

...but then if I call the route again separately, I could get:

coin flip true
coin flip true
coin flip true
coin flip true
coin flip true

Is it a problem with srand(UInt32(time(nil))) only randomizing the pseudo-random sequence of random()? I'm not sure what to do. Thanks in advance for your help!


Solution

  • time(nil)) returns the current time as a number of seconds, which means that you seed the random number generator with the same value when the method is called multiple times within a one second interval.

    You should call srand(UInt32(time(nil))) only once on application startup, not on each call of coinFlip().

    In addition, the function can be simplified a bit, and I would call it random(), not coinFlip():

    #if os(Linux)
        srand(UInt32(time(nil)))
    #endif
    
    extension Bool {
        static func random() -> Bool {
            #if os(Linux)
                return Glibc.random() % 2 == 0
            #else
                return arc4random_uniform(2) == 0
            #endif
        }
    }
    
    for _ in 1...5 {
        print(Bool.random())
    }