How does less than and greater than work on a logical level in binary? - machine-code

I see how equality could work by just comparing bit patterns, but how would one write one's own less than and greater than operators? What is the actual process to mechanically compare values to each other?

I assume you want to just know how logic does it? And mimic that? Well here goes:
First off you have to talk about unsigned greater than or less than vs signed greater than vs less than because they matter. Just do three bit numbers to make life easier, it all scales up to N bits wide.
As processor documentation usually states a compare instruction will do a subtraction of the two operands in order to generate flags, so it is a subtract that doesnt save the answer just modifies the flags. That then later jump or branch on some flag pattern can be used. Some processors dont use flags but have a similar solution, they still use the equivalent of flags but just dont save them anywhere. compare and branch if greater than kind of an instruction instead of separate compare and branch if greater than instructions.
What is a subtract in logic? Well in grade school we learned that
a - b = a + (-b).
We also know from intro programming classes that a negative in twos complement means invert and add one so
a - b = a + (~b) + 1.
Note ones complement means to invert ~b in C means invert all the bits it is also known as taking the ones complement.
so 7 - 5 is
1
111
+010
=====
Pretty cool we can use the carry in as the "plus one".
1111
111
+010
=====
010
So the answer is 2 with the carry out set. Carry out set is a good thing means we didnt borrow. Not all processors do the same but so far with a subtract we use an adder but invert the second operand and invert the carry in. If we invert the carry out we can call it a borrow, 7 - 5 doesnt borrow. Again some processor architectures dont invert and call it a borrow they just call it carry out. It still goes into the carry flag if they have flags.
Why does any of this matter? Just hang on.
Lets look at 6-5 5-5 and 4-5 and see what the flags tell us.
1101
110
+010
=====
001
1111
101
+010
=====
000
0001
100
+010
=====
111
So what this means is the carry out tells us (unsigned) less than if 0. If if 1 then greater than or equal. That was using a - b where b is what we were comparing against. So if we then do b - a that would imply that we can get (unsigned) greater than with the carry bit. 5 - 4, 5 - 5, 5 - 6. We already know what 5 - 5 looks like zero with the carry out set
1111
101
011
====
001
0011
101
001
====
111
Yep we can determine (unsigned) greater than or equal or (unsigned) less than or equal using the carry flag. Not less than is the same as greater than or equal and vice versa. You just need to get the operand you want to compare against in the right place. I probably did this backward from every compare instruction as I think they subtract a - b where a is what is being compared against.
Now that you have seen this you can easily scratch out the above math on a piece of paper in a few seconds to know which order you need things and what flags to use. Or do a simple experiment like this with a processor you are using and look at the flags to figure out which is subtracted from which and/or whether or not they invert the carry out and call it a borrow.
We can see from doing it with paper and pencil as in grade school that addition boils down to one column at a time, you have a carry in plus two operands, and you get a result and a carry out. You can cascade the carry out to the carry in of the next column and repeat this for any number of bits you can afford to store.
Some/many instruction sets use flags (carry, zero, signed overflow, and negative are the set you need to do most comparisons). You can see I hope that you dont need assembly language nor an instruction set with flags, you can do this yourself with a programming language that has the basic boolean and math operations.
Untested code I just banged out in this edit window.
unsigned char a;
unsigned char b;
unsigned char aa;
unsigned char bb;
unsigned char c;
aa = a&0xF;
bb = (~b)&0xF;
c = aa + bb + 1;
c >>=4;
a >>=4;
b >>=4;
aa = a&0xF;
bb = (~b)&0xF;
c = c + aa + bb;
c >>=4;
And there you go, using an equals comparison, compare c with zero. And depending on your operand order it tells you (unsigned) less than or greater than. If you want to do more than 8 bits then keep on cascading that add with carry indefinitely.
Signed numbers...
ADDITION (and subtraction) LOGIC DOES NOT KNOW THE DIFFERENCE BETWEEN SIGNED AND UNSIGNED OPERANDS. Important to know. This is the beauty of twos complement. Try it yourself write a program that adds bit patterns together and prints out the bit patterns. Interpret those bit patterns input and output as all unsigned or all signed and you see this works (note some combinations overflow and the result is clipped).
Now saying that the flags do vary for subtraction comparisons. We know from grade school math where we carry the one or whatever over as we see in binary as well. The carry out is an unsigned overflow for unsigned. If set you overflowed we have a 1 we cant fit into our register so the result is too big we fail. Signed overflow though is the V bit which tells us if the carry IN and carry OUT of the msbit were the same or not.
Now lets use four bits, cause I want to. We can do the 5 - 4, 5 - 5, and 5 - 6. These are positive numbers so we have seen this but we didnt look at the V flag nor N flag (nor z flag). The N flag is the msbit of the result which indicates negative using twos complement notation, not to be confused with a sign bit although it is as a side effect, it is just not a separate sign bit that you remove from the number.
11111
0101
1011
=====
0001
c = 1, v = 0, n = 0
11111
0101
1010
=====
0000
c = 1, v = 0, n = 0
00011
0101
1001
=====
1111
c = 0, v = 0, n = 1
Now negative numbers -5 - -6, -5 - -5, -5 - -4
10111
1011
1010
=====
0110
c = 0, v = 1, n = 1
You know what, there is an easier way.
#include <stdio.h>
int main ( void )
{
unsigned int ra;
unsigned int rb;
unsigned int rc;
unsigned int rd;
unsigned int re;
int a;
int b;
for(a=-5;a<=5;a++)
{
for(b=-5;b<=5;b++)
{
ra = a&0xF;
rb = (-b)&0xF;
rc = ra+rb;
re = rc&8;
re >>=3;
rc >>=4;
ra = a&0x7;
rb = (-b)&0x7;
rd = ra+rb;
rd >>=3;
rd += rc;
rd &=1;
printf("%+d vs %+d: c = %u, n = %u, v = %u\n",a,b,rc,re,rd);
}
}
return(0);
}
and a subset of the results
-5 vs -5: c = 1, n = 0, v = 0
-5 vs -4: c = 0, n = 1, v = 0
-4 vs -5: c = 1, n = 0, v = 0
-4 vs -4: c = 1, n = 0, v = 0
-4 vs -3: c = 0, n = 1, v = 0
-3 vs -4: c = 1, n = 0, v = 0
-3 vs -3: c = 1, n = 0, v = 0
-3 vs -2: c = 0, n = 1, v = 0
-2 vs -3: c = 1, n = 0, v = 0
-2 vs -2: c = 1, n = 0, v = 0
-2 vs -1: c = 0, n = 1, v = 0
-1 vs -2: c = 1, n = 0, v = 0
-1 vs -1: c = 1, n = 0, v = 0
-1 vs +0: c = 0, n = 1, v = 0
+0 vs -1: c = 0, n = 0, v = 0
+0 vs +0: c = 0, n = 0, v = 0
+0 vs +1: c = 0, n = 1, v = 0
+1 vs +0: c = 0, n = 0, v = 0
+1 vs +1: c = 1, n = 0, v = 0
+1 vs +2: c = 0, n = 1, v = 0
+3 vs +2: c = 1, n = 0, v = 0
+3 vs +3: c = 1, n = 0, v = 0
+3 vs +4: c = 0, n = 1, v = 0
And I will just tell you the answer...You are looking for n == v or not n == v. So if you compute n and v, then x = (n+v)&1. Then if that is a zero they were equal, if that is a 1 they were not. You can use an equals comparison. When they were not equal b was greater than a. Reverse your operands and you can check b less than a.
You can change the code above to only print out if n and v are equal. So if you are using a processor with only an equals comparison, you can still survive with real programming languages and comparisons.
Some processor manuals may chart this out for you. They may say n==v for one thing or not z and n!=v for the other (LT vs GT). But it could be simplified, from grade school the alligator eats the bigger one a > b when you flip it b < a. So feed the operators in one way and you get a > b, feed them the other way you get b < a.
Equals is just a straight bit comparison that goes through a separate logic path, not something that falls out of the addition. N is grabbed from the msbit of the result. C and V fall out of the addition.

