【问题标题】:How to know a value overflows without recurring to a runtime OverflowException如何在不重复运行时溢出异常的情况下知道值溢出
【发布时间】:2014-09-21 08:14:17
【问题描述】:

所以问题是:

给定一个在给定编译器(语言?)中表示最大可能数字的本机整数类型,例如 C# 中的 ulong,您如何检测到表示数字的输入字符串将溢出最大值可以由该给定类型表示,而无需回退到已检查的上下文和运行时OveflowException?

显然 C# 编译器可以检测常量整数溢出:

ulong l = 18446744073709551615; //ok
ulong l = 18446744073709551616; //compile time error: Integral constant is too large.

编译器是否在后台使用运行时OverflowException(或等效项)?如果是这样,有没有办法在不重复运行时异常或构建可以容纳更大数字的数字类型(如System.Numeric.BigInt)的情况下实际执行此操作?值得注意的是,BigInt 在 C# 中没有原生支持,因为以下是编​​译时错误,尽管整数常量在类型范围内:

BigInt i = 18446744073709551616; //compile time error: Integral constant is too large.

【问题讨论】:

  • TryParse 这样的幕后异常是否也算作禁忌?
  • 你可以看看UInt64.TryParse,路上没有try-catch。但是,我不知道编译器实际使用的方式。
  • @InBetween :“如果我没记错,TryParse 只是包装了 Parse,它确实会引发运行时异常”。不,这是一个无异常的实现。这就是重点。
  • 您可以使用unchecked 上下文并进行类似硬件的溢出检测,但不确定这是否比异常更好。
  • @InBetween:出于某种原因,我上面指向Uint64.TryParse 的链接不正确,这是我最初想要链接的内容:referencesource.microsoft.com/#mscorlib/system/…

标签: c# integer-overflow


【解决方案1】:

这样的解决方案可以算作一个解决方案吗?

string s1 = "18446744073709551616";
string s2 = ulong.MaxValue.ToString();
// assuming s1 contains digits only and no leading zeros
if(
    s1.Length > s2.Length ||
    s1.Length == s2.Length && string.CompareOrdinal(s1, s2) > 0
)
    Console.WriteLine("overflow");

【讨论】:

  • 不错的一个 :) 我们考虑过这样做,但它似乎比其他任何方法都更糟糕。我们更喜欢一些聪明的数学技巧,但似乎没有。
  • @InBetween 好吧,更合适的方法是实现自己的解析器。见NumberToUInt64
【解决方案2】:

编译器很可能一次只解析输入一个数字,代码类似于ulong.Parse,但显然适应了任务。

ulong.Parse 确定它溢出的方式相当简单,但您确实需要知道如何解析整数。 ulong.Parse 一次解析输入一个字符。它维护ulong 结果,并且对于每个字符,它将结果乘以 10,然后将字符的值相加(即 0 到 9),并一直这样做直到输入用完或结果溢出。

有两种溢出检查,因为有两种东西会溢出:乘以 10 和加法。为了检查乘法不会溢出,将当前结果与1844674407370955161 进行比较。如果结果大于这个值,并且还有数字,则算法退出,报告溢出。观察到这个数字和ulong.MaxValue一样,去掉了最后一个数字,使它成为可以乘以10而不会溢出的最大整数。

接下来,它需要检查从0到9的数字相加是否会溢出。它首先添加数字,然后检查结果是否减少而不是增加。这是因为加法是如何在 CPU 内部实现的;基本上结果的最高位被丢弃,因为它不适合。

就是这样,真的。如果字符用完而没有触发上述两个检查中的任何一个,则该数字解析成功,否则为溢出。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-07-11
    • 2020-11-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多