Fractions égyptiennes


20

Aperçu:

De Wikipédia : Une fraction égyptienne est la somme de fractions unitaires distinctes. Autrement dit, chaque fraction de l'expression a un numérateur égal à 1 et un dénominateur qui est un entier positif, et tous les dénominateurs diffèrent les uns des autres. La valeur d'une expression de ce type est un nombre rationnel positif a / b. Chaque nombre rationnel positif peut être représenté par une fraction égyptienne.

Défi:

Écrivez la fonction la plus courte qui renverra les valeurs de tous les dénominateurs pour le plus petit ensemble de fractions unitaires qui s'ajoutent à une fraction donnée.

Règles / Contraintes:

  • L'entrée sera deux valeurs entières positives.
    • Cela peut être sur STDIN, argv, séparés par des virgules, espace délimité, ou toute autre méthode que vous préférez.
  • La première valeur d'entrée doit être le numérateur et la deuxième valeur d'entrée le dénominateur.
  • La première valeur d'entrée doit être inférieure à la seconde.
  • La sortie peut inclure une ou des valeurs qui dépassent les limites de mémoire de votre système / langue (RAM, MAX_INT ou toute autre contrainte de code / système existant). Si cela se produit, tronquez simplement le résultat à la valeur la plus élevée possible et notez-le d'une manière ou d'une autre (c. ...-à-d.).
  • La sortie doit pouvoir gérer une valeur de dénominateur d'au moins 2 147 483 647 (2 31 -1, signé 32 bits int).
    • Une valeur plus élevée ( long, etc.) est parfaitement acceptable.
  • Le résultat doit être une liste de toutes les valeurs des dénominateurs du plus petit ensemble de fractions unitaires trouvées (ou des fractions elles-mêmes, c. 1/2-à-d.).
  • La sortie doit être ordonnée ascendante en fonction de la valeur du dénominateur (décroissante de la valeur de la fraction).
  • La sortie peut être délimitée comme vous le souhaitez, mais il doit y avoir un caractère entre afin de différencier une valeur de la suivante.
  • C'est le golf de code, donc la solution la plus courte l'emporte.

Exemples:

  • Entrée 1:

    43, 48

  • Sortie 1:

    2, 3, 16

  • Entrée 2:

    8/11

  • Sortie 2:

    1/2 1/6 1/22 1/66

  • Entrée 3:

    5 121

  • Sortie 3:

    33 121 363


Entrée / sortie 2 devrait être 8, 11et 2, 6, 22, 66non?
mellamokb

2
Une suggestion possible, pour supprimer toute abiguïté, serait d'exiger le plus petit ensemble de fractions unitaires avec le plus petit dénominateur final. Par exemple, 1/2 1/6 1/22 1/66serait préférable 1/2 1/5 1/37 1/4070pour l'entrée 8/11.
primo

2
Je suggère d'ajouter 5/121 = 1/33+1/121+1/363aux cas de test. Tous les programmes gourmands (y compris le mien) donnent 5 fractions pour cela. Exemple tiré de Wikipedia .
ugoren

1
@primo Je pense que s'il y a plusieurs minimums, celui qui peut être trouvé serait acceptable. Si un algorithme peut être écrit avec moins de caractères en conséquence, je ne voudrais pas entraver cette solution.
Gaffi

