Преобразование повторного десятичного числа в дробь


23

Этот вопрос не нужно применять только к конечным десятичным знакам - повторяющиеся десятичные дроби также можно преобразовать в дроби с помощью алгоритма.

Ваша задача состоит в том, чтобы создать программу, которая будет принимать повторяющиеся десятичные числа в качестве входных данных, и выводить соответствующий числитель и знаменатель (в самых низких терминах), который производит это десятичное расширение. Фракции больше 1 должны быть представлены как неправильные дроби, такие как 9/5. Вы можете предположить, что вход будет положительным.

Повторное десятичное число будет дано в этом формате:

5.3.87

со всем после повторения второй точки, например так:

5.3878787878787...

Ваша программа выведет два целых числа, представляющих числитель и знаменатель, разделенные косой чертой (или эквивалентную форму на вашем языке, если вы не выводите простой текст):

889/165

Обратите внимание, что после второй точки после десятичной запятой ничего не будет, а между двумя точками после десятичной точки без неповторяющейся десятичной части ничего не будет.

Контрольные примеры

Эти контрольные примеры охватывают все необходимые угловые случаи:

0..3 = 1/3
0.0.3 = 1/30
0.00.3 = 1/300
0.6875. = 11/16
1.8. = 9/5
2.. = 2/1
5..09 = 56/11
0.1.6 = 1/6
2..142857 = 15/7
0.01041.6 = 1/96
0.2.283950617 = 37/162
0.000000.1 = 1/9000000
0..9 = 1/1
0.0.9 = 1/10
0.24.9 = 1/4

Если вы хотите, вы также можете предположить, что дроби без целочисленных частей не имеют ничего слева от первой точки. Вы можете проверить это с помощью этих дополнительных тестовых случаев:

.25. = 1/4
.1.6 = 1/6
..09 = 1/11
.. = 0/1

1
Нужно ли упрощать дробь? Или разумно оставить это в упрощенной форме (например:) 9/99?
Джастин

3
(in lowest terms)т.е. дробь должна быть упрощена.
Джо З.

2
Могу ли я выводить 13вместо 13/1?
Мниип

4
Обязательно обработайте этот ввод 1.9999...и вывод2/1
Томас Эдинг

3
@ThomasEding 1.9999.это 19999/10000, чтобы получить 2/1вам нужно 1..9, не так ли?
Qwertiy

Ответы:


8

Dyalog APL ( 75 73 69 68 знаков)

Вот еще одна и пятая попытка (скорее всего, моя последняя); Я потратил весь день на то, чтобы написать какой-нибудь фрагмент кода длиной менее 80 символов и полностью соответствовать правилам. Этот вызов сделал мой день!

Я наконец-то получил строку APL, состоящую из 75 символов, работающую с Dyalog APL (но не на странице онлайн-переводчика, так как использует функцию execute ), которая выглядит следующим образом:

(N,D)÷D∨N←(⍎'0',1↓I/⍨2=+\P)+(⍎'0',I/⍨2>+\P)×D←D+0=D←⍎'0',⌽2↓⍕¯1+10⊥P←'.'=I← '1.2.3'

Конечно, я мог бы сделать это немного короче, но в особых случаях, когда одно, два или три поля отсутствуют. Мой код может даже обрабатывать ..случай ввода.

Я знаю, что APL трудно читать, и поскольку людям нравится понимать, как на самом деле работает фрагмент кода, вот некоторые объяснения. По сути, я вычисляю последний знаменатель в переменной D и последний числитель в переменной N.

