[FIX][BUG] Set>>atRandom: is not random

Lothar Schenk lothar.schenk at gmx.de
Thu Feb 26 20:22:49 UTC 2004


The problem still persists in a 3.7a image. Samir's explanation is correct. 
The current implementation picks a random element in the array internal to 
Set, and if this element is nil it starts to scan for a non-nil element from 
there. This leads to a non-uniform distribution of the sampled elements when 
nil-elements are present.

I have attached a fix.

Regards, Lothar

==============================================
Subject:		[BUG] Set>>atRandom: is not random
Author:		Samir Saidani
Date Posted: 26 June 2003
Archive ID: 10798
Comments:	Here is a little piece of code to reproduce the bug: 

|s a|
s_ Set new add: 'a'; add: 'b'; yourself.
a_Random new.
i_0.
500 timesRepeat: [ ((s atRandom: a)='a') ifTrue:[ i_i+1 ]. ].
Transcript show: i; cr.

Results (~100) show that you have 1/5 to have the first element.

A workaround is to change a set as an array (probability is 1/2).

|s a|
s_ Set new add: 'a'; add: 'b'; yourself.
a_Random new.
i_0.
500 timesRepeat: [ ((s asArray atRandom: a)='a') ifTrue:[ i_i+1 ]. ].
Transcript show: i; cr.

Don't have time for the moment to fix it, but certainly due to the
"array" representation of a set (Set(1,2) appears as an array of size
5 #(nil 1 2 nil nil nil).

-- 
Samir SAIDANI				
-------------- next part --------------
'From Squeak3.7alpha of 11 September 2003 [latest update: #5707] on 26 February 2004 at 9:04:27 pm'!

!Set methodsFor: 'accessing' stamp: 'los 2/26/2004 21:00'!
atRandom: aGenerator
	"Answer a random element of the receiver.  Uses aGenerator which
	should be kept by the user in a variable and used every time. Use
	this instead of #atRandom for better uniformity of random numbers 
	because only you use the generator.  Causes an error if self has no 
	elements."
	"The implementation of Set uses an internal Array (inst var: array)
	which may contain nil elements (i.e. empty slots), which must be ignored."
	
	| ind nonNilCounter |
	
	self emptyCheck.
	
	ind _ aGenerator nextInt: self size. "We are looking for the ind-th non-nil element in array"
	
	nonNilCounter := 0.
	1 to: array size do: [ :slot |
		(array at: slot) isNil ifFalse: [ nonNilCounter := nonNilCounter + 1.
								      (nonNilCounter = ind) ifTrue: [ ^ array at: slot ] ] ].
	
	"We have less than ind non-nil elements: this shouldnt happen"
	self error: 'Inconsistent number of elements in Set'! !



More information about the Squeak-dev mailing list