I'm writing an x64 application that crunches very large numbers.
I'm dealing with a situation where I need to determine whether it is safe to add a UInt64 to an Int64.
// Error: Operator '<=' is ambiguous on operands of type 'ulong' and 'long'
if (UNsignedUInt64Var <= Int64.MaxValue - signedInt64Var)
signedInt64Var = (Int64)(((UInt64)signedInt64Var) + UNsignedUInt64Var); // Maybe works?
else
// ... move on to a different operation ... unrelated ...
I might be missing something obvious, but I can't seem to figure out a safe way to compute the initial difference of Int64.MaxValue - signedInt64Var
since this will always produce a value >= 0
and could potentially produce a value outside the range of Int64 (if signedInt64Var is negative).
Do I need to use bitwise operators to mask the sign bit manually?
Or is there a solution using only basic comparison operators and maybe some signed/unsigned casting?
I'd like to avoid converting to decimal if at all possible - high-volume performance priorities.
It's actually really easy, casts are enough and there are no remaining corner cases that need special attention.
unchecked {
UInt64 n1 = (UInt64) Int64.MaxValue; // this is in range
UInt64 n2 = (UInt64) signedInt64Var; // this may wrap-around, if value is negative
UInt64 result = n1 - n2; // this is correct, because it
// wraps around in exactly the same cases that n2 did
}
However, this smells like an XY problem. Addressing your original task
I need to determine whether it is safe to add a UInt64 to an Int64
I would just do the operation and test whether your result is valid. In C++, you have to test in advance whether overflow could occur, because signed integer overflow is undefined behavior. In C# there is no such concern.
Int64 a;
UInt64 b;
unchecked {
UInt64 uresult = b + (UInt64)a;
bool unsigned_add_was_safe = (uresult < b) == (a < 0);
Int64 sresult = a + (Int64)b;
bool signed_add_was_safe = (sresult >= a);
}
These overflow tests rely on invariants that are true for conventional (unbounded) arithmetic -- if they fail, then overflow occurred.
b
is unsigned and therefore never negative