Jump to content

Integer long division

From Rosetta Code
Integer long division is a draft programming task. It is not yet considered ready to be promoted as a complete task, for reasons that should be found in its talk page.

Write a function that prints the result of the division of two positive integers with infinite precision (only limited by the available memory), stopping before the period starts repeating itself. Return also the length of this period (0 if there is no period).

Demonstrate it with the division 1/149, whose result is 0.0067114093959731543624161073825503355704697986577181208053691275167785234899328859060402684563758389261744966442953020134228187919463087248322147651, where the last 148 digits repeat endlessly.

The result could be stored as a string or simply output to the screen.
Note that the division of any two integers will always produce a period, but if the numerator is an exact multiple of the denominator, or if the denominator contains only the factors 2 and 5, the period will be 0. In the remaining cases, these possible 2's and 5's of the denominator produce a leading number of digits in the quotient, but have no effect on the period.


References


Related



C++

Library: GMP
#include <gmpxx.h>

#include <iomanip>
#include <iostream>
#include <map>
#include <string>

using big_int = mpz_class;

std::pair<std::string, size_t> divide(const big_int& n, const big_int& d) {
    assert(n >= 0);
    assert(d > 0);
    std::string result = big_int(n / d).get_str();
    result += '.';
    big_int c = 10 * (n % d);
    size_t digits = 0;
    std::map<big_int, size_t> seen;
    while (seen.count(c) == 0) {
        if (c == 0) {
            if (result.back() == '.')
                result.pop_back();
            return {result, 0};
        }
        seen[c] = digits++;
        if (c < d) {
            result += '0';
            c *= 10;
        } else {
            result += big_int(c / d).get_str();
            c = 10 * (c % d);
        }
    }
    return {result, digits - seen[c]};
}

int main() {
    big_int test[][2] = {
        {0, 1},   {1, 1},    {1, 5},
        {1, 3},   {1, 7},    {83, 60},
        {1, 17},  {10, 13},  {3227, 555},
        {1, 149}, {1, 5261}, {476837158203125, big_int("9223372036854775808")}};
    for (auto [n, d] : test) {
        auto [result, period] = divide(n, d);
        std::string str = n.get_str();
        str += '/';
        str += d.get_str();
        std::string repetend = result.substr(result.size() - period);
        if (repetend.size() > 30)
            repetend.replace(15, repetend.size() - 30, "...");
        result.resize(result.size() - period);
        std::cout << std::setw(35) << str << " = " << result;
        if (period != 0)
            std::cout << '{' << repetend << "} (period " << period << ')';
        std::cout << '\n';
    }
}
Output:
                                0/1 = 0
                                1/1 = 1
                                1/5 = 0.2
                                1/3 = 0.{3} (period 1)
                                1/7 = 0.{142857} (period 6)
                              83/60 = 1.38{3} (period 1)
                               1/17 = 0.{0588235294117647} (period 16)
                              10/13 = 0.{769230} (period 6)
                           3227/555 = 5.8{144} (period 3)
                              1/149 = 0.{006711409395973...087248322147651} (period 148)
                             1/5261 = 0.{000190077931952...263257935753659} (period 1052)
476837158203125/9223372036854775808 = 0.000051698788284564229679463043254372678347863256931304931640625

Common Lisp

(defun $/ (a b)
 "Divide a/b with infinite precision printing each digit as it is calculated and return the period length"
; ($/ 1 17) => 588235294117647 ; 16
  (assert (and (integerp a) (integerp b) (not (zerop b))))
  (do* (c 
       (i0 (1+ (max (factor-multiplicity b 2) (factor-multiplicity b 5)))) ; the position which marks the beginning of the period
       (r a (* 10 r)) ; remainder
       (i 0 (1+ i)) ; iterations counter
       (rem (if (= i i0) r -1) (if (= i i0) r rem)) ) ; the first remainder against which to check for repeating remainders
      ((and (= r rem) (not (= i i0))) (- i i0))
    (multiple-value-setq (c r) (floor r b))
    (princ c) ))


(defun factor-multiplicity (n factor)
"Return how many times the factor is contained in n"
; (factor-multiplicity 12 2) => 2
	(do* ((i 0 (1+ i))
	      (n (/ n factor) (/ n factor)) )
             ((not (integerp n)) i)
	    () ))
Output:
($/ 1 149) 
00067114093959731543624161073825503355704697986577181208053691275167785234899328859060402684563758389261744966442953020134228187919463087248322147651
148

FreeBASIC

Type Dict
    As Integer key
    As Integer value
    As Dict Ptr sgte
End Type

Function dict_find(head As Dict Ptr, key As Integer) As Integer
    Dim As Dict Ptr current = head
    While current <> 0
        If current->key = key Then Return current->value
        current = current->sgte
    Wend
    Return -1
End Function

Sub dict_add(head As Dict Ptr Ptr, key As Integer, value As Integer)
    Dim As Dict Ptr newNode = New Dict
    newNode->key = key
    newNode->value = value
    newNode->sgte = *head
    *head = newNode
End Sub

Sub dict_destroy(head As Dict Ptr)
    Dim As Dict Ptr current = head
    While current <> 0
        Dim As Dict Ptr sgte = current->sgte
        Delete current
        current = sgte
    Wend
End Sub

Sub test(n As Integer, d As Integer)
    Dim As Integer numr = Abs(n), denr = Abs(d)
    Dim As Integer c = 10 * (numr Mod denr)
    Dim As String sign = Iif((Sgn(n) * Sgn(d)) = -1, "-", "")
    Dim As String q = sign & Str(numr \ denr) & "."
    Dim As String digits = ""
    
    While c > 0 Andalso c < denr
        c *= 10
        q &= "0"
    Wend
    
    Dim As Dict Ptr dict = 0
    Dim As Integer posic = 1
    
    While dict_find(dict, c) = -1
        Dim As Integer digit = c \ denr
        digits &= Chr(Asc("0") + digit)
        dict_add(@dict, c, posic)
        c = 10 * (c Mod denr)
        posic += 1
    Wend
    
    Dim As Integer pc = dict_find(dict, c)
    dict_destroy(dict)
    
    q &= Left(digits, pc-1)
    digits = Mid(digits, pc)
    
    If digits = "0" Then
        If Right(q, 1) = "." Then q = Left(q, Len(q)-1)
    Else
        While Right(digits, 1) = Right(q, 1)
            Dim As String lastChar = Right(q, 1)
            digits = lastChar & Left(digits, Len(digits)-1)
            q = Left(q, Len(q)-1)
        Wend
        
        If Len(digits) > 20 Then digits = Left(digits, 10) & "..." & Right(digits, 10)
        q &= "{" & digits & "} (period " & Str(Len(digits)) & ")"
    End If
    
    Print Using Space(8- Len(Str(n)) - Len(Str(d))) & "&/& = &"; Str(n); Str(d); q
End Sub

' Test cases
Dim As Longint pairs(14,1) = { _
{0,1}, {1,1}, {1,3}, {-1,3}, {1,-3}, {-1,-3}, {-17,2}, {177,16}, _
{1,7}, {-83,60}, {1,17}, {10,13}, {3227,555}, {1,149}, {1,5261} }

For i As Integer = 0 To 14
    test(pairs(i,0), pairs(i,1))
Next

Sleep
Output:
      0/1 = 0
      1/1 = 1
      1/3 = 0.{3} (period 1)
     -1/3 = -0.{3} (period 1)
     1/-3 = -0.{3} (period 1)
    -1/-3 = 0.{3} (period 1)
    -17/2 = -8.5
   177/16 = 11.0625
      1/7 = 0.{142857} (period 6)
   -83/60 = -1.38{3} (period 1)
     1/17 = 0.{0588235294117647} (period 16)
    10/13 = 0.{769230} (period 6)
 3227/555 = 5.8{144} (period 3)
    1/149 = 0.{0067114093...8322147651} (period 23)
   1/5261 = 0.{0001900779...7935753659} (period 23)

Java

