Skip to content

Commit

Permalink
Merge pull request topazproject#551 from jstepien/random-rand
Browse files Browse the repository at this point in the history
Random#rand
  • Loading branch information
alex committed Mar 29, 2013
2 parents 2f081a0 + 86bc8ca commit b4720cf
Show file tree
Hide file tree
Showing 2 changed files with 69 additions and 31 deletions.
27 changes: 2 additions & 25 deletions spec/tags/core/random/rand_tags.txt
Original file line number Diff line number Diff line change
@@ -1,29 +1,6 @@
fails:Random.rand returns a Float if no max argument is passed
fails:Random.rand returns a Float >= 0 if no max argument is passed
fails:Random.rand returns a Float < 1 if no max argument is passed
fails:Random.rand returns the same sequence for a given seed if no max argument is passed
fails:Random.rand returns a Integer if an Integer argument is passed
fails:Random.rand returns an Integer >= 0 if an Integer argument is passed
fails:Random.rand returns an Integer < the max argument if an Integer argument is passed
fails:Random.rand returns the same sequence for a given seed if an Integer argument is passed
fails:Random.rand coerces arguments to Integers with #to_int
fails:Random#rand with Fixnum returns an Integer
fails:Random#rand with Fixnum returns a Fixnum greater than or equal to 0
fails:Random#rand with Fixnum returns a Fixnum less than the argument
fails:Random#rand with Fixnum returns the same sequence for a given seed
fails:Random#rand with Fixnum eventually returns all possible values
fails:Random#rand with Bignum typically returns a Bignum
fails:Random#rand with Bignum returns a Bignum greater than or equal to 0
fails:Random#rand with Bignum returns a Bignum less than the argument
fails:Random#rand with Bignum returns the same sequence for a given seed
fails:Random#rand with Float returns a Float
fails:Random#rand with Float returns a Float greater than or equal to 0.0
fails:Random#rand with Float returns a Float less than the argument
fails:Random#rand with Float returns the same sequence for a given seed
fails:Random#rand with Range returns an element from the Range
fails:Random#rand with Range returns an object that is a member of the Range
fails:Random#rand with Range works with inclusive ranges
fails:Random#rand with Range works with exclusive ranges
fails:Random#rand with Range returns the same sequence for a given seed
fails:Random#rand with Range eventually returns all possible values
fails:Random#rand with Range considers Integers as Floats if one end point is a float
fails:Random#rand with Bignum raises an ArgumentError when the argument is negative
fails:Random#rand with Range raises an ArgumentError when the endpoint lacks #+ and #- methods
73 changes: 67 additions & 6 deletions topaz/objects/randomobject.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,80 @@

from topaz.module import ClassDef
from topaz.objects.objectobject import W_Object
from topaz.objects.rangeobject import W_RangeObject
from topaz.coerce import Coerce


class W_RandomObject(W_Object):
classdef = ClassDef("Random", W_Object.classdef, filepath=__file__)

def __init__(self, space, klass=None):
def __init__(self, space, seed=0, klass=None):
W_Object.__init__(self, space, klass)
self.random = Random(abs(seed))

@classdef.setup_class
def setup_class(cls, space, w_cls):
default = space.send(w_cls, space.newsymbol("new"))
space.set_const(w_cls, "DEFAULT", default)

@classdef.singleton_method("allocate", seed="int")
def method_allocate(self, space, seed=0):
return W_RandomObject(space, seed, self)

@classdef.method("initialize")
def method_initialize(self, space, w_seed=None):
pass

@classdef.method("srand")
def method_srand(self, space, args_w):
self.random = Random()

@classdef.singleton_method("allocate")
def method_allocate(self, space):
return W_RandomObject(space, self)
@classdef.singleton_method("srand")
def method_singleton_srand(self, space, args_w):
default = space.find_const(self, "DEFAULT")
return space.send(default, space.newsymbol("srand"), args_w)

@classdef.method("rand")
def method_rand(self, space):
return space.newfloat(self.random.random())
def method_rand(self, space, w_max=None):
if w_max is None:
return space.newfloat(self.random.random())
elif space.is_kind_of(w_max, space.w_float):
return self._rand_float(space, w_max)
elif space.is_kind_of(w_max, space.getclassfor(W_RangeObject)):
return self._rand_range(space, w_max)
else:
return self._rand_int(space, w_max)

@classdef.singleton_method("rand")
def method_singleton_rand(self, space, args_w):
default = space.find_const(self, "DEFAULT")
return space.send(default, space.newsymbol("rand"), args_w)

def _rand_range(self, space, range):
random = self.random.random()
first = space.send(range, space.newsymbol("first"))
last = space.send(range, space.newsymbol("last"))
if space.is_true(space.send(range, space.newsymbol("include?"), [last])):
last = space.send(last, space.newsymbol("+"), [space.newint(1)])
diff = space.send(last, space.newsymbol("-"), [first])
offset = space.send(diff, space.newsymbol("*"), [space.newfloat(random)])
choice = space.send(offset, space.newsymbol("+"), [first])
if (not space.is_kind_of(first, space.w_float) and
not space.is_kind_of(last, space.w_float)):
choice = space.send(choice, space.newsymbol("to_i"))
return choice

def _rand_float(self, space, float):
random = self.random.random()
max = Coerce.float(space, float)
if max <= 0:
raise space.error(space.w_ArgumentError, "invalid argument")
return space.newfloat(random * max)

def _rand_int(self, space, integer):
random = self.random.random()
max = Coerce.int(space, integer)
if max <= 0:
raise space.error(space.w_ArgumentError, "invalid argument")
else:
return space.newint(int(random * max))

0 comments on commit b4720cf

Please sign in to comment.