Android 在长时间操作中测试溢出的最佳通用方法是什么?
在Kotlin中,与Java中一样,算术运算中没有溢出错误。我知道有一些特殊的Java操作可以测试溢出并抛出需要处理的异常 我想要一个更简单的方法。所以我想到了一个模型,虽然效率不高,但它非常简单有效 假设有人想测试2个长数字乘法:Android 在长时间操作中测试溢出的最佳通用方法是什么?,android,kotlin,entity-relationship,Android,Kotlin,Entity Relationship,在Kotlin中,与Java中一样,算术运算中没有溢出错误。我知道有一些特殊的Java操作可以测试溢出并抛出需要处理的异常 我想要一个更简单的方法。所以我想到了一个模型,虽然效率不高,但它非常简单有效 假设有人想测试2个长数字乘法:a*b 我用 if ( a.doDouble()* b.toDouble() - a*b != 0.0 ) println("Overflow") else println("Ok") 理由很简单。在Long的宇宙中,当Double不能达到所有精度时,
a*b
我用
if ( a.doDouble()* b.toDouble() - a*b != 0.0 )
println("Overflow")
else
println("Ok")
理由很简单。在Long
的宇宙中,当Double
不能达到所有精度时,一个数字与其Double
之间的差值总是0
,即使是在极端值下也是如此。在这种情况下,添加或减去一个小数字甚至不会更改相等性测试:
var l1= -Long.MAX_VALUE
var d1 = l1.toDouble()
if (d1-l1==0.0) println("-MaxLong")
if (d1+100-l1==0.0) println("it still -MaxLong")
var l2= Long.MAX_VALUE
var d2 =l2.toDouble()
if (d2-l2==0.0) println("MaxLong")
if (d2+100-l2==0.0) println("it still MaxLong")
这将生成输出:
-MaxLong
it still -MaxLong
MaxLong
it still MaxLong
是正确的还是我遗漏了什么?
即使它是正确的,还有比这更好的解决方案吗
更新1:请注意,如果Double
计算大于longValue.MAXVALUE
,则其他可能性正在测试。然而,它失败了
var n1= Long.MAX_VALUE/2+1
var n2= Long.MAX_VALUE/2+1
println((n1.toDouble()+n2.toDouble()) -
Long.MAX_VALUE.toDouble()==0.0)
println((n1.toDouble()+n2.toDouble()) > Long.MAX_VALUE.toDouble())
它打印:
true
false
更新2:虽然我的解决方案似乎有效,但它不起作用!
,在他接受的答案中指出以下情况:
val lo1 = Long.MAX_VALUE - 600
val lo2 = 100L
var do1: Double = lo1.toDouble()
var do2:Double = lo2.toDouble()
var d= do1+do2
var l=lo1+lo2
println(d-l==0.0)
由于结果在Long
范围内,它应该给出true
,但它给出false
,因为Double
计算不精确
正如他所说,最好的方法是真正使用封装在用户函数中的特殊函数,如multiplyExact
不幸的是,从API 24开始,它的资源只能在Android中使用,因此它依赖于另一个解决方案,即测试反向操作
例如,在乘法运算中,我们应该:
var a = Long.MIN_VALUE
var b = -1L
var c = a*b
if (b!=0 && c/b != a)
println("overflow $c")
else
println("ok $c")
它打印溢出-9223372036854775808
在传统的运算中,通常涉及加法、减法和乘法,它们是函数addExact
、subtractExact
、multipyExact
的对象,如前所述,这些函数很容易使用逆运算进行模拟
否定(
inv()
)还具有negateExact
函数来处理Long.MIN_值的否定,该函数无效,因为它没有正的对应项。评论较少的是分区,它在Java中没有专门的函数来引导溢出。但是,它在一种情况下会出现问题:Long.MIN\u VALUE/-1
无效。您应该知道Long数据类型具有固定的字节数
长数据类型是64位带符号的2的补码
整数。它的最小值为-9223372036854775808,并且
最大值为9223372036854775807(含)。使用这些数据
当需要比int提供的值范围更宽的值时,请键入
在漫长的宇宙中,一个数字和它的两倍之间的差值总是0
不,不是真的
println(Long.MAX_VALUE)
println(BigDecimal(Long.MAX_VALUE.toDouble()))
印刷品
9223372036854775807
9223372036854775808
您试图检查以下内容:
var l2= Long.MAX_VALUE
var d2 =l2.toDouble()
if (d2-l2==0.0) println("MaxLong")
但问题是JVM上的算术运算(实际上在大多数语言中)只能在相同类型的值上工作,因此编译器插入toDouble()
,您就可以真正计算d2-l2.toDouble()
如果你想要一个简单的测试,你可以这样做
val product = a*b
if ((b != 0 && product/b != a) || (a == Long.MIN_VALUE && b == -1)) {
println("Overflow")
} else {
// can use product here
println("OK")
}
但实际上,使用multipyexact
而不是手动操作更有意义。或者使用Kotlin的可空类型并定义
fun multiplyExact(x: Long, y: Long): Long? =
try { java.math.multiplyExact(x, y) } catch (e: ArithmeticException) { null }
编辑:为了在测试中演示一个错误,考虑加法(我很肯定它也是错误的乘法,但很难找到合适的数字):< /P>
原因是largeNumber.toDouble()+smallNumber.toDouble()==largeNumber.toDouble()
而(largeNumber+smallNumber.toDouble()==Long.MAX\u VALUE.toDouble()也许使用Yes,我知道,但我不想抛出异常。我想避免它。不幸的是,Long
类型不能像Double
那样工作。计算结果不会给出无穷大,它只是在字节大小内进行运算,并给出一个似乎有点不寻常的结果。例如,在中,如果使用2L
添加Long.MAX_值
,则结果是-Long.MAX_值
!我同意你说的一切,但我的测试仍然有效。如果第一个表达式不带BigDecimal
(Long.MAX\u VALUE.toDouble()-Long.MAX\u VALUE==0.0
),则为true。所以我的策略仍然有效,即使内部表示不同。如果doubleVar-longVar
测试真的是doubleVar-longVar.toDouble()
,这并不重要。长溢出计算结果与适当的双重计算结果非常不同。但是,你是对的,它更能用精确的函数封装检查。请参阅编辑以演示测试失败(至少是添加)。
var l2= Long.MAX_VALUE
var d2 =l2.toDouble()
if (d2-l2==0.0) println("MaxLong")
val product = a*b
if ((b != 0 && product/b != a) || (a == Long.MIN_VALUE && b == -1)) {
println("Overflow")
} else {
// can use product here
println("OK")
}
fun multiplyExact(x: Long, y: Long): Long? =
try { java.math.multiplyExact(x, y) } catch (e: ArithmeticException) { null }
val largeNumber = Long.MAX_VALUE - 600
val smallNumber = 100L
// prints true, even though there's no overflow
println((largeNumber.toDouble() + smallNumber.toDouble()) - (largeNumber + smallNumber) != 0.0)