20

Java で System.nanoTime() API を読んでいたとき。私はこの行を見つけました:

数値オーバーフローの可能性があるため、t1 < t0 ではなく、t1 - t0 < 0 を使用する必要があります。

http://docs.oracle.com/javase/7/docs/api/java/lang/System.html#nanoTime()

2 つの nanoTime 値を比較するには

long t0 = System.nanoTime();
...
long t1 = System.nanoTime();

数値オーバーフローの可能性があるため、t1 < t0 ではなく、t1 - t0 < 0 を使用する必要があります。

t1 - t0 < 0オーバーフローを防ぐための望ましい方法を知りたいです。

A < Bよりも好ましい他のスレッドから読んだからですA - B < 0

Java Integer compareTo() - 比較と減算を使用する理由

この二つのことは矛盾しています。

4

4 に答える 4

12

ナノ時間は「リアルタイム」時間ではなく、不特定のイベントが発生したときに不特定の数から増加する単なるカウンターです(おそらくコンピューターが起動されます)。

オーバーフローし、ある時点でマイナスになります。オーバーフローするt0直前 (つまり、非常に大きな正) で、t1直後 (非常に大きな負の数) の場合、 (つまり、後で発生しt1 < t0たため、条件が間違っています)..... t1t0

しかし、あなたが言うならt1 - t0 < 0、まあ、魔法は、同じオーバーフロー (アンデフロー) の理由 (非常に大きな負の減算は非常に大きな正のアンダーフローになります) であり、結果は t1 が経過したナノ秒数になりt0ます .... .そして正しいでしょう。

この場合、2 つの間違いが本当に正しいことになります。

于 2013-08-24T01:52:02.813 に答える
10

t0 - t1 < 0値の実際の差 (オーバーフロー前) が、すべての可能な値を含むセットの半分またはサイズを超えていないt0 < t1ことが確実な場合よりも優れています。 ナノ秒の場合、約 292 年になります (ナノ秒は long に格納され、サイズの半分は=ナノ秒 ~= 292 年です)。
long2^64/22^63

したがって、292 年未満で区切られた時間サンプルについてはt0 - t1 < 0、正しい結果を得るために使用する必要があります。


より視覚化するために、サイクルには 8 つの可能な値が含まれているとしましょう-4, -3, -2, -1 ,0, 1, 2, 3

タイムラインは次のようになります

real time values:  .., -6, -5, -4, -3, -2, -1,  0,  1,  2,  3,  4,  5,  6,  7, ..
overflowed values: ..,  2,  3, -4, -3, -2, -1,  0,  1,  2,  3, -4, -3, -2, -1, ..

