source: trunk/src/lol/math/rand.h @ 2536

Last change on this file since 2536 was 2536, checked in by sam, 8 years ago

math: try to refactor rand() to bypass an X360 compiler bug.

File size: 3.2 KB
Line 
1//
2// Lol Engine
3//
4// Copyright: (c) 2010-2013 Sam Hocevar <sam@hocevar.net>
5//   This program is free software; you can redistribute it and/or
6//   modify it under the terms of the Do What The Fuck You Want To
7//   Public License, Version 2, as published by Sam Hocevar. See
8//   http://www.wtfpl.net/ for more details.
9//
10
11//
12// The Random number generators
13// ----------------------------
14//
15
16#if !defined __LOL_MATH_RAND_H__
17#define __LOL_MATH_RAND_H__
18
19#include <cstdlib>
20#include <stdint.h>
21
22namespace lol
23{
24
25/* Random number generators */
26template<typename T> static inline T rand();
27template<typename T> static inline T rand(T a);
28template<typename T> static inline T rand(T a, T b);
29
30/* One-value random number generators */
31template<typename T> static inline T rand(T a)
32{
33    return rand<T>() % a;
34}
35
36template<> inline half rand<half>(half a)
37{
38    float f = (float)std::rand() / (float)RAND_MAX;
39    return (half)(a * f);
40}
41
42template<> inline float rand<float>(float a)
43{
44    float f = (float)std::rand() / (float)RAND_MAX;
45    return a * f;
46}
47
48template<> inline double rand<double>(double a)
49{
50    double f = (double)std::rand() / (double)RAND_MAX;
51    return a * f;
52}
53
54template<> inline ldouble rand<ldouble>(ldouble a)
55{
56    ldouble f = (ldouble)std::rand() / (ldouble)RAND_MAX;
57    return a * f;
58}
59
60/* Two-value random number generator -- no need for specialisation */
61template<typename T> static inline T rand(T a, T b)
62{
63    return a + rand<T>(b - a);
64}
65
66/* Default random number generator */
67template<typename T> static inline T rand()
68{
69    switch (sizeof(T))
70    {
71    case 1:
72        return static_cast<T>(std::rand() & 0x7f);
73    case 2:
74    {
75        uint16_t ret = std::rand();
76        if (RAND_MAX < 0x7fff)
77            ret = (ret << 7) ^ std::rand();
78        return static_cast<T>(ret & 0x7fffu);
79    }
80    case 4:
81    {
82        uint32_t ret = std::rand();
83        if (RAND_MAX >= 0xffff)
84            ret = (ret << 16) ^ std::rand();
85        else
86        {
87            ret = (ret << 8) ^ std::rand();
88            ret = (ret << 8) ^ std::rand();
89            ret = (ret << 8) ^ std::rand();
90        }
91        return static_cast<T>(ret & 0x7fffffffu);
92    }
93    case 8:
94    {
95        uint64_t ret = std::rand();
96        if (RAND_MAX >= 0xffff)
97        {
98            ret = (ret << 16) ^ std::rand();
99            ret = (ret << 16) ^ std::rand();
100            ret = (ret << 16) ^ std::rand();
101        }
102        else
103        {
104            ret = (ret << 8) ^ std::rand();
105            ret = (ret << 8) ^ std::rand();
106            ret = (ret << 8) ^ std::rand();
107            ret = (ret << 8) ^ std::rand();
108            ret = (ret << 8) ^ std::rand();
109            ret = (ret << 8) ^ std::rand();
110            ret = (ret << 8) ^ std::rand();
111        }
112        return static_cast<T>(ret & (~(uint64_t)0 >> 1));
113    }
114    default:
115        ASSERT(false, "rand() doesn’t support types of size %d\n",
116               (int)sizeof(T));
117        return 0;
118    }
119}
120
121template<> inline half rand<half>() { return rand<half>(1.f); }
122template<> inline float rand<float>() { return rand<float>(1.f); }
123template<> inline double rand<double>() { return rand<double>(1.0); }
124template<> inline ldouble rand<ldouble>() { return rand<ldouble>(1.0); }
125
126} /* namespace lol */
127
128#endif // __LOL_MATH_RAND_H__
129
Note: See TracBrowser for help on using the repository browser.