Arbitrary Precision Integer Division


16

Wir werden Division für beliebig große ganze Zahlen implementieren.

Das ist .

Die Aufgabe besteht darin, ein Programm oder eine Funktion zu schreiben, die Ganzzahlen mit willkürlicher Genauigkeit und Division darauf implementiert.

Beachten Sie, dass viele Dinge, die dies sehr einfach machen könnten, nicht zulässig sind . Lesen Sie die technischen Daten sorgfältig durch .

Eingang

Sie erhalten 2 Dinge als Eingabe:

  1. Nennen Sie es eine Zeichenfolge mit 10 Stellen zur Basis n.
  2. eine andere Zeichenfolge mit 10 Stellen zur Basis, nennen Sie es m

Nehmen n>m>0Sie an, dass Sie niemals aufgefordert werden, durch Null zu teilen .

Ausgabe

Sie werden ausgegeben zwei Zahlen, Qund Rwo m * Q + R = n und 0 <= R <m

Spezifikationen

  • Ihre Übermittlung sollte für beliebig große Ganzzahlen funktionieren (begrenzt durch den verfügbaren Speicher).

  • Sie dürfen keine externen Bibliotheken verwenden. Wenn Sie eine externe Bibliothek für I / O benötigen, können Sie diese als integrierte Bibliothek behandeln. (Betrachten von Dingen wie iostream usw.).

  • Wenn Ihre Sprache über eine integrierte Funktion verfügt, die dies trivialisiert, können Sie sie möglicherweise nicht verwenden. Dies umfasst (ohne darauf beschränkt zu sein) integrierte Typen, die Ganzzahlen mit beliebiger Genauigkeit verarbeiten können.

  • Wenn eine Sprache aus irgendeinem Grund standardmäßig Ganzzahlen mit willkürlicher Genauigkeit verwendet, kann diese Funktionalität nicht zur Darstellung von Ganzzahlen verwendet werden, die normalerweise nicht in 64-Bit-Formaten gespeichert werden konnten.

  • Eingang und Ausgang MÜSSEN in der Basis 10 sein . Es spielt keine Rolle, wie Sie die Zahlen im Speicher ablegen oder wie Sie mit ihnen rechnen, aber I / O wird die Basis 10 sein.

  • Sie haben 15 Sekunden Zeit, um ein Ergebnis auszugeben. Dies soll eine iterierte Subtraktion verhindern.

  • Das Ziel hierbei ist die Implementierung von Ganzzahlen mit willkürlicher Genauigkeit. Wenn Sie aus irgendeinem Grund in der Lage sind, die Herausforderungsspezifikationen einzuhalten und dies erfolgreich zu tun, ohne sie zu implementieren, dann klingt das gut für Sie.

Testfälle

  1. In diesem Fall sind die Eingänge 39! und 30!

Eingang

n = 20397882081197443358640281739902897356800000000 
m = 265252859812191058636308480000000

Ausgabe

Q = 76899763100160
R = 0
  1. nist die Summe aller Fakultäten bis zu 50 plus 1. mist verkettete Zahlen bis zu 20.

Eingang

n = 31035053229546199656252032972759319953190362094566672920420940313
m = 1234567891011121314151617181920

Ausgabe

q = 25138393324103249083146424239449429
r = 62459510197626865203087816633
  1. nist 205! + 200 !. mist, wie viele Tränen PeterTaylor mich vergossen hat, indem er Dinge, die ich im Sandkasten postiere, auseinandergerissen hat.

Eingang

n = 271841734957981007420619769446411009306983931324177095509044302452019682761900886307931759877838550251114468516268739270368160832305944024022562873534438165159941045492295721222833276717171713647977188671055774220331117951120982666270758190446133158400369433755555593913760141099290463039666313245735358982466993720002701605636609796997120000000000000000000000000000000000000000000000000
m = 247

Ausgabe

q = 1100573825740813795225181252819477770473619155158611722708681386445423816849801159141424129060075102231232666057768175183676764503262931271346408394876267875141461722640873365274628650676808557279259873162169126398101692109801549256156915750794061370041981513180387019893765753438422927286098434193260562682052606153857091520795991080960000000000000000000000000000000000000000000000000
r = 0;

Ich werde wahrscheinlich irgendwann weitere Testfälle hinzufügen.

verbunden

Klingt verwandt, ist es aber nicht


Zählen IO-Bibliotheken als externe Bibliotheken?
Johnson Steward

@JohnsonSteward Ich bin nicht sicher, was du damit meinst? Ich würde standardmäßig "Ja" wählen, aber könnten Sie das klären?
Liam

@ JohnsonSteward Nun, ich nehme an, es hängt davon ab, was Sie tun? Ist es Code / eine Bibliothek von Code?
Ashwin Gupta

1
Sind negative Zahlen erlaubt?
TheConstructor

