确定Int64变量和Int64.MaxValue之间差异的最佳方法是什么?

时间:2015-12-18 18:36:43

标签: c# 64-bit unsigned signed unsigned-integer

我正在编写一个压缩非常大数字的x64应用程序。

我处理的情况是我需要确定将UInt64添加到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 ...

我可能会遗漏一些明显的东西,但我似乎无法找到一种安全的方法来计算Int64.MaxValue - signedInt64Var的初始差异,因为这总是会产生一个值>= 0并且可能产生一个超出Int64范围的值(如果signedInt64Var为负数)。

我是否需要使用按位运算符手动屏蔽符号位?

或者是否存在仅使用基本比较运算符以及某些有符号/无符号转换的解决方案?

我希望尽可能避免转换为十进制 - 高容量性能优先级。

1 个答案:

答案 0 :(得分:2)

实际上非常简单,演员阵容已经足够,并且没有剩余的角落案例需要特别注意。

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
}

但是,这有点像XY问题。解决原始任务

  

我需要确定将UInt64添加到Int64是否安全

我只是做操作并测试你的结果是否有效。在C ++中,您必须提前测试是否可能发生溢出,因为有符号整数溢出是未定义的行为。在C#中没有这样的担忧。

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);
}

这些溢出测试依赖于常规(无界)算法的不变量 - 如果它们失败,则发生溢出。

  • 当且仅当另一个操作数为负
  • 时,总和小于一个操作数
  • b未签名,因此从不否定