2013-05-08 24 views
20

Gần đây tôi đã đi qua một số dự án Euler dễ dàng và giải quyết chúng trong Ruby và C++. Nhưng đối với Problem 14 liên quan đến giả thuyết Collatz, mã C++ của tôi tiếp tục trong khoảng nửa giờ trước khi tôi chấm dứt nó, mặc dù khi tôi dịch mã thành Ruby, nó đã giải quyết nó trong chín giây.Tại sao mã Ruby này nhanh hơn mã C++ tương đương?

Sự khác biệt đó là điều không thể tin được đối với tôi - tôi luôn được tin rằng C++ gần như luôn nhanh hơn Ruby, đặc biệt đối với quy trình toán học.

Mã của tôi như sau.

C++:

#include <iostream> 

using namespace std; 

int main() 
{ 
    int a = 2; 
    int b = 2; 
    int c = 0; 
    while (b < 1000000) 
    { 

     a = b; 
     int d = 2; 
     while (a != 4) 
     { 
      if (a % 2 == 0) 
       a /= 2; 
      else 
       a = 3*a + 1; 
      d++; 
     } 
     if (d > c) 
     { 
      cout << b << ' ' << d << endl; 
      c=d; 
     } 
     b++; 
    } 
    cout << c; 
    return 0; 
} 

Run thời gian - Thực sự tôi không biết, nhưng đây là thời điểm thực sự REALLY dài.

và Ruby:

#!/usr/bin/ruby -w 

    a = 0 
    b = 2 
    c = 0 
    while b < 1000000 
     a = b; 
     d = 2 
     while a != 4 
      if a % 2 == 0 
       a /= 2 
      else 
       a = 3*a + 1 
      end 
      d+=1 
     end 
     if d > c 
      p b,d 
      c=d 
     end 
     b+=1 
    end 
    p c 

Run thời gian - khoảng 9 giây.

Bất kỳ ý tưởng gì đang xảy ra ở đây?

P.S. mã C++ chạy một giao dịch tốt hơn mã Ruby cho đến khi nó đạt đến 100.000.

+8

Thay đổi 'endl' thành' "\ n" ', vì nó thực hiện một luồng của luồng và IO không bị nén là rất chậm. –

+0

Làm thế nào để bạn biên dịch C++? – selalerer

+0

sẽ làm, nhưng khi nó đạt đến con số cao hơn, nó có thể chỉ mất vài phút giữa các bản in và sự khác biệt của endl và "\ n" sẽ trở nên không thể bỏ qua –

Trả lời

33

Bạn đang quá tải int, vì vậy nó không bị chấm dứt. Sử dụng int64_t thay vì int trong mã C++ của bạn. Có thể bạn sẽ cần phải bao gồm stdint.h cho điều đó ..

+0

như xa như tôi có thể nói rằng làm cho không có sự khác biệt đáng chú ý –

+4

Cải thiện câu trả lời của bạn, giải thích lý do tại sao ông là tràn int. – fotanus

+0

Bạn đang thử nghiệm trên máy 32 bit .. tôi đã cập nhật câu trả lời của mình để sử dụng int64_t thay vì int dài. – hexist

3

Trong trường hợp của bạn, sự cố là lỗi trong triển khai C++ (tràn số).

Lưu ý tuy nhiên đó giao dịch ở một số bộ nhớ bạn có thể nhận được kết quả nhanh hơn nhiều hơn bạn đang làm ...

Gợi ý: giả sử bạn thấy rằng từ số 231 bạn cần 127 bước để kết thúc việc tính toán, và giả sử bắt đầu từ một số khác bạn nhận được 231 sau 22 bước ... bạn cần phải thực hiện bao nhiêu bước nữa?

+0

vâng, tôi nghĩ về việc lưu các giá trị vào một mảng khi d> 100 nhưng sau đó tôi nghĩ, tôi thực sự muốn kiểm tra đối với một mảng lớn cho mỗi lần lặp của mọi số dưới một triệu? Tôi cho rằng nếu tôi giữ mọi thứ được sắp xếp và sử dụng tìm kiếm nhị phân và chỉ được kiểm tra khi 'a' rơi xuống dưới một đập (có lẽ 'b') nó sẽ làm cho nó chạy nhanh hơn, nhưng khi nó giải quyết trong nửa giây kháng cáo với tôi, mặc dù tôi sẽ làm như vậy nếu đây là một phần của một chương trình lớn hơn và được gọi là thường xuyên –

+0

Còn lưu trữ số đếm cho 'b' vào' count [b] 'thì sao? Không cần phải "tìm kiếm" ;-) – 6502

+0

Là số nguyên tràn thực sự là một lỗi * trong C + + thực hiện *? Không phải là hành vi không xác định? –

3

Với số học 32 bit, mã C++ tràn trên a = 3*a + 1. Với số học 32 bit đã ký, vấn đề là phức tạp, vì đường dây a /= 2 sẽ giữ lại bit dấu.

Điều này làm cho khó hơn nhiều đối với a đến 4 bằng và thực sự khi b đạt tới 113383, a tràn và vòng lặp không bao giờ kết thúc.

Với 64-bit số học không có tràn, vì a maxes out at 56991483520, khi b là 704511.

Nếu không nhìn vào toán học, tôi suy đoán rằng unsigned 32-bit số học sẽ "có thể" làm việc, bởi vì phép nhân và unsigned phân chia cả hai sẽ làm việc modulo 2^32. Và với thời gian chạy ngắn của chương trình, các giá trị sẽ không bao quát quá nhiều quang phổ 64 bit, vì vậy nếu giá trị bằng 4 modulo 2^32, thì "có thể" thực sự bằng 4.

Các vấn đề liên quan