One method that is O(1) over all numbers in the given domain (keeping the number of bits constant) would be to subtract the numbers and check the sign bit. I.e., suppose you have A and B, then
C = A - B
If C's sign bit is 1, then B > A. Otherwise, A >= B.

Related

Algorithms :XOR operation [duplicate]

This question already has answers here:
Given an XOR and SUM of two numbers, how to find the number of pairs that satisfy them?
(2 answers)
Closed 5 years ago.
You are given a sum S and X , you need to find , if it there exist two numbers a and b such that a+b = S and a^b = X
I used a loop upto S/2 and check if it is possible or not
for(int i=0;i<=s/2;i++)
{
if(i^(s-i)==X)
return true;
}
complexity : O(n)
Need some better approach
Given that a+b = (a XOR b) + (a AND b)*2 (from here) we can calculate (a AND b):
If S < X => not possible, otherwise take S-X. If this is odd => not possible, otherwise (a AND b) = (S-X)/2.
now we can look at the bits of a and b individually. Checking all four combinations we see there is only one result that is impossible namely XOR and AND both 1.
So if (a XOR b) AND (a AND b) != 0 there is no solution. Otherwise one can find a and b that solve the equation.
if (S < X) return false;
Y = S - X;
if (Y is odd) return false;
if ((X & (Y/2)) != 0) return false;
return true;
Without previous knowledge of the equation, a+b = a^b + (a&b)*2, we can think of another solution. This solution is O(logK) where K is the maximum possible value of S and X. That is, if S and X are unsigned int then K is 2^32 - 1.
Start from the MSB of S and X. With the information that whether summing this bit must provide carry or not, we can check for this bit with condition that whether summing the bits to the right should provide carry or not.
Case1 ) summing must not provide carry
S X | need carry from right
------------------------------
0 0 | no (a = 0, b = 0)
0 1 | impossible
1 0 | yes (a = 0, b = 0)
1 1 | no (a = 1, b = 0 or 0,1)
Case2 ) summing must provide carry
S X | need carry from right
------------------------------
0 0 | no (a = 1, b = 1)
0 1 | yes (a = 1, b = 0 or 0,1)
1 0 | yes (a = 1, b = 1)
1 1 | impossible
There is a special case for the MSB where the carry doesn't matter.
Case3 ) don't care
S X | need carry from right
------------------------------
0 0 | no (a = 0, b = 0 or 1,1)
0 1 | yes (a = 1, b = 0 or 0,1)
1 0 | yes (a = 0, b = 0 or 1,1)
1 1 | no (a = 1, b = 0 or 0,1)
Lastly, the LSB must end with 'no need carry from right'.
The implementation and test code is here. It compares the output of the accepted solution and this solution.
I assume that you are assuming that your input sequence is sorted.
If it is, then this problem is as good as finding pair for a given sum and while checking sum check for their (a^b == SUM) this should be enough and this problem can be solved in O(n). URL
And you can't do better than that. In worst case you have to visit each element atleast once.

