Довільна точність цілочисельного відділу


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скільки сліз PeterTaylor змусив мене пролити, розриваючи речі, які я розміщую у пісочниці.

Вхідні дані

n = 271841734957981007420619769446411009306983931324177095509044302452019682761900886307931759877838550251114468516268739270368160832305944024022562873534438165159941045492295721222833276717171713647977188671055774220331117951120982666270758190446133158400369433755555593913760141099290463039666313245735358982466993720002701605636609796997120000000000000000000000000000000000000000000000000
m = 247

Вихідні дані

q = 1100573825740813795225181252819477770473619155158611722708681386445423816849801159141424129060075102231232666057768175183676764503262931271346408394876267875141461722640873365274628650676808557279259873162169126398101692109801549256156915750794061370041981513180387019893765753438422927286098434193260562682052606153857091520795991080960000000000000000000000000000000000000000000000000
r = 0;

Я, певно, додам ще тестових випадків у якийсь момент.

Пов'язані

Звуки пов'язані, але насправді немає


Чи вважаються бібліотеки IO зовнішніми бібліотеками?
Джонсон Стюард

@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.

Пояснення

Замість того, щоб представляти цілі числа у вигляді масивів цифр, ми представляємо кожне ціле число як набір бітів "on" у його бінарному поданні. Тобто ціле число 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використовується вбудована довільна арифметика точності під час перетворення?
Конструктор

1
@ TheConstructor No. d- це один десятковий розряд, iтобто від 0 до 3, а вся сума - від 0 до 9.
Ell

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

Безголівки:

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 повторень. : DI люблю ідею строгої точності.
Аддісон Кримп

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

1

Математика, 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.