import java.math.BigInteger;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public final class IntegerLongDivision {

	public static void main(String[] args) {
		List<List<String>> tests = List.of(
			List.of( "0", "1" ), List.of( "1", "1" ), List.of( "1", "3" ), List.of( "1", "7" ), List.of( "83","60" ),
			List.of( "1", "17" ), List.of( "10", "13" ), List.of( "3227", "555" ),
			List.of( "476837158203125", "9223372036854775808" ), List.of( "1", "149" ), List.of( "1", "5261" )
		);
		
		tests.forEach( test -> {
			BigInteger numer = new BigInteger(test.getFirst());
			BigInteger denom = new BigInteger(test.getLast());
			Tuple tuple = divide(numer, denom);
			String result = tuple.result;
			final int period = tuple.period(); 			
			
			String repetend = result.substring(result.length() - period);       
	        if ( repetend.length() > 30 ) {
	        	repetend = repetend.substring(0, 15) + " ... " + repetend.substring(repetend.length() - 15);
	        }
	        
	        result = result.substring(0, result.length() - period);
	        String rational = numer.toString() + " / " + denom.toString();
	        System.out.print(String.format("%38s%s%s", rational, " = ", result));
	        if ( period != 0 ) {
	            System.out.print("{" + repetend + "} (period " + period + ")");
	        }
	        System.out.println();
		} );
	}
	
	private static Tuple divide(BigInteger numer, BigInteger denom) {
		if ( numer.signum() < 0 ) {
			throw new AssertionError("m must not be negative.");
		}
		if ( denom.signum() <= 0 ) {
			throw new AssertionError("n must be positive.");
		}
		
		String result = numer.divide(denom).toString() + ".";
		BigInteger carry = numer.mod(denom).multiply(BigInteger.TEN);
		int digitCount = 0;
		Map<BigInteger, Integer> carries = new HashMap<BigInteger, Integer>();
		while ( ! carries.keySet().contains(carry) ) {
			if ( carry.signum() == 0 ) {
	            if ( result.endsWith(".") ) {
	                result = result.substring(0, result.length() - 1);
	            }
	            return new Tuple(result , 0);
	        }
	        carries.put(carry, digitCount++);
	        if ( carry.compareTo(denom) < 0 ) {
	            result += "0";
	            carry = carry.multiply(BigInteger.TEN);
	        } else {
	        	result += carry.divide(denom).toString();
	            carry = carry.mod(denom).multiply(BigInteger.TEN);
	        }
	    }
		
	    return new Tuple(result, digitCount - carries.getOrDefault(carry, 0));	  
	}

	private static record Tuple(String result, int period) {}

}
Output:
                                 0 / 1 = 0
                                 1 / 1 = 1
                                 1 / 3 = 0.{3} (period 1)
                                 1 / 7 = 0.{142857} (period 6)
                               83 / 60 = 1.38{3} (period 1)
                                1 / 17 = 0.{0588235294117647} (period 16)
                               10 / 13 = 0.{769230} (period 6)
                            3227 / 555 = 5.8{144} (period 3)
 476837158203125 / 9223372036854775808 = 0.000051698788284564229679463043254372678347863256931304931640625
                               1 / 149 = 0.{006711409395973 ... 087248322147651} (period 148)
                              1 / 5261 = 0.{000190077931952 ... 263257935753659} (period 1052)

jq

Adapted from Wren

Works with gojq, the Go implementation of jq

gojq supports unbounded-precision integer arithmetic, which makes light work of the task.

This entry uses the "(repetend)" convention (e.g. 1/3 => 0.(3)), partly because the Unicode "overline" might not display properly. In case the overline style is preferred, simply use the following function in the obvious way:

# "\u0305"
def overline: explode | map(., 773) | implode;
# To take advantage of gojq's support for accurate integer division:
def idivide($j):
  . as $i
  | ($i % $j) as $mod
  | ($i - $mod) / $j ;

# If $m >= 0, $n > 0 then emit [ s, repetend ]
# where s is the string representation of $m/$n (possibly including trailing dots);
#       repetend is a string giving the repeating part of the decimal if any.
#
def integer_division($m; $n):
    if $m < 0 then "numerator must not be negative" | error
    elif $n <= 0 then "denominator must be positive" | error
    else ($m | idivide($n) | tostring + ".") as $quotient
    |  {c: (($m % $n) * 10), $quotient }
    | until (.c <= 0 or .c >= $n;  .c *= 10 | .quotient += "0")
    | . + { digits: "", passed: {}, i: 0, emit: false }
    | until (.emit;
        (.c | tostring) as $cs
        | if .passed|has($cs) 
          then .quotient = .quotient + .digits[: .passed[$cs]]
	  | .emit = {quotient, repetend: .digits[.passed[$cs] :] }
          else .q = (.c | idivide($n))
          | .r = .c % $n
          | .passed[$cs] = .i
          | .digits += (.q|tostring)
          | .i += 1
          | .c = .r * 10
          end
          )
     end
     | .emit
     # move zeros from the tail of .repetend if possible
     | until ( .repetend[-1:] != "0" or .quotient[-1:] != "0";
              .quotient   |= .[:-1]
              | .repetend |= "0" + .[:-1] )
     | if .repetend != "0" and (.repetend|length > 0)
       then [.quotient + "(" + .repetend + ")", .repetend]
       else [(.quotient | sub("[.]$"; "")),
             (.repetend | if . == "0" then "" else . end)]
       end ;

def examples:
    [0, 1], [1, 1], [1, 3], [1, 7], [83,60], [1, 17], [10, 13], [3227, 555],
    [476837158203125, 9223372036854775808],
    [1, 149], [1, 5261]
;

def task:
  examples as [$a, $b]
  | (integer_division($a; $b)) as [$s, $r]
  |"\($a)/\($b) = \($s)",
    "Repetend is \($r)",
    "Period is \($r|length)\n" ;

task
Output:
0/1 = 0
Repetend is 
Period is 0

1/1 = 1
Repetend is 
Period is 0

1/3 = 0.(3)
Repetend is 3
Period is 1

1/7 = 0.(142857)
Repetend is 142857
Period is 6

83/60 = 1.38(3)
Repetend is 3
Period is 1

1/17 = 0.(0588235294117647)
Repetend is 0588235294117647
Period is 16

10/13 = 0.(769230)
Repetend is 769230
Period is 6

3227/555 = 5.8(144)
Repetend is 144
Period is 3

476837158203125/9223372036854775808 = 0.000051698788284564229679463043254372678347863256931304931640625
Repetend is 
Period is 0

1/149 = 0.(0067114093959731543624161073825503355704697986577181208053691275167785234899328859060402684563758389261744966442953020134228187919463087248322147651)
Repetend is 0067114093959731543624161073825503355704697986577181208053691275167785234899328859060402684563758389261744966442953020134228187919463087248322147651
Period is 148

1/5261 = 0.(00019007793195210036114807070899068618133434708230374453525945637711461699296711651777228663752138376734461129062915795476145219540011404675917126021668884242539441170880060824938224672115567382626877019578026991066337198251283026040676677437749477285687131724006842805550275613001330545523664702528036494962934803269340429576126211746816194639802318950769815624406006462649686371412279034404105683330165367800798327314198821516821896977760881961604257745675727048089716783881391370461889374643603877589811822847367420642463409998099220680478996388519292910093138186656529176962554647405436228853830070328834822277133624786162326553887093708420452385478045998859532408287397833111575746055882911993917506177532788443261737312298042197300893366280174871697395932332256225052271431286827599315719444972438699866945447633529747196350503706519673065957042387378825318380536019768104923018437559399353735031362858772096559589431666983463219920167268580117848317810302223911803839574225432427295191028321611860862953811062535639612241018817715263257935753659)
Repetend is 00019007793195210036114807070899068618133434708230374453525945637711461699296711651777228663752138376734461129062915795476145219540011404675917126021668884242539441170880060824938224672115567382626877019578026991066337198251283026040676677437749477285687131724006842805550275613001330545523664702528036494962934803269340429576126211746816194639802318950769815624406006462649686371412279034404105683330165367800798327314198821516821896977760881961604257745675727048089716783881391370461889374643603877589811822847367420642463409998099220680478996388519292910093138186656529176962554647405436228853830070328834822277133624786162326553887093708420452385478045998859532408287397833111575746055882911993917506177532788443261737312298042197300893366280174871697395932332256225052271431286827599315719444972438699866945447633529747196350503706519673065957042387378825318380536019768104923018437559399353735031362858772096559589431666983463219920167268580117848317810302223911803839574225432427295191028321611860862953811062535639612241018817715263257935753659
Period is 1052

Julia

function f2d(numr, denr)
    dpart, remainders, r = "", Dict{BigInt, Int}(), BigInt(numr) % denr
    while (r != 0) && !haskey(remainders, r)
        remainders[r] = length(dpart)
        r *= 10
        partrem, r = divrem(r, denr)
        dpart *= string(partrem)
    end
    return r == 0 ? (0, 0) : (dpart[remainders[r]+1:end], remainders[r])
end

overline(s) = mapreduce(c -> "\u0305" * c, *, s)

testpairs =  [(0, 1), (1, 1), (1, 3), (1, 7), (-83, 60), (1, 17), (10, 13), (3227, 555),
              (5^21, Int128(2)^63), (1, 149), (1, 5261)]

function testrepeatingdecimals()
    for (numr, denr) in testpairs
        n = numr < 0 ? -numr : numr
        repeated, extra = f2d(n, denr)
        if repeated == 0
            println(lpad("$numr/$denr", 36), "  (Period 0)     = ", BigFloat(numr)/denr)
        else
            prefix, suffix = split(string(BigFloat(numr) / denr)[begin:end-2], ".")
            println(lpad("$numr/$denr", 36), "  (Period ", rpad("$(length(repeated)))", 6),
                " = $prefix.$(suffix[begin:extra])$(overline(repeated))")
        end
    end
end

