如何修复整数溢出产生的错误数字?
我有一个导致整数溢出的错误,导致写入数据库的错误(负)时间戳。 代码已经修复,但我也想修复错误的数据 。
我想,我可以采取错误的结果并添加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); }
如何修复数据库中的错误
要修复数据库中的错误,您可以对所有错误数据执行以下添加:
long new_result = old_buggy_result + 1309965025280L;
常数是这样的:
- 检查有缺陷的
result
值 - 找出正确的
result
值应该是什么? - 对buggy
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
值。
那将是这样的:
long result = ... ; // bad negative from database long new_result = (long)((int)result - Integer.MAX_VALUE) + Integer.MAX_VALUE;
替换此行。
long result = (long)(sample + offset) * 1000L;