find greatest number, x for given y and n such that x ^ y <= n

I need to find a greatest number, x for given y and n such that x ^ y <= n
Here n can be very large number - 1 <= n <= 10^10
and 1 <= y <= 10^5
for example :
for y = 5 and n = 1024
x ^ 5, then x = 4 (4 ^ 5 = 1024)
for y = 5 and n = 480
x ^ 5 , then x = 3 (3 ^ 5 = 243, 4 ^ 5 = 1024) - selecting lowest one, so x = 3
i have written a small program, But i want more efficient technique because n and y can be very large.
def get(y, n):
x = 1
while x ** y <= n:
x += 1
return x - 1
Using a multiple-precision arithmetic library, such as gmpy2's iroot.
>>> import gmpy2
>>> root, exact = gmpy2.iroot(n, y)
This is simply an integer n-th root algorithm. It should be fast and correct even for huge numbers (something that floats cannot guarantee in the general case).
The second value returned is a boolean which indicates if the root is exact or not.
>>> print(*gmpy2.iroot(1024, 5))
4 True
>>> print(*gmpy2.iroot(480, 5))
3 False
you can use binary search on integer to move from your O(x) to O(log(x)) if you apply floating math then:
x^y = n // ^(1/y)
x = n^1/y
x = floor(pow(n,1/y))
your example n=400 and y=5 is like this:
x = floor(pow(400,1/5))
x = floor(pow(400,0.2))
x = floor(3.3144540173399868004685801443126)
x = 3
of coarse for big n will this not work with basic floating types. In such case either use bin search on big integers or implement your own bigint pow if you do not have it already at your disposal. Anyway both approaches are described here:
Power by squaring for negative exponents do not get fouled by the title it is all integer math ...
[edit1]
after absorbing your comments:
n = < 1 , 10^10 >
y = < 1 , 10^5 >
no FPU just integer math
I would use binary search. You need to use at least ceil(log2(10^10))=34 bit variables for this so unsigned 64 bit QWORD it is. if you do not have such variables you need to implement it from lower bit width variables first.
The binary search mask will be:
m = 2^33 = 1<<33 = 0x0000000200000000
so you first need to implement pow and then root adapting code from linked answer here is C++ result:
#define T_bits 34
#define T_MSB 0x0000000200000000
#define T QWORD
T pow(T x,T y) // power by squaring returns z=x^y where x>=0, y>=0
{
T i,z=1;
for (i=0;i<T_bits;i++) // test all bits from MSB to LSB
{
z*=z;
if (T(y&T_MSB)) z*=x;
y<<=1;
}
return z;
}
T bits(T x) // count how many bits is in x
{
T m=T_MSB,z=T_bits;
for (;m;m>>=1,z--)
if (x>=m) break;
return z;
}
T root(T x,T y) // bin search y-th root returns z=x^(1/y)
{
T m,z;
m=((bits(x)+y-1)/y); // ceil(bits(x)/y)
if (m) m=1<<m; else m=1; // MSB of the result for bin search 2^(ceil(bits(x)/y))
for (z=0;m;m>>=1) // test all bits of x from MSB to LSB
{
z|=m; // set actual bit
if (pow(z,y)>x) z^=m; // clear if result exceedes x
}
return z;
}
for those of you that have just 32 bit arithmetics and have lover limit n<2^32 change the defines to:
#define T_bits 32
#define T_MSB 0x80000000
#define T DWORD
or use any other variable type you got at your disposal. The T is your data-type T_MSB is MSB bit set and T_bits is used bit count.
If you use:
root(400,5);
it will return 3. You can use your ** instead of pow I can not as my compiler does not recognize ** operator. Now to explanation of binary search
let assume your example. You start with x=1 then test x=2 then x=3 and so on until you cross x^y>=n so in reality you had checked pow(n,1/y) values. if we use n=10000, y=2 that will lead to 100 tests.
The binary search does not increment but set individual bits instead. 10000 has 14 bits so ceil(14/y)=7 so the process will be:
x with set bit| x^y | action
-------------------------------
0100 0000 bin | 4096 | none
0110 0000 bin | 9216 | none
0111 0000 bin | 12544 | clear
0110 1000 bin | 10816 | clear
0110 0100 bin | 10000 | none
0110 0010 bin | 10404 | clear
0110 0001 bin | 10201 | clear
-------------------------------
0110 0000 bin | 10000 | result
leading to only 7 tests instead of your naive 100.

