[RUBY] how do generate a random number w specific distribution ( which library ?)

I know how to generate a random number between 1 and 2 :

def random return (1 + rand(2)) end

but let's say I would like to return 1 in 80% of the calls and 2 in 20% of the call... which library should I use ? ( I've seen a lot at http://raa.ruby-lang.org/ )

thanks for your suggestions

No doubt there are better ways but something like (rand(100) + 120)/100 should do it.

Colin

Well, perhaps something that reveals the intention better:

def usually_one    rand < 0.80 ? 1 : 2 end

-Rob

Rob Biedenharn Rob@AgileConsultingLLC.com http://AgileConsultingLLC.com/ rab@GaslightSoftware.com http://GaslightSoftware.com/

I know how to generate a random number between 1 and 2 :

def random return (1 + rand(2))

No it doesn't actually. 1 + rand would be better, though it depends what you mean by *between* whether even that is correct.

end

but let's say I would like to return 1 in 80% of the calls and 2 in 20% of the call... which library should I use ? ( I've seen a lot at http://raa.ruby-lang.org/ )

No doubt there are better ways but something like (rand(100) + 120)/100 should do it.

Colin

Well, perhaps something that reveals the intention better:

def usually_one rand < 0.80 ? 1 : 2 end

Yes, much better. I suppose it is the old programmer in me instinctively avoiding floating point to save on processor time. A bit silly when everything has hardware floating point.

Colin

Although I prefer Rob's suggestion as a better example of self documented code; this is another alternative...

  def usually_one     [1,2,2,2,2][rand(5)]   end

...there's many ways to skin a cat :slight_smile:

*ahem* of course.. this is the total opposite of what the OP asked for, and returns 1 in 20% of the calls :smiley:

sorry for not paying attention.... oops!

def usually_one rand < 0.80 ? 1 : 2 end

Yes, much better. I suppose it is the old programmer in me instinctively avoiding floating point to save on processor time. A bit silly when everything has hardware floating point.

Although I prefer Rob's suggestion as a better example of self documented code; this is another alternative...

def usually_one [1,2,2,2,2][rand(5)] end

Ha! Vindicated

ruby-1.8.7-p302 > begin ruby-1.8.7-p302 > t=Time.now ruby-1.8.7-p302 ?> 1000000.times{(rand(100) + 120)/100} ruby-1.8.7-p302 ?> puts Time.now-t ruby-1.8.7-p302 ?> end 0.905431

ruby-1.8.7-p302 > begin ruby-1.8.7-p302 > t=Time.now ruby-1.8.7-p302 ?> 1000000.times{rand < 0.80 ? 1 : 2} ruby-1.8.7-p302 ?> puts Time.now-t ruby-1.8.7-p302 ?> end 1.712769

ruby-1.8.7-p302 > begin ruby-1.8.7-p302 > t=Time.now ruby-1.8.7-p302 ?> 1000000.times{ [1,2,2,2,2][rand(5)] } ruby-1.8.7-p302 ?> puts Time.now-t ruby-1.8.7-p302 ?> end 1.150481

...there's many ways to skin a cat :slight_smile:

But how fast can you do it?

Colin

Ha! Vindicated

I expected to get different times, but to keep the proportions the same... but I get a little difference in order of speed:

begin

?> t=Time.now

1000000.times{(rand(100) + 120)/100} puts Time.now-t end

1.200484

begin

?> t=Time.now

1000000.times{rand < 0.80 ? 1 : 2} puts Time.now-t end

1.249109

begin

?> t=Time.now

1000000.times{[1,2,2,2,2][rand(5)]} puts Time.now-t end

1.498434

...there's many ways to skin a cat :slight_smile:

But how fast can you do it?

A fair bit faster if I don't build the array in every loop :wink:

x=[1,2,2,2,2]

=> [1, 2, 2, 2, 2]

begin

?> t=Time.now

1000000.times{x[rand(5)]} puts Time.now-t end

1.026202

OK, I admit defeat. I am using ruby 1.8.7 which may be the reason for the different ratios you are seeing (assuming you are using 1.9.2). Interestingly the benefit of your technique is even greater on 1.8.7, taking only 0.67 secs on my machine.

Colin

Nah! Who cares if it takes half-a-second or a second to select a million random numbers.... any of the methods are perfect for selecting one number.

Was a nice distraction from the recent run of posts...

OK, I admit defeat. the benefit of your technique is even greater on 1.8.7, taking only 0.67 secs on my machine.

Nah! Who cares if it takes half-a-second or a second to select a million random numbers.... any of the methods are perfect for selecting one number.

The OP might be doing some statistical simulation, so might need millions of values, but probably not.

Colin

def usually_one

rand < 0.80 ? 1 : 2

end

Yes, much better. I suppose it is the old programmer in me

instinctively avoiding floating point to save on processor time. A

bit silly when everything has hardware floating point.

Although I prefer Rob’s suggestion as a better example of self

