Arbitrary Precision Integer Division


16

Implementeremo la divisione per numeri interi arbitrariamente grandi.

Questo è .

Il compito è scrivere un programma o una funzione che implementa interi di precisione arbitrari e divisione su di essi.

Si noti che molte cose che potrebbero renderlo molto semplice non sono consentite, assicurarsi di leggere le specifiche .

Ingresso

Ti verranno dati 2 elementi come input:

  1. una stringa di 10 cifre di base, chiamala n.
  2. un'altra stringa di 10 cifre di base, chiamala m

Supponiamo chen>m>0 significhi che non ti verrà mai chiesto di dividere per zero .

Produzione

Verranno emessi due numeri Qe Rdove m * Q + R = n e 0 <= R <m

specificazioni

  • Il tuo invio dovrebbe funzionare per numeri interi arbitrariamente grandi (limitati dalla memoria disponibile).

  • Non è possibile utilizzare librerie esterne. Se è necessaria una libreria esterna per l'I / O, è possibile trattarla come integrata. (guardando cose come iostream, ecc.).

  • Se la tua lingua ha un built-in che banalizza questo, non puoi usarlo. Ciò include (ma non può essere limitato a) tipi incorporati in grado di gestire numeri interi di precisione arbitraria.

  • Se un linguaggio per qualche motivo utilizza numeri interi di precisione arbitraria per impostazione predefinita, questa funzionalità non può essere utilizzata per rappresentare numeri interi che in genere non possono essere memorizzati in un 64 bit.

  • Ingresso e uscita DEVONO essere nella base 10 . Non importa come si memorizzano i numeri in memoria o come si esegue l'aritmetica su di essi, ma i / o sarà base 10.

  • Hai 15 secondi per produrre un risultato. Questo per proibire la sottrazione iterata.

  • L'obiettivo qui è effettivamente implementare interi di precisione arbitrari. Se per qualche motivo sei in grado di aderire alle specifiche della sfida e farlo con successo senza implementarle, beh, credo che per te sembri valido.

Casi test

  1. In questo caso, gli input sono 39! e 30!

Ingresso

n = 20397882081197443358640281739902897356800000000 
m = 265252859812191058636308480000000

Produzione

Q = 76899763100160
R = 0
  1. nè la somma di tutti i fattoriali fino a 50, più 1. msono numeri concatenati fino a 20.

ingresso

n = 31035053229546199656252032972759319953190362094566672920420940313
m = 1234567891011121314151617181920

produzione

q = 25138393324103249083146424239449429
r = 62459510197626865203087816633
  1. nè 205! + 200 !. mè quante lacrime PeterTaylor mi ha fatto versare facendo a pezzi le cose che inserisco nella sandbox.

Ingresso

n = 271841734957981007420619769446411009306983931324177095509044302452019682761900886307931759877838550251114468516268739270368160832305944024022562873534438165159941045492295721222833276717171713647977188671055774220331117951120982666270758190446133158400369433755555593913760141099290463039666313245735358982466993720002701605636609796997120000000000000000000000000000000000000000000000000
m = 247

Produzione

q = 1100573825740813795225181252819477770473619155158611722708681386445423816849801159141424129060075102231232666057768175183676764503262931271346408394876267875141461722640873365274628650676808557279259873162169126398101692109801549256156915750794061370041981513180387019893765753438422927286098434193260562682052606153857091520795991080960000000000000000000000000000000000000000000000000
r = 0;

Probabilmente aggiungerò altri casi di test ad un certo punto.

Relazionato

Sembra correlato, ma in realtà non lo è


Le librerie IO contano come librerie esterne?
Johnson Steward,

@JohnsonSteward Non sono sicuro di cosa intendi dire? Per impostazione predefinita, "sì", ma potresti chiarire?
Liam,

@JohnsonSteward bene suppongo che dipenda da cosa stai IOing? È un codice / una libreria di codice?
Ashwin Gupta,

1
Sono ammessi numeri negativi?
TheConstructor

2
@TheConstructor: dalle regole: "supponi che n> m> 0", quindi no, i numeri negativi non sono ammessi.
nimi,

