# Terminating, Purely Periodic, or Eventually Periodic?

## 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.

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.

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

# 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

• Almost duplicate Oct 11 '16 at 16:30
• 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". Oct 11 '16 at 16:36
• given a fraction in the form p/q Given how? Can we take numerator and denominator as separate function arguments? Oct 11 '16 at 16:37
• 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? Oct 11 '16 at 16:49
• No, 1/13 is purely periodic because the repetent is '076923'. The 0 repeats with the repetent. Oct 12 '16 at 22:22

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

# Python, 6261 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.

• Fascinating! What does *r do? Oct 11 '16 at 18:31
• It unpacks the tuple r. f(1, *(2, 3), 4) is equivalent to f(1, 2, 3, 4). Oct 11 '16 at 18:32
• 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) Oct 11 '16 at 18:40
• 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) Oct 11 '16 at 19:14
• @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. Oct 11 '16 at 20:14

# 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.

# Perl, 4946 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

• All of the numbers in a certain group have to give the same value. Oct 11 '16 at 19:11
• @OliverNi They do now Oct 11 '16 at 19:12

## 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 %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.

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

# JavaScript (ES6), 918885797574 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.

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

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

# 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);
}
• 165 bytes Jul 9 '20 at 19:37

# 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.

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

# 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].

## 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.

# 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!

• 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 :). Oct 14 '16 at 19:21
• You can also use the input registers, which gives us ¿²r/fTrÖbÙJ as the final code :). Oct 14 '16 at 19:23

# 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