documented code; this is another alternative…

def usually_one

[1,2,2,2,2][rand(5)]

end

Ha! Vindicated

ruby-1.8.7-p302 > begin

ruby-1.8.7-p302 > t=Time.now

ruby-1.8.7-p302 ?> 1000000.times{(rand(100) + 120)/100}

ruby-1.8.7-p302 ?> puts Time.now-t

ruby-1.8.7-p302 ?> end

0.905431

ruby-1.8.7-p302 > begin

ruby-1.8.7-p302 > t=Time.now

ruby-1.8.7-p302 ?> 1000000.times{rand < 0.80 ? 1 : 2}

ruby-1.8.7-p302 ?> puts Time.now-t

ruby-1.8.7-p302 ?> end

1.712769

ruby-1.8.7-p302 > begin

ruby-1.8.7-p302 > t=Time.now

ruby-1.8.7-p302 ?> 1000000.times{ [1,2,2,2,2][rand(5)] }

ruby-1.8.7-p302 ?> puts Time.now-t

ruby-1.8.7-p302 ?> end

1.150481

Here’s my number from within and outside IRB from Mac OS 10.6.6:

ruby-1.9.2-head :001 > begin

ruby-1.9.2-head :002 > t=Time.now

ruby-1.9.2-head :003?> 1000000.times{(rand(100) + 120)/100}

ruby-1.9.2-head :004?> puts Time.now-t

ruby-1.9.2-head :005?> end

from-irb: 0.16657 from-ruby-script: 0.159452

ruby-1.9.2-head :006 > begin

ruby-1.9.2-head :007 > t=Time.now

ruby-1.9.2-head :008?> 1000000.times{rand < 0.80 ? 1 : 2}

ruby-1.9.2-head :009?> puts Time.now-t

ruby-1.9.2-head :010?> end

from-irb: 0.280634 from-ruby-script: 0.150247

ruby-1.9.2-head :011 > begin

ruby-1.9.2-head :012 > t=Time.now

ruby-1.9.2-head :013?> 1000000.times{[1,2,2,2,2][rand(5)]}

ruby-1.9.2-head :014?> puts Time.now-t

ruby-1.9.2-head :015?> end

from-irb: 0.521992 from-ruby-script: 0.35944

-Conrad

>>> def usually_one >>> rand < 0.80 ? 1 : 2 >>> end >> >> Yes, much better. I suppose it is the old programmer in me >> instinctively avoiding floating point to save on processor time. A >> bit silly when everything has hardware floating point. > > Although I prefer Rob's suggestion as a better example of self > documented code; this is another alternative... > > def usually_one > [1,2,2,2,2][rand(5)] > end >

Ha! Vindicated

ruby-1.8.7-p302 > begin ruby-1.8.7-p302 > t=Time.now ruby-1.8.7-p302 ?> 1000000.times{(rand(100) + 120)/100} ruby-1.8.7-p302 ?> puts Time.now-t ruby-1.8.7-p302 ?> end 0.905431

ruby-1.8.7-p302 > begin ruby-1.8.7-p302 > t=Time.now ruby-1.8.7-p302 ?> 1000000.times{rand < 0.80 ? 1 : 2} ruby-1.8.7-p302 ?> puts Time.now-t ruby-1.8.7-p302 ?> end 1.712769

ruby-1.8.7-p302 > begin ruby-1.8.7-p302 > t=Time.now ruby-1.8.7-p302 ?> 1000000.times{ [1,2,2,2,2][rand(5)] } ruby-1.8.7-p302 ?> puts Time.now-t ruby-1.8.7-p302 ?> end 1.150481

Here's my number from within and outside IRB from Mac OS 10.6.6: ruby-1.9.2-head :001 > begin ruby-1.9.2-head :002 > t=Time.now ruby-1.9.2-head :003?> 1000000.times{(rand(100) + 120)/100} ruby-1.9.2-head :004?> puts Time.now-t ruby-1.9.2-head :005?> end from-irb: 0.16657 from-ruby-script: 0.159452

I think I need a new laptop.

Colin

I use this often:

class Uuid   def self.uuid     return rand( 18446744073709551615 ).to_s( 36 ).rjust( 13, '0' )   end end

See T R U C K — Truck No. 3: Generate a unique ID

Nice, simple process (assuming it works... I've not tried it), but I don't think it has much to do with the topic of this thread, and it's not likely to create a *real* UUID (RFC4122) is it?

This old thread discusses it a bit:

Colin Law wrote in post #987114:

But how fast can you do it?

Ooh, that's an evil tweak... (a minor diversion which is much more fun than what I was doing)

Lenovo T61p, Core2Duo, T9300, 2.5GHz, ruby 1.9.2-p0

= 0.253025

And for curiosity, my Ubuntu 10.10 VM on top of the same hardware:

= 0.323791

I don't think it makes a true UUID, but I've run it into the billions and never got a repeat. So, effectively, it acts like UUID.