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); }