确定 Int64 变量和 Int64.MaxValue 之间差异的最佳方法是什么?
What's the best method of determining the difference between an Int64 variable and Int64.MaxValue?
我正在编写一个处理非常大的数字的 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 为负)。
是否需要使用按位运算符手动屏蔽符号位?
或者是否有仅使用基本比较运算符和一些 signed/unsigned 转换的解决方案?
我想尽可能避免转换为十进制 - 高容量性能优先级。
其实很简单,cast就够了,没有剩下需要特别注意的corner case。
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 问题。解决您的原始任务
I need to determine whether it is safe to add a UInt64 to an 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
是无符号的,因此永远不会为负数
使用 checked 关键字,我有一种稍微不同的方法来执行此操作。我假设 unsigned long 可能大于 signed long 的最大正值,只要结果在 Int64 的范围内即可。
这是 add_if_in_range() 函数,以及几个测试其 return 值的测试用例:
public static class Test {
public static Int64 add_if_in_range(Int64 basevalue, UInt64 newvalue) {
if (basevalue < 0 & (newvalue >= (UInt64)Int64.MaxValue) ) {
UInt64 ubase = (UInt64)(-basevalue);
return checked((Int64)(newvalue-ubase));
} else {
return checked(basevalue + (Int64)newvalue);
}
}
}
void Main()
{
// Some Test Cases:
Int64 l; UInt64 ul;
l = Int64.MaxValue; ul = 100; // result causes overflow of Int64
try {
Console.WriteLine(Test.add_if_in_range(l, ul));
} catch (OverflowException) {
Console.WriteLine("Adding would cause an overflow");
}
l = Int64.MaxValue - 101; ul = 100; // result should be +9223372036854775806
try {
Console.WriteLine(Test.add_if_in_range(l, ul));
} catch (OverflowException) {
Console.WriteLine("Adding would cause an overflow");
}
l = Int64.MaxValue/2; ul = (UInt64)Int64.MaxValue/2; // result should be +9223372036854775806
try {
Console.WriteLine(Test.add_if_in_range(l, ul));
} catch (OverflowException) {
Console.WriteLine("Adding would cause an overflow");
}
l = Int64.MinValue; ul = 100; // result should be -9223372036854775708
try {
Console.WriteLine(Test.add_if_in_range(l, ul));
} catch (OverflowException) {
Console.WriteLine("Adding would cause an overflow");
}
l = Int64.MinValue; ul = UInt64.MaxValue; // result should be +9223372036854775807
try {
Console.WriteLine(Test.add_if_in_range(l, ul));
} catch (OverflowException) {
Console.WriteLine("Adding would cause an overflow");
}
l = Int64.MinValue; ul = UInt64.MaxValue-100; // result should be +9223372036854775807
try {
Console.WriteLine(Test.add_if_in_range(l, ul));
} catch (OverflowException) {
Console.WriteLine("Adding would cause an overflow");
}
l = Int64.MinValue + 1; ul = UInt64.MaxValue; // result causes overflow of Int64
try {
Console.WriteLine(Test.add_if_in_range(l, ul));
} catch (OverflowException) {
Console.WriteLine("Adding would cause an overflow");
}
}
我正在编写一个处理非常大的数字的 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 为负)。
是否需要使用按位运算符手动屏蔽符号位?
或者是否有仅使用基本比较运算符和一些 signed/unsigned 转换的解决方案?
我想尽可能避免转换为十进制 - 高容量性能优先级。
其实很简单,cast就够了,没有剩下需要特别注意的corner case。
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 问题。解决您的原始任务
I need to determine whether it is safe to add a UInt64 to an 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
是无符号的,因此永远不会为负数
使用 checked 关键字,我有一种稍微不同的方法来执行此操作。我假设 unsigned long 可能大于 signed long 的最大正值,只要结果在 Int64 的范围内即可。
这是 add_if_in_range() 函数,以及几个测试其 return 值的测试用例:
public static class Test {
public static Int64 add_if_in_range(Int64 basevalue, UInt64 newvalue) {
if (basevalue < 0 & (newvalue >= (UInt64)Int64.MaxValue) ) {
UInt64 ubase = (UInt64)(-basevalue);
return checked((Int64)(newvalue-ubase));
} else {
return checked(basevalue + (Int64)newvalue);
}
}
}
void Main()
{
// Some Test Cases:
Int64 l; UInt64 ul;
l = Int64.MaxValue; ul = 100; // result causes overflow of Int64
try {
Console.WriteLine(Test.add_if_in_range(l, ul));
} catch (OverflowException) {
Console.WriteLine("Adding would cause an overflow");
}
l = Int64.MaxValue - 101; ul = 100; // result should be +9223372036854775806
try {
Console.WriteLine(Test.add_if_in_range(l, ul));
} catch (OverflowException) {
Console.WriteLine("Adding would cause an overflow");
}
l = Int64.MaxValue/2; ul = (UInt64)Int64.MaxValue/2; // result should be +9223372036854775806
try {
Console.WriteLine(Test.add_if_in_range(l, ul));
} catch (OverflowException) {
Console.WriteLine("Adding would cause an overflow");
}
l = Int64.MinValue; ul = 100; // result should be -9223372036854775708
try {
Console.WriteLine(Test.add_if_in_range(l, ul));
} catch (OverflowException) {
Console.WriteLine("Adding would cause an overflow");
}
l = Int64.MinValue; ul = UInt64.MaxValue; // result should be +9223372036854775807
try {
Console.WriteLine(Test.add_if_in_range(l, ul));
} catch (OverflowException) {
Console.WriteLine("Adding would cause an overflow");
}
l = Int64.MinValue; ul = UInt64.MaxValue-100; // result should be +9223372036854775807
try {
Console.WriteLine(Test.add_if_in_range(l, ul));
} catch (OverflowException) {
Console.WriteLine("Adding would cause an overflow");
}
l = Int64.MinValue + 1; ul = UInt64.MaxValue; // result causes overflow of Int64
try {
Console.WriteLine(Test.add_if_in_range(l, ul));
} catch (OverflowException) {
Console.WriteLine("Adding would cause an overflow");
}
}