Generate random number of certain amount of digits
Asked Answered
L

8

8

Hy,

I have a very Basic Question which is :

How can i create a random number with 20 digits no floats no negatives (basically an Int) in Swift ?

Thanks for all answers XD

Lineage answered 11/8, 2015 at 21:22 Comment(6)
Can the leading digit be a 0?Voltcoulomb
Yea shure that wouldnt materLineage
Here are some solutions for 64-bit random integers: #26550330, but note that UInt64 is not large enough for an arbitrary integer with 20 decimal digits (10^20 > 2^64).Cognomen
The largest number that can be represented in 64 bits is: 18446744073709551616 and that is insufficient. 20 decimal digits would require 67-bits. How do you propose holding the number?Voltcoulomb
@HuRiXD Did you really want a number that was 20 digits? Or was that an example number picked at random that happens to make computer scientists nervous?Mondrian
It was picket sort of random 20 would be nice but if 14 or 18 makes it easier if would also workLineage
M
4

Here is some pseudocode that should do what you want.

generateRandomNumber(20)
func generateRandomNumber(int numDigits){
   var place = 1
   var finalNumber = 0;
   for(int i = 0; i < numDigits; i++){
      place *= 10
      var randomNumber = arc4random_uniform(10)
      finalNumber += randomNumber * place
  }
  return finalNumber
}

Its pretty simple. You generate 20 random numbers, and multiply them by the respective tens, hundredths, thousands... place that they should be on. This way you will guarantee a number of the correct size, but will randomly generate the number that will be used in each place.

Update

As said in the comments you will most likely get an overflow exception with a number this long, so you'll have to be creative in how you'd like to store the number (String, ect...) but I merely wanted to show you a simple way to generate a number with a guaranteed digit length. Also, given the current code there is a small chance your leading number could be 0 so you should protect against that as well.

Mondrian answered 11/8, 2015 at 21:31 Comment(4)
This will probably abort with an overflow exception in Swift.Cognomen
Probably true... in that case store it in a String like a UUID and parse it back into a number wherever you need it.Mondrian
Parse it back to a number where? Into a uint128_t?Voltcoulomb
Good point @zaph. I'm not sure why he would need a number that's 20 digits. But perhaps the question was more geared towards generating a number with a certain amount of digits and 20 was a random number that is unusual. The title asked how to generate a number of digits, and the post is where the mystical number 20 appeared.Mondrian
S
16

Step 1

First of all we need an extension of Int to generate a random number in a range.

extension Int {
    init(_ range: Range<Int> ) {
        let delta = range.startIndex < 0 ? abs(range.startIndex) : 0
        let min = UInt32(range.startIndex + delta)
        let max = UInt32(range.endIndex   + delta)
        self.init(Int(min + arc4random_uniform(max - min)) - delta)
    }
}

This can be used this way:

Int(0...9) // 4 or 1 or 1...
Int(10...99) // 90 or 33 or 11
Int(100...999) // 200 or 333 or 893

Step 2

Now we need a function that receive the number of digits requested, calculates the range of the random number and finally does invoke the new initializer of Int.

func random(digits:Int) -> Int {
    let min = Int(pow(Double(10), Double(digits-1))) - 1
    let max = Int(pow(Double(10), Double(digits))) - 1
    return Int(min...max)
}

Test

