Thread: Numerical Recipe Problem

  1. #1
    Registered User
    Join Date
    Oct 2012
    Posts
    13

    Numerical Recipe Problem

    Hello guys

    To use on my codes, I found a pseudo-random number generator .h and .c files on the internet.
    prng.c: http://benpfaff.org/writings/clc/prng.c
    prng.h: http://benpfaff.org/writings/clc/prng.h

    I just saved and put them into my working directory. And then made a simple code to test them. Run my small code with "gcc rt.c -o rt -lm", on the gcc (using ubuntu)

    Code:
    //gcc rt.c -o rt -lm
    
    #include "prng.h" 
    #include <stdio.h> 
    #include <stdlib.h> 
    #include <math.h> 
    
    int main(void) 
    {
        double x;
        x=prng_get_double();
        printf("I got a random number: %lf",x);
    }
    Output is:
    /tmp/ccherC4G.o: In function `main':
    rt.c.text+0x9): undefined reference to `prng_get_double'
    collect2: ld returned 1 exit status

    Seems like my code couldn't run the header file functions. What should I do?

    By the way:
    prng.h:
    Code:
    #ifndef PRNG_H_INCLUDED
    #define PRNG_H_INCLUDED
    
    #include <stddef.h>
    
    void prng_seed_time (void);
    void prng_seed_bytes (const void *, size_t);
    unsigned char prng_get_octet (void);
    unsigned char prng_get_byte (void);
    void prng_get_bytes (void *, size_t);
    unsigned long prng_get_ulong (void);
    long prng_get_long (void);
    unsigned prng_get_uint (void);
    int prng_get_int (void);
    double prng_get_double (void);
    double prng_get_double_normal (void);
    
    #endif /* prng.h */
    prng.c:
    Code:
    /*
     * prng.c - Portable, ISO C90 and C99 compliant high-quality
     * pseudo-random number generator based on the alleged RC4
     * cipher.  This PRNG should be suitable for most general-purpose
     * uses.  Not recommended for cryptographic or financial
     * purposes.  Not thread-safe.
     */
    
    /*
     * Copyright (c) 2004 Ben Pfaff <[email protected]>.
     * All rights reserved.
     * 
     * Redistribution and use in source and binary forms, with or
     * without modification, are permitted provided that the
     * following conditions are met:
     *
     * 1. Redistributions of source code must retain the above
     * copyright notice, this list of conditions and the following
     * disclaimer.
     *
     * 2. Redistributions in binary form must reproduce the above
     * copyright notice, this list of conditions and the following
     * disclaimer in the documentation and/or other materials
     * provided with the distribution.
     *
     * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS
     * IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
     * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT
     * SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
     * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
     * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
     * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
     * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
     * OF SUCH DAMAGE.
     * 
     */
    
    #include "prng.h"
    #include <assert.h>
    #include <float.h>
    #include <limits.h>
    #include <math.h>
    #include <time.h>
    
    /* RC4-based pseudo-random state. */
    static unsigned char s[256];
    static int s_i, s_j;
    
    /* Nonzero if PRNG has been seeded. */
    static int seeded;
    
    /* Swap bytes that A and B point to. */
    #define SWAP_BYTE(A, B)                         \
            do {                                    \
                    unsigned char swap_temp = *(A); \
                    *(A) = *(B);                    \
                    *(B) = swap_temp;               \
            } while (0)
    
    /* Seeds the pseudo-random number generator based on the current
       time.
    
       If the user calls neither this function nor prng_seed_bytes()
       before any prng_get*() function, this function is called
       automatically to obtain a time-based seed. */
    void
    prng_seed_time (void) 
    {
      static time_t t;
      if (t == 0)
        t = time (NULL);
      else
        t++;
    
      prng_seed_bytes (&t, sizeof t);
    }
    
    /* Retrieves one octet from the array BYTES, which is N_BYTES in
       size, starting at an offset of OCTET_IDX octets.  BYTES is
       treated as a circular array, so that accesses past the first
       N_BYTES bytes wrap around to the beginning. */
    static unsigned char
    get_octet (const void *bytes_, size_t n_bytes, size_t octet_idx) 
    {
      const unsigned char *bytes = bytes_;
      if (CHAR_BIT == 8) 
        return bytes[octet_idx % n_bytes];
      else 
        {
          size_t first_byte = octet_idx * 8 / CHAR_BIT % n_bytes;
          size_t start_bit = octet_idx * 8 % CHAR_BIT;
          unsigned char c = (bytes[first_byte] >> start_bit) & 255;
    
          size_t bits_filled = CHAR_BIT - start_bit;
          if (CHAR_BIT % 8 != 0 && bits_filled < 8)
            {
              size_t bits_left = 8 - bits_filled;
              unsigned char bits_left_mask = (1u << bits_left) - 1;
              size_t second_byte = first_byte + 1 < n_bytes ? first_byte + 1 : 0;
    
              c |= (bytes[second_byte] & bits_left_mask) << bits_filled;
            }
    
          return c;
        }
    }
    
    /* Seeds the pseudo-random number based on the SIZE bytes in
       KEY.  At most the first 2048 bits in KEY are used. */
    void
    prng_seed_bytes (const void *key, size_t size) 
    {
      int i, j;
    
      assert (key != NULL && size > 0);
    
      for (i = 0; i < 256; i++) 
        s[i] = i;
      for (i = j = 0; i < 256; i++) 
        {
          j = (j + s[i] + get_octet (key, size, i)) & 255;
          SWAP_BYTE (s + i, s + j);
        }
    
      s_i = s_j = 0;
      seeded = 1;
    }
    
    /* Returns a pseudo-random integer in the range [0, 255]. */
    unsigned char
    prng_get_octet (void)
    {
      if (!seeded) 
        prng_seed_time ();
    
      s_i = (s_i + 1) & 255;
      s_j = (s_j + s[s_i]) & 255;
      SWAP_BYTE (s + s_i, s + s_j);
    
      return s[(s[s_i] + s[s_j]) & 255];
    }
    
    /* Returns a pseudo-random integer in the range [0, UCHAR_MAX]. */
    unsigned char
    prng_get_byte (void) 
    {
      unsigned byte;
      int bits;
    
      byte = prng_get_octet ();
      for (bits = 8; bits < CHAR_BIT; bits += 8) 
        byte = (byte << 8) | prng_get_octet ();
      return byte;
    }
    
    /* Fills BUF with SIZE pseudo-random bytes. */
    void
    prng_get_bytes (void *buf_, size_t size) 
    {
      unsigned char *buf;
    
      for (buf = buf_; size-- > 0; buf++)
        *buf = prng_get_byte (); 
    }
    
    /* Returns a pseudo-random unsigned long in the range [0,
       ULONG_MAX]. */
    unsigned long
    prng_get_ulong (void) 
    {
      unsigned long ulng;
      size_t bits;
    
      ulng = prng_get_octet ();
      for (bits = 8; bits < CHAR_BIT * sizeof ulng; bits += 8) 
        ulng = (ulng << 8) | prng_get_octet ();
      return ulng;
    }
    
    /* Returns a pseudo-random long in the range [0, LONG_MAX]. */
    long
    prng_get_long (void) 
    {
      return prng_get_ulong () & LONG_MAX;
    }
    
    /* Returns a pseudo-random unsigned int in the range [0,
       UINT_MAX]. */
    unsigned
    prng_get_uint (void) 
    {
      unsigned uint;
      size_t bits;
    
      uint = prng_get_octet ();
      for (bits = 8; bits < CHAR_BIT * sizeof uint; bits += 8) 
        uint = (uint << 8) | prng_get_octet ();
      return uint;
    }
    
    /* Returns a pseudo-random int in the range [0, INT_MAX]. */
    int
    prng_get_int (void) 
    {
      return prng_get_uint () & INT_MAX;
    }
    
    /* Returns a pseudo-random floating-point number from the uniform
       distribution with range [0,1). */
    double
    prng_get_double (void) 
    {
      for (;;)
        {
          double dbl = prng_get_ulong () / (ULONG_MAX + 1.0);
          if (dbl >= 0.0 && dbl < 1.0)
            return dbl;
        }
    }
    
    /* Returns a pseudo-random floating-point number from the
       distribution with mean 0 and standard deviation 1.  (Multiply
       the result by the desired standard deviation, then add the
       desired mean.) */
    double 
    prng_get_double_normal (void)
    {
      /* Knuth, _The Art of Computer Programming_, Vol. 2, 3.4.1C,
         Algorithm P. */
      static int has_next = 0;
      static double next_normal;
      double this_normal;
      
      if (has_next)
        {
          this_normal = next_normal;
          has_next = 0;
        }
      else 
        {
          static double limit;
          double v1, v2, s;
    
          if (limit == 0.0)
            limit = log (DBL_MAX / 2) / (DBL_MAX / 2);
          
          for (;;)
            {
              double u1 = prng_get_double ();
              double u2 = prng_get_double ();
              v1 = 2.0 * u1 - 1.0;
              v2 = 2.0 * u2 - 1.0;
              s = v1 * v1 + v2 * v2;
              if (s > limit && s < 1)
                break;
            }
    
          this_normal = v1 * sqrt (-2. * log (s) / s);
          next_normal = v2 * sqrt (-2. * log (s) / s);
          has_next = 1;
        }
      
      return this_normal;
    }
    Thank you

  2. #2
    Registered User
    Join Date
    Sep 2012
    Posts
    357
    Try compiling both your source (containing the main() function) and the source you found on the internet

    $ gcc rt.c prng.c -Wall -o rt -lm

    Oh! I also included the option to warn about stuff gcc developers found programmers should be warned about

  3. #3
    Registered User
    Join Date
    Oct 2012
    Posts
    13
    Also fixed my small code, and used your command. It works now.
    Thank you very much

    Code:
    #include "prng.h" 
    #include <stdio.h> 
    #include <stdlib.h> 
    #include <math.h> 
    
    int main() 
    {
        double x;
        x=prng_get_double();
        printf("I got the random: %lf\n",x);
        printf("I got another random: %lf\n",prng_get_double());
        return 0;
    }

  4. #4
    Registered User
    Join Date
    Sep 2012
    Posts
    357
    The conversion "%lf" is not valid for printf() (it should be used in scanf() with pointers to doubles).
    To print a value of type double, use "%f"; you cannot print a value of type float because the value gets converted to type double before it gets to the printf() code.

  5. #5
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Quote Originally Posted by qny
    The conversion "%lf" is not valid for printf()
    It is valid for C99 onwards, but it is redundant since %f has the same meaning.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  6. #6
    Registered User
    Join Date
    Oct 2012
    Posts
    13
    Thanks again

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Numerical integration using rkf45
    By kwzeet in forum C Programming
    Replies: 4
    Last Post: 05-29-2011, 07:25 PM
  2. Why use numerical type literals?
    By indigo0086 in forum C++ Programming
    Replies: 3
    Last Post: 03-22-2008, 07:16 AM
  3. Numerical Integration
    By Crazed in forum C Programming
    Replies: 13
    Last Post: 03-03-2008, 03:01 PM
  4. problem with numerical calculations
    By phyushin in forum C++ Programming
    Replies: 4
    Last Post: 01-28-2006, 07:12 PM
  5. problem with numerical calculations
    By Calef13 in forum C++ Programming
    Replies: 4
    Last Post: 01-28-2006, 08:21 AM

Tags for this Thread