Произвольное прецизионное целочисленное деление


16

Мы будем реализовывать деление для сколь угодно больших целых чисел.

Это .

Задача состоит в том, чтобы написать программу или функцию, которая реализует целые числа произвольной точности и деление на них.

Обратите внимание, что многие вещи, которые могут сделать это очень легко, запрещены, пожалуйста, не забудьте прочитать спецификацию .

вход

Вам дадут 2 вещи в качестве входных данных:

  1. Строка из 10 цифр, назовите это n.
  2. еще одна строка из 10 цифр, назовите ее m

Предположим, этоn>m>0 означает, что вас никогда не попросят делить на ноль .

Выход

Вы выведете два числа, Qи Rгде m * Q + R = n и 0 <= R <m

Характеристики

  • Ваше представление должно работать для сколь угодно больших целых чисел (ограничено доступной памятью).

  • Вы не можете использовать внешние библиотеки. Если вам нужна внешняя библиотека для ввода / вывода, вы можете рассматривать ее как встроенную. (глядя на такие вещи, как iostream и т. д.).

  • Если у вашего языка есть встроенная система, которая упрощает это, вы не можете ее использовать. Это включает (но не ограничивается ими) встроенные типы, которые могут обрабатывать произвольные целые числа точности.

  • Если по какой-либо причине в языке по умолчанию используются целые числа произвольной точности, эта функциональность не может использоваться для представления целых чисел, которые обычно не могут храниться в 64 битах.

  • Вход и выход ДОЛЖНЫ быть в базе 10 . Неважно, как вы храните числа в памяти или как вы выполняете арифметику с ними, но ввод / вывод будет основой 10.

  • У вас есть 15 секунд, чтобы вывести результат. Это должно запретить повторное вычитание.

  • Цель здесь - реализовать целые числа произвольной точности. Если по какой-то причине вы можете придерживаться спецификаций испытаний и успешно делать это без их реализации, я думаю, что это хорошо для вас, звучит правильно.

Тестовые случаи

  1. В этом случае входы 39! и 30!

вход

n = 20397882081197443358640281739902897356800000000 
m = 265252859812191058636308480000000

Выход

Q = 76899763100160
R = 0
  1. nэто сумма всех факториалов до 50, плюс 1. mэто объединенные числа до 20.

вход

n = 31035053229546199656252032972759319953190362094566672920420940313
m = 1234567891011121314151617181920

выход

q = 25138393324103249083146424239449429
r = 62459510197626865203087816633
  1. nэто 205! + 200 !. mСколько слез заставил меня пролить Питер Тейлор, разрывая вещи, которые я выкладываю в песочнице.

вход

n = 271841734957981007420619769446411009306983931324177095509044302452019682761900886307931759877838550251114468516268739270368160832305944024022562873534438165159941045492295721222833276717171713647977188671055774220331117951120982666270758190446133158400369433755555593913760141099290463039666313245735358982466993720002701605636609796997120000000000000000000000000000000000000000000000000
m = 247

Выход

q = 1100573825740813795225181252819477770473619155158611722708681386445423816849801159141424129060075102231232666057768175183676764503262931271346408394876267875141461722640873365274628650676808557279259873162169126398101692109801549256156915750794061370041981513180387019893765753438422927286098434193260562682052606153857091520795991080960000000000000000000000000000000000000000000000000
r = 0;

Я, вероятно, добавлю больше тестов в какой-то момент.

Связанный

Звучит похоже, но на самом деле это не так


Библиотеки ввода-вывода считаются внешними библиотеками?
Джонсон Стюард

@JohnsonSteward Я не уверен, что ты имеешь в виду под этим? Я бы по умолчанию сказал "да", но не могли бы вы уточнить?
Лиам

@JohnsonSteward хорошо, я полагаю, это зависит от того, что вы делаете? Это код / ​​библиотека кода?
Эшвин Гупта

1
Разрешены ли отрицательные числа?
TheConstructor

2
@TheConstructor: из правил: «предположим, что n> m> 0», поэтому нет, отрицательные числа не допускаются.
Ними,

Ответы:


4

Python 2, 427 байт

b=S=lambda l:sorted(l)[::-1]
A=lambda a,b,o=0:A(a^b,{n+1for n in[b&a,b-a][o]},o)if b else a
M=lambda a,*b:reduce(A,({n+m for n in a}for m in b))
def D(a,b):
 q=a-a
 while b<=S(a):n=max(a)-b[0];n-=S(M(b,n))>S(a);q|={n};a=A(a,M(b,n),1)
 return q,a
