Convert a repeated decimal to a fraction

23

3

This question doesn't need to apply to just terminating decimals - repeating decimals can also be converted to fractions via an algorithm.

Your task is to make a program that takes a repeated decimal as input, and output the corresponding numerator and denominator (in lowest terms) that produces that decimal expansion. Fractions greater than 1 should be represented as improper fractions like 9/5. You can assume that input will be positive.

The repeated decimal will be given in this format:

5.3.87

with everything after the second dot repeated, like this:

5.3878787878787...

Your program will output two integers representing the numerator and denominator, separated by a slash (or the equivalent form in your language if you do not output plain text):

889/165

Note that terminating decimals will have nothing after the second dot, and decimals with no non-repeating decimal portion will have nothing between the two dots.

Test cases

These test cases cover all of the required corner cases:

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

If you wish, you can also assume that fractions without integer parts have nothing to the left of the first dot. You can test that with these optional test cases:

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

Joe Z.

Posted 2014-01-07T18:50:24.397

Reputation: 30 589

1Is it necessary to simplify the fraction? Or is it reasonable to leave it in an unsimplified form (eg: 9/99)? – Justin – 2014-01-07T18:57:33.067

3(in lowest terms) i.e. the fraction must be simplified. – Joe Z. – 2014-01-07T18:58:28.257

2Am I allowed to output 13 instead of 13/1? – mniip – 2014-03-14T13:56:07.740

@mniip: No, it has to be 13/1. – Joe Z. – 2014-03-14T18:46:21.503

@JoeZ. Ok, I edited my answer – mniip – 2014-03-14T19:27:26.963

What range of numbers does this have to handle? Is it OK to assume the parts of the input are less than 2^31 or something like that? – Omar – 2014-03-14T20:03:57.207

4Be sure to handle this input 1.9999... and output 2/1 – Thomas Eding – 2014-03-14T20:08:48.987

I think this piece of J code is much more powerful than what is asked since it doesn't require the second dot as a hint; may I post it (((0:`(%@$:)@.(<&100))@%@-+])x:@<.) 5.3878787878787 (35 characters)? – Thomas Baruchel – 2014-03-15T21:23:04.997

@ברוכאל How does it handle something like 0.01020408163265306122448979590102040816326530... which looks like 1/98 but actually isn't? – Joe Z. – 2014-03-15T21:43:45.523

@Joe Z. It actually will tell 1/98. – Thomas Baruchel – 2014-03-15T21:49:33.847

One more question: is the "slash" symbol a requirement? Could a space be OK as long as it follows other conventions (even the "13/1" convention as "13 1")? I ask because the slash is only a symbol for representing the fraction; anyway the Mathematica solution doesn't use the slash since it outputs a graphical representation of the fraction? – Thomas Baruchel – 2014-03-16T07:27:26.663

@ברוכאל If it tells 1/98 for my input of 0..0102040816326530612244897959, then your solution is invalid, because the correct answer is just 102040816326530612244897959/9999999999999999999999999999. – Joe Z. – 2014-03-17T03:23:56.963

Also, the slash symbol is only a requirement if your solution outputs plain text. In the case of the Mathematica solution, the fraction line serves the same purpose. – Joe Z. – 2014-03-17T03:24:28.290

@Joe Z. Thank you for all your answers; I finally made up a 68-characters APL code; separator is a space because the return value is a 'tuple' numerator+denominator; is it OK? All rules have been strictly followed. – Thomas Baruchel – 2014-03-17T05:57:31.843

I think that should be okay. – Joe Z. – 2014-03-17T13:57:24.453

3@ThomasEding 1.9999. is 19999/10000, to get 2/1 you need 1..9, isn't it? – Qwertiy – 2014-12-05T08:07:38.863

Answers

8

Dyalog APL (75 73 69 68 characters)

Here is another and fifth attempt (most probably my last one); I spent the day trying to write some piece of code shorter than 80 characters and being fully consistent with the rules. This challenge made my day!

