2013-11-19 3 views
4

Мне нужен очень быстрый (быстрый) случайный генератор. Я нашел это от Intel: Fast Intel Random Number GeneratorИспользование быстрых генераторов случайных генераторов Intel (SSE2) с ошибкой в ​​стеке ... повреждено

Выглядит хорошо. Таким образом, я создал проект в MS Visual Studio 2013:

//FastRandom.h: 
#pragma once 
#include "emmintrin.h" 
#include <time.h> 
//define this if you wish to return values similar to the standard rand(); 
#define COMPATABILITY 

namespace Brans 
{ 
     __declspec(align(16)) static __m128i cur_seed; 

     // uncoment this if you are using intel compiler 
     // for MS CL the vectorizer is on by default and jumps in if you 
     // compile with /O2 ... 
     //#pragma intel optimization_parameter target_arch=avx 
     //__declspec(cpu_dispatch(core_2nd_gen_avx, core_i7_sse4_2, core_2_duo_ssse3, generic) 
     inline void rand_sse(unsigned int* result) 
     { 
      __declspec(align(16)) __m128i cur_seed_split; 

      __declspec(align(16)) __m128i multiplier; 

      __declspec(align(16)) __m128i adder; 

      __declspec(align(16)) __m128i mod_mask; 

      __declspec(align(16)) __m128i sra_mask; 

      __declspec(align(16)) __m128i sseresult; 

      __declspec(align(16)) static const unsigned int mult[4] = 

      { 214013, 17405, 214013, 69069 }; 

      __declspec(align(16)) static const unsigned int gadd[4] = 

      { 2531011, 10395331, 13737667, 1 }; 

      __declspec(align(16)) static const unsigned int mask[4] = 

      { 0xFFFFFFFF, 0, 0xFFFFFFFF, 0 }; 

      __declspec(align(16)) static const unsigned int masklo[4] = 

      { 0x00007FFF, 0x00007FFF, 0x00007FFF, 0x00007FFF }; 



      adder = _mm_load_si128((__m128i*) gadd); 

      multiplier = _mm_load_si128((__m128i*) mult); 

      mod_mask = _mm_load_si128((__m128i*) mask); 

      sra_mask = _mm_load_si128((__m128i*) masklo); 

      cur_seed_split = _mm_shuffle_epi32(cur_seed, _MM_SHUFFLE(2, 3, 0, 1)); 



      cur_seed = _mm_mul_epu32(cur_seed, multiplier); 

      multiplier = _mm_shuffle_epi32(multiplier, _MM_SHUFFLE(2, 3, 0, 1)); 

      cur_seed_split = _mm_mul_epu32(cur_seed_split, multiplier); 


      cur_seed = _mm_and_si128(cur_seed, mod_mask); 

      cur_seed_split = _mm_and_si128(cur_seed_split, mod_mask); 

      cur_seed_split = _mm_shuffle_epi32(cur_seed_split, _MM_SHUFFLE(2, 3, 0, 1)); 

      cur_seed = _mm_or_si128(cur_seed, cur_seed_split); 

      cur_seed = _mm_add_epi32(cur_seed, adder); 


#ifdef COMPATABILITY 



      // Add the lines below if you wish to reduce your results to 16-bit vals... 

      sseresult = _mm_srai_epi32(cur_seed, 16); 

      sseresult = _mm_and_si128(sseresult, sra_mask); 

      _mm_storeu_si128((__m128i*) result, sseresult); 

      return; 

#endif 


      _mm_storeu_si128((__m128i*) result, cur_seed); 

      return; 
     } 

     inline void srand_sse(unsigned int seed) 
     { 
      cur_seed = _mm_set_epi32(seed, seed + 1, seed, seed + 1); 
     } 

     inline void srand_sse() 
     { 
      unsigned int seed = (unsigned int)time(0); 
      cur_seed = _mm_set_epi32(seed, seed + 1, seed, seed + 1); 
     } 

     inline unsigned int GetRandom(unsigned int low, unsigned int high) 
     { 
      unsigned int ret = 0; 
      rand_sse(&ret); 
      return ret % (high - low + 1) + low; 
     } 

    }; 


// Test.cpp : Defines the entry point for the console application. 
// 

#include "stdafx.h" 
#include "FastRandom.h" 
#include <iostream> 

using namespace Brans; 

int _tmain(int argc, _TCHAR* argv[]) 
{ 
    srand_sse(); 
    unsigned int result = 0; 
    for (size_t i = 0; i < 10000; i++) 
    { 
     result += GetRandom(1, 50); 
     result -= GetRandom(1, 50); 
    } 

    std::cout << result << std::endl; 
    return 0; 
} 

Я ожидаю 0 результат + - 50. Но когда я запустить программу отладки, я получил: Run-Time Check Failure # 2 - Stack вокруг переменной «ret» был поврежден. в GetRandom (...). Когда я запускаю его в выпуске, я получил undefined результат, до max unsigned int. (Я использую процессор Intel i5).

Что не так?

========= Добавить в принятый ответ, и у меня есть ошибка, что я должен использовать длинные вместо знака междунар потому, что отрицательный результат стал большим положительным для знака.

+0

ли вы добавить соответствующие флаги компилятора для включения SSE2 компиляции? – pyCthon

+0

Запустили ли вы его под отладчиком и определили, где именно происходит повреждение стека? –

+0

pyCthon: Я включил: Потоковые SIMD-расширения 2 (/ arch: SSE2). Это все, что мне нужно? –

ответ

5

Из документов на Intel генератора Fast Random:

The rand_sse () реализует векторизованную версию этой функции fast_rand(), где целые математические операции выполняются в четыре раза, используя архитектуру SIMD.

Это означает, что rand_sse генерирует 4 случайных числа одновременно с использованием sse2.

Таким образом, вы должны дать ему массив unsigned int-х:

unsigned int result[4]; 
rand_sse(result); 
2

Эта инструкция:

_mm_storeu_si128((__m128i*) result, cur_seed); 

Насильно бросает result, unsigned int* Ань __m128i*, а затем записывает 128-битное значение там. unsigned int не может вместить 128-битное значение, так что вы в конечном итоге развращает стек вокруг места вызова, в GetRandom:

unsigned int ret = 0; 
rand_sse(&ret); 
Смежные вопросы