hôm bữa có test cái ruby tính giai thừa trong tích tắc làm anh em mê đắm thì xin mời đội ruby vô giải thích lý giải cái này cho cái.
đã test trong python chạy nhanh không kém test giới hạn của nó là 984.
Mời anh em chém gió tiếp.
Vấn đề này là mời anh Đôn vào trả lời. Nhưng mà giờ mình cũng có câu hỏi là cấu trúc dữ liệu của Python như thế nào mà nó cũng xử lí nhanh như bên Ruby vậy? Hehe, mời bác ![]()
P.S: mà hôm bữa anh An tính giai thừa bằng vòng lặp nó cũng nhanh không kém mà giới hạn lên tới hơn 4 chữ số :))
A.Đôn đâu rồi?
[QUOTE=09520134;2581]Vấn đề này là mời anh Đôn vào trả lời. Nhưng mà giờ mình cũng có câu hỏi là cấu trúc dữ liệu của Python như thế nào mà nó cũng xử lí nhanh như bên Ruby vậy? Hehe, mời bác ![]()
P.S: mà hôm bữa anh An tính giai thừa bằng vòng lặp nó cũng nhanh không kém mà giới hạn lên tới hơn 4 chữ số :))[/QUOTE]
Nó chuyển đổi về mảng các bit để thao tác. (Đọc [1] để biết thêm chi tiết )
Quá trình chọn kiểu giữa int hay float xảy ra tự động bên trong ngôn ngữ , tùy thuộc vào khả năng lưu trữ 1 word của máy , nếu vượt quá thì nó sẽ chuyến sang lưu trữ dựa trên bộ nhớ của máy .
Ví dụ về quá trình chuyển đổi này :
Trước hết ta cần một hàm cho về một số cực lớn , chẳng hạn như hàm tính toán giai thừa như sau :
def back_mul(x):
if(x>1):
i = 2
s = 1
while(i <= x ):
s = s * i
i +=1
return s
def fact(x):
if x == 0 or x == 1 :
return 1
else :
return back_mul(x)
Thử xem , với hàm fact(x) này thì với x bằng mấy thì quá trình chuyển kiểu từ int sang long diễn ra :
if __name__ == '__main__':
count = 0
while(str(type(fact(count))) == "<type 'int'>"):
count += 1
print "the bigest value of count is : %s" %(count )
Kết quả :
>>>
the bigest value of count is : 13
>>>
Với giá trị x = 13 này , số bit ta cần để lưu trữ giá trị (ở dạng nhị phân là ) :
>>> long.bit_length(fact(13))
==>
33
Với x = 12 thì sao ? fact(12) trả về kết quả kiểu int
>>> type(fact(12))
>>> <type 'int'>
hoặc
>>> isinstance(fact(12) , int)
>>> True
>>> s = bin(fact(12))
>>> len(s[2:len(s)]
Kết quả là :
29
Thử cái nào to hơn tí !
>>> long.bit_length(fact(2000))
19053
>>>
tham khảo :
[1] http://www.python.org/dev/peps/pep-0237/
[2] http://stackoverflow.com/questions/5295903/how-many-bits-does-a-word-contain-in-32-64-bit-os-respectively
[3] http://stackoverflow.com/questions/538551/handling-very-large-numbers-in-python
Sorry cả nhà for delay! ![]()
Dạ, điều đầu tiên em muốn nói là về nhận định của các “chuyên gia trong ngành” về Bignum:
- Ưu điểm: Không giới hạn
- Khuyết điểm: + CHẬM (Ngược với những gì em và các bác “cảm thấy” nhỉ?!
)
+ Tốn bộ nhớ.
Vậy giờ chúng ta sẽ từng bước tìm hiểu sao lại có các nhận định này!
Hmmm, bắt đầu với cái gì giờ nhỉ?
, chẹp, data struct trước nhen.:eek:
struct RBignum {
00837 struct RBasic basic;
00838 union {
00839 struct {
00840 long len;
00841 BDIGIT *digits;
00842 } heap;
00843 BDIGIT ary[RBIGNUM_EMBED_LEN_MAX];
00844 } as;
00845 };
ruby.h
À chết quên mất, trước tiên các bác cần đọc về objects structures của Ruby tại http://rhg.rubyforge.org/chapter02.html đã nhen. (Em đi làm tách trà chờ các bác đã.:D)
…
…
Xong rồi đúng hok cả nhà? ;;). Nào, đầu tiên ta thấy gì nhỉ? Thay vì lưu trữ số dưới dạng nhị phân như thông thường, Bignum lưu số dưới dạng một dãy các số thập phân, sau đó thì Bignum sử dụng những math function của máy tính để tính toán số học như…cách mà chúng ta làm trên giấy vậy! :rolleyes: → Chính điều này khiến Bignum chậm. Haizz!
Như chúng ta đã biết thì số nguyên 32 bits có thể lưu được một trời ơi số (trong khoảng của nó) chỉ trong vòng 4 byte, nhưng với Bignum? 4 byte chỉ lưu được 4 CHỮ SỐ! → Quá tốn bộ nhớ! Nhưng bù lại được cái ưu điểm là không giớ hạn về kích thước, trên lý thuyết thì các bác có thể làm việc với số SIÊU LỚN (có thể vượt quá cả số lượng RAM mà các bác có! Nhưng nhớ, đây là trên lý thuyết nhá! Haha) Và em đã thử với tình giai thừa tới 12000, vẫn bỉnh thường!:rolleyes:
Giờ chúng ta xem thử cách mà Ruby khởi tạo một số lớn nha:
00133 static VALUE
00134 bignew_1(VALUE klass, long len, int sign)
00135 {
00136 NEWOBJ(big, struct RBignum);
00137 OBJSETUP(big, klass, T_BIGNUM);
00138 RBIGNUM_SET_SIGN(big, sign?1:0);
00139 if (len <= RBIGNUM_EMBED_LEN_MAX) {
00140 RBASIC(big)->flags |= RBIGNUM_EMBED_FLAG;
00141 RBIGNUM_SET_LEN(big, len);
00142 }
00143 else {
00144 RBIGNUM(big)->as.heap.digits = ALLOC_N(BDIGIT, len);
00145 RBIGNUM(big)->as.heap.len = len;
00146 }
00147
00148 return (VALUE)big;
00149 }
00150
00151 #define bignew(len,sign) bignew_1(rb_cBignum,len,sign)
00152
00153 VALUE
00154 rb_big_new(long len, int sign)
00155 {
00156 return bignew(len, sign != 0);
00157 }
bignum.c
rồi đến xem thử phương thức cộng 2 số nữa:
VALUE
01886 rb_big_plus(VALUE x, VALUE y)
01887 {
01888 long n;
01889
01890 switch (TYPE(y)) {
01891 case T_FIXNUM:
01892 n = FIX2LONG(y);
01893 if ((n > 0) != RBIGNUM_SIGN(x)) {
01894 if (n < 0) {
01895 n = -n;
01896 }
01897 return bigsub_int(x, n);
01898 }
01899 if (n < 0) {
01900 n = -n;
01901 }
01902 return bigadd_int(x, n);
01903
01904 case T_BIGNUM:
01905 return bignorm(bigadd(x, y, 1));
01906
01907 case T_FLOAT:
01908 return DBL2NUM(rb_big2dbl(x) + RFLOAT_VALUE(y));
01909
01910 default:
01911 return rb_num_coerce_bin(x, y, '+');
01912 }
01913 }
bignum.c
Về cơ bản là vậy các bác ạ, còn việc sao cả nhà mình cảm thấy nhanh thế, em chỉ còn biết nghĩ đến: Cảm ơn các nhà thiết kế phần cứng! :">
Có vẻ như với cấu trúc dữ liệu như vậy thì bên Python xử lí nhanh hơn nhỉ. Nhưng mà thôi kệ test thử chơi cho biết. Mình thử tính thời gian thực thi hàm tính giai thừa bằng đệ quy với tham số truyền vào là 5000 thử xem thằng nào tính nhanh hơn ![]()
def fact(n)
if n==0
1
else
n*fact(n-1)
end
end
begin_time = Time.now
result = fact(5000)
end_time = Time.now
puts "Execution time = #{(end_time - begin_time) * 1000} milliseconds
Kết quả:

