为什么我的mt19937随机发生器给我带来荒谬的结果?C++

Mod*_*ife 6 c++ random c++11

在另一个项目上工作,我们需要使用mt19937随机生成的数字.我们应该让它根据网格的部分随机选择一个x和y坐标.例如,我的函数传递minX,maxX,minY,maxY给一个函数.我的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] = '.';
                    }

            }
    }

}
Run Code Online (Sandbox Code Playgroud)

Haa*_*hii 16

我认为你应该为mt19937使用随机分布.所以用它吧

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

int iRandomWidth = dist(mt);
int iRandomHeight = dist(mt);
Run Code Online (Sandbox Code Playgroud)

这样,您可以保证获得4到13之间的随机数.

更新 虽然我的答案解决了原始问题,并且在我看来代码可读性有所提高,但它实际上并没有解决原始代码中的问题.另请参阅jogojapan的答案.

  • @ModdedLife从您发布的代码,我猜想,你有一个被零除,例如在`iStartX = MT()%(maxX的 - iRandomWidth);`(和其中Y相同的线).什么是`maxX`?因为如果`maxX - iRandomWidth`可能为零,则会导致此错误. (2认同)

jog*_*pan 5

问题的最终原因是您在代码中混合使用了有符号和无符号整数,而没有采取必要的预防措施(并且不需要).

具体来说,如果minY有时小于13,它会偶尔发生iRandomHeight负面变化.你得到的是类似于下面演示的效果:

#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;
}
Run Code Online (Sandbox Code Playgroud)

这首先生成一个略大于符合有符号整数的无符号整数.mt19937返回unsigned,有时会给你像i上面代码中的值.

上面代码的输出(参见liveworkspace)如下:

2
2147484647
-2147482649
Run Code Online (Sandbox Code Playgroud)

第二行显示带有负数的模数结果(例如iRandomHeight有时会是),应用于大于适合相应的有符号整数的无符号整数.第三行显示当您将其转换回有符号整数时会发生什么(当您将其分配给您的一个有符号整数变量时,它会隐式执行).

虽然我同意Haatschii你应该std::uniform_int_distribution用来让你的生活更轻松,但即使这样,使用签名和未签名也很重要.


Mod*_*ife 0

在@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] = '.';
                    }

            }
    }

}
Run Code Online (Sandbox Code Playgroud)

谢谢提醒伙计!