运算符*和+在数字火星中产生错误的结果

时间:2014-12-06 10:25:51

标签: c

我正在尝试计算产生最长Collat​​z序列的数字。但这是一个奇怪的问题。当3n+1为3时,38654705674变为n。我没有看到错误。这是完整的代码:

/* 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;
}

1 个答案:

答案 0 :(得分: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

我还使用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 edx会对eax进行隐含操作。结果存储在两个寄存器中,较高部分(在本例中为0)存储在edx中,而较低部分存储在eax中。