How can I generate large, ranged random numbers in Swift? -


i'm looking efficient method of generating large numbers (that includes floating point types!) in swift, arbitrary ranges (which may uint.max or int.max)

all existing questions i've seen either crash large values (uint.max) or don't support ranges. know can read /dev/urandom random bytes, doesn't restrict these values given interval (and i'm pretty sure looping until isn't efficient).

here possible solution uint, int , double works full range of types. written extension methods (now updated swift 2), same can done global functions.

note arc4random_uniform() produces 32-bit numbers only, can not used if int/uint 64-bit integers (which case os x machines , newer ios devices).

for uint use technique https://stackoverflow.com/a/26550169/1187415 (which swift translation of https://stackoverflow.com/a/10989061/1187415). case range covers full range of uint treated separately.

extension uint {     static func random(minvalue minvalue : uint, maxvalue : uint) -> uint {         precondition(minvalue <= maxvalue, "attempt call random() minvalue > maxvalue")          if minvalue == uint.min && maxvalue == uint.max {             // random number in full range of uint:              var rnd : uint = 0             arc4random_buf(&rnd, sizeofvalue(rnd))             return rnd         } else {             // compute random number in range 0 ... (maxvalue-minvalue),             // using technique              // https://stackoverflow.com/a/26550169/1187415, https://stackoverflow.com/a/10989061/1187415             // , avoiding "modulo bias problem":              let range = maxvalue - minvalue + 1             let randlimit = uint.max - uint.max % range             var rnd : uint = 0             repeat {                 arc4random_buf(&rnd, sizeofvalue(rnd))             } while rnd >= randlimit             rnd = rnd % range              // transform `rnd` range minvalue ... maxvalue:             return minvalue + rnd         }     } } 

examples:

let u1 = uint.random(minvalue: 1000, maxvalue: 2000) let u2 = uint.random(minvalue: uint.min, maxvalue: uint.max) 

the case of signed integers can reduced unsigned case using overflow operators , bitpattern: conversion:

extension int {     static func random(minvalue minvalue : int, maxvalue : int) -> int {         precondition(minvalue <= maxvalue, "attempt call random() minvalue > maxvalue")          // compute unsigned random number in range 0 ... (maxvalue-minvalue):         let diff = uint(bitpattern: maxvalue &- minvalue)         let rnd = uint.random(minvalue: 0, maxvalue: diff)          // transform `rnd` range minvalue ... maxvalue:         return minvalue &+ int(bitpattern: rnd)     } } 

examples:

let i1 = int.random(minvalue: -1000, maxvalue: 1000) let i2 = int.random(minvalue: int.min, maxvalue: int.max) 

finally, straight-forward implementation double:

extension double {     static func random(minvalue minvalue : double, maxvalue : double) -> double {         precondition(minvalue <= maxvalue, "attempt call random() minvalue > maxvalue")          // random floating point number in range 0.0 ... 1.0:         let rnd = double(uint.random(minvalue: 0, maxvalue: uint.max))/double(uint.max)          // scale range minvalue ... maxvalue:         return minvalue + rnd * (maxvalue - minvalue)     } } 

example:

let d = double.random(minvalue: 10.5, maxvalue: 123.5) 

update swift 3:

extension uint {     static func random(minvalue: uint, maxvalue: uint) -> uint {         precondition(minvalue <= maxvalue, "attempt call random() minvalue > maxvalue")          if minvalue == uint.min && maxvalue == uint.max {             // random number in full range of uint:              var rnd: uint = 0             arc4random_buf(&rnd, memorylayout.size(ofvalue: rnd))             return rnd         } else {             // compute random number in range 0 ... (maxvalue-minvalue),             // using technique              // https://stackoverflow.com/a/26550169/1187415, https://stackoverflow.com/a/10989061/1187415             // , avoiding "modulo bias problem":              let range = maxvalue - minvalue + 1             let randlimit = uint.max - uint.max % range             var rnd: uint = 0             repeat {                 arc4random_buf(&rnd, memorylayout.size(ofvalue: rnd))             } while rnd >= randlimit             rnd = rnd % range              // transform `rnd` range minvalue ... maxvalue:             return minvalue + rnd         }     } }  extension int {     static func random(minvalue: int, maxvalue: int) -> int {         precondition(minvalue <= maxvalue, "attempt call random() minvalue > maxvalue")          // compute unsigned random number in range 0 ... (maxvalue-minvalue):         let diff = uint(bitpattern: maxvalue &- minvalue)         let rnd = uint.random(minvalue: 0, maxvalue: diff)          // transform `rnd` range minvalue ... maxvalue:         return minvalue &+ int(bitpattern: rnd)     } }  extension double {     static func random(minvalue: double, maxvalue: double) -> double {         precondition(minvalue <= maxvalue, "attempt call random() minvalue > maxvalue")          // random floating point number in range 0.0 ... 1.0:         let rnd = double(uint.random(minvalue: 0, maxvalue: uint.max))/double(uint.max)          // scale range minvalue ... maxvalue:         return minvalue + rnd * (maxvalue - minvalue)     } } 

Comments

Popular posts from this blog

javascript - Using jquery append to add option values into a select element not working -

Android soft keyboard reverts to default keyboard on orientation change -

Rendering JButton to get the JCheckBox behavior in a JTable by using images does not update my table -