Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Swift generate random number without arc4random [duplicate]

Im having 2 problems when trying to generate a random string in Linux with Swift 3.

  1. arc4random_uniform is not available in Linux only on BSD. SO i was able to get away with using random() function. And this worked when i was generating random numbers of a variable size (See code below)

    func generateRandomNumber() -> Int
    {
       var place = 1
    
       var finalNumber = 0;
    
    #if os(Linux)
    for _ in 0..<5
    {
        place *= 10
    
        let randomNumber = Int(random() % 10) + 1
    
        finalNumber += randomNumber * place
    }
    #else
    for _ in 0..<5
    {
        place *= 10
    
        let randomNumber = Int(arc4random_uniform(10))
    
        finalNumber += randomNumber * place
    }
    #endif
    
      return finalNumber
    }
    

And that WORKS. Edit: it works but it gives me the same number every time :(

  1. When trying to generate random alphanumeric string I'm limited to using Swift String and NOT NSSTRING. Linux throws this error

original pre Linux block of code:

   func randomString(_ length: Int) -> String
   {

      let letters : NSString = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
      let len = UInt32(letters.length)

      var randomString = ""

      for _ in 0 ..< length {
    let rand = arc4random_uniform(len)
    var nextChar = letters.character(at: Int(rand))
    randomString += NSString(characters: &nextChar, length: 1) as String
      }

       return randomString
    }

And the actual error I get when using above code

    error: cannot convert value of type 'NSString' to type 'String' in coercion
        randomString += NSString(characters: &nextChar, length: 1) as String

modified for linux block of code.

    func randomString(_ length: Int) -> String
    {

let letters : String = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
let len = letters.characters.count

var randomString = ""

#if os(Linux)

    for _ in 0..<length
    {
        let randomValue = (random() % len) + 1

        randomString += "\(letters[letters.index(letters.startIndex, offsetBy: Int(randomValue))])"
    }

    #else
    for _ in 0 ..< length
    {
        let rand = arc4random_uniform(UInt32(len))

        randomString += "\(letters[letters.index(letters.startIndex, offsetBy: Int(rand))])"
    }
    #endif


      return randomString
}          

but this time the error is weird it only says Illegal instruction with no extra information. I ran the docker container in interactive mode and i saw my server running and printing out when calling other functions etc.

but the thing is the function actually WORKS when i ran it in IBMs swift sandbox

enter image description here and I'm assuming its using linux also. Im very stuck and confused any help would be greatly appreciated.

(UPDATE): I ran the same function in just a linux env with a single swift file and not the Vapor swift web framework. and it works. As mentioned in my edit above it gives me the same random string everytime. I will still have to test the entire project once my build finishes. But besides that i need to know if the random() function will actually give me something new each time instead of the same crap.

like image 897
Andrew Edwards Avatar asked Nov 19 '22 03:11

Andrew Edwards


1 Answers

Figured it out.

So the answer to the repeating random number/string was to just add this line before i called the random() function

srand(UInt32(time(nil)))

and I'm assuming thats what fixed the illegal instruction also. Because i don't recall changing anything else.

Needless to say here is my final result

 func generateRandomNumber() -> Int
 {
    var place = 1

    var finalNumber = 0;

    #if os(Linux)

    srand(UInt32(time(nil)))

    for _ in 0..<5
    {
        place *= 10

        let randomNumber = Int(random() % 10) + 1

        finalNumber += randomNumber * place
    }
    #else
    for _ in 0..<5
    {
        place *= 10

        let randomNumber = Int(arc4random_uniform(10))

        finalNumber += randomNumber * place
    }
    #endif

     return finalNumber
 }



 func randomString(_ length: Int) -> String
 {

    let letters : String = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
    let len = letters.characters.count

    var randomString = ""

    #if os(Linux)

    srand(UInt32(time(nil)))

   for _ in 0..<length
   {
     let randomValue = (random() % len) + 1

     randomString += "\(letters[letters.index(letters.startIndex, offsetBy: Int(randomValue))])"
   }

   #else
  for _ in 0 ..< length
  {
     let rand = arc4random_uniform(UInt32(len))

     randomString += "\(letters[letters.index(letters.startIndex, offsetBy: Int(rand))])"
  }
  #endif

   return randomString
 }  
like image 149
Andrew Edwards Avatar answered Nov 22 '22 07:11

Andrew Edwards