Risposte:


4

Python 2, 427 byte

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

Legge l'input tramite STDIN, ogni numero su una riga separata e stampa il risultato su STDOUT.

Spiegazione

Invece di rappresentare numeri interi come matrici di cifre, rappresentiamo ogni numero intero come l'insieme di bit "on" nella sua rappresentazione binaria. Cioè, un numero intero n è rappresentato come un insieme di indici dei bit che corrispondono a 1 nella rappresentazione binaria di n . Ad esempio, il numero 10, 1010 in binario, è rappresentato come l'insieme {1, 3}. Questa rappresentazione ci permette di esprimere alcune delle operazioni aritmetiche in modo piuttosto succinto, usando le operazioni impostate di Python.

Per aggiungere due insiemi, prendiamo (ricorsivamente) la somma della loro differenza simmetrica, e l'insieme degli interi successivi alla loro intersezione (che corrisponde al carry collettivo, e quindi alla fine diventa l'insieme vuoto, a quel punto abbiamo la somma finale Allo stesso modo, per sottrarre due insiemi, prendiamo (ricorsivamente) la differenza della loro differenza simmetrica e l'insieme degli interi successivi alla loro (insiema) differenza (che corrisponde al prestito collettivo, e quindi alla fine diventa l'insieme vuoto, a quale punto abbiamo la differenza finale.) La somiglianza di queste due operazioni ci consente di implementarle come un'unica funzione ( A).

La moltiplicazione ( M) è semplicemente un'aggiunta distribuita: dati due insiemi A e B , prendiamo la somma, come descritto sopra, di tutti gli insiemi { A + b | bB } (dove A + b è l'insieme { a + b | a A }).

Il confronto intero diventa confronto lessicografico dei due insiemi, ordinati in ordine decrescente.

Per dividere ( D) due insiemi, A e B , iniziamo con l'insieme vuoto come quoziente e troviamo ripetutamente il più grande intero n , in modo che B + n sia minore o uguale ad A (che è semplicemente la differenza tra i massimi di A e B , possibilmente meno-1), aggiungere n come elemento al quoziente e sottrarre B + n da A , come descritto sopra, fino a quando A diventa inferiore a B , ovvero fino a quando non diventa il resto.

Non c'è pranzo libero, ovviamente. Paghiamo l'imposta dovendo convertire da- e in-, decimale. In effetti, la conversione in decimale è ciò che richiede la maggior parte del tempo di esecuzione. Facciamo la conversione "nel solito modo", usando solo le operazioni sopra descritte, anziché l'aritmetica ordinaria.


Solo per curiosità: non s=`sum(2**i for i in d)`+sutilizza l'aritmetica di precisione arbitraria integrata durante la conversione?
TheConstructor il

1
@TheConstructor No. dè una singola cifra decimale, quindi iè compresa tra 0 e 3 e l'intera somma è compresa tra 0 e 9.
Ell

4

Java 8, 485 byte

Potrebbe ridurre di altri 5 byte denominando la funzione danziché di dividealtri 16 byte se non si considera la definizione di classe.

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

Può essere usato in questo modo:

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

cedevole

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

Ho sacrificato un po 'di velocità non precalcolando un array con i mtempi da 1 a 9 e iniziando con b=0invece di b=l(m), ma risparmiando molti byte facendolo. Se sei interessato ad aggiungere arbitrariamente la precisione, vedi una versione precedente .

Immagino che questa non sarà la soluzione più breve, ma forse darà un buon inizio.


Se implementi anche addizioni, moltiplicazioni e sottrazioni per questo, farò una ricompensa di 500 rappresentanti. : DI ama l'idea della precisione Stringy.
Addison Crump,

@VoteToClose lo vedrà domani. Immagino che la parte più difficile sia finita.
TheConstructor l'

1

Mathematica, 251 byte

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]

Spiegazione

L'aritmetica sui numeri decimali può essere facilmente implementata da FoldPairList. Per esempio,

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

imita semplicemente il processo di fare moltiplicazioni a mano.

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

Caso di prova

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

significa 123456789 / 54321= 2272...39477.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.