APL анализируется справа налево.

  • Во-первых, строка хранится в переменной I ( I←).
  • Затем он сопоставляется с вектором логических значений, указывающих, где находится точка, и этот вектор называется P ( P←'.'=). Например, '1.2.3' будет отображено на 0 1 0 1 0.
  • Этот вектор является цифрой в базе 10 ( 10⊥); сейчас «1.2.3» составляет 1010.
  • Затем 1 вычитается из этого числа (либо с, 1-⍨либо с ¯1+, здесь я выбрал второе). Теперь «1.2.3» - это 1009.
  • Затем это число преобразуется в строку ( ), удаляются две начальные цифры ( 2↓), что составляет 09 из нашего первоначального примера 1.2.3; строка перевернута ( ).
  • Здесь, в качестве особого случая, я добавляю начальный символ 0 перед строкой; мне грустно использовать четыре символа, '0',но я сделал это, чтобы избежать ошибки, когда второе и третье поля пусты. Строка преобразуется обратно в число ( ) и сохраняется в D, который является знаменателем, за исключением случаев, когда оба последних поля пусты, потому что в этом случае D равно 0.
  • D←D+0=Кусок кода множества D 1 , если она в настоящее время нулевой, а теперь D содержит знаменатель (до НОД разделения однако).
  • Этот знаменатель умножается ( ×) на содержание исходной строки I до второй точки, с (⍎'0',I/⍨2>+\P)которой снова начинается с P (0 1 0 1 0 в моем примере), добавляет последовательные числа, накапливая их (что составляет 0 1 1 2 2 в моем примере), проверьте, какие значения меньше 2 (делая логический вектор 1 1 1 0 0), и принимая соответствующие символы в I; еще один 0 добавляется перед строкой для предотвращения другой ловушки (если два начальных поля пусты), и все преобразуется в число.
  • Последняя часть входной строки добавляется к предыдущему продукту с помощью (⍎'0',1↓I/⍨2=+\P), которая снова принимает P, добавляет путем кумуляции снова, проверяет, какие значения равны 2 (см. Предыдущее объяснение), берет символы-символы, удаляет первый, который является точкой , добавляет начальный нулевой символ и преобразует в число.
  • Этот продукт с последующей суммой хранится в N, который является числителем.
  • Наконец, GCD вычисляется с помощью D∨N, и оба числа делятся на этот GCD.

изменить: вот исправление для 73 символов:

(N,D)÷D∨N←(⍎'0',1↓P/I)+(⍎'0',I/⍨~P←2=+\P)×D←D+0=D←⍎'0',⌽2↓⍕¯1+10⊥P←'.'=I←

Идея этого взлома состоит в том, чтобы сначала вычислить случай, когда накопленное сложение имеет значения, равные 2, сохранить их для последующего использования и инвертировать эту побитовую маску для получения первого случая; таким образом, для вычисления следующего случая требуется меньше символов.

редактировать: вот еще одно исправление для 69 символов:

(N,D)÷D∨N←(⍎'0',1↓P/I)+(⍎'0',I/⍨~P←2=+\P)×D←⍎'1⌈0',⌽2↓⍕¯1+10⊥P←'.'=I←

Идея этого взлома состоит в том, чтобы встроить наиболее сложный частный случай в виде кода APL в строку, которая должна быть оценена (на этапе преобразования строки в число).

редактировать: вот еще одно исправление для 68 символов:

(N,D)÷D∨N←(⍎'0',1↓P/I)+(⍎'0',I/⍨~P←2=+\P)×D←⍎'1⌈0',⌽3↓⍕1-10⊥P←'.'=I←

Идея этого хака состоит в том, чтобы заменить добавление -1 к значению для вычитания 1 к этому значению операцией, вычтя это значение к 1, а затем удалить вначале еще один символ в начале (что будет знаком минус).

изменить: косметическое изменение:

(N,D)÷D∨N←(⍎'0',1↓P/I)+(⍎'0',I/⍨~P←2=+\P)×D←1⌈⍎'0',⌽3↓⍕1-10⊥P←'.'=I←

Нет улучшения в размере, но более удовлетворен, чтобы получить максимальную функцию из кода, подлежащего оценке.


Я попытался запустить это с tryapl.org, и он жалуется INVALID TOKEN. Ты знаешь почему?
Питер Тейлор

@ Питер Тейлор: Да, это даже сказано в моем сообщении; это потому, что я использую оператор «execute», который был бы небезопасен для сервера Dyalog и был отключен онлайн (безопасный режим). Вы должны попробовать это на установленной версии Dyalog APL.
Томас Барухель

Ах, позор. Я не собираюсь тратить 60 €, чтобы иметь возможность проверить случайную подачу PCG. Я нашел альтернативный онлайн-тестер APL, но, похоже, в вашем коде есть что-то специфичное для Dyalog, потому что оно дает ошибки ранга или длины.
Питер Тейлор

