Problems with pseudo-random number generation
-
Hi all,
I'm developing a windows application to inject faults in VHDL models running in ModelSim. Among other utilities, the application has to "randomly" (pseudo-randomly, actually) generate a simulation script from a configuration file in XML. The algorithm has to calculate "randomly" the targets where to inject, the instant(s) to inject the fault, the duration of the faults injected, etc. Then, the application will launch ModelSim (as a Tcp server) running this script to perform the fault injection.
Anyway, for obvious reasons, the simulation script generated for a particular injection campaign configuration of a VHDL model should be alway the same, no matter when it is generated. That's to say, if I run the application n times and I generate the injection script for the same model and using the same configuration file, I should get always the same script. And of course, if I generate the script several times in the same execution of the application, I also should get the same script.
So, I've looked for the proper method to do, and I've tried this:
#include <QtGlobal> ... // This is the slot associated to the "Generate injection macro" option of the application void MainWindow::on_actionGenerate_injection_macro_triggered() { // I use "0" as seed to guarantee the repeatability of the execution qsrand(0); // Read the XML configuration file and save the the configuration on an private object, called "InjConf" ReadInjectionParametersFromQDom(); // Generate the script GenerateInjectionMacros(); } ... void MainWindow::GenerateInjectionMacros() { // Here, and in other related functions called from this, there are multiple calls to "qrand()" to generate the required "random" values explained above }
However, surprisingly, I get absolutely different scripts whenever I run the algorithm. It doesn't matter if I do in the same program execution or in different executions separated one minute or one hour. It's always different! Can anyone tell me why, please? What am I doing wrong?
It's crazy. I've tried this because people in the forum has been warning (for a long time) about this fact to other colleagues that tried to get "real" random sequences, and I (that I really want absolute repeatability in the output sequences) don't get it.
In fact, I've observed that, if I put
qsrand(0);
several times (one, two, three, ...), and I then generate a sequence of n random numbers, I get different sequences depending on the number of qsrand calls.
I hope it is easy to solve. By the way, I'm working with Qt 4.8.1.
Thanks and regards,
P.S. Sorry for the sooooo long explanation.
-
Hi again aha_ 1980, and thank you for your quick answer.
Maybe I've found the mistake? when copying the code to answer you.
I need to generate "random" values according to different distribution functions (Uniform, Gaussian, Exponential, Weibull, etc.), although the most usual is the Uniform (in fact, it's the only one I've used so far). So, I've implemented this:
// It's in the same main unit as "GenerateInjectionMacro" in my previous message. int MainWindow::Uniform(double lowerlimit, double upperlimit) { double val = static_cast<double>(qrand()) / RAND_MAX; // Random number in the range [0, 1) return static_cast<int>((val * (upperlimit + 1 - lowerlimit)) + lowerlimit); } void MainWindow::GenerateInjectionMacros() { ... // Generate target int target = Uniform(0, (targetList.size() - 1)); ... // And so on with the other parameters... }
To generate a simple sequence of pseudo-random integers (for instance from 1 to 10) I simply do this (just like I've seen in the examples):
QList<int> random_list; qsrand(0); for (int i = 0; (i < 10); i++) random_list << ((qrand() % 10 + 1);
This works ok. But, if I calculate every random number like in "Uniform" function (that's to say, "((qrand() / RAND_MAX) * 10 + 1)"), then it doesn't work.
The problem is that I need the random number between [0, 1) to apply to other distribution functions...
Any idea about what's the mistake?
Regards,
-
Hi,
I've changed Uniform function like this:
int MainWindow::Uniform(double lowerlimit, double upperlimit) { int range = static_cast<int>(upperlimit - lowerlimit + 1); return static_cast<int>((rand() % range) + lowerlimit); }
but surprinsingly the scripts still are different.
Even I've checked that I only seed once (just in case...). Now I'm really shocked.
Regards,
-
Hi Leonardo,
As far as I know, I only have a thread in my application, at least in this part... Are there ways to manage threads other than explicitly using QThread? If not, so I just have a thread.
Anyway, in another slot I run a QProcess to launch the simulator to run in parallel with the application and then both applications communicate (with TcpSockets) to perform the fault injection. But I wouldn't call this a "thread", would you? And this does not affect this particular slot activation, does it?
So, unless threads are generated indirectly, when chosing option "Generate injection macro" in the main window, the "on_actionGenerate_injection_macro_triggered" slot is executed, sequentially:
- seeding to 0,
- reading the XML configuration file, and
- calling "GenerateInjectionMacro" function which, in turn, and depending on the configuration file, may call other functions to generate randonmly different aspects of the simulation, as I mentionned in my first post: injection target(s) (and, if an injection target selected is multibit, i.e. a register or a memory, the different indexes are generated too), injection instant, fault duration, fault model, etc.
Actually, I call qsrand() and qrand() in different functions, called from "GenerateInjectionMacro", but I think thay are in the same thread. How could I confirm?
How about moving qsrand() to "GenerateInjectionMacro"? I actually haven't tried this because it seems silly...
And how about creating an object that would perform all random functions? If the seeding is performed in the class constructor, I might declare an instance of this object and destroy in "GenerateInjectionMacro", so every time I would run "GenerateInjectionMacro" I would have a 0-reseeded object.
Regards, and thanks for your interest,
JCBaraza
-
Hi all,
I've solved on my own the problem with pseudo-random generation. It's the most ridiculous solution ever, but it finally works. I don't know if it's due to a side effect or whatever else, but I've just moved the seed initialisation (qsrand(0)) from the slot (on_actionGenerate_injection_macro_triggered()) to the function where the script is generated (i.e. GenerateInjectionMacros()), and voilà. The magic is made. Now, every time I generate the macro for the same model and configuration, I get the same script.
Abracadabra...
Regards,