source: trunk/src/core/random.cc @ 533

Last change on this file since 533 was 533, checked in by epyon, 8 years ago
  • getting rid of size_t
  • datatypes now restricted to uint32 size
  • 64-bit compatibility
  • copyright updates where modified
File size: 7.6 KB
RevLine 
[319]1// Copyright (C) 2012-2014 ChaosForge Ltd
[175]2// http://chaosforge.org/
3//
[395]4// This file is part of Nova libraries.
5// For conditions of distribution and use, see copying.txt file in root folder.
[175]6
[319]7#include "nv/core/random.hh"
8#include "nv/core/time.hh"
[443]9#include "nv/stl/utility/common.hh"
[175]10
11using namespace nv;
12
[443]13static const uint32 mt_upper_mask = 0x80000000UL;
14static const uint32 mt_lower_mask = 0x7FFFFFFFUL;
15static const uint32 mt_full_mask  = 0xFFFFFFFFUL;
16static const uint32 mt_matrix_a   = 0x9908B0DFUL;
[175]17
[533]18#define NV_MT_MIXBITS(u, v) ( uint32( (u) & mt_upper_mask) | uint32( (v) & mt_lower_mask) )
19#define NV_MT_TWIST(u, v)  ( uint32(NV_MT_MIXBITS(u, v) >> uint32(1)) ^ uint32( (v) & uint32(1) ? mt_matrix_a : uint32(0)) )
[443]20
[503]21nv::random& random::get()
[175]22{
[503]23        static random default_rng;
24        return default_rng;
25}
26
27void random_mersenne::mt_init( uint32 seed )
28{
[471]29        m_state[0] = static_cast<uint32>( seed & mt_full_mask );
[487]30        for ( uint32 i = 1; i < mersenne_n; i++ )
[443]31        {
32                m_state[i]  = ( 1812433253UL * ( m_state[i - 1] ^ ( m_state[i - 1] >> 30 ) ) + i );
33                m_state[i] &= mt_full_mask;
34        }
[175]35
[443]36        m_remaining = 0;
37        m_next      = nullptr;
38        m_seeded    = 1;
[175]39}
40
[443]41
[503]42void random_mersenne::mt_update()
[175]43{
[443]44        uint32 *p = m_state;
[533]45        constexpr int m = mersenne_m;
46        constexpr int n = mersenne_n;
[175]47
[533]48        for ( int count = ( n - m + 1 ); --count; p++ )
[443]49                *p = p[mersenne_m] ^ NV_MT_TWIST( p[0], p[1] );
50
51        for ( int count = mersenne_m; --count; p++ )
[533]52        {
53                *p = p[m - n] ^ NV_MT_TWIST( p[0], p[1] );
54        }
[443]55
[533]56        *p = p[m - n] ^ NV_MT_TWIST( p[0], m_state[0] );
[443]57
58        m_remaining = mersenne_n;
59        m_next      = m_state;
[175]60}
61
[443]62
[503]63uint32 random_mersenne::mt_uint32()
[175]64{
[443]65        uint32 r;
[175]66
[443]67        if ( !m_remaining ) mt_update();
68
69        r = *m_next++;
70        m_remaining--;
71
72        r ^= ( r >> 11 );
73        r ^= ( r << 7 ) & 0x9D2C5680UL;
74        r ^= ( r << 15 ) & 0xEFC60000UL;
75        r ^= ( r >> 18 );
76
77        r &= mt_full_mask;
78
79        return r;
[175]80}
81
[503]82random_mersenne::random_mersenne( random_mersenne::seed_type seed /*= 0 */ )
[487]83        : m_next( nullptr ), m_remaining( 0 ), m_seeded( 0 )
[175]84{
[503]85        mt_init( seed );
[175]86}
87
[503]88random_mersenne::seed_type random_mersenne::set_seed( random_mersenne::seed_type seed /*= 0 */ )
[175]89{
[443]90        mt_init( seed );
91        return seed;
[175]92}
93
[503]94random_mersenne::result_type random_mersenne::rand()
[175]95{
[443]96        return mt_uint32();
[175]97}
98
[503]99random_base::seed_type random_base::randomized_seed()
[175]100{
[372]101        // TODO: this seems off, as it might often seed the same, use general time
102        // instead
[175]103        return narrow_cast< seed_type >( get_ticks() );
104}
[308]105
[503]106nv::vec2 nv::random_base::precise_unit_vec2()
[308]107{
[451]108        f32 angle = frand( math::pi<f32>() * 2.f );
[471]109        return vec2( cos( angle ), sin( angle ) );
[308]110}
111
[503]112nv::vec3 nv::random_base::precise_unit_vec3()
[308]113{
[451]114        f32 cos_theta = frange( -1.0f, 1.0f );
[471]115        f32 sin_theta = sqrt( 1.0f - cos_theta * cos_theta );
[451]116        f32 phi       = frand( 2 * math::pi<f32>() );
[308]117        return vec3(
[471]118                sin_theta * sin(phi),
119                sin_theta * cos(phi),
[308]120                cos_theta
121                );
122}
123
[503]124nv::vec2 nv::random_base::fast_disk_point()
[308]125{
[451]126        f32 r1 = frand();
127        f32 r2 = frand();
[443]128        if ( r1 > r2 ) swap( r1, r2 );
[451]129        f32 rf = 2* math::pi<f32>()*(r1/r2);
[471]130        return vec2( r2*cos( rf ), r2*sin( rf ) );
[308]131}
132
[503]133nv::vec2 nv::random_base::precise_disk_point()
[308]134{
[471]135        f32 r = sqrt( frand() );
[451]136        f32 rangle = frand( math::pi<f32>() );
[471]137        return vec2( r*cos( rangle ), r*sin( rangle ) );
[308]138}
139
[503]140nv::vec3 nv::random_base::fast_sphere_point()
[308]141{
[451]142        f32 rad     = frand();
143        f32 pi      = math::pi<f32>();
[471]144        f32 phi     = asin( frange( -1.0f, 1.0f ) ) + pi*.5f;
[451]145        f32 theta   = frange( 0.0f, 2 * math::pi<f32>() );
[471]146        f32 sin_phi = sin( phi );
[308]147        return vec3(
[471]148                rad * cos(theta) * sin_phi,
149                rad * sin(theta) * sin_phi,
150                rad * cos(phi)
[308]151        );
152}
153
[503]154nv::vec3 nv::random_base::precise_sphere_point()
[308]155{
[471]156        f32 radius = pow( frand(), 1.f/3.f );
[451]157        f32 cos_theta = frange( -1.0f, 1.0f );
[471]158        f32 sin_theta = sqrt( 1.0f - cos_theta * cos_theta );
[451]159        f32 phi       = frange( 0.0f, 2 * math::pi<f32>() );
[308]160        return vec3(
[471]161                radius * sin_theta * sin(phi),
162                radius * sin_theta * cos(phi),
[308]163                radius * cos_theta
164                );
165}
166
[503]167nv::vec2 nv::random_base::precise_ellipse_point( const vec2& radii )
[308]168{
[443]169        vec2 p = range( -radii, radii );
[308]170        vec2 inv_radii  = 1.f / radii;
171        vec2 inv_radii2 = inv_radii * inv_radii;
172        for ( uint32 i = 0; i < 12; ++i )
173        {
[443]174                if ( p.x * p.x * inv_radii2.x + p.y * p.y * inv_radii2.y <= 1.f )
[308]175                {
[443]176                        return p;
[308]177                }
178        }
179        return fast_disk_point() * radii;
180}
181
[503]182nv::vec3 nv::random_base::precise_ellipsoid_point( const vec3& radii )
[308]183{
[443]184        vec3 p = range( -radii, radii );
[308]185        vec3 inv_radii  = 1.f / radii;
186        vec3 inv_radii2 = inv_radii * inv_radii;
187        for ( uint32 i = 0; i < 12; ++i )
188        {
[443]189                if ( p.x * p.x * inv_radii2.x + p.y * p.y * inv_radii2.y + p.z * p.z * inv_radii2.z <= 1.f )
[308]190                {
[443]191                        return p;
[308]192                }
193        }
194        return fast_sphere_point() * radii;
195}
196
[503]197nv::vec2 nv::random_base::fast_hollow_disk_point( f32 iradius, f32 oradius )
[308]198{
[451]199        f32 idist2 = iradius * iradius;
200        f32 odist2 = oradius * oradius;
[471]201        f32 rdist  = sqrt( frange( idist2, odist2 ) );
[308]202        return rdist * precise_unit_vec2();
203}
204
[503]205nv::vec2 nv::random_base::precise_hollow_disk_point( f32 iradius, f32 oradius )
[308]206{
207        return fast_hollow_disk_point( iradius, oradius );
208}
209
[503]210nv::vec3 nv::random_base::fast_hollow_sphere_point( f32 iradius, f32 oradius )
[308]211{
[451]212        f32 idist3 = iradius * iradius * iradius;
213        f32 odist3 = oradius * oradius * oradius;
[471]214        f32 rdist  = pow( frange( idist3, odist3 ), 1.f/3.f );
[308]215        return rdist * precise_unit_vec3();
216}
217
[503]218nv::vec3 nv::random_base::precise_hollow_sphere_point( f32 iradius, f32 oradius )
[308]219{
220        return fast_hollow_sphere_point( iradius, oradius );
221}
222
223
[503]224nv::vec2 nv::random_base::fast_hollow_ellipse_point( const vec2& iradii, const vec2& oradii )
[308]225{
[372]226        vec2 iradii2 = iradii * iradii;
[308]227        vec2 opoint     = ellipse_edge( oradii );
228        vec2 opoint2    = opoint * opoint;
[454]229        vec2 odir       = math::normalize( opoint );
[451]230        f32 odist2    = opoint2.x + opoint2.y;
[308]231
[451]232        f32 low    = iradii2.y * opoint2.x + iradii2.x * opoint2.y;
233        f32 idist2 = ((iradii2.x * iradii2.y) / low ) * odist2;
[308]234
[471]235        f32 rdist     = sqrt( frange( idist2, odist2 ) );
[308]236        return odir * rdist;   
237}
238
[503]239nv::vec2 nv::random_base::precise_hollow_ellipse_point( const vec2& iradii, const vec2& oradii )
[308]240{
241        return fast_hollow_ellipse_point( iradii, oradii );
242}
243
[503]244nv::vec3 nv::random_base::fast_hollow_ellipsoid_point( const vec3& iradii, const vec3& oradii )
[308]245{
[372]246        vec3 iradii2 = iradii * iradii;
[308]247        vec3 opoint     = ellipsoid_edge( oradii );
248        vec3 opoint2    = opoint * opoint;
[454]249        vec3 odir       = math::normalize( opoint );
[451]250        f32 odist2    = opoint2.x + opoint2.y + opoint2.z;
[308]251
[451]252        f32 low    =
[308]253                iradii2.y * iradii2.z * opoint2.x +
254                iradii2.x * iradii2.z * opoint2.y +
255                iradii2.x * iradii2.y * opoint2.z;
[451]256        f32 idist2 = ((iradii2.x * iradii2.y * iradii2.z) / low ) * odist2;
[308]257
[471]258        f32 odist3 = odist2 * sqrt( odist2 );
259        f32 idist3 = idist2 * sqrt( idist2 );
[308]260
[471]261        f32 rdist     = pow( frange( idist3, odist3 ), 1.f/3.f );
[308]262        return odir * rdist;   
263}
264
[503]265nv::vec3 nv::random_base::precise_hollow_ellipsoid_point( const vec3& iradii, const vec3& oradii )
[308]266{
267        return fast_hollow_ellipsoid_point( iradii, oradii );
268}
269
[503]270nv::random_xor128::random_xor128( seed_type seed /*= randomized_seed() */ )
271{
272        set_seed( seed );
273}
274
275nv::random_base::seed_type nv::random_xor128::set_seed( seed_type seed /*= 0 */ )
276{
[509]277        if ( seed == 0 ) seed = randomized_seed();
[504]278        uint32 s = uint32( 4294967296 - seed );
[503]279        m_state[0] = 123456789 * s;
280        m_state[1] = 362436069 * s;
281        m_state[2] = 521288629 * s;
282        m_state[3] = 88675123 * s;
283        return seed;
284}
285
286nv::random_base::result_type nv::random_xor128::rand()
287{
288        uint32 t = m_state[0];
289        t ^= t << 11;
290        t ^= t >> 8;
291        m_state[0] = m_state[1]; m_state[1] = m_state[2]; m_state[2] = m_state[3];
292        m_state[3] ^= m_state[3] >> 19;
293        m_state[3] ^= t;
294        return m_state[3];
295}
Note: See TracBrowser for help on using the repository browser.