Есть ли хороший, производительный тип беззнакового BigInteger для C #? - PullRequest
4 голосов
/ 10 мая 2011

Я знаком с классом System.Numerics.BigInteger, но в моем приложении я имею дело только с положительными целыми числами. Отрицательные целые числа являются ошибкой, и было бы неплохо, если бы существовал неподписанный эквивалент типа BigInteger, чтобы я мог удалить все эти проверки. Один существует?

Ответы [ 5 ]

2 голосов
/ 10 мая 2011

Там нет ничего в рамках, нет.Я бы попытался централизовать проверки как можно меньшего размера общедоступного API, а затем обработать данные как действительные в течение остального времени - так же, как и для чего-то вроде нулевой проверки.Конечно, вам все равно нужно быть осторожным, если вы выполняете какие-либо операции, которые могут создать отрицательное значение (например, вычитать одно из другого).

Вы можете сделать код немного аккуратнеесоздав метод расширения, например,

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

... и используйте его так:

input.ThrowIfNegative("input");

Вы можете потенциально создать свою собственную UBigInteger структуру, которая содержит BigIntegerи выполнять операции между различными значениями, используя реализацию и проверки BigInteger, но я подозреваю, что это будет довольно много работы для сравнительно небольшой выгоды, и может иметь влияние на производительность, если вы используете егодля многих расчетов.

1 голос
/ 10 мая 2011

Хорошо, давайте посмотрим на простой пример

        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, где они вам нужны, например, так, как предложил Джон Скит.</p>

1 голос
/ 10 мая 2011

Если вы используете только небольшое подмножество API-интерфейса BigInteger, написание собственного класса-оболочки легко, если кропотливо. Вот пример кода, демонстрирующий, что операция не должна быть такой большой:

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 ...
}
0 голосов
/ 10 мая 2011

Если отрицательные значения представляют такую ​​проблему, возможно ли их как-то устранить, чтобы неверные данные (отрицательные значения) даже не доходили до вашей логики?Это исключит проверку все вместе.Не могли бы вы опубликовать короткий фрагмент того, что вы делаете?

0 голосов
/ 10 мая 2011

В фреймворке нет поддержки для объявления BigInteger как unsigned. Однако вы можете создать статический метод, чтобы проверить, является ли число отрицательным или нет.

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