testrepeatingdecimals()
Output:

                                 0/1  (Period 0)     = 0.0
                                 1/1  (Period 0)     = 1.0
                                 1/3  (Period 1)     = 0.̅3
                                 1/7  (Period 6)     = 0.̅1̅4̅2̅8̅5̅7
                              -83/60  (Period 1)     = -1.38̅3
                                1/17  (Period 16)    = 0.̅0̅5̅8̅8̅2̅3̅5̅2̅9̅4̅1̅1̅7̅6̅4̅7
                               10/13  (Period 6)     = 0.̅7̅6̅9̅2̅3̅0
                            3227/555  (Period 3)     = 5.8̅1̅4̅4
 476837158203125/9223372036854775808  (Period 0)     = 5.1698788284564229679463043254372678347863256931304931640625e-05
                               1/149  (Period 148)   = 0.̅0̅0̅6̅7̅1̅1̅4̅0̅9̅3̅9̅5̅9̅7̅3̅1̅5̅4̅3̅6̅2̅4̅1̅6̅1̅0̅7̅3̅8̅2̅5̅5̅0̅3̅3̅5̅5̅7̅0̅4̅6̅9̅7̅9̅8̅6̅5̅7̅7̅1̅8̅1̅2̅0̅8̅0̅5̅3̅6̅9̅1̅2̅7̅5̅1̅6̅7̅7̅8̅5̅2̅3̅4̅8̅9̅9̅3̅2̅8̅8̅5̅9̅0̅6̅0̅4̅0̅2̅6̅8̅4̅5̅6̅3̅7̅5̅8̅3̅8̅9̅2̅6̅1̅7̅4̅4̅9̅6̅6̅4̅4̅2̅9̅5̅3̅0̅2̅0̅1̅3̅4̅2̅2̅8̅1̅8̅7̅9̅1̅9̅4̅6̅3̅0̅8̅7̅2̅4̅8̅3̅2̅2̅1̅4̅7̅6̅5̅1
                              1/5261  (Period 1052)  = 0.̅0̅0̅0̅1̅9̅0̅0̅7̅7̅9̅3̅1̅9̅5̅2̅1̅0̅0̅3̅6̅1̅1̅4̅8̅0̅7̅0̅7̅0̅8̅9̅9̅0̅6̅8̅6̅1̅8̅1̅3̅3̅4̅3̅4̅7̅0̅8̅2̅3̅0̅3̅7̅4̅4̅5̅3̅5̅2̅5̅9̅4̅5̅6̅3̅7̅7̅1̅1̅4̅6̅1̅6̅9̅9̅2̅9̅6̅7̅1̅1̅6̅5̅1̅7̅7̅7̅2̅2̅8̅6̅6̅3̅7̅5̅2̅1̅3̅8̅3̅7̅6̅7̅3̅4̅4̅6̅1̅1̅2̅9̅0̅6̅2̅9̅1̅5̅7̅9̅5̅4̅7̅6̅1̅4̅5̅2̅1̅9̅5̅4̅0̅0̅1̅1̅4̅0̅4̅6̅7̅5̅9̅1̅7̅1̅2̅6̅0̅2̅1̅6̅6̅8̅8̅8̅4̅2̅4̅2̅5̅3̅9̅4̅4̅1̅1̅7̅0̅8̅8̅0̅0̅6̅0̅8̅2̅4̅9̅3̅8̅2̅2̅4̅6̅7̅2̅1̅1̅5̅5̅6̅7̅3̅8̅2̅6̅2̅6̅8̅7̅7̅0̅1̅9̅5̅7̅8̅0̅2̅6̅9̅9̅1̅0̅6̅6̅3̅3̅7̅1̅9̅8̅2̅5̅1̅2̅8̅3̅0̅2̅6̅0̅4̅0̅6̅7̅6̅6̅7̅7̅4̅3̅7̅7̅4̅9̅4̅7̅7̅2̅8̅5̅6̅8̅7̅1̅3̅1̅7̅2̅4̅0̅0̅6̅8̅4̅2̅8̅0̅5̅5̅5̅0̅2̅7̅5̅6̅1̅3̅0̅0̅1̅3̅3̅0̅5̅4̅5̅5̅2̅3̅6̅6̅4̅7̅0̅2̅5̅2̅8̅0̅3̅6̅4̅9̅4̅9̅6̅2̅9̅3̅4̅8̅0̅3̅2̅6̅9̅3̅4̅0̅4̅2̅9̅5̅7̅6̅1̅2̅6̅2̅1̅1̅7̅4̅6̅8̅1̅6̅1̅9̅4̅6̅3̅9̅8̅0̅2̅3̅1̅8̅9̅5̅0̅7̅6̅9̅8̅1̅5̅6̅2̅4̅4̅0̅6̅0̅0̅6̅4̅6̅2̅6̅4̅9̅6̅8̅6̅3̅7̅1̅4̅1̅2̅2̅7̅9̅0̅3̅4̅4̅0̅4̅1̅0̅5̅6̅8̅3̅3̅3̅0̅1̅6̅5̅3̅6̅7̅8̅0̅0̅7̅9̅8̅3̅2̅7̅3̅1̅4̅1̅9̅8̅8̅2̅1̅5̅1̅6̅8̅2̅1̅8̅9̅6̅9̅7̅7̅7̅6̅0̅8̅8̅1̅9̅6̅1̅6̅0̅4̅2̅5̅7̅7̅4̅5̅6̅7̅5̅7̅2̅7̅0̅4̅8̅0̅8̅9̅7̅1̅6̅7̅8̅3̅8̅8̅1̅3̅9̅1̅3̅7̅0̅4̅6̅1̅8̅8̅9̅3̅7̅4̅6̅4̅3̅6̅0̅3̅8̅7̅7̅5̅8̅9̅8̅1̅1̅8̅2̅2̅8̅4̅7̅3̅6̅7̅4̅2̅0̅6̅4̅2̅4̅6̅3̅4̅0̅9̅9̅9̅8̅0̅9̅9̅2̅2̅0̅6̅8̅0̅4̅7̅8̅9̅9̅6̅3̅8̅8̅5̅1̅9̅2̅9̅2̅9̅1̅0̅0̅9̅3̅1̅3̅8̅1̅8̅6̅6̅5̅6̅5̅2̅9̅1̅7̅6̅9̅6̅2̅5̅5̅4̅6̅4̅7̅4̅0̅5̅4̅3̅6̅2̅2̅8̅8̅5̅3̅8̅3̅0̅0̅7̅0̅3̅2̅8̅8̅3̅4̅8̅2̅2̅2̅7̅7̅1̅3̅3̅6̅2̅4̅7̅8̅6̅1̅6̅2̅3̅2̅6̅5̅5̅3̅8̅8̅7̅0̅9̅3̅7̅0̅8̅4̅2̅0̅4̅5̅2̅3̅8̅5̅4̅7̅8̅0̅4̅5̅9̅9̅8̅8̅5̅9̅5̅3̅2̅4̅0̅8̅2̅8̅7̅3̅9̅7̅8̅3̅3̅1̅1̅1̅5̅7̅5̅7̅4̅6̅0̅5̅5̅8̅8̅2̅9̅1̅1̅9̅9̅3̅9̅1̅7̅5̅0̅6̅1̅7̅7̅5̅3̅2̅7̅8̅8̅4̅4̅3̅2̅6̅1̅7̅3̅7̅3̅1̅2̅2̅9̅8̅0̅4̅2̅1̅9̅7̅3̅0̅0̅8̅9̅3̅3̅6̅6̅2̅8̅0̅1̅7̅4̅8̅7̅1̅6̅9̅7̅3̅9̅5̅9̅3̅2̅3̅3̅2̅2̅5̅6̅2̅2̅5̅0̅5̅2̅2̅7̅1̅4̅3̅1̅2̅8̅6̅8̅2̅7̅5̅9̅9̅3̅1̅5̅7̅1̅9̅4̅4̅4̅9̅7̅2̅4̅3̅8̅6̅9̅9̅8̅6̅6̅9̅4̅5̅4̅4̅7̅6̅3̅3̅5̅2̅9̅7̅4̅7̅1̅9̅6̅3̅5̅0̅5̅0̅3̅7̅0̅6̅5̅1̅9̅6̅7̅3̅0̅6̅5̅9̅5̅7̅0̅4̅2̅3̅8̅7̅3̅7̅8̅8̅2̅5̅3̅1̅8̅3̅8̅0̅5̅3̅6̅0̅1̅9̅7̅6̅8̅1̅0̅4̅9̅2̅3̅0̅1̅8̅4̅3̅7̅5̅5̅9̅3̅9̅9̅3̅5̅3̅7̅3̅5̅0̅3̅1̅3̅6̅2̅8̅5̅8̅7̅7̅2̅0̅9̅6̅5̅5̅9̅5̅8̅9̅4̅3̅1̅6̅6̅6̅9̅8̅3̅4̅6̅3̅2̅1̅9̅9̅2̅0̅1̅6̅7̅2̅6̅8̅5̅8̅0̅1̅1̅7̅8̅4̅8̅3̅1̅7̅8̅1̅0̅3̅0̅2̅2̅2̅3̅9̅1̅1̅8̅0̅3̅8̅3̅9̅5̅7̅4̅2̅2̅5̅4̅3̅2̅4̅2̅7̅2̅9̅5̅1̅9̅1̅0̅2̅8̅3̅2̅1̅6̅1̅1̅8̅6̅0̅8̅6̅2̅9̅5̅3̅8̅1̅1̅0̅6̅2̅5̅3̅5̅6̅3̅9̅6̅1̅2̅2̅4̅1̅0̅1̅8̅8̅1̅7̅7̅1̅5̅2̅6̅3̅2̅5̅7̅9̅3̅5̅7̅5̅3̅6̅5̅9

Nim

Translation of: Wren
Library: bignum
import strformat, strutils, tables
import bignum

proc divide(m, n: Int): tuple[repr: string; cycle: string; period: int] =
  doAssert m >= 0, "m must not be negative."
  doAssert n > 0, "n must be positive."
  
  var quotient = &"{m div n}."
  var c = m mod n * 10
  var zeros = 0
  while c > 0 and c < n:
    c *= 10
    quotient &= '0'
    inc zeros
  
  var digits = ""
  var passed: Table[string, int]
  var i = 0
  while true:
    let cs = $c
    if cs in passed:
      let idx = passed[cs]
      let prefix = digits[0..<idx]
      var cycle = digits[idx..^1]
      var repr = &"{quotient}{prefix}({cycle})"
      repr = repr.replace("(0)", "").strip(leading = false, trailing = true, {'.'})
      let index = repr.find('(')
      if index < 0: return (repr, "", 0)
      repr = repr.multiReplace(("(", ""), (")", ""))
      for _ in 1..zeros:
        if cycle[^1] == '0':
          repr.setLen(repr.len - 1)
          cycle = '0' & cycle[0..^2]
        else:
          break
      return (repr & "...", cycle, cycle.len)

    let q = c div n
    let r = c mod n
    passed[cs] = i
    digits &= $q
    inc i
    c = r * 10


