For a range of 0..<(2<<b) (size being 2<<b) and mod m, its less pronounced for 
small m. Worst case would be a mod greater than 2^(b-1), in which case some 
values are twice as likely as others.

The increased probability I believe is (floor(s/m)+ 1) / floor(s/m) for s % m 
!= 0

For me, its not so much about being statistically correct as leading people 
down the right path in terms of comprehension and readability. I find it much 
easier to think of the classic example program of “pick a number between 1 and 
100” as

(1…100).random() 

vs say

Int(UInt64.random()%100) + 1

which (with all that complexity) still isn’t a uniform distribution!

Thats completely ignoring some of the finer issues you get with floating point 
numbers as you certain transforms of a [0,1] distribution

-DW

> On Jan 13, 2018, at 7:41 PM, C. Keith Ray via swift-evolution 
> <swift-evolution@swift.org> wrote:
> 
> Could someone measure how bad the "random(32 bits) mod m" problem actually 
> is? It's prominent when the number of bits is close to m, eg 4 bits and m == 
> 3. Is it bad when bits == 32 and m is less than 2^16? Or bits == 64 and m is 
> less than 2^32?
> 
> C. Keith Ray
> https://leanpub.com/wepntk <https://leanpub.com/wepntk> <- buy my book?
> http://agilesolutionspace.blogspot.com/ 
> <http://agilesolutionspace.blogspot.com/>
> twitter: @ckeithray
> http://www.thirdfoundationsw.com/keith_ray_resume_2014_long.pdf 
> <http://www.thirdfoundationsw.com/keith_ray_resume_2014_long.pdf>
> 
> On Jan 13, 2018, at 6:15 PM, Jonathan Hull via swift-evolution 
> <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
> 
>> 
>>> On Jan 12, 2018, at 8:22 PM, Nate Cook <natec...@apple.com 
>>> <mailto:natec...@apple.com>> wrote:
>>> 
>>> On Jan 12, 2018, at 6:24 PM, Jonathan Hull via swift-evolution 
>>> <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
>>> 
>>>> I think we have different definitions of consistency.  I am fine with the 
>>>> ergonomics of (0…100).random() as a convenience, but it really worries me 
>>>> here that everything is special cased.  Special cased things are fine for 
>>>> individual projects, but not the standard library.  We should make sure 
>>>> that the design is flexible and extensible, and that comes in part from 
>>>> having a consistent interface.
>>>> 
>>>> Also, as I said before, we really shouldn’t be doing these crazy 
>>>> contortions to avoid ‘random() % 100’.  Instead we should look for that 
>>>> pattern and issue with a warning + fixit to change it to random(in:).  I 
>>>> think that will be much more effective in actually changing the behavior 
>>>> in the long run.
>>> 
>>> I’m not sure what contortions you’re describing—from what I’ve seen, the 
>>> proposal author is going to revise the proposal to have these ways of 
>>> generating individual values:
>> 
>> Mainly avoiding ‘random(using:)’ as a thing we can count on generically 
>> because of the fear of it being used with mod.  This makes random(using:) on 
>> Bool a one-off special case instead of a thing I can call on anything 
>> adhering to a protocol.
>> 
>> 
>>> In extensions to FixedWidthInteger and BinaryFloatingPoint:
>>> static func random(in: Range/ClosedRange<Self>, using: 
>>> RandomNumberGenerator) -> Self
>>> 
>>> In an extension to Bool:
>>> static func random(using: RandomNumberGenerator) -> Self
>>> 
>>> If someone still needs a full-width random value as a building-block for 
>>> generating random instances of other types, they should use the `next()` 
>>> method directly on a RandomNumberGenerator. In the example code you sent, 
>>> you could switch to using a RandomNumberGenerator instead of your 
>>> RandomSourceValue, or base your RandomSourceValue generation on a 
>>> RandomNumberGenerator instead of whatever random generator you’re using now.
>>> 
>>>> Finally, tying everything to Range is extremely limiting.  I understand if 
>>>> we don’t want to add other types to the standard library, but I should be 
>>>> able to build on what we add to do it myself without having to reinvent 
>>>> the wheel for each type.  It is important to have a consistent story for 
>>>> these things (including multi-dimensional types) so that they can 
>>>> interoperate.
>>>> 
>>>> We really should be looking at GamePlayKit more for design inspiration.  
>>>> There are several use-cases there that are being blatantly ignored in this 
>>>> discussion.  For example, what if I want to randomly generate a game world 
>>>> (e.g. The square from The Battle For Polytopia” formerly “SuperTribes”)?  
>>>> Or what if I want an effect where it randomly fades in letters from a 
>>>> String.  (…).random() will be completely inadequate for these things.
>>> 
>>> The goal at this point is to build into the standard library the basis for 
>>> all kinds of other use cases. Your library is one such example of something 
>>> that can be built on top of the protocol and methods that are being 
>>> proposed, as are a variety of other tasks, as I tried to show in the 
>>> playground.
>>> 
>>> What’s being proposed now is deliberately short of solving every need—the 
>>> additions would handle the hard stuff (correct and safe generation of 
>>> integers and floating-points, along with shuffling collections) and lay the 
>>> groundwork for other libraries to take things farther (by establishing the 
>>> RandomNumberGenerator, a default generator, and a pattern for their use).
>> 
>> I think we are mostly in agreement on this.  I don’t need the proposal to 
>> solve every need.  I would just really like to see something that those 
>> other things can be built on.  I don’t expect other types to conform out of 
>> the box, but I want the types that I add conformance to to be able to 
>> interoperate with machinery that others build around randomness.
>> 
>> For example, if we instead went with Letanyan’s mental model of having to 
>> define a space to select a random element from using a generator, that would 
>> be perfectly fine for me, since we can conform Range to that protocol… and 
>> then we can operate generically on objects which conform to it.
>> 
>> 
>>> Speaking of GameplayKit, you can make GKRandomSource conform to 
>>> RandomNumberGenerator in an extension, making all the GK... sources 
>>> generators. If you’re already depending on those random sources, you’d 
>>> still have access to them with the proposed model.
>> 
>> Agreed.  I was thinking someone was removing the ‘using:’ variant from the 
>> proposal for some reason.
>> 
>> Thanks,
>> Jon
>> 
>> 
>>> 
>>> Nate
>>> 
>>>> Thanks,
>>>> Jon
>>>> 
>>>> 
>>>> 
>>>>> On Jan 12, 2018, at 5:11 AM, Letanyan Arumugam <letanya...@gmail.com 
>>>>> <mailto:letanya...@gmail.com>> wrote:
>>>>> 
>>>>> Nate’s design follows a consistent idea of getting a random value from 
>>>>> some set of values. Adding the static method random() to a type 
>>>>> essentially creates an implicit set which you yourself said leads to 
>>>>> inconsistency (Double/Int). Secondly I don’t see why random(in:) should 
>>>>> be added when it is just a different spelling for what is already 
>>>>> provided. If my second statement is incorrect and there’s something I’m 
>>>>> missing please correct me?
>>>>> 
>>>>> I think that consistency outweighs the random trapping inconsistency, 
>>>>> however I would actually be fine if random returned an optional. Though 
>>>>> the way random is used would likely lead to less opportunities for a trap 
>>>>> than the other methods you mention. 
>>>>> 
>>>>> 
>>>>> Letanyan
>>>>> 
>>>>>> On 12 Jan 2018, at 04:39, Alejandro Alonso <aalonso...@outlook.com 
>>>>>> <mailto:aalonso...@outlook.com>> wrote:
>>>>>> 
>>>>>> If anything, Nate’s design is inconsistent as properties like `.first` 
>>>>>> and `.last` return an optional, and methods like `.min()` and `.max()` 
>>>>>> return an optional as well. Having `.random()` on ranges be an exception 
>>>>>> and return non optionals are inconsistent with other collection 
>>>>>> facilities, and with other collections that aren’t ranges that return 
>>>>>> optionals on `.random()`.
>>>>>> 
>>>>>> - Alejandro
>>>>>> 
>>>>>> On Jan 11, 2018, 12:06 PM -0600, Letanyan Arumugam via swift-evolution 
>>>>>> <swift-evolution@swift.org <mailto:swift-evolution@swift.org>>, wrote:
>>>>>>> This is really cool and seems very powerful. However I don’t think we 
>>>>>>> should sacrifice consistency for extendability. Especially when the 
>>>>>>> extendability would not be what most people need. 
>>>>>>> 
>>>>>>> What I am basically trying to say is that. I think the proposals 
>>>>>>> current design direction fits better in a Random library rather than 
>>>>>>> the Standard Library. And Nate’s design more directly addresses the 
>>>>>>> motivating points of the proposal.
>>>>>>> 
>>>>>>> Letanyan
>>>>>>> 
>>>>>>>> 
>>>>>>>> Sure. Small disclaimer that this was originally written back in the 
>>>>>>>> Swift 1~2 days, so it is overdue for a simplifying rewrite.
>>>>>>>> 
>>>>>>>> Also, I should point out that the term “Source” has a special meaning 
>>>>>>>> in my code.  It basically means that something will provide an 
>>>>>>>> ~infinite collection of values of a type T.   I have what I call a 
>>>>>>>> “ConstantSource” which just wraps a T and gives it back when asked.  
>>>>>>>> But then I have a bunch of other “sources" which let you create 
>>>>>>>> repeating patterns and do deferred calculations and things like that.  
>>>>>>>> Finally I have a “RandomSource” which is part of what started this 
>>>>>>>> discussion.  You set up a RandomSource with a set of constraints, and 
>>>>>>>> then it gives you random values of T that adhere to those constraints 
>>>>>>>> (e.g. colors with a range of hues but the same saturation) whenever 
>>>>>>>> you ask for them.
>>>>>>>> 
>>>>>>>> This is really useful for doing things like graphic effects because, 
>>>>>>>> for example, I can ask for a source of colors and a source of line 
>>>>>>>> widths and then get out a large variety of interesting patterns from 
>>>>>>>> the same algorithm.  I can make simple stripes with ConstantSources, 
>>>>>>>> or I can make repeating patterns of lines with repeating sources, or I 
>>>>>>>> can have random colors which look good together by using a 
>>>>>>>> RandomSource.  I can take a BezierPath and make it look hand-drawn by 
>>>>>>>> breaking it into a bunch of lines and then offset the points a small 
>>>>>>>> amount using a RandomSource of CGVectors.
>>>>>>>> 
>>>>>>>> Not sure how useful this concept of randomness (and pattern) is to 
>>>>>>>> others, but I find it immensely useful!  Not sure of the best way to 
>>>>>>>> implement it.  The way I do it is a type erased protocol with private 
>>>>>>>> conforming structs and then public initializers on the type-erasing 
>>>>>>>> box.  The end result is that I can just say:
>>>>>>>> 
>>>>>>>> let myConst = Source(1) //ConstantSource with 1 as a value
>>>>>>>> let myPattern = Source([1, 2]) //OrderedSource which repeats 1, then 2 
>>>>>>>> over and over forever
>>>>>>>> let myMeta = Source([myConst, myPattern]) //Will alternate between 
>>>>>>>> sub-sources in order. Can be nested.
>>>>>>>> //…and so on.
>>>>>>>> 
>>>>>>>> It is quite extensible and can make very complex/interesting patterns 
>>>>>>>> very easily.  What I like about it is that (well controlled) random 
>>>>>>>> values and patterns or constant values can be interchanged very easily.
>>>>>>>> 
>>>>>>>> The RandomSource has a RandomSourceCreatable Protocol that lets it 
>>>>>>>> take random bits and turn them into objects/structs of T adhering to 
>>>>>>>> the given constraints.  This is way more complex under the hood than 
>>>>>>>> it needs to be, but it works well in practice, and I haven’t gotten 
>>>>>>>> around to cleaning it up yet:
>>>>>>>> 
>>>>>>>> public protocol RandomSourceCreatable {
>>>>>>>>     associatedtype ConstraintType = Self
>>>>>>>>     
>>>>>>>>     
>>>>>>>> ///This should be implimented by simple types without internal 
>>>>>>>> components
>>>>>>>>     
>>>>>>>> static func createRandom(rnd value:RandomSourceValue, 
>>>>>>>> constraint:RandomSourceConstraint<ConstraintType>)->Self
>>>>>>>>     
>>>>>>>> ///This should be implimented by complex types with multiple axis of 
>>>>>>>> constraints
>>>>>>>>     
>>>>>>>> static func createRandom(rnd value:RandomSourceValue, 
>>>>>>>> constraints:[String:RandomSourceConstraint<ConstraintType>])->Self
>>>>>>>>     
>>>>>>>>     
>>>>>>>> ///Returns the proper dimension for the type given the constraints
>>>>>>>>     
>>>>>>>> static func dimension(given 
>>>>>>>> contraints:[String:RandomSourceConstraint<ConstraintType>])->RandomSourceDimension
>>>>>>>>     
>>>>>>>>     
>>>>>>>> ///Validates the given contraints to make sure they can create valid 
>>>>>>>> objects. Only needs to be overridden for extremely complex types
>>>>>>>>     static func validateConstraints(_ 
>>>>>>>> constraints:[String:RandomSourceConstraint<ConstraintType>])->Bool
>>>>>>>>     
>>>>>>>>     
>>>>>>>> ///Convienience method which provides whitelist of keys for implicit 
>>>>>>>> validation of constraints
>>>>>>>>     static var allowedConstraintKeys:Set<String> {get}
>>>>>>>>    }
>>>>>>>> 
>>>>>>>> Most of these things also have default implementations so you only 
>>>>>>>> really have to deal with them for complex cases like colors or points. 
>>>>>>>>  The constraints are given using a dictionary with string keys and a 
>>>>>>>> RandomSourceConstraint value, which is defined like this:
>>>>>>>> 
>>>>>>>> public enum RandomSourceConstraint<T> {
>>>>>>>>     case none
>>>>>>>>     case constant(T)
>>>>>>>>     case min(T)
>>>>>>>>     case max(T)
>>>>>>>>     case range (T,T)
>>>>>>>>     case custom ( (RandomSourceValue)->T )
>>>>>>>> //A bunch of boring convenience code here that transforms values so I 
>>>>>>>> don’t always have to switch on the enum in other code that deals with 
>>>>>>>> this. I just ask for the bounds or constrained T (Note: T here refers 
>>>>>>>> to the type for a single axis as opposed to the generated type. e.g. 
>>>>>>>> CGFloat for a point) 
>>>>>>>>     }
>>>>>>>> 
>>>>>>>> I have found that this handles pretty much all of the constraints I 
>>>>>>>> need, and the custom constraint is useful for anything exotic (e.g. 
>>>>>>>> sig-figs).  The RandomSource itself has convenience inits when T is 
>>>>>>>> Comparable that let you specify a range instead of having to create 
>>>>>>>> the constraints yourself.
>>>>>>>> 
>>>>>>>> I then have conformed many standard types to RandomSourceCreatable so 
>>>>>>>> that I can create Sources out of them.  Here is CGPoint for reference:
>>>>>>>> 
>>>>>>>> extension CGPoint:RandomSourceCreatable {
>>>>>>>>     
>>>>>>>>     
>>>>>>>> public static func dimension(given 
>>>>>>>> contraints:[String:RandomSourceConstraint<CGFloat>])->RandomSourceDimension
>>>>>>>>  {
>>>>>>>>         
>>>>>>>> return RandomSourceDimension.manyWord(2)
>>>>>>>>     }
>>>>>>>>     
>>>>>>>>     public typealias ConstraintType = CGFloat
>>>>>>>>     public static var allowedConstraintKeys:Set<String>{
>>>>>>>>         return ["x","y"]
>>>>>>>>     }
>>>>>>>>     
>>>>>>>>     
>>>>>>>> public static func createRandom(rnd value:RandomSourceValue, 
>>>>>>>> constraints:[String:RandomSourceConstraint<CGFloat>])->CGPoint {
>>>>>>>>         let xVal = value.value(at: 0)
>>>>>>>>         let yVal = value.value(at: 1)
>>>>>>>>         
>>>>>>>> //Note: Ints have a better distribution for normal use cases of points
>>>>>>>>         let x = CGFloat(Int.createRandom(rnd: xVal, constraint: 
>>>>>>>> constraints["x"]?.asType({Int($0 * 1000)}) ?? .none))/1000
>>>>>>>>         let y = CGFloat(Int.createRandom(rnd: yVal, constraint: 
>>>>>>>> constraints["y"]?.asType({Int($0 * 1000)}) ?? .none))/1000
>>>>>>>>         return CGPoint(x: x, y: y)
>>>>>>>>     }
>>>>>>>>     }
>>>>>>>> 
>>>>>>>> Notice that I have a RandomSourceValue type that provides the random 
>>>>>>>> bits of the requested dimension. When I get around to updating this, I 
>>>>>>>> might do something closer to the proposal, where I would just pass the 
>>>>>>>> generator and grab bits as needed.  The main reason I did it the way I 
>>>>>>>> did is that it lets me have random access to the source very easily. 
>>>>>>>> 
>>>>>>>> The ‘asType’ method converts a constraint to work with another type 
>>>>>>>> (in this case Ints).
>>>>>>>> 
>>>>>>>> Colors are a bit more complicated, mainly because I allow a bunch of 
>>>>>>>> different constraints, and I also have validation code to make sure 
>>>>>>>> the constraints fit together properly. I also ask for different 
>>>>>>>> amounts of randomness based on whether it is greyscale or contains 
>>>>>>>> alpha. Just to give you a sense, here are the allowed constraint keys 
>>>>>>>> for a CGColor:
>>>>>>>> public static var allowedConstraintKeys:Set<String>{
>>>>>>>>         return ["alpha","gray","red","green","blue", "hue", 
>>>>>>>> "saturation", "brightness"]
>>>>>>>>     }
>>>>>>>> 
>>>>>>>> and here is the creation method when the keys are for RGBA (I have 
>>>>>>>> similar sections for HSBA and greyscale):
>>>>>>>> 
>>>>>>>> let rVal = value.value(at: 0)
>>>>>>>>     let gVal = value.value(at: 1)
>>>>>>>>     let bVal = value.value(at: 2)
>>>>>>>>     let aVal = value.value(at: 3)
>>>>>>>>     let r = CGFloat.createRandom(rnd: rVal, constraint: 
>>>>>>>> constraints["red"] ?? .range(0,1))
>>>>>>>>     let g = CGFloat.createRandom(rnd: gVal, constraint: 
>>>>>>>> constraints["green"] ?? .range(0,1))
>>>>>>>>     let b = CGFloat.createRandom(rnd: bVal, constraint: 
>>>>>>>> constraints["blue"] ?? .range(0,1))
>>>>>>>>     let a = CGFloat.createRandom(rnd: aVal, constraint: 
>>>>>>>> constraints["alpha"] ?? .constant(1.0))
>>>>>>>>             
>>>>>>>>     return self.init(colorSpace: CGColorSpaceCreateDeviceRGB(), 
>>>>>>>> components: [r,g,b,a])!
>>>>>>>> 
>>>>>>>> 
>>>>>>>> The end result is that initializing a source of CGColors looks like 
>>>>>>>> this (either parameter can be omitted if desired):
>>>>>>>> 
>>>>>>>> let colorSource:Source<CGColor> = Source(seed: optionalSeed, 
>>>>>>>> constraints:["saturation": .constant(0.4), "brightness": 
>>>>>>>> .constant(0.6)])
>>>>>>>> 
>>>>>>>> Anyway, I hope this was useful/informative.  I know the code is a bit 
>>>>>>>> messy, but I still find it enormously useful in practice.  I plan to 
>>>>>>>> clean it up when I find time, simplifying the RandomSourceValue stuff 
>>>>>>>> and moving from String Keys to a Struct with static functions for the 
>>>>>>>> constraints.  The new constraints will probably end up looking like 
>>>>>>>> this:
>>>>>>>> 
>>>>>>>> let colorSource:Source<CGColor> = Source(seed: optionalSeed, 
>>>>>>>> constraints:[.saturation(0.4), .brightness(0.4...0.6)])
>>>>>>>> 
>>>>>>>> Thanks,
>>>>>>>> Jon
>>>>>>>> 
>>>>>>>> 
>>>>>>>> _______________________________________________
>>>>>>>> swift-evolution mailing list
>>>>>>>> swift-evolution@swift.org <mailto:swift-evolution@swift.org>
>>>>>>>> https://lists.swift.org/mailman/listinfo/swift-evolution 
>>>>>>>> <https://lists.swift.org/mailman/listinfo/swift-evolution>
>>>>>>> 
>>>>>>> _______________________________________________
>>>>>>> swift-evolution mailing list
>>>>>>> swift-evolution@swift.org <mailto:swift-evolution@swift.org>
>>>>>>> https://lists.swift.org/mailman/listinfo/swift-evolution 
>>>>>>> <https://lists.swift.org/mailman/listinfo/swift-evolution>
>>>>> 
>>>> 
>>>> _______________________________________________
>>>> swift-evolution mailing list
>>>> swift-evolution@swift.org <mailto:swift-evolution@swift.org>
>>>> https://lists.swift.org/mailman/listinfo/swift-evolution 
>>>> <https://lists.swift.org/mailman/listinfo/swift-evolution>
>> 
>> _______________________________________________
>> swift-evolution mailing list
>> swift-evolution@swift.org <mailto:swift-evolution@swift.org>
>> https://lists.swift.org/mailman/listinfo/swift-evolution 
>> <https://lists.swift.org/mailman/listinfo/swift-evolution>
> _______________________________________________
> swift-evolution mailing list
> swift-evolution@swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

Reply via email to