Целочисленный счетчик - что делать, когда Max-Value? - PullRequest
1 голос
/ 07 января 2010

Как решить проблему максимального значения при использовании целочисленного счетчика, который выглядит как

counter = counter + 1;

Когда это достигает максимального значения, как вы узнаете, что это произошло? Вы добавляете еще один счетчик для этого подсчета, как часто это происходило?

Мой вопрос касается Java.

Ответы [ 10 ]

7 голосов
/ 07 января 2010

Вы можете определить, достигли ли вы максимального значения, сравнив его с Integer.MAX_VALUE.

4 голосов
/ 07 января 2010

Для быстрого насыщенного 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 голосов
/ 07 января 2010

Выберите числовой тип, диапазон которого достаточно удобен для ваших потребностей.Поэтому, если int недостаточно велико, используйте long или BigInteger.

. Вы узнаете, когда ваш int превысил Integer.MAX_VALUE, потому что он переполнится и станет отрицательным.

3 голосов
/ 07 января 2010

Вы должны знать кое-что о том, насколько велика вероятность того, что переменная counter будет расти.

  • Integer.MAX_VALUE - 2147483647
  • Long.MAX_VALUE - 9223372036854775807L (значительно больше)

Если ни один из этих двух вариантов не является достаточно большим, у BigInteger нет максимума (кроме того, что может обрабатывать ваша машина).

На практике большинство вещей, которые вы хотите сосчитать, легко помещаются в int.

2 голосов
/ 07 января 2010

Дэн ответ правильный. Однако, если вы определенно увеличиваете на 1 каждый раз, и вам нужно по какой-то причине использовать int (не могу себе представить, почему), тогда вам действительно понадобится второй счетчик, скажем b, который get увеличивается каждый раз a ++ == max_value (или ++% max_value == 0). Вы можете сделать то же самое для б и так далее. По сути, вы просто работаете в базовой арифметике max_value вместо базовой 10.

1 голос
/ 01 августа 2012

Java не обнаруживает и не вызывает ничего с целочисленным переполнением, отрицательным или положительным, с типами 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 для long, и предпринять некоторые изящные действия, такие как запуск с начала от 0. Альтернатива состоит в том, чтобы остановить обработку или приспособить поведение арифметики дополнения до двух, которая переходит к максимальному отрицательному значению и переходит оттуда. Если переполнение действительно является проблемой, потому что вы используете действительно большие целые числа, используйте экземпляр класса BigInteger. Он почти так же эффективен, как int, и, вероятно, намного эффективнее, чем обработка переноса дополнения в вашем собственном коде.

1 голос
/ 07 января 2010

Наличие одного int в качестве счетчика и другого int для подсчета переполнений дает тот же диапазон, что и long (на самом деле, меньше, поскольку целые числа являются знаковыми, что составляет один потерянный бит для счетчика переполнения).

Возможно, вы захотите использовать BigIntegers, если ожидаете переполнения счетчика.

1 голос
/ 07 января 2010

Что вы делаете, зависит от того, для чего вам это нужно.

Если вы делаете это как своего рода генератор идентификаторов для сообщений-запросов, отправляемых по сети, то, в зависимости от ваших потребностей, вы можете не заботиться о переполнении, поскольку к тому времени истек срок действия самых старых идентификаторов. Если важно, чтобы значение никогда не было видно раньше, тогда вы используете больший тип данных - с длиной 64 бита у вас есть более 9 значений квинтиллиона, поэтому их должно быть достаточно (хотя во многих случаях 2,1 миллиарда тоже должно хватить int!)

0 голосов
/ 07 ноября 2017

Возможно, будет немного поздно ответить на этот вопрос, но я склонен делать что-то подобное.

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

Прекращает увеличение при переполнении.

0 голосов
/ 07 января 2010

Вы можете начать counter с Integer.MAX_VALUE и идти вниз. Вы можете остановиться на Zero или перейти на -Integer.MAX_VALUE.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...