I finally got a line of APL made of 75 characters, working with Dyalog APL (but not on the online interpreter page because using the execute function), which is the following one:

(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'

Of course I could make it a little shorter, but the special cases where one, two or three fields are missing. My code can even handle the .. input case.

I know that APL is difficult to read, and since people enjoy understanding how a piece of code actually works, here are some explanation. Basically, I compute the final denominator in the variable D and the final numerator in the variable N.

APL is parsed from right to left.

  • First, the string is stored in variable I (I←).
  • Then it is mapped to a vector of booleans indicating where a dot is, and this vector is called P (P←'.'=). For instance '1.2.3' will be mapped to 0 1 0 1 0.
  • This vector is digits in base 10 (10⊥); now '1.2.3' is 1010.
  • Then 1 is substracted from this number (either with 1-⍨ or with ¯1+, here I chose the second). Now '1.2.3' is 1009.
  • Then this number is converted to a string (), two initial digits are removed (2↓), which makes 09 from our initial '1.2.3' example; the string is reversed ().
  • Here, as a special case, I add an initial 0 character in front of the string; it makes me sad to use the four characters '0', but I did it for avoiding an error when the second and thirds fields are both empty. The string is converted back to a number () and it is stored in D, which is the denominator except when both last fields are empty, because in such case D is equal to 0.
  • The D←D+0= piece of code set D to 1 if it is currently null, and now D contains the denominator (before GCD division however).
  • This denominator is multiplied (×) with the content of the initial string I up to the second dot with (⍎'0',I/⍨2>+\P) which starts from P again (0 1 0 1 0 in my example), adds the successive numbers by cumulating them (which makes 0 1 1 2 2 in my example), check which values are smaller than 2 (making the boolean vector 1 1 1 0 0), and taking corresponding characters in I; another 0 is added in front of the string for preventing another trap (if the two initial fields are empty) and the whole is converted to a number.
  • The last part of the input string is added to the previous product with (⍎'0',1↓I/⍨2=+\P), which takes P again, adds by cumulating again, check which values are equal to 2 (see previous explanation), takes the characers, removes the first one which is a dot, adds a preventing initial 0 character and converts to a number.
  • This product followed with a sum is stored in N which is the numerator.
  • Finally the GCD is computed with D∨N and both numbers are divided by this GCD.

edit: Here is a fix for 73 characters:

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

The idea of this hack is computing first the case where cumulative addition has values equal to 2, storing them for later and inverting this bitwise mask for getting the first case; thus computing the next case needs less characters.

edit: Here is another fix for 69 characters:

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

The idea of this hack is to embed the most complicated special case as APL code in the string to be evaluated (at string to number conversion stage).

edit: Here is another fix for 68 characters:

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

The idea of this hack is to replace adding -1 to the value for substracting 1 to that value by the operation substracting that value to 1 then remove later one character more at the beginning (which will be the minus sign).

edit: Cosmetic change:

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

No improvement in size, but more satisfied to get the maximum function out of the code to be evaluated.

Thomas Baruchel

Posted 2014-01-07T18:50:24.397

Reputation: 1 590

I attempted to run this with tryapl.org and it complains INVALID TOKEN. Do you know why? – Peter Taylor – 2014-03-22T19:19:37.870

@Peter Taylor: Yes, it is even said in my message; this is because I use the "execute" operator which would be unsafe for the server of Dyalog and has been disabled online (safe mode). You have to try it on an installed version of Dyalog APL. – Thomas Baruchel – 2014-03-22T19:28:12.207

Ah, shame. I'm not going to spend 60€ to be able to test an occasional PCG submission. I've found an alternative online APL tester, but there seems to be something Dyalog-specific in your code because it gives rank errors or length errors. – Peter Taylor – 2014-03-22T19:41:44.537

@Peter Taylor; no ;-) Please, use my own website (still experimental and not official) with GNU APL; but I had to add two characters to make it compatible (parenthesis around one I): see this permalink

– Thomas Baruchel – 2014-03-22T19:54:26.570

15

Perl 6 (93 101 100 80 68 66 bytes)

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