random(1) // 8
random(2) // 12
random(3) // 829
random(4) // 2374
Slight answered 11/8, 2015 at 21:39 Comment(6)
Love the idea to do it in an extension! +1Mondrian
Actually here I used the extension only to generate a random number in a range. But you are right, we could transform the random function as an extension of UInt.Slight
How will you represent the number 36893488147419103232? (that requires more than 64-bits and still only has 20 decimal digits.Voltcoulomb
Again, this cannot work with 20 digits. Also note that your UInt32(..) calculations can overflow on a 64-bit platform if the range includes negative numbers (which is not the case for this question). Try let rnd = Int(Int.min + 10 ..< Int.max - 10) (it crashes). Here is a safe way to produce random numbers in an arbitrary integer range: #31392077.Cognomen
In Swift 4, getting error "cannot invoke initializer for type 'Int' with an argument list of type '(CountableClosedRange<Int>)'"Emera
@LucaAngeletti I checked your Step2 solution by printing 1000 times and it gives me 9 wrong numbers. for _ in 1...1000 { print(random(digits: 2)) }.Oneness
O
15

Swift 5: Simple Solution

func random(digits:Int) -> String {
    var number = String()
    for _ in 1...digits {
       number += "\(Int.random(in: 1...9))"
    }
    return number
}

print(random(digits: 1)) //3
print(random(digits: 2)) //59
print(random(digits: 3)) //926

Note It will return value in String, if you need Int value then you can do like this

let number = Int(random(digits: 1)) ?? 0
Oneness answered 1/4, 2020 at 10:52 Comment(0)
M
4

Here is some pseudocode that should do what you want.

generateRandomNumber(20)
func generateRandomNumber(int numDigits){
   var place = 1
   var finalNumber = 0;
   for(int i = 0; i < numDigits; i++){
      place *= 10
      var randomNumber = arc4random_uniform(10)
      finalNumber += randomNumber * place
  }
  return finalNumber
}

Its pretty simple. You generate 20 random numbers, and multiply them by the respective tens, hundredths, thousands... place that they should be on. This way you will guarantee a number of the correct size, but will randomly generate the number that will be used in each place.

Update

As said in the comments you will most likely get an overflow exception with a number this long, so you'll have to be creative in how you'd like to store the number (String, ect...) but I merely wanted to show you a simple way to generate a number with a guaranteed digit length. Also, given the current code there is a small chance your leading number could be 0 so you should protect against that as well.

Mondrian answered 11/8, 2015 at 21:31 Comment(4)
This will probably abort with an overflow exception in Swift.Cognomen
Probably true... in that case store it in a String like a UUID and parse it back into a number wherever you need it.Mondrian
Parse it back to a number where? Into a uint128_t?Voltcoulomb
Good point @zaph. I'm not sure why he would need a number that's 20 digits. But perhaps the question was more geared towards generating a number with a certain amount of digits and 20 was a random number that is unusual. The title asked how to generate a number of digits, and the post is where the mystical number 20 appeared.Mondrian
C
2

you can create a string number then convert the number to your required number.

func generateRandomDigits(_ digitNumber: Int) -> String {
    var number = ""
    for i in 0..<digitNumber {
        var randomNumber = arc4random_uniform(10)
        while randomNumber == 0 && i == 0 {
            randomNumber = arc4random_uniform(10)
        }
        number += "\(randomNumber)"
    }
    return number
}

print(Int(generateRandomDigits(3)))

for 20 digit you can use Double instead of Int

Chante answered 21/12, 2016 at 9:54 Comment(0)
S
2

Swift 3 appzyourlifz's answer updated to Swift 3

Step 1:

extension Int {
init(_ range: Range<Int> ) {
    let delta = range.lowerBound < 0 ? abs(range.lowerBound) : 0
    let min = UInt32(range.lowerBound + delta)
    let max = UInt32(range.upperBound   + delta)
    self.init(Int(min + arc4random_uniform(max - min)) - delta)
    }
}

Step 2:

func randomNumberWith(digits:Int) -> Int {
    let min = Int(pow(Double(10), Double(digits-1))) - 1
    let max = Int(pow(Double(10), Double(digits))) - 1
    return Int(Range(uncheckedBounds: (min, max)))
}

Usage:

randomNumberWith(digits:4) // 2271
randomNumberWith(digits:8) // 65273410 
Saffron answered 1/8, 2017 at 12:25 Comment(0)
V
1

Here is 18 decimal digits in a UInt64:

(Swift 3)

let sz: UInt32 = 1000000000
let ms: UInt64   = UInt64(arc4random_uniform(sz))
let ls: UInt64   = UInt64(arc4random_uniform(sz))
let digits: UInt64 = ms * UInt64(sz) + ls

print(String(format:"18 digits: %018llu", digits)) // Print with leading 0s.

16 decimal digits with leading digit 1..9 in a UInt64:

let sz: UInt64 = 100000000
let ld: UInt64 = UInt64(arc4random_uniform(9)+1)
let ms: UInt64 = UInt64(arc4random_uniform(UInt32(sz/10)))
let ls: UInt64 = UInt64(arc4random_uniform(UInt32(sz)))
let digits: UInt64 = ld * (sz*sz/10) + (ms * sz) + ls

print(String(format:"16 digits: %llu", digits))
Voltcoulomb answered 11/8, 2015 at 22:5 Comment(2)
thank you for your solution. How to get 16 decimal digits?Thithia
Updated the answer for 16 digits where the leading digit must be 1-9.Voltcoulomb
P
1

Swift 4 version of Unome's validate response plus :

  • Guard it against overflow and 0 digit number

  • Adding support for Linux's device because "arc4random*" functions don't exit

With linux device don't forgot to do

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

only once before calling random.

/// This function generate a random number of type Int with the given digits number
///
/// - Parameter digit: the number of digit
/// - Returns: the ramdom generate number or nil if wrong parameter
func randomNumber(with digit: Int) -> Int? {

    guard 0 < digit, digit < 20 else { // 0 digit number don't exist and 20 digit Int are to big
        return nil
    }

    /// The final ramdom generate Int
    var finalNumber : Int = 0;

    for i in 1...digit {

        /// The new generated number which will be add to the final number
        var randomOperator : Int = 0

        repeat {
            #if os(Linux)
                randomOperator = Int(random() % 9) * Int(powf(10, Float(i - 1)))
            #else
                randomOperator = Int(arc4random_uniform(9)) * Int(powf(10, Float(i - 1)))
            #endif

        } while Double(randomOperator + finalNumber) > Double(Int.max) // Verification to be sure to don't overflow Int max size

        finalNumber += randomOperator
    }

    return finalNumber
} 
Pouch answered 5/7, 2018 at 1:0 Comment(0)
F
0

Usage in single extension:

Int.randomNumberWith(digits: 6) // 453532
extension Int {
    init(_ range: Range<Int> ) {
        let delta = range.startIndex < 0 ? abs(range.startIndex) : 0
        let min = UInt32(range.startIndex + delta)
        let max = UInt32(range.endIndex   + delta)
        self.init(Int(min + arc4random_uniform(max - min)) - delta)
    }
    
    static func randomNumberWith(digits: Int) -> Int {
        let min = Int(pow(Double(10), Double(digits-1))) - 1
        let max = Int(pow(Double(10), Double(digits))) - 1
        return Int(Range(uncheckedBounds: (min, max)))
    }
}
Forcier answered 16/1 at 16:53 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.