0

我需要在 GNU 的 c 库中使用 stdlib.h 中的函数 random(),但我在 Windows 上使用 Visual Studio 2008(我没有任何选项。是的,我也讨厌 VS,并且有更好的 RNG在那里)。当 MS 的 stdlib.h 不包含它时,有没有办法使用 GNU random() 函数?

我应该补充一点,我在 MS VS 和 C++ 方面的经验总体上是相当有限的,因为我学习了大部分 Java 编程。

4

1 回答 1

1

从这里获取源代码,然后分解 stdlib/random_r.c (random()调用random_r()所以你不需要random.c)和相关的头文件(stdlib.h) - 你可能必须从部分制作自己的头文件stdlib,也许还有其他人。

这是一个“补丁”,它可以在没有任何标准库头文件的情况下编译:

--- myrandom.c  2012-12-26 12:25:17.439514392 +0000
+++ ../glibc/stdlib/random_r.c  2012-12-26 12:29:16.581770976 +0000
@@ -51,14 +51,10 @@
  * Rewritten to be reentrant by Ulrich Drepper, 1995
  */

-#if 1
-#include "myrandom.h"
-#else
 #include <errno.h>
 #include <limits.h>
 #include <stddef.h>
 #include <stdlib.h>
-#endif


 /* An improved random number generation package.  In addition to the standard
@@ -161,7 +157,10 @@
    information a given number of times to get rid of any initial dependencies
    introduced by the L.C.R.N.G.  Note that the initialization of randtbl[]
    for default usage relies on values produced by this routine.  */
-int srandom_r (unsigned int seed, struct random_data *buf)
+int
+__srandom_r (seed, buf)
+     unsigned int seed;
+     struct random_data *buf;
 {
   int type;
   int32_t *state;
@@ -206,7 +205,7 @@
   while (--kc >= 0)
     {
       int32_t discard;
-      (void) random_r (buf, &discard);
+      (void) __random_r (buf, &discard);
     }

  done:
@@ -216,6 +215,7 @@
   return -1;
 }

+weak_alias (__srandom_r, srandom_r)


 /* Initialize the state information in the given array of N bytes for
    future random number generation.  Based on the number of bytes we
@@ -228,10 +228,12 @@
    Note: The first thing we do is save the current state, if any, just like
    setstate so that it doesn't matter when initstate is called.
    Returns 0 on success, non-zero on failure.  */
-int initstate_r (unsigned int seed, 
-        char *arg_state, 
-        size_t n, 
-        struct random_data *buf)
+int
+__initstate_r (seed, arg_state, n, buf)
+     unsigned int seed;
+     char *arg_state;
+     size_t n;
+     struct random_data *buf;
 {
   if (buf == NULL)
     goto fail;
@@ -271,7 +273,7 @@

   buf->state = state;

-  srandom_r (seed, buf);
+  __srandom_r (seed, buf);

   state[-1] = TYPE_0;
   if (type != TYPE_0)
@@ -284,6 +286,7 @@
   return -1;
 }

+weak_alias (__initstate_r, initstate_r)


 /* Restore the state from the given state array.
    Note: It is important that we also remember the locations of the pointers
@@ -293,7 +296,10 @@
    to the order in which things are done, it is OK to call setstate with the
    same state as the current state
    Returns 0 on success, non-zero on failure.  */
-int setstate_r (char *arg_state, struct random_data *buf)
+int
+__setstate_r (arg_state, buf)
+     char *arg_state;
+     struct random_data *buf;
 {
   int32_t *new_state = 1 + (int32_t *) arg_state;
   int type;
@@ -337,6 +343,7 @@
   return -1;
 }

+weak_alias (__setstate_r, setstate_r)


 /* If we are using the trivial TYPE_0 R.N.G., just do the old linear
    congruential bit.  Otherwise, we do our fancy trinomial stuff, which is the
@@ -349,7 +356,10 @@
    rear pointers can't wrap on the same call by not testing the rear
    pointer if the front one has wrapped.  Returns a 31-bit random number.  */

-int random_r (struct random_data *buf, int32_t *result)
+int
+__random_r (buf, result)
+     struct random_data *buf;
+     int32_t *result;
 {
   int32_t *state;

@@ -397,24 +407,4 @@
   return -1;
 }

-
-// Additional code to show that "it works" ... 
-static struct random_data rbuf;
-char state_array[12345];
-
-void init_myrandom(void)
-{
-    initstate_r(4711, state_array, sizeof(state_array), &rbuf);
-}
-
-int myrandom(void)
-{
-    int rc;
-    int32_t res;
-    if ((rc = random_r (&rbuf, &res)) > 0)
-    {
-   return -errno;
-    }
-    return res;
-}
-
+weak_alias (__random_r, random_r)
[MatsP@linuxhost random]$ diff -u ../glibc/stdlib/random_r.c  myrandom.c 
--- ../glibc/stdlib/random_r.c  2012-12-26 12:29:16.581770976 +0000
+++ myrandom.c  2012-12-26 12:25:17.439514392 +0000
@@ -51,10 +51,14 @@
  * Rewritten to be reentrant by Ulrich Drepper, 1995
  */