Generate number with equal probability

You are given a function let’s say bin() which will generate 0 or 1 with equal probability. Now you are given a range of contiguous integers say [a,b] (a and b inclusive).
Write a function say rand() using bin() to generate numbers within range [a,b] with equal probability
The insight you need is that your bin() function returns a single binary digit, or "bit". Invoking it once gives you 0 or 1. If you invoke it twice you get two bits b0 and b1 which can be combined as b1 * 2 + b0, giving you one of 0, 1, 2 or 3 with equal probability. If you invoke it thrice you get three bits b0, b1 and b2. Put them together and you get b2 * 2^2 + b1 * 2 + b0, giving you a member of {0, 1, 2, 3, 4, 5, 6, 7} with equal probability. And so on, as many as you want.
Your range [a, b] has m = b-a+1 values. You just need enough bits to generate a number between 0 and 2^n-1, where n is the smallest value that makes 2^n-1 greater than or equal to m. Then just scale that set to start at a and you're good.
So let's say you are given the range [20, 30]. There are 11 numbers there from 20 to 30 inclusive. 11 is greater than 8 (2^3), but less than 16 (2^4), so you'll need 4 bits. Use bin() to generate four bits b0, b1, b2, and b3. Put them together as x = b3 * 2^3 + b2 * 2^2 + b1 * 2 + b0. You'll get a result, x, between 0 and 15. If x > 11 then generate another four bits. When x <= 11, your answer is x + 20.
Help, but no code:
You can shift the range [0,2 ** n] easily to [a,a+2 ** n]
You can easily produce an equal probability from [0,2**n-1]
If you need a number that isn't a power of 2, just generate a number up to 2 ** n and re-roll if it exceeds the number you need
Subtract the numbers to work out your range:
Decimal: 20 - 10 = 10
Binary : 10100 - 01010 = 1010
Work out how many bits you need to represent this: 4.
For each of these, generate a random 1 or 0:
num_bits = 4
rand[num_bits]
for (x = 0; x < num_bits; ++x)
rand[x] = bin()
Let's say rand[] = [0,1,0,0] after this. Add this number back to the start of your range.
Binary: 1010 + 0100 = 1110
Decimal: 10 + 4 = 14
You can always change the range [a,b] to [0,b-a], denote X = b - a. Then you can define a function rand(X) as follows:
function int rand(X){
int i = 1;
// determine how many bits you need (see above answer for why)
while (X < 2^i) {
i++;
}
// generate the random numbers
Boolean cont = true;
int num = 0;
while (cont == true) {
for (j = 1 to i) {
// this generates num in range [0,2^i -1] with equal prob
// but we need to discard if num is larger than X
num = num + bin() * 2^j;
}
if (num <= X) { cont = false}
}
return num;
}