The size was increased to handle nothing, instead of just failing. Mouq proposed to use $/, so it's now being used, and the code is 20 bytes shorter. Ayiko proposed replacing / with , so the code is even shorter (by 12 bytes). Then Mouq proposed replacing chars with comb (in numeric context, they are identical, because list of characters after conversion to number is number of characters).

Sample output:

$ 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

Konrad Borowski

Posted 2014-01-07T18:50:24.397

Reputation: 11 185

Technically this is written in Rakudo Perl 6 as the Std parser dies with Unsupported use of $/ variable as input record separator; in Perl 6 please use the filehandle's :irs attribute – Brad Gilbert b2gills – 2015-03-07T18:26:48.553

@BradGilbertb2gills: Could be fixed with := operator, but I prefer to work with how actual implementation of language works, rather than how it should work according to the specification. – Konrad Borowski – 2015-03-07T18:41:23.447

Can't you eliminate the space character after the split and after the say in Perl 6? I know you can in Perl 5. – Todd Lehman – 2015-04-14T21:54:17.803

@ToddLehman: You cannot, this is Perl 6, requiring a space after function call (or opening paren). – Konrad Borowski – 2015-04-17T16:01:54.967

Unfortunately, it turns out that using zero as a placeholder between two dots is a no-go. 0..09 returns 1/11, but 0.0.09 returns 1/110. – Joe Z. – 2014-01-07T19:32:50.130

@JoeZ. Oh, ok. I updated my code to handle the case when nothing is typed. – Konrad Borowski – 2014-01-07T19:37:00.473

I don't know Perl 6, but am I correct in guessing that given 'a.b.c', your program uses exact rational arithmetic to compute c/99...9, but only uses floating point to compute a.b? In that case if b has many digits it will give an incorrect answer. – Omar – 2014-03-14T14:16:04.690

@OmarAntolín-Camarena: Not quite. In Perl 6, rationals are default, not floating point numbers. For example, 0.1 + 0.2 == 0.3 in Perl 6. – Konrad Borowski – 2014-03-14T14:32:16.860

Oh, cool, I wish more languages made rationals the default, @xfix. – Omar – 2014-03-14T14:49:07.343

2Golfed to 80 chars: $/=split ".",get;say join "/",($0+($1+$2/(9 x chars $2 or 1))/10**$1.chars).nude :) – Mouq – 2014-03-15T17:57:34.713

@Mouq: Thanks, updated. Nice idea about using $/ array, which is magical for Perl 6. – Konrad Borowski – 2014-03-15T20:27:41.820

@xfix: given the current accepted answer is allowed to replace the / with a space, this can be shortened to $/=split ".",get;say ($0+($1+$2/(9 x$2.chars||1))/10**$1.chars).nude, also 68 chars. – Ayiko – 2014-03-22T23:18:26.827

6

J (85 90 89 chars)

My original function, which was 5 characters shorter than the second, had a couple of bugs: it didn't output integers as "n/1" and it gave the wrong answer on numbers with more than a dozen or so digits. Here's a corrected function in J that also incorporates Eelvex's suggestion to save a character:

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

It receives a string and returns a string. Here's a sample session:

   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

Omar

Posted 2014-01-07T18:50:24.397

Reputation: 1 154

You should fix your function to output 0/1 and 3/1 inf first two test cases, See this comment

– mniip – 2014-03-14T20:15:43.880

I fixed the output for integers at the cost of 5 chars, @mniip. – Omar – 2014-03-14T23:54:47.237

Use ('0','x',~]) and save a byte. – Eelvex – 2014-03-16T01:32:48.447

5

C, 171

Quite long. Could be further reduced. No scanf, which really can't handle it if there aren't any numbers between the dots. No strtol. Just number crunching:

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);}

Test:

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

orion

Posted 2014-01-07T18:50:24.397

Reputation: 3 095

5

Javascript, 203

Way too long, but still fun. Newlines because semicolons are unreadable.

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

tomsmeding

Posted 2014-01-07T18:50:24.397