const Tests = [("0", "1"), ("1", "1"), ("1", "3"), ("1", "7"),
               ("83","60"), ("1", "17"), ("10", "13"), ("3227", "555"),
               ("476837158203125", "9223372036854775808"), ("1", "149"), ("1", "5261")]

for test in Tests:
  let a = newInt(test[0])
  let b = newInt(test[1])
  let (repr, cycle, period) = divide(a, b)
  echo &"{a}/{b} = {repr}"
  echo &"Cycle is <{cycle}>"
  echo &"Period is {period}\n"
Output:
0/1 = 0
Cycle is <>
Period is 0

1/1 = 1
Cycle is <>
Period is 0

1/3 = 0.3...
Cycle is <3>
Period is 1

1/7 = 0.142857...
Cycle is <142857>
Period is 6

83/60 = 1.383...
Cycle is <3>
Period is 1

1/17 = 0.0588235294117647...
Cycle is <0588235294117647>
Period is 16

10/13 = 0.769230...
Cycle is <769230>
Period is 6

3227/555 = 5.8144...
Cycle is <144>
Period is 3

476837158203125/9223372036854775808 = 0.000051698788284564229679463043254372678347863256931304931640625
Cycle is <>
Period is 0

1/149 = 0.0067114093959731543624161073825503355704697986577181208053691275167785234899328859060402684563758389261744966442953020134228187919463087248322147651...
Cycle is <0067114093959731543624161073825503355704697986577181208053691275167785234899328859060402684563758389261744966442953020134228187919463087248322147651>
Period is 148

1/5261 = 0.00019007793195210036114807070899068618133434708230374453525945637711461699296711651777228663752138376734461129062915795476145219540011404675917126021668884242539441170880060824938224672115567382626877019578026991066337198251283026040676677437749477285687131724006842805550275613001330545523664702528036494962934803269340429576126211746816194639802318950769815624406006462649686371412279034404105683330165367800798327314198821516821896977760881961604257745675727048089716783881391370461889374643603877589811822847367420642463409998099220680478996388519292910093138186656529176962554647405436228853830070328834822277133624786162326553887093708420452385478045998859532408287397833111575746055882911993917506177532788443261737312298042197300893366280174871697395932332256225052271431286827599315719444972438699866945447633529747196350503706519673065957042387378825318380536019768104923018437559399353735031362858772096559589431666983463219920167268580117848317810302223911803839574225432427295191028321611860862953811062535639612241018817715263257935753659...
Cycle is <00019007793195210036114807070899068618133434708230374453525945637711461699296711651777228663752138376734461129062915795476145219540011404675917126021668884242539441170880060824938224672115567382626877019578026991066337198251283026040676677437749477285687131724006842805550275613001330545523664702528036494962934803269340429576126211746816194639802318950769815624406006462649686371412279034404105683330165367800798327314198821516821896977760881961604257745675727048089716783881391370461889374643603877589811822847367420642463409998099220680478996388519292910093138186656529176962554647405436228853830070328834822277133624786162326553887093708420452385478045998859532408287397833111575746055882911993917506177532788443261737312298042197300893366280174871697395932332256225052271431286827599315719444972438699866945447633529747196350503706519673065957042387378825318380536019768104923018437559399353735031362858772096559589431666983463219920167268580117848317810302223911803839574225432427295191028321611860862953811062535639612241018817715263257935753659>
Period is 1052

Pascal

Free Pascal

simple version.

PROGRAM Periode;
{$IFDEF FPC}  {$MODE Delphi} {$OPTIMIZATION ON,ALL} {$ENDIF}
{$IFDEF WINDOWS}{$Apptype Console}{$ENDIF}  
uses  
  sysutils;
 
const
  cTestVal : array[0..11] of LongInt = (2,5,3,7,13,17,60,149,555,625,5261,high(longInt));
  // don't try cBase= 7 for high(longInt) length of period=2147483647 -1   
  cBase = 10;
  cLen = 80;// 1 shl 14 is much faster for high(longInt) 2.9 s -> 2.0 s

var
  pS : pAnsiChar;
  s : array of AnsiString;
  idxS,
  idxP : integer;  

  function CheckMaxStartOfPeriod(dom:LongInt):longInt;
  var
    n : Int64;
    quot : longInt;
  Begin
    n := 1;
    result := 1;
    repeat
      n *=cbase;
      quot := n DIV dom;
      n -= dom*quot;    
      if (n = 0) OR (quot<>0) then
        BREAK;
      inc(result);  
    until false;
  end;
  
  procedure Xtend;
  begin
    idxS += 1;        
    setlength(s,idxS+1);
    setlength(s[idxS],cLen);    
    pS := @s[idxS][1];      
    idxP := 0;    
  end;
  
  procedure WritePeriod(nom:Int64;dom:LongInt);
  var
    remind  : Int64;
    quot,i : longInt;    
  begin
    write(nom,'/',dom);
    quot := 0;
    if nom > dom then
    Begin
      quot := nom DIV dom;
      nom := nom -quot*dom;
    end;
    setlength(s,1);
    idxS := 0; 
    s[idxS] := IntToStr(quot)+'.';  
    idxP := length(s[idxS]);  
    setlength(s[idxS],cLen);  
    pS := @s[idxS][1];
    i := CheckMaxStartOfPeriod(dom);
    write(' Max start idx after "." = ',i);
    while i > 0 do
    Begin
      nom *=cbase;
      quot := nom DIV dom;
      nom -= dom*quot;    
      pS[idxP] := chr(quot+Ord('0'));       
      inc(idxP);// always < cLen    
      dec(i);
      if (nom = 0)then
        BREAK;
    end;
    remind := nom;
    
    i := 0;
    while (nom<>0) do
    begin
      inc(i);
      nom *=cbase;
      quot := nom DIV dom;
      nom -= dom*quot;
      pS[idxP] := chr(quot+Ord('0'));       
      inc(idxP);    
      if idxP = cLen then
        Xtend;
      if (nom = remind) then
        BREAK;     
    end;
    if nom <> 0 then
      write('  length of period : ',i);     
    writeln;  
    setlength(s[idxS],idxP);
    if idxS > 0 then
    Begin
      writeln(s[0]);
      if idxS>1 then
      begin
        s[idxS-1] += s[idxS];
        s[idxS] := copy(s[idxS-1],length(s[idxS-1])-cLen+1,cLen);
        writeln('..');
      end;  
    end;  
    writeln(s[idxS]);    
   
    //delete
    for i := idxs downto 0 do
      setlength(s[i],0);
    setlength(s,0);  
  end;
  
var
  i : longint;  
BEGIN
  For i := Low(cTestVal) to High(cTestVal) do
  Begin
    WritePeriod(1,cTestVal[i]);
    writeln;
  end;  
END.
Output:
1/2 Max start idx after "." = 1
0.5

1/5 Max start idx after "." = 1
0.2

1/3 Max start idx after "." = 1  length of period : 1
0.33

1/7 Max start idx after "." = 1  length of period : 6
0.1428571

1/13 Max start idx after "." = 2  length of period : 6
0.07692307

1/17 Max start idx after "." = 2  length of period : 16
0.058823529411764705

1/60 Max start idx after "." = 2  length of period : 1
0.016

1/149 Max start idx after "." = 3  length of period : 148
0.006711409395973154362416107382550335570469798657718120805369127516778523489932
8859060402684563758389261744966442953020134228187919463087248322147651006

1/555 Max start idx after "." = 3  length of period : 3
0.001801

1/625 Max start idx after "." = 3
0.0016

1/5261 Max start idx after "." = 4  length of period : 1052
0.000190077931952100361148070708990686181334347082303744535259456377114616992967
..
42254324272951910283216118608629538110625356396122410188177152632579357536590001

1/2147483647 Max start idx after "." = 10  length of period : 195225786
0.000000000465661287524579692410575082716799845321476387475373403856239003993682
..
89889934747428602887051460746234031741616330920539950449271104507740170000000004
real	0m2,916s

alternative using Euler Phi

copy and paste of version from 2012 modified of 2002 ...

PROGRAM Periode;
//https://entwickler-ecke.de/viewtopic.php?t=108866
//checking lenght and start period of 1/value 
//using Euler Phi
{$IFDEF FPC}
  {$MODE Delphi}
  {$OPTIMIZATION ON,ALL}
{$else}
  {$Apptype Console}
{$ENDIF}  
uses  
  sysutils;
  
const
  cTestVal : array[0..11] of LongInt = (2,5,3,7,13,17,60,149,555,625,5261,High(longint));
  cBase = 10;
  PRIMFELDOBERGRENZE = 6542; 
  {Das sind alle Primzahlen bis 2^16}
  {Das reicht fuer alle Primzahlen bis 2^32}
type
   tPrimFeld = array [1..PRIMFELDOBERGRENZE] of Word;
   tFaktorPotenz = record
                     Faktor,
                     Potenz  : DWord;
                   end;
   //2*3*5*7*11*13*17*19*23  *29 > DWord also maximal 9 Faktoren
   tFaktorFeld =  array [1..9] of TFaktorPotenz;//DWord                           
// tFaktorFeld =  array [1..15] of TFaktorPotenz;//QWord
   tFaktorisieren = class(TObject)
                      private
                        fFakZahl   : DWord;
                        fNominator : DWord; 
                        fFakBasis  : DWord;
                        fFakAnzahl : Dword;
                        fAnzahlMoeglicherTeiler : Dword;
                        fEulerPhi  : DWORD;
                        fStartPeriode : DWORD;
                        fPeriodenLaenge  : DWORD;
                        fTeiler    : array of DWord;
                        fFaktoren  : tFaktorFeld;
                        fBasFakt   : tFaktorFeld;
                        fPrimfeld  : tPrimFeld;

                        procedure PrimFeldAufbauen;
                        procedure Fakteinfuegen(var Zahl:Dword;inFak:Dword);
                        function  BasisPeriodeExtrahieren(var inZahl:Dword):DWord;
                        procedure NachkommaPeriode(var OutText: String);
                      public 
                        constructor create; overload;       
                        function  Prim(inZahl:Dword):Boolean;        
                        procedure AusgabeFaktorfeld(n : DWord);
                        procedure Faktorisierung (inZahl: DWord);
                        procedure TeilerErmitteln; 
                        procedure PeriodeErmitteln(inZahl:Dword);
                        function BasExpMod( b, e, m : Dword) : DWord; 
                                               
                     property 
                        EulerPhi : Dword read fEulerPhi;
                     property    
                        PeriodenLaenge: DWord read fPeriodenLaenge ;
                     property    
                        StartPeriode: DWord read fStartPeriode ;
                    end;  
                    
constructor tFaktorisieren.create;
begin  
  inherited;
  PrimFeldAufbauen;
  
  fFakZahl  := 0;  
  fNominator := 1;
  fFakBasis := cBase;
  Faktorisierung(fFakBasis);
  fBasFakt := fFaktoren;  

  fFakZahl := 0;  
  fEulerPhi := 1;
  fPeriodenLaenge :=0;
  fFakZahl := 0;  
  fFakAnzahl := 0;
  fAnzahlMoeglicherTeiler := 0;
end;

function tFaktorisieren.Prim(inZahl:Dword):Boolean;
{Testet auf PrimZahl}
var
  Wurzel,
  pos       : Dword;
Begin
  if fFakZahl = inZahl then
    begin
    result := (fAnzahlMoeglicherTeiler = 2);
    exit;
    end;
  result := false;  
  if inZahl >1 then
    begin
    result := true;    
    Pos := 1;  
    Wurzel:= trunc(sqrt(inZahl));
    While fPrimFeld[Pos] <= Wurzel do
      begin
      if (inZahl mod fPrimFeld[Pos])=0 then
        begin
        result := false;
        break;
        end;
      inc(Pos);
      IF Pos > High(fPrimFeld) then
        break;
      end;
    end;  
end;

Procedure tFaktorisieren.PrimFeldAufbauen;
{genearating list of primes}
const
  MAX = 65536;
var
  TestaufPrim,
  Zaehler,delta : Dword;
  
begin
Zaehler := 1;
fPrimFeld[Zaehler] := 2;
inc(Zaehler);
fPrimFeld[Zaehler] := 3;

delta := 2;
TestAufPrim:=5;
repeat
  if prim(TestAufPrim) then
    begin
    inc(Zaehler);
    fPrimFeld[Zaehler] := TestAufPrim;
    end;
  inc(TestAufPrim,delta);
  delta := 6-delta; // 2,4,2,4,2,4,2,
until (TestAufPrim>=MAX);

end; {PrimfeldAufbauen}

procedure tFaktorisieren.Fakteinfuegen(var Zahl:Dword;inFak:Dword);
var
  i : DWord;
begin
  inc(fFakAnzahl);
  with fFaktoren[fFakAnzahl] do
    begin
      fEulerPhi := fEulerPhi*(inFak-1);
    Faktor :=inFak;
    Potenz := 0;
    while (Zahl mod inFak) = 0 do
      begin
      Zahl := Zahl div inFak;
      inc(Potenz);
      end;
    For i := 2 to Potenz do
      fEulerPhi := fEulerPhi*inFak;
    end;
  fAnzahlMoeglicherTeiler:=fAnzahlMoeglicherTeiler*(1+fFaktoren[fFakAnzahl].Potenz);
end;

procedure tFaktorisieren.Faktorisierung (inZahl: DWord);
var
  j,
  og : longint;
begin
if fFakZahl = inZahl then
  exit;
  
fPeriodenLaenge := 0;  
fFakZahl   := inZahl;
fEulerPhi  := 1;
fFakAnzahl := 0;
fAnzahlMoeglicherTeiler :=1;
setlength(fTeiler,0);

If inZahl < 2 then
  exit;
og := round(sqrt(inZahl)+1.0);
{Suche Teiler von inZahl}
for j := 1 to High(fPrimfeld) do
  begin
  If fPrimfeld[j]> OG then
    Break;
  if (inZahl mod fPrimfeld[j])= 0 then
    Fakteinfuegen(inZahl,fPrimfeld[j]);
  end;
If inZahl>1 then
  Fakteinfuegen(inZahl,inZahl);
TeilerErmitteln;
end; {Faktorisierung}
  
procedure tFaktorisieren.AusgabeFaktorfeld(n : DWord);
var
  i :integer;
begin
  if fFakZahl <> n then
    Faktorisierung(n);
  write(fAnzahlMoeglicherTeiler:5,' Faktoren ');      

  For i := 1 to fFakAnzahl-1 do
    with fFaktoren[i] do
      IF potenz >1 then
        write(Faktor,'^',Potenz,'*')
      else
        write(Faktor,'*');
  with fFaktoren[fFakAnzahl] do
    IF potenz >1 then
      write(Faktor,'^',Potenz)
    else
      write(Faktor);
  writeln('  Euler Phi: ',fEulerPhi:12,PeriodenLaenge:12);      
end;

procedure tFaktorisieren.TeilerErmitteln;
var
  Position : DWord;
  i,j : DWord;
  procedure FaktorAufbauen(Faktor: DWord;n: DWord);
  var
    i,
    Pot : DWord;
  begin
    Pot := 1;  
    i := 0;
    repeat
      IF n > Low(fFaktoren) then
        FaktorAufbauen(Pot*Faktor,n-1)
      else  
        begin
        FTeiler[Position] := Pot*Faktor;
        inc(Position);
        end;
      Pot := Pot*fFaktoren[n].Faktor;   
      inc(i);
    until  i > fFaktoren[n].Potenz;
  end;
  
begin
  Position:= 0;
  setlength(FTeiler,fAnzahlMoeglicherTeiler);
  FaktorAufbauen(1,fFakAnzahl);
  //Sortieren
  For i := Low(fTeiler) to fAnzahlMoeglicherTeiler-2 do
    begin
    j := i;
    while (j>=Low(fTeiler)) AND (fTeiler[j]>fTeiler[j+1]) do
      begin
      Position := fTeiler[j];
      fTeiler[j] := fTeiler[j+1];
      fTeiler[j+1]:= Position;    
      dec(j);
      end;
    end;
end;

function tFaktorisieren.BasisPeriodeExtrahieren(var inZahl:Dword):DWord;
var
 i,cnt,
 Teiler: Dword;
begin
  cnt := 0;
  result := 0;
  For i := Low(fBasFakt) to High(fBasFakt) do
    begin
    with fBasFakt[i] do 
      begin
      IF Faktor = 0 then
        BREAK;
      Teiler := Faktor;
      For cnt := 2 to Potenz do
        Teiler := Teiler*Faktor;
      end;   
    cnt := 0;  
    while (inZahl<> 0) AND (inZahl mod Teiler = 0) do 
      begin
      inZahl := inZahl div Teiler;
      inc(cnt);
      end;
    IF cnt > result then
      result := cnt;
    end;
end;

procedure tFaktorisieren.PeriodeErmitteln(inZahl:Dword);
var
  i,
  TempZahl,
  TempPhi,
  TempPer,
  TempBasPer: DWord;
begin
  Faktorisierung(inZahl);
  TempZahl := inZahl;
  //Die Basis_Nicht_Periode ermitteln
  TempBasPer := BasisPeriodeExtrahieren(TempZahl);
  TempPer := 0;
  IF TempZahl >1 then
    begin
    Faktorisierung(TempZahl);
    TempPhi := fEulerPhi;
    IF (TempPhi > 1) then
      begin
      Faktorisierung(TempPhi);
      i := 0;
      repeat
        TempPer := fTeiler[i];
        IF BasExpMod(fFakBasis,TempPer,TempZahl)= 1 then
          Break;
        inc(i);
      until i >= Length(fTeiler);
      IF i >= Length(fTeiler) then
        TempPer := inZahl-1;
      end;
    end;

  Faktorisierung(inZahl);
  fPeriodenlaenge := TempPer;
  fStartPeriode   := TempBasPer;  
end;

procedure tFaktorisieren.NachkommaPeriode(var OutText: String);
var
  Rest,
  Rest1,
  Divi,
  base: Int64;
  i,
  limit : integer;
  
  pText : pChar;
  
  procedure Ziffernfolge(Ende: longint);
  //generate the digits in Base 
  var 
    j : longint;
  begin
    j := i-Ende;
    
    while j < 0 do
      begin
      Rest := Rest *base;      
      Rest1:= Rest Div Divi;
      Rest := Rest-Rest1*Divi;//== Rest1 Mod Divi     
    
      pText^ := chr(Rest1+Ord('0'));
      inc(pText);

      inc(j);
	  end;
	
	i := Ende;
  end;
  
begin
  limit:= fStartPeriode+fPeriodenlaenge;
  
  setlength(OutText,limit+2+2+5);
  OutText[1]:='0';
  OutText[2]:='.';
  pText := @OutText[3];

  Rest := fNominator;//1;
  Divi := fFakZahl; 
  base := fFakBasis;
  
  i := 0;
  Ziffernfolge(fStartPeriode);
  if fPeriodenlaenge = 0 then 
  begin
    setlength(OutText,fStartPeriode+2);
    EXIT;
  end;

  pText^ := '_'; inc(pText);
  Ziffernfolge(limit);
  pText^ := '_'; inc(pText);

  Ziffernfolge(limit+5);
end;  

type 
   tZahl   = integer;
   tRestFeld = array[0..31] of integer;

VAR
    F : tFaktorisieren;
  
function tFaktorisieren.BasExpMod( b, e, m : Dword) : DWord; 
begin 
  Result := 1; 
  IF m = 0 then
    exit;
  Result := 1; 
  while ( e > 0 ) do 
    begin 
    if (e AND 1) <> 0 then 
      Result :=  (Result * int64(b)) mod m; 
    b := (int64(b) * b ) mod m; 
    e := e shr 1; 
    end; 
end;

procedure start;
VAR
  i,
  Divisor : DWord;
  Zeile : AnsiString;
  t1,t0: TDateTime;
BEGIN
  t0 := time;
  writeln('Calculate the length of period of 1/value');
  write('     value  start of   length of period     ');
  For i := low(cTestVal) to High(cTestVal) do
  begin
    writeln;
    Divisor := cTestVal[i];
    F.PeriodeErmitteln(Divisor);
	write(Divisor:10);  
	if F.PeriodenLaenge > 0 then
      write(F.StartPeriode:10,F.PeriodenLaenge:12)
    else
      write(F.StartPeriode:10,'--':12); 
    //only create small strings   
    IF F.PeriodenLaenge < 1053 then
    begin
      F.NachkommaPeriode(Zeile);    
      write('  ',Zeile);
    end;  
    Zeile :='';
  end;
  t1 := time;
  writeln;
  writeln(FormatDateTime('HH:NN:SS.ZZZ',T1-T0),' time taken');
END;

BEGIN
  F := tFaktorisieren.create;
  start;
  writeln('Done');
  F.free;  
  {$IFDEF WINDOWS}
  readln;
  {$ENDIF}
end.
Output:

Calculate the length of period of 1/value
     value  start of   length of period     
         2         1          --  0.5
         5         1          --  0.2
         3         0           1  0._3_33333
         7         0           6  0._142857_14285
        13         0           6  0._076923_07692
        17         0          16  0._0588235294117647_05882
        60         2           1  0.01_6_66666
       149         0         148  0._0067114093959731543624161073825503355704697986577181208053691275167785234899328859060402684563758389261744966442953020134228187919463087248322147651_00671
       555         1           3  0.0_018_01801
       625         4          --  0.0016
      5261         0        1052  0._00019007793195210036114807070899068618133434708230374453525945637711461699296711651777228663752138376734461129062915795476145219540011404675917126021668884242539441170880060824938224672115567382626877019578026991066337198251283026040676677437749477285687131724006842805550275613001330545523664702528036494962934803269340429576126211746816194639802318950769815624406006462649686371412279034404105683330165367800798327314198821516821896977760881961604257745675727048089716783881391370461889374643603877589811822847367420642463409998099220680478996388519292910093138186656529176962554647405436228853830070328834822277133624786162326553887093708420452385478045998859532408287397833111575746055882911993917506177532788443261737312298042197300893366280174871697395932332256225052271431286827599315719444972438699866945447633529747196350503706519673065957042387378825318380536019768104923018437559399353735031362858772096559589431666983463219920167268580117848317810302223911803839574225432427295191028321611860862953811062535639612241018817715263257935753659_00019
2147483647         0   195225786
00:00:00.000 time taken
Done

Perl

use strict;
use warnings;
use utf8;
binmode(STDOUT, ':utf8');

sub long_division {
    my($n, $d) = @_;
    my %seen;

    my($numerator,$denominator) = (abs $n, abs $d);
    my $negative = ($n < 0 xor $d < 0) ? '-' : '';

    my $fraction = sprintf '%d.', $numerator / $denominator;
    my $position = length $fraction;
    $numerator %= $denominator;
    while (!$seen{$numerator}) {
        return 0, $fraction =~ s/\.$//r unless $numerator;
        $seen{$numerator} = $position;
        $fraction  .= int 10 * $numerator / $denominator;
        $numerator  =     10 * $numerator % $denominator;
        $position++;
    }

    my $period = length($fraction) - $seen{$numerator};
    substr($fraction, $seen{$numerator}+(2*$_)+1, 0, "\N{COMBINING OVERLINE}") for 0 .. $period-1;
    $period, $negative . $fraction
}

printf "%10s Period is %5d : %s\n", $_, long_division split '/' 
    for <0/1 1/1 1/5 1/3 -1/3 1/7 -83/60 1/17 10/13 3227/555 1/149>
Output:
                                0/1 Period is     0 : 0
                                1/1 Period is     0 : 1
                                1/5 Period is     0 : 0.2
                                1/3 Period is     1 : 0.3̅
                               -1/3 Period is     1 : -0.3̅
                                1/7 Period is     6 : 0.1̅4̅2̅8̅5̅7̅
                             -83/60 Period is     1 : -1.383̅
                               1/17 Period is    16 : 0.0̅5̅8̅8̅2̅3̅5̅2̅9̅4̅1̅1̅7̅6̅4̅7̅
                              10/13 Period is     6 : 0.7̅6̅9̅2̅3̅0̅
                           3227/555 Period is     3 : 5.81̅4̅4̅
476837158203125/9223372036854775808 Period is     0 : 0.0000516987882845642321427703791414387524127960205078125
                              1/149 Period is   148 : 0.0̅0̅6̅7̅1̅1̅4̅0̅9̅3̅9̅5̅9̅7̅3̅1̅5̅4̅3̅6̅2̅4̅1̅6̅1̅0̅7̅3̅8̅2̅5̅5̅0̅3̅3̅5̅5̅7̅0̅4̅6̅9̅7̅9̅8̅6̅5̅7̅7̅1̅8̅1̅2̅0̅8̅0̅5̅3̅6̅9̅1̅2̅7̅5̅1̅6̅7̅7̅8̅5̅2̅3̅4̅8̅9̅9̅3̅2̅8̅8̅5̅9̅0̅6̅0̅4̅0̅2̅6̅8̅4̅5̅6̅3̅7̅5̅8̅3̅8̅9̅2̅6̅1̅7̅4̅4̅9̅6̅6̅4̅4̅2̅9̅5̅3̅0̅2̅0̅1̅3̅4̅2̅2̅8̅1̅8̅7̅9̅1̅9̅4̅6̅3̅0̅8̅7̅2̅4̅8̅3̅2̅2̅1̅4̅7̅6̅5̅1̅

Phix

Translation of the Python code linked to by the Wren entry, modified to cope with negatives.

with javascript_semantics
procedure test(sequence s)
    atom {n,d} = s,
         {numr,denr} = {abs(n),abs(d)},
         c = 10*remainder(numr,denr)
    string sgn = iff(sign(n)*sign(d)=-1?"-":""),
           q = sprintf("%s%d.",{sgn,floor(numr/denr)}),
           digits = ""
    while c and c<denr do
        c *= 10
        q &= '0'
    end while
    integer passed = new_dict()
    while getd_index(c,passed)=NULL do
        integer digit = floor(c/denr)
        assert(digit>=0 and digit<=9)
        digits &= '0'+digit
        setd(c,length(digits),passed)
        c = 10*remainder(c,denr)
    end while
    integer pc = getd(c,passed)
    destroy_dict(passed)
    q &= digits[1..pc-1]
    digits = digits[pc..$]
    if digits="0" then
        q = trim_tail(q,'.')
    else        
        while digits[$] = q[$] do
            {digits,q} = {q[$]&digits[1..$-1],q[1..$-1]}
        end while
        integer ld = length(digits)
        if ld>20 then digits[11..-11] = "..." end if
        q = sprintf("%s{%s} (period %d)",{q,digits,ld})
    end if
    string nod = sprintf("%d/%d",{n,d})
    printf(1,"%40s = %s\n",{nod,q})
end procedure

constant tests = {{0,1},{1,1},{1,3},{-1,3},{1,-3},{-1,-3},{-17,2},{177,16},
                  {1,7},{-83,60},{1,17},{10,13},{3227,555},{1,149},{1,5261},
                  {476837158203125,9223372036854775808}}[1..$-(machine_bits()=32)]
papply(tests,test)
Output:

The results below are on 64 bit, not surprisingly the last example is inaccurate past 16 significant digits on 32 bit (ditto p2js), and hence omitted.

                                     0/1 = 0
                                     1/1 = 1
                                     1/3 = 0.{3} (period 1)
                                    -1/3 = -0.{3} (period 1)
                                    1/-3 = -0.{3} (period 1)
                                   -1/-3 = 0.{3} (period 1)
                                   -17/2 = -8.5
                                  177/16 = 11.0625
                                     1/7 = 0.{142857} (period 6)
                                  -83/60 = -1.38{3} (period 1)
                                    1/17 = 0.{0588235294117647} (period 16)
                                   10/13 = 0.{769230} (period 6)
                                3227/555 = 5.8{144} (period 3)
                                   1/149 = 0.{0067114093...8322147651} (period 148)
                                  1/5261 = 0.{0001900779...7935753659} (period 1052)
     476837158203125/9223372036854775808 = 0.000051698788284564229679463043254372678347863256931304931640625

Raku

It's a built-in.

for 0/1, 1/1, 1/3, 1/7, -83/60, 1/17, 10/13, 3227/555, 5**21/2**63, 1/149, 1/5261 -> $rat {
    printf "%35s - Period is %-5s: %s%s\n", $rat.nude.join('/'), .[1].chars, .[0], (.[1].comb Z~ "\c[COMBINING OVERLINE]" xx *).join
        given $rat.base-repeating
}
Output:
                                0/1 - Period is 0    : 0
                                1/1 - Period is 0    : 1
                                1/3 - Period is 1    : 0.3̅
                                1/7 - Period is 6    : 0.1̅4̅2̅8̅5̅7̅
                             -83/60 - Period is 1    : -1.383̅
                               1/17 - Period is 16   : 0.0̅5̅8̅8̅2̅3̅5̅2̅9̅4̅1̅1̅7̅6̅4̅7̅
                              10/13 - Period is 6    : 0.7̅6̅9̅2̅3̅0̅
                           3227/555 - Period is 3    : 5.81̅4̅4̅
476837158203125/9223372036854775808 - Period is 0    : 0.000051698788284564229679463043254372678347863256931304931640625
                              1/149 - Period is 148  : 0.0̅0̅6̅7̅1̅1̅4̅0̅9̅3̅9̅5̅9̅7̅3̅1̅5̅4̅3̅6̅2̅4̅1̅6̅1̅0̅7̅3̅8̅2̅5̅5̅0̅3̅3̅5̅5̅7̅0̅4̅6̅9̅7̅9̅8̅6̅5̅7̅7̅1̅8̅1̅2̅0̅8̅0̅5̅3̅6̅9̅1̅2̅7̅5̅1̅6̅7̅7̅8̅5̅2̅3̅4̅8̅9̅9̅3̅2̅8̅8̅5̅9̅0̅6̅0̅4̅0̅2̅6̅8̅4̅5̅6̅3̅7̅5̅8̅3̅8̅9̅2̅6̅1̅7̅4̅4̅9̅6̅6̅4̅4̅2̅9̅5̅3̅0̅2̅0̅1̅3̅4̅2̅2̅8̅1̅8̅7̅9̅1̅9̅4̅6̅3̅0̅8̅7̅2̅4̅8̅3̅2̅2̅1̅4̅7̅6̅5̅1̅
                             1/5261 - Period is 1052 : 0.0̅0̅0̅1̅9̅0̅0̅7̅7̅9̅3̅1̅9̅5̅2̅1̅0̅0̅3̅6̅1̅1̅4̅8̅0̅7̅0̅7̅0̅8̅9̅9̅0̅6̅8̅6̅1̅8̅1̅3̅3̅4̅3̅4̅7̅0̅8̅2̅3̅0̅3̅7̅4̅4̅5̅3̅5̅2̅5̅9̅4̅5̅6̅3̅7̅7̅1̅1̅4̅6̅1̅6̅9̅9̅2̅9̅6̅7̅1̅1̅6̅5̅1̅7̅7̅7̅2̅2̅8̅6̅6̅3̅7̅5̅2̅1̅3̅8̅3̅7̅6̅7̅3̅4̅4̅6̅1̅1̅2̅9̅0̅6̅2̅9̅1̅5̅7̅9̅5̅4̅7̅6̅1̅4̅5̅2̅1̅9̅5̅4̅0̅0̅1̅1̅4̅0̅4̅6̅7̅5̅9̅1̅7̅1̅2̅6̅0̅2̅1̅6̅6̅8̅8̅8̅4̅2̅4̅2̅5̅3̅9̅4̅4̅1̅1̅7̅0̅8̅8̅0̅0̅6̅0̅8̅2̅4̅9̅3̅8̅2̅2̅4̅6̅7̅2̅1̅1̅5̅5̅6̅7̅3̅8̅2̅6̅2̅6̅8̅7̅7̅0̅1̅9̅5̅7̅8̅0̅2̅6̅9̅9̅1̅0̅6̅6̅3̅3̅7̅1̅9̅8̅2̅5̅1̅2̅8̅3̅0̅2̅6̅0̅4̅0̅6̅7̅6̅6̅7̅7̅4̅3̅7̅7̅4̅9̅4̅7̅7̅2̅8̅5̅6̅8̅7̅1̅3̅1̅7̅2̅4̅0̅0̅6̅8̅4̅2̅8̅0̅5̅5̅5̅0̅2̅7̅5̅6̅1̅3̅0̅0̅1̅3̅3̅0̅5̅4̅5̅5̅2̅3̅6̅6̅4̅7̅0̅2̅5̅2̅8̅0̅3̅6̅4̅9̅4̅9̅6̅2̅9̅3̅4̅8̅0̅3̅2̅6̅9̅3̅4̅0̅4̅2̅9̅5̅7̅6̅1̅2̅6̅2̅1̅1̅7̅4̅6̅8̅1̅6̅1̅9̅4̅6̅3̅9̅8̅0̅2̅3̅1̅8̅9̅5̅0̅7̅6̅9̅8̅1̅5̅6̅2̅4̅4̅0̅6̅0̅0̅6̅4̅6̅2̅6̅4̅9̅6̅8̅6̅3̅7̅1̅4̅1̅2̅2̅7̅9̅0̅3̅4̅4̅0̅4̅1̅0̅5̅6̅8̅3̅3̅3̅0̅1̅6̅5̅3̅6̅7̅8̅0̅0̅7̅9̅8̅3̅2̅7̅3̅1̅4̅1̅9̅8̅8̅2̅1̅5̅1̅6̅8̅2̅1̅8̅9̅6̅9̅7̅7̅7̅6̅0̅8̅8̅1̅9̅6̅1̅6̅0̅4̅2̅5̅7̅7̅4̅5̅6̅7̅5̅7̅2̅7̅0̅4̅8̅0̅8̅9̅7̅1̅6̅7̅8̅3̅8̅8̅1̅3̅9̅1̅3̅7̅0̅4̅6̅1̅8̅8̅9̅3̅7̅4̅6̅4̅3̅6̅0̅3̅8̅7̅7̅5̅8̅9̅8̅1̅1̅8̅2̅2̅8̅4̅7̅3̅6̅7̅4̅2̅0̅6̅4̅2̅4̅6̅3̅4̅0̅9̅9̅9̅8̅0̅9̅9̅2̅2̅0̅6̅8̅0̅4̅7̅8̅9̅9̅6̅3̅8̅8̅5̅1̅9̅2̅9̅2̅9̅1̅0̅0̅9̅3̅1̅3̅8̅1̅8̅6̅6̅5̅6̅5̅2̅9̅1̅7̅6̅9̅6̅2̅5̅5̅4̅6̅4̅7̅4̅0̅5̅4̅3̅6̅2̅2̅8̅8̅5̅3̅8̅3̅0̅0̅7̅0̅3̅2̅8̅8̅3̅4̅8̅2̅2̅2̅7̅7̅1̅3̅3̅6̅2̅4̅7̅8̅6̅1̅6̅2̅3̅2̅6̅5̅5̅3̅8̅8̅7̅0̅9̅3̅7̅0̅8̅4̅2̅0̅4̅5̅2̅3̅8̅5̅4̅7̅8̅0̅4̅5̅9̅9̅8̅8̅5̅9̅5̅3̅2̅4̅0̅8̅2̅8̅7̅3̅9̅7̅8̅3̅3̅1̅1̅1̅5̅7̅5̅7̅4̅6̅0̅5̅5̅8̅8̅2̅9̅1̅1̅9̅9̅3̅9̅1̅7̅5̅0̅6̅1̅7̅7̅5̅3̅2̅7̅8̅8̅4̅4̅3̅2̅6̅1̅7̅3̅7̅3̅1̅2̅2̅9̅8̅0̅4̅2̅1̅9̅7̅3̅0̅0̅8̅9̅3̅3̅6̅6̅2̅8̅0̅1̅7̅4̅8̅7̅1̅6̅9̅7̅3̅9̅5̅9̅3̅2̅3̅3̅2̅2̅5̅6̅2̅2̅5̅0̅5̅2̅2̅7̅1̅4̅3̅1̅2̅8̅6̅8̅2̅7̅5̅9̅9̅3̅1̅5̅7̅1̅9̅4̅4̅4̅9̅7̅2̅4̅3̅8̅6̅9̅9̅8̅6̅6̅9̅4̅5̅4̅4̅7̅6̅3̅3̅5̅2̅9̅7̅4̅7̅1̅9̅6̅3̅5̅0̅5̅0̅3̅7̅0̅6̅5̅1̅9̅6̅7̅3̅0̅6̅5̅9̅5̅7̅0̅4̅2̅3̅8̅7̅3̅7̅8̅8̅2̅5̅3̅1̅8̅3̅8̅0̅5̅3̅6̅0̅1̅9̅7̅6̅8̅1̅0̅4̅9̅2̅3̅0̅1̅8̅4̅3̅7̅5̅5̅9̅3̅9̅9̅3̅5̅3̅7̅3̅5̅0̅3̅1̅3̅6̅2̅8̅5̅8̅7̅7̅2̅0̅9̅6̅5̅5̅9̅5̅8̅9̅4̅3̅1̅6̅6̅6̅9̅8̅3̅4̅6̅3̅2̅1̅9̅9̅2̅0̅1̅6̅7̅2̅6̅8̅5̅8̅0̅1̅1̅7̅8̅4̅8̅3̅1̅7̅8̅1̅0̅3̅0̅2̅2̅2̅3̅9̅1̅1̅8̅0̅3̅8̅3̅9̅5̅7̅4̅2̅2̅5̅4̅3̅2̅4̅2̅7̅2̅9̅5̅1̅9̅1̅0̅2̅8̅3̅2̅1̅6̅1̅1̅8̅6̅0̅8̅6̅2̅9̅5̅3̅8̅1̅1̅0̅6̅2̅5̅3̅5̅6̅3̅9̅6̅1̅2̅2̅4̅1̅0̅1̅8̅8̅1̅7̅7̅1̅5̅2̅6̅3̅2̅5̅7̅9̅3̅5̅7̅5̅3̅6̅5̅9̅