差が 4 を超えない場合 (サイクル サイズの半分、-4 は最小値であり、デルタを計算するための最小結果になる可能性があることを意味します) の値に対してどのように動作し、どのように動作するかt0 - t1 < 0を見てみましょう。オーバーフローした場合にのみ正しい結果が得られることにt0 < t1注意してくださいt0 - t1 < 0t1

  1. delta = 1大きい方の値のオーバーフローあり (注意:小さい方の値のオーバーフローは行いません。これは、両方の値が同じサイクルにあることを意味するため、計算はオーバーフローがない場合と同じになるためです)

    • 実際の値:t0 = 3 t1 = 4
    • オーバーフロー: t0 = 3 t1 = -4
    • t0 < t1==> 3 < -4 ->
    • t0 - t1 < 0==> 3 - (-4) < 0==> -1 < 0(7 回のオーバーフローで -1) true

    そのため、オーバーフローにもかかわらず、またはおそらくオーバーフローのおかげで、t0 - t1 < 0正しい結果が得られました。

  2. デルタ = 1ですが、今回はオーバーフローはありません

    a) 正の値

    • t0 = 2t1 = 3
    • 2 < 3 真実
    • 2 - 3 < 0==>-1 < 0

    b) 負の値

    • t0 = -4t1 = -3
    • -4 < -3 真実
    • -4 - (-3) < 0==>-1 < 0

    実際のデルタ = 1 の残りのケースでは、t0 < t1t0 - t1 < 0テストの両方で正しい結果が得られます (t0 - t1常に になります-1) 。

  3. デルタ = 3 (サイクルのほぼ半分)

    a1)より大きな値のオーバーフロー

    • 実際の値:t0 = 3 t1 = 6
    • オーバーフロー: t0 = 3 t1 = -2
    • t0 < t1==> 3 < -2 ->
    • t0 - t1 < 0==> 3 - (-2) < 0==> -3 < 0(-3 への 5 つのオーバーフロー) true

    a2)オーバーフローを伴う別のケース

    • 実際の値:t0 = 2 t1 = 5
    • オーバーフロー: t0 = 2 t1 = -3
    • t0 < t1==> 2 < -3 ->
    • t0 - t1 < 0==> 2 - (-3) < 0==> -3 < 0(再び 5 回のオーバーフローで -3) true


    したがって、再びt0 - t1 < 0正しい結果のみが得られました。

    b)オーバーフローなし は常に(-delta)t0 - t1と等しくなるため、常に正しい結果が得られます。また、正しい反発力を与えます-3t0 < t1

    • 実際の値:t0 = -1 t1 = 2
    • t0 < t1==> -1 < 2 ->
    • t0 - t1 < 0==> -1 - 2 < 0==>-3 < 0
  4. デルタ = 4の結果t0 - t1は常に と等しくなる-4ため、 も となります<0

    オーバーフローの例
    a1)

    • 実際の値:t0 = 0 t1 = 4
    • オーバーフロー: t0 = 0 t1 = -4
    • t0 < t1==> 0 < -4 ->
    • t0 - t1 < 0==> 0 - (-4) < 0==> -4 < 0(-4 への 4 つのオーバーフロー) true

    a2)

    • 実際の値:t0 = 1 t1 = 5
    • オーバーフロー: t0 = 1 t1 = -3
    • t0 < t1==> 1 < -4 ->
    • t0 - t1 < 0==> 1 - (-3) < 0==> -4 < 0(-4 への 4 つのオーバーフロー) true

    したがってt0 - t1 < 0、正しい結果のみを返します。

    オーバーフローのない例は、両方のテストで明らかに正しいでしょう。

  5. デルタ = 5 (およびそれ以上)

    a1) オーバーフローあり
    (最小値 tor t0 は -1 なので、それから始めましょう)

    • 実際の値:t0 = -1 t1 = 4
    • オーバーフロー: t0 = -1 t1 = -4
    • t0 < t1==> -1 < -4 ->
    • t0 - t1 < 0==> -1 - (-4) < 0==>3 < 0

    a2) オーバーフローあり

    • 実際の値:t0 = 1 t1 = 6
    • オーバーフロー: t0 = 1 t1 = -2
    • t0 < t1==> 1 < -2 ->
    • t0 - t1 < 0==> 1 - (-2) < 0==> 3 < 0 false 両方のテストが失敗しました

    b1) オーバーフローなし

    • t0 = -4t1 = 1
    • -4 < 1 真実
    • -4 - 1 < 0==> 3 < 0(-5 から 3 へのオーバーフロー) false

+-------------+-----------------------------+----------------------------+
|  tests if   | delta <= size of half cycle | delta > size of half cycle |
| t0 is less  |-----------------------------|----------------------------|
|  than t1    |  overflow  |  no overflow   | overflow  |  no overflow   |
|-------------|------------|----------------|-----------|----------------|
|   t0 < t1   |      -     |       +        |     -     |       +        |
|-------------|------------|----------------|-----------|----------------|
| t0 - t1 < 0 |      +     |       +        |     -     |       +        |
|-------------|------------|----------------|-----------|----------------|
| t0 - t1 > 0 |      -     |       -        |     +     |       -        |
+-------------+------------+----------------+-----------+----------------+
于 2013-08-24T05:59:19.753 に答える
1

APIからの引用は実際には次のとおりです。

約 292 年 (2^63 ナノ秒) を超える連続する呼び出しの違いは、数値のオーバーフローにより、経過時間を正確に計算できません。

t0 と t1 が 292 年離れて測定された場合、数値オーバーフローが発生します。それ以外の場合は、比較または減算のいずれかが正常に機能します。

于 2013-08-24T02:04:31.067 に答える
-1

任意の方法を使用してください。
直近の 290 年では違いはありません。
プログラム (および Java 自体) はそれほど長くは存続しません。

于 2013-08-24T05:30:44.463 に答える