@ Питер Тейлор; нет ;-) Пожалуйста, используйте мой собственный сайт (все еще экспериментальный и не официальный) с GNU APL; но мне пришлось добавить два символа, чтобы сделать его совместимым (круглые скобки вокруг одного I): см. эту постоянную ссылку
Томас Барухель

15

Perl 6 (93 101 100 80 68 66 байт)

$/=split ".",get;say ($0+($1+$2/(9 x$2.comb||1))/10**$1.comb).nude

Размер был увеличен, чтобы ничего не обрабатывать, а не просто потерпеть неудачу. Mouq предложил использовать $/, так что теперь он используется, а код на 20 байт короче. Айико предложил заменить /на , поэтому код стал еще короче (на 12 байт). Затем Mouq предложил заменить charsна comb(в числовом контексте они идентичны, поскольку список символов после преобразования в число равен числу символов).

Пример вывода:

$ perl6 script.p6
5.3.87
889 165
$ perl6 script.p6
2.0.0
2 1
$ perl6 script.p6
0..3
1 3
$ perl6 script.p6
0.0.3
1 30
$ perl6 script.p6
0.0.0
0 1
$ perl6 script.p6
0.1.6
1 6
$ perl6 script.p6
0.01041.6
1 96
$ perl6 script.p6
0.2.283950617
37 162
$ perl6 script.p6
123.456.789
41111111 333000

К сожалению, оказывается, что использование нуля в качестве заполнителя между двумя точками не допускается. 0..09возвращается 1/11, но 0.0.09возвращается 1/110.
Джо З.

@JoeZ. О хорошо Я обновил свой код, чтобы обработать случай, когда ничего не напечатано.
Конрад Боровски

Я не знаю Perl 6, но я правильно предположил, что с учетом 'abc' ваша программа использует точную рациональную арифметику для вычисления c / 99 ... 9, но использует только плавающую точку для вычисления ab? В этом случае, если b имеет много цифр, это даст неправильный ответ.
Омар

@ ОмарАнтолин-Камарена: Не совсем. В Perl 6 по умолчанию используются рациональные числа, а не числа с плавающей запятой. Например, 0.1 + 0.2 == 0.3в Perl 6.
Конрад Боровски

2
Гольф до 80 символов: $/=split ".",get;say join "/",($0+($1+$2/(9 x chars $2 or 1))/10**$1.chars).nude:)
Mouq

6

J ( 85 90 89 символов)

Моя первоначальная функция, которая была на 5 символов короче второй, содержала пару ошибок: она не выводила целые числа как «n / 1» и дала неправильный ответ на числа, содержащие более дюжины или около того цифр. Вот исправленная функция в J, которая также включает предложение Eelvex о сохранении символа:

f=:3 :0
'a t'=.|:(".@('0','x',~]),10x^#);._1'.',y
(,'/'&,)&":/(,%+.)&1+/a%*/\1,0 1-~}.t
)

Он получает строку и возвращает строку. Вот пример сеанса:

   f '..'
0/1
   f '0.0.0'
0/1
   f '3..'
3/1
   f '..052631578947368421'
1/19
   f '0.2.283950617'
37/162
   f '.0.103092783505154639175257731958762886597938144329896907216494845360824742268041237113402061855670'
1/97

Вы должны исправить свою функцию для вывода 0/1и 3/1inf первых двух тестовых случаев, см. Этот комментарий
mniip

Я исправил вывод для целых чисел стоимостью 5 символов, @mniip.
Омар

Используйте ('0','x',~])и сохраните байт.
Eelvex

5

С 171

Довольно долго. Может быть дополнительно уменьшено. Нет scanf, который действительно не может справиться с этим, если между точками нет чисел. Нет strtol. Просто хруст номера:

a,b,c,d,q;main(){while((q=getchar()-48)>-3)q<0?(d=b>0,b+=!b):d?(c=c*10+q,d*=10):(a=a*10+q,b*=10);for(a=a*--d+c,q=b*=d;q>1;a%q+b%q?--q:(a/=q,b/=q));printf("%d/%d\n",a,b);}

