Author: pfg
Date: Sun Dec  2 21:50:00 2012
New Revision: 1416271

URL: http://svn.apache.org/viewvc?rev=1416271&view=rev
Log:
i121421 - Calc's RAND() behaves poorly on most platforms.

The random number generation function from libc was useful for very basic 
purposes but hasn't kept up with the times.

There are many options to provide a Portable Random Number Generator: one 
of the most popular and easiest to implement was designed by B.A Wichmann
and I.D Hill in 1982.

We chose to implement the newer 2006[1] algorithm which is better suited
modern platforms and passes DIEHARD and TestU01 - Big Crush tests.

Use of libc's rand() has been completely eliminated by using preexisting
rtl/random support to generate the initial seeds.

Special thanks to orcmid@ for discussion and testing.

Reference:

[1] B. A. Wichmann and Hill, Generating good pseudorandom numbers,
    Computational Statistics & Data Analysis, Volume 51 Issue 3,
    December, 2006, Pages 1614-1622.

Modified:
    openoffice/trunk/main/sc/source/core/tool/interpr1.cxx

Modified: openoffice/trunk/main/sc/source/core/tool/interpr1.cxx
URL: 
http://svn.apache.org/viewvc/openoffice/trunk/main/sc/source/core/tool/interpr1.cxx?rev=1416271&r1=1416270&r2=1416271&view=diff
==============================================================================
--- openoffice/trunk/main/sc/source/core/tool/interpr1.cxx (original)
+++ openoffice/trunk/main/sc/source/core/tool/interpr1.cxx Sun Dec  2 21:50:00 
2012
@@ -40,6 +40,7 @@
 #include <unotools/transliterationwrapper.hxx>
 #include <rtl/ustring.hxx>
 #include <rtl/logfile.hxx>
+#include <rtl/random.h>
 #include <unicode/uchar.h>
 
 #include "interpre.hxx"
@@ -1542,7 +1543,46 @@ void ScInterpreter::ScPi()
 void ScInterpreter::ScRandom()
 {
     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScRandom" 
);
-    PushDouble((double)rand() / ((double)RAND_MAX+1.0));
+
+    static sal_Int32 aScRandomIx = 0, aScRandomIy = 0, aScRandomIz = 0, 
aScRandomIt = 0;
+    static rtlRandomPool aPool = rtl_random_createPool();
+
+    // Seeding for the PRNG: should be good enough but we
+    // monitor the values to keep things under control.
+    if (aScRandomIx <= 0)
+       rtl_random_getBytes(aPool, &aScRandomIx, sizeof(aScRandomIx));
+    if (aScRandomIy <= 0)
+       rtl_random_getBytes(aPool, &aScRandomIy, sizeof(aScRandomIy));
+    if (aScRandomIz <= 0)
+       rtl_random_getBytes(aPool, &aScRandomIz, sizeof(aScRandomIz));
+    if (aScRandomIt <= 0)
+       rtl_random_getBytes(aPool, &aScRandomIt, sizeof(aScRandomIt));
+    
+    // Basically unmodified algorithm from
+    // Wichman and Hill, "Generating good pseudo-random numbers",
+    //         December 5, 2005.
+
+    double aScRandomW;
+    
+    aScRandomIx = 11600L * (aScRandomIx % 185127L) - 10379L * (aScRandomIx / 
185127L);
+    aScRandomIy = 47003L * (aScRandomIy %  45688L) - 10479L * (aScRandomIy /  
45688L);
+    aScRandomIz = 23000L * (aScRandomIz %  93368L) - 19423L * (aScRandomIz /  
93368L);
+    aScRandomIt = 33000L * (aScRandomIt %  65075L) -  8123L * (aScRandomIt /  
65075L);
+    if (aScRandomIx < 0)
+       aScRandomIx += 2147483579L;
+    if (aScRandomIy < 0)
+       aScRandomIy += 2147483543L;
+    if (aScRandomIz < 0)
+       aScRandomIz += 2147483123L;
+    if (aScRandomIt < 0)
+       aScRandomIt += 2147483123L;
+
+    aScRandomW = 
(double)aScRandomIx*0.0000000004656613022697297188506231646486 +
+               (double)aScRandomIy*0.0000000004656613100759859932486569933169 +
+               (double)aScRandomIz*0.0000000004656613360968421314794009471615 +
+               (double)aScRandomIt*0.0000000004656614011489951998100056779817;
+
+    PushDouble(aScRandomW - (sal_Int64)aScRandomW);
 }
 
 


Reply via email to