2006/07/06

競速

決定來一次 C / C++ / Java / Ruby ACM#100 競速大亂鬥(Common Lisp 還不行 XD)。以下是各種語言的程式碼,以自然為主,不特地做 tweak。程式邏輯均相同,變數名稱儘量維持一致:

 1: /* ACM#100 in C */
 2: 
 3: #include <stdio.h>
 4: 
 5: int main() {
 6:   int i, j, temp, k, max, kk, count;
 7:   while (scanf("%d%d", &i, &j) == 2) {
 8:     printf("%d %d ", i, j);
 9:     if (i > j) {
10:       temp = j;
11:       j = i;
12:       i = temp;
13:     }
14:     max = 0;
15:     for (k = i; k <= j; ++k) {
16:       kk = k;
17:       count = 1;
18:       while (kk != 1) {
19:         kk = kk % 2 ? kk * 3 + 1 : kk / 2;
20:         ++count;
21:       }
22:       if (count > max) {
23:         max = count;
24:       }
25:     }
26:     printf("%d\n", max);
27:   }
28:   return 0;
29: }

 1: // ACM#100 in C++
 2: 
 3: #include <algorithm>
 4: #include <iostream>
 5: using namespace std;
 6: 
 7: int main() {
 8:   int i, j;
 9:   while(cin >> i >> j){
10:     cout << i << ' ' << j << ' ';
11:     if (i > j) {
12:       swap(i, j);
13:     }
14:     int max = 0;
15:     for (int k = i; k <= j; ++k) {
16:       int kk = k;
17:       int count = 1;
18:       while (kk != 1) {
19:           kk = kk % 2 ? kk * 3 + 1 : kk / 2;
20:         ++count;
21:       }
22:       if (count > max) {
23:         max = count;
24:       }
25:     }
26:     cout << max << endl;
27:   }
28: }

 1: // ACM#100 in Java
 2: 
 3: import java.io.*;
 4: import java.util.*;
 5: 
 6: public class ACM100 {
 7:   public static void main(String[] args) throws Exception {
 8:     Scanner in = new Scanner(System.in);
 9:     int i, j;
10:     while(in.hasNextInt()) {
11:       i = in.nextInt();
12:       j = in.nextInt();
13:       System.out.print(i + " " + j + " ");
14:       if (i > j) {
15:         int temp = j;
16:         j = i;
17:         i = temp;
18:       }
19:       int max = 0;
20:       for (int k = i; k <= j; ++k) {
21:         int count = 1;
22:         int kk = k;
23:         while (kk != 1) {
24:           kk = kk % 2 == 0 ? kk / 2 : 3 * kk + 1;
25:           ++count;
26:         }
27:         if (max < count) {
28:           max = count;
29:         }
30:       }
31:       System.out.println(max);
32:     }
33:   }
34: }

 1: # ACM#100 in Ruby
 2: 
 3: while s = gets
 4:   i, j = s.split(/\s+/).collect {|t| t.to_i}
 5:   i, j = j, i if i > j
 6:   print "#{i} #{j} "
 7:   max = 0
 8:   (i..j).each do |k|
 9:     count = 1
10:     until k == 1
11:       k = k % 2 == 0 ? k / 2 : 3 * k + 1
12:       count += 1
13:     end
14:     max = count if max < count
15:   end
16:   puts max
17: end

然後是協助我加上行號的 Ruby script lineno

1: #!/usr/local/bin/ruby -w
2: 
3: a = readlines
4: for i in 0...a.length
5:   printf("%#{(Math.log10(a.length) + 1).to_i}d: %s", i + 1, a[i])
6: end

以及擔任本次大亂鬥評審的 Ruby script timer

1: #!/usr/local/bin/ruby -w
2: 
3: s = ARGV[0]
4: s = s[1...-1] if s[0] == '"'
5: t1 = Time.now
6: system(s)
7: t2 = Time.now
8: printf("elapsed time: %.6f second(s).\n", t2.to_f - t1.to_f)

C/C++ 編譯時不開最佳化。測試時,皆將「內含一行 "1 100000" 的檔案」重新導向(redirect)到程式的 stdin。以下是結果:

語言CC++JavaRuby
秒數0.2090.2050.64227.635
比值1.02013.132134.805

其中「比值」是對「最少秒數」(C++)的比值。

雖然這次競速中,C 小輸 C++,但兩者實際上相差無幾,誰贏只是機率問題。這很顯然,因為這次競速用的程式碼,幾乎落在 C++ 的 "better C" paradigm 裡面(即 Scott Meyers 所謂的 C part of C++)。而且此次競速的 I/O 並不大量,若給多筆測資,C++ iostream 應該就得敗給 C stdio。Java VM 雖然帶有 JIT 技術,但終究多了一道間接層,比 C/C++ 慢了三倍。Ruby 就不用說了,要拚速度絕不是對手。On the other hand,Ruby 的程式碼看起來真的比較清爽一些,尤其和 Java 相比 :P。

Blogger yen37/06/2006 4:50 pm 說:

一次看那麼多程式碼
重要的是,大概都能看種,真是一件令人高興的事
ruby慢到讓我覺得神奇啊...這其中必然有原因,不僅僅只是script language而己

 

<< 回到主頁