Тест:

rfc <<< "2..142857"
15/7

5

DC (не полностью общий, сокращен до 76 символов)

Не совсем общее, но, пожалуйста, учтите, что я сделал это с одной из самых старых вещей в мире:

5.3.87 dsaX10r^d1-rla*sasbdscX10r^dlc*rlb*rlb*la+snsdlnld[dSarLa%d0<a]dsax+dldr/rlnr/f

Редактировать: я редактирую свое решение; это не более общее, но немного короче:

sadsbX10r^sclaX10r^dd1-dsdlblc**rla*+dsnrld*dsd[dSarLa%d0<a]dsax+dldr/rlnr/f

Используйте это как:

5.3.87 sadsbX10r^sclaX10r^dd1-dsdlblc**rla*+dsnrld*dsd[dSarLa%d0<a]dsax+dldr/rlnr/f
  • Первое поле не обязательно:

    .1.3 sadsbX10r^sclaX10r^dd1-dsdlblc**rla*+dsnrld*dsd[dSarLa%d0<a]dsax+dldr/rlnr/f
    

    все в порядке.

  • Второе и жаждущее поля требуют как минимум одну цифру


5

Javascript, 203

Слишком долго, но все равно весело. Новые строки, потому что точки с запятой не читаются.

s=prompt(b=1).split(".")
P=Math.pow
a=s[0]
c=s[1]
d=P(10,l=c.length)
f=(P(10,s[2].length)-1)*P(10,l)||1
e=s[2]=+s[2]
a=d*a+b*c;b*=d
a=f*a+b*e;b*=f
function g(a,b){return b?g(b,a%b):a}g=g(a,b);a/g+"/"+b/g

Я получаю, 889/NaNкогда я бегу 5.3.87... Я делаю что-то не так?
rafaelcastrocouto

Я не знаю ... Если я просто вставлю этот код в консоль Safari (Firefox или Chrome тоже должны это сделать), нажмите Enter и введите «5.3.87», я просто попаду "889/165"в консоль. Как ты это делаешь? @rafaelcastrocouto
Томсминг

неважно ... Я думаю, что я сделал что-то не так, поскольку это работает сейчас ...
rafaelcastrocouto

1
Вы можете сохранить 1 символ, переместив b=1деталь внутрь prompt().
user2428118

1
f=(P(10,s[2].length)-1)*P(10,l),f=f?f:1=>f=(P(10,s[2].length)-1)*P(10,l)||1
f.ardelian

3

J (другой метод)

