From 432d6a3596c981568624caaf7524fc9f4bea05f5 Mon Sep 17 00:00:00 2001 From: Moritz Bunkus Date: Mon, 2 May 2005 13:50:23 +0000 Subject: [PATCH] Improved random number generation (lacking the Windows implementation which will come next). --- src/common/common.cpp | 19 ++---- src/common/random.cpp | 118 +++++++++++++++++++++++++++++++++++ src/common/random.h | 78 +++++++++++++++++++++++ src/extract/xtr_ogg.cpp | 5 +- src/merge/output_control.cpp | 1 - 5 files changed, 203 insertions(+), 18 deletions(-) create mode 100644 src/common/random.cpp create mode 100644 src/common/random.h diff --git a/src/common/common.cpp b/src/common/common.cpp index 526c8fe37..3d5321de9 100644 --- a/src/common/common.cpp +++ b/src/common/common.cpp @@ -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 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); diff --git a/src/common/random.cpp b/src/common/random.cpp new file mode 100644 index 000000000..dc8ed697a --- /dev/null +++ b/src/common/random.cpp @@ -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 . +*/ + +#include "os.h" + +#if !defined(SYS_WINDOWS) +# include +# include +#endif + +#include "mm_io.h" +#include "random.h" + +#if defined(SYS_WINDOWS) + +#else // defined(SYS_WINDOWS) + +bool random_c::m_seeded = false; +auto_ptr 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(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(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); +} diff --git a/src/common/random.h b/src/common/random.h new file mode 100644 index 000000000..1ad9f06ee --- /dev/null +++ b/src/common/random.h @@ -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 . +*/ + +#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 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 diff --git a/src/extract/xtr_ogg.cpp b/src/extract/xtr_ogg.cpp index f7c2dc5b9..9514d5e94 100644 --- a/src/extract/xtr_ogg.cpp +++ b/src/extract/xtr_ogg.cpp @@ -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. diff --git a/src/merge/output_control.cpp b/src/merge/output_control.cpp index fc6168eec..e9c7de839 100644 --- a/src/merge/output_control.cpp +++ b/src/merge/output_control.cpp @@ -1947,7 +1947,6 @@ setup() { #endif mm_file_io_c::setup(); - srand(time(NULL)); cc_local_utf8 = utf8_init(""); init_cc_stdio();