Microsoft Interview Question
Country: -
Maybe i didn't make clear why multiplying by 10 is needed
if
ghy/abdc = 0.ABDCUDEG..
then
ghy * 10 / abdc = A.BDCUDEG..
so we extracting A here
@anonymous1 :
what will happen in cases of 0.449672
or 0.0007711983.
i think you r wrong
Why make it super complex when the entire decimal portion can be obtained as below:
double x = N/D;
double decimal = x - (int) x;
I think the main part of the problem is not how we extract the decimal portion, but rather how we can find a pattern within the decimal part. I think the easiest way to find the pattern is to rely on suffix trees; check my solution below.
@anonymous: WOW!! thanks for visualizing the schoolbook division ))
Generating digits of decimal expansion can be done,
e.g., using the following simple algorithm:
void div_periodic(int num, int denom) {
int div = num / denom;
int mod = num % denom;
printf("%d.", div); // print integer part
num = mod;
int niters = 100;
std::vector< int > digits;
while(niters--) {
num *= 10; // num is always smaller than denom
int n_zeros = 0;
while(num < denom) { // add the required number of zeros
num *= 10; n_zeros++;
digits.push_back(0);
}
div = num / denom; // div is always a single digit
mod = num % denom;
digits.push_back(div); // add the next digit
num = mod;
if(num == 0)
break;
}
}
However, now it comes to the two main problems:
how to find where the period starts ?
how to find the length of the period ?
I think interviewers that ask such questions do not really understand the problem themselves because there is a significant amount of math behind it.
Consuling wikipedia, we find out that whenever
a denominator has factors of the form 2^a*5^b,
the resulting reciprocal is eventually periodic
but has a non-repeating sequence of digits of size max(a,b).
Now assume we know where the period starts.
The next problem is that a smaller period can be the part of larger
ones. For example, consider a decimal expansion of
1414147 / 999999999
which is 0.(001414147)
so there is no trivial way to detect it unless we know
what the maximal period of a fraction could be.
Again consulting wikipedia, we find that
the period of a reciprocal 1 / p is the order of 10 in Z/Zp,
given by Euler totient function, and is at most (p-1).
This suggests that we have to compute the first (p-1) digits
of decimal expansion of 1/p to find the period!!!
Is there another way ?
> how to find where the period starts ?
> how to find the length of the period ?
Standard cycle-finding algorithm, e.g., Floyd's.
> Is there another way ?
Basically we're computing a discrete logarithm. The naive algorithm isn't the fastest, but no one knows how to compute discrete logs in poly-time (i.e., in the number of digits of the modulus).
Extract the decimal portion as:
double x = N/D;
double decimal = x - (int) x;
- Now convert this decimal portion into a string (this can be achieved by first converting it into an int (multiplying by sufficient power of 10), and then converting to string.
- Construct a suffix tree for this string
- Now the repeated portion is the node value (within the suffix tree) which is added when processing each index (suffix); and the repetition ends at index i for which you have to create a new node within the suffix tree after identifying a pattern.
For example consider 0.34567567567
We extract a string:
Index: 0 1 2 3 4 5 6 7 8 9 10 11 12 13
Value:3 4 5 6 7 5 6 7 5 6 7 5 6 7
Now starting from index 10, the only node that is newly added to suffix tree is '567'. This continues until we process index 1. Hence the result is 0.34 (567)
Any number a / b can be expressed as c + d / b such that d < b.
- Anonymous October 07, 2011Now c will the left side of decimal and d / b will be contributing to the right side of decimal. The point to note is that d / b doesn't have any influence on c.
Consider an example 7 / 37. Consider what happens when we multiply it by 10.
70 / 37 = 1 + 33 / 37
So 1 will be the first place after decimal 33 / 37 will only contribute to second place and after.
Multiple by 10 again
330 / 37 = 8 + 34 / 37
So 8 will be the second place after decimal 34 / 37 will only contribute to third place and after.
Whenever a number less than 37 is divided by 37 the remainer can only be any values from 0-36 only 37 possible values so remainer is bound to repeat sometime. If the remainer is 0 we can stop. If the remainder is something we have seen before it will be beginning of the repetition.
Another example.
1 / 8
10 / 8 = 1 + 2 / 8 (so first place 0.1)
20 / 8 = 2 + 4 / 8 (so second place 0.12)
40 / 8 = 5 + 9 / 8 (so third place 0.125 ) remainder is 0 so terminate
Another example
4 / 7
40 / 7 = 35 + 5 / 7 ( so first place is 0.5 )
50 / 7 = 7 + 1 / 7 ( so second place 0.57 )
10 / 7 = 1 + 3 / 7 ( so third place 0.571 )
30 / 7 = 4 + 2 / 7 ( so fourth place 0.5714 )
20 / 7 = 2 + 6 / 7 ( so fifth place 0.57142 )
60 / 7 = 8 + 4 / 7 ( so sixthe place 0.571428 )
40 / 7 == we have encounter this before so it becomes 0.571428571428....
I am sure this can be coded pretty easy