Simplest way to add bits mod n?

Given a bunch of integers, I want to convert them to base n and for each bit, add the bits up and mod them by n.
Example: Let n = 3, and suppose I want to add the bits mod 3 in 4, 4, 4, 2. These numbers in base 3 is 11, 11, 11, 02. The least significant bit adds up to 1 + 1 + 1 + 2 = 5 = 2 mod 3. The second least significant bit adds up to 1 + 1 + 1 + 0 = 3 = 0 mod 3. The answer is then 02 base 3 = 2. Alternatively, if we didn't convert to base 3 before the addition, and just did it in binary, we have 100, 100, 100, 010. The resulting bits from least significant to most significant is: 0 + 0 + 0 + 0 = 0 mod 3, 0 + 0 + 0 + 1 = 1 mod 3, 1 + 1 + 1 + 0 = 0 mod 3, so the answer is 010 = 2.
The case where n = 2 is pretty easy, you can just XOR everything. Is there a way to generalize this?
Here's a ditty in ruby:
#! /usr/bin/env ruby
def naryxor(n, terms)
puts "Calculating the #{n}-ary XOR of #{terms.join(", ")}..."
raise "Negative terms are forbidden" if terms.any? { |i| i < 0 }
xor = [] # "Digits" of our n-ary xor result
done = false
while not done
done = true # Assume we're done until proven otherwise
xor.insert(0, 0) # Insert a new total digit at the front
terms = terms.select { |i| i > 0 }.collect do |i|
done = false # Not all remaining terms were zero
digit = i % n # Find the least n-ary digit
rest = (i - digit) / n # shift it off
xor[0] += digit # add it to our xor
rest # Replace this integer with its remainder
end
xor[0] %= n # Take the mod once, after summing.
end
xor[1..-1] # Drop untouched leading digit
end
raise "Usage: ./naryxor.rb arity term term..." if ARGV.size <= 1
puts naryxor(ARGV[0].to_i, ARGV[1..-1].collect(&:to_i)).join("")
Running it:
$ ./naryxor.rb 3 4 4 4 2
Calculating the 3-ary XOR of 4, 4, 4, 2...
02
This is just expands the n-ary representations of the passed integers and does the dumb thing. If n were taken to be a power of two, we could do some more interesting bit-twiddles to avoid the integer divisions, but you gave no such guarantee.
I don't think there's a mathematical property that leads to an efficient general short-cut. The reason XOR works for base 2 is because XOR has the convenient property of being an addition with carry discard.
A simple recursive function can apply the algorithm, e.g. taking advantage of Scala's BigInt class for base conversion:
def sums(radix: Int, digits: List[List[String]]): String =
if(digits exists { _.nonEmpty }) // there's at least 1 bit left to add
(digits.flatMap { _.headOption } // take the 1st bit of all numbers
.map { BigInt(_, radix) } // convert to int representation
.sum
.toInt % radix // modulo by base
).toString +
sums(radix, digits map { _.drop(1) }) // do next most significant bit
else
"" // base case: no digits left to add
def sum(radix: Int, ns: List[Int]): Int =
BigInt(
sums(
radix,
ns // use BigInt to convert from int representation to string
.map { BigInt(_) }
.map { _.toString(radix).split("").drop(1).toList.reverse }
)
.reverse,
radix
).toInt
scala> sum(3, List(4,4,4,2))
res0: Int = 2
Your question is tagged 'performance' but doesn't lay out any additional constraints about memory or runtime to inform an improved approach.