Reputation: 2 034

1f=(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 – 2015-04-14T15:55:53.307

I'm getting 889/NaN when I run 5.3.87 ... Am I doing something wrong? – rafaelcastrocouto – 2014-03-17T14:29:05.653

I don't know... If I just paste this code in the Safari console (Firefox or Chrome should do too), hit enter and type "5.3.87", I just get "889/165" in the console. How are you running it? @rafaelcastrocouto – tomsmeding – 2014-03-17T16:43:40.493

nevermind ... I guess I did something wrong since it is working now ... – rafaelcastrocouto – 2014-03-18T11:49:09.510

1You can save 1 character by moving the b=1 part inside prompt(). – user2428118 – 2014-04-24T08:41:02.437

@user2428118 applied, together with another improvement. – tomsmeding – 2014-04-24T09:36:29.830

5

DC (not fully general, shortened to 76 characters)

Not fully general, but please, consider I did it with one of the oldest things in the world:

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

Edit: I edit my solution; it isn't more general, but a little shorter:

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

Use it as:

5.3.87 sadsbX10r^sclaX10r^dd1-dsdlblc**rla*+dsnrld*dsd[dSarLa%d0<a]dsax+dldr/rlnr/f
  • First field isn't required:

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

    is OK.

  • Second and thirst field require at least one digit

Thomas Baruchel

Posted 2014-01-07T18:50:24.397

Reputation: 1 590

3

J (different method)

Another solution based on a very different method; this time it is fully general; only missing is the 1-denominator when an integer is submitted:

   ".((({.~(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

Thomas Baruchel

Posted 2014-01-07T18:50:24.397

Reputation: 1 590

3

GolfScript (67 chars)

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

NB This supports empty integer parts.

If the string is of the form 'n.p.q' then the value is n + p/E + q/(DE) = ((nD + p)E + q)/DE where D = 10^(len p) and E = 10^(len q) - 1, except when len q = 0, in which case E = 1 (to avoid division by 0).

Dissection:

           # 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

Online demo which simulates running the program with each of the test inputs, one at a time.

Peter Taylor

Posted 2014-01-07T18:50:24.397

Reputation: 41 901

I tried it, and it doesn't seem to follow all the rules: "Note that terminating decimals will have nothing after the second dot, and decimals with no non-repeating decimal portion will have nothing between the two dots." I couldn't make your code work with input being 0.1. – Thomas Baruchel – 2014-03-21T14:50:26.097

-1. I retried it another time after having noticed you got the +300 points. It isn't fair, because other solutions have done their best to follow all the rules, which you obviously haven't done. – Thomas Baruchel – 2014-03-22T15:50:53.333

@ברוכאל, I object to your assertion that I haven't tried to follow the rules. The position of the optional test cases confused me into thinking that the final block covered all of the required cases; it turns out that I was wrong, and I'm going to edit the question shortly to avoid other people making the same mistake. I have now updated my code to handle the previously unhandled corner cases, and updated my link to a test to demonstrate that. – Peter Taylor – 2014-03-22T19:15:00.917

that's OK. You probably deserve the 300 points. Being new to CodeGolf, these 300 points were a challenging target for me, and I am still disappointed not to have got them while I am still thinking that at the deadline time my code was the shortest to perfectly fit the rules. Anyway, I have all my life for winning points. Regards. – Thomas Baruchel – 2014-03-22T19:32:56.977

@ברוכאל: I wanted to start 500 points (yes, I'm generous like that, it's not that I can give less) bounty, and give you those points, but I guess there is already a bounty started. Well, whatever. I'm wondering when this bounty will end, and who will get those points. – Konrad Borowski – 2014-03-22T22:13:50.233

Thank you for all these discussions and clarifications; I am not sure I can do better for this problem anyway; now looking for next problems to come. I removed my downvote because the code seems to work fully now. Regards. – Thomas Baruchel – 2014-03-23T09:39:54.127

2

Ruby - 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

This is my first experiment with ruby, so feel free to suggest improvements.

$ 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

mniip

Posted 2014-01-07T18:50:24.397

Reputation: 9 396

Removing support "..' and ".1.2" means you're not following the spec, right? (I would prefer removing them too.) – Omar – 2014-03-14T20:11:14.580

@OmarAntolín-Camarena On that particular point, the spec says, If you wish. I do not wish, so I'm not supporting fractions without 1st or 3rd group of digits. I am however supporting fractions lacking 2nd group of digits, which matches the spec. – mniip – 2014-03-14T20:14:32.937

@minip, you misread the spec: it doesn't say "if you wish you can support .. and .1.2", it says, "if you wish, you can assume that 0.. and 0.1.2 are always given as .. and .1.2". – Omar – 2014-03-14T20:47:51.637

@OmarAntolín-Camarena Point taken. Edited. – mniip – 2014-03-14T20:53:23.020

2

Python

No libraries - 156 characters

_=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)

