[gnumeric] random: fix long double and win32 cases.
- From: Morten Welinder <mortenw src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnumeric] random: fix long double and win32 cases.
- Date: Fri, 6 Aug 2010 14:27:32 +0000 (UTC)
commit 47f396dc78ccd391346e7894932ccf70eddb740e
Author: Morten Welinder <terra gnome org>
Date: Fri Aug 6 10:27:12 2010 -0400
random: fix long double and win32 cases.
ChangeLog | 8 ++++++
src/gnm-random.c | 66 +++++++++++++++++++++++++++++++++++++++++++++++++-----
2 files changed, 68 insertions(+), 6 deletions(-)
---
diff --git a/ChangeLog b/ChangeLog
index ed004bf..9f9107e 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,11 @@
+2010-08-06 Morten Welinder <terra gnome org>
+
+ * src/gnm-random.c (random_01_mersenne): Produce full precision
+ for long double case.
+ (mt_setup_win32): New function.
+ (random_01_determine): Try mt_setup_win32 on Win32. Might fix
+ 533779.
+
2010-08-05 Morten Welinder <terra gnome org>
* src/value.c (value_new_from_string): Quiet warning.
diff --git a/src/gnm-random.c b/src/gnm-random.c
index 6bf6cef..3cd6587 100644
--- a/src/gnm-random.c
+++ b/src/gnm-random.c
@@ -7,6 +7,9 @@
#include "gnm-random.h"
#include "mathfunc.h"
#include <glib/gstdio.h>
+#ifdef G_OS_WIN32
+#include <windows.h>
+#endif
#include <fcntl.h>
#include <unistd.h>
@@ -200,7 +203,6 @@ double genrand_real3(void)
return (((double)genrand_int32()) + 0.5)*(1.0/4294967296.0);
/* divided by 2^32 */
}
-#endif
/* generates a random number on [0,1) with 53-bit resolution*/
static double genrand_res53(void)
@@ -209,6 +211,7 @@ static double genrand_res53(void)
return(a*67108864.0+b)*(1.0/9007199254740992.0);
}
/* These real versions are due to Isaku Wada, 2002/01/09 added */
+#endif
#if 0
int main(void)
@@ -253,14 +256,58 @@ mt_setup_seed (const char *seed)
g_free (longs);
}
+#ifdef G_OS_WIN32
+
+static gboolean
+mt_setup_win32 (void)
+{
+ /* See http://msdn.microsoft.com/en-us/library/Aa387694 */
+ typedef BOOLEAN (CALLBACK* LPFNRTLGENRANDOM) (void*,ULONG);
+ LPFNRTLGENRANDOM MyRtlGenRandom;
+ unsigned long buffer[256];
+ HMODULE hmod;
+ gboolean res = FALSE;
+
+ hmod = GetModuleHandle ("ADVAPI32.DLL");
+ if (!hmod)
+ return FALSE;
+
+ MyRtlGenRandom = (LPFNRTLGENRANDOM)
+ GetProcAddress(hmod, "SystemFunction036");
+ if (MyRtlGenRandom &&
+ MyRtlGenRandom (buffer, sizeof (buffer))) {
+ mt_init_by_array (buffer, G_N_ELEMENTS (buffer));
+ res = TRUE;
+ }
+
+ FreeLibrary (hmod);
+
+ return res;
+}
+
+#endif
+
+/* ------------------------------------------------------------------------ */
+
static gnm_float
random_01_mersenne (void)
{
- /*
- * Only 52-bit precision. But hey, if you are using pseudo
- * random numbers that ought to be good enough to you.
- */
- return genrand_res53 ();
+ size_t N = (sizeof (gnm_float) + sizeof (guint32) - 1) / sizeof (guint32);
+ gnm_float res;
+
+ do {
+ size_t n;
+
+ res = 0;
+ for (n = 0; n < N; n++)
+ res = (res + genrand_int32()) / 4294967296.0;
+ /*
+ * It is conceivable that rounding turned the result
+ * into 1, so repeat in that case.
+ */
+ } while (res >= 1);
+
+ return res;
}
/* ------------------------------------------------------------------------ */
@@ -324,6 +371,13 @@ random_01_determine (void)
return;
}
+#ifdef G_OS_WIN32
+ if (mt_setup_win32 ()) {
+ random_src = RS_MERSENNE;
+ return;
+ }
+#endif
+
random_device_file = g_fopen (RANDOM_DEVICE, "rb");
if (random_device_file) {
random_src = RS_DEVICE;
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]