swiftkotlincode-conversion

Equivalent of Swift's subtractingReportingOverflow in Kotlin?


What would be the Kotlin equivalent of detecting overflow as is done in Swift's subtractingReportingOverflow?

For instance, the following in Swift yields shiftValue of 7212078330627782743 and overflow of true :

var someValue = 7212078330627782743
let shiftSize = 5
let shiftedValue = (someValue << shiftSize).subtractingReportingOverflow(someValue)

print("shiftedValue: \(shiftedValue.partialValue)") //yields 7212078330627782743
print("overflow: \(shiftedValue.overflow)") //yields true

I've tried calculating the overflow a couple of ways in Kotlin but I don't get the same results:

fun isOverflow1(shiftedValue: Long):Boolean {
    return shiftedValue < 0
}

fun isOverflow2(shiftedValue: Long):Boolean { 
    return shiftedValue > Int.MIN_VALUE && shiftedValue < Int.MAX_VALUE) {
}

val someValue = 7212078330627782743
val shiftedValue: Long = (someValue shl shiftSize) - someValue
val overflow = isOverflow1(shiftedValue)  // isOverflow2(shiftedValue)

println("overflow: $overflow") // yields false regardless of isOverflow1() or isOverflow2()

Solution

  • The closest would be Math.subtractExact, for Kotlin JVM only. This method "reports overflow" by throwing an ArithmeticException. You can use this if whatever you are doing should "fail" in the case of an overflow.

    Math.subtractExact(someValue shl shiftSize, someValue)
    

    If you want to do something else when it overflows, I would not catch the exception and use it as a control flow mechanism. I suggest writing your own method, based on the implementation of subtractExact.

    infix fun Long.subtractReportingOverflow(other: Long): Pair<Long, Boolean> {
        val r = this - other
        return r to ((this xor other) and (this xor r) < 0)
    }
    

    That said, this allocates a new Pair on the heap every time, and might affect GC if you use this often.