[前][次][番号順一覧][スレッド一覧]

ruby-changes:25074

From: nobu <ko1@a...>
Date: Tue, 9 Oct 2012 18:01:51 +0900 (JST)
Subject: [ruby-changes:25074] nobu:r37126 (trunk): array.c: use rb_random_ulong_limited

nobu	2012-10-09 18:01:40 +0900 (Tue, 09 Oct 2012)

  New Revision: 37126

  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=rev&revision=37126

  Log:
    array.c: use rb_random_ulong_limited
    
    * array.c (rb_ary_sample): use rb_random_ulong_limited, since
      precision of long may be larger than double.

  Modified files:
    trunk/ChangeLog
    trunk/NEWS
    trunk/array.c
    trunk/test/ruby/test_array.rb
    trunk/test/ruby/test_rand.rb

Index: array.c
===================================================================
--- array.c	(revision 37125)
+++ array.c	(revision 37126)
@@ -3996,7 +3996,7 @@
     (argc > 0 && !NIL_P((opts) = rb_check_hash_type(argv[argc-1])) && (--argc, 1))
 static VALUE sym_random;
 
-#define RAND_UPTO(max) (long)(rb_random_real(randgen)*(max))
+#define RAND_UPTO(max) (long)rb_random_ulong_limited((randgen), (max)-1)
 
 /*
  *  call-seq:
@@ -4091,7 +4091,7 @@
     VALUE nv, result, *ptr;
     VALUE opts, randgen = rb_cRandom;
     long n, len, i, j, k, idx[10];
-    double rnds[numberof(idx)];
+    long rnds[numberof(idx)];
 
     if (OPTHASH_GIVEN_P(opts)) {
 	randgen = rb_hash_lookup2(opts, sym_random, randgen);
@@ -4104,11 +4104,11 @@
 	    i = 0;
 	}
 	else {
-	    double x = rb_random_real(randgen);
-	    if ((len = RARRAY_LEN(ary)) == 0) return Qnil;
-	    i = (long)(x * len);
+	    i = RAND_UPTO(len);
+	    if ((len = RARRAY_LEN(ary)) <= i) return Qnil;
+	    ptr = RARRAY_PTR(ary);
 	}
-	return RARRAY_PTR(ary)[i];
+	return ptr[i];
     }
     rb_scan_args(argc, argv, "1", &nv);
     n = NUM2LONG(nv);
@@ -4116,27 +4116,37 @@
     if (n > len) n = len;
     if (n <= numberof(idx)) {
 	for (i = 0; i < n; ++i) {
-	    rnds[i] = rb_random_real(randgen);
+	    rnds[i] = RAND_UPTO(len - i);
 	}
     }
+    k = len;
     len = RARRAY_LEN(ary);
     ptr = RARRAY_PTR(ary);
+    if (len < k) {
+	if (n <= numberof(idx)) {
+	    for (i = 0; i < n; ++i) {
+		if (rnds[i] >= len) {
+		    return rb_ary_new2(0);
+		}
+	    }
+	}
+    }
     if (n > len) n = len;
     switch (n) {
       case 0:
 	return rb_ary_new2(0);
       case 1:
-	i = (long)(rnds[0] * len);
+	i = rnds[0];
 	return rb_ary_new4(1, &ptr[i]);
       case 2:
-	i = (long)(rnds[0] * len);
-	j = (long)(rnds[1] * (len-1));
+	i = rnds[0];
+	j = rnds[1];
 	if (j >= i) j++;
 	return rb_ary_new3(2, ptr[i], ptr[j]);
       case 3:
-	i = (long)(rnds[0] * len);
-	j = (long)(rnds[1] * (len-1));
-	k = (long)(rnds[2] * (len-2));
+	i = rnds[0];
+	j = rnds[1];
+	k = rnds[2];
 	{
 	    long l = j, g = i;
 	    if (j >= i) l = i, g = ++j;
@@ -4147,9 +4157,9 @@
     if (n <= numberof(idx)) {
 	VALUE *ptr_result;
 	long sorted[numberof(idx)];
-	sorted[0] = idx[0] = (long)(rnds[0] * len);
+	sorted[0] = idx[0] = rnds[0];
 	for (i=1; i<n; i++) {
-	    k = (long)(rnds[i] * --len);
+	    k = rnds[i];
 	    for (j = 0; j < i; ++j) {
 		if (k < sorted[j]) break;
 		++k;
Index: ChangeLog
===================================================================
--- ChangeLog	(revision 37125)
+++ ChangeLog	(revision 37126)
@@ -1,5 +1,8 @@
-Tue Oct  9 17:59:00 2012  Nobuyoshi Nakada  <nobu@r...>
+Tue Oct  9 18:01:37 2012  Nobuyoshi Nakada  <nobu@r...>
 
+	* array.c (rb_ary_sample): use rb_random_ulong_limited, since
+	  precision of long may be larger than double.
+
 	* random.c (rb_random_ulong_limited): new function to return a random
 	  value from 0 upto limit as unsigned long, simillary to
 	  rb_genrand_ulong_limited but with arbitrary RNG object.
Index: NEWS
===================================================================
--- NEWS	(revision 37125)
+++ NEWS	(revision 37126)
@@ -17,6 +17,11 @@
 
 * builtin classes
 
+  * Array
+    * incompatible changes:
+      * random parameter of Array#shuffle! and Array#sample now
+        will be called with one argument, maximum value.
+
   * Enumerable
     * added method:
       * added Enumerable#lazy method for lazy enumeration.
Index: test/ruby/test_array.rb
===================================================================
--- test/ruby/test_array.rb	(revision 37125)
+++ test/ruby/test_array.rb	(revision 37126)
@@ -2019,15 +2019,15 @@
   def test_sample_random
     ary = (0...10000).to_a
     assert_raise(ArgumentError) {ary.sample(1, 2, random: nil)}
-    gen0 = proc do
-      0.5
+    gen0 = proc do |max|
+      (max+1)/2
     end
     class << gen0
       alias rand call
     end
-    gen1 = proc do
+    gen1 = proc do |max|
       ary.replace([])
-      0.5
+      (max+1)/2
     end
     class << gen1
       alias rand call
Index: test/ruby/test_rand.rb
===================================================================
--- test/ruby/test_rand.rb	(revision 37125)
+++ test/ruby/test_rand.rb	(revision 37126)
@@ -170,8 +170,9 @@
 
   def test_shuffle
     srand(0)
-    assert_equal([1,4,2,5,3], [1,2,3,4,5].shuffle)
-    assert_equal([1,4,2,5,3], [1,2,3,4,5].shuffle(random: Random.new(0)))
+    result = [*1..5].shuffle
+    assert_equal([*1..5], result.sort)
+    assert_equal(result, [*1..5].shuffle(random: Random.new(0)))
   end
 
   def test_big_seed

--
ML: ruby-changes@q...
Info: http://www.atdot.net/~ko1/quickml/

[前][次][番号順一覧][スレッド一覧]