繁体   English   中英

存储大量基数B的最佳方法是什么?

[英]Best way to store large base B numbers?

存储大型基本B编号的最佳方法是什么,以便能够有效地完成右移和检查最低有效位等操作?

实际上,我遇到了一个面试问题

Given two numbers N and K such that 0<=N<=1000 and 0<=K<=1000^1000. I need 
to check that whether N^N = K or not. For example:

if N=2 and K=4 , 2^2 = 4 so return true;
if N=3 and K=26 , 3^3 != 26 so return false

我在想的是,如果我考虑base N number system ,那么N^N将等于1 followed by N zero 例如 - 对于N = 2,2 ^ 2 = 100(在基数2中),对于N = 3,3 ^ 3 = 1000(在基数3中)。 然后,我可以轻松编写一个函数来判断K = N^N是否。

int check(unsigned long int N, unsigned long int K) 
{
    unsigned long int i;
    for (i=0; i<N; i++) 
    {
        if (K%N != 0) //checking whether LSB is 0 or not in base N number system 
           return 0;
        K = K/N; //right shift K by one. 
    }
    return (K==1);
}

现在这个功能有两个主要问题:

1) An unsigned long int is not sufficient to store large numbers of range 0 
to 1000^1000.
2) The modulus and the division operations makes it every less efficient.  

为了使其高效,我正在寻找一些方法来表示大的基数N数,以便我可以执行右移并有效地检查最低有效位操作。 以前有人遇到过这样的事吗? 或者有谁知道有效解决这个问题的任何其他方法?

要检查相等性,您实际上不必进行高精度算术 - 您可以使用http://en.wikipedia.org/wiki/Chinese_remainder_theorem 找到足够的质数以确保它们的乘积大于N ^ N,然后依次检查N ^ N对K的每个质数的模数。

在实践中,我可能会使用Java BigInteger包进行简单的计算。

根据面试官的不同,可以接受一些答案。 如果其中任何一项都不被接受,那么希望面试官能够迅速推动您提出其他建议。

  • 使用gmp ,或者使用mpz_t而不是unsigned long来执行除法和模数,或者只计算N^N并将其与K进行比较。 这是最简单的方法。
  • 编写自己的大数字库,可能使用基数10作为内部表示而不是基数2,如果输入在基数10中,并且认为坚持使用它可能比首先转换为二进制更快。 当然它不一定是一个完整的算术库,你真正需要的只是与余数的划分。
  • 发明一些你可以在开始之前做的快速测试,以避免在某些方面KN^N附近时很多工作。 例如,测试log(K) / N是否近似等于log(N) ,在任何基数中采用的日志对于输入最方便。 或测试多少次KN是整除的数字方便像210 :如果K是不能分开的正是N次很多次N ,那么它显然是错误的。 或者测试它们是否等于一些小数,例如ULONG_MAX1000000 不幸的是,这种事情只能加速某些不平等的情况,它会减慢其他一切,包括它们的情况。 所以它可能适得其反,取决于你期望的输入。

mcdowella的回答可能是也可能不是最好的,我不知道。 特别有希望的是,您只需要生成一次素数(当您编写程序时),并且在100 N <= 1000从1009开始的1000个素数就足够了。 较大的素数意味着需要的更少,因此工作量更少,特别是如果它们不超过ULONG_MAX平方根。 通过平方或等效使用取幂来得到N^N模数每个素数,并且对于K ,无论输入是什么基础,每次都做几个数字。

要真正闪存,对于每个预先选择的素数p您可以编写(或让编译器为您编写)模运算操作,该操作比适用于任何除数的一般整数模运算更快。 也就是说,一个体面的编译器i % 1009可能会快于i % j其中的价值j是在编译时未知,但原来在运行时是1009。但要注意,在速度上的差异可能收不回(比如)通过函数指针调用它的成本。 因此,利用它可能需要一些丑陋的重复代码。

为什么要将数字转换为基数N?

你可以继续除以N.如果你在N之后得到1这样的除数那么它就是N ^ N. 否则它不是。

您必须将K存储为字符串并执行divison操作。

divide(k,n):
  c = ''
  a = ''
  for i in k:
    c = c+i
    a = a+ str(int(c)/ int(n))
    c = str(int(c) % int(n))
 return a

这是在python中,你可以在C中实现类似的东西

给定两个数字N和K,使得0 <= N <= 1000且0 <= K <= 1000 ^ 1000。 我需要检查是否N ^ N = K.

很大程度上取决于提供给代码时这些数字的存储方式。 假设它们是文本格式,我只是保持这种方式,并创建一个包含N ^ N值的1001个字符串数组。 您可以使用任意精度算术命令行程序(如bc来一次性创建这些字符串,并在循环中调用它。

由于1000 ^ 1000中只有1000个“好”值(并且它们将彼此相距很远),因此可以先使用一些对数近似来猜测N. 在那之后,您最多只需要一次精确检查(例如,使用一些bignum库)。

这个对数不必是精确的,即使strlen()可以足够近似。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM