在0和1之间快速浮动


Answers:


103

尝试将除数也初始化为浮点数la:

CGFloat(Float(arc4random()) / Float(UINT32_MAX))

谢谢,我曾尝试用CGFloat转换分母,但没有用。但是看起来好像先转换为浮点数,然后转换为CGFloat是可行的。
Joe_Schmoe 2014年

2
无需经过Float-只是CGFloat(arc4random()) / CGFloat(UInt32.max)
Hamish

@Joe_Schmoe如果你不通过浮动/ CGFloat的划分是一个小整数由一个大整数分割,将始终返回0
腾大号

4
但在4.2版中只需使用:Float.random(in:0 .. <1)
Andrew Paul Simmons

116

这是 对Int,Double,Float,CGFloat随机数的扩展

Swift 3&4&5语法

import Foundation
import CoreGraphics

// MARK: Int Extension

public extension Int {

    /// Returns a random Int point number between 0 and Int.max.
    static var random: Int {
        return Int.random(n: Int.max)
    }

    /// Random integer between 0 and n-1.
    ///
    /// - Parameter n:  Interval max
    /// - Returns:      Returns a random Int point number between 0 and n max
    static func random(n: Int) -> Int {
        return Int(arc4random_uniform(UInt32(n)))
    }

    ///  Random integer between min and max
    ///
    /// - Parameters:
    ///   - min:    Interval minimun
    ///   - max:    Interval max
    /// - Returns:  Returns a random Int point number between 0 and n max
    static func random(min: Int, max: Int) -> Int {
        return Int.random(n: max - min + 1) + min

    }
}

// MARK: Double Extension

public extension Double {

    /// Returns a random floating point number between 0.0 and 1.0, inclusive.
    static var random: Double {
        return Double(arc4random()) / 0xFFFFFFFF
    }

    /// Random double between 0 and n-1.
    ///
    /// - Parameter n:  Interval max
    /// - Returns:      Returns a random double point number between 0 and n max
    static func random(min: Double, max: Double) -> Double {
        return Double.random * (max - min) + min
    }
}

// MARK: Float Extension

public extension Float {

    /// Returns a random floating point number between 0.0 and 1.0, inclusive.
    static var random: Float {
        return Float(arc4random()) / 0xFFFFFFFF
    }

    /// Random float between 0 and n-1.
    ///
    /// - Parameter n:  Interval max
    /// - Returns:      Returns a random float point number between 0 and n max
    static func random(min: Float, max: Float) -> Float {
        return Float.random * (max - min) + min
    }
}

// MARK: CGFloat Extension

public extension CGFloat {

    /// Randomly returns either 1.0 or -1.0.
    static var randomSign: CGFloat {
        return (arc4random_uniform(2) == 0) ? 1.0 : -1.0
    }

    /// Returns a random floating point number between 0.0 and 1.0, inclusive.
    static var random: CGFloat {
        return CGFloat(Float.random)
    }

    /// Random CGFloat between 0 and n-1.
    ///
    /// - Parameter n:  Interval max
    /// - Returns:      Returns a random CGFloat point number between 0 and n max
    static func random(min: CGFloat, max: CGFloat) -> CGFloat {
        return CGFloat.random * (max - min) + min
    }
}

使用 :

let randomNumDouble  = Double.random(min: 0.00, max: 23.50)
let randomNumInt     = Int.random(min: 56, max: 992)
let randomNumFloat   = Float.random(min: 6.98, max: 923.09)
let randomNumCGFloat = CGFloat.random(min: 6.98, max: 923.09)

1
@DaRk -_- D0G我试图理解数学。为什么将Float和Double的random()除以0xFFFFFFFF?
水晶

2
@EthanMick为Swift 2外观添加更新;)
YannSteph 2015年

1
“不能调用非功能型‘CGFloat的’价值”的上试图用CGFloat.random(分:0.1,最大:10.1)出现错误
安德鲁

1
没有更新需要斯威夫特4
RyuX51

1
@YannickSteph使用Swift 5和Xcode 10.2,该行return Float(arc4random()) / 0xFFFFFFFF现在发出警告:'4294967295' is not exactly representable as 'Float'; it becomes '4294967296'。任何想法如何解决该警告?我正在考虑除以Float(UInt32.max)
和平型

36

迅捷4.2:

let randomFloat = Float.random(in: 0..<1)

26

更新Sandy Chapman对Swift 3的回答

extension ClosedRange where Bound : FloatingPoint {
    public func random() -> Bound {
        let range = self.upperBound - self.lowerBound
        let randomValue = (Bound(arc4random_uniform(UINT32_MAX)) / Bound(UINT32_MAX)) * range + self.lowerBound
        return randomValue
    }
}

现在您可以说诸如此类的东西(-1.0...1.0).random()

编辑我认为今天(快速4)我会这样写:

extension ClosedRange where Bound : FloatingPoint {
    public func random() -> Bound {
        let max = UInt32.max
        return
            Bound(arc4random_uniform(max)) /
            Bound(max) *
            (upperBound - lowerBound) +
            lowerBound
    }
}

注意Swift 4.2引入了本机随机数生成,所有这些都变得毫无意义。


16

在这里,框架可以很好地在Swift中生成随机数数据:https//github.com/thellimist/SwiftRandom/blob/master/SwiftRandom/Randoms.swift

public extension Int {
    /// SwiftRandom extension
    public static func random(lower: Int = 0, _ upper: Int = 100) -> Int {
        return lower + Int(arc4random_uniform(UInt32(upper - lower + 1)))
    }
}

public extension Double {
    /// SwiftRandom extension
    public static func random(lower: Double = 0, _ upper: Double = 100) -> Double {
        return (Double(arc4random()) / 0xFFFFFFFF) * (upper - lower) + lower
    }
}

public extension Float {
    /// SwiftRandom extension
    public static func random(lower: Float = 0, _ upper: Float = 100) -> Float {
        return (Float(arc4random()) / 0xFFFFFFFF) * (upper - lower) + lower
    }
}

public extension CGFloat {
    /// SwiftRandom extension
    public static func random(lower: CGFloat = 0, _ upper: CGFloat = 1) -> CGFloat {
        return CGFloat(Float(arc4random()) / Float(UINT32_MAX)) * (upper - lower) + lower
    }
}

为编译时此方法不起作用Generic iOS device。0xffffffff不适合放在Int内部。尝试改用CGFloat(UInt32.max)
neoneye

13

下面是IntervalType执行此操作的类型的扩展:

extension IntervalType {
    public func random() -> Bound {
        let range = (self.end as! Double) - (self.start as! Double)
        let randomValue = (Double(arc4random_uniform(UINT32_MAX)) / Double(UINT32_MAX)) * range + (self.start as! Double)
        return randomValue as! Bound
    }
}

使用此扩展,您可以使用interval语法生成一个间隔,然后在该间隔中获取随机值:

(0.0...1.0).random()

加成

如果您希望对Ints做同样的事情,那么可以在CollectionType协议上使用以下扩展名:

extension CollectionType {
    public func random() -> Self._Element {
        if let startIndex = self.startIndex as? Int {
            let start = UInt32(startIndex)
            let end = UInt32(self.endIndex as! Int)
            return self[Int(arc4random_uniform(end - start) + start) as! Self.Index]
        }
        var generator = self.generate()
        var count = arc4random_uniform(UInt32(self.count as! Int))
        while count > 0 {
            generator.next()
            count = count - 1
        }
        return generator.next() as! Self._Element
    }
}

Int不要使用IntervalType。他们Range改用。在CollectionType类型上执行此操作的好处是,它会自动结转到DictionaryArray类型。

例子:

(0...10).random()               // Ex: 6
["A", "B", "C"].random()        // Ex: "B"
["X":1, "Y":2, "Z":3].random()  // Ex: (.0: "Y", .1: 2)