exec"a=b;b=[]\nfor d in raw_input():b=A(M(b,3,1),{i for i in range(4)if int(d)>>i&1})\n"*2
for n in D(a,S(b)):
 s=''
 while n:n,d=D(n,[3,1]);s=`sum(2**i for i in d)`+s
 print s or 0

Считывает ввод через STDIN, каждое число в отдельной строке, и выводит результат в STDOUT.

объяснение

Вместо того, чтобы представлять целые числа как массивы цифр, мы представляем каждое целое число как набор включенных бит в его двоичном представлении. Таким образом, целое число n представляется как набор индексов битов, равных 1 в двоичном представлении n . Например, число 10, 1010 в двоичном виде, представлено в виде набора {1, 3}. Это представление позволяет нам довольно кратко выразить некоторые арифметические операции, используя операции множеств Python.

Чтобы добавить два набора, мы (рекурсивно) берем сумму их симметричной разности и набор последовательных целых чисел на их пересечении (что соответствует коллективному переносу, и, следовательно, в конечном итоге становится пустым набором, и в этот момент мы получаем окончательную сумму .) Аналогично, чтобы вычесть два набора, мы (рекурсивно) берем разность их симметричной разности, а набор последующих целых чисел - их (множество) разности (что соответствует коллективному заимствованию и, следовательно, в конечном итоге становится пустым множеством, в в какой момент у нас есть окончательное различие.) Сходство этих двух операций позволяет нам реализовать их как одну функцию ( A).

Умножение ( M) является просто распределенным сложением: для двух множеств A и B мы берем сумму, как описано выше, всех множеств { A + b | bB } (где A + b - множество { a + b | aA }).

Целочисленное сравнение становится лексикографическим сравнением двух наборов, отсортированных по убыванию.

Чтобы разделить ( D) два набора, A и B , мы начинаем с пустого набора в качестве фактора и многократно находим наибольшее целое число n , такое, что B + n меньше или равно A (что является просто разницей между максимумами). из A и B , возможно, минус 1), добавьте n в качестве элемента к частному и вычтите B + n из A , как описано выше, до тех пор, пока A не станет меньше B , то есть до тех пор, пока не станет остаток.

Там нет бесплатного обеда, конечно. Мы платим налог, когда необходимо преобразовать десятичные дробные числа в десятичные. Фактически, преобразование в десятичное - это то, что занимает большую часть времени выполнения. Мы делаем преобразование «обычным способом», используя только вышеприведенные операции вместо обычной арифметики.


Просто из любопытства: разве не s=`sum(2**i for i in d)`+sиспользуется встроенная арифметика произвольной точности во время преобразования?
TheConstructor

1
@TheConstructor No. d- это одна десятичная цифра, поэтому она iнаходится в диапазоне от 0 до 3, а вся сумма в диапазоне от 0 до 9.
Весь

4

Java 8, 485 байт

Может быть уменьшен еще на 5 байтов, называя функцию dвместо divideили еще на 16 байтов, если не считать определение класса.

public class G{int l(String a){return a.length();}String s(String n,String m){while(l(n)>l(m))m=0+m;String a="";for(int c=1,i=l(n);i>0;c=c/10){c=n.charAt(--i)+c-m.charAt(i)+9;a=c%10+a;}return e(a);}String e(String a){return a.replaceAll("^0+(?=[0-9])","");}String divide(String n,String m){String q="",p=q,y;for(int b=0,i=0;b<=l(n);i--){y=n.substring(0,b);if(l(y)==l(p)&&p.compareTo(y)<=0||l(y)>l(p)){y=s(y,p);n=y+n.substring(b);q+=i;b=l(y)+1;i=10;p=m+0;}p=s(p,m);}return e(q)+","+n;}}

Можно использовать так:

public static void main(String[] args) {
    G devision = new G();
    System.out.println(devision.divide("20397882081197443358640281739902897356800000000",
            "265252859812191058636308480000000"));
    System.out.println(devision.divide("31035053229546199656252032972759319953190362094566672920420940313",
            "1234567891011121314151617181920"));
    System.out.println(devision.divide(
            "271841734957981007420619769446411009306983931324177095509044302452019682761900886307931759877838550251114468516268739270368160832305944024022562873534438165159941045492295721222833276717171713647977188671055774220331117951120982666270758190446133158400369433755555593913760141099290463039666313245735358982466993720002701605636609796997120000000000000000000000000000000000000000000000000",
            "247"));
}

