Integer long division
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++
#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
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
« 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)
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