I have written a Java class to solve a problem in the textbook, Javanotes 7, which asks for a program that displays statistics related to the number of rolls it takes to get a given value on a pair of dice. My class does not give me the correct statistics, yet—as far as I can tell—it is logically identical to the solution given in the textbook. Obviously it is not.
Here is my code:
/**
This program rolls a pair of dice until they come up a certain value. It repeats this for a certain number of trials and then gives the user the average number of
rolls required to achieve the target value. It does this for each possible value of two six-sided dice. It also gives the standard deviation and the maximum
number of rolls.
*/
public class DiceAverage{
static final int SAMPLE_SIZE = 10000;
public static void main(String[] args){
System.out.println("Total on Dice Average Number of Rolls Standard Deviation Maximum Number of Rolls");
System.out.println("------------- ----------------------- ------------------ -----------------------");
//each dice value iterator
for(int i = 2; i < 13; i ++){
//for each value, create a Statcalc, and PairOfDice object
StatCalc dataset = new StatCalc();
PairOfDice dice = new PairOfDice();
//each trial iterator
for(int j = 0; j < SAMPLE_SIZE; j ++){
int counter = 1;//counter for number of rolls. Initialized at 1 because dice object is rolled upon construction.
//get die1 and die2
while(dice.getDie1() + dice.getDie2() != i){
dice.roll();
counter ++;
}
dataset.enter(counter);
}
System.out.printf(" %-19d%-25.3f%-25.3f%1.3f%n", i, dataset.getMean(), dataset.getStandardDeviation(), dataset.getMax());
}
}
}
And here is the actual solution:
/**This program performs the following type of experiment:
* Given a desired total roll, such as 7, roll a pair of
* dice until the given total comes up, and count how many
* rolls are necessary. Now do the experiment over and over,
* and find the average number of rolls. The number of times
* the experiment is repeated is given by the constant,
* NUMBER_OF_EXPERIMENTS. Several statistics are computed and
* printed out for each possible roll = 2, 3, ..., 12:
* the average number of rolls, the standard deviation,
* and the maximum number of rolls.
*/
public class DiceRollStats2 {
static final int NUMBER_OF_EXPERIMENTS = 10000;
private static PairOfDice dice = new PairOfDice();
// A single pair of dice, which will be used for all
// the experiments.
public static void main(String[] args) {
System.out.println("Dice Total Avg # of Rolls Stand. Deviation Max # of Rolls");
System.out.println("---------- -------------- ---------------- --------------");
for ( int total = 2; total <= 12; total++ ) {
StatCalc stats; // An object that will compute the statistics.
stats = new StatCalc();
for ( int i = 0; i < NUMBER_OF_EXPERIMENTS; i++ ) {
// Do the experiment of counting the number of rolls
// required to roll the desired total, and enter the
// number of rolls into stats' dataset.
stats.enter( rollFor(total) );
}
System.out.printf("%6d", total);
System.out.printf("%18.3f", stats.getMean());
System.out.printf("%19.3f", stats.getStandardDeviation());
System.out.printf("%14.3f", stats.getMax());
System.out.println();
}
} // end main
/**
* Roll the dice repeatedly until the total on the
* two dice comes up to be N. N MUST be one of the numbers
* 2, 3, ..., 12. (If not, this routine will go into an
* infinite loop!). The number of rolls is returned.
*/
static int rollFor( int N ) {
int rollCt = 0; // Number of rolls made.
do {
dice.roll();
rollCt++;
} while ( dice.getDie1() + dice.getDie2() != N );
return rollCt;
}
} // end class DiceRollStats2
I cannot see the logical difference between these. What is it?
You are counting 1 extra roll by initializing int counter = 1;
Try initializing it with 0.
int rollCt = 0; // Number of rolls made.
do {
dice.roll();
rollCt++;
} while ( dice.getDie1() + dice.getDie2() != N );
return rollCt;
Here the dice are rolled before the boolean test in the do...while loop.
int counter = 1;//counter for number of rolls. Initialized at 1 because dice object is rolled upon construction.
//get die1 and die2
while(dice.getDie1() + dice.getDie2() != i){
dice.roll();
counter ++;
}
Whereas here the dice are rolled after the boolean test. So if the dice become equal to i, the dice values are never changed by roll()—as the while loop is skipped—and you get a bunch of iterations through the for loop with count == 1. Basically, the dice roll is not simulated properly this way.
Related
I'm trying to develop a method that interacts with this main class code to find the sum of n dice. (the main class program limits this count to the sum of 2, 3, 4 and 5 dice respectively).
for (int numberOfDice = 2; numberOfDice <= 5; ++numberOfDice) {
System.out.println("Rolling " + numberOfDice + " dice gives "
+ MathCalc.rollDice(numberOfDice));
The task of the method is to sum the number of dice (each evaluation is independent of another, meaning that the sum of 3 dice could be 11 for example while the sum of 4 dice might only be 8.) using only a loop and some local variables.
I have produced this method for another section of my code to simulate a single roll of the dice but for some reason I cant seem to wrap my head around this next step.
public static int rollDie() {
//roll a random number between 1-6 to simulate the roll of a die
return 1 + (int) (Math.random() * 6);
}
Math.random is obsolete and flawed, don't use it, use Random instead, specifically its nextInt() method, for example:
Random random = new Random();
// get values in the range [1:6]
int roll() {
return 1 + random.nextInt(6);
}
To sum up n rolls, call this method in a loop:
int sum = 0;
for (int numberOfDice = 0; numberOfDice < count; ++numberOfDice) {
sum += roll();
}
For bonus points in your tutorial, submit this:
public static int rollDie() {
return DoubleStream.generate(Math::random).limit(n).mapToInt(d -> (int)(d * 6) + 1).sum();
}
thanks in advance for any help I'm in an intro to java class and our home work was to generate 10 random numbers between 1&50 which I got and then average the generated numbers. I can't figure out how to average them here's what I have. Is there a way to store each random number as a variable?
public class randomNumberGen
{
public static void main(String [] args)
{
Random r=new Random();
for (int i=1;i<=10;i++){
System.out.println(r.nextInt(50));
System.out.println();
int average = (i/4);
System.out.println("your average is"+average);
}
}
}
use streams with java 8
final int numberOfRandom = 10;
final int min = 0;
final int max = 50;
final Random random = new Random();
System.out.println("The ave is: "+random.ints(min, max).limit(numberOfRandom).average());
First of all you have to replace "r.nextInt(50)" for "r.nextInt(50) + 1" because r.nextInt(n) returns a number between 0 (inclusive) and n (exclusive). Then, you know that an average is just a sum of n values divided by n. What you can do is just declare a "total" variable initialized to 0 before the loop. On each iteration you add to this variable the random value generated by r.nextInt(50). After the loop you can just divide the total by 10 so you get the average.
PS: it's a good practice to don't use "magic numbers", so it would be perfect (and luckily your teacher will have it in count) if you declare a constant for the number of iterations and then use it both in the loop condition and in the average calculation. Like this, if you have to make it for 100 numbers you only have to change the constant value from 10 to 100 instead of replacing two 10's por two 100's. Also this gives you the chance to give semantic value to these numbers, because now they will be "AMOUNT_OF_NUMBERS = 10" instead of just "10".
Like every average, it's sum of elements / amount of elements. So let's apply it here:
import java.util.Random;
public class randomNumberGen
{
public static void main(String [] args)
{
Random r=new Random();
double sum = 0; // is double so to prevent int division later on
int amount = 10;
int upperBound = 50;
for (int i = 0; i < amount; i++){
int next = r.nextInt(upperBound) + 1; // creates a random int in [1,50]
System.out.println(next);
sum += next; // accumulate sum of all random numbers
}
System.out.println("Your average is: " + (sum/amount));
}
}
Store variables outside of the loop to store both the total amount of numbers generated as well as the sum of those numbers. After the loop completes, divide the sum by the total amount of numbers.
public static void main(String [] args)
{
Random r=new Random();
double sum = 0;
int totalNums;
for (totalNums=1;totalNums<=10;totalNums++){
int randomNum = r.nextInt(50);
sum += randomNum;
System.out.println(randomNum);
}
double average = sum/totalNums;
System.out.println("your average is: "+average);
}
Average = Sum of numbers / amount of numbers
int sum = 0;
for (int i=1;i<=10;i++){
sum += r.nextInt(50) +1; //nextInt 50 produces value 0 to 49 so you add 1 to get 1 to 50 OR as suggested in the comments sum/10d
}
System.out.println("Average is: " + sum/10) // If you want the result in double (with decimals) just write sum*1.0/10
You could also do the same with a while loop.
int i = 0;
int sum = 0;
while(i < 10){
sum += r.nextInt(50) +1;
i++;
}
System.out.println("Average is: " + sum*1.0/i);
Or even shorter with lambda expressions: (/java 8 streams)
OptionalDouble average = IntStream.range(1, 10).map(x-> x = r.nextInt(50) +1).average();
System.out.println("Average is "+ average.getAsDouble());
.map(x-> x = r.nextInt(50) +1) // maps (changes) each value from 1 to 10 to a random number between 1 and 50
.average(); // calculates the average.
Simply create a variable sum starting at zero that you increment at each iteration. After the loop, simply divide by the number of elements..
Average means you should add everything up and devide it by the number of elements (50).
import java.util.Random;
class Homework {
public static final Random RANDOM = Random(); // never regenerate randoms
public static void main(String args[]) {
final int N = 50;
int sum = 0;
for (int i = 0; i < N; ++i) {
sum += RANDOM.nextInt(50)+1;
}
System.out.println("Avg: "+ sum / (float) N);
}
}
This should do the trick. Try to learn from it not just C+P.
Ps: Friggin annoying to write code on a phone.
I am trying to write a program that selects 5 integers at random between 1 and 6. I then need the program to display the missing integer. I can't figure out how to have it not display "0" as an integer. This is what I have so far...
import java.util.Random;
public class Task6
{
public static void main(String[] args)
{
int[] numbers = new int[5];
Random random = new Random();
for(int n = 1; n < 5; n++)
{
int select = random.nextInt(n + 1); //shuffle generator so it will not duplicate numbers
numbers[n] = numbers[select];
numbers[select] = n;
}//end for statement
for(int number : numbers)
{
System.out.println("Numbers selected : " + number);
}//end for
}
}
I have to have a O(n^2) operation in this as well.
If I understand correctly, you want your random numbers to only be between 1 and 6 (inclusive)? If that's the case then you need to restrict the range of what the RNG can actually spit out, using code similar to this:
/**
* Returns a pseudo-random number between min and max, inclusive.
* The difference between min and max can be at most
* <code>Integer.MAX_VALUE - 1</code>.
*
* #param min Minimum value
* #param max Maximum value. Must be greater than min.
* #return Integer between min and max, inclusive.
* #see java.util.Random#nextInt(int)
*/
public static int randInt(int min, int max) {
// NOTE: Usually this should be a field rather than a method
// variable so that it is not re-seeded every call.
Random rand = new Random();
// nextInt is normally exclusive of the top value,
// so add 1 to make it inclusive
int randomNum = rand.nextInt((max - min) + 1) + min;
return randomNum;
}
Also, your for loop:
for(int n = 1; n < 5; n++) { ... }
will not generate 5 numbers, it will generate 4. Think about the constraints of the loop; it will run through once with n = 1, 2, 3, 4, and then stop (5 is not less than 5).
If you want 5 iterations, you can do this:
for (int n = 0; n < 5; n++) { ... }.
or this:
for (int n = 1; n <= 5; n++) { ... }
Your number of iterations and your random number range don't need to be related.
Check this excellent answer for more detail if you need it.
Create a method that applies your constraints to the random number. Here is an example.
// this assumes that only 0 is unacceptable.
private static int myRandomBlammy()
{
int returnValue;
do
{
returnValue = blam; // replace blam with some way of generating a random integer.
} while (returnValue == 0);
return returnValue;
}
You should have an if statement on your loop that goes through the numbers.
for(int number : numbers)
{
if(number != 0){
System.out.println("Numbers selected : " + number);
}
}//end for
I am trying to write a program that selects 5 integers at random
between 1 and 6. I then need the program to display the missing
integer. I can't figure out how to have it not display "0" as an
integer.
From your question, there may be a case where your 5 random integers will not all be unique, and there may be more than one unique number that was not generated.
I would handle this with an array that counts how many of each number is generated:
import java.util.Random;
public class RandomCounter
{
/**
* An example that uses array indices to count how many random
* numbers are generated in a range.
*/
public static void main(String[] args)
{
//use an array of size n + 1 (ignore the zero index)
int[] numbers = new int[7];
Random r = new Random();
//generate random numbers
for (int i = 1; i < 6; i++){
int next = r.nextInt(6) + 1;
numbers[next]++; //count each number at the index
}
//print any numbers that didn't occur at least once.
for(int i = 1; i < numbers.length; i++){
if(numbers[i] != 0){
System.out.println(i);
}
}
}
}
Replace the last for-loop with this code snippet to see how many of each number occurred:
//print how many of each number occurred.
for(int i = 1; i < numbers.length; i++){
System.out.println (i + ": " + numbers[i]); }
}
Array index counting is a useful way to dynamically count occurrences of numbers.
So... I have a bit of a problem in a lab. I've been at it for a while, but my program just isn't doing what I'm expecting it to do. I'm currently writing a Sieve of Eratosthenes program in Java. Unfortunately, it's not giving the expected output of a list of primes. I can't, for the life of me, figure out what's wrong... Could anyone here give me a pointer as to where I might have messed something up?
Much thanks!
import java.util.*;
import java.math.*;
public class primeSieve {
/**
* #param args
*/
public static void main(String[] args){
// TODO Auto-generated method stub
Scanner kb = new Scanner(System.in);
//Get user input
System.out.println("Please enter the first number of the set of numbers to calculate primes (first number MUST be prime):");
int first = kb.nextInt();
System.out.println("Please enter the last number of the set of numbers to calculate primes (first number MUST be prime):");
int last = kb.nextInt();
List<Integer> primeList = new ArrayList<Integer>();
List<Integer> numList = new ArrayList<Integer>();
//Make array with values from 2 to the last value entered by user
for(int i = 2; i <= last; i++){
numList.add(i);
}
int size = numList.size();
//Calculate primes
for(int i = 0; i < size; i++)
{
if(i != 0 && i % 2 == 0){continue;} //No point in checking even numbers
if(numList.get(i) == 0){continue;} //If a value has been removed, it's been set to 0. No need to check it.
int prime = numList.get(i); //The current number being worked on. Should be prime
primeList.add(prime); //The number is prime, put it into the prime list.
for(int j = prime; j < size; j += prime) //Loop to remove multiples
{
numList.set(j, 0); //Number is a multiple of the prime previously calculated. Set it to 0, not a prime.
}
}
int primeSize = primeList.size();
System.out.println(primeSize);
System.out.println("The prime numbers from " + first + " to " + last + " are:");
for(int i = first; i < primeSize; i++)
{
System.out.println(primeList.get(i));
}
}
}
Edit: The output for the program when I look for primes between 2 and 50 is this:
The prime numbers from 2 to 50 are:
7
13
19
25
31
39
43
49
In the nested for loop, you start j at prime. However, consider the prime 2: it is at index 0, not index 2. Things should work out if you start j at prime-first. Also, as a commenter pointed out, your print loop should start at index 0 rather than first.
My previous question was similar to this, except I did not mention my ending goal,
In this code I have one die, and I print out the number of times it rolls a 4. Now I want to know if I have two dice, both six sided, how many times both would roll 2 and thus add to 4.
However, I would need to use arrays because it is mandatory in this assignment. I have tried adding another exception in the if statement, except I keep realizing that I need to be actually using arrays in the program. 1000 arrays should be stored, since the dice has to roll 1000 times, and thus check how many times it added to 4 from the rolls, then print the amount of times.
import java.io.*;
public class dont {
public static void main(String[] args) throws Exception {
// System.out.println(input());
int[] counts = new int[13];
System.out.print("The number of times it rolls 4 on two 6 sided dice :" + counts);
}
public static int input () throws IOException {
BufferedReader myInput = new BufferedReader (new InputStreamReader
System.out.println("Hello and welcome to the program");
System.out.println("In this program two six sided dices will be rolled and one eleven
sided dice will be rolled (1000 times each");
int sum;
int[] counts = new int[13];
System.out.println("The dices will be rolled to determine the odds of how many times the roll 2 comes up on both dies(Press any key to con't) ");
myInput.readLine();
//int count2=0;
int Sixside;
for (int i = 0; i < 1000; i++)
{
// two dice that add to 4, after being rolled one thousand times
Sixside = (int)(Math.random ()*6+1)+(int)(Math.random ()*6+1) == 4;
//print the number of times they add to 4
counts[sum]++;
}
counts[i] = Sixside;
{
//return array to main
return counts [13];
}
}
}
Your example produces reasonable answers for two dice that sum to 4. I suspect you're supposed to create an array that can hold sums for any pair with a sum between 2 and 12, for example:
int[] counts = new int[13];
Then you don't need an if statement in your loop; you can just increment the count for that sum, for example:
counts[sum]++;
This table can help you decide if your other counts are reasonable.
Addendum: Here's a simplified version of your method:
public static int[] input() {
int[] counts = new int[13];
for (int i = 0; i < 1000; i++) {
int sum = // your expression for the sum of two dice
counts[sum]++;
}
return counts;
}
You can call it like this and examine any particular total, e.g. counts[4].
int[] counts = input();