簡體   English   中英

為什么我的mt19937隨機發生器給我帶來荒謬的結果? C ++

[英]Why is my mt19937 Random generator giving me ridiculous results? C++

在另一個項目上工作,我們需要使用mt19937隨機生成數字。 我們應該讓它根據網格的部分隨機選擇一個x和y坐標。 例如,我的函數將minXmaxXminYmaxY傳遞給函數。 我的x坐標工作正常。 我在測試運行時隨機出錯。 有時它會毫無問題地運行10次,然后出現錯誤。 我輸入了一些自調試行來顯示mt生成器實際生成的內容。 就像我說的那樣,x工作正常,y有時會工作。 它會隨機給我一個-3437892或9743903。

這是我的代碼:

void DungeonLevel::generateRoom(int minX,int maxX,int minY, int maxY){
    mt19937 mt;
    mt.seed( time(NULL) );


    // Calculate random width and height; these both range
    // from 4-13
    int iRandomWidth = 4 + (mt() % 10);
    int iRandomHeight = 4 + (mt() % 10);

    // Calculate the start points in both X and Y directions

    int iStartX;
    iStartX = mt() % (maxX - iRandomWidth);
    cout << "xStart: " << iStartX<<endl; //cout flag
    while ((iStartX > maxX) && (iStartX >= 0)){
            cout << "xStart: " << iStartX<<endl;//cout flag
            iStartX = mt() % (maxX - iRandomWidth);
    }
    int iStartY = 0;
    iStartY = mt() % (maxY - iRandomHeight);
    cout<<"yStart: " <<iStartY<<endl; //cout flag
    while ((iStartY > maxY)){
            cout<<"yStart: " <<iStartY<<endl;//cout flag
            iStartY = (mt() % (maxY - iRandomHeight));
    }

    // Iterate through both x and y coordinates, and
    // set the tiles to room tiles
    // SINGLE ROOM
    for( int x = iStartX; x <= iStartX + iRandomWidth; x++ ){
            for( int y = iStartY; y <= iStartY + iRandomHeight; y++ ){
                    if (y == iStartY){
                            dungeonGrid[y][x] = '-';
                    }
                    else if (iStartX == x){
                            dungeonGrid[y][x] = '|';
                    }
                    else if (y == (iStartY+iRandomHeight)){
                            dungeonGrid[y][x] = '-';
                    }
                    else if (x == (iStartX+iRandomWidth)){
                            dungeonGrid[y][x] = '|';
                    }
                    else {
                            dungeonGrid[y][x] = '.';
                    }

            }
    }

}

我認為你應該為mt19937使用隨機分布。 所以用它吧

mt19937 mt;
mt.seed( time(nullptr) );
std::uniform_int_distribution<int> dist(4, 13);

int iRandomWidth = dist(mt);
int iRandomHeight = dist(mt);

這樣,您可以保證獲得4到13之間的隨機數。

更新雖然我的答案解決了原始問題,並且在我看來代碼可讀性有所提高,但它實際上並沒有解決原始代碼中的問題。 另請參閱jogojapan的答案。

問題的最終原因是您在代碼中混合使用了有符號和無符號整數,而沒有采取必要的預防措施(並且不需要)。

具體來說,如果minY有時小於13,那么iRandomHeightiRandomHeight負數。 你得到的是類似於下面演示的效果:

#include <limits>
#include <iostream>

using namespace std;

int main()
{
  /* Unsigned integer larger than would fit into a signed one.
     This is the kind of thing mt199737 returns sometimes. */
  unsigned int i = ((unsigned int)std::numeric_limits<int>::max()) + 1000;
  cout << (i % 3) << endl;
  cout << (i % -3) << endl;
  cout << (signed)(i % -3) << endl;
  return 0;
}

這首先生成一個略大於符合有符號整數的無符號整數。 mt19937返回unsigned,有時會在上面的代碼中給出像i這樣的值。

上面代碼的輸出(參見liveworkspace )如下:

2
2147484647
-2147482649

第二行顯示帶有負數的模數結果(例如iRandomHeight有時會),應用於大於適合相應的有符號整數的無符號整數。 第三行顯示當您將其轉換回有符號整數時會發生什么(當您將其分配給您的一個有符號整數變量時,它會隱式執行)。

雖然我同意Haatschii你應該使用std::uniform_int_distribution讓你的生活更輕松,但即使這樣,使用有符號和無符號也很重要。

弄清楚我在@haatschii的幫助下犯下的業余錯誤。

它現在非常有意義。 iStartY和iStartX對於被設置為低於或等於零的數字沒有限制。我覺得因為沒有抓住那個哈哈而感到愚蠢。 我添加了另一個循環以確保該值大於0.我還使iStartX和iStartY值以maxX + 1和maxY + 1開始,以便它們自動進入循環以生成大於0的解。

下面是解決方案代碼:

void DungeonLevel::generateRoom(int minX,int maxX,int minY, int maxY){
    mt19937 mt;
    mt.seed( time(NULL) );

    // Calculate random width and height; these both range
    // from 4-13
    int iRandomWidth = 4 + (mt() % 10);
    int iRandomHeight = 4 + (mt() % 10);

    int iStartX = maxX+1; //automatically has to enter the second while loop        
    while ((iStartX > maxX) && (iStartX >= 0)){
            while ((maxX - iRandomWidth) <= 0){
                    iRandomHeight = 4 + (mt() % 10); //makes value > 0
            }
            iStartX = mt() % (maxX - iRandomWidth);
    }

    int iStartY = maxY+1; //automatically has to enter the second loop
    while ((iStartY > maxY)){
            while ((maxY - iRandomHeight) <= 0){
                    iRandomHeight = 4 + (mt() % 10); //sets to valid value
            }
            iStartY = mt() % (maxY - iRandomHeight);
    }
    // Iterate through both x and y coordinates, and
    // set the tiles to room tiles
    // SINGLE ROOM
    for( int x = iStartX; x <= iStartX + iRandomWidth; x++ ){
            for( int y = iStartY; y <= iStartY + iRandomHeight; y++ ){
                    if (y == iStartY){
                            dungeonGrid[y][x] = '-';
                    }
                    else if (iStartX == x){
                            dungeonGrid[y][x] = '|';
                    }
                    else if (y == (iStartY+iRandomHeight)){
                            dungeonGrid[y][x] = '-';
                    }
                    else if (x == (iStartX+iRandomWidth)){
                            dungeonGrid[y][x] = '|';
                    }
                    else {
                            dungeonGrid[y][x] = '.';
                    }

            }
    }

}

謝謝提醒伙計!

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM