21
\$\begingroup\$

Introduction

A decimal is terminating if it has a finite number of decimal digits. For example, 0.4 (2/5) is terminating because it has one decimal digit.

A decimal is purely periodic if it has an infinite number of decimal digits and has no decimal digits before its repetent (the part of the decimal that repeats.) For example, 0.142857142857142… (1/7) is purely periodic because it has a repetend 142857, which starts repeating immediately after the decimal point.

A decimal is eventually periodic if it has an infinite number of decimal digits and has a finite number of decimal digits before its repetent (the part of the decimal that repeats.) For example, 0.166666666666666… (1/6) is eventually periodic because its repetend 6 starts repeating after a 1.

Your task

Write a program or function that, when given numbers p and q (integers, 0 <= p < q <= 100), will determine if the decimal representation of p/q is terminating, purely periodic, or eventually periodic.

You must output a if it's Terminating (i.e. 0.1), b if it's Purely Periodic (i.e. 0.333...), or c if it's Eventually Periodic (i.e. 0.166...), where a, b, and c are any distinct, constant strings of your choice.

Test cases

0/1 => Terminating
0/2 => Terminating
1/2 => Terminating
0/3 => Terminating
1/3 => Purely Periodic
2/3 => Purely Periodic
0/4 => Terminating
1/4 => Terminating
2/4 => Terminating
3/4 => Terminating
0/5 => Terminating
1/5 => Terminating
2/5 => Terminating
3/5 => Terminating
4/5 => Terminating
0/6 => Terminating
1/6 => Eventually Periodic
2/6 => Purely Periodic
3/6 => Terminating
4/6 => Purely Periodic
5/6 => Eventually Periodic
0/7 => Terminating
1/7 => Purely Periodic
2/7 => Purely Periodic
3/7 => Purely Periodic
4/7 => Purely Periodic
5/7 => Purely Periodic
6/7 => Purely Periodic
0/8 => Terminating
1/8 => Terminating
2/8 => Terminating
3/8 => Terminating
4/8 => Terminating
5/8 => Terminating
6/8 => Terminating
7/8 => Terminating
0/9 => Terminating
1/9 => Purely Periodic
2/9 => Purely Periodic
3/9 => Purely Periodic
4/9 => Purely Periodic
5/9 => Purely Periodic
6/9 => Purely Periodic
7/9 => Purely Periodic
8/9 => Purely Periodic
0/10 => Terminating
1/10 => Terminating
2/10 => Terminating
3/10 => Terminating
4/10 => Terminating
5/10 => Terminating
6/10 => Terminating
7/10 => Terminating
8/10 => Terminating
9/10 => Terminating
0/11 => Terminating
1/11 => Purely Periodic
2/11 => Purely Periodic
3/11 => Purely Periodic
4/11 => Purely Periodic
5/11 => Purely Periodic
6/11 => Purely Periodic
7/11 => Purely Periodic
8/11 => Purely Periodic
9/11 => Purely Periodic
10/11 => Purely Periodic
0/12 => Terminating
1/12 => Eventually Periodic
2/12 => Eventually Periodic
3/12 => Terminating
4/12 => Purely Periodic
5/12 => Eventually Periodic
6/12 => Terminating
7/12 => Eventually Periodic
8/12 => Purely Periodic
9/12 => Terminating
10/12 => Eventually Periodic
11/12 => Eventually Periodic
0/13 => Terminating
1/13 => Purely Periodic
2/13 => Purely Periodic
3/13 => Purely Periodic
4/13 => Purely Periodic
5/13 => Purely Periodic
6/13 => Purely Periodic
7/13 => Purely Periodic
8/13 => Purely Periodic
9/13 => Purely Periodic
10/13 => Purely Periodic
11/13 => Purely Periodic
12/13 => Purely Periodic
0/14 => Terminating
1/14 => Eventually Periodic
2/14 => Purely Periodic
3/14 => Eventually Periodic
4/14 => Purely Periodic
5/14 => Eventually Periodic
6/14 => Purely Periodic
7/14 => Terminating
8/14 => Purely Periodic
9/14 => Eventually Periodic
10/14 => Purely Periodic
11/14 => Eventually Periodic
12/14 => Purely Periodic
13/14 => Eventually Periodic
0/15 => Terminating
1/15 => Eventually Periodic
2/15 => Eventually Periodic
3/15 => Terminating
4/15 => Eventually Periodic
5/15 => Purely Periodic
6/15 => Terminating
7/15 => Eventually Periodic
8/15 => Eventually Periodic
9/15 => Terminating
10/15 => Purely Periodic
11/15 => Eventually Periodic
12/15 => Terminating
13/15 => Eventually Periodic
14/15 => Eventually Periodic

You can find all test cases here.

You are allowed to choose your own 3 values for the output, but it must be clear as to which one it is.

Remember, this is , so the code with the smallest number of bytes wins.

Hints

Terminating:

The prime factorization of a terminating decimal's denominator in simplest form consists only of 2s and 5s.

Purely Periodic:

The prime factorization of a purely periodic decimal's denominator in simplest form does not include any 2s or 5s.

Eventually Periodic:

The prime factorization of an eventually periodic decimal's denominator in simplest form includes at least one 2 or 5, but also includes other numbers.

Leaderboards

Here is a Stack Snippet to generate both a regular leaderboard and an overview of winners by language.

To make sure that your answer shows up, please start your answer with a headline, using the following Markdown template:

# Language Name, N bytes

where N is the size of your submission. If you improve your score, you can keep old scores in the headline, by striking them through. For instance:

# Ruby, <s>104</s> <s>101</s> 96 bytes

If there you want to include multiple numbers in your header (e.g. because your score is the sum of two files or you want to list interpreter flag penalties separately), make sure that the actual score is the last number in the header:

# Perl, 43 + 2 (-p flag) = 45 bytes

You can also make the language name a link which will then show up in the leaderboard snippet:

# [><>](http://esolangs.org/wiki/Fish), 121 bytes

var QUESTION_ID=95926,OVERRIDE_USER=12537;function answersUrl(e){return"https://api.stackexchange.com/2.2/questions/"+QUESTION_ID+"/answers?page="+e+"&pagesize=100&order=desc&sort=creation&site=codegolf&filter="+ANSWER_FILTER}function commentUrl(e,s){return"https://api.stackexchange.com/2.2/answers/"+s.join(";")+"/comments?page="+e+"&pagesize=100&order=desc&sort=creation&site=codegolf&filter="+COMMENT_FILTER}function getAnswers(){jQuery.ajax({url:answersUrl(answer_page++),method:"get",dataType:"jsonp",crossDomain:!0,success:function(e){answers.push.apply(answers,e.items),answers_hash=[],answer_ids=[],e.items.forEach(function(e){e.comments=[];var s=+e.share_link.match(/\d+/);answer_ids.push(s),answers_hash[s]=e}),e.has_more||(more_answers=!1),comment_page=1,getComments()}})}function getComments(){jQuery.ajax({url:commentUrl(comment_page++,answer_ids),method:"get",dataType:"jsonp",crossDomain:!0,success:function(e){e.items.forEach(function(e){e.owner.user_id===OVERRIDE_USER&&answers_hash[e.post_id].comments.push(e)}),e.has_more?getComments():more_answers?getAnswers():process()}})}function getAuthorName(e){return e.owner.display_name}function process(){var e=[];answers.forEach(function(s){var r=s.body;s.comments.forEach(function(e){OVERRIDE_REG.test(e.body)&&(r="<h1>"+e.body.replace(OVERRIDE_REG,"")+"</h1>")});var a=r.match(SCORE_REG);a&&e.push({user:getAuthorName(s),size:+a[2],language:a[1],link:s.share_link})}),e.sort(function(e,s){var r=e.size,a=s.size;return r-a});var s={},r=1,a=null,n=1;e.forEach(function(e){e.size!=a&&(n=r),a=e.size,++r;var t=jQuery("#answer-template").html();t=t.replace("{{PLACE}}",n+".").replace("{{NAME}}",e.user).replace("{{LANGUAGE}}",e.language).replace("{{SIZE}}",e.size).replace("{{LINK}}",e.link),t=jQuery(t),jQuery("#answers").append(t);var o=e.language;/<a/.test(o)&&(o=jQuery(o).text()),s[o]=s[o]||{lang:e.language,user:e.user,size:e.size,link:e.link}});var t=[];for(var o in s)s.hasOwnProperty(o)&&t.push(s[o]);t.sort(function(e,s){return e.lang>s.lang?1:e.lang<s.lang?-1:0});for(var c=0;c<t.length;++c){var i=jQuery("#language-template").html(),o=t[c];i=i.replace("{{LANGUAGE}}",o.lang).replace("{{NAME}}",o.user).replace("{{SIZE}}",o.size).replace("{{LINK}}",o.link),i=jQuery(i),jQuery("#languages").append(i)}}var ANSWER_FILTER="!t)IWYnsLAZle2tQ3KqrVveCRJfxcRLe",COMMENT_FILTER="!)Q2B_A2kjfAiU78X(md6BoYk",answers=[],answers_hash,answer_ids,answer_page=1,more_answers=!0,comment_page;getAnswers();var SCORE_REG=/<h\d>\s*([^\n,]*[^\s,]),.*?(\d+)(?=[^\n\d<>]*(?:<(?:s>[^\n<>]*<\/s>|[^\n<>]+>)[^\n\d<>]*)*<\/h\d>)/,OVERRIDE_REG=/^Override\s*header:\s*/i;
body{text-align:left!important}#answer-list,#language-list{padding:10px;width:290px;float:left}table thead{font-weight:700}table td{padding:5px}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> <link rel="stylesheet" type="text/css" href="//cdn.sstatic.net/codegolf/all.css?v=83c949450c8b"> <div id="answer-list"> <h2>Leaderboard</h2> <table class="answer-list"> <thead> <tr><td></td><td>Author</td><td>Language</td><td>Size</td></tr></thead> <tbody id="answers"> </tbody> </table> </div><div id="language-list"> <h2>Winners by Language</h2> <table class="language-list"> <thead> <tr><td>Language</td><td>User</td><td>Score</td></tr></thead> <tbody id="languages"> </tbody> </table> </div><table style="display: none"> <tbody id="answer-template"> <tr><td>{{PLACE}}</td><td>{{NAME}}</td><td>{{LANGUAGE}}</td><td>{{SIZE}}</td><td><a href="{{LINK}}">Link</a></td></tr></tbody> </table> <table style="display: none"> <tbody id="language-template"> <tr><td>{{LANGUAGE}}</td><td>{{NAME}}</td><td>{{SIZE}}</td><td><a href="{{LINK}}">Link</a></td></tr></tbody> </table>

\$\endgroup\$
  • 2
    \$\begingroup\$ Almost duplicate \$\endgroup\$ – Peter Taylor Oct 11 '16 at 16:30
  • 2
    \$\begingroup\$ If I thought it was actually a duplicate, I would have cast a close vote. There's a reason that I used the word "almost". \$\endgroup\$ – Peter Taylor Oct 11 '16 at 16:36
  • 1
    \$\begingroup\$ given a fraction in the form p/q Given how? Can we take numerator and denominator as separate function arguments? \$\endgroup\$ – Dennis Oct 11 '16 at 16:37
  • 2
    \$\begingroup\$ Can we output a non-constant value meeting a specific condition, such as anything falsy for terminating, 1 for purely periodic, and anything greater than 1 for eventually periodic? \$\endgroup\$ – ETHproductions Oct 11 '16 at 16:49
  • 1
    \$\begingroup\$ No, 1/13 is purely periodic because the repetent is '076923'. The 0 repeats with the repetent. \$\endgroup\$ – Oliver Ni Oct 12 '16 at 22:22

14 Answers 14

8
+50
\$\begingroup\$

Jelly, 10 bytes

:gÆfḍ⁵ṢQ¬Ḅ

Accepts denominator and numerator (in that order) as arguments. Returns 0 for terminating, 1 for purely periodic, and 2 for eventually periodic. Try it online! or verify all test cases.

How it works

:gÆfḍ⁵ṢQ¬Ḅ  Main link. Arguments: d (denominator), n (numerator)

 g          Compute the GCD of d and n.
:           Divide d by the GCD, yielding the denominator of the simplified form.
  Æf        Yield all prime factors of the previous result.
    ḍ⁵      Test 10 for divisibility by each prime factor.
            This yields 1 for 2 and 5, 0 for all other primes.
      Ṣ     Sort the resulting Booleans.
       Q    Unique; deduplicate the sorted Booleans.
        ¬   Logical NOT; replace 0 with 1 and vice versa to yield one of the
            following arrays.
              [    ]  <- no prime factors (denominator 1)
              [   0]  <- only 2 and 5
              [1   ]  <- neither 2 nor 5
              [1, 0]  <- mixed
         Ḅ  Unbinary; convert from base 2 to integer.
            This maps [] and [0] to 0, [1] to 1, and [1, 0] to 2.
\$\endgroup\$
11
\$\begingroup\$

JavaScript (ES6), 70 .. 68 53 bytes

f=(a,b,s=[],x)=>a?(s[a]^=a)?f(a*10%b,b,s,x||a):x==a:0

Returns 0 for terminating, true for purely periodic and false for eventually periodic.

How it works

What we're doing here is actually simulating a division by hand:

  1. a?...:0 - If the numerator is zero, we stop here and return 0. The sequence is terminating.
  2. (s[a]^=a)?...:x==a - If we've already encountered this numerator before, it means that the sequence is periodic and is going to repeat forever. We stop here and return either true if a is equal to the first value x of the sequence (purely periodic) or false if it's not (eventually periodic).
  3. f(a*10%b,b,s,x||a) - Else, we multiply the numerator a by 10. We compute the remainder of the division by the denominator b. And we repeat the process by using this remainder as the new numerator. (We also pass a as the first value of the sequence if it's not already stored in x.)

Example

  • Blue: numerator = 1
  • Green: denominator = 7
  • Red: multiplications by 10
  • Black: remainders
  • Gray: quotient digits (we don't really care about them here, and the above code is not computing them at all)

division

\$\endgroup\$
9
\$\begingroup\$

Python, 62 61 59 bytes

f=lambda n,d,r=[0,0]:(r[:3]+r).count(n)or f(10*n%d,d,r+[n])

Prints 1 for eventually periodic, 2 for purely periodic, and 4 for terminating.

Verify all test cases on repl.it.

\$\endgroup\$
  • \$\begingroup\$ Fascinating! What does *r do? \$\endgroup\$ – ETHproductions Oct 11 '16 at 18:31
  • \$\begingroup\$ It unpacks the tuple r. f(1, *(2, 3), 4) is equivalent to f(1, 2, 3, 4). \$\endgroup\$ – Dennis Oct 11 '16 at 18:32
  • \$\begingroup\$ So this would be 56 bytes in JS: f=(n,d,...r)=>n in r?~(n>0?n==r[0]:2):f(10*n%d,d,...r,n) \$\endgroup\$ – ETHproductions Oct 11 '16 at 18:40
  • \$\begingroup\$ My bad, 63 bytes (I forgot that in serves a very different purpose in JS than in Python): f=(n,d,...r)=>~r.indexOf(r)?~(n>0?n==r[0]:2):f(10*n%d,d,...r,n) \$\endgroup\$ – ETHproductions Oct 11 '16 at 19:14
  • \$\begingroup\$ @ETHproductions Neat. I guess f=(n,d,...r)=>~(i=r.indexOf(n))?n&&!i:f(10*n%d,d,...r,n) would work as well. \$\endgroup\$ – Dennis Oct 11 '16 at 20:14
6
\$\begingroup\$

Perl, 49 46 45 bytes

Includes +3 for -p

Based on Dennis's elegant idea but implemented in a perlish way

Give input numbers on STDIN

terminating.pl <<< "2 26"

termninating.pl:

#!/usr/bin/perl -p
/ /;1until$a{$_=$_*10%$' or$`}++;$_=$a{$`}

Prints a 2 if terminating. 1 if periodic and nothing if eventually periodic

\$\endgroup\$
  • \$\begingroup\$ All of the numbers in a certain group have to give the same value. \$\endgroup\$ – Oliver Ni Oct 11 '16 at 19:11
  • \$\begingroup\$ @OliverNi They do now \$\endgroup\$ – Ton Hospel Oct 11 '16 at 19:12
3
\$\begingroup\$

Batch, 247 bytes

@set/af=%1,g=%2
:g
@if not %f%==0 set/ah=g,g=f,f=h%%g&goto g
@set/ae=d=%2/g
:l
@set/ag=-~!(d%%2)*(!(d%%5)*4+1)
@if not %g%==1 set/ad/=g&goto l
@if %d%==1 (echo Terminating)else if %d%==%e% (echo Purely Periodic)else echo Eventually Periodic

Uses my fast gcd10 trick from Fraction to exact decimal. Obviously I could save a bunch of bytes by using a custom output format.

\$\endgroup\$
  • \$\begingroup\$ Why don't you just do @if %d%==1 (echo T)else if %d%==%e% (echo P)else echo E to save 42 bytes? \$\endgroup\$ – ETHproductions Oct 11 '16 at 17:55
  • \$\begingroup\$ Obviously I could save a bunch of bytes by using a custom output format. \$\endgroup\$ – Oliver Ni Oct 11 '16 at 19:14
  • \$\begingroup\$ @ETHproductions I think he doesn't want to, as Oliver has noted with a quote. \$\endgroup\$ – Erik the Outgolfer Oct 12 '16 at 15:35
3
\$\begingroup\$

JavaScript (ES6), 91 88 85 79 75 74 78 bytes

f=(n,d,g=(a,b)=>b?g(b,a%b):a,t=g(d/=c=g(n,d),10))=>n*~-d?t-1?f(n/c,d/t)/0:1:+f

Outputs NaN for terminating, 1 for purely periodic, and Infinity for eventually periodic.

Test snippet

f=(n,d,g=(a,b)=>b?g(b,a%b):a,t=g(d/=c=g(n,d),10))=>n*~-d?t-1?f(n/c,d/t)/0:1:+f

l=(n,d)=>console.log(n+"/"+d+":",f(n,d))

for(i=1;i<10;i++)for(j=0;j<i;j++)l(j,i);

Explanation

First, we divide both n and d by gcd(d,n), to reduce the fraction to its simplest form. This lets us avoid situations like 2/6 where the result would otherwise be calculated as purely periodic. We also define variable t as gcd(d,10); this will be used later.

The first check is whether n is 0 or d is 1. If n*(d-1) is 0, we return +f, or NaN: the fraction is terminating.

The next check is whether t is 1. If so, we return 1: the fraction is purely periodic.

If t is not 1, we divide d by t, run the whole function again, and divide by 0. If n/(d/t) is terminating, this returns NaN/0 = NaN: the fraction is terminating. Otherwise, it returns 1/0 = Infinity: the fraction is eventually periodic.

\$\endgroup\$
  • \$\begingroup\$ Where is the reduction to the simplest form ? \$\endgroup\$ – Ton Hospel Oct 11 '16 at 16:53
  • \$\begingroup\$ @TonHospel Fixed. \$\endgroup\$ – ETHproductions Oct 11 '16 at 17:01
  • \$\begingroup\$ @Arnauld I'm not sure what you mean. It returns Infinity for all of those values. \$\endgroup\$ – ETHproductions Oct 11 '16 at 18:49
  • \$\begingroup\$ @Arnauld Aw, man, I thought I could get away with never adjusting n... Thanks for pointing that out. \$\endgroup\$ – ETHproductions Oct 11 '16 at 19:05
3
\$\begingroup\$

Mathematica, 41 bytes

Ordering@{d=Denominator@#,GCD[d,10^d],1}&

Outputs {3,1,2} if the input has a terminating decimal expansion, {2,3,1} if the input has a purely periodic decimal expansion, and {3,2,1} if the input has an eventually periodic decimal expansion.

Based on the sneaky trick: if d is the denominator of a fraction in lowest terms, then the greatest common divisor of d and 10^d equals d if d has only 2s and 5s in its prime factorization; equals 1 if d has neither 2s nor 5s in its prime factorization; and equals some integer in between if d has 2s/5s and other primes.

The Ordering function just reports where the smallest, next smallest, and largest elements of the triple are, with ties broken left-to-right.

Flaw: returns the variant output {1,2,3} instead of {3,1,2} if the input is 0.

Mathematica, 46 bytes, perverse

b[a][[Log[d=Denominator@#,GCD[d,10^d]]]][[1]]&

Returns a[[1]] if the input has a terminating decimal expansion, b[[1]] if the input has a purely periodic decimal expansion, and b[a] if the input has an eventually periodic decimal expansion. Throws an error in all cases!

As above, we want to know whether that greatest common divisor equals 1, d, or somewhere in between. The base-d logarithm of that gcd equals 0, 1, or something in between.

Now we start torturing Mathematica. b[a][[n]] denotes the nth part of the expression b[a]. So b[a][[1]] returns a; b[a][[0]] returns b; and b[a][[x]], where x is a number between 0 and 1, makes Mathematica throw the error "Part::pkspec1: The expression x cannot be used as a part specification." and returns b[a][[x]] unevaluated.

This already distinguishes the three cases appropriately, except that the output for the eventually periodic case is b[a][[x]], which is non-constant because x is the actual logarithm of something. So then we apply [[1]] to the outputs already described. Because of how Mathematica internally represents b[a][[x]], the result of b[a][[x]][[1]] is simply b[a]. On the other hand, applying [[1]] to a results in a different error "Part::partd: Part specification a[[1]] is longer than depth of object." and returns a[[1]] unevaluated (and similarly for b).

Flaw: lies about the input 0, returning b[a] instead of a[[1]].

\$\endgroup\$
2
\$\begingroup\$

C 173 Bytes

Takes two integers from stdin, prints 1 for purely periodic, -1 for eventually periodic, and 0 for terminating.

int r;main(_,n,d){_-1?_-2?d-1?d%2&&d%5?r=1:d%2?main(3,n,d/5):main(3,n,d/2),r=r?-1:0:r=0:d?main(2,d,n%d):r=n:scanf("%d %d",&n,&d),main(2,n,d),main(3,n/r,d/r),printf("%d",r);}

Ungolfed:

// returns 1 for periodic, 0 for terminating, <0 for eventually periodic
int periodic(int num, int den) { // 3
    if (den == 1) return 0;
    if (den % 2 && den % 5) // pure periodic
        return 1;
    if (den % 2) return periodic(num,den/5) ? -1 : 0;
    return periodic(num,den/2) ? -1 : 0;
}

int gcd(int num, int den) { // 2
    if (den) 
        return gcd(den,num%den);
    return num;
}

int main(n,d) // 1
{
    scanf("%d %d",&n,&d);
    printf("%d",periodic(n/gcd(n,d),d/gcd(n,d)));
    return 0;
}   

Half-golfed:

int r;main(_,n,d){
    _-1? 
    _-2?
    // periodic
    d-1?
        d%2&&d%5?
            r=1:
                d%2?
                    main(3,n,d/5): //periodic
                    main(3,n,d/2), //periodic
                        r=r?-1:0:
                r=0
    // gcd
    :d?main(2,d,n%d):r=n // gcd
    // main
    :scanf("%d %d",&n,&d),
     main(2,n,d), // gcd
     main(3,n/r,d/r), // periodic
     printf("%d",r);
}
\$\endgroup\$
2
\$\begingroup\$

Actually, 15 bytes

This is based on Dennis' Jelly answer. 0 is terminating, 1 is purely periodic, and 2 is eventually periodic. Golfing suggestions welcome. Try it online!

▼Ny9u♀%SR♂b╔2@¿

Ungolfing

      Implicit input [a, b].
▼     Divide a and b by gcd(a,b).
Ny    Get the unique prime divisors of the reduced denominator.
9u    Push 10.
♀%    10 mod every member of uniq_p_d.
SR    Sort the mods and reverse.
♂b    Logical buffer. Converts every (10 % p != 0) to 1, and everything else to 0.
        Meaning if 2 or 5 divided b, they are now 0, and every other prime is now 1.
╔     Uniquify the list.
        If terminating, return [0].
        If purely periodic, return [1].
        If eventually periodic, return [1, 0].
        Else, (if b was 1), return [].
2@¿   Convert from binary to decimal. Return 0, 1, or 2.
      Implicit return.
\$\endgroup\$
1
\$\begingroup\$

Mathematica, 44 bytes

If[ListQ@Last@#,Length@#==1]&@@RealDigits@#&

Returns Null for Terminating, True for purely periodic, and False for eventually periodic.

Explanation

RealDigits

Find the decimal expansion of N. (repeated digits are surrounded by an extra head List {}).

ListQ@Last@#

Check whether the last element of the decimal expansion is a List.

Length@#==1

If the above condition is True, check whether the entire decimal expansion consists of one thing. (A List counts as one entity). (returns True or False)

(If the condition is False, then a Null is returned because there is no third argument for If)

\$\endgroup\$
1
\$\begingroup\$

Pyth, 31 27 bytes

AQ={P/HiGH?l@H=j25T?l-HT1Z2

Input

4,12

You can try it here. Prints 1 for eventually periodic, 2 for purely periodic, and 0 for terminating. This is my first time answering in codegolf. Any suggestions are welcome.

Explanation

AQ                                              // 1st element to G and 2nd element to H
    ={P                                         // Assign unique prime factors to H
        /H                                      // Simplify denominator
            iGH                                 // Find GCD
                ?l                              // Check length of filtered H
                    @H                          // Filter H by Y
                        =j25T                   // Assign a set [2,5] to T
                                ?l-HT           // Check length of H - T
                                        1Z2     // Print result

Note that [2,3] filtered by [2,5] = [2] but [2,3,5] - [2,5] = [3].

\$\endgroup\$
1
\$\begingroup\$

PARI/GP, 64 bytes

f(x,y)=if(setminus(factor(y=y/gcd(x,y))[,1]~,[2,5]),gcd(y,10)>1)

Outputs nothing for terminating, 0 for purely and 1 for eventually periodic.

Not very fancy, I hoped for something better when I started.

\$\endgroup\$
1
\$\begingroup\$

05AB1E, 16 11 bytes

Saved 5 bytes thanks to @Adnan!

¿²r/fTrÖbÙJ

Prints 0 for Purely Periodic, 1 for Terminating, and 10 for Eventually Periodic.

Explanation:

                 # Implicit input
                 # Implicit input
  ¿              # Take GCD of numbers
   ²             # Push top value from input register
    r            # Reverse stack order
     /           # Divide (denominator by GCD)
      f          # Find unique prime factors
       TrÖ       # Test 10 for divisibility
          b      # Convert (True -> 1, False -> 0)
           Ù     # Deduplicate array
            J    # Join chars in array
                 # Implicit print

Input is taken as p newline q.

Try it online!

\$\endgroup\$
  • \$\begingroup\$ Nice to see you using 05AB1E :). Osabie also uses implicit input which allows us to remove the first two I's. Furthermore, a constant predefined to 10 is T. Same for 2B, which is b :). \$\endgroup\$ – Adnan Oct 14 '16 at 19:21
  • \$\begingroup\$ You can also use the input registers, which gives us ¿²r/fTrÖbÙJ as the final code :). \$\endgroup\$ – Adnan Oct 14 '16 at 19:23
1
\$\begingroup\$

PHP, 126 Bytes

$d=$argv[2];$a[]=$n=$argv[1];while($n%$d&&!$t){$n*=10;$t=in_array($n%=$d,$a);$a[]=$n;}if($a[1]&&$t)$t+=$a[0]!=end($a);echo+$t;

Prints 0 for terminated and 1 for purely periodic 2 for eventually. Let me explain if a numerator is twice in the array here starts the periodic session if it is terminated the echo end($a); value is 0 If you not trust me put $t=count($a)>$d?2:0; in the loop

To make it more clear please add print_r($a); or var_dump($a); or json_encode($a); after the loop

you can see one numerator twice or a zero at the end of the array if a numerator is twice count the items between the two items and you can get the length of the periodic and you can see the position by the first numerator where the periodic begins

So after that we can find the position and the length of the periodic sequence with if($t){echo $p=array_search(end($a),$a);echo $l=count($a)-$p-1;}

Visualize the periodic

$d=$argv[2];
$a[]=$n=$argv[1]; #array numerator
$r[]=$n/$d^0; #array result of the division
$r[]=".";
while($n%$d&&!$t){
    $n*=10; 
    $n-=$d*$r[]=$n/$d^0;
    $t=in_array($n%=$d,$a); #stop if numerator is twice 
    $a[]=$n;
}
if($a[1]&&$t)$t+=$a[0]!=end($a); #periodic term starts directly?
if($t){
    echo $p=array_search(end($a),$a)."\n"; #output the beginning position of the periodic term
    echo $l=count($a)-$p-1; #output the length of the periodic term
    echo "\n";
    echo str_repeat(" ",2+$p).str_repeat("_",$l-1)."\n"; #visualize the periodic term
    #echo join(array_slice($r,0,1+$p)).join(array_slice($r,1+$p))."\n";# if you want only the periodic term 
    echo join($r); #result if the division
}
echo+$t; # 0 terminated 1+2 periodic 2 periodic start not directly

Output visualize the periodic term

1/18
   _
0.05

1/12
    _
0.083

1/13
  ______
0.076923

1/14
   ______
0.0714285

An other way with 130 Bytes

$r=bcdiv(($z=$argv)[1],$z[2],400);for($p=2;$i++<200;)if(substr($r,2,$i)==substr($r,2+$i,$i))$p=1;echo strlen(rtrim($r,0))<50?0:$p;

Expanded Version

$r=bcdiv(($z=$argv)[1],$z[2],400); # 100 is the maximal denominator 
# we need a string length with the double value of the sum the length from 1 until the denominator
for($p=2;$i++<200;)if(substr($r,2,$i)==substr($r,2+$i,$i))$p=1;
# all results begin with 0. 
#take two substrings with the same length after that and comparize both. 
#if we found 2 same substrings we have a periodic which starts at the first decimal place
echo strlen(rtrim($r,0))<50?0:$p; 
# if we can trim the length of the result we have a terminated result
\$\endgroup\$
  • \$\begingroup\$ See also Fraction to exact decimal. \$\endgroup\$ – Neil Oct 12 '16 at 20:18
  • \$\begingroup\$ @Neil you mean I should modify the code to answer the other question? \$\endgroup\$ – Jörg Hülsermann Oct 12 '16 at 20:30
  • \$\begingroup\$ Well, I was just thinking the other question doesn't have a PHP answer; perhaps you would like to provide one. \$\endgroup\$ – Neil Oct 13 '16 at 0:21
  • \$\begingroup\$ @RosLuP For the example 3/53 this array will be create [3,30,35,32,2,20,41,39,19,31,45,26,48,3] \$\endgroup\$ – Jörg Hülsermann Oct 13 '16 at 18:59
  • \$\begingroup\$ 3 / 103 =0.0291262135922330097087378640776699029126213592233009708 and so in the same period can appear the same digit (for example the digit 7 between 00...00 above ) But if the array you speak about is not the one of digit but the array of the {d=10*(d%b)} where the digit is d/c than I think it is ok there is only one value d_i to each period... \$\endgroup\$ – RosLuP Oct 13 '16 at 19:20

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.