-1

New to Java on this end. I'm trying to run a program that rolls two dice and when the total roll between the two die is either 7 or 11 the program will exit. For some reason my while statement is executing over and over again, and I can't figure out why. Any help would be really appreciated. Code is below.

Again, very new to this. Not so much focused on a more efficient way to do this at the very moment, but rather the semantic details of why this is not functioning.

// import required packages for the program
// import all classes to be on the safe side
// will be using input/ouput and math, so those imports are needed
import java.io.*;
import java.math.*;
import java.text.*;

// Declare a class, class name Dice chosen
public class Dice
{
// need to use throws IOException because we are dealing with input and output, simple main method will not suffice
    public static void main(String[] args) throws IOException
    {

        // declare variables for the two dice, randomize each
        // die can each be rolled for # between 1-6
        double dice1 = Math.round(Math.random() * 6) + 1;
        double dice2 = Math.round(Math.random() * 6) + 1;

        // declare variable for combined roll
        double totalRoll = dice1 + dice2;

        //create loop to determine if totalRoll is a 7 or 11, if not continue rolling
        while ((totalRoll != 7.0) || (totalRoll != 11.0))
            {
            dice1 = Math.round(Math.random() * 6) + 1;
            dice2 = Math.round(Math.random() * 6) + 1;

            totalRoll = dice1 + dice2;

            System.out.println("The roll on die 1 is: " + dice1);
            System.out.println("The roll on die 2 is: " + dice2);
            System.out.println("The total of the two rolls is: " + totalRoll + "\n");

            if ((totalRoll == 7.0) || (totalRoll == 11.0)) 
            {
            System.out.println("You win!");
            }
            }


        /*
        // declare in as a BufferedReader; used to gain input from the user
        BufferedReader in;
        in = new BufferedReader(new InputStreamReader(System.in));

        //Simulate tossing of two dice
        */




    }
}
Zack
  • 661
  • 2
  • 11
  • 27
  • 3
    What does `(totalRoll != 7.0) || (totalRoll != 11.0)` mean? Can a number be equal to two values? – Sotirios Delimanolis Jan 12 '14 at 22:03
  • If the total roll is not 7 or 11 then re roll the die until a 7 or 11 is hit – Zack Jan 12 '14 at 22:04
  • 1
    Why are you using `double`s to represent dice? Think about which values you want them to be able to have. – Keppil Jan 12 '14 at 22:05
  • I know that they are integers, but representing .0 doesn't really affect the program functionality, does it? – Zack Jan 12 '14 at 22:06
  • @Keppil its a real dice :D – Sebastian Hoffmann Jan 12 '14 at 22:07
  • 1
    @Zack, if a 7 is rolled the `while` would *still* continue because it's also not equal to 11. `totalRoll == 7.0` but `totalRoll != 11.0`. That satisfies the condition because you're using an `OR`. – pcnThird Jan 12 '14 at 22:07
  • Your || should be && (or just &) – DSlomer64 Jan 12 '14 at 22:08
  • @DSlomer64 `&` is bitwise AND – Sebastian Hoffmann Jan 12 '14 at 22:09
  • Well, read this: "The && and || operators 'short-circuit', meaning they don't evaluate the right hand side if it isn't necessary. The & and | operators, when used as logical operators, always evaluate both sides." I found that and **31 up votes** [here](http://stackoverflow.com/questions/8759868/java-logical-operator-short-circuiting) among other places. So I just gave that guy another up vote. – DSlomer64 Jan 18 '14 at 19:57

5 Answers5

5

I think you want to swap your OR for an AND. With an OR, that while statement will always evaluate to true, because a single number can not be both 7 and 11 at the same time (unless it's some brutal quantum computing, but I'll assume it's not).

while(totalRoll != 7.0 && totalRoll != 11.0) {
    // Continue.
}

NOTE: If you are trying to make a quantum dice, then one could argue you'd need to roll the dice an infinite amount of times, given the single di face could equal all numbers simultaneously, so in this context your program is working beautifully... just food for thought.

Serious NOTE: Using a double to represent a value on a dice is really wasteful. You're reserving a lot more memory than you need to. Use an int or even a byte, if you wanted to optimize your memory usage.

Edit in response to comment

You added the break to your if statement; I am assuming. Well, you see, this is different. You're claiming if the number equals one of these numbers. Let me run an example for you.

When dealing with equality

The logic in your if statement is fine, because, let's say:

double totalRoll = 7.0;

if(totalRoll == 7.0 || totalRoll == 11.0)
{
    // Do something.
}

This evaluates to:

if(7.0 == 7.0 || 7.0 == 11.0)
{
}

Which becomes:

if(true || false)

And because TRUE OR X == TRUE, it becomes:

if(true)

Likewise, if you set totalRoll to 9.0:

if(9.0 == 7.0 || 9.0 == 11.0)
{
}

Which becomes.

if(false || false)

Which finally evaluates to:

if(false)

So we have proven by demonstration, that this if statement can handle input. Let's try out your while loop.

When dealing with inequality

double totalRoll = 7.0;

// We expect this to stop the loop..
while(totalRoll != 7.0 || totalRoll != 11.0)

Evaluates to

while(7.0 != 7.0 || 7.0 != 11.0)

And that evaluates to:

while(false || true)

Once again, X OR TRUE == TRUE so.

while(true)

Oh dear. So as you can see, the only way this while loop will ever break, is if the value of totalRoll is both 7.0 and 11.0 at the same time.

Why the solution works

We fix it, by swapping the OR for an AND.

double totalRoll = 7.0;

while(7.0 != 7.0 && 7.0 != 11.0)
{
}

Evaluates to..

while(false && true)

And we know that FALSE AND X == FALSE so

while(false)

And the loop breaks. The same will happen with 11.0, but not with any other number.

christopher
  • 26,815
  • 5
  • 55
  • 89
1

You could add an break, right after the System.out.print

if ((totalRoll == 7.0) || (totalRoll == 11.0))
    {
        System.out.println("You win!");
        break;
    }
Lucas
  • 33
  • 9
  • True, but that doesn't really explain why the `while` loop isn't working the way OP expects it to. – Keppil Jan 12 '14 at 22:09
0

You probably would like the while statement to be this--it's clearer:

   while (!(totalRoll == 7.0 || totalRoll == 11.0))

"While it is not true that roll equals 7 or 11..."

DSlomer64
  • 4,234
  • 4
  • 53
  • 88
0

Re: @Paranix "& is bitwise"...

Here's a quote from SO:

"The && and || operators 'short-circuit', meaning they don't evaluate the right hand side if it isn't necessary. The & and | operators, when used as logical operators, always evaluate both sides."

I found that and 31 up votes here and found similar wording elsewhere. But maybe that quote needs modification, since & does do "bitwise and", period.

That is, if both operands happen to be boolean, they're integers, either 1 or 0, so bitwise stuff applies.

1&1 is true (equals 1); 1&0, 0&1, 0&0 are false (equal 0).

The statement below prints 0,0,0,1:

System.out.println((1&0) + "," + (0&1) + "," + (0&0) + "," + (1&1));

You get error if using (1 && 0) since && requires boolean operands.

In any event, the modified dice code works correctly with either & or &&.

I've read that && is definitely required if there's any chance the right-hand operand is null, but I can't demonstrate that.

Community
  • 1
  • 1
DSlomer64
  • 4,234
  • 4
  • 53
  • 88
-1

Comparing doubles like that is very problematic; due to the way double values are represented chances are that totalRoll == 7.0 will not give you true, even if totalRoll is exactly 7.0. A better way to compare doubles (if you have to use them) would be something like this:

while (Math.abs(totalRoll - 7.0) > 0.0001 && Math.abs(totalRoll - 11.0) > 0.0001) { ... }

That way the inaccuracy of saving double values doesn't hurt you as much.

Edit: As there have been downvotes, I'll post some more information to back up what I'm saying:

Also, the following code prints false for me:

System.out.println(((7.0 / 100) * 100) == 7.0);

If anyone has information that disproves what I'm saying then please tell me about it.

Community
  • 1
  • 1
blalasaadri
  • 5,990
  • 5
  • 38
  • 58
  • This is just completely untrue. – Dawood ibn Kareem Jan 12 '14 at 22:32
  • Oh, is it? Is there a great new way of using double values that contradicts this? http://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html If so, why do we need `BigDecimal`? I'm happy to take my answer back if you have anything that disproves my statement. – blalasaadri Jan 12 '14 at 22:37
  • Have you looked at the `double` representation of 7.0? As a general rule, the `double` type represents smallish integers exactly; so `==` works fine to compare them. You get into trouble with non-integer values, or with very large integers; but 7.0 is neither. And as far as disproving your statement goes, I suggest you simply test `(x == 7.0)` for various values of `x` and see for yourself. – Dawood ibn Kareem Jan 12 '14 at 23:28
  • As for `((7.0 / 100) * 100)` - the reason why this isn't exactly `7.0` is that `0.07` can't be represented exactly as a `double`. So there's an implicit rounding step that happens with the division, and that introduces a small error. So the problem isn't with 7.0, it's with 0.07. – Dawood ibn Kareem Jan 12 '14 at 23:31
  • 1
    @DavidWallace That is, basically, what I said: the representation of doubles is imperfect, so you shouldn't compare doubles with `==`. I wasn't suggesting that the problem in the original post could be solved by switching to a different type of comparison, I was commenting on the danger of comparing doubles with `==`. Mind you, the information about when they are easy to represent and when they aren't is interesting, I didn't know that distinction. – blalasaadri Jan 13 '14 at 09:16
  • 1
    The dialog between @David Wallace and @blalasaadri needn't cause downvotes. Both make excellent points from which significant learning can occur, whether by newbie or old-bie. I, for one, paid no attention to the use of `double` in a situation that definitely calls for `int`. I figured "leave the code alone as much as possible" rather than give unrequested advice. But I, for one, am glad the last few comments were posted. – DSlomer64 Jan 14 '14 at 20:47
  • I just bought Ivor Horton's "Beginning Java", a very good book. He addresses "&& vs. &" and "|| vs. |" by calling && and || "conditional and" and "conditional or", respectively, his point being that only conditionally will the right-hand operand be dealt with. I like that. This is also the terminology used at [this Java tutorial](http://docs.oracle.com/javase/tutorial/java/nutsandbolts/op2.html) . – DSlomer64 Feb 09 '14 at 00:37
  • @DSlomer64 While this is true, it has nothing to do with my reply; maybe you meant to add it to the original question or to a reply that handles those operators? – blalasaadri Feb 10 '14 at 09:12
  • 1
    @blala... I didn't intend either of my comments to be criticism of your answer. In fact, I upvoted you on Jan 14 (I just found out as I tried to do so again) and admonished whoever DID downvote you in my comment of that same date (my comment before yesterday's). When I posted my comment yesterday, I wasn't paying attention to where I was sticking it. My intent was to make sure it was noticed in that "conditional and" (... "or") concisely and vividly describes the difference between && and & (|| and |). I will be more aware in the future that position of comments matters. – DSlomer64 Feb 10 '14 at 23:56