1 /*---------------------------------------------------------------------------* 2 Project: Horizon 3 File: math_MersenneTwister.cpp 4 5 Copyright (C)2009-2012 Nintendo Co., Ltd. All rights reserved. 6 7 These coded instructions, statements, and computer programs contain 8 proprietary information of Nintendo of America Inc. and/or Nintendo 9 Company Ltd., and are protected by Federal copyright law. They may 10 not be disclosed to third parties or copied or duplicated in any form, 11 in whole or in part, without the prior written consent of Nintendo. 12 13 $Rev: 47665 $ 14 *---------------------------------------------------------------------------*/ 15 16 #include <nn/types.h> 17 #include <nn/assert.h> 18 #include <nn/math/math_MersenneTwister.h> 19 #include <nn/crypto.h> 20 21 namespace nn { namespace math { 22 23 const int MersenneTwister::PARAMETER_N; 24 25 namespace 26 { MixMsb2(bit32 v)27 inline bit32 MixMsb2(bit32 v) 28 { 29 return v ^ (v >> 30); 30 } 31 GenerateInitialValue(const bit32 * pState,int index,bit32 d)32 bit32 GenerateInitialValue(const bit32* pState, int index, bit32 d) 33 { 34 const bit32 s0 = pState[index + 0]; 35 const bit32 s1 = pState[index + 1]; 36 37 const bit32 a = MixMsb2(s0); 38 const bit32 b = s1 ^ (a * d); 39 40 return b; 41 } 42 } 43 // anonymous namespace 44 45 46 47 /* ------------------------------------------------------------------------ 48 public 49 ------------------------------------------------------------------------ */ 50 Initialize()51 void MersenneTwister::Initialize() 52 { 53 crypto::GenerateRandomBytes(m_State, sizeof(m_State)); 54 m_Index = 0; 55 } 56 Initialize(bit32 seed)57 void MersenneTwister::Initialize(bit32 seed) 58 { 59 m_State[0] = seed; 60 61 for( int i = 1; i < PARAMETER_N; i++ ) 62 { 63 const bit32 v = MixMsb2(m_State[i - 1]); 64 m_State[i] = v * 0x6c078965 + i; 65 } 66 67 m_Index = 0; 68 } 69 Initialize(const bit32 * pSeed,int num)70 void MersenneTwister::Initialize(const bit32* pSeed, int num) 71 { 72 Initialize(0x012bd6aa); 73 74 int stateIndex = 0; 75 76 { 77 const int numLoop = Max(PARAMETER_N, num); 78 int seedIndex = 0; 79 80 for( int i = 0; i < numLoop; ++i ) 81 { 82 const bit32 v = GenerateInitialValue(m_State, stateIndex, 0x0019660d); 83 84 stateIndex++; 85 86 m_State[stateIndex] = v + pSeed[seedIndex] + seedIndex; 87 88 if( stateIndex >= PARAMETER_N - 1 ) 89 { 90 m_State[0] = m_State[PARAMETER_N - 1]; 91 stateIndex = 0; 92 } 93 94 seedIndex++; 95 if( seedIndex >= num ) 96 { 97 seedIndex = 0; 98 } 99 } 100 } 101 102 for( int i = 0; i < PARAMETER_N - 1; ++i ) 103 { 104 const bit32 v = GenerateInitialValue(m_State, stateIndex, 0x5d588b65); 105 106 stateIndex++; 107 108 m_State[stateIndex] = v - stateIndex; 109 110 if( stateIndex >= PARAMETER_N - 1 ) 111 { 112 m_State[0] = m_State[PARAMETER_N - 1]; 113 stateIndex = 0; 114 } 115 } 116 117 m_State[0] = 0x80000000; 118 } 119 SaveState(MersenneTwister::State * pStateBuffer)120 void MersenneTwister::SaveState(MersenneTwister::State* pStateBuffer) 121 { 122 NN_POINTER_TASSERT_(pStateBuffer); 123 124 for( int i = 0; i < PARAMETER_N; ++i ) 125 { 126 pStateBuffer->state[i] = m_State[i]; 127 } 128 129 pStateBuffer->index = m_Index; 130 } 131 RestoreState(const MersenneTwister::State * pStateBuffer)132 void MersenneTwister::RestoreState(const MersenneTwister::State* pStateBuffer) 133 { 134 NN_POINTER_TASSERT_(pStateBuffer); 135 NN_MINMAX_TASSERT_(pStateBuffer->index, 0, PARAMETER_N - 1); 136 137 for( int i = 0; i < PARAMETER_N; ++i ) 138 { 139 m_State[i] = pStateBuffer->state[i]; 140 } 141 142 m_Index = pStateBuffer->index; 143 } 144 GenerateRandomU32()145 u32 MersenneTwister::GenerateRandomU32() 146 { 147 u32 v; 148 149 // Updates the state 150 { 151 int currIndex = m_Index; 152 int nextIndex = currIndex + 1; 153 int baseIndex = currIndex + PARAMETER_M; 154 155 if( nextIndex >= PARAMETER_N ) 156 { 157 nextIndex -= PARAMETER_N; 158 } 159 if( baseIndex >= PARAMETER_N ) 160 { 161 baseIndex -= PARAMETER_N; 162 } 163 164 v = GenerateXkn(m_State[baseIndex], m_State[currIndex], m_State[nextIndex]); 165 166 m_State[currIndex] = v; 167 m_Index = nextIndex; 168 } 169 170 171 // tempering 172 v ^= (v >> PARAMETER_U); 173 v ^= (v << PARAMETER_S) & PARAMETER_B; 174 v ^= (v << PARAMETER_T) & PARAMETER_C; 175 v ^= (v >> PARAMETER_L); 176 177 return v; 178 } 179 GenerateRandomBytes(void * p,size_t size)180 void MersenneTwister::GenerateRandomBytes(void* p, size_t size) 181 { 182 uptr begin = reinterpret_cast<uptr>(p); 183 uptr end = begin + size; 184 uptr begin4 = RoundUp(begin, 4); 185 uptr end4 = RoundDown(end, 4); 186 187 if( begin < begin4 ) 188 { 189 bit32 v = GenerateRandomU32(); 190 std::memcpy(reinterpret_cast<void*>(begin), &v, begin4 - begin); 191 } 192 193 { 194 bit32* p32 = reinterpret_cast<bit32*>(begin4); 195 bit32* pEnd = reinterpret_cast<bit32*>(end4); 196 197 while( p32 < pEnd ) 198 { 199 *p32++ = GenerateRandomU32(); 200 } 201 } 202 203 if( end4 < end ) 204 { 205 bit32 v = GenerateRandomU32(); 206 std::memcpy(reinterpret_cast<void*>(end4), &v, end - end4); 207 } 208 } 209 210 211 212 /* ------------------------------------------------------------------------ 213 private 214 ------------------------------------------------------------------------ */ 215 MixBits(bit32 u,bit32 l)216 inline bit32 MersenneTwister::MixBits(bit32 u, bit32 l) 217 { 218 return (u & MIX_MASK) | (l & ~MIX_MASK); 219 } 220 GenerateXkn(bit32 xkm,bit32 xk,bit32 xk1)221 inline bit32 MersenneTwister::GenerateXkn(bit32 xkm, bit32 xk, bit32 xk1) 222 { 223 bit32 v = (MixBits(xk, xk1) >> 1); 224 225 if( (xk1 & 1) != 0 ) 226 { 227 v ^= PARAMETER_A; 228 } 229 230 return xkm ^ v; 231 } 232 233 234 235 }} 236 237