2014-12-06 33 views
3

我在計算產生最長的Collat​​z序列的數字。但這是一個奇怪的問題。當n是3時,3n+1變爲38654705674。我沒有看到錯誤。這裏是全碼:運算符*和+在數字火星中產生錯誤的結果

/* 6.c -- calculates Longest Collatz sequence */ 
#include <stdio.h> 
long long get_collatz_length(long long); 
int main(void) 
{ 
    long long i; 
    long long current, current_count, count; 

    current_count = 1; 
    current = 1; 
    for(i=2;i<1000000;i++) 
    { 
     // works fine when i is 2 the next line take eternity when i is 3; 
     count = get_collatz_length(i); 
     if(current_count <= count) 
     { 
      current = i; 
      current_count = count; 
     } 
    } 
    printf("%lld %lld\n", current, current_count); 

    return 0; 
} 

long long get_collatz_length(long long num) 
{ 
    long long count; 

    count = 1; 
    while(num != 1) 
    { 
     printf("%lld\n", num); 
     if(num%2) 
     { 
      num = num*3+1;  // here it is; 
     } 
     else 
     { 
      num/=2; 
     } 
     count++; 
    } 
    puts(""); 
    return count; 
} 
+0

由於此行爲'count = get_collat​​z_length(i); 3',所以不會編譯。而'printf(「%lld%lld/n」,current,current_count);'不會打印出新行 – 2014-12-06 10:33:26

+0

啊!,它是上一行註釋的一部分。由於垂直滾動條,我只是將它移動到一行中。它不是代碼的一部分。謝謝你指出。 – silentboy 2014-12-06 10:35:42

+0

什麼是你的平臺上的'sizeof(long long)'? – slugonamission 2014-12-06 10:35:51

回答

6

這似乎是錯誤的dmc編譯器,卻不能正確處理long long類型。這裏變窄測試用例:

#include <stdio.h> 

int main(void) 
{ 
    long long num = 3LL; 

    /*printf("%lld\n", num);*/ 

    num = num * 3LL; 

    char *t = (char *) &num; 
    for (int i = 0; i < 8; i++) 
     printf("%x\t", t[i]); 
    putchar('\n'); 

    /*printf("%lld\n", num);*/ 

    return 0; 
} 

它產生(小端,所以0x900000009 == 38 654 705 673):

9  0  0  0  9  0  0  0 

從dissasembly它看起來它存儲64位整數作爲兩個32位寄存器:

.data:0x000000be 6bd203 imul edx,edx,0x3 
.data:0x000000c1 6bc803 imul ecx,eax,0x3 
.data:0x000000c4 03ca add ecx,edx 
.data:0x000000c6 ba03000000 mov edx,0x3 
.data:0x000000cb f7e2 mul edx 
.data:0x000000cd 03d1 add edx,ecx 
.data:0x000000cf 31c0 xor eax,eax 

我additionaly與objconv工具測試它,這恰恰印證了我的初步診斷:

#include <stdio.h> 

void mul(void) 
{ 
    long long a; 
    long long c; 

    a = 5LL; 
    c = a * 3LL; 

    printf("%llx\n", c); 
} 

int main(void) 
{ 
    mul(); 

    return 0; 
} 

拆裝(單節):

>objconv.exe -fmasm ..\dm\bin\check.obj 

_mul PROC NEAR 
     mov  eax, 5         ; 0000 _ B8, 00000005 
     cdq            ; 0005 _ 99 
     imul edx, edx, 3        ; 0006 _ 6B. D2, 03 
     imul ecx, eax, 3        ; 0009 _ 6B. C8, 03 
     add  ecx, edx        ; 000C _ 03. CA 
     mov  edx, 3         ; 000E _ BA, 00000003 
     mul  edx          ; 0013 _ F7. E2 
     add  edx, ecx        ; 0015 _ 03. D1 
     push edx          ; 0017 _ 52 
     push eax          ; 0018 _ 50 
     push offset FLAT:?_001      ; 0019 _ 68, 00000000(segrel) 
     call _printf         ; 001E _ E8, 00000000(rel) 
     add  esp, 12         ; 0023 _ 83. C4, 0C 
     ret            ; 0026 _ C3 
_mul ENDP 

注意mul edxeax隱含操作。結果存儲在兩個寄存器中,較高的部分(在這種情況下爲0)存儲在edx中,而較低的部分存儲在eax中。

+0

哇,這看起來很嚴重:( – Dai 2014-12-06 11:48:07

+0

非常好,我會選擇一個替代方案。'char * t =(char *)#'garanteed工作嗎? – silentboy 2014-12-06 12:33:07

+2

@silentboy:是的,但它有點偏執,'printf(「%llx \ n」,num);'也顯示正確的十六進制值。 – 2014-12-06 12:41:35