Tauschen Sie einige periodische und nichtperiodische Teile aus

21

In der Dezimaldarstellung jeder rationalen Zahl p/qhaben Sie ein periodisches Ende, einen nichtperiodischen Kopf und einen Abschnitt vor dem Dezimalpunkt im folgenden Format:

(before decimal point).(non-periodic)(periodic)

Einige Beispiele sind:

1/70 = 0.0142857... = (0).(0)(142857)
10/7 = 1.428571... = (1).()(428571)            ## no non-periodic part
1/13 = 0.076923... = (0).()(076923)
3/40 = 0.075 = (0).(075)()                    ## no periodic part
-2/15 = -0.13... = -(0).(1)(3)                ## negative
75/38 = 1.9736842105263157894... = (1).(9)(736842105263157894)
                                              ## periodic part longer than float can handle
25/168 = 0.148809523... = (0).(148)(809523)
120/99 = 40/33 = 1.212121... = (1).()(21)
2/1 = 2 = (2).()()                            ## no periodic, no non-periodic
0/1 = 0 = (0).()()
0/2 = 0 = (0).()()
299/792 = 0.37752... = (0).(377)(52)
95/-14 = -6.7857142... = -(6).(7)(857142)
-95/-14 = 6.7857142... = (6).(7)(857142)

Die Herausforderung besteht darin, die periodischen und nichtperiodischen Teile auszutauschen und dabei die before decimal pointRuhe zu lassen, um eine neue Nummer zu erstellen. Beispielsweise:

25/168 = 0.148809523... = (0).(148)(809523)
       => (0).(809523)(148) = 0.809523148148... = 870397/1080000

Wenn eine Zahl keinen periodischen Teil wie hat, 0.25verwandle diese Zahl in eine neue periodische Zahl und umgekehrt.

1/4 = 0.25 = (0).(25)() => (0).()(25) = 0.252525... = 25/99
4/9 = 0.444444... = (0).()(4) => (0).(4)() = 0.4 = 2/5
5/1 = 5 = (5).()() => (5).()() = 5 = 5/1

Die Herausforderung

  • Nehmen Sie einen Bruch xals Eingabe, eine Zeichenfolge, zwei Eingaben, eine rationale Zahl oder eine andere Methode, die zu Ihrer Sprache passt.
  • Tauschen Sie den periodischen und den nichtperiodischen Teil der Dezimaldarstellung aus x, um eine neue Zahl zu erstellen, und lassen Sie den Teil vor der Dezimalstelle allein. Der periodische Teil beginnt immer so schnell wie möglich, damit der nichtperiodische Teil so kurz wie möglich ist. Beispiele sind unten.
  • Geben Sie die getauschte Nummer als neuen Bruch zurück. Die Eingabe wird nicht unbedingt reduziert, obwohl die Ausgabe sein sollte. Das Eingabeformat darf vom Ausgabeformat abweichen.
  • Der Zähler pvon xist eine ganze Zahl mit einem absoluten Wert von einer Million oder weniger und der Nenner qvon xist eine ganze Zahl ungleich Null mit einem absoluten Wert von einer Million oder weniger.
  • Der Zähler rund Nenner sdes Ergebnisses beträgt garantiert nicht weniger als eine Million. Angesichts der Länge der periodischen Teile dieser Zahlen wird empfohlen, keine direkte Konvertierung in Gleitkommazahlen vorzunehmen.
  • Das ist Code Golf. Kürzeste Antwort in Bytes gewinnt.

Beispiele

1/70 = (0).(0)(142857)     => (0).(142857)(0) = (0).(142857)() = 0.142857 = 142857/1000000
10/7 = (1).()(428571)      => (1).(428571)() = 1.428571 = 1428571/1000000
1/13 = (0).()(076923)      => (0).(076923)() = 0.076293 = 76923/1000000
3/40 = (0).(075)()         => (0).()(075) = 0.075075... = 75/999 = 25/333
-2/15 = -(0).(1)(3)        => -(0).(3)(1) = -0.311111... = -28/90 = -14/45
75/38 = (1).(9)(736842105263157894)
      => (1).(736842105263157894)(9) = (1).(736842105263157895)()  ## since 0.999... = 1
      = 1.736842105263157895 = 1736842105263157895/1000000000000000000
      = 347368421052631579/200000000000000000
25/168 = (0).(148)(809523) => (0).(809523)(148) = 0.809523148148... = 870397/1080000
120/99 = (1).()(21)        => (1).(21)() = 1.21 = 121/100
2/1 = (2).()()             => (2).()() = 2 = 2/1
0/1 = (0).()()             => (0).()() = 0 = 0/1
0/2 = (0).()()             => (0).()() = 0 = 0/1
299/792 = (0).(377)(52)    => (0).(52)(377) = 0.52377377... = 2093/3996
95/-14 = -(6).(7)(857142)  => -(6).(857142)(7) = -6.857142777... = -12342857/1800000
-95/-14 = (6).(7)(857142)  => (6).(857142)(7) = 6.857142777... = 12342857/1800000
Sherlock9
quelle
Am 0Ende von Testfall 2 ( 10/7) fehlt : 1428571/100000sollte sein 1428571/1000000.
JungHwan Min
1
Wie bereits erwähnt, wird es für eine bestimmte Eingabe keine eindeutige Antwort geben. 1/7könnte wie folgt dargestellt werden (0).()(142857) oder (0).(1)(428571), 1kann dargestellt werden (1).()(), (0).()(9), (0).()(99), (0).(9)(9)etc.
ngenisis
@ngenisis Das war in den Beispielen implizit, aber ich habe es explizit gemacht. Vielen Dank für die Rückmeldung :)
Sherlock9
@ R.Kap Ich habe bereits in der Herausforderung festgestellt, dass es am besten ist, hier auf die Verwendung von Schwimmern zu verzichten. Es gibt Möglichkeiten, die Dezimalstellen einer Zahl zu ermitteln, ohne sie in einen Gleitkommawert umzuwandeln. Ich hoffe, dies beantwortet Ihre Frage :)
Sherlock9
können sowohl p als auch q negativ sein?
edc65

Antworten:

5

Python 2, 292 Bytes

def x(n,d):
 L=len;s=cmp(n*d,0);n*=s;b=p=`n/d`;a={};n%=d
 while not n in a:
  a[n]=p;q=n/d;n=n%d
  if q==0:n*=10;p+=' '
  p=p[:-1]+`q`
 p=p[L(a[n]):];a=a[n][L(b):]
 if n==0:p=''
 n=int(b+p+a);d=10**L(p+a)
 if a!='':n-=int(b+p);d-=10**L(p)
 import fractions as f;g=f.gcd(n,d);return(n/g*s,d/g)

Ungolfed-Version, funktioniert sowohl in Python 2 als auch in Python 3. Druckt auch die Dezimaldarstellung.

def x(n,d):
# sign handling
 s=n*d>0-n*d<0
 n*=s
