Обміняйте деякі періодичні та неперіодичні частини


21

У десятковому поданні кожного раціонального числа у p/qвас є періодичний хвіст, неперіодична головка та розділ перед десятковою крапкою у такому форматі:

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

Деякі приклади включають:

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)

Завдання полягає в тому, щоб поміняти місцями періодичні та неперіодичні частини, залишивши в before decimal pointспокої, створити нове число. Наприклад:

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

Якщо число не має періодичної частини, наприклад 0.25перетворіть це число на нове періодичне число, і навпаки.

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

Змагання

  • Візьміть дріб xяк вхідний текст, як рядок, два входи, раціональне число або будь-який метод, який відповідає вашій мові.
  • Поміняйте місцями періодичні та неперіодичні частини десяткового подання, xщоб створити нове число, залишивши частину перед десятковою самою. Періодична частина завжди починається якомога швидше, щоб неперіодична частина була якомога коротшою. Приклади наведені нижче.
  • Повернути замінене число як новий дріб. Вхід не обов'язково зменшується, хоча вихід має бути. Формат введення дозволяється відрізнятись від формату виводу.
  • Чисельник pз xбуде цілим з абсолютним значенням одного мільйона або менше , і знаменником qу xбуде відмінний від нуля цілого числа з абсолютним значенням одного мільйона або менше.
  • Чисельник rта знаменник sрезультату не гарантовано становлять менше одного мільйона. Враховуючи довжину періодичних частин цих чисел, рекомендується уникати прямого перетворення на плавці.
  • Це код гольфу. Найкоротша відповідь у байтах виграє.

Приклади

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

У 0кінці тестового випадку 2 ( 10/7) є відсутність : 1428571/100000має бути 1428571/1000000.
JungHwan Min

1
Як зазначено, не буде однозначної відповіді на даний вхід. 1/7може бути представлена в вигляді , (0).()(142857) або (0).(1)(428571), 1може бути представлена в вигляді (1).()(), (0).()(9), (0).()(99), (0).(9)(9)і т.д.
ngenisis

@ngenisis Це було приховано в прикладах, але я зробив це явно. Дякую за відгук :)
Sherlock9

@ R.Kap Я вже заявив у виклику, що найкраще уникати використання поплавців тут. Існують способи знайти десяткові цифри числа, не перетворюючись на поплавок. Я сподіваюся, що це відповість на ваше запитання :)
Sherlock9

можуть і p, і q бути негативними?
edc65

Відповіді:


5

Python 2, 292 байт

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 версія, працює як в python 2 & 3. Також друкує десяткове подання.

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)

Спробуйтеd=10**len(p+a)
Sherlock9

1
Ось посилання TIO для легкого тестування: Спробуйте його в Інтернеті!
Kritixi Lithos

Молодці на вашу відповідь: D. Деякі подальші поради щодо гольфу: використовуйте більше крапки з комою, де це можливо, позбудьтесь місця в рядку if n==0: p='', використовуйте ``будь-яке місце, яке ви використовуєте str, як-от `n/d`замість цього str(n/d), і перейменуйте lenна Lз L=len;на початку функції.
Шерлок9

@ Sherlock9 Я навіть не знав про підлогу. Дякую за всі поради.
Райнер П.

Не проблема. Ось ще кілька: D Два місця для крапки з комою: n=int(b+p+a);d=10**L(p+a)і import fractions as f;g=f.gcd(n,d);return(n/g*s,d/g). Також я отримую 295 байт для вашої поточної редагування. Чи є зайвий новий рядок, який ви забуваєте залишити поза?
Шерлок9

2

Желе , 102 101 89 87 83 81 79 78 77 74 байт

Це знадобилося довго писати, занадто довго налагоджувати, і, безумовно, потрібно багато гольфу ( вісім сім шість п’ять чотирьох ланок, свята корова), але це, наскільки мені відомо, правильно. Багато, багато хто дякує Деннісу за його допомогу тут, особливо з першими двома посиланнями. Велике спасибі і Райнеру П., коли я врешті запозичив багато алгоритму у їхній відповіді на Python.

Редагування для гольфу: -1 байт завдяки Xanderhall. Виправлення помилок через невірно використаний логічний НЕ вбудований. -13 байт від гольфу посилання чисельника. +1 байт, щоб виправити помилку за негативом dзавдяки Деннісу. Перебудували посилання так, щоб генерація чисельника була в одному посиланні. -2 байти від поєднання другої та третьої ланок. -4 байти від переміщення деяких загальних елементів третьої та четвертої ланок до другої та основної ланки. -2 байти від видалення деяких зайвих операторів ланцюга. -2 байти від перестановки посилання чисельника. -1 байт від переміщення Ḣ€до кінця другої ланки. Виправлена ​​помилка в основному посиланні. -1 байт від зміни Ṫ ... ,Ḣдо Ḣ ... ṭ. -3 байти від переміщення чисельного посилання в основне посилання.

Пропозиції з гольфу вітаються! Спробуйте в Інтернеті!

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

Пояснення

Спочатку я поясню основне посилання , яке називає інші посилання.

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

Потім, перше посилання, яке отримує цифри.

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.

Тепер, друга ланка, яка отримує періодичні та неперіодичні частини n/dта багато інших важких підйомів.

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

Третя ланка , яке дає наш новий знаменник.

Ç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.
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.