Pseudorandom Number Generation and Common Errors
Pseudorandom Number Generation
Section titled “Pseudorandom Number Generation”Pseudorandom number generation was not covered in the lecture but may appear in future assignments, studios, or the final exam. Therefore, this studio begins by introducing the topic, which you’ll explore briefly below.
Modern digital computers are designed to be deterministic, meaning they are intended to behave predictably. However, many software applications benefit from simulating randomness. For example, randomness can be used to implement game mechanics, create statistical models, or design orchestration systems that distribute requests randomly across servers.
Since computers are inherently deterministic, they cannot generate true randomness. Instead, they rely on pseudorandomness, which appears random but is produced through a deterministic process. A pseudorandom number generator (PRNG) is a software tool that generates numbers that seem random but are mathematically derived. While these numbers are predictable in theory, the underlying process is often complex enough to make reverse engineering impractical for humans. Some advanced PRNGs, such as cryptographically secure PRNGs, even draw entropy from user interactions like mouse movements, making them more unpredictable.
In C++, a PRNG is available in the standard library. To use it, include the <cstdlib> header at the top of your program. This gives you access to the srand and rand functions. It’s good practice to prefix these functions with std::, as they are part of the std namespace.
How PRNGs Work
Section titled “How PRNGs Work”Most PRNGs start with a number called the random seed. This seed undergoes a series of complex mathematical transformations to generate the next number in the pseudorandom sequence. The output of this process is then used as the seed for the next iteration, creating a sequence of numbers. A good PRNG ensures that small changes in the seed result in significant and seemingly arbitrary differences in the output sequence.
By default, C++ initializes the PRNG with a seed of 1. As a result, running the program repeatedly will produce the same sequence of pseudorandom numbers. To avoid this, you must ensure that the seed is different for each program execution.
Using the Current Time as a Seed
Section titled “Using the Current Time as a Seed”A common approach is to derive the seed from the current time. Specifically, the number of seconds since the Unix epoch (midnight, January 1, 1970) is often used. To retrieve this value, include the <ctime> header and use one of the following expressions: time(nullptr), time(NULL), or time(0).
To set the PRNG seed, use the srand function provided by <cstdlib>. This function accepts an integer argument representing the seed. Typically, you should call srand only once at the beginning of your program, usually in the main function.
Example of setting the seed:
std::srand(time(nullptr));Generating Pseudorandom Numbers
Section titled “Generating Pseudorandom Numbers”Once the PRNG is seeded, you can generate pseudorandom numbers by calling the rand function. This function returns a positive integer between 0 and a constant value RAND_MAX. If you need numbers in a specific range, such as a die roll (1 to 6) or a probability (0.0 to 1.0), you’ll need to adjust the output of rand using mathematical operations.
Here’s an example program that demonstrates how to generate random numbers:
#include <iostream>#include <cstdlib> // For rand() and srand()#include <ctime> // For time()
int main() { // Seed the PRNG at the start of the program std::srand(time(nullptr));
// Generate and print two random integers std::cout << "Value 1: " << std::rand() << std::endl;
// Store a random value in a variable int another_value = std::rand(); std::cout << "Value 2: " << another_value << std::endl;
return 0;}Guiding Questions
Section titled “Guiding Questions”Answer the following questions based on a PRNG seeded with srand(time(nullptr)) at the beginning of the main function:
- What is the value of
0 % 4? - What is the value of
1 % 4? - What is the value of
2 % 4? - What is the value of
3 % 4? - What is the value of
4 % 4? - What is the value of
5 % 4? - Identify the interval in which
x % 4lies, regardless of the value ofx. - Identify the interval in which
x % 10lies, regardless of the value ofx. - Construct an expression using the above information to generate a pseudorandom integer between 0 and 5, inclusive.
- Given a pseudorandom integer between 0 and 10, explain how to transform it into a pseudorandom integer between 5 and 15.
- Construct an expression that generates a pseudorandom integer between 5 and 15, inclusive.
- Construct an expression that generates a pseudorandom integer between
aandb(inclusive), whereaandbareintvariables. - Construct an expression that generates a pseudorandom
doublevalue between 0.0 and 1.0, inclusive. Usestatic_castto avoid truncation. - Assume the PRNG generates uniform random numbers between 0 and 1. Create a boolean expression that evaluates to true 54.3% of the time and false 45.7% of the time.
Program
Section titled “Program”Write a program that simulates rolling two dice. Each die should generate a pseudorandom integer between 1 and 6. Print the two values, and if the rolls are equal, display the message: “You rolled doubles!”
Common Errors
Section titled “Common Errors”This section is dedicated to helping you identify and resolve common errors in a C++ program. Each error is accompanied by an example, an explanation, and suggestions for fixes.
Syntax Errors
Section titled “Syntax Errors”Error 1: Variable Not Declared in Scope
Section titled “Error 1: Variable Not Declared in Scope”Suppose your compiler outputs the following error message when trying to compile a program:
main.cpp: In function 'double triple_number()':main.cpp:4:16: error: 'favorite_number' was not declared in this scope4 | return favorite_number * 3; | ^~~~~~~~~~~~~~~main.cpp: In function 'int main()':main.cpp:12:47: error: too many arguments to function 'double triple_number()'12 | double triple_favorite = triple_number(favorite_number); | ^~~~~~~~~~~~~~main.cpp:3:8: note: declared here3 | double triple_number() { | ^~~~~~~~~~~~~~Read this error carefully. Focus especially on the beginning of the error message. What does the error mean? On what line does the error directly occur? In what function does the error directly occur? You should be able to figure out the answers to these questions without looking at the associated code, but for context, suppose the code looks like this:
#include <iostream>
double triple_number() { return favorite_number * 3;}
int main() { std::cout << "Enter your favorite number, and I'll triple it for you: "; double favorite_number; std::cin >> favorite_number;
double triple_favorite = triple_number(favorite_number); std::cout << "Your number, tripled, is: " << triple_favorite << std::endl;}Looking at the code and the error message, what changes might you make to the code to resolve the error?
Error 2: Missing Return Statement and Variable Not Declared
Section titled “Error 2: Missing Return Statement and Variable Not Declared”Suppose your compiler outputs the following error message when trying to compile a program:
main.cpp: In function 'char prompt_for_character()':main.cpp:7:1: warning: no return statement in function returning non-void [-Wreturn-type]7 | } | ^main.cpp: In function 'int main()':main.cpp:11:65: error: 'initial' was not declared in this scope11 | std::cout << "You said that your first initial is: " << initial; | ^~~~~~Read this error carefully. Focus especially on the beginning of the error message. What does the error mean? On what line does the error directly occur? In what function does the error directly occur? You should be able to figure out the answers to these questions without looking at the associated code, but for context, suppose the code looks like this:
#include <iostream>
char prompt_for_character() { std::cout << "What is your first initial? Enter a single character: "; char initial; std::cin >> initial;}
int main() { prompt_for_character(); std::cout << "You said that your first initial is: " << initial;}Looking at the code and the error message, what changes might you make to the code to resolve the error?
Logic Errors
Section titled “Logic Errors”Error 3: Incorrect Mathematical Expression
Section titled “Error 3: Incorrect Mathematical Expression”Suppose you want to convert the mathematical statement to a C++ function. You’ve implemented the function for it, but your compiler outputs the following error message when trying to compile your code:
main.cpp: In function 'double f(double)':main.cpp:4:16: error: unable to find numeric literal operator 'operator""x'4 | return 2x + 5; | ^Read this error carefully. Focus especially on the beginning of the error message. What does the error mean? On what line does the error directly occur? In what function does the error directly occur? You should be able to figure out the answers to these questions without looking at the associated code, but for context, suppose the code looks like this:
#include <iostream>
double f(double x) { return 2x + 5;}...Looking at the code and the error message, what changes might you make to the code to resolve the error?
Error 4: Incorrect Conditional Logic
Section titled “Error 4: Incorrect Conditional Logic”You’ve written a program that recommends a board game to the user based on their age. However, you’ve noticed that there’s some sort of logic error—it always recommends “Candyland” to them, regardless of their age.
#include <iostream>
/*** Function: prompt_for_age* Description: Prompts for user’s age* Returns (int): User’s age as given through the terminal*/int prompt_for_age() { std::cout << "Enter your age: "; int age; std::cin >> age; return age;}
/*** Function: print_board_game_recommendation* Description: Prints a board game recommendation based on the user’s age* Parameters:* age (int): User’s age*/void print_board_game_recommendation(int age) { if (2 <= age <= 7) { std::cout << "Candyland" << std::endl; } else if (8 <= age <= 12) { std::cout << "Monopoly" << std::endl; } else if (age >= 13) { std::cout << "Munchkin" << std::endl; }}
int main() { // Get user’s age int age = prompt_for_age(); // Print board game recommendation print_board_game_recommendation(age);}What’s causing the logic error, and how would you fix it?