# b, a, p: BEFORE decimal, AFTER decimal, PERIODIC part
 b=p=str(n//d)
 a={}
 n%=d
# long division
 while not n in a:
  a[n]=p
  q=n//d
  n=n%d
  if q==0:
   n*=10
   p+=' '
  p=p[:-1]+str(q)
# a/p still contain b/ba as prefixes, remove them
 p=p[len(a[n]):]
 a=a[n][len(b):]
 if n==0: p=''
# print decimal representation
 print("(" + b + ").(" + a + ")(" + p + ")")
# reassemble fraction (with a and p exchanged)
 n=int(b+p+a)
 d=10**len(p+a)
 if a!='':
  n-=int(b+p)
  d-=10**len(p)
# reduce output
 from fractions import gcd
 g=gcd(n,d)
 return(n//g*s,d//g)
Rainer P.
quelle
Versuchen Sied=10**len(p+a)
Sherlock9
1
Hier ist ein TIO-Link zum einfachen Testen: Probieren Sie es online aus!
Kritixi Lithos
Gut gemacht für Ihre Antwort: D. Einige weitere Golf - Tipps: Verwenden Sie mehr Semikolons , wo möglich, der Raum in der Leitung loszuwerden if n==0: p='', die Verwendung ``in jedem Ort , den Sie verwenden str, wie zum Beispiel `n/d`statt str(n/d), und Umbenennungs lenzu Lmit L=len;am Anfang der Funktion.
Sherlock9
@ Sherlock9 Ich wusste nicht einmal über die Backticks Bescheid. Vielen Dank für alle Ratschläge.
Rainer P.
Kein Problem. Hier noch ein paar mehr: D Zwei Stellen für Semikolons: n=int(b+p+a);d=10**L(p+a)und import fractions as f;g=f.gcd(n,d);return(n/g*s,d/g). Außerdem erhalte ich 295 Bytes für Ihre aktuelle Bearbeitung. Gibt es einen zusätzlichen Zeilenumbruch, den Sie nicht auslassen dürfen?
Sherlock9
2

Jelly , 102 101 89 87 83 81 79 78 77 74 Bytes

Es hat viel zu lange gedauert, um es zu schreiben, viel zu lange, um es zu debuggen, und es erfordert definitiv viel Golf ( acht, sieben, sechs, fünf, vier Glieder, heilige Kuh), aber es ist nach meinem besten Wissen korrekt. Vielen, vielen Dank an Dennis für seine Hilfe, insbesondere bei den ersten beiden Links. Vielen Dank auch an Rainer P., der mir letztendlich einen Großteil des Algorithmus in seine Python-Antwort geliehen hat.

Golf Änderungen: -1 Byte dank Xanderhall. Fehlerkorrektur, da nicht das richtige logische NOT eingebaut wurde. -13 Bytes vom Golfen der Zählerverbindungen. +1 Byte vom Beheben eines Fehlers für Negative ddank Dennis. Die Links wurden neu strukturiert, sodass die Zählergenerierung in einem Link enthalten ist. -2 Bytes aus der Kombination der zweiten und dritten Verbindung. -4 Bytes von dem Verschieben einiger gemeinsamer Elemente der dritten und vierten Verbindung zu der zweiten Verbindung und der Hauptverbindung. -2 Bytes beim Entfernen einiger überflüssiger Kettenoperatoren. -2 Bytes von der Neuordnung der Zähler-Verbindung. -1 Byte vom Verschieben Ḣ€zum Ende der zweiten Verbindung. Ein Fehler im Hauptlink wurde behoben. -1 Byte vom Ändern Ṫ ... ,Ḣzu Ḣ ... ṭ. -3 Bytes vom Verschieben des Zählerlinks in den Hauptlink.

Golfvorschläge willkommen! Probieren Sie es online!

2ị×⁵d⁴
ÇÐḶ,ÇÐĿḟ@\µḢḅÐfıṭµḢḊṭµḢ€€µF,ḢQ
ÇL€⁵*
×Ṡ©⁸×%µ³,⁴A:/;Ѐ2ĿḌ×®,Ç_/€µ:g/

Erläuterung

Zuerst erkläre ich den Hauptlink , der die anderen Links aufruft.

×Ṡ©⁸×%µ³,⁴A:/;Ѐ2ĿḌ×®,Ç_/€µ:g/  Main link. Left argument: n (int), right argument: d (int)
                                Split into three chains.
×Ṡ©⁸×%  First chain
×       Multiply n by d.
 Ṡ©     Yield sign(n*d) and save it to the register.
   ⁸×   Multiply by n.
     %  Yield n*sgn(n*d) modulo d.

µ³,⁴A:/;Ѐ2ĿḌ×®,Ç_/€  Second chain
                        What follows is the formula for the numerator.
                        (+) means combining the digits of two numbers into one number.
                        ( `integer (+) periodic (+) non-periodic` - `integer (+) periodic` )
µ                     Start a new monadic chain with n*sgn(n*d)%d.
 ³,⁴                  Pair the original two arguments as a nilad.
    A                 Get their absolute values.
     :/               Integer divide to get the integer part of abs(n)/abs(d).
          2Ŀ          Yield the results of the second link.
       ;Ѐ            Append the integer part to each item in the right argument.
                        This appends to both lists from the second link.
            Ḍ         Convert each list from decimal to integer.
             ×®       Multiply by sign(n*d) retrieved from the register.
               ;Ç     Concatenate with the result of the third link (our new denominator).
                 _/€  Reduced subtract over each list.
                        Yields the proper numerator and denominator.

µ:g/  Third chain
µ     Start a new monadic chain with [numerator, denominator].
  g/  Yield gcd(numerator, denominator).
 :    Divide [numerator, denominator] by the gcd.
      Return this as our new fraction.

Dann der erste Link , der die Ziffern erhält.

2ị×⁵d⁴  First link: Gets the decimal digits one at a time in the format:
          [digit, remainder to use in the next iteration]
2ị      Gets the second index (the remainder).
  ×⁵    Multiply by 10.
    d⁴  Divmod with d.

Jetzt das zweite Glied , das die periodischen und nichtperiodischen Teile von n/dund eine Menge anderer schwerer Lasten abruft.

ÇÐḶ,ÇÐĿḟ@\µḢḅÐfıṭµḢḊṭµḢ€€µF,ḢQ  Second link: Loops the first link,
                                  separates the periodic digits and non-periodic digits,
                                  removes the extras to get only the decimal digits,
                                  and prepares for the third and fourth links.
                                Split into five chains.
ÇÐḶ,ÇÐĿḟ@\  First chain
ÇÐḶ         Loop and collect the intermediate results **in the loop**.
    ÇÐĿ     Loop and collect **all** of the intermediate results.
   ,        Pair into one list.
       ḟ@\  Filter the loop results out the list of all results,
              leaving only [[periodic part], [non-periodic part]].

µḢḅÐfıṭµḢḊṭ  Second and third chains
µ            Start a new monadic chain.
 Ḣ           Get the head [periodic part].
   Ðf        Filter out any [0, 0] lists from a non-periodic number,
  ḅ  ı        by converting to a complex number before filtering.
               Only removes 0+0j. This removes extra zeroes at the end.
      ṭ      Tack the result onto the left argument again.
       µ     Start a new monadic chain.
        Ḣ    Get the head [non-periodic and extra baggage].
         Ḋ   Dequeue the extra baggage.
          ṭ  Tack the result onto the left argument again.

µḢ€€µF,ḢQ  Fourth and fifth chains
µ          Start a new monadic chain with the processed periodic and non-periodic parts.
 Ḣ€€       Get the head of each list (the digits)
            in both the periodic and non-periodic parts.
    µ      Start a new monadic chain with these lists of digits.
     F     Left argument flattened.
       Ḣ   Head of the left argument.
      ,    Pair the flattened list and the head into one list.
        Q  Uniquify this list. (Only removes if non-periodic part is empty)
             Removes any duplicates resulting from a purely periodic n/d.

Das dritte Glied , das unseren neuen Nenner ergibt.

ÇL€⁵*  Third link: Generate the denominator.
         What follows is the formula for the denominator.
         ( 10**(num_digits) - ( 10**(num_periodic_digits) if len(non-periodic) else 0 ) )
Ç      Yield the results of the second link.
 L€    Get the length of each item in the list.
         The number of digits in total and the number of digits in the periodic part.
   ⁵*  10 to the power of each number of digits.
Sherlock9
quelle