changeset 17662:0b7f5c56f853

Allow randperm to work with bigger inputs (bug #39378) * rand.cc (Frandperm): Remove restriction on maximum size of m. Wrap the allocation of idx in a try-catch block. Allocate a smaller idx in the catch block. Add a test.
author Jordi Gutiérrez Hermoso <jordigh@octave.org>
date Tue, 15 Oct 2013 14:48:48 -0400
parents 1978a6c76aa9
children 7975d75f933c
files libinterp/corefcn/rand.cc
diffstat 1 files changed, 18 insertions(+), 2 deletions(-) [+]
line wrap: on
line diff
--- a/libinterp/corefcn/rand.cc	Tue Oct 15 11:09:07 2013 -0700
+++ b/libinterp/corefcn/rand.cc	Tue Oct 15 14:48:48 2013 -0400
@@ -1157,7 +1157,7 @@
 
       // Quick and dirty heuristic to decide if we allocate or not the
       // whole vector for tracking the truncated shuffle.
-      bool short_shuffle = m < n/5 && m < 1e5;
+      bool short_shuffle = m < n/5;
 
       if (! error_state)
         {
@@ -1166,7 +1166,20 @@
           double *rvec = r.fortran_vec ();
 
           octave_idx_type idx_len = short_shuffle ? m : n;
-          Array<octave_idx_type> idx (dim_vector (1, idx_len));
+          Array<octave_idx_type> idx;
+          try
+            {
+              idx = Array<octave_idx_type> (dim_vector (1, idx_len));
+            }
+          catch(std::bad_alloc)
+            {
+              // Looks like n is too big and short_shuffle is false.
+              // Let's try again, but this time with the alternative.
+              idx_len = m;
+              short_shuffle = true;
+              idx = Array<octave_idx_type> (dim_vector (1, idx_len));
+            }
+
           octave_idx_type *ivec = idx.fortran_vec ();
 
           for (octave_idx_type i = 0; i < idx_len; i++)
@@ -1231,6 +1244,9 @@
 %!assert (sort (randperm (20)), 1:20)
 %!assert (length (randperm (20,10)), 10)
 
+## Test biggish N (bug #39378)
+%!assert (length (randperm(30000^2, 100000)), 100000);
+
 %!test
 %! rand ("seed", 0);
 %! for i = 1:100