【问题标题】:While loop not exitingWhile循环不退出
【发布时间】:2014-01-12 22:01:26
【问题描述】:

在这方面是 Java 新手。我正在尝试运行一个掷两个骰子的程序,当两个骰子之间的总掷骰数为 7 或 11 时,程序将退出。出于某种原因,我的 while 语句一遍又一遍地执行,我不知道为什么。任何帮助将非常感激。代码如下。

再次,对此非常陌生。目前并不太关注一种更有效的方法来做到这一点,而是关注为什么它不起作用的语义细节。

// 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
        */




    }
}

【问题讨论】:

  • (totalRoll != 7.0) || (totalRoll != 11.0) 是什么意思?一个数字可以等于两个值吗?
  • 如果总点数不是 7 或 11,则重新掷骰子,直到命中 7 或 11
  • 你为什么用doubles来代表骰子?想想你希望他们能够拥有哪些价值观。
  • 我知道它们是整数,但表示 .0 并不会真正影响程序功能,是吗?
  • @Zack,如果掷出 7,while仍然继续,因为它也不等于 11。totalRoll == 7.0 而是 totalRoll != 11.0。这满足条件,因为您使用的是OR

标签: java while-loop


【解决方案1】:

我想你想把你的OR 换成AND。使用ORwhile 语句将始终评估为 true,因为单个数字不能同时是 711(除非它是一些残酷的量子计算,但我假设它是不是)。

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

注意:如果您尝试制作一个量子骰子,那么有人可能会争辩说您需要无限次掷骰子,因为单次di face 可以同时等于所有数字,因此在这种情况下,您的程序运行良好......只是值得深思。

严重提示:使用double 表示骰子上的值真的很浪费。您保留的内存比您需要的多得多。如果您想优化内存使用,请使用int 甚至byte

根据评论进行编辑

您在if 语句中添加了中断;我假设。嗯,你看,这是不同的。您声称该数字是否等于这些数字之一。让我为你举一个例子。

当处理平等时

你的 if 语句中的逻辑很好,因为,让我们说:

double totalRoll = 7.0;

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

计算结果为:

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

变成:

if(true || false)

因为TRUE OR X == TRUE,它变成:

if(true)

同样,如果您将totalRoll 设置为9.0

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

变成这样。

if(false || false)

最终计算结果为:

if(false)

所以我们通过演示证明了这个if statement 可以处理输入。让我们试试你的 while 循环。

处理不平等时

double totalRoll = 7.0;

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

评估为

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

计算结果为:

while(false || true)

再一次,X OR TRUE == TRUE 所以。

while(true)

哦,亲爱的。如您所见,这个while 循环将永远中断的唯一方法是,如果totalRoll 的值同时是7.011.0

为什么解决方案有效

我们通过将OR 替换为AND 来修复它。

double totalRoll = 7.0;

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

评估为..

while(false && true)

我们知道FALSE AND X == FALSE 所以

while(false)

然后循环中断。 11.0 也会发生同样的情况,但其他号码不会。

【讨论】:

  • 但是当我添加中断时,while 循环似乎可以工作。 or 操作似乎得到了我想要做的事情?如果数字不是这个或不是这个,则重新滚动。
  • 我刚刚添加了一个大型演示为什么 while loop 不起作用。
  • 对理解逻辑很有帮助。非常感谢。
  • 如果这个答案最有帮助,请您将其标记为正确。
【解决方案2】:

您可以在 System.out.print 之后添加一个中断

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

【讨论】:

  • 没错,但这并不能真正解释为什么 while 循环没有按照 OP 的预期工作。
【解决方案3】:

您可能希望while 声明是这样的——这样更清楚:

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

“虽然 roll 不等于 7 或 11...”

【讨论】:

    【解决方案4】:

    回复:@Paranix “& 是按位的”...

    这是来自 SO 的引述:

    “&& 和 || 运算符 '短路',这意味着如果不需要,它们不会计算右侧。& 和 | 运算符,当用作逻辑运营商,总是评估双方。”

    我发现了这一点并且 31 票赞成 here 并在其他地方找到了类似的措辞。但也许该引用需要修改,因为 & 确实“按位与”,句号

    也就是说,如果两个操作数恰好都是布尔值,那么它们就是整数,1 或 0,因此适用按位计算。

    1&1 为真(等于 1); 1&0, 0&1, 0&0 为假(等于 0)。

    下面的语句打印 0,0,0,1:

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

    如果使用 (1 && 0) 会出错,因为 && 需要布尔操作数。

    无论如何,修改后的骰子代码与 & 或 && 都可以正常工作。

    我已经读过,如果右侧操作数有可能为 null,则肯定需要 &&,但我无法证明这一点。

    【讨论】:

      【解决方案5】:

      这样比较双打是很成问题的;由于 double 值的表示方式,即使totalRoll 正好是 7.0,totalRoll == 7.0 也不会给你真实的值。比较双打的更好方法(如果你必须使用它们)是这样的:

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

      这样保存双精度值的不准确性不会对您造成太大伤害。

      编辑:由于有人反对,我将发布更多信息来支持我所说的话:

      另外,以下代码为我打印false

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

      如果有人有信息反驳我所说的话,请告诉我。

      【讨论】:

      • 这完全不真实。
      • 哦,是吗?有没有一种很好的新方法来使用与此相矛盾的双值? docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html 如果是这样,为什么我们需要BigDecimal?如果您有任何反驳我的陈述的地方,我很乐意收回我的回答。
      • @DavidWallace 基本上就是我所说的:双打的表示是不完美的,所以你不应该将双打与== 进行比较。我并不是说原始帖子中的问题可以通过切换到不同类型的比较来解决,我是在评论将双打与== 进行比较的危险。请注意,关于它们何时易于表示以及何时不易表示的信息很有趣,我不知道这种区别。
      • @David Wallace 和 @blalasaadri 之间的对话不必引起反对票。无论是新手还是老手,两者都提出了重要的学习点。一方面,我没有注意在肯定需要int 的情况下使用double。我认为“尽可能不考虑代码”而不是提供未经请求的建议。但我,一方面,很高兴发布了最后几个 cmets。
      • @blala... 我的任何一个 cmets 都不打算批评您的回答。事实上,我在 1 月 14 日对你投了赞成票(当我再次尝试这样做时我才发现),并在我对同一日期的评论(我在昨天之前的评论)中告诫任何人对你投了反对票。当我昨天发表我的评论时,我并没有注意我把它贴在哪里。我的目的是确保在“条件与”(...“或”)中简洁生动地描述了 && 和 &(|| 和 |)之间的区别。将来我会更加意识到 cmets 的位置很重要。
      猜你喜欢
      • 2015-08-15
      • 1970-01-01
      • 1970-01-01
      • 2016-02-27
      • 2013-06-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-03-01
      相关资源
      最近更新 更多