Bên python show hàng thử đi ![]()
[QUOTE=09520134;2589]Có vẻ như với cấu trúc dữ liệu như vậy thì bên Python xử lí nhanh hơn nhỉ. Nhưng mà thôi kệ test thử chơi cho biết. Mình thử tính thời gian thực thi hàm tính giai thừa bằng đệ quy với tham số truyền vào là 5000 thử xem thằng nào tính nhanh hơn ![]()
[/QUOTE]
Tình hình là như vậy là không thể so sánh được nha Khải! ![]()
Sao vậy ![]()
[QUOTE=09520134;2592]Sao vậy :([/QUOTE]
Đồng ý với ý kiến của bạn Đôn , không thể so sánh được như trên , bởi trong khoảng thời gian từ khi gọi :
begin_time = Time.now
và
end_time = Time.now
Hàm fact() không nhất thiết được thực hiện liên tục , điều này phụ thuộc vào việc cấp phát tài nguyên CPU của hệ điều hành .
Có thể trong thời gian này ,có thể có rất nhiều tiến trình khác xen vào :-ss
Thế nên không thể so sánh đơn giản như vậy được
Sử dụng vòng lặp thay vì đệ quy, tính giai thừa của 100.000. Chạy khi máy đang rảnh (Ctrl + Alt + F1, login và test bằng dòng lệnh thay vì vào X), vẫn có thể có một so sánh tương đối, thử đi.
Và dù là trong điều kiện lý tưởng, tức là mình nó chạy thì cũng chẳng thể so sánh vậy được, CPU khác nhau, khả năng tính toán cũng khác nhau rồi! ![]()
[QUOTE=07520004;2594]Sử dụng vòng lặp thay vì đệ quy, tính giai thừa của 100.000. Chạy khi máy đang rảnh (Ctrl + Alt + F1, login và test bằng dòng lệnh thay vì vào X), vẫn có thể có một so sánh tương đối, thử đi.[/QUOTE]
limit của nó là 984 anh ![]()
nhân tiện hỏi vì sao limit của nó là 984 :-?
[QUOTE=09520017;2596]limit của nó là 984 anh ![]()
nhân tiện hỏi vì sao limit của nó là 984 :-?[/QUOTE]
Đọc kỹ cái câu “sử dụng vòng lặp thay vì đệ quy” chứ
@Đôn: Chạy trên cùng một máy chứ ai điên lại chạy trên 2 máy khác nhau
[QUOTE=07520004;2604]Đọc kỹ cái câu “sử dụng vòng lặp thay vì đệ quy” chứ
@Đôn: Chạy trên cùng một máy chứ ai điên lại chạy trên 2 máy khác nhau[/QUOTE]
Tại thấy chú Khải đang có ý định đó mà!![]()
Ý định của em là test 2 thằng Python với Ruby chứ đâu có nói là phải test trên 2 máy đâu :))
[QUOTE=07520004;2604]Đọc kỹ cái câu “sử dụng vòng lặp thay vì đệ quy” chứ
@Đôn: Chạy trên cùng một máy chứ ai điên lại chạy trên 2 máy khác nhau[/QUOTE]
thế à thế thì vì sao đệ quy limit của nó 984 :-?
[QUOTE=09520134;2614]Ý định của em là test 2 thằng Python với Ruby chứ đâu có nói là phải test trên 2 máy đâu :))[/QUOTE]
Nhưng ý em là để cho bên kia chạy Python bên máy họ thì thành 2 máy mất tiêu rồi còn đâu! ![]()
[pntruongan@myhost ~]$ for i in {1…5} ; do ruby test.rb ; done
Execution time = 16665.249226 milliseconds
Execution time = 16770.90626 milliseconds
Execution time = 17424.745088000003 milliseconds
Execution time = 11975.103197999999 milliseconds
Execution time = 8119.571873 milliseconds
[pntruongan@myhost ~]$ for i in {1…5} ; do python test.py ; done
Excution take 15.000612020492554 seconds
Excution take 14.943933010101318 seconds
Excution take 14.681034803390503 seconds
Excution take 14.694528818130493 seconds
Excution take 14.696242094039917 seconds
[pntruongan@myhost ~]$ for i in {1…5} ; do ruby test.rb ; done
Execution time = 16998.403903 milliseconds
Execution time = 17213.061538 milliseconds
Execution time = 16735.761197 milliseconds
Execution time = 17109.171642 milliseconds
Execution time = 17592.870357 milliseconds
[pntruongan@myhost ~]$ for i in {1…5} ; do python test.py ; done
Excution take 14.777976036071777 seconds
Excution take 14.74532413482666 seconds
Excution take 14.618777990341187 seconds
Excution take 6.212836027145386 seconds
Excution take 14.822159051895142 seconds
Các chú cứ chém lung tung quá, anh ra tay đây. Tính giai thừa của Một trăm ngàn (100000) bằng python và ruby, ghi lại kết quả của 5 lần chạy. Ai đưa ra nhận xét và lý giải phát nào
Ới, Ruby chạy nhanh thế cơ áh. Python mần tới 1x seconds luôn… Mà pro nào giải thích đi nhỉ, đặt gạch ngồi nghe ngóng tin tức ![]()
[QUOTE=07520004;2622][pntruongan@myhost ~]$ for i in {1…5} ; do ruby test.rb ; done
Execution time = 16665.249226 milliseconds
Execution time = 16770.90626 milliseconds
Execution time = 17424.745088000003 milliseconds
Execution time = 11975.103197999999 milliseconds
Execution time = 8119.571873 milliseconds
[pntruongan@myhost ~]$ for i in {1…5} ; do python test.py ; done
Excution take 15.000612020492554 seconds
Excution take 14.943933010101318 seconds
Excution take 14.681034803390503 seconds
Excution take 14.694528818130493 seconds
Excution take 14.696242094039917 seconds
[pntruongan@myhost ~]$ for i in {1…5} ; do ruby test.rb ; done
Execution time = 16998.403903 milliseconds
Execution time = 17213.061538 milliseconds
Execution time = 16735.761197 milliseconds
Execution time = 17109.171642 milliseconds
Execution time = 17592.870357 milliseconds
[pntruongan@myhost ~]$ for i in {1…5} ; do python test.py ; done
Excution take 14.777976036071777 seconds
Excution take 14.74532413482666 seconds
Excution take 14.618777990341187 seconds
Excution take 6.212836027145386 seconds
Excution take 14.822159051895142 seconds
Các chú cứ chém lung tung quá, anh ra tay đây. Tính giai thừa của Một trăm ngàn (100000) bằng python và ruby, ghi lại kết quả của 5 lần chạy. Ai đưa ra nhận xét và lý giải phát nào[/QUOTE]
Sao bất chợt nó chạy nhanh ta ?