13

I'm working with Swift in Ubuntu, and I am getting an error that arc4random is an unresolved identifier. More information on this known bug here. Basically, the function only exists in BSD distros. I've tried module mapping header files, apt-getting packages, and I get more and more errors, which is not worth pursuing since this one function is not used very often.

Are there any functions to get pseudo random numbers with an upper-bound parameter that is compatible with Swift in Linux?

Tyress
  • 3,573
  • 2
  • 22
  • 45
  • 2
    What does *"do the same thing"* mean? As you noticed, arc4random is not available on Ubuntu (unless you install the libbsd package). There are other functions for generating (pseudo) random numbers, but they are not "the same" as arc4random. – Martin R Dec 08 '16 at 09:35
  • @MartinR edited my question. I wanted to go for a function that did something like arc4random_uniform(max), but I guess the modulo bias is not that important for my use – Tyress Dec 09 '16 at 01:43
  • Possible duplicate of [Generating random numbers with Swift](https://stackoverflow.com/questions/32552336/generating-random-numbers-with-swift) – jww Nov 05 '17 at 15:35
  • @jww the arc4random Linux bug as I linked to in my question is still not resolved at the moment. The other question doesn't seem to mention anything that will workaround this issue. – Tyress Nov 07 '17 at 06:12

4 Answers4

11

Swift 4.2

let random = Int.random(in: 0...100)

https://developer.apple.com/documentation/swift/int/2995648-random

PS. It works in Linux.

Serhii Didanov
  • 2,200
  • 1
  • 16
  • 31
6

I went with something like this for 4-digit random numbers:

#if os(Linux)
 srandom(UInt32(time(nil)))
 randomString = String(format: "%04d", UInt32(random() % 10000))
#else
 randomString = String(format: "%04d", Int(arc4random_uniform(10000)))
#endif

Edit: Note that the call to srandom(UInt32(time(nil))) should be outside a function/loop, otherwise it will produce the same value over and over again

Tyress
  • 3,573
  • 2
  • 22
  • 45
  • 1
    Note that by using 9999 the maximum random number returned by `arc4random_uniform` would be 9998. You should use `arc4random_uniform(10000)` – Leo Dabus Nov 05 '17 at 14:52
  • The code above has a bias, and the distribution is not uniform. – jww Nov 05 '17 at 15:17
  • @jww As I wrote in my comment 1 year ago to MartinR, the modulo bias isn't important for my use. However if you can provide a better answer that would probably be helpful for other people, feel free to write one! – Tyress Nov 07 '17 at 06:21
5

If generating a random number within a function, using srandom(UInt32(time(nil))) inside the function can produce the same random number every time.

Instead, prepare the random seed at the top of your main.swift once, and then random should behave as expected throughout.

Example:

//
//  main.swift
//  Top of your code
//

import Foundation

#if os(Linux)
    srandom(UInt32(time(nil)))
#endif


func getRandomNum(_ min: Int, _ max: Int) -> Int {
    #if os(Linux)
        return Int(random() % max) + min
    #else
        return Int(arc4random_uniform(UInt32(max)) + UInt32(min))
    #endif
}

// Print random numbers between 1 and 10
print(getRandomNum(1, 10))
print(getRandomNum(1, 10))
print(getRandomNum(1, 10))
print(getRandomNum(1, 10))
print(getRandomNum(1, 10))

Swift on Linux (Ubuntu in my case) will produce the same number every time if you put the srandom call inside my getRandomNum function.

Note of Caution:

srandom and random do not create a "truly" random number, and can be a security concern when making mission-critical applications that would be a target of a hack. The only real solution in that case is to execute Linux's /dev/random directly via Process(), and using its result. But this is outside the scope of the question.

gavanon
  • 1,293
  • 14
  • 15
  • The code above has a bias, and the distribution is not uniform. – jww Nov 05 '17 at 15:11
  • What? The question was about Swift code running on Ubuntu. “The distribution is not uniform”? It has a bias? Please explain in detail. – gavanon Nov 05 '17 at 15:12
  • [Unbiased random number generator using a biased one](https://stackoverflow.com/q/1986859/608639), [Generating Random Numbers without Modulo Bias](https://zuttobenkyou.wordpress.com/2012/10/18/generating-random-numbers-without-modulo-bias/), [How much bias is introduced by the remainder technique?](https://ericlippert.com/2013/12/16/how-much-bias-is-introduced-by-the-remainder-technique/), etc. – jww Nov 05 '17 at 15:16
  • So then you would also have a problem with the accepted answer and have voted it down. Yet you didn’t. My point was to emphasize that initialize the seed in a function is problematic. – gavanon Nov 05 '17 at 15:18
  • The same applied to the other incorrect answers, too. Maybe you need to refresh your browser. – jww Nov 05 '17 at 15:20
  • If want to see the code to do it, the see [Generating random numbers with Swift](https://stackoverflow.com/a/32552511/608639) and [How does one generate a random number in Apple's Swift language?](https://stackoverflow.com/a/25129039/608639). – jww Nov 05 '17 at 15:33
  • You misunderstand the problem. arc4random_uniform is NOT AVAILABLE on Linux versions of Swift. You did not understand the problem. Your suggestion is not possible on Ubuntu, and shows you didn’t read the question or do research before giving out downvotes. – gavanon Nov 05 '17 at 15:39
  • You downvoted without understanding the problem, and provided a solution that’s not even possible. Read the question and the link provided in it. I’ve added to my answer a note about security concerns, but as the question stated: “Are there any functions to get pseudo random numbers”. A 100% safe random number was not requested for this question. – gavanon Nov 05 '17 at 18:11
  • You ignored the max parameter in the title and the body of the question. Misquoting the body's question is disingenuous. If you are not going to fix your answer you should probably delete it. – jww Nov 05 '17 at 18:21
  • You made a mistake. Own up to it. Your solution is unhelpful and literally impossible given the context of the question. And the accepted answer is not by itself helpful either - when put inside a function, it will produce the same number every time it's called. – gavanon Nov 05 '17 at 18:26
  • Own up to what? He wants numbers in the range `[0, max)`. He wants them from a uniform distribution. The `arc4random` gear is missing on Ubuntu. What else is there to this question? – jww Nov 05 '17 at 18:39
  • 1
    Own up to your mistake. You provided a solution which suggested using `arc4random`, which is impossible on Linux. In fact, it’s currently impossible to generate a truly random number in Swift on Linux, and thus, it’s wrong to downvote every answer because it doesn’t do the impossible. – gavanon Nov 05 '17 at 18:43
  • Your initial complaint was that our answers were not truly random. You provided two links, but both relied on `arc4random`. This won't compile on Linux. And now you're name-calling. Provide your own answer, which has no bias, and compiles on Linux. – gavanon Nov 05 '17 at 18:54
  • Just as a heads up, the min and max may not be what you think they are. This function produces numbers in the range of [min, min+max), rather than the [min, max) or [min, max] you might expect. – Ryan Pendleton Jun 04 '18 at 03:52
2

You could try something like this?

    #if os(Linux)
       random()
    #else
        arc4random_uniform()
    #endif
Joe Daniels
  • 1,646
  • 1
  • 11
  • 9
  • Thanks for your answer, but arc4random_uniform actually needs a max parameter, and so do I. I posted my solution. – Tyress Dec 09 '16 at 06:46