2
@TheConstructor: Aus den Regeln: "nehme an, dass n> m> 0 ist", also nein, negative Zahlen sind nicht erlaubt.
nimi

Antworten:


4

Python 2, 427 Bytes

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

Liest die Eingabe über STDIN, jede Nummer in einer separaten Zeile, und gibt das Ergebnis an STDOUT aus.

Erläuterung

Anstatt Ganzzahlen als Arrays von Ziffern darzustellen, stellen wir jede Ganzzahl als die Menge von "Ein" -Bits in ihrer Binärdarstellung dar. Das heißt, eine ganze Zahl n wird als die Menge von Indizes der Bits dargestellt, die in der binären Darstellung von n gleich 1 sind . Beispielsweise wird die Zahl 10, 1010 im Binärformat als Menge {1, 3} dargestellt. Diese Darstellung ermöglicht es uns, einige der arithmetischen Operationen mit Pythons Mengenoperationen ziemlich prägnant auszudrücken.

Um zwei Mengen zu addieren, nehmen wir (rekursiv) die Summe ihrer symmetrischen Differenz und die Menge der nachfolgenden ganzen Zahlen zu ihrem Schnittpunkt (der dem kollektiven Übertrag entspricht und daher schließlich zur leeren Menge wird, an diesem Punkt haben wir die Endsumme .) Um zwei Mengen zu subtrahieren, nehmen wir (rekursiv) die Differenz ihrer symmetrischen Differenz und die Menge der nachfolgenden ganzen Zahlen zu ihrer (Mengen-) Differenz (die der kollektiven Entlehnung entspricht und somit letztendlich zur leeren Menge wird, zu Welchen Punkt haben wir den endgültigen Unterschied.) Die Ähnlichkeit dieser beiden Operationen ermöglicht es uns, sie als eine einzige Funktion zu implementieren ( A).

Multiplikation ( M) ist einfach verteilte Addition: Bei zwei Mengen A und B nehmen wir wie oben beschrieben die Summe aller Mengen { A + b | bB } (wobei A + b die Menge { a + b | aA } ist).

Der Ganzzahlvergleich wird zum lexikografischen Vergleich der beiden Mengen, sortiert in absteigender Reihenfolge.

Um ( D) zwei Mengen A und B zu teilen , beginnen wir mit der leeren Menge als Quotient und finden wiederholt die größte ganze Zahl n , so dass B + n kleiner oder gleich A ist (was einfach die Differenz zwischen den Maxima ist) von A und B , möglicherweise minus 1), addieren Sie n als Element zum Quotienten und subtrahieren Sie B + n von A , wie oben beschrieben, bis A kleiner als B wird , dh bis es zum Rest wird.

Natürlich gibt es kein kostenloses Mittagessen. Wir zahlen die Steuer, indem wir von- und zu- Dezimalstellen umrechnen müssen. Tatsächlich nimmt die Konvertierung in Dezimalzahlen den größten Teil der Laufzeit in Anspruch. Wir führen die Konvertierung "auf die übliche Art und Weise" durch und verwenden nur die oben genannten Operationen anstelle von gewöhnlicher Arithmetik.


Nur aus Neugier: s=`sum(2**i for i in d)`+sVerwenden Sie während der Konvertierung keine eingebaute Arithmetik mit willkürlicher Genauigkeit?
TheConstructor

1
@TheConstructor No. dist eine einzelne Dezimalstelle, iliegt also zwischen 0 und 3, und die gesamte Summe liegt zwischen 0 und 9.
Ell

4

Java 8, 485 Bytes

Könnte die Benennung der Funktion dstattdessen um weitere 5 Bytes reduzieren divideoder um weitere 16 Bytes, wenn die Klassendefinition nicht gezählt wird.

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;}}

Kann so verwendet werden:

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"));
}

nachgebend

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"));
    }
}

Ich habe ein wenig an Geschwindigkeit eingebüßt, indem ich ein Array mit den mZeiten 1 bis 9 nicht vorberechnet und b=0stattdessen mit begonnen habe b=l(m), sondern viele Bytes gespart habe. Wenn Sie an einer beliebigen Präzisionsaddition interessiert sind, lesen Sie eine frühere Version .

Ich denke, dies wird nicht die kürzeste Lösung sein, aber vielleicht gibt es einen guten Start.


Wenn Sie auch hierfür Addition, Multiplikation und Subtraktion implementieren, mache ich eine Prämie von 500 Wiederholungen. : DI lieben die Idee der Stringy Präzision.
Addison Crump

@VoteToClose wird sich morgen darum kümmern. Vermutlich ist der schwierigste Teil erledigt.
TheConstructor

1

Mathematica, 251 Bytes

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]

Erläuterung

Arithmetik auf Dezimalzahlen kann leicht durch implementiert werden FoldPairList. Beispielsweise,

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

ahmt nur den Vorgang der Multiplikation von Hand nach.

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

Testfall

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

bedeutet 123456789 / 54321= 2272...39477.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.