在C#

时间:2017-02-14 22:44:35

标签: c# math

我正在使用的api有ulong字段(我无法更改此字段)。我需要按long金额调整此字段(也可能是int)。但是,我无法添加这些togeather:Operator '+' is ambiguous on operands of type 'ulong' and 'long'

我无法将long转换为ulong,因为我会丢失该符号,我无法将ulong转换为long因为我可能会失去部分价值。

最终我想尝试调整值,如果它会导致换行我想要返回false并且没有完成调整。如果它没有换行我想完成调整并返回true;我可以做这个部分,但前提是我可以找到一种方法将两个字段一起添加到一起。

public ulong Value;
public bool AdjustValue(long amount)
{
    // Operator '+' is ambiguous on operands of type 'ulong' and 'long'
    ulong adjustValue = Value + amount; 

    if (amount < 0 && adjustValue > Value)
        return false;
    if (amount > 0 && adjustValue < Value)
        return false;

    Value = adjustValue;
    return true;
}

我该如何解决这个问题?

2 个答案:

答案 0 :(得分:6)

为了便于阅读,您可能更喜欢评论中的建议:

adjustValue = Value;
if (amount < 0)
    adjustValue -= (ulong)(-amount);
else
    adjustValue += (ulong)amount;

这清楚地说明了您希望数学运算的方式。

...然而

几乎每个现代硬件CPU中的整数表示都是两个补码。其中一个原因是使用二进制补码二进制数的数学具有非常好的属性:无论是否处理有符号或无符号值,都可以获得相同的加法和减法二进制表示。

这意味着您可以将调整值强制转换为ulong以进行添加。根据C#语言规则,演员表将简单地将签名值的二进制表示重新解释为无符号。添加无符号值将具有与添加具有相同二进制表示的带符号值完全相同的效果。

这是一个显示此工作的代码示例:

static void Main(string[] args)
{
    ulong[] values = { ulong.MinValue, ulong.MaxValue, long.MaxValue };
    long[] adjust = { 0, 1, -1, long.MinValue, long.MaxValue };

    for (int i = 0; i < values.Length; i++)
    {
        for (int j = 0; j < adjust.Length; j++)
        {
            ulong value = values[i];

            bool result = AdjustValue(adjust[j], ref value);
            Console.WriteLine($"{values[i]} + {adjust[j]} = {values} (overflow: {!result})");
        }
    }
}

static bool AdjustValue(long amount, ref ulong value)
{
    ulong adjustValue = value + (ulong)amount;

    if (amount < 0 && adjustValue > value)
        return false;
    if (amount > 0 && adjustValue < value)
        return false;

    value = adjustValue;
    return true;
}

注意:默认情况下,未选中数学运算是运行时。但是,有一个编译器开关可以改变它。如果您在启用该开关的情况下编译代码,强制检查算术运算,则需要将上述内容包装在unchecked块中,以避免出现溢出异常。

答案 1 :(得分:0)

有人会讨厌这个答案,但你可以使用十进制数据类型,因为它能够存储28-29个有效数字而2 ^ 64只有20个数字。

当然,使用浮点数据类型会在性能方面产生一些开销,但另一方面,此代码非常易于阅读,并且可能比需要{{1}的解决方案具有更好的分支预测/流水线操作}。

if

如果你溢出,系统会抛出足够的public static ulong Add(this ulong baseValue, long offset) { decimal adjustedValue = (decimal)baseValue + offset; return (ulong)adjustedValue; } ,但你也可以自己滚动:

ArgumentOutOfRangeException