how to find n'th number in the decimal expansion of a proper fraction?

GolfScript 17

10\?@abs*\abs/10%

GolfScript can't handle real numbers well, but multiplying by powers of 10 is equivalent.

Here's an explanation and walkthrough with sample input, for any of you who are new to GolfScript, since I think this is a nice simple introduction:

59 -17 5
10\ #Place 10 on the stack and then switch the top 2 elements
-> 59 -17 10 5
? #Exponentiate
-> 59 -17 100000
@ #Rotate top 3 elements
-> -17 100000 59
abs #Take absolute value of top element
-> -17 100000 59
* #Multiply the top 2 elements
-> -17 5900000
\ #Switch top 2 elements
-> 5900000 -17
abs #Take absolute value of top element
-> 5900000 17
/ #Do integer division
-> 347058
10% #Place 10 on the stack and then take modulo
-> 8

Java

static int digit(int N, int D, int R) {
    if (D < 0) D = -D;
    if (N < 0) N = -N;
    int Q=0;
    while (R-- > 0) {
        while (N >=D) N -=D;
        int P=N = ((N+N)<<1)+N;
        for (Q=P^P; N >D; N -=D) Q++;
        while (P >=D) P -=D;
        N = P<<1;
    }
    for (; N >= 0; N -=D) R++;
    return (Q<<1) + R;
}

This code

  • avoids multiplication and division
  • splits decimal digit in 5- and 2-digit (Q and final R) internally

Explanation

When dividing manually you get digits by multiplying remainders by 10 and comparing the results to multiples of the divisor

10 / 17 = Digit 0, Remainder 10 (x 10)
100 / 17 = Digit 5, Remainder 15 (x 10)
 150 / 17 = Digit 8, Remainder 14 (x 10)
  140 / 17 = Digit 8, Remainder 4 (x 10)
etc.

So the basic code (ignoring all digits except the R-th) would be

static int digitA(int N, int D, int R) {
    while (R-- > 0) {
        N = N % D;
        N = N * 10;
    }
    return N / D;
}

Replacing multiplications and divisions by adding/subtracting and shifting results in

while (R-- > 0) {
    while (N >= D) N = N - D;
    N = ((N << 2) + N) << 1;
}
int digit = 0;
while (N > D) { digit++; N = N - D; }
return digit;

As R is -1 after the first loop, it can be used to replace digit afterwards. With avoiding shifting by more than 1 and introducing intermediate P the code becomes

while (R-- > 0) {
    while (N >= D) N = N - D;
    int P = ((N + N) << 1) + N;
    N = P << 1;
}
for ( ; N >= D; N = N - D) R++;
return R;

The number of loop runs can be reduced by "splitting the decimal digit into two digits with base 5 and 2". The above manual division schema would become something like

10 / 17 = 2-Digit 0, Remainder 10 (x 5)
50 / 17 = 5-Digit 2, Remainder 16 (x 2)
32 / 17 = 2-Digit 1, Remainder 15 (x 5) --> 10-digit = 2*2 + 1
75 / 17 = 5-Digit 4, Remainder 7 (x 2)
14 / 17 = 2-Digit 0, Remainder 14 (x 5) --> 10-digit = 4*2 + 0
70 / 17 = 5-Digit 4, Remainder 2 (x 2)
4 / 17 = 2-Digit 0, Remainder 4 (x 5) --> 10-digit = 4*2 + 0
etc.

As only the R-th decimal digit is to be returned, only the R-th 5-digit before the R-th 2-digit is required to compose the R-th decimal digit.

int P=N = ((N+N)<<1)+N; // N = N * 5
for (Q=P^P; N >D; N -=D) Q++; // Q=digit(5)
//...
return (Q<<1) + R;

The rest is some "obfuscation"

  • P^P is zero - inspired by machine code where XORing may be the most efficient way to set a register to zero :-)
  • The line while (P >=D) P -=D; is the same as P=N; - but is more "smiling" :-)

Mathematica: 36 chars

f = RealDigits[#1/#2, 10, 1, -#3][[1, 1]] &

Test case:

f[1, 70000, 5]

1