1/большое целое число в С#

я хочу сделать

BigInteger.ModPow(1/BigInteger, 2,5);

но 1/BigInteger всегда возвращает 0, что приводит к тому, что результат тоже 0. Я пытался найти какой-нибудь класс BigDecimal для С#, но ничего не нашел. Есть ли способ, как это посчитать, даже если BigDecimal нет?


person MartinS    schedule 06.01.2013    source источник
comment
Используйте что-то другое вместо Integer. Как насчет двойного?   -  person Vlad Spreys    schedule 06.01.2013
comment
Double слишком короток для деления на BigInteger   -  person MartinS    schedule 06.01.2013
comment
Как возможно 1/BigInteger возвращает 0 ?. BigInters значение по умолчанию — 0. Он должен быть брошен DivideByZeroException.   -  person Soner Gönül    schedule 06.01.2013
comment
Из того немногого, что я знаю об Эль-Гамале, я не думаю, что буквальное мультипликативное обратное — это то, что вы ищете.   -  person Rawling    schedule 06.01.2013
comment
@MartinŠevic Зависит от того, что вы хотите. Предположим, что ваш знаменатель представляет собой BigInteger с менее чем 300 десятичными цифрами, тогда деление 1 на соответствующий двойной работает нормально. Точность теряется, но величина в порядке. Но с, например. 400 десятичных цифр, double будет переполняться/ниже значения до бесконечности или нуля.   -  person Jeppe Stig Nielsen    schedule 06.01.2013
comment
@SonerGönül Ну, он не должен компилироваться, потому что он не говорит ни new BigInteger(), ни default(BigInteger). Он должен жаловаться, что тип используется как переменная в выражении.   -  person Jeppe Stig Nielsen    schedule 06.01.2013
comment
@JeppeStigNielsen В этом случае BigInteger не выглядит как переменная. Это похоже на использование класса.   -  person Soner Gönül    schedule 06.01.2013
comment
@SonerGönül Как я уже сказал, это это тип (в данном случае это struct), и поэтому его запрещено использовать как если бы это была переменная.   -  person Jeppe Stig Nielsen    schedule 06.01.2013
comment
Microsoft Solver Foundation имеет рациональный класс; если вы хотите представить точные рациональные числа, это весьма полезно. Вы можете скачать это бесплатно.   -  person Eric Lippert    schedule 06.01.2013


Ответы (3)


1/a равно 0 для |a|>1, так как BigIntegers использует целочисленное деление, где дробная часть деления игнорируется. Я не уверен, какой результат вы ожидаете от этого.

Я предполагаю, что вы хотите модульную мультипликативную инверсию a по модулю m, а не дробное число. Эта инверсия существует тогда и только тогда, когда a и m взаимно просты, т. е. gcd(a, m) = 1.

На связанной странице википедии перечислены два стандартных алгоритма вычисления модульного мультипликативного обратного:

  • Расширенный алгоритм Евклида, который работает для произвольных модулей
    Он быстр, но его время выполнения зависит от ввода .

    У меня нет под рукой кода C#, но перенос псевдокода из Википедии должен быть простым.

  • Используя теорему Эйлера:
    $i^{-1} = i^{φ(  n)-1}$
    Это требует знания φ(m), т.е. вам нужно знать простые множители m. Это популярный выбор, когда m является простым числом и, следовательно, φ(m) = m-1, когда оно просто становится $a^{-1} = a^{p-2}$. Если вам нужно постоянное время выполнения и вы знаете φ(m), то это то, что вам нужно.

    В С# это становится BigInteger.ModPow(a, phiOfM-1, m)

person CodesInChaos    schedule 06.01.2013
comment
Возможно, ты прав. Обратите внимание, что i и n должны быть взаимно простыми, чтобы это было правильно определено. - person Jeppe Stig Nielsen; 06.01.2013

Перегрузка выбранного оператора / выглядит следующим образом:

public static BigInteger operator /(
        BigInteger dividend,
        BigInteger divisor
)

См. раздел Оператор BigInteger.Division. Если результат находится между 0 и 1 (что вероятно, когда dividend равно 1, как в вашем случае), поскольку возвращаемое значение является целым числом, как вы видите, возвращается 0.

Что вы пытаетесь сделать с помощью метода ModPow? Вы понимаете, что 2,5 - это два аргумента, два и пять, а не "две целых пять десятых"? Ваше намерение «взять квадрат по модулю 5»?

Если вы хотите деление с плавающей запятой, вы можете использовать:

1.0 / (double)yourBigInt

Обратите внимание на приведение к double. Это может привести к потере точности и даже к нулю, если yourBigInt слишком велико.

person Jeppe Stig Nielsen    schedule 06.01.2013

Например, вам нужно получить d следующим образом:
3*d = 1 (mod 9167368)

это равно:
3*d = 1 + k * 9167368, где k = 1, 2, 3, ...

перепишите его:
d = (1 + k * 9167368)/3

Ваше d должно быть целым числом с наименьшим k.
Давайте напишем формулу:
d = (1 + k * fi)/e

public static int MultiplicativeInverse(int e, int fi)
        {
            double result;
            int k = 1;
            while (true)
            {
                result = (1 + (k * fi)) / (double) e;
                if ((Math.Round(result, 5) % 1) == 0) //integer
                {
                    return (int)result;
                }
                else
                {
                    k++;
                }
            }
        } 

давайте протестируем этот код:

Assert.AreEqual(Helper.MultiplicativeInverse(3, 9167368), 6111579); // passed
person Yuliia Ashomok    schedule 08.03.2015