You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@openoffice.apache.org by pf...@apache.org on 2013/01/25 05:47:23 UTC

svn commit: r1438322 - in /openoffice/trunk/main: sc/source/core/tool/interpr1.cxx scaddins/source/analysis/analysis.cxx

Author: pfg
Date: Fri Jan 25 04:47:23 2013
New Revision: 1438322

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

Replace WH2006 PRNG with the well known Mersenne Twister
as implemented in Boost. This actually has some drawbacks
with respect to our previous implementation: we lose the
nifty seeding and instead use the timer which is
non-optimal.

The main reason is the speed: MT is said to be at least
4 times faster.

On the other hand I also moved the WH to the scaddins
module where it is  used by Calc's RANDBETWEEN function.
This way we still have the alternative PRNG and we
drop another use of the unreliable rand from libc. 

Modified:
    openoffice/trunk/main/sc/source/core/tool/interpr1.cxx
    openoffice/trunk/main/scaddins/source/analysis/analysis.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=1438322&r1=1438321&r2=1438322&view=diff
==============================================================================
--- openoffice/trunk/main/sc/source/core/tool/interpr1.cxx (original)
+++ openoffice/trunk/main/sc/source/core/tool/interpr1.cxx Fri Jan 25 04:47:23 2013
@@ -40,7 +40,6 @@
 #include <unotools/transliterationwrapper.hxx>
 #include <rtl/ustring.hxx>
 #include <rtl/logfile.hxx>
-#include <rtl/random.h>
 #include <unicode/uchar.h>
 
 #include "interpre.hxx"
@@ -72,6 +71,9 @@
 #include "doubleref.hxx"
 #include "queryparam.hxx"
 
+#include <boost/random/mersenne_twister.hpp>
+#include <boost/random/uniform_01.hpp>
+
 #include <boost/math/special_functions/acosh.hpp>
 #include <boost/math/special_functions/asinh.hpp>
 #include <boost/math/special_functions/atanh.hpp>
@@ -1546,46 +1548,12 @@ void ScInterpreter::ScPi()
 
 void ScInterpreter::ScRandom()
 {
-    RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScRandom" );
+    RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "bst", "ScInterpreter::ScRandom" );
 
-    static sal_Int32 nScRandomIx = 0, nScRandomIy = 0, nScRandomIz = 0, nScRandomIt = 0;
-    static rtlRandomPool aPool = rtl_random_createPool();
-    double fScRandomW;
-
-    // Seeding for the PRNG: should be good enough but we
-    // monitor the values to keep things under control.
-    if (nScRandomIx <= 0)
-	rtl_random_getBytes(aPool, &nScRandomIx, sizeof(nScRandomIx));
-    if (nScRandomIy <= 0)
-	rtl_random_getBytes(aPool, &nScRandomIy, sizeof(nScRandomIy));
-    if (nScRandomIz <= 0)
-	rtl_random_getBytes(aPool, &nScRandomIz, sizeof(nScRandomIz));
-    if (nScRandomIt <= 0)
-	rtl_random_getBytes(aPool, &nScRandomIt, sizeof(nScRandomIt));
-    
-    // Basically unmodified algorithm from
-    // Wichman and Hill, "Generating good pseudo-random numbers",
-    //		December 5, 2005.
+    boost::random::mt19937 ScGen(static_cast<unsigned int>(std::time(0)));
+    static boost::uniform_01<boost::mt19937> ScZeroOne(ScGen);
     
-    nScRandomIx = 11600L * (nScRandomIx % 185127L) - 10379L * (nScRandomIx / 185127L);
-    nScRandomIy = 47003L * (nScRandomIy %  45688L) - 10479L * (nScRandomIy /  45688L);
-    nScRandomIz = 23000L * (nScRandomIz %  93368L) - 19423L * (nScRandomIz /  93368L);
-    nScRandomIt = 33000L * (nScRandomIt %  65075L) -  8123L * (nScRandomIt /  65075L);
-    if (nScRandomIx < 0)
-	nScRandomIx += 2147483579L;
-    if (nScRandomIy < 0)
-	nScRandomIy += 2147483543L;
-    if (nScRandomIz < 0)
-	nScRandomIz += 2147483123L;
-    if (nScRandomIt < 0)
-	nScRandomIt += 2147483123L;
-
-    fScRandomW = (double)nScRandomIx*0.0000000004656613022697297188506231646486 +
-	      	(double)nScRandomIy*0.0000000004656613100759859932486569933169 +
-		(double)nScRandomIz*0.0000000004656613360968421314794009471615 +
-		(double)nScRandomIt*0.0000000004656614011489951998100056779817;
-
-    PushDouble(fScRandomW - (sal_Int32)fScRandomW);
+    PushDouble(ScZeroOne());
 }
 
 

