是否有适用于 C# 的良好、高性能的无符号 BigInteger 类型

本文关键字:高性能 无符号 BigInteger 类型 适用于 是否 | 更新日期: 2023-09-27 17:56:11

>我熟悉System.Numerics.BigInteger类,但在我的应用程序中,我只处理正整数。负整数是一种错误情况,如果有一个 BigInteger 类型的无符号等效项,这样我就可以删除所有这些检查,那就太好了。存在吗?

是否有适用于 C# 的良好、高性能的无符号 BigInteger 类型

框架中没有任何内容,没有。我会尝试将检查集中在尽可能小的公共 API 中,然后在其余时间将数据视为有效 - 就像您对空检查之类的事情一样。当然,如果您执行任何可能产生负值的操作(例如,从一个减去另一个),您仍然需要小心。

您可以通过创建扩展方法使代码稍微整洁一些,例如

public static void ThrowIfNegative(this BigInteger value, string name)
{
    if (value.Sign < 0)
    {
        throw new ArgumentOutOfRangeException(name);
    }
}

。并像这样使用它:

input.ThrowIfNegative("input");

您可以创建自己的包含BigIntegerUBigInteger 结构,并使用BigInteger实现和检查在不同值之间执行操作,但我怀疑这将是相当多的工作,相对较少的好处,并且如果您将其用于大量计算,可能会对性能产生影响。

好吧,让我们看一个简单的例子

        uint a=1;
        uint b=2;
        uint c=a-b;
        Console.WriteLine(c);

为您提供输出4294967295 (=2^32-1)。

但是,如果您有一个具有类似行为的无符号 BigInteger 怎么办?

        UBigInteger a(1);
        UBigInteger b(2);
        UBigInteger c=a-b;
        Console.WriteLine(c.ToString());

那应该是什么?当然,从你写的内容来看,你可以假设在这种情况下你可能会得到某种异常,但这种行为与int不一致。例如,最好在需要的地方引入<0 的检查,就像 Jon Skeet 建议的那样。

如果您只使用 BigInteger API 的相当小的子集,那么编写自己的包装类很容易,尽管很费力。 下面是一些示例代码来演示它不需要那么大的操作:

public struct UnsignedBigInteger
{
    private BigInteger value;
    private UnsignedBigInteger(BigInteger n) { value = n; }
    public UnsignedBigInteger(uint n) { value = new BigInteger(n); }
    // ... other constructors ...
    public static UnsignedBigInteger operator+(UnsignedBigInteger lhs, UnsignedBigInteger rhs)
    {
        return new UnsignedBigInteger(lhs.value + rhs.value);
    }
    public static UnsignedBigInteger operator-(UnsignedBigInteger lhs, UnsignedBigInteger rhs)
    {
        var result = lhs.value - rhs.value;
        if (result < BigInteger.Zero) throw new InvalidOperationException("value out of range");
        return new UnsignedBigInteger(result);
    }
    // ... other operators ...
}

如果负值存在这样的问题,是否可以以某种方式消除它们,以便错误数据(负值)甚至无法到达您的逻辑?这将一起消除检查。你能发布一个你正在做的事情的简短片段吗?

框架中没有任何支持将BigInteger声明为 unsigned 。但是,您可以创建一个静态方法来检查该数字是否为负数。

public static void ValidateBigIntForUnsigned(BigInteger bigInteger)
{
   if(bigInteger.Sign < 0)
       throw new Exception("Only unsigned numbers are allowed!");
}