取幂的前 n 位数字

Posted

技术标签:

【中文标题】取幂的前 n 位数字【英文标题】:first n digits of an exponentiation 【发布时间】:2011-04-21 20:37:08 【问题描述】:

如何确定取幂的前 n 位 (ab)。

eg: for a = 12, b = 13 & n = 4, the first 4 digits are 1069.

【问题讨论】:

我看到了***.com/questions/635183/…,但我看不清楚。让某人简要说明一下。 这在 math.stackexchange 上不是更好吗?我在这里没有看到编程问题。 @Mark B:考虑到它被标记的语言,以及snprintf 或 C++ 等价物可能是一种不需要自己编写算法的可能实现,我认为这个问题是完全适合 SO。 @R 问题没有说明您可以将自己限制在由double 表示的值集,我认为它们可能是任意的。开发适当的算法以仅生成第一个 n 数字将更适合 math.stackexchange。 我以前从编程的角度在这里问过类似的数学问题 (***.com/questions/3215235/…),从来没有人质疑它是否离题。 【参考方案1】:

n=9 k=3 n^n=387420489 答案应该是 387

这与@RC 在他的代码中所做的相同。 谢谢@RC,我刚刚展示了您的代码的数学表示。

【讨论】:

【参考方案2】:

另一种解决方案,使用 log10:

#include <stdio.h>
#include <stdlib.h>
#include <math.h>

int main(int argc, char **argv) 
       int a = 12;
       int b = 13;
       int n = 4;
       double x, y;

       x = b * log10(a);
       y = floor(pow(10, x - floor(x) + n - 1));
       printf("Result: %d\n", (int)y);

       return EXIT_SUCCESS;

【讨论】:

【参考方案3】:

通过以下迭代计算ab

a1 = a1,a2 = a 2,...ai = ai em>,...ab = ab

你有 ai+1 = ai×a。不精确地计算每个 ai。问题是 ab 的相对误差小于 a 的相对误差的 n 倍。 您希望获得小于 10-n 的最终相对误差。因此,每一步的相对误差可能是。删除每一步的最后一位数字。

例如,a=2b=16n=1。最终相对误差为 10-n = 0.1。每一步的相对误差为0.1/16 > 0.001。因此,3 位数字在每一步都很重要。如果 n = 2,则必须保存 4 位。通用规则:每一步保存 [n+log10 b] 个数字。

2 (1), 4 (2), 8 (3), 16 (4), 32 (5), 64 (6), 128 (7), 256 (8), 512 (9), 1024 ( 10) → 102, 204 (11), 408 (12), 816 (13), 1632 (14) → 163, 326 (15), 652 (16)。

答案:6。

该算法的复杂度为O(b)。但是很容易将其更改为 O(log b)

【讨论】:

每一步的相对误差是多少(10^(-n))/b,是怎么推导出来的?你能解释一下吗?【参考方案4】:

对于这种情况 - 使用幻数 12、13、4:

#include <sstream>
#include <iomanip>
#include <cmath>

double a = 12;
int b = 13;
double result = std::pow(a,b);

std::stringstream strVal;
strVal.setf( ios::fixed, ios::floatfield );
strVal << result;
std::string output(strVal.str().substr(0,4));

输出 = "1069"

std::stringstream intStr(output);
int intVal;
intStr >> intVal;

intVal = 1069

编辑: 这应该适用于结果不会溢出的任何组合double

【讨论】:

只要结果不溢出double,即使对于巨大的数字也是正确的?我怀疑是这样,但作为完整答案的一部分,值得讨论。 @R.. - 好点,编辑使用 long double 并添加评论 long double 可能与 Windows 上的 double 相同。对代码是否会受到浮点不精确的影响进行一些分析会比仅仅抛出更大的类型来解决问题要好。 @R.. - 它与运行时库的 pow 函数一样准确,不是吗?我错过了你的意思吗? 除非您的系统的浮点到十进制转换比任何规范要求的要好,否则它会因n&gt;DECIMAL_DIG 而失败,即使pow(a,b) 是完全可表示的(如果a 总是如此)是 2) 的幂。是否还有其他失败案例,我不确定。我认为只要n 明显小于DECIMAL_DIG 就可以了。【参考方案5】:

以编程方式执行此操作的最简单方法是使用字符串流将求幂结果转换为字符串,然后取 n 个最重要(即左侧)字符。

如果您想要一种没有字符串的方法,那么这将起作用:

#include <iostream>
#include <sstream>
#include <math.h>

using namespace std;

double nDigExp( double a, double b, int n )

    stringstream ss;
    ss.setf( ios::fixed, ios::floatfield );
    ss << pow(a,b);
    double ret;
    for ( int i = 0; i < n; ++i) ret = (10 * ret) + (ss.get() - '0'); // Yeuch!!
    return ret;


int main( )

    double result = nDigExp( 12, 13, 4 );

    cout << result << endl;

    return 0;

但这并不是最优雅的代码。我相信你可以改进它。

【讨论】:

以上是关于取幂的前 n 位数字的主要内容,如果未能解决你的问题,请参考以下文章

c语言 一个整数的前n位数之和sum

ACM_求N^N的前5位数和后5位数(数论)

基数排序是不是适用于具有不同位数的数字?

分析涉及按位运算和 2 次幂的算法?

商品条码的前3位代表产地(国家)

C语言输出一个五位数,万位和百位数字一样,前三位数字和为9,后两位