4

I am trying to generate a number of series of double random numbers with high precision. For example, 0.856365621 (has 9 digits after decimal).

I've found some methods from internet, however, they do generate double random number, but the precision is not as good as I request (only 6 digits after the decimal).

Thus, may I know how to achieve my goal?

Robert Harvey
  • 178,213
  • 47
  • 333
  • 501
ChangeMyName
  • 7,018
  • 14
  • 56
  • 93
  • 2
    Can you demonstrate the methods you have tried so we know what you have tried. – Shafik Yaghmour Aug 08 '13 at 16:48
  • 3
    Are you sure you're not just _printing_ the numbers with the default 6 digits of precision? – Useless Aug 08 '13 at 16:51
  • http://stackoverflow.com/q/1340729 – Robert Harvey Aug 08 '13 at 16:55
  • You need 52 random bits for full double precision, so you'll need a PRNG at least that large, or else you'll have to call a smaller PRNG more than once to get a value of at least 52 bits, then you can do the division or move bits into the double value directly. – Lee Daniel Crocker Aug 08 '13 at 22:52
  • "Generating random doubles" is typically fraught with problems. There are as many doubles between 0.25 and 0.5 as there are between 0.5 and 1.0. Should the chance of getting result `x` depend on the value of `x`? If it doesn't, the chance of a result between 0.25 and 0.5 would then be equal to the chance of a result between 0.5 and 1. – MSalters Aug 09 '13 at 07:56
  • It has been a while, I am curious if you had any questions or whether my answer covered everything. – Shafik Yaghmour Nov 10 '14 at 20:23

4 Answers4

5

In C++11 you can using the <random> header and in this specific example using std::uniform_real_distribution I am able to generate random numbers with more than 6 digits. In order to see set the number of digits that will be printed via std::cout we need to use std::setprecision:

#include <iostream>
#include <random>
#include <iomanip>    

int main()
{
    std::random_device rd;

    std::mt19937 e2(rd());

    std::uniform_real_distribution<> dist(1, 10);

    for( int i = 0 ; i < 10; ++i )
    {
       std::cout << std::fixed << std::setprecision(10) << dist(e2) << std::endl ;
    }

    return 0 ;
}

you can use std::numeric_limits::digits10 to determine the precision available.

