这是来自谷歌的代码堵塞,练习问题"所有你的基地"。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
long long pow_longlong(int digit, int raiseto)
{
if (raiseto == 0) return 1;
else return digit * pow_longlong(digit, raiseto - 1);
}
long long base10_with_map(int base, char* instr, char* digits)
{
if (base < 2) base = 2;
long long result = 0;
int len = strlen(instr);
int i = 0;
while (len--)
result += digits[instr[len]] * pow_longlong(base, i++);
return result;
}
long long test(char* in)
{
char appear[256];
int i;
int len = strlen(in);
int hold = 0;
for (i = 0; i < 256; i++) appear[i] = '\xFF';
for (i = 0; i < len; i++)
if (appear[in[i]] == '\xFF')
{
if (hold == 0) { appear[in[i]] = 1; hold++; }
else if (hold == 1) { appear[in[i]] = 0; hold++; }
else appear[in[i]] = hold++;
}
return base10_with_map(hold, in, appear);
}
int main(int argc, char* argv[])
{
if (argc < 2)
{
printf("Usage: %s <input-file> \n", argv[0]); return 1;
}
char buf[100];
int a, i;
FILE* f = fopen(argv[1], "r");
fscanf(f, "%d", &a);
long long result;
for (i = 1; i <= a; i++)
{
fscanf(f, "%s", buf);
result = test(buf);
printf("Case #%d: %lld\n", i, result);
}
return 0;
}
这可以按预期工作,并为问题产生正确的结果。但是如果我用math.h中的pow()替换自己的pow_longlong(),那么一些计算会有所不同。
这是什么原因?好奇。
编辑: - 没有溢出,普通长度足以存储值,长期只是矫枉过正 - 当然我包括math.h - 例如:test(&#34; wontyouplaywithme&#34;),pow_longlong返回674293938766347782(右)和math.h 674293938766347904(错误)
答案 0 :(得分:0)
pow
(请参阅reference)未定义整数,但仅针对浮点数。如果您以pow
作为参数致电int
,则结果将为double
。
您通常不能假设pow
的结果与使用纯函数pow_longlong
中的纯整数数学完全相同。
来自维基百科的关于double precision floating point numbers的引用:
在2 ^ 52 = 4,503,599,627,370,496和2 ^ 53 = 9,007,199,254,740,992之间 可表示的数字正是整数。对于下一个范围, 从2 ^ 53到2 ^ 54,一切都乘以2,所以可以表示 数字是偶数等等。
如果结果大于2 ^ 53,那么pow
会得到不准确的结果。
答案 1 :(得分:0)
很抱歉,我不会通过你的例子和你的中间功能;由于double
不足而导致您遇到的问题,而不是long long
。只是数字变得太大,导致它需要越来越精确到最后,超过double
可以安全地代表。
在这里,尝试这个非常简单的程序,或者只是信任我附加的输出,看看我的意思:
#include <stdio.h>
int main( ){
double a;
long long b;
a = 674293938766347782.0;
b = a;
printf( "%f\n", a );
printf( "%lld", b );
getchar( );
return 0;
}
/*
Output:
674293938766347780.000000
674293938766347776
*/
你看,double
可能有8个字节,与long long
一样多,但它的设计使得它也能够保存非整数值,这使得在某些情况下,比long long
更不精确。
我不知道确切的具体细节,但在这里,in MSDN据说它的表示范围是从-1.7e308
到+1.7e308
(可能只是平均)15位精度
因此,如果您只打算使用正整数,请坚持使用您的函数。如果您想拥有优化版本,请查看以下内容:https://stackoverflow.com/a/101613/2736228
它利用了这样一个事实:例如,在计算x to the power 8
时,你可以逃脱3次操作:
...
result = x * x; // x^2
result = result * result; // (x^2)^2 = x^4
result = result * result; // (x^4)^2 = x^8
...
而不是处理7个操作,将它们逐个相乘。