From 3bcbb1615b907c8b81ff5fcf274ff2ac83137316 Mon Sep 17 00:00:00 2001
From: Mark Olesen <Mark.Olesen@esi-group.com>
Date: Tue, 12 Jun 2018 08:16:06 +0200
Subject: [PATCH] ENH: improve uniformity of Random::position<label>()  
 (closes #865)

- start/end values were underrepresented due to rounding.
  Now extend the range to include -0.5 and +0.5 beyond the usual
  range to ensure the same number density.
---
 applications/test/Random/Test-Random.C        | 16 ++++++++++-
 .../primitives/random/Random/Random.C         | 28 ++++++++++---------
 2 files changed, 30 insertions(+), 14 deletions(-)

diff --git a/applications/test/Random/Test-Random.C b/applications/test/Random/Test-Random.C
index b4bd2f25522..a724fe83577 100644
--- a/applications/test/Random/Test-Random.C
+++ b/applications/test/Random/Test-Random.C
@@ -174,7 +174,21 @@ int main(int argc, char *argv[])
         }
     }
 
-    cout<< nl << "Done." << endl;
+    // Test uniformity of random
+    {
+        List<label> samples(20, Zero);
+
+        Random rnd(123456);
+        for (label i=0; i < 1000*samples.size(); ++i)
+        {
+            ++samples[rnd.position<label>(0,19)];
+        }
+
+        Info<< nl << "uniform [0,20)" << nl << "  "
+            << flatOutput(samples) << nl;
+    }
+
+    Info<< nl << "Done." << endl;
 
     return 0;
 }
diff --git a/src/OpenFOAM/primitives/random/Random/Random.C b/src/OpenFOAM/primitives/random/Random/Random.C
index 307fcb0eb1b..ed09267b126 100644
--- a/src/OpenFOAM/primitives/random/Random/Random.C
+++ b/src/OpenFOAM/primitives/random/Random/Random.C
@@ -121,14 +121,16 @@ Foam::scalar Foam::Random::position
 template<>
 Foam::label Foam::Random::position(const label& start, const label& end)
 {
-    return start + round(scalar01()*(end - start));
+    // Extend range from [0, N-1] to (-0.5, N-0.5) to ensure that round()
+    // results in the same number density at the ends.
+    return start + round(scalar01()*((end - start) + 0.998) - 0.499);
 }
 
 
 template<>
 Foam::scalar Foam::Random::globalSample01()
 {
-    scalar value = -GREAT;
+    scalar value(-GREAT);
 
     if (Pstream::master())
     {
@@ -144,7 +146,7 @@ Foam::scalar Foam::Random::globalSample01()
 template<>
 Foam::label Foam::Random::globalSample01()
 {
-    label value = labelMin;
+    label value(labelMin);
 
     if (Pstream::master())
     {
@@ -160,7 +162,7 @@ Foam::label Foam::Random::globalSample01()
 template<>
 Foam::scalar Foam::Random::globalGaussNormal()
 {
-    scalar value = -GREAT;
+    scalar value(-GREAT);
 
     if (Pstream::master())
     {
@@ -176,16 +178,16 @@ Foam::scalar Foam::Random::globalGaussNormal()
 template<>
 Foam::label Foam::Random::globalGaussNormal()
 {
-    scalar value = -GREAT;
+    label value(labelMin);
 
     if (Pstream::master())
     {
-        value = GaussNormal<scalar>();
+        value = GaussNormal<label>();
     }
 
     Pstream::scatter(value);
 
-    return round(value);
+    return value;
 }
 
 
@@ -196,16 +198,16 @@ Foam::scalar Foam::Random::globalPosition
     const scalar& end
 )
 {
-    scalar value = -GREAT;
+    scalar value(-GREAT);
 
     if (Pstream::master())
     {
-        value = scalar01()*(end - start);
+        value = position<scalar>(start, end);
     }
 
     Pstream::scatter(value);
 
-    return start + value;
+    return value;
 }
 
 
@@ -216,16 +218,16 @@ Foam::label Foam::Random::globalPosition
     const label& end
 )
 {
-    label value = labelMin;
+    label value(labelMin);
 
     if (Pstream::master())
     {
-        value = round(scalar01()*(end - start));
+        value = position<label>(start, end);
     }
 
     Pstream::scatter(value);
 
-    return start + value;
+    return value;
 }
 
 
-- 
GitLab