[swift-users] arc4random_uniform on Linux is missing from Foundation??
Jens Persson
jens at bitcycle.com
Mon May 22 16:21:53 CDT 2017
Sorry for the premature send ...
Here is the site: http://xoroshiro.di.unimi.it
There is also a section there about "generating uniform doubles in unit
interval" which is worth reading.
And here's how to get uniform floating point values in the range [0, 1)
from various (supposedly) random bit patterns:
extension Double {
init(unitRange v: UInt64) {
let shifts: UInt64 = 63 - UInt64(Double.significandBitCount)
self = Double(v >> shifts) * (.ulpOfOne/2)
}
init(unitRange v: UInt32) {
self = (Double(v) + 0.5) / (Double(UInt32.max) + 1.0)
}
init(unitRange v: UInt16) {
self = (Double(v) + 0.5) / (Double(UInt16.max) + 1.0)
}
init(unitRange v: UInt8) {
self = (Double(v) + 0.5) / (Double(UInt8.max) + 1.0)
}
}
extension Float {
init(unitRange v: UInt64) {
let shifts: UInt64 = 63 - UInt64(Float.significandBitCount)
self = Float(v >> shifts) * (.ulpOfOne/2)
}
init(unitRange v: UInt32) {
let shifts: UInt32 = 31 - UInt32(Float.significandBitCount)
self = Float(v >> shifts) * (.ulpOfOne/2)
}
init(unitRange v: UInt16) {
let a = Float(v) + 0.5
let b = Float(UInt16.max) + 1.0
self = a / b
}
init(unitRange v: UInt8) {
let a = Float(v) + 0.5
let b = Float(UInt8.max) + 1.0
self = a / b
}
}
You will get a very fast and good quality prng using xoroshiro, converting
to unit range floating point and then back to uniform range int if you want
to, much much faster than arc4random.
/Jens
On Mon, May 22, 2017 at 11:17 PM, Jens Persson <jens at bitcycle.com> wrote:
> Check out the generators (especially xoroshiro) on this site:
>
> On Mon, May 22, 2017 at 6:54 PM, Saagar Jha via swift-users <
> swift-users at swift.org> wrote:
>
>>
>> Saagar Jha
>>
>> On May 22, 2017, at 08:44, Edward Connell via swift-users <
>> swift-users at swift.org> wrote:
>>
>> Any ideas when Foundation on Linux will support arc4random_uniform? This
>> is kind of an important function.
>> There doesn't seem to be any decent substitute without requiring the
>> installation of libbsd-dev, which turns out to be messy. Currently I am
>> doing this, but glibc random with mod does not produce good quality
>> numbers, due to modulo bias.
>>
>>
>> Modulo bias is easy to deal with, though, if you force random to produce
>> a range that is a multiple of the range that you’re trying to produce:
>>
>> guard range > 0 else { return 0 }
>> var random: Int
>> repeat {
>> random = Int(random())
>> } while(random > LONG_MAX / range * range)
>> return random % range
>>
>>
>> Has anyone come up with a better solution to get a true uniform
>> distribution that isn't super messy?
>>
>> import Foundation
>>
>> #if os(Linux)
>> import Glibc
>> #endif
>>
>>
>> public func random_uniform(range: Int) -> Int {
>> guard range > 0 else { return 0 }
>> #if os(Linux)
>> return Int(random()) % range
>> #else
>> return Int(arc4random_uniform(UInt32(range)))
>> #endif
>> }
>>
>>
>> Thanks, Ed
>> _______________________________________________
>> swift-users mailing list
>> swift-users at swift.org
>> https://lists.swift.org/mailman/listinfo/swift-users
>>
>>
>>
>> _______________________________________________
>> swift-users mailing list
>> swift-users at swift.org
>> https://lists.swift.org/mailman/listinfo/swift-users
>>
>>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-users/attachments/20170522/da504d1b/attachment.html>
More information about the swift-users
mailing list