RPL

Works with: HP version 48
Translation of: Nim
« DUP2 / 
  IF DUP FP THEN
     IP "." +  ROT ROT   @ HP49+: add R→I after IP
     ABS SWAP ABS OVER MOD 10 * { }
     → quotient n c passed
     « ""
       WHILE c DUP n < AND REPEAT
          10 'c' STO*
          'quotient' "0" STO+
       END
       WHILE passed c POS NOT REPEAT
          'passed' c STO+
           c n / IP +   @ HP49+: replace / IP by IQUOT
           c n MOD 10 * 'c' STO
       END
       passed c POS DUP2 1 SWAP 1 - SUB 
       quotient SWAP + ROT ROT 
       OVER SIZE SUB
       IF DUP "0" == THEN DROP "" END
     »
  ELSE →STR ROT ROT DROP2 "" END
» 'LDIV' STO      @ ( m n → "quotient.prefix" "repetend" ) 

« DUP2 "/" SWAP + + " = " + ROT ROT
  LDIV 
  IF DUP SIZE THEN ")" + SWAP "(" + SWAP + ELSE DROP END
  +
» 'VUDIV' STO     @ @ ( m n → "m/n = quotient.prefix(repetend)" ) 
-3227 555 VUDIV
355 113 VUDIV
Output:
 
2: "-3227/555 = -5.8(144)"
1: 355/113 = 3.(1415929203539823008849557522123893805309734513274336283185840707964601769911504424778761061946902654867256637168)

V (Vlang)

Translation of: wren
import math.big

const big_ten = big.integer_from_int(10)

fn divide(m big.Integer, n big.Integer) ?[]string {
    if m < big.zero_int {
        return error('m must not be negative')
    }
    if n <= big.zero_int {
        return error('n must be positive')
    }
    mut quotient := '${(m/n)}.'
    mut c := (m % n) * big_ten
    mut zeros := 0
    for c > big.zero_int && c < n {
        c = c * big_ten
        quotient = quotient + "0"
        zeros ++
    }
    mut digits := ""
    mut passed := map[string]int{}//string:int
    mut i := 0
    for {
        mut cs := c.str()
        if cs in passed {
            prefix := digits[0..passed[cs]]
            mut repetend := digits[passed[cs]..digits.len]
            mut result := '$quotient${prefix}(${repetend})'
            result = result.replace("(0)", "").trim_right(".")
            index := result.index("(") or {-1}
            if index == -1 {
                return [result, "", '0']
            }
            result = result.replace("(", "").replace(")", "")
            for _ in 0..zeros {
                if repetend[repetend.len-1] == 0 {
                    result = result[0..result.len-1]
                    repetend = "0" + repetend[0..result.len-1]
                } else {
                    break
                }
            }
            return [result + "....", repetend, repetend.len.str()]
        }
        q := c / n
        r := c % n
        passed[cs] = i
        digits += q.str()
        i++
        c = r * big_ten
    }
    return ['FAIL','','']
}

fn main(){
    for test in [[0, 1], [1, 1], [1, 3], [1, 7], [83,60], [1, 17], [10, 13], [3227, 555],
    [476837158203125, 9223372036854775808], [1, 149], [1, 5261]] {
        a := big.integer_from_i64(test[0])
        b := big.integer_from_i64(test[1])
        res := divide(a,b) or {['Need positive numbers','','']}
        println('$a/$b = ${res[0]}')
        println("repetend is '${res[1]}'")
        println('period is ${res[2]}\n')
    }
}
Output:
Similar as wren entry

Wren

This is based on the Python code here.

import "./big" for BigInt

var divide = Fn.new { |m, n|
    if (m < 0) Fiber.abort("m must not be negative")
    if (n <= 0) Fiber.abort("n must be positive.")
    var quotient = (m/n).toString + "."
    var c = (m % n) * 10
    var zeros = 0
    while (c > 0 && c < n) {
        c = c * 10
        quotient = quotient + "0"
        zeros = zeros + 1
    }
    var digits = ""
    var passed = {}
    var i = 0
    while (true) {
        var cs = c.toString
        if (passed.containsKey(cs)) {
            var prefix = digits[0...passed[cs]]
            var repetend = digits[passed[cs]..-1]
            var result = quotient + prefix + "(" + repetend + ")"
            result = result.replace("(0)", "").trimEnd(".")
            var index = result.indexOf("(")
            if (index == -1) return [result, "", 0]
            result = result.replace("(", "").replace(")", "")
            for (i in 0...zeros) {
                if (repetend[-1] == "0") {
                    result = result[0..-2]
                    repetend = "0" + repetend[0..-2]
                } else break
            }
            return [result + "....", repetend, repetend.count]
        }
        var q = c / n
        var r = c % n
        passed[cs] = i
        digits = digits + q.toString
        i = i + 1
        c = r * 10
    }
}

var tests = [
    [0, 1], [1, 1], [1, 3], [1, 7], [83,60], [1, 17], [10, 13], [3227, 555],
    [476837158203125, "9223372036854775808"], [1, 149], [1, 5261]
]
for (test in tests) {
    var a = BigInt.new(test[0])
    var b = BigInt.new(test[1])
    var res = divide.call(a, b)
    System.print("%(a)/%(b) = %(res[0])")
    System.print("Repetend is '%(res[1])'")
    System.print("Period is %(res[2])\n")
}
Output:
0/1 = 0
Repetend is ''
Period is 0

1/1 = 1
Repetend is ''
Period is 0

1/3 = 0.3....
Repetend is '3'
Period is 1

1/7 = 0.142857....
Repetend is '142857'
Period is 6

83/60 = 1.383....
Repetend is '3'
Period is 1

1/17 = 0.0588235294117647....
Repetend is '0588235294117647'
Period is 16

10/13 = 0.769230....
Repetend is '769230'
Period is 6

3227/555 = 5.8144....
Repetend is '144'
Period is 3

476837158203125/9223372036854775808 = 0.000051698788284564229679463043254372678347863256931304931640625
Repetend is ''
Period is 0

1/149 = 0.0067114093959731543624161073825503355704697986577181208053691275167785234899328859060402684563758389261744966442953020134228187919463087248322147651....
Repetend is '0067114093959731543624161073825503355704697986577181208053691275167785234899328859060402684563758389261744966442953020134228187919463087248322147651'
Period is 148

1/5261 = 0.00019007793195210036114807070899068618133434708230374453525945637711461699296711651777228663752138376734461129062915795476145219540011404675917126021668884242539441170880060824938224672115567382626877019578026991066337198251283026040676677437749477285687131724006842805550275613001330545523664702528036494962934803269340429576126211746816194639802318950769815624406006462649686371412279034404105683330165367800798327314198821516821896977760881961604257745675727048089716783881391370461889374643603877589811822847367420642463409998099220680478996388519292910093138186656529176962554647405436228853830070328834822277133624786162326553887093708420452385478045998859532408287397833111575746055882911993917506177532788443261737312298042197300893366280174871697395932332256225052271431286827599315719444972438699866945447633529747196350503706519673065957042387378825318380536019768104923018437559399353735031362858772096559589431666983463219920167268580117848317810302223911803839574225432427295191028321611860862953811062535639612241018817715263257935753659....
Repetend is '00019007793195210036114807070899068618133434708230374453525945637711461699296711651777228663752138376734461129062915795476145219540011404675917126021668884242539441170880060824938224672115567382626877019578026991066337198251283026040676677437749477285687131724006842805550275613001330545523664702528036494962934803269340429576126211746816194639802318950769815624406006462649686371412279034404105683330165367800798327314198821516821896977760881961604257745675727048089716783881391370461889374643603877589811822847367420642463409998099220680478996388519292910093138186656529176962554647405436228853830070328834822277133624786162326553887093708420452385478045998859532408287397833111575746055882911993917506177532788443261737312298042197300893366280174871697395932332256225052271431286827599315719444972438699866945447633529747196350503706519673065957042387378825318380536019768104923018437559399353735031362858772096559589431666983463219920167268580117848317810302223911803839574225432427295191028321611860862953811062535639612241018817715263257935753659'
Period is 1052
Cookies help us deliver our services. By using our services, you agree to our use of cookies.