谜题35:一分钟又一分钟

下面的程序在模仿一个简单的时钟。它的循环变量表示一个毫秒计数器,其计数值从0开始直至一小时中包含的毫秒数。循环体以定期的时间间隔对一个分钟计数器执行增量操作。最后,该程序将打印分钟计数器。那么它会打印出什么呢?


public class Clock {

    public static void main(String[] args) {

        int minutes = 0;

        for (int ms = 0; ms < 60*60*1000; ms++)

            if (ms % 60*1000 == 0)

                minutes++;

        System.out.println(minutes);

    }

}

在这个程序中的循环是一个标准的惯用for循环。它步进毫秒计数器(ms),从0到一小时中的毫秒数,即3,600,000,包括前者但是不包括后者。循环体看起来是在每当毫秒计数器的计数值是60,000(一分钟内所包含毫秒数)的倍数时,对分钟计数器(minutes)执行增量操作。这在循环的生命周期内总共发生了3,600,000/60,000次,即60次,因此你可能期望程序打印出60,毕竟,这就是一小时所包含的分钟数。但是,该程序的运行却会告诉你另外一番景象:它打印的是60000。为什么它会如此频繁地对minutes执行了增量操作呢?

问题在于那个布尔表达式(ms % 601000 == 0)。你可能会认为这个表达式等价于(ms % 60000 == 0),但是它们并不等价。取余和乘法操作符具有相同的优先级[JLS 15.17],因此表达式ms % 601000 等价于(ms % 60)*1000。如果(ms % 60)等于0的话,这个表达式就等于0,因此循环每60次迭代就对minutes执行增量操作。这使得最终的结果相差1000倍。

订正该程序的最简单的方式就是在布尔表达式中插入一对括号,以强制规定计算的正确顺序:


if (ms % (60 * 1000) == 0)

     minutes++;

然而,有一个更好的方法可以订正该程序。用被恰当命名的常量来替代所有的魔幻数字:


public class Clock {

    private static final int MS_PER_HOUR = 60 * 60 * 1000;

    private static final int MS_PER_MINUTE = 60 * 1000;

    public static void main(String[] args) {    

        int minutes = 0;

        for (int ms = 0; ms < MS_PER_HOUR; ms++)

            if (ms % MS_PER_MINUTE == 0)

                minutes++;

        System.out.println(minutes);

    }

}

之所以要在最初的程序中展现表达式 ms % 60*1000,是为了诱使你去认为乘法比取余有更高的优先级。然而,编译器是忽略空格的,所以千万不要使用空格来表示分组,要使用括号。空格是靠不住的,而括号是从来不说谎的。

原文地址:https://www.cnblogs.com/yuyu666/p/9840479.html

时间: 2024-11-05 22:45:00

谜题35:一分钟又一分钟的相关文章

[转] - spark推荐 - 从50多分钟到3分钟的优化

原文地址 从50多分钟到3分钟的优化 某推荐系统需要基于Spark用ALS算法对近一天的数据进行实时训练, 然后进行推荐. 输入的数据有114G, 但训练时间加上预测的时间需要50多分钟, 而业务的要求是在15分钟左右, 远远达不到实时推荐的要求, 因此, 我们与业务侧一起对Spark应用进行了优化. 另外提一下, 该文最好与之前我写的另一篇blog < Spark + Kafka 流计算优化 > 一起看, 因为一些细节我不会再在该文中描述. 优化分析 从数据分析, 虽然数据有114G, 但A

Oracle 5分钟或30分钟分割方法

