Division de l'entier de précision arbitraire


16

Nous allons implémenter la division pour les entiers arbitrairement grands.

C'est du .

La tâche consiste à écrire un programme ou une fonction qui implémente des entiers de précision arbitraire et une division sur eux.

Notez que beaucoup de choses qui pourraient rendre cela très facile sont interdites, veuillez vous assurer de lire la spécification .

Contribution

Vous recevrez 2 choses en entrée:

  1. une chaîne de 10 chiffres de base, appelez-la n.
  2. une autre chaîne de base de 10 chiffres, appelez-la m

Supposons que celan>m>0 signifie que l' on ne vous demandera jamais de diviser par zéro .

Production

Vous allez sortir deux nombres, Qet Rm * Q + R = n et 0 <= R <m

Caractéristiques

  • Votre soumission doit fonctionner pour des entiers arbitrairement grands (limités par la mémoire disponible).

  • Vous ne pouvez pas utiliser de bibliothèques externes. Si vous avez besoin d'une bibliothèque externe pour les E / S, vous pouvez la traiter comme intégrée. (en regardant des choses comme iostream, etc.).

  • Si votre langue a une fonction intégrée qui banalise cela, vous ne pouvez pas l' utiliser. Cela inclut (mais sans s'y limiter) les types intégrés qui peuvent gérer des entiers de précision arbitraires.

  • Si, pour une raison quelconque, un langage utilise des entiers de précision arbitraire par défaut, cette fonctionnalité ne peut pas être utilisée pour représenter des entiers qui ne peuvent généralement pas être stockés sur 64 bits.

  • L'entrée et la sortie DOIVENT être en base 10 . Peu importe la façon dont vous stockez les nombres en mémoire ou la façon dont vous effectuez l'arithmétique, mais les E / S seront de base 10.

  • Vous avez 15 secondes pour produire un résultat. Ceci pour interdire la soustraction itérée.

  • Le but ici est d'implémenter des entiers de précision arbitraires. Si pour une raison quelconque, vous êtes en mesure d'adhérer aux spécifications du défi et de réussir à le faire sans les mettre en œuvre, eh bien je suppose que c'est bon pour vous, cela semble valable.

Cas de test

  1. Dans ce cas, les entrées sont de 39! et 30!

Contribution

n = 20397882081197443358640281739902897356800000000 
m = 265252859812191058636308480000000

Production

Q = 76899763100160
R = 0
  1. nest la somme de toutes les factorielles jusqu'à 50, plus 1. mest des nombres concaténés jusqu'à 20.

contribution

n = 31035053229546199656252032972759319953190362094566672920420940313
m = 1234567891011121314151617181920

production

q = 25138393324103249083146424239449429
r = 62459510197626865203087816633
  1. nest 205! + 200 !. mest le nombre de larmes que PeterTaylor m'a fait verser en déchirant les choses que je poste dans le bac à sable.

Contribution

n = 271841734957981007420619769446411009306983931324177095509044302452019682761900886307931759877838550251114468516268739270368160832305944024022562873534438165159941045492295721222833276717171713647977188671055774220331117951120982666270758190446133158400369433755555593913760141099290463039666313245735358982466993720002701605636609796997120000000000000000000000000000000000000000000000000
m = 247

Production

q = 1100573825740813795225181252819477770473619155158611722708681386445423816849801159141424129060075102231232666057768175183676764503262931271346408394876267875141461722640873365274628650676808557279259873162169126398101692109801549256156915750794061370041981513180387019893765753438422927286098434193260562682052606153857091520795991080960000000000000000000000000000000000000000000000000
r = 0;

J'ajouterai probablement plus de cas de test à un moment donné.

en relation

Sons liés, mais pas vraiment


Les bibliothèques d'E / S comptent-elles comme des bibliothèques externes?
Johnson Steward

@JohnsonSteward Je ne sais pas ce que tu veux dire par là? Je voudrais par défaut "oui", mais pourriez-vous préciser?
Liam

@JohnsonSteward et je suppose que cela dépend de ce que vous êtes en train de faire? Est-ce du code / une bibliothèque de code?
Ashwin Gupta

1
Les nombres négatifs sont-ils autorisés?
TheConstructor

2
@TheConstructor: d'après les règles: "supposez que n> m> 0", donc non, les nombres négatifs ne sont pas autorisés.
nimi

Réponses:


4

Python 2, 427 octets

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

