【问题标题】:Find the kth digit after the decimal point of a fraction a/b with a,b,k being very large integers (less than 10e18)找到分数 a/b 小数点后的第 k 位,其中 a,b,k 是非常大的整数(小于 10e18)
【发布时间】:2017-01-29 10:33:56
【问题描述】:

我的任务是找到分数 (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 循环终止后,数组将存储repetend 中的每个数字。根据数组内的位数,我们可以计算出第k位。
    然而,该算法仍然被证明是耗时的,因为在 a 和 b 是两个连续整数的情况下,repetend 变得非常大。 你能帮我出主意吗?

【问题讨论】:

  • a,b,k 多大?你能指定一个范围吗?
  • 如果所有变量都适合 64 位,那么就没有什么可做的了,除非 b 大于 10*b 溢出
  • 如果所有变量都是integers,那么它们怎么可能小于等于10e18??据我所知,c++ 中整数的最高限制(也就是unsigned long int 大约是4.29e9
  • @progy_rock:试试uint64_t。它不一定存在,但如果存在,它将持有 10e18。

标签: c++ algorithm math


【解决方案1】:

你的 for 循环计算的实际上是 10 * (a*10k % 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,它都会在眨眼间运行。

【讨论】:

  • 非常感谢。我之前的任务是计算 (a^b*b^a)%m,但我没有意识到我可以使用算法来解决这个问题。
【解决方案2】:

我相信上面的两个解决方案仍然不正确,因为有一点错误。

我认为以下会很好地工作:

10 * (a*10^(k-1) % b) / b

【讨论】:

  • 您的答案可以通过额外的支持信息得到改进。请edit 添加更多详细信息,例如引用或文档,以便其他人可以确认您的答案是正确的。你可以找到更多关于如何写好答案的信息in the help center
猜你喜欢
  • 1970-01-01
  • 2021-05-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-09-30
  • 2014-12-29
  • 1970-01-01
相关资源
最近更新 更多