| /* | |
| Creation, 2020: | |
| - New random number generator using a mersenne twister + tweaked lemire | |
| postprocessor. This fixed a convergence issue on windows targets for | |
| libsvm and liblinear. | |
| Sylvain Marie, Schneider Electric | |
| See <https://github.com/scikit-learn/scikit-learn/pull/13511#issuecomment-481729756> | |
| */ | |
| extern "C" { | |
| // Scikit-Learn-specific random number generator replacing `rand()` originally | |
| // used in LibSVM / LibLinear, to ensure the same behaviour on windows-linux, | |
| // with increased speed | |
| // - (1) Init a `mt_rand` object | |
| std::mt19937 mt_rand(std::mt19937::default_seed); | |
| // - (2) public `set_seed()` function that should be used instead of `srand()` to set a new seed. | |
| void set_seed(unsigned custom_seed) { | |
| mt_rand.seed(custom_seed); | |
| } | |
| // - (3) New internal `bounded_rand_int` function, used instead of rand() everywhere. | |
| inline uint32_t bounded_rand_int(uint32_t range) { | |
| // "LibSVM / LibLinear Original way" - make a 31bit positive | |
| // random number and use modulo to make it fit in the range | |
| // return abs( (int)mt_rand()) % range; | |
| // "Better way": tweaked Lemire post-processor | |
| // from http://www.pcg-random.org/posts/bounded-rands.html | |
| uint32_t x = mt_rand(); | |
| uint64_t m = uint64_t(x) * uint64_t(range); | |
| uint32_t l = uint32_t(m); | |
| if (l < range) { | |
| uint32_t t = -range; | |
| if (t >= range) { | |
| t -= range; | |
| if (t >= range) | |
| t %= range; | |
| } | |
| while (l < t) { | |
| x = mt_rand(); | |
| m = uint64_t(x) * uint64_t(range); | |
| l = uint32_t(m); | |
| } | |
| } | |
| return m >> 32; | |
| } | |
| } | |