Commits

vrld  committed 2b3afd9

Add random([[min], max]) and random_normal([o]).

Little helpers for drawing numbers from bounded uniform and Gaussian
distributions.

  • Participants
  • Parent commits 05f0d0e

Comments (3)

  1. Boolsheet

    math.cpp:28: msvc throws a warning about the precision loss for the double->float cast. LOVE_M_PI is a double literal. Cast it to float perhaps?

    math.h:117: That probably should be random_gaussian.

    And there's the precision problem thing with (float)RAND_MAX + 1.0f again. I guess it doesn't really matter here, it just irks me that the "[0:1)" in the comment only holds true on Windows.

    1. vrld author

      And there's the precision problem thing with (float)RAND_MAX + 1.0f again.

      GCC 4.6.3 on the other hand warns about float(RAND_MAX + 1):

      warning: integer overflow in expression [-Woverflow]

      1. Boolsheet

        Hah, the proper OS really go to the max.

        What I meant is that in probably all cases (float)RAND_MAX + 1.0f == (float)RAND_MAX if RAND_MAX > (1 << 24). The RAND_MAX could be limited by LÖVE to 24 bits to solve this.

        #define LOVE_FLOAT_RAND_MASK 0xffffff
        #if RAND_MAX > LOVE_FLOAT_RAND_MASK
        #define LOVE_FLOAT_RAND_MAX LOVE_FLOAT_RAND_MASK
        #else
        #define LOVE_FLOAT_RAND_MAX RAND_MAX
        #endif
        
        inline float random()
        {
        	return float(rand() & LOVE_FLOAT_RAND_MASK) / (float(LOVE_FLOAT_RAND_MAX) + 1.0f);
        }
        

Files changed (2)

File src/common/math.cpp

+#include "math.h"
+#include <limits>
+#include <cmath>
+
+namespace
+{
+	// The Box–Muller transform generates two random numbers, one of which we cache here.
+	// A value +infinity is used to signal the cache is invalid and that new numbers have
+	// to be generated.
+	float last_randnormal = std::numeric_limits<float>::infinity();
+}
+
+namespace love
+{
+
+float random_normal(float o)
+{
+	// number in cache?
+	if (last_randnormal != std::numeric_limits<float>::infinity())
+	{
+		float r = last_randnormal;
+		last_randnormal = std::numeric_limits<float>::infinity();
+		return r * o;
+	}
+
+	// else: generate numbers using the Box-Muller transform
+	float a = sqrt(-2.0f * log(random()));
+	float b = LOVE_M_PI * 2.0f * random();
+	last_randnormal = a * cos(b);
+	return a * sin(b) * o;
+}
+
+} // namespace love

File src/common/math.h

 #define LOVE_MATH_H
 
 #include <climits> // for CHAR_BIT
+#include <cstdlib> // for rand() and RAND_MAX
 
 /* Definitions of useful mathematical constants
  * M_E        - e
 	return static_cast<float>(next_p2(static_cast<int>(x)));
 }
 
+/**
+ * Draws a random number from a uniform distribution.
+ * @returns Uniformly distributed random number in [0:1).
+ */
+inline float random()
+{
+	return float(rand()) / (float(RAND_MAX) + 1.0f);
+}
+
+/**
+ * Draws a random number from a uniform distribution.
+ * @return Uniformly distributed random number in [0:max).
+ */
+inline float random(float max)
+{
+	return random() * max;
+}
+
+/**
+ * Draws a random number from a uniform distribution.
+ * @return Uniformly distributed random number in [min:max).
+ */
+inline float random(float min, float max)
+{
+	return random(max - min) + min;
+}
+
+/**
+ * Draws a random number from a normal/gaussian distribution.
+ * @param o Standard deviation of the distribution.
+ * @returns Normal distributed random number with mean 0 and variance o^2.
+ */
+float random_normal(float o = 1.);
+#define random_gaussion random_normal
+
 } // love
 
 #endif // LOVE_MATH_H