Kaydet (Commit) 564fc483 authored tarafından Michael Stahl's avatar Michael Stahl

tdf#90110: basic: fix Randomize statement

- time() is used to seed the RNG but since it only has second resolution,
  the same values will be generated if it's called multiple times like
  in the bug report

- BASIC using the global rng would be fine except that BASIC Randomize
  takes an optional parameter to set the seed, which should continue
  to be supported, but should not affect the RNG state for non-BASIC
  users of comphelper::random

(regression from df466d79,
 but the old implementation was even more delightfully absurd,
 where Randomize was essentially srand((sal_uInt16)rand()) ...)

Change-Id: I0f30e509de08f933c02ac77c5d932b20e79586c5
üst e1b1f953
......@@ -30,7 +30,6 @@
#include <com/sun/star/uno/XInterface.hpp>
#include <com/sun/star/util/DateTime.hpp>
#include <comphelper/processfactory.hxx>
#include <comphelper/random.hxx>
#include <comphelper/string.hxx>
#include <config_features.h>
#include <config_version.h>
......@@ -46,6 +45,7 @@
#include <osl/file.hxx>
#include <osl/process.h>
#include <osl/time.h>
#include <random>
#include <rtl/character.hxx>
#include <rtl/instance.hxx>
#include <rtl/math.hxx>
......
......@@ -47,7 +47,6 @@
#include "errobject.hxx"
#include <comphelper/processfactory.hxx>
#include <comphelper/random.hxx>
#include <comphelper/string.hxx>
#include <com/sun/star/uno/Sequence.hxx>
......@@ -61,6 +60,8 @@
#include <boost/scoped_array.hpp>
#include <boost/scoped_ptr.hpp>
#include <random>
using namespace comphelper;
using namespace osl;
using namespace com::sun::star;
......@@ -3518,6 +3519,38 @@ RTLFUNC(Format)
}
}
namespace {
// note: BASIC does not use comphelper::random, because
// Randomize(int) must be supported and should not affect non-BASIC random use
struct RandomNumberGenerator
{
std::mt19937 global_rng;
RandomNumberGenerator()
{
try
{
std::random_device rd;
// initialises the state of the global random number generator
// should only be called once.
// (note, a few std::variate_generator<> (like normal) have their
// own state which would need a reset as well to guarantee identical
// sequence of numbers, e.g. via myrand.distribution().reset())
global_rng.seed(rd() ^ time(nullptr));
}
catch (std::runtime_error& e)
{
SAL_WARN("basic", "Using std::random_device failed: " << e.what());
global_rng.seed(time(nullptr));
}
}
};
class theRandomNumberGenerator : public rtl::Static<RandomNumberGenerator, theRandomNumberGenerator> {};
}
RTLFUNC(Randomize)
{
(void)pBasic;
......@@ -3531,12 +3564,9 @@ RTLFUNC(Randomize)
if( rPar.Count() == 2 )
{
nSeed = (int)rPar.Get(1)->GetInteger();
theRandomNumberGenerator::get().global_rng.seed(nSeed);
}
else
{
nSeed = (int)time(NULL);
}
comphelper::rng::reseed(nSeed);
// without parameter, no need to do anything - RNG is seeded at first use
}
RTLFUNC(Rnd)
......@@ -3550,7 +3580,9 @@ RTLFUNC(Rnd)
}
else
{
rPar.Get(0)->PutDouble(comphelper::rng::uniform_real_distribution());
std::uniform_real_distribution<double> dist(0.0, 1.0);
double const tmp(dist(theRandomNumberGenerator::get().global_rng));
rPar.Get(0)->PutDouble(tmp);
}
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment