求一个分数a / b的小数点后面的第k个数字,a,b,k是一个非常大的整数(小于10e18)

时间:2016-09-21 09:05:53

标签: c++ algorithm math

我的任务是在分数(a / b)的小数点后找到第k个位置的数字。 昨天我发现了这个算法 为了获得小数点后的任何数字,我生成一个名为rem的变量并进行循环

for (int i = 1; i <= k+1; i++)    
      {
         rem = a%b;
         a = rem*10;
      }
      cout << a/b;    

循环将返回一个值,即小数点后的第k位 然而,任务要求我用a,b,k计算非常大的数字(小于或等于10e18),因此它确保代码将超过时间限制。

  • 查找重复前的数字位数。它是分母中2和5个因子中较大的数字。
  • 如果k没有超过位数,请运行for循环。
  • 否则,我们仍然会将for循环运行到k + 1。将除法的其余部分的值存储在变量x。
  • 运行具有相同内容的while循环,直到余数再次具有x的值。从那时起,将分区的每个商存储为数组名称qut。
  • while循环终止后,数组将存储重复内的每个数字。根据数组内的数字位数,我们可以计算出第k位数 然而,该算法仍然是耗时的,因为在a和b是两个连续整数的情况下,重复变得非常大。 你能帮我解决一下吗?

1 个答案:

答案 0 :(得分:3)

你的for循环计算的是10 *(a * 10 k %b)/ b。我们可以通过平方取幂来更有效地做到这一点。我们必须小心,不要在每个点溢出:

int kth_digit_frac(uint64_t a, uint64_t b, uint64_t k) {
    return 10 * mulmodu64(a, powmod(10, k, b), b) / b;
}

// a*b % m, overflow safe
inline uint64_t mulmodu64(uint64_t a, uint64_t b, uint64_t m) {
    #if defined(__GNUC__) && defined(__x86_64__)
        uint64_t q, r;
        asm("mulq %3;"
            "divq %4;"
            : "=a"(q), "=d"(r)
            : "a"(a), "d"(b), "rm"(m)
            : "cc");
        return r;
    #else
        a %= m;
        b %= m;

        // No overflow possible.
        if (a == 0) return 0;
        if (b <= std::numeric_limits<uint64_t>::max() / a) return (a*b) % m;

        uint64_t res = 0;
        while (a != 0) {
            if (a & 1) {
                if (b >= m - res) res -= m;
                res += b;
            }

            a >>= 1;
            if (b >= m - b) b += b - m;
            else            b += b;
        }

        return res;
    #endif
}


// b^e % m, overflow safe
inline uint64_t powmod(uint64_t b, uint64_t e, uint64_t m) {
    uint64_t r = 1;

    b %= m;
    while (e) {
        if (e % 2 == 1) r = mulmodu64(r, b, m);
        b = mulmodu64(b, b, m);
        e >>= 1;
    }

    return r;
}

对于任何适合64位整数的a,b,k,它会眨眼间运行。