Lit l'entrée via STDIN, chaque numéro sur une ligne distincte et imprime le résultat dans STDOUT.

Explication

Au lieu de représenter des entiers sous forme de tableaux de chiffres, nous représentons chaque entier comme l'ensemble de bits "on" dans sa représentation binaire. Autrement dit, un entier n est représenté comme l'ensemble des indices des bits qui sont égaux à 1 dans la représentation binaire de n . Par exemple, le nombre 10, 1010 en binaire, est représenté comme l'ensemble {1, 3}. Cette représentation nous permet d'exprimer certaines des opérations arithmétiques assez succinctement, en utilisant les opérations d'ensemble de Python.

Pour ajouter deux ensembles, nous prenons (récursivement) la somme de leur différence symétrique, et l'ensemble des entiers successifs à leur intersection (qui correspond au portage collectif, et devient donc finalement l'ensemble vide, à quel point nous avons la somme finale .) De même, pour soustraire deux ensembles, nous prenons (récursivement) la différence de leur différence symétrique, et l'ensemble des entiers successifs à leur différence (ensemble) (qui correspond à l'emprunt collectif, et devient donc finalement l'ensemble vide, à point auquel nous avons la différence finale.) La similitude de ces deux opérations nous permet de les implémenter comme une seule fonction ( A).

La multiplication ( M) est simplement une addition distribuée: étant donné deux ensembles A et B , nous prenons la somme, comme décrit ci-dessus, de tous les ensembles { A + b | bB } (où A + b est l'ensemble { a + b | aA }).

La comparaison entière devient une comparaison lexicographique des deux ensembles, triés par ordre décroissant.

Pour diviser ( D) deux ensembles, A et B , nous commençons par l'ensemble vide comme quotient, et trouvons à plusieurs reprises le plus grand entier n , tel que B + n est inférieur ou égal à A (qui est simplement la différence entre les maxima de A et B , éventuellement moins-1), ajoutez n comme élément au quotient et soustrayez B + n de A , comme décrit ci-dessus, jusqu'à ce que A devienne inférieur à B , c'est-à-dire jusqu'à ce qu'il devienne le reste.

Il n'y a pas de déjeuner gratuit, bien sûr. Nous payons la taxe en convertissant de- et en-, décimal. En fait, la conversion en décimal est ce qui prend la plupart du temps d'exécution. Nous effectuons la conversion "de la manière habituelle", en utilisant uniquement les opérations ci-dessus, au lieu de l'arithmétique ordinaire.


Juste par curiosité: n'utilise pas l' s=`sum(2**i for i in d)`+sarithmétique de précision arbitraire intégrée lors de la conversion?
TheConstructor

1
@TheConstructor No. dest un seul chiffre décimal, donc ientre 0 et 3, et la somme totale est entre 0 et 9.
Ell

4

Java 8, 485 octets

Pourrait réduire de 5 octets supplémentaires en nommant la fonction dau lieu de divideou 16 octets supplémentaires si la définition de classe n'est pas comptée.

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

Peut être utilisé comme ceci:

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

céder

76899763100160,0
25138393324103249083146424239449429,62459510197626865203087816633
1100573825740813795225181252819477770473619155158611722708681386445423816849801159141424129060075102231232666057768175183676764503262931271346408394876267875141461722640873365274628650676808557279259873162169126398101692109801549256156915750794061370041981513180387019893765753438422927286098434193260562682052606153857091520795991080960000000000000000000000000000000000000000000000000,0

Non golfé:

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

J'ai sacrifié un peu de vitesse en ne précalculant pas un tableau avec les mtemps 1 à 9 et en commençant par b=0au lieu de b=l(m), mais j'ai économisé beaucoup d'octets en le faisant. Si vous êtes intéressé par l'ajout de précision arbitraire, voir une version précédente .

Je suppose que ce ne sera pas la solution la plus courte, mais peut-être que cela donne un bon départ.


Si vous implémentez également l'addition, la multiplication et la soustraction pour cela, je ferai une prime de 500 répétitions. : DI aime l'idée de la précision Stringy.
Addison Crump

@VoteToClose s'en occupera demain. Je suppose que la partie la plus difficile est terminée.
TheConstructor

1

Mathematica, 251 octets

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]

Explication

L'arithmétique sur les nombres décimaux peut facilement être implémentée par FoldPairList. Par exemple,

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

imite simplement le processus de multiplication à la main.

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

Cas de test

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

signifie 123456789 / 54321= 2272...39477.

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.