我们如何使它也适用于Ints,而不是最初的问题,但是如果我们要扩展IntervalType
Joe_Schmoe

1
@Joe_Schmoe:我已经使用s,s和s.random()Int的详细信息更新了我的答案DictionaryArray
Sandy Chapman

我真的很喜欢这种解决方案,但是我正在更新以包含更好的通用做法
tbondwilkinson

1
在Swift 3中被破坏
。–哑光


6

jmduke提出的建议似乎可以在Playground中使用,但对函数的更改很小:

func randomCGFloat() -> Float {
    return Float(arc4random()) /  Float(UInt32.max)
}

以及drewag指出的快速文档的原因:类型转换必须是明确的,该文档中的示例为:

let three = 3
let pointOneFourOneFiveNine = 0.14159
let pi = Double(three) + pointOneFourOneFiveNine
// pi equals 3.14159, and is inferred to be of type Double

2
drand48()

如果您需要[Double]。在0和1之间。仅此而已。


1

根据YannickSteph的回答

为了使它适用于任何浮点类型,像DoubleFloatCGFloat等等,你可以为一个扩展BinaryFloatingPoint类型:

extension BinaryFloatingPoint {

    /// Returns a random floating point number between 0.0 and 1.0, inclusive.
    public static var random: Self {
        return Self(arc4random()) / 0xFFFFFFFF
    }

    /// Random double between 0 and n-1.
    ///
    /// - Parameter n:  Interval max
    /// - Returns:      Returns a random double point number between 0 and n max
    public static func random(min: Self, max: Self) -> Self {
        return Self.random * (max - min) + min
    }
}

1

细节

Xcode:9.2,Swift 4

extension BinaryInteger {

    static func rand(_ min: Self, _ max: Self) -> Self {
        let _min = min
        let difference = max+1 - _min
        return Self(arc4random_uniform(UInt32(difference))) + _min
    }
}

extension BinaryFloatingPoint {

    private func toInt() -> Int {
        // https://stackoverflow.com/q/49325962/4488252
        if let value = self as? CGFloat {
            return Int(value)
        }
        return Int(self)
    }

    static func rand(_ min: Self, _ max: Self, precision: Int) -> Self {

        if precision == 0 {
            let min = min.rounded(.down).toInt()
            let max = max.rounded(.down).toInt()
            return Self(Int.rand(min, max))
        }

        let delta = max - min
        let maxFloatPart = Self(pow(10.0, Double(precision)))
        let maxIntegerPart = (delta * maxFloatPart).rounded(.down).toInt()
        let randomValue = Int.rand(0, maxIntegerPart)
        let result = min + Self(randomValue)/maxFloatPart
        return Self((result*maxFloatPart).toInt())/maxFloatPart
    }
}

用法

print("\(Int.rand(1, 20))")
print("\(Float.rand(5.231233, 44.5, precision: 3))")
print("\(Double.rand(5.231233, 44.5, precision: 4))")
print("\(CGFloat.rand(5.231233, 44.5, precision: 6))")

完整样本

import Foundation
import CoreGraphics

func run() {
    let min = 2.38945
    let max = 2.39865
    for _ in 0...100 {
        let precision = Int.rand(0, 5)
        print("Precision: \(precision)")
        floatSample(min: Float(min), max: Float(max), precision: precision)
        floatSample(min: Double(min), max: Double(max), precision: precision)
        floatSample(min: CGFloat(min), max: CGFloat(max), precision: precision)
        intSample(min: Int(1), max: Int(10000))
        print("")
    }
}

private func printResult<T: Comparable>(min: T, max: T, random: T) {
    let result = "\(T.self) rand[\(min), \(max)] = \(random)"
    print(result)
}

func floatSample<T: BinaryFloatingPoint>(min: T, max: T, precision: Int) {
    printResult(min: min, max: max, random: T.rand(min, max, precision: precision))
}

func intSample<T: BinaryInteger>(min: T, max: T) {
    printResult(min: min, max: max, random: T.rand(min, max))
}

结果

在此处输入图片说明

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.