Improved random number generation (lacking the Windows implementation which will come next).

This commit is contained in:
Moritz Bunkus 2005-05-02 13:50:23 +00:00
parent b53de99588
commit 432d6a3596
5 changed files with 203 additions and 18 deletions

View File

@ -60,6 +60,7 @@ using namespace libebml;
#include "error.h"
#include "hacks.h"
#include "mm_io.h"
#include "random.h"
int verbose = 1;
bool suppress_warnings = false;
@ -185,10 +186,7 @@ bitvalue_c::data()
void
bitvalue_c::generate_random() {
int i;
for (i = 0; i < bitsize / 8; i++)
value[i] = (unsigned char)(255.0 * rand() / RAND_MAX);
random_c::generate_bytes(value, bitsize / 8);
}
/*
@ -597,7 +595,6 @@ init_cc_stdio() {
*/
static vector<uint32_t> ru_numbers[4];
static bool random_seeded = false;
void
clear_list_of_unique_uint32(unique_id_category_e category) {
@ -661,7 +658,7 @@ remove_unique_uint32(uint32_t number,
uint32_t
create_unique_uint32(unique_id_category_e category) {
uint32_t rnumber, half;
uint32_t rnumber;
assert((category >= UNIQUE_TRACK_IDS) &&
(category <= UNIQUE_ATTACHMENT_IDS));
@ -671,16 +668,8 @@ create_unique_uint32(unique_id_category_e category) {
return ru_numbers[category].size();
}
if (!random_seeded) {
srand(time(NULL));
random_seeded = true;
}
do {
half = (uint32_t)(65535.0 * rand() / RAND_MAX);
rnumber = half;
half = (uint32_t)(65535.0 * rand() / RAND_MAX);
rnumber |= (half << 16);
rnumber = random_c::generate_32bits();
} while ((rnumber == 0) || !is_unique_uint32(rnumber, category));
add_unique_uint32(rnumber, category);

118
src/common/random.cpp Normal file
View File

@ -0,0 +1,118 @@
/*
mkvmerge -- utility for splicing together matroska files
from component media subtypes
Distributed under the GPL
see the file COPYING for details
or visit http://www.gnu.org/copyleft/gpl.html
$Id$
random number generating functions
Written by Moritz Bunkus <moritz@bunkus.org>.
*/
#include "os.h"
#if !defined(SYS_WINDOWS)
# include <sys/time.h>
# include <time.h>
#endif
#include "mm_io.h"
#include "random.h"
#if defined(SYS_WINDOWS)
#else // defined(SYS_WINDOWS)
bool random_c::m_seeded = false;
auto_ptr<mm_file_io_c> random_c::m_dev_urandom;
bool random_c::m_tried_dev_urandom = false;
void
random_c::generate_bytes(void *destination,
int num_bytes) {
int i;
try {
if (!m_tried_dev_urandom) {
m_tried_dev_urandom = true;
m_dev_urandom =
auto_ptr<mm_file_io_c>(new mm_file_io_c("/dev/urandom", MODE_READ));
}
if ((NULL != m_dev_urandom.get()) &&
(m_dev_urandom->read(destination, num_bytes) == num_bytes))
return;
} catch(...) {
}
if (!m_seeded) {
struct timeval tv;
gettimeofday(&tv, NULL);
srand(tv.tv_usec + tv.tv_sec);
m_seeded = true;
}
for (i = 0; i < num_bytes; ++i)
((unsigned char *)destination)[i] =
(unsigned char)(256.0 * rand() / (RAND_MAX + 1.0));
}
#endif // defined(SYS_WINDOWS)
void
random_c::test() {
uint32_t n, ranges[16], i, k;
const int num = 1000000;
bool found;
for (i = 0; i < 16; i++)
ranges[i] = 0;
for (i = 0; i < num; i++) {
n = random_c::generate_32bits();
found = false;
for (k = 1; k <= 15; ++k)
if (n < (k * 0x10000000)) {
++ranges[k - 1];
found = true;
break;
}
if (!found)
++ranges[15];
}
for (i = 0; i < 16; i++)
printf("%0d: %d (%.2f%%)\n", i, ranges[i],
(double)ranges[i] * 100.0 / num);
#if !defined(SYS_WINDOWS)
m_tried_dev_urandom = true;
m_dev_urandom = auto_ptr<mm_file_io_c>(NULL);
for (i = 0; i < 16; i++)
ranges[i] = 0;
for (i = 0; i < num; i++) {
n = random_c::generate_32bits();
found = false;
for (k = 1; k <= 15; ++k)
if (n < (k * 0x10000000)) {
++ranges[k - 1];
found = true;
break;
}
if (!found)
++ranges[15];
}
for (i = 0; i < 16; i++)
printf("%0d: %d (%.2f%%)\n", i, ranges[i],
(double)ranges[i] * 100.0 / num);
#endif
exit(0);
}

78
src/common/random.h Normal file
View File

@ -0,0 +1,78 @@
/*
mkvmerge -- utility for splicing together matroska files
from component media subtypes
Distributed under the GPL
see the file COPYING for details
or visit http://www.gnu.org/copyleft/gpl.html
$Id$
definitions for random number generating functions
Written by Moritz Bunkus <moritz@bunkus.org>.
*/
#ifndef __RANDOM_H
#define __RANDOM_H
#include "os.h"
#include "mm_io.h"
#include "smart_pointers.h"
class MTX_DLL_API random_c {
private:
#if !defined(SYS_WINDOWS)
static bool m_seeded;
static auto_ptr<mm_file_io_c> m_dev_urandom;
static bool m_tried_dev_urandom;
#endif
public:
static void generate_bytes(void *destination, int num_bytes);
static uint8_t generate_8bits() {
uint8_t b;
generate_bytes(&b, 1);
return b;
}
static int16_t generate_15bits() {
return (int16_t)(generate_16bits() & 0x7fff);
}
static uint16_t generate_16bits() {
uint16_t b;
generate_bytes(&b, 2);
return b;
}
static int32_t generate_31bits() {
return (int32_t)(generate_32bits() & 0x7fffffff);
}
static uint32_t generate_32bits() {
uint32_t b;
generate_bytes(&b, 4);
return b;
}
static int64_t generate_63bits() {
return (int64_t)(generate_64bits() & 0x7fffffffffffull);
}
static uint64_t generate_64bits() {
uint64_t b;
generate_bytes(&b, 8);
return b;
}
static void test();
};
#endif // __RANDOM_H

View File

@ -14,6 +14,7 @@
#include "common.h"
#include "commonebml.h"
#include "random.h"
#include "xtr_ogg.h"
@ -61,7 +62,7 @@ xtr_oggbase_c::create_file(xtr_base_c *_master,
if (no_variable_data)
ogg_stream_init(&os, 1804289383);
else
ogg_stream_init(&os, rand());
ogg_stream_init(&os, random_c::generate_31bits());
}
void
@ -172,7 +173,7 @@ xtr_oggflac_c::create_file(xtr_base_c *_master,
if (no_variable_data)
ogg_stream_init(&os, 1804289383);
else
ogg_stream_init(&os, rand());
ogg_stream_init(&os, random_c::generate_31bits());
// Handle the three header packets: Headers, comments, codec
// setup data.

View File

@ -1947,7 +1947,6 @@ setup() {
#endif
mm_file_io_c::setup();
srand(time(NULL));
cc_local_utf8 = utf8_init("");
init_cc_stdio();