Другое решение, основанное на совершенно другом методе; на этот раз оно полностью общее; пропущен только один знаменатель, когда передается целое число:

   ".((({.~(i.&1)),'+'"_,((":@(10&^)@#,'%~',])@}.@#~~:/\),'+%',((,~(##'9'"_),'%x:0'"_)@}.@#~2:=+/\@]))(=&'.')) '.1.3'
2r15
   ".((({.~(i.&1)),'+'"_,((":@(10&^)@#,'%~',])@}.@#~~:/\),'+%',((,~(##'9'"_),'%x:0'"_)@}.@#~2:=+/\@]))(=&'.')) '.1.'
1r10
   ".((({.~(i.&1)),'+'"_,((":@(10&^)@#,'%~',])@}.@#~~:/\),'+%',((,~(##'9'"_),'%x:0'"_)@}.@#~2:=+/\@]))(=&'.')) '1..'
1
   ".((({.~(i.&1)),'+'"_,((":@(10&^)@#,'%~',])@}.@#~~:/\),'+%',((,~(##'9'"_),'%x:0'"_)@}.@#~2:=+/\@]))(=&'.')) '1..3'
4r3

3

GolfScript (67 символов)

`{'.'/1$=.10\,?@-).!+0@+~}+3,/1$4$*]-1%~;*+*+].~{.@\%.}do;{/}+/'/'@

NB Это поддерживает пустые целочисленные части.

Если строка имеет вид, 'n.p.q'то значение - это n + p/E + q/(DE) = ((nD + p)E + q)/DEгде D = 10^(len p)и E = 10^(len q) - 1, кроме случаев, когда len q = 0и в этом случаеE = 1 (чтобы избежать деления на 0).

Вскрытие:

           # Stack: 'n.p.q'
`{         # Combined with the }+ below this pulls the value into the block
           # Stack: idx 'n.p.q'
    '.'/   # Stack: idx ['n' 'p' 'q']
    1$=    # Stack: idx str   (where str is the indexed element of ['n' 'p' 'q'])
    .10\,? # Stack: idx str 10^(len str)
    @-)    # Stack: str 10^(len str)-idx+1
           #   If idx = 0 we don't care about the top value on the stack
           #   If idx = 1 we compute D = 10^(len 'p')
           #   If idx = 2 we compute E' = 10^(len 'q') - 1
    .!+    # Handle the special case E'=0; note that D is never 0
    0@+~   # Stack: 10^(len str)-idx+1 eval('0'+str) (GolfScript doesn't treat 011 as octal)
}+         # See above
3,/        # Run the block for idx = 0, 1, 2
           # Stack: _ n D p E q
1$4$*      # Stack: _ n D p E q D*E
]-1%~;     # Stack: D*E q E p D n
*+*+       # Stack: D*E q+E*(p+D*n)
].~        # Stack: [denom' num'] denom' num'
{.@\%.}do; # Stack: [denom' num'] gcd
{/}+/      # Stack: denom num
'/'@       # Stack: num '/' denom

Онлайн-демонстрация, которая имитирует запуск программы с каждым из тестовых входов, по одному.


Я попробовал это, и, похоже, он не следует всем правилам: «Обратите внимание, что после второй точки после десятичной точки ничего не будет, а между двумя точками без десятичной части не будет ничего». Я не мог заставить твой код работать с входными данными0.1.
Томас Барухель

-1. Я повторил это в другой раз, заметив, что вы получили +300 баллов. Это несправедливо, потому что другие решения сделали все возможное, чтобы следовать всем правилам, чего вы явно не сделали.
Томас Барухель

@ ברוכאל, я возражаю против твоего утверждения, что я не пытался следовать правилам. Положение факультативных тестовых случаев смутило меня в мысли, что последний блок охватывает все необходимые случаи; получается, что я был неправ, и я собираюсь отредактировать вопрос в ближайшее время, чтобы другие люди не совершили ту же ошибку. Теперь я обновил свой код для обработки ранее необработанных угловых случаев и обновил свою ссылку на тест, чтобы продемонстрировать это.
Питер Тейлор

ничего страшного. Вы, вероятно, заслуживаете 300 баллов. Будучи новичком в CodeGolf, эти 300 баллов стали для меня сложной задачей, и я все еще разочарован тем, что не получил их, хотя я все еще думаю, что в то время, когда мой код был самым коротким, чтобы полностью соответствовать правилам. Во всяком случае, у меня есть вся моя жизнь для получения очков. С уважением.
Томас Барухель

@ ברוכאל: Я хотел набрать 500 очков (да, я щедрый, я не могу дать меньше), и дать вам эти очки, но я думаю, что награда уже началась. Ну, как угодно. Мне интересно, когда закончится эта награда, и кто получит эти очки.
Конрад Боровски

2

питон

Нет библиотек - 156 символов

_=lambda a,b:b and _(b,a%b)or a;a,b,c=raw_input().split('.');d,e=int(a+b+c)-bool(c)*int(a+b),
(10**len(c)-bool(c))*10**len(b);f=_(d,e);print'%i/%i'%(d/f,e/f)

Использование fractions- 127 символов

from fractions import*;a,b,c=raw_input().split('.');print Fraction(int(a+b+c)-bool(c)*int(a+b
),(10**len(c)-bool(c))*10**len(b))

В fractionsверсии печатает такие вещи , как «фракции (7, 5)» вместо «7/5», не так ли?
Омар

Это не так; Между прочим, я не получаю лучший. _=lambda a,b:b and _(b,a%b)or a;a,b,c=raw_input().split('.');d,e=int(a+b+c)-bool(c)*int(a+b), ValueError: need more than 1 value to unpack
Томсминг

@ OmarAntolín-Camarena AFAIK, printиспользует, strкогда доступно, нет repr. Это вывод с моей стороны: puu.sh/7w64w.png
Оберон

@tomsmeding Оба находятся в одной строке; добавлен разрыв строки, чтобы они соответствовали ответу. _=lambda a,b:b and _(b,a%b)or a;a,b,c=raw_input().split('.');d,e=int(a+b+c)-bool(c)*int(a+b),(10**len(c)-bool(c))*10**len(b);f=_(d,e);print'%i/%i'%(d/f,e/f)должен идти все в одну строку.
Оберон

О, верно, @Oberon, как вы можете догадаться, я не был за компьютером и не мог запустить код.
Омар

2

Математика, 143

Как обычно, Mathematica предлагает множество высокоуровневых функций для выполнения работы, но дает им подробные имена.

x=StringTake;c=ToExpression;p=s~StringPosition~".";{o,t}=First/@p;u=StringLength@s-t;d=t-o-1;Rationalize@(c@x[s,t-1]+c@x[s,-u]/((10^u)-1)/10^d)

Пример вывода будет добавлен позже, когда у меня будет время.


Мне кажется, что это выводит целые числа как n, а не n / 1. Это правильно? (Мое решение имеет ту же ошибку ... :()
Омар

Ах, теперь я вижу .... указано в комментариях. Что за странное требование ... если каждая другая дробь уменьшена, почему бы не позволить n/1уменьшить до n? Я добавлю дополнительные ~ 50 байтов для преобразования целых чисел позже.
Джонатан Ван Матре

Ваш подход в порядке. Мой использует, FromDigitsпоэтому я решил опубликовать его тоже.
DavidC

2

Рубин - 112

x,y,z=gets.chop.split".";y||='0';z||='0';puts((y.to_i+Rational(z.to_i,10**z.length-1))/10**y.length+x.to_i).to_s

Это мой первый эксперимент с ruby, поэтому не стесняйтесь предлагать улучшения.

$ ruby20 % <<< '5.3.87'
889/165
$ ruby20 % <<< '0..3'
1/3
$ ruby20 % <<< '0.0.3'
1/30
$ ruby20 % <<< '0.00.3'
1/300
$ ruby20 % <<< '0.6875.0'
11/16
$ ruby20 % <<< '1.8.0'
9/5
$ ruby20 % <<< '2..'
2/1
$ ruby20 % <<< '..'
0/1

Удаление поддержки ".." и ".1.2" означает, что вы не следуете спецификации, верно? (Я бы предпочел удалить их тоже.)
Омар

@ OmarAntolín-Camarena На этот конкретный момент, спецификация говорит If you wish. Я не желаю, поэтому я не поддерживаю дроби без 1-й или 3-й группы цифр. Однако я поддерживаю дроби, в которых отсутствует вторая группа цифр, что соответствует спецификации.
Мниип

@minip, вы неправильно прочитали спецификацию: он не говорит «если вы хотите, чтобы вы могли поддержать .. и .1.2», он говорит: «если вы хотите, вы можете предположить, что 0 .. и 0.1.2 всегда задаются как .. и .1.2 ".
Омар

@ ОмарАнтолин-Камарена Точка занята. Ред.
Мниип

2

С, 164

Это похоже на решение С orion, хотя я сделал это с нуля. Признаюсь, однако, украл ряд его оптимизаций. Это не намного короче, но это обрабатывает .25. = 1/4 и 0,000000,1 = 1/9000000.

long a,b,c,d,e;main(){while((c=getchar()-48)>-3)c+2?a=a*10+c,b*=10:b?e=a,d=b:(b=1);
b>d?a-=e,b-=d:0;for(d=2;d<=a;)a%d+b%d?d++:(a/=d,b/=d);printf("%ld/%ld\n",a,b);}

2

Два ответа Python без использования библиотек. Сначала обрабатывает необязательный ввод без цифры перед первым. и составляет 162 символа

_=lambda a,b:b and _(b,a%b)or a;i,t,r=raw_input().split(".");b=r!="";d=(10**len(r)-b)*10**len(t);n=int((i+t+r)or 0)-b*int((i+t)or 0);f=_(d,n);print "%i/%i"%(n,d)

Second не обрабатывает ничего до первой цифры, но правильно обрабатывает все необходимые входы и составляет 150 символов

_=lambda a,b:b and _(b,a%b)or a;i,t,r=raw_input().split(".");b=r!="";d=(10**len(r)-b)*10**len(t);n=int(i+t+r)-b*int(i+t);f=_(d,n);print "%i/%i"%(n,d)

2

Haskell

import Data.Ratio
f n=case s '.' n of
    [x,y,z]->(r x)%1+(r y)%(10^(length y))+(r z)%((10^t-1)*(10^(length y)))
        where
            r ""=0
            r n=read n
            t = if length z==0 then 9 else length z
s _ []=[[]]
s n (x:xs) | x==n = []:(s n xs)
           | otherwise = let (l:ls)=s n xs in (x:l):ls

Эй, это код-гольф, ты даже не пытаешься!
Мниип

@mniip Я не очень хорош в код-гольфе. По крайней мере, я использовал однозначные имена переменных.
PyRulez

1
Вы никогда не указывали язык или общее количество использованных символов / байтов.
Джастин Фэй

2
Используйте {;}, чтобы сэкономить место в отступах, spanреализовать s, добавить короткие псевдонимы для функций, удалить пространство, где это возможно. import Data.Ratio v=span(/='.');w=tail;l=length;f n=(r x)%1+(r y)%p+(r z)%((10^t-1)*p)where{(x,b)=v n;(y,d)=v(w b);z=w d;p=10^(l y);r""=0;r n=read n;t=if null z then 9 else l z}- 178 символов, по сравнению с 321. NB Trueявляется синонимом otherwise, null zэтоlength z==0
bazzargh

2

JavaScript (ECMASCript 6) 180 175

G=(a,d)=>d?G(d,a%d):a;P=a=>+("1e"+a);L=a=>a.length;f=prompt().split(".");B=P(L(b=f[1]));D=P(L(b)+L(c=f[2]))-P(L(b))||1;alert((m=(f[0]+b||0)*D+B*(c||0))/(g=G(m,n=B*D))+"/"+n/g)

Хотя это не явный победитель для награды 300 ... это самое короткое, что я могу придумать:

  • Изменения по сравнению с предыдущей версией: небольшое изменение в логике, а также изменение Pфункции Power путем изменения ее +("1e"+a)вместо Math.pow(10,a)сохранения нескольких символов ...

1

Mathematica 175

f@i_:=
If[IntegerQ[g=FromDigits[Map[IntegerDigits@ToExpression@#&,StringSplit[i,"."]/.""-> {}]
/.{a_,b_,c_}:> {{Sequence@@Join[a,b],c},Length@a}]],HoldForm[Evaluate@g]/HoldForm@1,g]

Большая часть рутины идет на массаж ввода. Примерно 50 символов ушло на обработку целых чисел.


Примеры

f["7801.098.765"]

frac1

Больше примеров:

TableForm[
 Partition[{#, f[#]} & /@ {"19..87", "19.3.87", "5.3.87", "0.0.3", "0..3", "0.2.283950617", 
"123.456.789", "6666.7777.8888", "2.0.0","0.0.0"}, 5], TableSpacing -> {5, 5}]

frac2


Как это обычно достигается в Mathematica

FromDigitsможно получить дробь непосредственно из повторяющегося десятичного числа при условии, что входные данные имеют определенную форму. Целые числа отображаются как целые числа.

z={{{1, 9, {8, 7}}, 2}, {{1, 9, 3, {8, 7}}, 2}, {{5, 3, {8, 7}}, 1}, {{{3}}, -1}, {{{3}}, 0}, 
{{2, {2, 8, 3, 9, 5, 0, 6, 1, 7}}, 0}, {{1, 2, 3, 4, 5, 6, {7, 8, 9}}, 3}, 
{{6, 6, 6, 6, 7, 7, 7, 7, {8}}, 4}, {{2}, 1}, {{0}, 1}}

FromDigits/@z

Z


Ваш вывод в неправильном формате, это слишком красиво.
Омар

Странно, но это формат по умолчанию для выражения дробей в Mathematica. Чтобы изменить этот формат на более простой, потребуется еще несколько символов.
DavidC

1

J (96 знаков)

Я не использую символ косой черты в качестве разделителя (но решение в Mathematica также не используется, поскольку оно использует графическое представление, которое в любом случае лучше); на языке J фракция отображается rвместо /:

   (((-.@]#[)((".@[%#@[(10x&^)@-{.@])+({.@](10x&^)@-#@[)*<:@{:@](".%<:@(10x&^)@#)@}.[)I.@])(=&'.')) '1..3'
4r3
   (((-.@]#[)((".@[%#@[(10x&^)@-{.@])+({.@](10x&^)@-#@[)*<:@{:@](".%<:@(10x&^)@#)@}.[)I.@])(=&'.')) '123.456.789'
41111111r333000

1

APL (не полностью общий)

Не полностью общий (как мое решение для DC); работает с Dyalog APL (но не с онлайн-версией Dyalog APL, не знаю почему):

(R,F)÷(F←D×N)∨R←(⍎C)+D×(⍎I/⍨2>+\P)×N←10*¯1++/≠\P⊣D←¯1+10*⍴C←1↓I/⍨2=+\P←'.'=I← '123.456.789'

Первое поле является необязательным, но для обоих остальных полей требуется как минимум одна цифра.


1

JavaScript (189)

i=prompt().split(".");a=i[0];b=i[1];c=i[2];B=b.length;p=Math.pow;n=a+b+c-(a+b);d=p(10,B+c.length)-p(10,B);f=1;while(f){f=0;for(i=2;i<=n;i++)if(n%i==0&&d%i==0){n/=i;d/=i;f=1}};alert(n+"/"+d)

Пример:

Входные данные:

5.3.87

Выход:

889/165

1

C (420 символов, как написано; меньше после удаления ненужных пробелов)

Обратите внимание, что это предполагает 64-битный long(например, 64-битный Linux); это не удастся для тестового случая 0.2.283950617на системах, использующих 32-битный long. Это можно исправить за счет некоторых символов, изменив тип на long longи соответственно изменив printfстроку формата.

#include <stdio.h>

long d[3], n[3], i;

int main(int c, char** v)
{
  while (c = *v[1]++)
    switch(c)
    {
    case '.':
      n[++i] = 1;
      break;
    default:
      d[i] = 10 * d[i] + c - '0';
      n[i] *= 10;
    }

  n[2] -= n[2] != 1;

  while (i--)
    d[2] += d[i] * n[i+1], n[i]*=n[i+1];

  i = d[2];
  *n = n[1];

  while (i)
    *d = i, i = *n%i, *n = *d;
  printf("%ld/%ld\n", d[2]/ *n, n[1]/ *n);
}

Ницца. Вы можете сбрить 1 символ, изменив '0'на 48.
Тодд Леман

Я думаю, что вы также можете сэкономить еще несколько, переписав switchзаявление как if(c==46) n[++i]=1; else d[i]=10*d[i]+c-48,n[i]*=10;.
Тодд Леман

-3

БРГ , 81

`_:s;_,1,l?_)-S;_,"."
s;A;,1,S;_,".")-1
s;_,1+S;_,"."),l?_)-S;_,"."))→_
x?A;+_)►Frac

пример

?3.25.
            13/4

4
Пока компилятор не станет свободно доступным для этого языка, я буду опускать каждый ответ, который его использует.
Гарет

1
Кажется, есть компилятор на странице, указанной выше?
Скибрянски

@skibrianski Смотрите этот пост на meta
mniip

2
@ Гарет, есть пара ответов Mathematica, чтобы вы тоже понизили голос. : P
Омар

2
@ OmarAntolín-Camarena Существует компилятор / интерпретатор для Mathematica. У GTB нет ни одного. Перейдите по GTBссылке выше, если вы мне не верите. Вы получите сжатый материал для проприетарной программы, затем поищете эту программу и обнаружите, что сайт, который утверждает, что предоставляет загрузку, говорит, что он недоступен. Так как мы это скомпилируем?
Гарет
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.