在最近项目中,有一个客户需求是针对每天所有时间点的数据,分割成每5分钟展示一个用户数总数. 数据情景是: 一个游戏中所有用户在线的时间数据(当然简单的求和,可能会有重复数据).但在这重点是Oracle  SQL 中用于按照一定时间间隔分割的方法,具体5分钟分割实例如下: SELECT tt.reasonContent,to_char(tt.day_id,'hh24:mi')daytime  ,tt.num FROM (   SELECT ll.day_id,ll.reasonContent,CO

2016最新 wamp2.5+windows 10安装CoedSgniffer代码格式检查:5分钟安装 30分钟入门和浏览常用命令

14:59 2016/1/112016最新 wamp2.5+windows 10安装CoedSgniffer代码格式检查:注意问题:1.手动安装2.5.0和pear安装方式都成功但是执行时无任何反映,最终发现问题是版本问题,最后手动安装2.4.0就成功了!下载地址:http://pear.php.net/package/PHP_CodeSniffer/download/2.4.02.加入环境变量:d:\dev\tools\PHP_CodeSniffer-2.4.03.下面的 @[email pr

用十条命令在一分钟内检查 Linux 服务器性能

原文地址: http://www.oschina.net/news/69132/linux-performance 如果你的Linux服务器突然负载暴增,告警短信快发爆你的手机,如何在最短时间内找出Linux性能问题所在?来看Netflix性能工程团队的这篇博文,看它们通过十条命令在一分钟内对机器性能问题进行诊断. 概述 通过执行以下命令,可以在1分钟内对系统资源使用情况有个大致的了解. uptime dmesg | tail vmstat 1 mpstat -P ALL 1 pidstat 1

用十条命令在一分钟内检查Linux服务器性能

如果你的Linux服务器突然负载暴增,告警短信快发爆你的手机,如何在最短时间内找出Linux性能问题所在?Netflix性能工程团队的Brendan Gregg写下了这篇博文,兄弟连Linux培训 小编整理如下:一起来看他们是怎样通过十条命令在一分钟内对机器性能问题进行诊断. 概述 通过执行以下命令,可以在1分钟内对系统资源使用情况有个大致的了解. uptime dmesg | tail vmstat 1 mpstat -P ALL 1 pidstat 1 iostat -xz 1 free -

如何用十条命令在一分钟内检查Linux服务器性能

如果你的Linux服务器突然负载暴增,报警短信快发爆你的手机,如何在最短时间内找出Linux性能问题所在?来看Netflix性能工程团队的这篇博文,看它们通过十条命令在一分钟内对机器性能问题进行诊断. 概述 通过执行以下命令,可以在1分钟内对系统资源使用情况有个大致的了解. uptime dmesg | tail vmstat 1 mpstat -P ALL 1 pidstat 1 iostat -xz 1 free -m sar -n DEV 1 sar -n TCP,ETCP 1 top 其

1分钟内检查Linux服务器性能的10条命令

如果你的Linux服务器突然负载暴增,告警短信快发爆你的手机,如何在最短时间内找出Linux性能问题所在?Netflix性能工程团队的Brendan Gregg写下了这篇博文,来看他们是怎样通过十条命令在一分钟内对机器性能问题进行诊断. 概述 通过执行以下命令,可以在1分钟内对系统资源使用情况有个大致的了解. uptime dmesg | tail vmstat 1 mpstat -P ALL 1 pidstat 1 iostat -xz 1 free -m sar -n DEV 1 sar -

如何用十条命令在1分钟检查linux服务器性能

如果你的Linux服务器突然负载暴增,告警短信快发爆你的手机,如何在最短时间内找出Linux性能问题所在?来看Netflix性能工程团队的这篇博文,看它们通过十条命令在一分钟内对机器性能问题进行诊断. 概述 通过执行以下命令,可以在1分钟内对系统资源使用情况有个大致的了解. uptime dmesg | tail vmstat 1 mpstat -P ALL 1 pidstat 1 iostat -xz 1 free -m sar -n DEV 1 sar -n TCP,ETCP 1 top 其

3分钟配置zabbix 监控mysql

月小升在mysql的配置上卡了3天,原因一方面不熟悉,一方面我昨天18:00配置完毕,半天没有数据,就绝望的关闭了,我昨天晚上还在纠结要不要继续研究,今天打开一看,数据图表都有了.原来mysql的监控,需要一点时间来生效. 当知道了正确的办法,我在另一台服务器配置,其实只需要3分钟 关联mysql模版 步骤:配置 > 主机 > 点击主机的主机 > 模版 见图 转存失败重新上传取消点击那个模版进去看看模版的描述 Requirements for template operation:1.I