получая

76899763100160,0
25138393324103249083146424239449429,62459510197626865203087816633
1100573825740813795225181252819477770473619155158611722708681386445423816849801159141424129060075102231232666057768175183676764503262931271346408394876267875141461722640873365274628650676808557279259873162169126398101692109801549256156915750794061370041981513180387019893765753438422927286098434193260562682052606153857091520795991080960000000000000000000000000000000000000000000000000,0

Ungolfed:

public class ArbitraryPrecisionDivision {

    /**
     * Length of String
     */
    int l(String a) {
        return a.length();
    }

    /**
     * substract m of n; n >= m
     */
    String s(String n, String m) {
        while (l(n) > l(m))
            m = 0 + m;
        String a = "";
        for (int c = 1, i = l(n); i > 0; c = c / 10) {
            c = n.charAt(--i) + c - m.charAt(i) + 9;
            a = c % 10 + a;
        }
        return e(a);
    }

    /**
     * trim all leading 0s
     */
    String e(String a) {
        return a.replaceAll("^0+(?=[0-9])", "");
    }

    /**
     * divide n by m returning n/m,n%m; m may not start with a 0!
     */
    String divide(String n, String m) {
        // q stores the quotient, p stores m*i, y are the b leading digits of n
        String q = "", p = q, y;
        for (int b = 0, i = 0; b <= l(n); i--) {
            y = n.substring(0, b);
            if (l(y) == l(p) && p.compareTo(y) <= 0 || l(y) > l(p)) {
                y = s(y, p);
                n = y + n.substring(b);
                q += i;
                b = l(y) + 1;
                i = 10;
                p = m + 0;
            }
            p = s(p, m);
        }
        return e(q) + "," + n;
    }

    public static void main(String[] args) {
        ArbitraryPrecisionDivision division = new ArbitraryPrecisionDivision();
        System.out.println(division.divide("20397882081197443358640281739902897356800000000",
                "265252859812191058636308480000000"));
        System.out.println(division.divide("31035053229546199656252032972759319953190362094566672920420940313",
                "1234567891011121314151617181920"));
        System.out.println(division.divide(
                "271841734957981007420619769446411009306983931324177095509044302452019682761900886307931759877838550251114468516268739270368160832305944024022562873534438165159941045492295721222833276717171713647977188671055774220331117951120982666270758190446133158400369433755555593913760141099290463039666313245735358982466993720002701605636609796997120000000000000000000000000000000000000000000000000",
                "247"));
    }
}

Я пожертвовал немного скоростью, не рассчитав массив с m1 по 9 и начав с b=0вместо b=l(m), но сохранив при этом много байтов. Если вы заинтересованы в добавлении произвольной точности, смотрите предыдущую версию .

Я думаю, это не будет самым коротким решением, но, возможно, оно даст хорошее начало.


Если вы также примените сложение, умножение и вычитание для этого, я вознагражу за это 500 представителей. : D Мне нравится идея строгой точности.
Эддисон Крамп

@VoteToClose позаботится об этом завтра. Угадай, самая сложная часть сделана.
TheConstructor

1

Mathematica, 251 байт

r=Reverse;f=FoldPairList;s={0}~Join~#&;
p[a_,b_]:={First@#,#[[2,1,-1,2]]}/.{Longest[0..],x__}:>{x}&@Reap@f[Sow@{Length@#-1,Last@#}&@NestWhileList[r@f[{#~Mod~10,⌊#/10⌋}&[#+Subtract@@#2]&,0,r@Thread@{#,s@b}]&,Rest@#~Join~{#2},Order[#,s@b]<=0&]&,0s@b,s@a]

объяснение

Арифметика десятичных чисел может быть легко реализована FoldPairList. Например,

times[lint_,m_]:=Reverse@FoldPairList[{#~Mod~10,⌊#/10⌋}&[m #2+#]&,0,Reverse@lint]

просто имитирует процесс умножения вручную.

times[{1,2,3,4,5},8]
(* {9,8,7,6,0} *)

Прецедент

p[{1,2,3,4,5,6,7,8,9},{5,4,3,2,1}] 
(* {{2,2,7,2},{3,9,4,7,7}} *)

значит 123456789 / 54321= 2272...39477.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.