2014-03-31 104 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也沒有幫助。無論如何,使用浮點算術總是需要非常小心。現在我真的應該去睡覺了。

相關問題