/* * Copyright (C) 2010 Julien BLACHE * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include #include #include #include #include #include "rng.h" /* Park & Miller Minimal Standard PRNG * w/ Bays-Durham shuffle * From Numerical Recipes in C, 2nd ed. */ static int32_t rng_rand_internal(int32_t *seed) { int32_t hi; int32_t lo; int32_t res; hi = *seed / 127773; lo = *seed % 127773; res = 16807 * lo - 2836 * hi; if (res < 0) res += 0x7fffffffL; /* 2147483647 */ *seed = res; return res; } void rng_init(struct rng_ctx *ctx) { int32_t val; int i; gcry_randomize(&ctx->seed, sizeof(ctx->seed), GCRY_STRONG_RANDOM); /* Load the shuffle array - first 8 iterations discarded */ for (i = sizeof(ctx->iv) / sizeof(ctx->iv[0]) + 7; i >= 0; i--) { val = rng_rand_internal(&ctx->seed); if (i < sizeof(ctx->iv) / sizeof(ctx->iv[0])) ctx->iv[i] = val; } ctx->iy = ctx->iv[0]; } int32_t rng_rand(struct rng_ctx *ctx) { int i; /* Select return value */ i = ctx->iy / (1 + (0x7fffffffL - 1) / (sizeof(ctx->iv) / sizeof(ctx->iv[0]))); ctx->iy = ctx->iv[i]; /* Refill */ ctx->iv[i] = rng_rand_internal(&ctx->seed); return ctx->iy; } /* Integer in [min, max[, min >= 0 */ int32_t rng_rand_range(struct rng_ctx *ctx, int32_t min, int32_t max) { int32_t res; int32_t range; range = max - min; res = rng_rand(ctx); res = (int32_t)((double)range * ((1.0 / 2147483647.0) * (double)res)); if (min > 0) res += min; return res; } /* Fisher-Yates shuffling algorithm * Durstenfeld in-place shuffling variant */ void shuffle_ptr(struct rng_ctx *ctx, void **values, int len) { int i; int32_t j; void *tmp; for (i = len - 1; i > 0; i--) { j = rng_rand_range(ctx, 0, i + 1); tmp = values[i]; values[i] = values[j]; values[j] = tmp; } }