+#if 1
+#include "myrandom.h"
+#else
 #include <errno.h>
 #include <limits.h>
 #include <stddef.h>
 #include <stdlib.h>
+#endif


 /* An improved random number generation package.  In addition to the standard
@@ -157,10 +161,7 @@
    information a given number of times to get rid of any initial dependencies
    introduced by the L.C.R.N.G.  Note that the initialization of randtbl[]
    for default usage relies on values produced by this routine.  */
-int
-__srandom_r (seed, buf)
-     unsigned int seed;
-     struct random_data *buf;
+int srandom_r (unsigned int seed, struct random_data *buf)
 {
   int type;
   int32_t *state;
@@ -205,7 +206,7 @@
   while (--kc >= 0)
     {
       int32_t discard;
-      (void) __random_r (buf, &discard);
+      (void) random_r (buf, &discard);
     }

  done:
@@ -215,7 +216,6 @@
   return -1;
 }

-weak_alias (__srandom_r, srandom_r)


 /* Initialize the state information in the given array of N bytes for
    future random number generation.  Based on the number of bytes we
@@ -228,12 +228,10 @@
    Note: The first thing we do is save the current state, if any, just like
    setstate so that it doesn't matter when initstate is called.
    Returns 0 on success, non-zero on failure.  */
-int
-__initstate_r (seed, arg_state, n, buf)
-     unsigned int seed;
-     char *arg_state;
-     size_t n;
-     struct random_data *buf;
+int initstate_r (unsigned int seed, 
+        char *arg_state, 
+        size_t n, 
+        struct random_data *buf)
 {
   if (buf == NULL)
     goto fail;
@@ -273,7 +271,7 @@

   buf->state = state;

-  __srandom_r (seed, buf);
+  srandom_r (seed, buf);

   state[-1] = TYPE_0;
   if (type != TYPE_0)
@@ -286,7 +284,6 @@
   return -1;
 }

-weak_alias (__initstate_r, initstate_r)


 /* Restore the state from the given state array.
    Note: It is important that we also remember the locations of the pointers
@@ -296,10 +293,7 @@
    to the order in which things are done, it is OK to call setstate with the
    same state as the current state
    Returns 0 on success, non-zero on failure.  */
-int
-__setstate_r (arg_state, buf)
-     char *arg_state;
-     struct random_data *buf;
+int setstate_r (char *arg_state, struct random_data *buf)
 {
   int32_t *new_state = 1 + (int32_t *) arg_state;
   int type;
@@ -343,7 +337,6 @@
   return -1;
 }

-weak_alias (__setstate_r, setstate_r)


 /* If we are using the trivial TYPE_0 R.N.G., just do the old linear
    congruential bit.  Otherwise, we do our fancy trinomial stuff, which is the
@@ -356,10 +349,7 @@
    rear pointers can't wrap on the same call by not testing the rear
    pointer if the front one has wrapped.  Returns a 31-bit random number.  */

-int
-__random_r (buf, result)
-     struct random_data *buf;
-     int32_t *result;
+int random_r (struct random_data *buf, int32_t *result)
 {
   int32_t *state;

@@ -407,4 +397,24 @@
   return -1;
 }

-weak_alias (__random_r, random_r)
+
+// Additional code to show that "it works" ... 
+static struct random_data rbuf;
+char state_array[12345];
+
+void init_myrandom(void)
+{
+    initstate_r(4711, state_array, sizeof(state_array), &rbuf);
+}
+
+int myrandom(void)
+{
+    int rc;
+    int32_t res;
+    if ((rc = random_r (&rbuf, &res)) > 0)
+    {
+   return -errno;
+    }
+    return res;
+}
+

随机数.h:

#ifndef MYRANDOM_H
#define MYRANDOM_H


#define NULL 0

#define EINVAL 23

typedef int int32_t;
typedef unsigned long size_t;


struct random_data
{
    int32_t *fptr;      /* Front pointer.  */
    int32_t *rptr;      /* Rear pointer.  */
    int32_t *state;     /* Array of state values.  */
    int rand_type;      /* Type of random number generator.  */
    int rand_deg;       /* Degree of random number generator.  */
    int rand_sep;       /* Distance between front and rear.  */
    int32_t *end_ptr;       /* Pointer behind state table.  */
};


#define errno my_errno
extern int my_errno;

static inline void __set_errno(int err) { my_errno = err; };

int random_r (struct random_data *buf, int32_t *result);

int myrandom(void);
void init_myrandom();

#endif

#include <stdio.h>
#include "myrandom.h"

int my_errno;

int main()
{
    int i;
    init_myrandom();
    for(i = 0; i < 100; i++)
    {
    printf("%d\n", myrandom());
    }
    return 0;
}

我不保证这将在 Windows 系统上运行,但我会这么认为。除非有一些我没有发现的“gcc-isms”。

我或许还应该指出,标准随机中设置的状态是在random.c的第 137 行左右完成的——要获得与在 gcc 编译的系统中运行 random() 相同的值,你需要复制它。我没有这样做,而是在“init_myrandom”中组成了我自己的一组变量[可能不是最佳的]。

于 2012-12-26T02:08:41.720 回答