У меня есть функция для генерации (псевдо) случайного блуждания по квадратной решетке, где блуждание не должно выходить за границы этого квадрата, полная функция приведена ниже:
/**
* @brief Performs a single random walk returning the final distance from the origin
*
* Completes a random walk on a square lattice using the mersenne twister engine based pseudo-random
* number-generator (PRNG). The walk will not breach the boundaries of the square size provided to
* the function. The random walk starts at the origin and ends after some parameterised number of steps.
* Position co-ordinates of the walk for each iteration are sent to an output file.
*
* @param squareSideLength Length of square lattice side
* @param steps Number of steps to compute random walk up to
* @param engine Mersenne Twister engine typedef (used for generating random numbers locally)
* @param distribution Default distribution of random walk
* @param outputFile [Default nullptr] Pointer to file to write co-ordinate data of random walk to
* @return final distance of the particle from the origin
*/
double randomWalkSquareLattice(int squareSideLength, int steps, std::mt19937& engine, std::uniform_real_distribution<double>& distribution, std::ofstream* outputFile = nullptr) {
// store the half-length of the square lattice
const int halfSquareLength = squareSideLength / 2;
// initialise co-ordinates to the origin
double positionX = 0.0;
double positionY = 0.0;
// assign the default distribution to distDefault
std::uniform_real_distribution<double> distDefault = distribution;
// loop over a number of iterations given by the steps parameter
for (int i = 0; i < steps; i++) {
std::cout << positionX << "\t" << positionY << std::endl;
// if the x-position of the particle is >= to positive
// half square lattice length then generate decremental
// random number (avoiding breaching the boundary)
if (positionX >= halfSquareLength) {
double offset = positionX - halfSquareLength;
std::cout << std::endl << offset << std::endl;
std::uniform_real_distribution<double> distOffset(-offset, -1.0);
positionX += distOffset(engine);
}
// else if the x-position of the particle is <= to negative
// half square lattice length then generate incremental random
// number (avoiding breaching the boundary)
else if (positionX <= -halfSquareLength) {
double offset = std::abs(positionX + halfSquareLength);
std::cout << std::endl << offset << std::endl;
std::uniform_real_distribution<double> distOffset(offset, 1.0);
positionX += distOffset(engine);
}
// else (in case where x-position of particle is not touching
// the lattice boundary) generate default random number
else {
positionX += distDefault(engine);
}
// if the y-position of the particle is >= to positive
// half square lattice length then generate decremental
// random number (avoiding breaching the boundary)
if (positionY >= halfSquareLength) {
double offset = positionY - halfSquareLength;
std::cout << std::endl << offset << std::endl;
std::uniform_real_distribution<double> distOffset(-offset, -1.0);
positionY += distOffset(engine);
}
// else if the y-position of the particle is <= to negative
// half square lattice length then generate incremental
// random number (avoiding breaching the boundary)
else if (positionY <= -halfSquareLength) {
double offset = std::abs(positionY + halfSquareLength);
std::cout << std::endl << offset << std::endl;
std::uniform_real_distribution<double> distOffset(offset, 1.0);
positionY += distOffset(engine);
}
// else (in case where y-position of particle is not touching
// the lattice boundary) generate default random number
else {
positionY += distDefault(engine);
}
// if an outputFile is supplied to the function, then write data to it
if (outputFile != nullptr) {
*outputFile << positionX << "\t" << positionY << std::endl;
}
}
// compute final distance of particle from origin
double endDistance = std::sqrt(positionX*positionX + positionY*positionY);
return endDistance;
}
В тех случаях, когда условия, видимые в методе, не позволяют выходить за пределы границ. Однако, когда это вызывается с достаточным количеством шагов (так что выполняется любое из этих условий), я получаю сообщение об ошибке:
invalid min and max arguments for uniform_real
Обратите внимание, что dist, который я посылаю этой функции:
std::uniform_real_distribution<double> dist(-1.0,1.0);
И поэтому (как вы можете видеть из значений, напечатанных на терминале), проблема не в том, что смещение когда-либо будет больше, чем максимальное значение, заданное distOffset в любом из условных случаев.
Является ли проблема, что я не могу дать u_r_d двойное значение произвольной точности? Или что-то еще здесь играет, что мне не хватает?
Редактировать: я должен добавить, что это значения, используемые в main ():
int main(void) {
std::uniform_real_distribution<double> dist(-1.0, 1.0);
std::random_device randDevice;
std::mt19937 engine(randDevice());
//std::cout << dist(engine) << std::endl;
// Dimensions of Square Lattice
const int squareLength = 100;
// Number of Steps in Random Walk
const int nSteps = 10000;
randomWalkSquareLattice(squareLength, nSteps, engine, dist);
}
uniform_real_distribution(a,b);
требует, чтобы a ≤ b
,
Если positionX == halfSquareLength
, затем,
double offset = positionX - halfSquareLength;
это то же самое, что сказать
double offset = positionX - positionX;
а также offset
будет ноль.
Это приводит к
std::uniform_real_distribution<double> distOffset(-0.0, -1.0);
и нарушает a ≤ b
,
Вот решение, которое я придумал, похоже, пока работает для всех тестовых случаев:
/**
* @brief Performs a single random walk returning the final distance from the origin
*
* Completes a random walk on a square lattice using the mersenne twister engine based pseudo-random
* number-generator (PRNG). The walk will not breach the boundaries of the square size provided to
* the function. The random walk starts at the origin and ends after some parameterised number of steps.
* Position co-ordinates of the walk for each iteration are sent to an output file.
*
* @param squareSideLength Length of square lattice side
* @param steps Number of steps to compute random walk up to
* @param engine Mersenne Twister engine typedef (used for generating random numbers locally)
* @param distribution Default distribution of random walk
* @param outputFile [Default nullptr] Pointer to file to write co-ordinate data of random walk to
* @return final distance of the particle from the origin
*/
double randomWalkSquareLattice(int squareSideLength, int steps, std::mt19937& engine, std::uniform_real_distribution<double>& distribution, std::ofstream* outputFile = nullptr) {
// store the half-length of the square lattice
const int halfSquareLength = squareSideLength / 2;
// initialise co-ordinates to the origin
double positionX = 0.0;
double positionY = 0.0;
// assign the default distribution to distDefault
std::uniform_real_distribution<double> distDefault = distribution;
std::uniform_real_distribution<double> distBound(0.0, 1.0);
double oS;
// loop over a number of iterations given by the steps parameter
for (int i = 0; i < steps; i++) {
//std::cout << positionX << "\t" << positionY << std::endl;
positionX += distDefault(engine);
positionY += distDefault(engine);
// if the x-position of the particle is >= to positive
// half square lattice length then generate decremental
// random number (avoiding breaching the boundary)
if (positionX >= halfSquareLength) {
oS = distBound(engine);
double offset = positionX - halfSquareLength;
double desiredOffset = -(oS + offset);
if (desiredOffset < -1.0) {
double offsetFromNegUnity = desiredOffset + 1.0;
desiredOffset -= offsetFromNegUnity;
}
positionX += desiredOffset;
}
// else if the x-position of the particle is <= to negative
// half square lattice length then generate incremental random
// number (avoiding breaching the boundary)
else if (positionX <= -halfSquareLength) {
oS = distBound(engine);
double offset = std::abs(positionX + halfSquareLength);
double desiredOffset = offset+oS;
if (desiredOffset > 1.0) {
double offsetFromUnity = desiredOffset - 1.0;
desiredOffset -= offsetFromUnity;
}
positionX += desiredOffset;
}
// if the y-position of the particle is >= to positive
// half square lattice length then generate decremental
// random number (avoiding breaching the boundary)
if (positionY >= halfSquareLength) {
oS = distBound(engine);
double offset = positionY - halfSquareLength;
double desiredOffset = -(offset+oS);
if (desiredOffset < -1.0) {
double offsetFromNegUnity = desiredOffset + 1.0;
desiredOffset -= offsetFromNegUnity;
}
positionY += desiredOffset;
}
// else if the y-position of the particle is <= to negative
// half square lattice length then generate incremental
// random number (avoiding breaching the boundary)
else if (positionY <= -halfSquareLength) {
oS = distBound(engine);
double offset = std::abs(positionY + halfSquareLength);
double desiredOffset = offset+oS;
if (desiredOffset > 1.0) {
double offsetFromUnity = desiredOffset - 1.0;
desiredOffset -= offsetFromUnity;
}
positionY += desiredOffset;
}
// if an outputFile is supplied to the function, then write data to it
if (outputFile != nullptr) {
*outputFile << positionX << "\t" << positionY << std::endl;
}
}
// compute final distance of particle from origin
double endDistance = std::sqrt(positionX*positionX + positionY*positionY);
return endDistance;
}
Здесь смещение было сгенерировано случайным образом на интервале (0,1), и к этому смещению было добавлено различие от границы, по которой нарушенная позиция оси или оси y, чтобы создать двойное значение, которое будет иметь минимум этой разрыва и дополнительная вложенная условная проверка) максимум 1,0 (или -1,0 для противоположной границы).