std::cout << std::numeric_limits<double>::digits10 << std::endl;
Shafik Yaghmour
  • 154,301
  • 39
  • 440
  • 740
  • I also have similar question [here](http://stackoverflow.com/questions/35258164/how-to-prevent-numbers-from-showing-up-in-scientific-notations) If possible can you help me out? – user1950349 Feb 14 '16 at 19:22
1

In a typical system, RAND_MAX is 231-1 or something similar to that. So your "precision" from using a method like:L

 double r = rand()/RAND_MAX;

would be 1/(2<sup>31</sup)-1 - this should give you 8-9 digits "precision" in the random number. Make sure you print with high enough precision:

 cout << r << endl;

will not do. This will work better:

 cout << fixed << sprecision(15) << r << endl; 

Of course, there are some systems out there with much smaller RAND_MAX, in which case the results may be less "precise" - however, you should still get digits down in the 9-12 range, just that they are more likely to be "samey".

Mats Petersson
  • 126,704
  • 14
  • 140
  • 227
-1

Why not create your value out of multiple calls of the random function instead?

For instance:

   const int numDecimals = 9;

   double result = 0.0;
   double div = 1.0;
   double mul = 1.0;
   for (int n = 0; n < numDecimals; ++n)
   {
      int t = rand() % 10;
      result += t * mul;
      mul *= 10.0;
      div /= 10.0;
   }    
   result = result * div;

I would personally try a new implementation of the rand function though or at least multiply with the current time or something..

MasterPlanMan
  • 992
  • 7
  • 14
  • 1
    I can see why this would get voted down, because the other answers use more "official" methods designed for the question, from standard library, etc. However, I voted it up because I'm using MQL5, a derivative of C++, whose only random generator function produces a random integer from 0 to 32767 (= (2^15)-1). Far too low. So I've adapted this idea -- randomly generate a string of digits any length I want -- to solve my problem, more reliably (and arguably more randomly also), than anything else I can find or think of. I will post my solution as an answer in case it helps anyone. – DavidT Mar 14 '22 at 23:18
-1

In my case, I'm using MQL5, a very close derivative of C++ for a specific market, whose only random generator produces a random integer from 0 to 32767 (= (2^15)-1). Far too low precision.

So I've adapted his idea -- randomly generate a string of digits any length I want -- to solve my problem, more reliably (and arguably more randomly also), than anything else I can find or think of. My version builds a string and converts it to a double at the end -- avoids any potential math/rounding errors along the way (because we all know 0.1 + 0.2 != 0.3 )

Posting it here in case it helps anyone.

(Disclaimer: The following is valid MQL5. MQL5 and C++ are very close, but some differences. eg. No RAND_MAX constant (so I've hard-coded the 32767). I'm not entirely sure of all the differences, so there may be C++ syntax errors here. Please adapt accordingly).

const int RAND_MAX_INCL = 32767;
const int RAND_MAX_EXCL = RAND_MAX_INCL + 1;

int iRandomDigit() {
    const double dRand = rand()/RAND_MAX_EXCL;  // double 0.0 <= dRand < 1.0
    return (int)(dRand * 10); // int 0 <= result < 10
};

double dRandom0IncTo1Exc(const int iPrecisionDigits) {
    int iPrecisionDigits2 = iPrecisionDigits;
    if ( iPrecisionDigits > DBL_DIG ) { // DBL_DIG == "Number of significant decimal digits for double type"
        Print("WARNING: Can't generate random number with precision > ", DBL_DIG, ". Adjusted precision to ", DBL_DIG, " accordingly.");
        iPrecisionDigits2 = DBL_DIG;
    };
    string sDigits = "";
    for (int i = 0; i < iPrecisionDigits2; i++) {
        sDigits += (string)iRandomDigit();
    };
    const string sResult = "0." + sDigits;
    const double dResult = StringToDouble(sResult);
    return dResult;
}

Noted in a comment on @MasterPlanMan's answer -- the other answers use more "official" methods designed for the question, from standard library, etc. However, I think conceptually it's a good solution when faced with limitations that the other answers can't address.

E_net4
  • 27,810
  • 13
  • 101
  • 139
DavidT
  • 655
  • 7
  • 19
  • Instead of creating a string (expensive and weird), you can do some math to get higher precision. For example, something like rand()/32768 + rand()/(32768*32768) – Joe C. May 09 '22 at 00:55
  • @Joe C. Indeed. But have you actually tried that? I explored various different math options (including your example) but they don’t provide evenly spread results. It’s similar to how repeatedly rolling two dice produces a lot more sevens than twos or twelves. The method above is guaranteed to be evenly spread. Not sure if you’re the downvoter. If you are, perhaps you might reconsider. – DavidT May 09 '22 at 13:38
  • There are still better options, for example, off the top of my head, you can do something like this between the 2 rand() calls: repeat (rand()%10) times: rand(), which will shake things up – Joe C. May 09 '22 at 20:09
  • @Joe C. Context: I mentioned I tried & failed with a bunch of math possibilities. But I didn’t find myself too surprised. I’ve forgotten most of my college math statistics as it was many many years ago, but I’m still pretty sure that any effort to mathematically combine additions/multiples of a rand() function will skew the results away from an even distribution (like the dice example). Plus, rand() is only pseudo- in almost all languages anyway, which the digit by digit approach also mitigates. I’m not saying this approach is the be all & end all, simply an option that does work… – DavidT May 10 '22 at 00:48
  • …(logically & practically), and does address those issues reliably, so is suitable for situations where the other answers can't be used. I say all that to then add: I’m sorry, I’m not really following your example. Do you have a numerical/math method that you’re certain addresses those issues? Could you post some actual tested code? … Unless, you’re proposing an alternative digit by digit approach, multiplying each digit by successive powers of 10 instead of concatenating them as strings…? If so, that's basically @ MasterPlanMan's answer...? Should work. Is it somehow intrinsically better? – DavidT May 10 '22 at 01:02