JAVA解惑--長整除

1727 ワード

もっと読む
   長い整除というのは、二つのlong型の数値についての手順があるからです。除数されるのは一日の微秒数です。除数は一日のミリ秒数を表します。このプログラムはどんな結果をプリントしますか?
public class LongDivision{
   public static void main(String[] args){
      final long MICROS_PER_DAY = 24 * 60 * 60 * 1000 * 1000;
      final long MILLIS_PER_DAY = 24 * 60 * 60 * 1000;
      System.out.println(MICROS_PER_DAY/MILLIS_PER_DAY);
   }
}
   この問題はかなり直観的に見える。毎日のミリ秒数も、毎日のマイクロ秒数も定数です。明確にするために、それらは積の形で表されます。ミリ秒数とマイクロ秒数の違いは、最後の因子1000が少ないだけです。   除数と除数はいずれもlongタイプで、オーバーフローを発生せずにこの2つの積を容易に保存することができるほどlongタイプが大きいです。したがって、プログラム印刷の結果は必ず1000になります。しかし、印刷されたのは5です。この中で何が起こっていますか?   問題は定数MICROS_PER_DAYの計算は「確か」に溢れています。計算の結果、longに入れるのに適していますが、そのスペースに余裕があります。この結果はintに入れるのには適していません。この計算は完全にint演算で実行され、演算が完了した後だけlongに引き上げられます。計算がオーバーフローして200倍以下の数値を返します。intからlongへの昇格は、元のタイプの転換を広げ、不正な数値を残しています。この値はその後、MILLIS_によって変更されます。PER_DAY除去、MILLIS_PER_DAYの計算は正しいです。このように整理した結果、5を得ました。   なぜ計算はint演算で行われるのですか?すべての因子はint値ですから。二つのint値を合わせた場合、得られたのはやはりintタイプです。Javaはターゲット確定タイプの特性を持っていません。これは中国語の特性です。その意味は結果を格納する変数タイプが計算に影響するタイプです。   原因を知ると、このプログラムを簡単に修正できます。各文の最初の因子をlongに変換して残りの演算を行うことができます。それでもMICROS_だけです。PER_DAY表現は必要ですが、二つの積の中でこのようにするのは良い方法です。同じように、積の「一番目」の数値としてlongを使うことも必要ではないですが、これも良い方法です。次のプログラムは私たちが望む結果をプリントアウトします。
public class LongDivision{
   public static void main(String[] args){
      final long MICROS_PER_DAY = 24L * 60 * 60 * 1000 * 1000;
      final long MILLIS_PER_DAY = 24L * 60 * 60 * 1000;
      System.out.println(MICROS_PER_DAY/MILLIS_PER_DAY);
   }
}
   この教訓は簡単です。大きな数字を操作する時に、溢れないように注意してください。沈黙の殺し屋です。結果を保存するための変数が十分大きいように見えても、結果を生成する計算が正しいタイプであるとは限らない。時間に合わないときは、longを使って全体の計算を実行します。