Modified: openoffice/trunk/main/scaddins/source/analysis/analysis.cxx
URL: http://svn.apache.org/viewvc/openoffice/trunk/main/scaddins/source/analysis/analysis.cxx?rev=1438322&r1=1438321&r2=1438322&view=diff
==============================================================================
--- openoffice/trunk/main/scaddins/source/analysis/analysis.cxx (original)
+++ openoffice/trunk/main/scaddins/source/analysis/analysis.cxx Fri Jan 25 04:47:23 2013
@@ -27,6 +27,7 @@
 #include <osl/diagnose.h>
 #include <rtl/ustrbuf.hxx>
 #include <rtl/math.hxx>
+#include <rtl/random.h>
 #include <string.h>
 
 #include <tools/resmgr.hxx>
@@ -808,15 +809,52 @@ double SAL_CALL AnalysisAddIn::getSqrtpi
 
 double SAL_CALL AnalysisAddIn::getRandbetween( double fMin, double fMax ) THROWDEF_RTE_IAE
 {
+    static sal_Int32 nScRandomIx = 0, nScRandomIy = 0, nScRandomIz = 0, nScRandomIt = 0;
+    static rtlRandomPool aPool = rtl_random_createPool();
+    double fScRandomW;
+
     fMin = ::rtl::math::round( fMin, 0, rtl_math_RoundingMode_Up );
     fMax = ::rtl::math::round( fMax, 0, rtl_math_RoundingMode_Up );
 	if( fMin > fMax )
 		THROW_IAE;
 
+    // Seeding for the PRNG: should be good enough but we
+    // monitor the values to keep things under control.
+    if (nScRandomIx <= 0)
+	rtl_random_getBytes(aPool, &nScRandomIx, sizeof(nScRandomIx));
+    if (nScRandomIy <= 0)
+	rtl_random_getBytes(aPool, &nScRandomIy, sizeof(nScRandomIy));
+    if (nScRandomIz <= 0)
+	rtl_random_getBytes(aPool, &nScRandomIz, sizeof(nScRandomIz));
+    if (nScRandomIt <= 0)
+	rtl_random_getBytes(aPool, &nScRandomIt, sizeof(nScRandomIt));
+    
+    // Basically unmodified algorithm from
+    // Wichman and Hill, "Generating good pseudo-random numbers",
+    //		December 5, 2005.
+    
+    nScRandomIx = 11600L * (nScRandomIx % 185127L) - 10379L * (nScRandomIx / 185127L);
+    nScRandomIy = 47003L * (nScRandomIy %  45688L) - 10479L * (nScRandomIy /  45688L);
+    nScRandomIz = 23000L * (nScRandomIz %  93368L) - 19423L * (nScRandomIz /  93368L);
+    nScRandomIt = 33000L * (nScRandomIt %  65075L) -  8123L * (nScRandomIt /  65075L);
+    if (nScRandomIx < 0)
+	nScRandomIx += 2147483579L;
+    if (nScRandomIy < 0)
+	nScRandomIy += 2147483543L;
+    if (nScRandomIz < 0)
+	nScRandomIz += 2147483123L;
+    if (nScRandomIt < 0)
+	nScRandomIt += 2147483123L;
+
+    fScRandomW = (double)nScRandomIx*0.0000000004656613022670 +
+	      	(double)nScRandomIy*0.0000000004656613100760 +
+		(double)nScRandomIz*0.0000000004656613360968 +
+		(double)nScRandomIt*0.0000000004656614011490;
+
+ 
 	// fMax -> range
     double fRet = fMax - fMin + 1.0;
-    fRet *= rand();
-    fRet /= (RAND_MAX + 1.0);
+    fRet *= fScRandomW - (sal_Int32)fScRandomW ;
     fRet += fMin;
     fRet = floor( fRet );   // simple floor is sufficient here
     RETURN_FINITE( fRet );