2010-01-07 73 views
1

使用整数计数器时,你如何解决最大值问题,看起来像整数计数器 - 最大值时该怎么办?

​​

当此达到最大值,你怎么知道这事?你是否增加了另一个计数器来计算发生这种事情的频率?

我的问题关注java。

+0

嗨大卫, 我这样做,但有些仍然打开,用户想要稍后编辑或关闭。所以没有太多的问题要检查和回答。 :) – 2010-01-07 00:12:26

+0

@Andreas:不用担心编辑部分 - 如果用户想编辑他们的答案,他们仍然可以在接受它之后做到这一点。 – 2010-01-07 01:51:10

回答

4

对于一个快速饱和int增量(一个当它到达MAX_VALUE即停止工作),我想你可以写:

counters = (counter+1) + ((counter+1)>>31); 

或者

counters = (counter+1) - ((counter+1)>>>31); 

还是在开心的利益,为AtomicInteger,我认为:

private final AtomicInteger counter = new AtomicInteger(0); 

public void increment() { 
    int count; 
    do { 
     count = counter.get(); 
     if (count == Integer.MAX_VALUE) { 
      return; 
     } 
    } while (!counter.compareAndSet(count, count+1)); 
} 
4

选择一个数值类型,其范围足以满足您的要求。因此,如果int不够大,请使用longBigInteger

当您的int超过Integer.MAX_VALUE时,您会知道它会溢出并变为负值。

1

那么,你做什么取决于你需要什么。

如果您是通过网络发送请求消息的一种ID生成器,那么根据您的需要,您可能不会在意溢出,因为最早的ID将在此时过期。如果以前从未见过该值是重要的,那么您使用的数据类型较大 - 一个64位长的数据类型,你有9个以上的值,所以应该是很多的(尽管在很多情况下,21亿美元诠释应该是足够了!)

+0

只是将事情看得很透彻:如果你在一秒内耗尽了大约43亿个无符号32位整数的值,假定速度恒定需要大约68年的时间 - 这大约是每3人2个ID在地球*每秒*,这是疯狂的不切实际的。 – 2010-01-07 00:42:39

+0

在长时间翻身时,您不需要关心它,因为ID可能已经过期并且可以重复使用,或者您有更大的问题能够存储许多EB字节数 - 如果不是Z字节或甚至yottabytes - 数据(某人使用ID作为事物,所以必须有一些与之相关的数据)。 – 2010-01-07 00:43:14

1

有一个int作为计数器和另一个int来计数溢出给你相同的范围作为长(实际上,因为整数签名,这是一个溢出计数器浪费位)。

如果您希望计数器溢出,您可能需要使用BigIntegers。

7

您可以通过比较Integer.MAX_VALUE来判断您是否达到了最大值。

+2

有时候“简单就是最好的”:) – akuhn 2010-01-07 00:32:10

2

丹的答案是正确的。但是,如果你肯定每次递增1,并且出于某种原因需要使用int(无法想象为什么),那么你确实需要第二个计数器,比如说b,每次都增加一个++ == max_value (或++%max_value == 0)。你可以为b等做同样的事情。本质上,你只是在基础max_value算术,而不是基数为10.

+0

不错的想法 - 虽然它会很有趣,试图将所有这些计数器结合在一起:int total = c * Integer.MAX_VALUE * Integer.MAX_VALUE + b * Integer .MAX_VALUE + a' ... ;-) – 2010-01-07 01:52:52

3

你必须知道'counter'变量可能增长的大小。

  • Integer.MAX_VALUE的是2147483647
  • Long.MAX_VALUE是9223372036854775807L(相当大)

如果没有这些2的足够大,BigInteger的没有最大(除非你的机器能处理) 。

在实践中,你想要计算的大部分东西很容易适合int。

-2

您可以从Integer.MAX_VALUE开始counter并关闭。你可以停在Zero或去-Integer.MAX_VALUE

+2

但这并不能解决检测或应对溢出的问题。无论如何,从MAX_VALUE到MAX_VALUE的相同数量的滴答数量将从MAX_VALUE降到零。此外,计数器的值会很难处理(我可以保证在任何非平凡的情况下,有人会忘记“真实”值是“MAX_VALUE - counter”)。 – 2010-01-07 01:55:09

1

Java没有解决ct也不会导致整数溢出发生任何事情,无论是负值还是正值,使用int或long类型。

原始类型int和long及其对应的类类型Int和Long根据二进制补码算法在正方向或负方向溢出。最大正值之后的第一个值是最大负值。对于整数,它是Integer.MIN_VALUE。长期以来,它是Long.MIN_VALUE。反过来发生负溢出。最大负值之后的第一个值是最大正值。对于整数,它是Integer.MAX_VALUE。长期以来,它是Long.MAX_VALUE。

使用递增+1的计数器,检测溢出的一种非常简单的方法是检查它是否已达到Integer.MAX_VALUE(对于int或Long.MAX_VALUE很长时间),并采取一些优雅动作,如启动从0开始。另一种方法是停止处理或容纳二进制补码运算的行为,该运算将滚动到最大负值并从那里继续。如果溢出确实是一个问题,因为您使用的是非常大的整数,那么请使用BigInteger类的实例。它几乎和int一样有效,并且可能比在自己的代码中处理二进制补码翻转更有效率。

0

回答这个问题可能有点晚,但我倾向于做这样的事情。

if (atomicInt.get() < 0 || atomicInt.incrementAndGet() > MAX) { 
     // ... 
    } 

一旦溢出就停止递增。