Cambiar algunas partes periódicas y no periódicas

21

En la representación decimal de cada número racional p/q, tiene una cola periódica, una cabeza no periódica y una sección antes del punto decimal en el siguiente formato:

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

Algunos ejemplos incluyen:

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)

El desafío es intercambiar las partes periódicas y no periódicas, dejando las before decimal pointsolas, para crear un nuevo número. Por ejemplo:

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

Si un número no tiene una parte periódica como 0.25convertir ese número en un nuevo número periódico, y viceversa.

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

El reto

  • Tome una fracción xcomo entrada, como una cadena, dos entradas, un número racional o cualquier método que se adapte a su idioma.
  • Cambie las partes periódicas y no periódicas de la representación decimal de xpara crear un nuevo número, dejando solo la parte anterior al decimal. La parte periódica siempre comienza lo antes posible para que la parte no periódica sea lo más corta posible. Los ejemplos están abajo.
  • Devuelve el número intercambiado como una nueva fracción. La entrada no se reduce necesariamente aunque la salida debería serlo. El formato de entrada puede diferir del formato de salida.
  • El numerador pde xserá un número entero con un valor absoluto de un millón o menos y el denominador qde xserá un número entero distinto de cero con un valor absoluto de un millón o menos.
  • No se garantiza que el numerador ry el denominador sdel resultado sea inferior a un millón. Dada la longitud de las partes periódicas de estos números, se recomienda evitar la conversión directa a flotantes.
  • Este es el código de golf. La respuesta más corta en bytes gana.

Ejemplos

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
fuente
Falta un elemento 0al final del caso de prueba 2 ( 10/7): 1428571/100000debería ser 1428571/1000000.
JungHwan Min
1
Como se indicó, no habrá una respuesta única para una entrada dada. 1/7podría ser representado como (0).()(142857) o (0).(1)(428571), 1podría ser representado como (1).()(), (0).()(9), (0).()(99), (0).(9)(9), etc.
ngenisis
@ngenisis Eso estaba implícito en los ejemplos, pero lo he hecho explícito. Gracias por los comentarios :)
Sherlock9
@ R.Kap Ya he dicho en el desafío que es mejor evitar el uso de carrozas aquí. Hay formas de encontrar los dígitos decimales de un número sin convertirlo en flotante. Espero que esto responda tu pregunta :)
Sherlock9
¿pueden tanto p como q ser negativos?
edc65

Respuestas:

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)

Versión sin golf, funciona tanto en python 2 como en 3. También imprime la representación decimal.

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.
fuente
Pruebad=10**len(p+a)
Sherlock9
1
Aquí hay un enlace TIO para una prueba fácil: ¡ Pruébelo en línea!
Kritixi Lithos
Bien hecho en su respuesta: D. Algunos consejos de golf más: un uso más puntos y comas donde sea posible, deshacerse del espacio en la línea if n==0: p='', su uso ``en todos los lugares se utiliza str, por ejemplo `n/d`en lugar de str(n/d)y de cambio de nombre lena Lla L=len;al comienzo de la función.
Sherlock9
@ Sherlock9 Ni siquiera sabía sobre los backticks. Gracias por todos los consejos.
Rainer P.
No es un problema. Aquí hay más: D Dos lugares para punto n=int(b+p+a);d=10**L(p+a)y coma: y import fractions as f;g=f.gcd(n,d);return(n/g*s,d/g). Además, obtengo 295 bytes para su edición actual. ¿Hay una nueva línea adicional que te olvides de dejar?
Sherlock9
2

Jalea , 102 101 89 87 83 81 79 78 77 74 bytes

Esto tomó mucho tiempo para escribir, demasiado tiempo para depurar, y definitivamente necesita mucho golf ( ocho siete seis cinco cuatro enlaces, vaca sagrada), pero es, a mi leal saber y entender, correcto. Muchas, muchas gracias a Dennis por su ayuda aquí, especialmente con los dos primeros enlaces. Muchas gracias a Rainer P. también, ya que terminé tomando prestado mucho del algoritmo en su respuesta de Python.

Ediciones de golf: -1 byte gracias a Xanderhall. Corrección de errores por no usar la lógica NO correcta incorporada. -13 bytes de golfing los enlaces del numerador. +1 byte por arreglar un error negativo dcon gracias a Dennis. Reestructurado los enlaces para que la generación del numerador sea todo en un enlace. -2 bytes de la combinación del segundo y tercer enlace. -4 bytes de mover algunos elementos comunes de los enlaces tercero y cuarto al segundo enlace y al enlace principal. -2 bytes de eliminar algunos operadores de cadena superfluos. -2 bytes de reorganizar el enlace del numerador. -1 byte desde el movimiento Ḣ€hasta el final del segundo enlace. Se corrigió un error en el enlace principal. -1 byte de cambiar Ṫ ... ,Ḣa Ḣ ... ṭ. -3 bytes de mover el enlace del numerador al enlace principal.

Sugerencias de golf bienvenidas! Pruébalo en línea!

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

Explicación

Primero, explicaré el enlace principal , que llama a los otros enlaces.

×Ṡ©⁸×%µ³,⁴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.

Luego, el primer enlace que obtiene los dígitos.

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.

Ahora, el segundo enlace que obtiene las partes periódicas y no periódicas n/d, y muchos otros trabajos pesados.

ÇÐḶ,ÇÐĿḟ@\µḢḅÐ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.

El tercer enlace , que produce nuestro nuevo denominador.

Ç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
fuente