【问题标题】:unchecked block doesn't work with BigInteger?未经检查的块不适用于 BigInteger?
【发布时间】:2011-08-27 13:30:57
【问题描述】:

刚刚注意到unchecked 上下文在使用 BigInteger 时不起作用,例如:

unchecked
{
    // no exception, long1 assigned to -1 as expected
    var long1 = (long)ulong.Parse(ulong.MaxValue.ToString());
}

unchecked
{
    var bigInt = BigInteger.Parse(ulong.MaxValue.ToString());

    // throws overflow exception
    var long2 = (long)bigInt;
}

知道为什么会这样吗?将大整数转换为其他原始整数类型的方式有什么特别之处吗?

谢谢,

【问题讨论】:

    标签: c# c#-4.0 biginteger unchecked


    【解决方案1】:

    C# 编译器根本不知道 BigInteger 在逻辑上是“整数类型”。它只看到一个用户定义的类型,其中用户定义的显式转换为 long。从编译器的角度来看,

    long long2 = (long)bigInt;
    

    完全一样:

    long long2 = someObject.SomeMethodWithAFunnyNameThatReturnsALong();
    

    它无法进入该方法内部并告诉它停止抛出异常。

    但是当编译器看到

    int x = (int) someLong;
    

    编译器正在生成执行转换的代码,因此它可以选择生成它认为合适的检查或未检查代码。

    记住,“checked”和“unchecked”在运行时无效;当控制进入未经检查的上下文时,CLR 不会进入“未经检查的模式”。 “checked”和“unchecked”是给编译器的关于在块内生成什么样的代码的指令。它们只在编译时起作用,BigInt 转换为 long 的编译已经发生。它的行为是固定的。

    【讨论】:

    • 那么无论如何,有没有办法显式检查或不检查自定义类型方法中的溢出?除了 try/catch(OverflowException)。
    • @alexander,您必须询问编写相关方法的人。
    【解决方案2】:

    OverflowException 实际上是由BigInteger 上定义的显式转换运算符抛出的。它看起来像这样:

    int num = BigInteger.Length(value._bits);
    if (num > 2)
    {
        throw new OverflowException(SR.GetString("Overflow_Int64"));
    }
    

    换句话说,它以这种方式处理溢出无论checkedunchecked 上下文。 The docs actually say so.

    更新:当然,Eric 是最后的决定。请去阅读他的帖子:)

    【讨论】:

      【解决方案3】:

      documentation 明确声明它会在这种情况下抛出OverflowException。检查的上下文仅对 C# 编译器发出的“本机”算术运算产生影响 - 它不包括调用显式转换运算符。

      要“安全地”执行转换,您必须先将其与long.MaxValuelong.MinValue 进行比较,以检查它是否在范围内。为了获得溢出到负面的效果,我怀疑您必须首先在 BigInteger 中执行使用位运算符。例如:

      using System;
      using System.Numerics;
      
      class Program
      {
          static void Main(string[] args)
          {
              BigInteger bigValue = new BigInteger(ulong.MaxValue);
      
              long x = ConvertToInt64Unchecked(bigValue);
              Console.WriteLine(x);
          }
      
          private static readonly BigInteger MaxUInt64AsBigInteger
              = ulong.MaxValue;
      
          private static long ConvertToInt64Unchecked(BigInteger input)
          {
              unchecked
              {
                  return (long) (ulong) (input & MaxUInt64AsBigInteger);
              }
          }
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-12-26
        • 2013-11-24
        • 1970-01-01
        • 2021-07-12
        相关资源
        最近更新 更多