2014-03-31 130 views
2

我正在研究一个个人项目,其中一部分涉及计算一定范围内的广场和立方体(本例中为10,000)。所以,我写了一个简单的C程序,我认为它会验证我的结果。这里是小程序,我放在一起,看到所有的立方体:为什么我在这个简单的C程序中得到这个奇怪的输出?

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


int main() { 

     double i; 
     int cubes = 0; 

     for (i = 1; i < 10000; i++) { 

     if (i == cbrt(i) * cbrt(i) * cbrt(i)) { 

      printf("%f --- %f\n",i, cbrt(i)); 
      cubes++; 
     } 
     } 

    printf("%i\n", cubes); 

    return 0; 
} 

我得到了(不正确)输出:24.如果你想看看这个去看了看问题的数字15和20上输出。为什么我得到错误的答案(正确的答案是21)是完全不同的问题。我的问题出现了,当我瞎搞我的代码,试图解决这个问题,我暂时把它改成这样:

int main() { 

    double i; 
    int cubes = 0; 

    for (i = 1; i < 10000; i++) { 

     double temp = (cbrt(i) * cbrt(i) * cbrt(i)); 

     if (i == temp) { 

      printf("%f -> %f\n", i, temp); 
      cubes++; 
     } 
    } 

    printf("%i\n", cubes); 

    return 0; 
} 

现在,程序打印1至9999之间的每个号码所以,我失去的东西可笑容易或发生了什么?我所做的只是在cbrt(i)*cbrt(i)*cbrt(i)而不是有条件我设置一个双变量等于结果并将其放置在条件。为什么我的程序会这样做?

我不知道为什么这个投票。我觉得这是一个合理的问题。对不起S.O.社区...

+0

你究竟在做什么?您是否在尝试使用整数立方体根来查找数字? –

+5

第一印象 - 您正在检查浮点数(“双”)的平等,这只是在寻找问题。为什么不用简单的'int'来代替?或'uint64_t',或其他。 – Kamiccolo

+0

假设我是一个int并且temp是一个double,由于double的内部四舍五入,你不会经常达到平等。 – Duck

回答

1

double cbrt(double x)返回最接近的可表示的立方根x

结果的不精确性,然后立方,可能不会再精确地等于'x'。


为什么第二个程序不同:

C不履行义务double数学double精度。它可能使用更宽(long double)。取决于许多事情,第二个代码看起来在long double中比第一个做得更多。有了这个额外的精度,很容易看出结果,四舍五入到double看起来确切。

C11dr§5.2.4.2.29除了分配和流延(其去除所有多余的范围和精度),是由操作者操作数浮动产生的值和值受到通常的算术转换和浮动常数是评估的格式的范围和精度可能会大于类型所要求的格式。


为什么一个典型的程序运行(或者代码)产生的约3333

从2至4和8至64 double号码考虑double数的结果是对数分布。有许多不同的double 2至4个如8至16 16至32 32至64

所以,现在从8到64的所有3套有一立方根在1组的一些答案2至4.现在,如果我们对数字2到4进行多维数据集化,我们可以在8到64的范围内得到答案。1组数字映射到3组中。往返并不确切。请参阅Pigeonhole principle。 IOW:平均而言,8至64范围内的3个数字具有相同的立方根。然后该根的立方体将是3个原始的1。


找到最完美的整数立方体0的次数为N

unsigned Perfect_Cube_Count(unsigned n) { 
    if (n == 0) 
    return 1; 
    unsigned i; 
    // overflow not possible 
    for (i = 0; i*i < n/i; i++); 
    return i; 
} 

或者

// valid for 0 <= x <= something_well_over_1e9 
double Perfect_Cube_Count_d(double x) { 
    double y = cbrt(x); 
    return floor(y) + 1; 
} 
+0

这仍然没有向我解释'程序正在打印1到9999之间的每个数字'行为。 –

+0

OP在循环结束时打印计数,这将很难错过结果... –

+0

@BuellaGáborTrue ....嗯。当我运行2个程序时,我获得了3321次。预计为3321,因为它大约是9999的三分之一,这是上面的鸽子洞补充。我现在怀疑一个微弱的'cbrt(double x)'编码或一些有趣的四舍五入的设置。 – chux

1

你可能想,安德鲁猜测,全数字立方根。由于舍入误差,浮点数学非常棘手。一般来说,你不能依赖平等,但必须与误差相比较。

为了解决您的问题,虽然我想构造事先21个立方体,然后遍历整数,与预先构建的立方体进行比较。或者是作弊? ;-)

在塞缪尔·贝克特的小说“瓦特”中,有一段关于苏格兰“数学天才”的文章,他可以在他的脑海里计算出整数立方体的所有整数第三根,高达10000左右!

1

我的问题是,你的编译器在第二种情况下做了优化,eli敲入cbrt调用。它只是说cbrt的结果是严格定义的标准,所以它可能总是这种情况,(i == temp)

你可以通过一些命令行参数来绕过它,并强制它做到代码中写的是什么。我记得,这应该是C编译器关于浮动关节模型的默认事情,但你的编译器可能认为它比你更聪明。

编辑

是的,这个代码有没有关系找到完美的立方体...

编辑 完全不是一个问题的答案,但作为一个快速运动,这我写了这个:

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

static unsigned long count_cubes(unsigned long max_n) 
{ 
    unsigned long n = 1; 
    while (n*n*n <= max_n) { 
     ++n; 
    } 
    return n-1; 
} 

int main(int argc, char **argv) 
{ 
    unsigned long max_n; 
    char *p; 

    if (argc < 2) { 
     return EXIT_FAILURE; 
    } 
    max_n = strtoul(argv[1], &p, 10); 
    if (max_n < 1 || max_n == ULONG_MAX) { 
     return EXIT_FAILURE; 

    } 
    printf("%lu\n", count_cubes(max_n)); 
    return EXIT_SUCCESS; 
} 

注:不需要浮点运算

编辑

对不起,我做到了这...

这一个可以更快一点:

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

static unsigned long count_cubes(unsigned long max_n) 
{ 
    unsigned long n; 
    if (max_n < 256) { 
     n = 1; 
    } 
    else { 
     n = cbrtl(max_n) - 1; 
    } 
    while (n*n*n <= max_n) { 
     ++n; 
    } 
    return n-1; 
} 

int main(int argc, char **argv) 
{ 
    unsigned long max_n; 
    char *p; 

    if (argc < 2) { 
     return EXIT_FAILURE; 
    } 
    max_n = strtoul(argv[1], &p, 10); 
    if (max_n < 1 || max_n == ULONG_MAX) { 
     return EXIT_FAILURE; 

    } 
    printf("%lu\n", count_cubes(max_n)); 
    return EXIT_SUCCESS; 
} 

编辑(最后一次,我保证.. 。)

为了表示我的小环的解释上面,开始cbrt(max_n)-1,我尝试了一个由@chux建议,这里有一些结果与稍大的数字:

PerfectCubes(18446724184312856125) == 2642246

这是很好的,但也

PerfectCubes(18446724184312856125-10) == 2642246

这是完全不细,因为18446724184312856125 == 2642245^3,这意味着有2642245个完美的立方体< = 18446724184312856125-10。

这也是浮点表示不准确的结果。你可以自己试一试,如果你的电脑是有点类似地雷:

 printf("%f\n", cbrt(2642245UL * 2642245UL * 2642245UL)); 
    /* prints 2642245.000000 */ 
    printf("%f\n", cbrt(2642245UL * 2642245UL * 2642245UL - 10UL)); 
    /* prints 2642245.000000 */ 

这两个数字显然不具有相同的立方根,但cbrt返回相同的结果。在这种情况下,floor也没有帮助。无论如何,使用浮点算术总是需要非常小心。现在我真的应该去睡觉了。

相关问题