[swift-users] arc4random_uniform on Linux is missing from Foundation??

Edward Connell ewconnell at gmail.com
Wed May 24 10:15:50 CDT 2017


Thank you for all the feedback and options. In further investigation, I
also ran across the family of xx48 rngs, which appear to be on both
platforms. They claim to be uniformly distributed.

drand48, erand48, jrand48, lcong48, lrand48, mrand48, nrand48, seed48,
srand48

http://pubs.opengroup.org/onlinepubs/007908775/xsh/drand48.html

Any reason not to use one of these instead?

Thanks, Ed

On Tue, May 23, 2017 at 3:18 AM, Jens Persson <jens at bitcycle.com> wrote:

> Here's a stripped down verison of my implementation of the Xoroshiro128+
> PRNG:
> https://gist.github.com/anonymous/527602968812f853d6147aea8c66d660
>
> /Jens
>
>
> On Mon, May 22, 2017 at 11:21 PM, Jens Persson <jens at bitcycle.com> wrote:
>
>> 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/20170524/31366f16/attachment.html>


More information about the swift-users mailing list