Using fractions - 127 characters

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))

Oberon

Posted 2014-01-07T18:50:24.397

Reputation: 2 881

The fractions version prints things like "Fraction(7, 5)" instead of "7/5", doesn't it? – Omar – 2014-03-14T23:48:53.480

It doesn't; I'm not getting the top one working, by the way. _=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 – tomsmeding – 2014-03-15T07:51:03.130

@OmarAntolín-Camarena AFAIK, print uses str when available, not repr. This is the output on my end: http://puu.sh/7w64w.png

– Oberon – 2014-03-15T11:50:59.750

@tomsmeding Both are on one line; the line break was added to make them fit in the answer. _=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) should go all in one line. – Oberon – 2014-03-15T11:53:39.383

Oh right, @Oberon, as you can probably guess I wasn't at my computer and couldn't run the code. – Omar – 2014-03-15T12:18:15.590

I count 158 chars, it could be shortened further by replacing raw_input() by input() and defining t=bool(c) giving 152 chars _=lambda a,b:b and _(b,a%b)or a;a,b,c=input().split('.');t=bool(c);d,e=int(a+b+c)-t*int(a+b),(10**len(c)-t)*10**len(b);f=_(d,e);print'%i/%i'%(d/f,e/f)** – Willem – 2014-03-16T08:41:53.380

neglect the last ** in the previous comment – Willem – 2014-03-16T08:50:15.933

2

Mathematica, 143

As usual, Mathematica offers many high-level functions to do the job, but gives them verbose names.

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)

Sample output to be added later when I have time.

Jonathan Van Matre

Posted 2014-01-07T18:50:24.397

Reputation: 2 307

It looks to me as if this outputs integers as n, rather than n/1. Is that right? (My solution has the same bug... :() – Omar – 2014-03-14T20:02:27.357

Ah, now I see....specified in the comments. What an odd requirement...if every other fraction is reduced, why not allow n/1 to reduce to n? I'll add the extra ~50 bytes to convert integers later. – Jonathan Van Matre – 2014-03-14T20:07:52.833

Your approach is fine. Mine makes use of FromDigits so I decided to post it too. – DavidC – 2014-03-14T21:40:57.890

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

PyRulez

Posted 2014-01-07T18:50:24.397

Reputation: 6 547

Hey, this is code-golf, you aren't even trying! – mniip – 2014-03-16T14:34:35.363

@mniip I am not good at code golf. Atleast I used single character variable names. – PyRulez – 2014-03-16T20:00:06.547

1You never specified the language or the total amount of characters/bytes used. – Justin Fay – 2014-03-19T23:31:38.800

2Use {;} to save space on indents, span to implement s, add short aliases for functions, remove space where possible. 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 chars, down from 321. NB True is a synonym for otherwise, null z is length z==0 – bazzargh – 2014-03-20T12:30:32.887

2

C, 164

This is similar to orion's C solution, even though I did it from scratch. I confess however stealing a number of his optimizations. It is not much shorter, but it handles .25. = 1/4 and 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);}

Florian F

Posted 2014-01-07T18:50:24.397

Reputation: 591

2

Two python answers using no libraries. First handles the optional input without a digit before the first . and is 162 chars

_=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 doesn't handle nothing before the first digit but does handle all required inputs correctly and is 150 chars

_=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)