1
A donné +1 depuis que j'ai appris les fractions égyptiennes dans un cours d'histoire des mathématiques (et j'ai dû faire des mathématiques avec elles, ainsi que trouver des sommes fractionnaires comme ce problème.) Un défi agréable et créatif.
mbomb007

Réponses:


6

Lisp commun, 137 caractères

(defun z(n)(labels((i(n s r)(cond((= n 0)r)((< n(/ 1 s))(i n(ceiling(/ 1 n))r))(t(i(- n(/ 1 s))(1+ s)(cons s r))))))(reverse(i n 2'()))))

(z 43/48) -> (2 3 16)

(z 8/11) -> (2 5 37 4070)

(z 5/121) -> (25 757 763309 873960180913 1527612795642093418846225)

Pas besoin de s'inquiéter des nombres énormes ou de la gestion de la notation fractionnaire!


(defun z (n) (labels ((i (nsr) (cond ((= n 0) r)) ((<n (/ 1 s)) (in (plafond (/ 1 n)) r)) (t ( i (- n (/ 1 s)) (1+ s) (contre sr)))))) (inverse (dans 2 '())))) (z 43/48) Afficher ne pas résulter en tio ... Que dois-je utiliser pour imprimer le résultat?
RosLuP

1
(print (z 103/333)) retourne une liste de 5 nombres mais existerait une liste de 4 nombres comme: 1 / 4,1 / 18,1 / 333,1 / 1332. Ainsi, la fonction ci-dessus ne retournerait pas le minimum.
RosLuP

8

Python 2, 169 167 caractères

x,y=input()
def R(n,a,b):
 if n<2:return[b/a][b%a:]
 for m in range((b+a-1)/a,b*n/a):
  L=R(n-1,a*m-b,m*b)
  if L:return[m]+L
n=L=0
while not L:n+=1;L=R(n,x,y)
print L

Prend des arguments séparés par des virgules sur stdin et imprime une liste python sur stdout.

$ echo 8,11 | ./egypt.py 
[2, 5, 37, 4070]

2
1. Je pense que vous pouvez enregistrer deux caractères en utilisant tabulation au deuxième niveau d'indentation. 2. Le script n'indique pas la troncature en raison du dépassement des limites de la mémoire système.
boîte à pain le

In Tio Votre code sort de la mémoire pour seulement 103/45533
RosLuP

Au lieu de cela, dans Ideone, votre code passe en erreur d'exécution pour la même entrée 103,45533: Erreur d'exécution #stdin #stdout #stderr 0.89s 99264KB
RosLuP

4

PHP 82 octets

<?for(fscanf(STDIN,"%d%d",$a,$b);$a;)++$i<$b/$a||printf("$i ",$a=$a*$i-$b,$b*=$i);

Cela pourrait être raccourci, mais le numérateur et le dénominateur actuels doivent être conservés sous forme de nombres entiers pour éviter les erreurs d'arrondi à virgule flottante (au lieu de conserver la fraction actuelle).

Exemple d'utilisation:

$ echo 43 48 | php egyptian-fraction.php
2 3 16
$ echo 8 11 | php egyptian-fraction.php
2 5 37 4070

L'opérateur virgule émulé comme arguments inutiles pour printf? Je devrais garder cette astuce quelque part.
Konrad Borowski

1
Je suis sûr que c'est un algorithme gourmand , donc il ne donnera pas toujours le plus petit ensemble de fractions. Si vous l'exécutez avec une entrée comme 5 121ou 31 311, cela donnera la mauvaise réponse (après très longtemps).
grc

@grc 31/311 -> {a [1] -> 11, a [2] -> 115, a [3] -> 13570, a [4] -> 46422970}
Dr. belisarius

4

C, 163 177 caractères

6/6 : Enfin, le programme gère désormais correctement la troncature dans tous les cas. Cela a pris beaucoup plus de caractères que je ne l'espérais, mais ça valait le coup. Le programme devrait maintenant adhérer à 100% aux exigences du problème.

d[99],c,z;
r(p,q,n,i){for(c=n+q%p<2,i=q/p;c?d[c++]=i,0:++i<n*q/p;)q>~0U/2/i?c=2:r(i*p-q,i*q,n-1);}
main(a,b){for(scanf("%d%d",&a,&b);!c;r(a,b,++z));while(--c)printf("%d\n",d[c]);}

Le programme prend le numérateur et le dénominateur sur l'entrée standard. Les dénominateurs sont imprimés sur la sortie standard, un par ligne. La sortie tronquée est indiquée en imprimant un dénominateur zéro à la fin de la liste:

$ ./a.out
2020 2064
2
3
7
402
242004

$ ./a.out
6745 7604
2
3
19
937
1007747
0

Les dénominateurs du deuxième exemple totalisent 95485142815/107645519046, ce qui diffère de 6745/7604 d'environ 1e-14.


Encore une fois, je pense que c'est un algorithme gourmand.
grc

La boucle la plus à l'extérieur explore toutes les réponses possibles des dénominateurs N avant de commencer à tester les réponses des dénominateurs N + 1. Vous pouvez l'appeler gourmand, je suppose, mais je crois qu'il répond au problème déclaré.
boîte à pain

Désolé, je reprends ça. Il ne suit pas la solution gourmande, mais j'ai trouvé qu'elle n'est pas complètement précise pour certaines entrées ( 31 311par exemple).
grc

31 311déborde, mais le programme ne parvient pas à le signaler.
boîte à pain

3

Python, 61 caractères

Entrée de STDIN, séparée par des virgules.
Sortie vers STDOUT, nouvelle ligne séparée.
Ne renvoie pas toujours la représentation la plus courte (par exemple pour 5/121).

a,b=input()
while a:
    i=(b+a-1)/a
    print"1/%d"%i
    a,b=a*i-b,i*b

Les caractères sont comptés sans les nouvelles lignes inutiles (c'est-à-dire rejoindre toutes les lignes dans l' whileutilisation ;).
La fraction est a/b.
iest b/aarrondi, donc je sais 1/i <= a/b.
Après l'impression 1/i, je remplace a/bpar a/b - 1/i, qui est (a*i-b)/(i*b).


Je veux voter pour cela, car il est si petit, mais il manque juste cette pièce!
Gaffi

2
Je veux réparer ce morceau, mais ce ne sera pas si petit ... J'ai l'impression que je vais juste réinventer la solution de Keith Randall.
ugoren

2

C, 94 octets

n,d,i;main(){scanf("%i%i",&n,&d);for(i=1;n>0&++i>0;){if(n*i>=d)printf("%i ",i),n=n*i-d,d*=i;}}

Essayez-le en ligne

edit: Une version plus courte du code a été publiée dans les commentaires, je l'ai donc remplacée. Merci!


2
Bonjour et bienvenue sur le site! Il s'agit d'une compétition de code-golf , donc l'objectif est de rendre votre code aussi court que possible . Il semble qu'il y ait beaucoup de choses que vous pourriez faire pour raccourcir votre code. Par exemple, vous pouvez supprimer tous les espaces inutiles de votre réponse.
DJMcMayhem

@DJMcMayhem Merci monsieur, compris et fait.
う ち わ 密 か

Salut, bienvenue chez PPCG! Pourriez-vous peut-être ajouter un lien TryItOnline avec le code de test pour les cas de test du défi? En outre, certaines choses que vous pourriez for(i=2;n>0&&i>0;i++)jouer au golf: peuvent l'être for(i=1;n>0&++i>0;); les crochets de la boucle for peuvent être supprimés (car elle n'a que l' ifintérieur); d=d*i;peut être d*=i;; et je ne suis pas tout à fait sûr, mais je pense #include <stdio.h>peut être sans espaces: #include<stdio.h>. Oh, et il pourrait être intéressant de lire Conseils pour jouer au golf en C et Conseils pour jouer au golf dans <toutes les langues>
Kevin Cruijssen

@KevinCruijssen Merci pour les conseils.
う ち わ 密 か



0

AXIOM, 753 octets

L==>List FRAC INT
macro  M(q)==if c<m or(c=m and m<999 and reduce(max,map(denom,q))<xv)then(m:=c;a:=q;xv:=reduce(max,map(denom,a)))
f(x,n)==(y:=x;a:L:=[];c:=0;q:=denom x;q:=q^4;for i in n.. repeat((c:=c+1)>50=>(a:=[];break);1/i>y=>1;member?(1/i,a)=>1;a:=concat(a,1/i);(y:=y-1/i)=0=>break;numer(y)=1 and ~member?(y,a)=>(a:=concat(a,y);break);(i:=floor(1/y))>q=>(a:=[];break));a)
h(x:FRAC INT):L==(a:L:=[];x>1=>a;numer(x)=1=>[x];n:=max(2,floor(1/x));xv:=m:=999;d:=denom x;zd:=divisors d;z:=copy zd;for i in 2..30 repeat z:=concat(z,i*zd);d:=min(10*d,n+9*m);for i in n..d repeat((c:=maxIndex(b:=f(x,i)))=0=>1;c>m+1=>1;M(b);v:=reduce(+,delete(b,1));for j in z repeat((c:=1+maxIndex(q:=f(v,j)))=1=>1;member?(b.1,q)=>1;q:=concat(b.1,q);M(q)));reverse(sort a))

L'idée serait d'appliquer "l'algorithme gourmand" avec différents points initiaux, et d'enregistrer la liste qui a une longueur minimale. Mais pas toujours il trouverait la solution min avec moins de précision: "le tableau A sera inférieur au tableau B si et seulement si A a peu d'éléments de B, ou si le nombre d'éléments de A est le même que le nombre d'éléments de B , que A est inférieur à B si le plus petit élément de A est plus grand en nombre, que le plus petit élément de B ". Non golfé et tester

-- this would be the "Greedy Algorithm"
fracR(x,n)==
   y:=x;a:L:=[];c:=0;q:=denom x;q:=q^4
   for i in n.. repeat
      (c:=c+1)>50   =>(a:=[];break)
      1/i>y         =>1
      member?(1/i,a)=>1
      a:=concat(a,1/i)
      (y:=y-1/i)=0  =>break
      numer(y)=1 and ~member?(y,a)=>(a:=concat(a,y);break)
      (i:=floor(1/y))>q           =>(a:=[];break)
   a

-- Return one List a=[1/x1,...,1/xn] with xn PI and x=r/s=reduce(+,a) or return [] for fail
Frazione2SommaReciproci(x:FRAC INT):L==
    a:L:=[]
    x>1       =>a
    numer(x)=1=>[x]
    n:=max(2,floor(1/x));xv:=m:=999;d:=denom x;zd:=divisors d;z:=copy zd
    for i in 2..30 repeat z:=concat(z,i*zd)
    d:=min(10*d,n+9*m) 
    for i in n..d repeat
        (c:=maxIndex(b:=fracR(x,i)))=0=>1 
        c>m+1                         =>1
        M(b)
        v:=reduce(+,delete(b,1))
        for j in z repeat
              (c:=1+maxIndex(q:=fracR(v,j)))=1=>1
              member?(b.1,q)                  =>1
              q:=concat(b.1,q)
              M(q) 
    reverse(sort a)

(7) -> [[i,h(i)] for i in [1/23,2/23,43/48,8/11,5/121,2020/2064,6745/7604,77/79,732/733]]
   (7)
      1   1      2   1  1      43  1 1  1      8  1 1  1  1
   [[--,[--]], [--,[--,---]], [--,[-,-,--]], [--,[-,-,--,--]],
     23  23     23  12 276     48  2 3 16     11  2 6 22 66
      5    1  1   1      505  1 1 1  1    1
    [---,[--,---,---]], [---,[-,-,-,---,----]],
     121  33 121 363     516  2 3 7 602 1204
     6745  1 1  1  1    1      1       77  1 1 1  1  1   1
    [----,[-,-,--,---,-----,------]], [--,[-,-,-,--,---,---]],
     7604  2 3 19 950 72238 570300     79  2 3 8 79 474 632
     732  1 1 1  1   1    1     1
    [---,[-,-,-,--,----,-----,-----]]]
     733  2 3 7 45 7330 20524 26388
                                                      Type: List List Any
       Time: 0.07 (IN) + 200.50 (EV) + 0.03 (OT) + 9.28 (GC) = 209.88 sec
(8) -> h(124547787/123456789456123456)
   (8)
        1             1                         1
   [---------, ---------------, ---------------------------------,
    991247326  140441667310032  613970685539400439432280360548704
                                     1
    -------------------------------------------------------------------]
    3855153765004125533560441957890277453240310786542602992016409976384
                                              Type: List Fraction Integer
                     Time: 17.73 (EV) + 0.02 (OT) + 1.08 (GC) = 18.83 sec
(9) -> h(27538/27539)
         1 1 1  1  1    1      1        1
   (9)  [-,-,-,--,---,-----,------,----------]
         2 3 7 52 225 10332 826170 1100871525
                                              Type: List Fraction Integer
                     Time: 0.02 (IN) + 28.08 (EV) + 1.28 (GC) = 29.38 sec

référence et numéros de: http://www.maths.surrey.ac.uk/hosted-sites/R.Knott/Fractions/egyptian.html

pour ajouter quelque chose, ce qui suit serait celui optimisé pour trouver la fraction de longueur min qui a le dénominateur max moins (et non optimisé pour la longueur)

L==>List FRAC INT

-- this would be the "Greedy Algorithm"
fracR(x,n)==
   y:=x;a:L:=[];c:=0;q:=denom x;q:=q^20
   for i in n.. repeat
      (c:=c+1)>1000  =>(a:=[];break)
      1/i>y          =>1
      member?(1/i,a) =>1
      a:=concat(a,1/i)
      (y:=y-1/i)=0  =>break
      numer(y)=1 and ~member?(y,a)=>(a:=concat(a,y);break)
      (i:=floor(1/y))>q           =>(a:=[];break)
   a

-- Return one List a=[1/x1,...,1/xn] with xn PI and x=r/s=reduce(+,a) or return [] for fail
Frazione2SommaReciproci(x:FRAC INT):L==
    a:L:=[]
    x>1       =>a
    numer(x)=1=>[x]
    n:=max(2,floor(1/x));xv:=m:=999;d:=denom x;zd:=divisors d;z:=copy zd; 
    w1:= if d>1.e10 then 1000 else 300; w2:= if d>1.e10 then 1000 else if d>1.e7 then 600 else if d>1.e5 then 500 else if d>1.e3 then 400 else 100;
    for i in 2..w1 repeat(mt:=(i*zd)::List PI;mv:=[yy for yy in mt|yy>=n];z:=sort(removeDuplicates(concat(z,mv)));#z>w2=>break)
    for i in z repeat
        (c:=maxIndex(b:=fracR(x,i)))=0=>1 
        c>m+1                         =>1
        if c<m or(c=m and m<999 and reduce(max,map(denom,b))<xv)then(m:=c;a:=b;xv:=reduce(max,map(denom,a)))
        v:=reduce(+,delete(b,1))
        for j in z repeat
              (c:=1+maxIndex(q:=fracR(v,j)))=1=>1
              member?(b.1,q)                  =>1
              q:=concat(b.1,q)
              if c<m or(c=m and m<999 and reduce(max,map(denom,q))<xv)then(m:=c;a:=q;xv:=reduce(max,map(denom,a)))
    reverse(sort a)

Les resultats:

(5) -> [[i,Frazione2SommaReciproci(i)] for i in [1/23,2/23,43/48,8/11,5/121,2020/2064,6745/7604,77/79,732/733]]
   (5)
      1   1      2   1  1      43  1 1  1      8  1 1  1  1
   [[--,[--]], [--,[--,---]], [--,[-,-,--]], [--,[-,-,--,--]],
     23  23     23  12 276     48  2 3 16     11  2 6 22 66
      5    1  1   1      505  1 1 1  1    1
    [---,[--,---,---]], [---,[-,-,-,---,----]],
     121  33 121 363     516  2 3 7 602 1204
     6745  1 1  1  1    1      1       77  1 1 1  1  1   1
    [----,[-,-,--,---,-----,------]], [--,[-,-,-,--,---,---]],
     7604  2 3 19 950 72238 570300     79  2 3 8 79 474 632
     732  1 1 1  1   1    1     1
    [---,[-,-,-,--,----,-----,-----]]]
     733  2 3 7 45 7330 20524 26388
                                                      Type: List List Any
                     Time: 0.08 (IN) + 53.45 (EV) + 3.03 (GC) = 56.57 sec
(6) -> Frazione2SommaReciproci(124547787/123456789456123456)
   (6)
        1            1               1                  1
   [---------, ------------, ----------------, -------------------,
    994074172  347757767307  2764751529594496  1142210063701888512
                      1
    -------------------------------------]
    2531144929865351036156388364636113408
                                              Type: List Fraction Integer
         Time: 0.15 (IN) + 78.30 (EV) + 0.02 (OT) + 5.28 (GC) = 83.75 sec
(7) -> Frazione2SommaReciproci(27538/27539)
         1 1 1  1   1     1       1       1
   (7)  [-,-,-,--,----,-------,-------,-------]
         2 3 7 43 1935 3717765 5204871 7105062
                                              Type: List Fraction Integer
                     Time: 0.05 (IN) + 45.43 (EV) + 2.42 (GC) = 47.90 sec

Il semble que de nombreux bons dénominateurs aient comme diviseurs de facteur le dénominateur de la fraction d'entrée.



0

APL (NARS), 2502 octets

fdn←{1∧÷⍵}⋄fnm←{1∧⍵}⋄ffl←{m←⎕ct⋄⎕ct←0⋄r←⌊⍵⋄⎕ct←m⋄r}⋄divisori←{a[⍋a←{∪×/¨{0=≢⍵:⊂⍬⋄s,(⊂1⌷⍵),¨s←∇1↓⍵}π⍵}⍵]}

r←frRF w;x;y;c;q;i;j
(x i)←w⋄i-←1⋄y←x⋄r←⍬⋄c←0⋄q←fdn x⋄q←q*20
i+←1
→4×⍳∼1000<c+←1⋄→6
j←÷i⋄→2×⍳j>y⋄→2×⍳(⊂j)∊r⋄r←r,(⊂j)⋄y←y-j⋄→0×⍳y=0⋄→5×⍳1≠fnm y⋄→5×⍳(⊂y)∊r⋄r←r,⊂y⋄→0
→2×⍳∼q<i←ffl ÷y
r←⍬

r←fr2SumF x;n;xv;m;d;zd;z;i;b;c;t;v;j;k;q;w1;w2;t;b1
z←r←⍬⋄→0×⍳1≤ffl x
:if 1=fnm x⋄r←,⊂x⋄→0⋄:endif
n←2⌈ffl÷x⋄xv←m←999⋄d←fdn x⋄zd←divisori d
w1←1000⋄w2←50⋄:if d>1.e10⋄w2←700⋄:elseif d>1.e7⋄w2←600⋄:elseif d>1.e5⋄w2←500⋄:elseif d>1.e3⋄w2←400⋄:elseif d>1.e2⋄w2←100⋄:endif
:for i :in ⍳w1⋄z←∪z∪k/⍨{⍵≥n}¨k←i×zd⋄:if w2<≢z⋄:leave⋄:endif⋄:endfor
z←∪z∪zd⋄z←z[⍋z]
:for i :in z
    :if 0=c←≢b←frRF x i ⋄:continue⋄:endif
    :if      c>m+1      ⋄:continue⋄:endif
    :if      c<m        ⋄m←c⋄r←b⋄xv←⌈/fdn¨b
    :elseif (c=m)∧(m<999)
         :if xv>t←⌈/fdn¨b⋄m←c⋄r←b⋄xv←t⋄:endif
    :endif
    :if c≤2⋄:continue⋄:endif
    v←↑+/1↓b⋄b1←(⊂↑b)
    :for j :in z
       :if 1=c←1+≢q←frRF v j⋄:continue⋄:endif
       :if        b1∊q      ⋄:continue⋄:endif
       q←b1,q
       :if  c<m⋄m←c⋄r←q     ⋄xv←⌈/fdn¨q
       :elseif (c=m)∧(m<999)
           :if xv>t←⌈/fdn¨q⋄m←c⋄r←q⋄xv←t⋄:endif
       :endif
    :endfor
:endfor
→0×⍳1≥≢r⋄r←r[⍋fdn¨r]

Traduction du code AXIOM pour ce problème, en APL, en utilisant pour la première fois (pour moi) le type de fraction (c'est-à-dire bignum ...).

103r233 signifie la fraction 103/233. Tester:

  ⎕fmt fr2SumF 1r23
┌1────┐
│ 1r23│
└~────┘
  ⎕fmt fr2SumF 2r23
┌2──────────┐
│ 1r12 1r276│
└~──────────┘
  ⎕fmt fr2SumF 43r48
┌3────────────┐
│ 1r2 1r3 1r16│
└~────────────┘
  fr2SumF 8r11
1r2 1r6 1r22 1r66 
  fr2SumF 5r121
1r33 1r121 1r363 
  fr2SumF 2020r2064
1r2 1r3 1r7 1r602 1r1204 
  fr2SumF 6745r7604
1r2 1r3 1r19 1r950 1r72238 1r570300 
  fr2SumF 77r79
1r2 1r3 1r8 1r79 1r474 1r632 
  fr2SumF 732r733
1r2 1r3 1r7 1r45 1r7330 1r20524 1r26388 
  fr2SumF 27538r27539
1r2 1r3 1r7 1r43 1r1935 1r3717765 1r5204871 1r7105062 
  fr2SumF 124547787r123456789456123456
1r994074172 1r347757767307 1r2764751529594496 1r1142210063701888512 
  1r2531144929865351036156388364636113408 
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.