【问题标题】:Generate random number of certain amount of digits生成一定位数的随机数
【发布时间】:2023-03-28 15:20:01
【问题描述】:

喂,

我有一个非常基本的问题:

如何在 Swift 中创建一个 20 位无浮点数无负数(基本上是 Int)的随机数?

感谢所有回答XD

【问题讨论】:

  • 开头的数字可以是0吗?
  • 是的,这不重要
  • 以下是 64 位随机整数的一些解决方案:stackoverflow.com/questions/26549830/…,但请注意 UInt64 不足以容纳 20 位小数的任意整数 (10^20 > 2^64)。
  • 64位能表示的最大数是:18446744073709551616,这是不够的。 20 个十进制数字需要 67 位。您如何建议持有该号码?
  • @HuRiXD 你真的想要一个 20 位数的数字吗?或者是随机选择的一个示例数字恰好让计算机科学家感到紧张?

标签: swift random range


【解决方案1】:

步骤 1

首先我们需要Int的扩展来生成一个范围内的随机数。

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)
    }
}

可以这样使用:

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

第二步

现在我们需要一个函数来接收请求的位数,计算随机数的范围并最终调用 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)
}

测试

random(1) // 8
random(2) // 12
random(3) // 829
random(4) // 2374

【讨论】:

  • 喜欢在扩展中这样做的想法! +1
  • 其实这里我使用扩展只是为了生成一个范围内的随机数。但你是对的,我们可以将random 函数转换为UInt 的扩展。
  • 你将如何表示数字 36893488147419103232? (这需要超过 64 位,但仍然只有 20 个十进制数字。
  • 再一次,这不适用于 20 位数字。另请注意,如果范围包括负数(this 问题不是这种情况),您的 UInt32(..) 计算可能会在 64 位平台上溢出。试试let rnd = Int(Int.min + 10 ..&lt; Int.max - 10)(它崩溃了)。这是一种在任意整数范围内生成随机数的安全方法:stackoverflow.com/questions/31391577/…
  • 在 Swift 4 中,出现错误“无法使用类型为 '(CountableClosedRange)' 的参数列表调用类型为 'Int' 的初始化程序”
【解决方案2】:

Swift 5:简单解决方案

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

注意它会在String中返回值,如果你需要Int值那么你可以这样做

let number = Int(random(digits: 1)) ?? 0

【讨论】:

    【解决方案3】:

    这里有一些伪代码可以做你想做的事。

    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
    }
    

    它非常简单。您生成 20 个随机数,然后将它们乘以它们应该在的十位、百分之一、千位……。这样,您将保证数字大小正确,但会随机生成将在每个地方使用的数字。

    更新

    正如 cmets 中所说,您很可能会遇到一个带有这么长数字的溢出异常,因此您必须创造性地存储数字(字符串等),但我只是想向您展示一种生成具有保证数字长度的数字的简单方法。此外,鉴于当前代码,您的前导数字可能为 0 的可能性很小,因此您也应该防范这种情况。

    【讨论】:

    • 这可能会因 Swift 中的溢出异常而中止。
    • 可能是真的......在这种情况下,将其存储在 UUID 之类的字符串中,并在需要时将其解析回数字。
    • 把它解析回一个数字在哪里?进入 uint128_t?
    • 好点@zaph。我不确定他为什么需要一个 20 位数的数字。但也许这个问题更倾向于生成一个具有一定位数的数字,而 20 是一个不寻常的随机数。标题问如何生成数字,帖子是神秘数字20出现的地方。
    【解决方案4】:

    您可以创建一个字符串数字,然后将该数字转换为您需要的数字。

    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)))
    

    对于 20 位,您可以使用 Double 而不是 Int

    【讨论】:

      【解决方案5】:

      这是 UInt64 中的 18 位十进制数字:

      (斯威夫特 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.
      

      UInt64 中的 16 个十进制数字,前导数字 1..9:

      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))
      

      【讨论】:

      • 感谢您的解决方案。如何获得 16 位小数?
      • 更新了 16 位数字的答案,其中前导数字必须是 1-9。
      【解决方案6】:

      斯威夫特 3 appzyourlifz 的答案已更新为 Swift 3

      第 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)
          }
      }
      

      第 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)))
      }
      

      用法:

      randomNumberWith(digits:4) // 2271
      randomNumberWith(digits:8) // 65273410 
      

      【讨论】:

        【解决方案7】:

        Swift 4 版本的 Unome 的验证响应加:

        • 防止溢出和0位数字

        • 添加对 Linux 设备的支持,因为“arc4random*”函数不会退出

        用linux设备别忘了做

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

        一次,然后调用随机

        /// 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
        } 
        

        【讨论】:

          猜你喜欢
          • 2018-04-03
          • 2011-09-18
          • 1970-01-01
          • 2011-08-09
          • 2020-11-19
          • 2011-06-26
          • 1970-01-01
          • 2023-01-03
          • 1970-01-01
          相关资源
          最近更新 更多