staircase27

Posted 2014-01-07T18:50:24.397

Reputation: 21

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)

While it isn't a clear winner for the 300 bounty... this is the shortest I can come up with:

  • Changes from previous version: some slight alteration to logic, and changes to the Power P function by altering it to +("1e"+a) instead of Math.pow(10,a) thereby saving a few more characters...

WallyWest

Posted 2014-01-07T18:50:24.397

Reputation: 6 949

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]

Most of the routine goes to massaging the input. Approximately 50 chars went to handling integers.


Examples

f["7801.098.765"]

frac1

More examples:

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


How it would normally be accomplished in Mathematica

FromDigits can obtain a fraction directly from a recurring repeating decimal, provided that the input is of a particular form. Integers are displayed as integers.

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

DavidC

Posted 2014-01-07T18:50:24.397

Reputation: 24 524

Your output is in the wrong format, it is way too pretty. – Omar – 2014-03-14T22:58:54.153

Strangely, this is the default format for expressing fractions in Mathematica. It would take several more characters to change this format to the simpler one. – DavidC – 2014-03-15T13:28:24.660

1

J (96 characters)

I don't use the slash symbol as a separator (but solution in Mathematica doesn't either since it uses a graphical representation which is better anyway); in J language the fraction is displayed with r instead as /:

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

Thomas Baruchel

Posted 2014-01-07T18:50:24.397

Reputation: 1 590

1

APL (not fully general)

Not fully general (like my solution for dc); works with Dyalog APL (but not on the online version of Dyalog APL, not sure why):

(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'

The first field is optional, but at least one digit is required for both other fields.

Thomas Baruchel

Posted 2014-01-07T18:50:24.397

Reputation: 1 590

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)

Example:

Input:

5.3.87

Output:

889/165

kitcar2000

Posted 2014-01-07T18:50:24.397

Reputation: 2 689

1

C (420 characters as written; less after removing unnecessary whitespace)

Note that this assumes 64-bit long (e.g. 64 bit Linux); it will fail for the test case 0.2.283950617 on systems using 32-bit long. This can be fixed at the cost of some characters by changing the type to long long and changing the printf format string accordingly.

#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);
}

celtschk

Posted 2014-01-07T18:50:24.397

Reputation: 4 650

Nice. You can shave off 1 character by changing '0' to 48. – Todd Lehman – 2015-04-14T21:59:41.843

I think you could also save a few more by rewriting the switch statement as if(c==46) n[++i]=1; else d[i]=10*d[i]+c-48,n[i]*=10;. – Todd Lehman – 2015-04-14T22:10:13.907

-3

GTB, 81

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

Example

?3.25.
            13/4

Timtech

Posted 2014-01-07T18:50:24.397

Reputation: 12 038

4Until a compiler is made freely available for this language, I will downvote every answer which uses it. – Gareth – 2014-03-14T18:33:27.760

1There seems to be a compiler on the page linked above? – skibrianski – 2014-03-14T21:20:06.070

@skibrianski See this post on meta

– mniip – 2014-03-14T21:32:09.820

2@Gareth, there are a couple of Mathematica answers for you to downvote, too. :P – Omar – 2014-03-14T22:25:23.587

2@OmarAntolín-Camarena There is a compiler/interpreter for Mathematica. GTB has none. Follow the GTB link above if you don't believe me. You'll get some compressed stuff for a proprietary program, then you'll search for that program and find that the site that claims to provide a download says it's not available. So how do we compile it? – Gareth – 2014-03-14T22:41:51.927

Oh, I'm sorry, I didn't know the GTB situation, I thought you meant there was a compiler or interpreter for it but that it was not freely available. @Gareth – Omar – 2014-03-14T22:58:26.020

Essentially, it's just a search-replace compiler. I'd have that fixed in under 5 minutes. -- in a normal language. – tomsmeding – 2014-03-15T07:57:18.687