Как исправить неправильные числа, вызванные переполнением целого числа? - PullRequest
7 голосов
/ 15 июня 2011

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

Я подумал, что могу просто взять неправильные результаты и добавить Integer.MAX_VALUE, но это, похоже, не сработало, это оставило меня с высокими значениями. У меня есть значение offset в фрагменте кода ниже, но входные значения не сохраняются.

Следующий код воспроизводит ошибку:

@Test
public void testArexxConversion()
{
    // The input values represent seconds since midnight, Jan 1, 2000 UTC
    final int sample = 361450072; // A sample input value drawn from production
    // I use the offset from the UNIX epoch to convert the vakue to UNIX seconds
    final int offset = 946684800; // midnight, Jan 01 2000 UTC in UNIX seconds
    // This was the buggy line in my code, the assertion will fail
    long result = (sample + offset) * 1000;
    // Prints 'Result is negative: -1830153280'
    Assert.assertTrue(result > 0, String.format("Result is negative: %d", result));
    // This is for comparison
    Date dt = new Date(offset * 1000);
    Assert.assertEquals(dt.getTime() + sample * 1000, result);
}

Ответы [ 3 ]

4 голосов
/ 15 июня 2011

Как исправить ошибку в вашей базе данных

Чтобы исправить ошибку в вашей базе данных, вы можете сделать следующее дополнение ко всем ошибочным данным:

long new_result = old_buggy_result + 1309965025280L;

Постоянное число было найдено так:

  1. Проверить багги result значение
  2. Найдите, какое должно быть правильное значение result?
  3. Сделайте дополнение к ошибочному значению result, чтобы найти правильный `результат.

Но это возможно только в том случае, если вы сохранили sample и offset в своей базе данных или в другом месте.

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

long size_of_int = (long)Math.pow(2, 32);
int number_of_wraps = 305 // Only correct in your example!
                          // You can't deduct the number of wraps from
                          // the wrong value alone, because that information
                          // is lost in the modulo (the "wrap")
long correct_number = wrong_number + size_of_int * number_of_wraps;

Если числа в вашей базе данных достаточно близки к вашему значению выборки, это означает, что вы можете сделать выше, используя 305 в качестве числа переносов.

Объяснение ошибки (для будущих читателей)

Операция здесь:

 (sample + offset) * 1000;

вычисляется с использованием int, а не long. Но результат «слишком велик» для сохранения в переменной int. Вот почему у вас переполнение.

Измените его на:

  ((long) sample + offset) * 1000L;

Так что теперь операции + и * будут выполняться с использованием значений long, и в результате будет значение long, которое не будет переполнено.

2 голосов
/ 15 июня 2011

Это было бы так:

long result = ... ; // bad negative from database
long new_result = (long)((int)result - Integer.MAX_VALUE) + Integer.MAX_VALUE;
0 голосов
/ 15 июня 2011

Заменить эту строку.

long result = (long)(sample + offset) * 1000L;
...