2015-11-21 74 views
-2

这里是我的代码看起来像剥了下来,尽可能:的Java奇怪的浮动行为

float delay = (float)5000; 
     long startTime = System.nanoTime(); 
     int elapsed = 0; 
     for (int i = 0; i < 20; i++) { 
      elapsed = (int) ((System.nanoTime() - startTime)/1000000); 
//   System.out.println("Elapsed: " + elapsed); 
      float range = delay * 0.4f; 
      float randomNum = (float)(Math.random() * range - (delay * 0.2f)); 
      if (elapsed > (delay + randomNum)) { 
       System.out.println("Random Num: " + randomNum); 
       startTime = System.nanoTime(); 
      } else { 
       i--; 
       continue; 
      } 
     } 

正如你可以看到我的循环20次,5秒钟后打印出一个随机数(5000毫秒)。这是输出的样子:

enter image description here

正如你可以看到,所有的输出都非常接近-1000。我试图产生一个从-1000到1000的随机浮动,但他们似乎都在-1000左右。所以,我检查,以确保实际的随机数发生器工作时,使用此代码:

float delay = (float)5000; 
     long startTime = System.nanoTime(); 
     int elapsed = 0; 
     for (int i = 0; i < 20; i++) { 
      elapsed = (int) ((System.nanoTime() - startTime)/1000000); 
//   System.out.println("Elapsed: " + elapsed); 
      float range = delay * 0.4f; 
      float randomNum = (float)(Math.random() * range - (delay * 0.2f));     
      System.out.println("Random Num: " + randomNum); 
      startTime = System.nanoTime(); 
     } 

基本上我拿了过去的方程和刚刚打印的随机数,而不if语句。这是我得到的输出:

enter image description here

在这个例子中,我很随意输出,完全像你期望的那样。但是,如果像第一组代码中一样添加过去后,输出将回到-999,并带有一些随机小数位。

更有意思的是,如果你把打印语句正上方,如果randomNum后声明和权限被分配一个值,你会得到这些输出:再次

enter image description here

,数字是随机的。由于某些原因,第一个示例代码中放入了部分代码,randomNum变量在调用if语句之后立即发生变化。为什么会发生?

+0

'range'的类型是什么?你可以把它归结为一个独立的例子吗?您已经忽略了足够的重要信息,任何人都很难提供帮助,问题可能会被解决。 –

+0

对不起,我只是尽可能地编辑它。你在这个问题中看到的所有代码都在没有任何其他外部代码的主方法内部运行。 –

回答

1

问题是,虽然您在所需的范围内生成随机数,但您系统地丢弃了所有-999以上的数。

考虑这样的代码:

while (true) { 
    // generate a random number in the range [-1000, 1000): 
    final double randomNum = 2000 * Math.random() - 1000; 

    // print it if it's in the range [-1000, -999): 
    if (randomNum < -999) { 
     System.out.println("Random Num: " + randomNum); 
    } 
} 

上面的代码将打印出一串随机数的范围在[− 1000,  − 999);你明白为什么?

你的代码当然更复杂,但它实际上是在做同样的事情。

要了解原因,让我们看看你的代码:

float delay = (float)5000; 
     long startTime = System.nanoTime(); 
     int elapsed = 0; 
     for (int i = 0; i < 20; i++) { 
      elapsed = (int) ((System.nanoTime() - startTime)/1000000); 
//   System.out.println("Elapsed: " + elapsed); 
      float range = delay * 0.4f; 
      float randomNum = (float)(Math.random() * range - (delay * 0.2f)); 
      if (elapsed > (delay + randomNum)) { 
       System.out.println("Random Num: " + randomNum); 
       startTime = System.nanoTime(); 
      } else { 
       i--; 
       continue; 
      } 
     } 

让我们简化/修剪了一点,所以它更容易阅读—删除注释掉线,清理空格,删除强制转换为intfloat(这是确定使用longdouble),内联的各种值,改变for -loop - 即,包含代码,也就是说,发生变异,其指数变量转化为更多的明确while -loop,将System.nanoTime()更改为,但将百万分结果更改为System.currentTimeMillis(),将某些变量重命名莱为清楚起见,等:

long prevTimeMillis = System.currentTimeMillis(); 
int i = 0; 
while (i < 20) { 
    final long elapsedMillis = System.currentTimeMillis() - prevTimeMillis; 
    final double randomNum = 2000 * Math.random() - 1000; 
    if (elapsedMillis > 5000 + randomNum) { 
     System.out.println("Random Num: " + randomNum); 
     prevTimeMillis = System.currentTimeMillis(); 
     i++; 
    } 
} 

即使在手是简单的代码,我们还需要两个关键的见解:

  • elapsedMillis > 5000 + randomNum是写randomNum < elapsedMillis - 5000的另一种方式。
  • 最初,elapsedMillis == 0;每次我们成功打印出一个数字后,再次输入elapsedMillis == 0。在这之间,有一些循环迭代,其中elapsedMillis增加了1,但是在大多数循环迭代中它根本不会改变。
    • 这是因为这个循环非常快,每毫秒有很大数量的迭代。 (这不是从第一原理一定是显而易见的,但它的解释你得到的输出的唯一方式。)

所以这个代码将循环快,产生一个又一个随机数并放弃每一个一直到elapsedMillis == 4001,此时每个随机数将被丢弃,除以外的随机数小于-999。由于您每毫秒执行大量的循环迭代,并且每毫秒生成大量的随机数,因此极有可能设法生成一个小于-999的随机数,而elapsedMillis == 4001。然后elapsedMillis重置为零。所以大于-999的随机数从来没有机会参与竞争:elapsedMillis从不大于4001,所以这样的数字总是被丢弃。

要解决此问题,您需要预先选择一个随机数“我应该延迟多久?” 之前你开始循环,然后循环,直到你的elapsedMillis超过一个预选的随机数。另外,假设你真正的目标是在[4秒,6秒]的范围内延迟一段时间,你应该使用Thread.sleep()而不是这个轮询/忙等待机制。这样,您可以优雅地放弃此处理器,以供其他线程和进程使用,而不是仅仅刻录CPU,直到您准备好继续。要做到这一点,你可以写:

for (int i = 0; i < 20; i++) { 
    final long millisToDelay = (long) (2000 * Math.random() - 1000); 
    System.out.println("Millis To Delay: " + millisToDelay); 
    Thread.sleep(millisToDelay); 
} 
+0

非常聪明!抓住这个好工作,并且非常感谢。 –

+0

@ScottyPippen:不客气! – ruakh

0

我相信你确实有问题的答案位于你提供给我们的第二行代码中。注意你如何转换为浮点数:(float)?

请在包含行同样的事情:

浮点数=延迟+ randomNum;

,使得其看起来像:

浮点数=(浮点)延迟+ randomNum;

延迟不是浮点数据类型。我认为应该这样做。

+0

延迟是一种浮点型。我有这样的代码“float delay =(float)delayMS;”而delayMS是一个int。 –