Algorithm for detecting repeating decimals?

Is there an algorithm for figuring out the following things?
If the result of a division is a repeating decimal (in binary).
If it repeats, at what digit (represented as a power of 2) does the repetition start?
What digits repeat?
Some examples:
1/2 = 1/10 = 0.1 // 1 = false, 2 = N/A, 3 = N/A, 4 = N/A
1/3 = 1/11 = 0.010101... // 1 = true, 2 = -2, 3 = 10
2/3 = 10/11 = 0.101010... // 1 = true, 2 = -1, 3 = 10
4/3 = 100/11 = 1.010101... // 1 = true, 2 = 0, 3 = 10
1/5 = 1/101 = 0.001100110011... // 1 = true, 2 = -3, 3 = 1100
Is there a way to do this? Efficiency is a big concern. A description of the algorithm would be preferred over code, but I'll take what answer I can get.
It's also worth noting that the base isn't a big deal; I can convert the algorithm over to binary (or if it's in, say base 256 to use chars for ease, I could just use that). I say this because if you're explaining it might be easier for you to explain in base 10 :).
if the divisor is not a power of 2 (in general, contains prime factors not shared with the base of representation)
repeat cycle length will be driven by the largest prime factor of the dividend (but not connected with the length of the representation of that factor -- see 1/7 in decimal), but the first cycle length may differ from the repeat unit (e.g. 11/28 = 1/4+1/7 in decimal).
the actual cycle will depend on the numerator.
I can give a hint - repeating decimals in base ten are all fraction with the denominator having at least one prime factors other than two and five. If the denominator contains no prime factors two or five, they can always be represented with a denominator of all nines. Then the nominator is the repeating part and the number of nines is the length of the repeating part.
3 _
- = 0.3
9
1 142857 ______
- = ------ = 0.142857
7 999999
If there are prime factors two or five in the denominator, the repeating part starts not at the first position.
17 17 ______
-- = ----- = 0.4857142
35 5 * 7
But I cannot remember how to derive the non-repeating part and its length.
This seem to translate well to base two. Only fraction with a power of two denominator are non-repeating. This can be easily checked by asserting that only a single bit in the denominator is set.
1/2 = 1/10 = 0.1
1/4 = 1/100 = 0.01
3/4 = 11/100 = 0.11
5/8 = 101/1000 = 0.101
All fraction with odd denominators should be repeating and the pattern and its length can be obtained by expressing the fraction with a denominator in the form 2^n-1.
__
1/3 = 1/(2^2-1) = 1/11 = 0.01
__
2/3 = 2/(2^2-1) = 10/11 = 0.10
__
4/3 => 1 + 1/3 => 1.01
__
10/3 => 3 + 1/3 => 11.01
____
1/5 = 3/15 = 3/(2^4-1) = 11/1111 = 0.0011
________
11/17 = 165/255 = 11/(2^8-1) = 10100101/11111111 = 0.10100101
As for base ten, I cannot tell how to handle denominators containing but not being a power of two - for example 12 = 3 * 2^2.
First of all, one of your examples is wrong. The repeating part of 1/5 is 0011 rather than 1100, and it begins at the very beginning of the fractional part.
A repeating decimal is something like:
a/b = c + d(2-n + 2-n-k + 2-n-2k + ...)
= c + 2-n * d / (1 - 2-k)
in which n and d are what you want.
For example,
1/10(dec) = 1/1010(bin) = 0.0001100110011... // 1 = true, 2 = -1, 3 = 0011
could be represented by the formula with
a = 1, b = 10(dec), c = 0, d = 0.0011(bin), n = 1, k = 4;
(1 - 2-k) = 0.1111
Therefore, 1/10 = 0.1 * 0.0011/0.1111. The key part of a repeating decimal representation is generated by dividing by (2n - 1) or its any multiple of 2. So you can either find a way to express your denominator as such (like building constant tables), or do a big number division (which is relatively slow) and find the loop. There's no quick way to do this.
Check out decimal expansion, and specifically about the period of a fraction.
You can do a long division, noting the remainders. The structure of the remainders will give you the structure of any rational decimal:
the last remainder is zero: it is a decimal without any repeating part
the first and the last remainder are equal: the decimal is repeating right after the dot
the distance between the first and the first remainder equal to the last are the non-repeating digits, the remainder is the repeating part
In general the distances will give you the amount of digits for each part.
You can see this algorithm coded in C++ in the method decompose() here.
Try 228142/62265, it has a period of 1776 digits!
To find the repeating pattern, just keep track of the values you use along the line:
1/5 = 1/101:
1 < 101 => 0
(decimal separator here)
10 < 101 => 0
100 < 101 => 0
1000 >= 101 => 1
1000 - 101 = 11
110 >= 101 => 1
110 - 101 = 1
10 -> match
As you reach the same value as you had at the second bit, the process will just repeat from that point producing the same bit pattern over and over. You have the pattern "0011" repeating from the second bit (first after decimal separator).
If you want the pattern to start with a "1", you can just rotate it until it matches that condition:
"0011" from the second bit
"0110" from the third bit
"1100" from the fourth bit
Edit:
Example in C#:
void FindPattern(int n1, int n2) {
int digit = -1;
while (n1 >= n2) {
n2 <<= 1;
digit++;
}
Dictionary<int, int> states = new Dictionary<int, int>();
bool found = false;
while (n1 > 0 || digit >= 0) {
if (digit == -1) Console.Write('.');
n1 <<= 1;
if (states.ContainsKey(n1)) {
Console.WriteLine(digit >= 0 ? new String('0', digit + 1) : String.Empty);
Console.WriteLine("Repeat from digit {0} length {1}.", states[n1], states[n1] - digit);
found = true;
break;
}
states.Add(n1, digit);
if (n1 < n2) {
Console.Write('0');
} else {
Console.Write('1');
n1 -= n2;
}
digit--;
}
if (!found) {
Console.WriteLine();
Console.WriteLine("No repeat.");
}
}
Called with your examples it outputs:
.1
No repeat.
.01
Repeat from digit -1 length 2.
.10
Repeat from digit -1 length 2.
1.0
Repeat from digit 0 length 2.
.0011
Repeat from digit -1 length 4.
As others have noted, the answer involves a long division.
Here is a simple python function which does the job:
def longdiv(numerator,denominator):
digits = []
remainders = [0]
n = numerator
while n not in remainders: # until repeated remainder or no remainder
remainders.append(n) # add remainder to collection
digits.append(n//denominator) # add integer division to result
n = n%denominator * 10 # remainder*10 for next iteration
# Result
result = list(map(str,digits)) # convert digits to strings
result = ''.join(result) # combine list to string
if not n:
result = result[:1]+'.'+result[1:] # Insert . into string
else:
recurring = remainders.index(n)-1 # first recurring digit
# Insert '.' and then surround recurring part in brackets:
result = result[:1]+'.'+result[1:recurring]+'['+result[recurring:]+']'
return result;
print(longdiv(31,8)) # 3.875
print(longdiv(2,13)) # 0.[153846]
print(longdiv(13,14)) # 0.9[285714]
It’s heavily commented, so it shouldn’t be too hard to write in other languages, such as JavaScript.
The most important parts, as regards recurring decimals are:
keep a collection of remainders; the first remainder of 0 is added as a convenience for the next step
divide, noting the integer quotient and the remainder
if the new remainder is 0 you have a terminating decimal
if the new remainder is already in the collection, you have a recurring decimal
repeat, adlib and fade etc
The rest of the function is there to format the results.

Resources