Develop and Download Open Source Software

Browse Subversion Repository

Annotation of /branches/mty-makai/mty.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 253 - (hide annotations) (download) (as text)
Mon Dec 27 09:22:27 2010 UTC (13 years, 3 months ago) by notanpe
File MIME type: text/x-csrc
File size: 14302 byte(s)
とりあえず今の開発環境で動くように変更。
1 chapuni 1 /***********************************************************************
2     *
3 chapuni 26 * file: mty.c
4 chapuni 1 *
5 chapuni 2 * まあ、待て屋。
6 chapuni 1 *
7     * $Id$
8     *
9     */
10    
11     #include <assert.h>
12 chapuni 20 #include <stddef.h>
13 chapuni 1 #include <stdio.h>
14     #include <time.h>
15 notanpe 192 #include <sys/timeb.h>
16 chapuni 10
17     #if defined(WIN32)
18    
19     #include <windows.h>
20 notanpe 148 #include <process.h>
21 chapuni 10
22     #elif defined(__GNUC__)
23    
24     #include <sys/time.h>
25    
26     #endif
27    
28 chapuni 41 #include "desconst.h"
29 chapuni 46 #include "expr_parse.h"
30 notanpe 252 #include "hit.h"
31     #include "key.h"
32     #include "log.h"
33 chapuni 46 #include "scoreboard.h"
34     #include "synth.h"
35 notanpe 148 #include "util.h"
36 chapuni 1
37 notanpe 252 static HANDLE mutex_key;
38 notanpe 198
39 notanpe 192 /* CRYPT64 記述子 */
40     static
41     struct CRYPT64_DESC const *const crypt64_descs[] =
42     {
43     &crypt64_desc,
44     };
45    
46 notanpe 252 /* 速度評価用 */
47     static int n_cpus;
48     static uint64_t loop_cpu[1024];
49 chapuni 1
50 notanpe 192 #define USEC_SEC 1000 /* 1秒 */
51    
52 chapuni 1 static
53 notanpe 192 uint64_t
54 notanpe 148 usec(void)
55 notanpe 119 {
56 notanpe 120 uint32_t sec, msec;
57    
58 notanpe 119 #if !defined(WIN32)
59     struct timeval tv;
60     gettimeofday(&tv, NULL);
61 notanpe 120 sec = tv.tv_sec;
62 notanpe 192 msec = tv.tv_usec / (1000000 / USEC_SEC);
63 notanpe 119 #else
64     struct timeb tm;
65     ftime(&tm);
66 notanpe 120 sec = tm.time;
67 notanpe 192 msec = tm.millitm / (1000 / USEC_SEC);
68 notanpe 119 #endif
69 notanpe 120
70 notanpe 192 return (uint64_t)USEC_SEC * sec + msec;
71 notanpe 119 }
72    
73 chapuni 1 /***************************************************************
74     *
75 notanpe 192 * CPU capabilities を取得
76     * [XXX] あまりにも古いプロセッサのことは考えない。
77 chapuni 1 *
78 notanpe 192 * a[4] = {EAX,EBX,ECX,EDX}
79     *
80 chapuni 1 */
81    
82 notanpe 192 #if defined(__GNUC__)
83    
84     #define cpuid(n,a,b,c,d) \
85     asm("cpuid" \
86     : "=a"(a), "=b"(b), "=c"(c), "=d"(d) \
87     : "a"(n))
88    
89     #elif defined(WIN32)
90    
91     #define cpuid(n,a,b,c,d) \
92     do {int r[4]; __cpuid(r,n); \
93     (a) = r[0]; (b) = r[1]; (c) = r[2]; (d) = r[3];} while (0)
94    
95     #endif
96    
97     static
98     unsigned
99     cpuid_getfflags(void)
100 notanpe 148 {
101 notanpe 192 unsigned a, b, c, d;
102     cpuid(1, a, b, c, d);
103     return d;
104     }
105 chapuni 1
106 notanpe 148 static
107 notanpe 192 int
108     cpuid_issupported(void)
109     {
110     unsigned m = REQUIRED_CAPS;
111     return !((cpuid_getfflags() ^ m) & m);
112     }
113    
114     /***************************************************************
115     *
116     * バッチ処理用パケット
117     *
118     */
119    
120     static
121 notanpe 148 struct PACKET_CRYPT64 *
122     packet_create(int n, /* パケット数 */
123     int tn, /* 末尾要素にて必要なワーク数 */
124     uint8_t const *ini_key)
125     {
126     int i;
127     int siz;
128     void *p;
129 notanpe 192 intptr_t a = 128;
130 notanpe 148 struct PACKET_CRYPT64 *pkts;
131     assert(IS_POWER2(sizeof(struct PACKET_CRYPT64)));
132     assert(n >= 1);
133    
134 notanpe 192 siz = (a - 1
135 notanpe 148 + (n - 1) * sizeof(struct PACKET_CRYPT64)
136     + offsetof(struct PACKET_CRYPT64, param64.hit[tn]));
137     p = calloc(siz, 1);
138     /* バンダリあわせ */
139     pkts = (struct PACKET_CRYPT64 *)(((intptr_t)p
140 notanpe 192 + a - 1)
141     & -a);
142 notanpe 148 #if DEBUG>=1
143     fprintf(stderr,
144     "packet(n=%d,tn=%d) %d allocated; %p aligned to %p\n",
145     n, tn,
146     siz, p, pkts);
147     #endif
148    
149     /* 内部の初期化
150     コピーして回るのは、厳密には
151     最終要素のケツを破ってしまうことになるので
152     どうせ速度も要求されないしベタコード */
153     for (i = 0; i < n; i++)
154     {
155 notanpe 192 int j, k;
156 notanpe 148
157     /* t[16] は、内部演算で使用する、all 1 が入っている */
158     memset(&pkts[i].param64.t[T_INV], -1, sizeof(SLICE));
159    
160     /* 固定キーの生成 */
161     key_init_sk(&pkts[i].key64);
162    
163     /* キースケジュールをここに押し込めておく
164     従来は crypt64.S 内で完結するように引いていた */
165     for (j = 0; j < 28; j++)
166 notanpe 192 for (k = 0; k < N_ALU; k++)
167     pkts[i].key64.ks[j].a[k] = sizeof(WS_T) * ks_ls[j];
168 notanpe 148
169     /* 念のため、鍵をここで落ち着けておく(不要?) */
170     for (j = 0; j < 8; j++)
171     key_set64(&pkts[i].key64, j, pkts[i].uk.key[j] = ini_key[j], 0, 0x7F);
172     }
173    
174     return pkts;
175     }
176    
177     /***************************************************************
178     *
179     * thread
180     *
181     */
182    
183     #if defined(__GNUC__)
184    
185     typedef int32_t ATOMWORD_T;
186    
187     #define LOCK_INC(p) \
188     asm volatile ("lock incl %0" \
189     : "=m"(*(p)) \
190     : /*nil*/ \
191     : "memory")
192    
193     #define LOCK_DEC(p) \
194     asm volatile ("lock decl %0" \
195     : "=m"(*(p)) \
196     : /*nil*/ \
197     : "memory")
198    
199     #define LOCK_CAS(pd,s,r) \
200     ({ ATOMWORD_T a; \
201     asm volatile ("lock cmpxchg %2,%1" \
202     : "=a"(a) \
203     : "m"(*(pd)), "r"(s), "0"(r) \
204     : "memory");a;})
205    
206     #define LOCK_CASP(pd,s,r) \
207     ({ void *a; \
208     asm volatile ("lock cmpxchg %2,%1" \
209     : "=a"(a) \
210     : "m"(*(pd)), "r"(s), "0"(r) \
211     : "memory");a;})
212    
213     #elif defined(WIN32)
214    
215     typedef LONG ATOMWORD_T;
216    
217     #define LOCK_INC(p) InterlockedIncrement((LONG *)(p))
218     #define LOCK_DEC(p) InterlockedDecrement((LONG *)(p))
219     #define LOCK_CAS(pd,s,r) InterlockedCompareExchange((LONG *)(pd), s, r)
220     #define LOCK_CASP(pd,s,r) InterlockedCompareExchangePointer((PVOID *)(pd), (PVOID)(s), (PVOID)r)
221    
222     #else
223     #error "configuration not implemented"
224     #endif
225    
226     #if defined(WIN32)
227    
228     typedef DWORD THREAD_TIMEOUT_T;
229    
230     #define THREAD_INFINITE INFINITE
231    
232     typedef HANDLE THREAD_TH_T;
233    
234     #define thread_sleep(n) Sleep(n)
235     #define thread_create(th, proc, arg) {(th) = (HANDLE)_beginthread(proc, 8192, arg);}
236     #define thread_get_tid() GetCurrentThread()
237     #define thread_set_priority(tid,n) SetThreadPriority(tid, n)
238     #define thread_set_affinity(tid,m) SetThreadAffinityMask(tid, (DWORD_PTR)1 << (m))
239    
240 notanpe 252 #elif defined(_POSIX_SOURCE)
241 notanpe 148
242     #include <pthread.h>
243     #include <unistd.h>
244    
245     typedef int THREAD_TIMEOUT_T;
246    
247     #define THREAD_INFINITE INT_MAX
248    
249     #if defined(THREAD_PRIORITY_BELOW_NOROMAL) || defined(THREAD_PRIORITY_IDLE)
250     #error "unsupported implementation"
251     #endif
252    
253     #define THREAD_PRIORITY_NORMAL 14
254     #define THREAD_PRIORITY_BELOW_NORMAL 15
255     #define THREAD_PRIORITY_IDLE 16
256    
257     typedef pthread_t THREAD_TH_T;
258    
259     #define thread_sleep(n) (usleep(1000 * (n)) != EINVAL || sleep((n) / 1000))
260     #define thread_create(th, proc, arg) thread_create_p(&(th), proc, arg)
261    
262     static
263     void
264     thread_create_p(pthread_t *th, NORETURN (*proc)(void *), void *param)
265     {
266     pthread_create(th, NULL, (void *(*)(void *))proc, param);
267     }
268    
269     #if defined(__linux__)
270    
271     /* デフォルトスケジューリングポリシーでは
272     優先度設定したりアイドルスレッド起こしても
273     おもしろくないので、そのへんは今後の研究課題。 */
274    
275     #include <linux/unistd.h>
276     _syscall0(pid_t,gettid)
277    
278     #define thread_get_tid() gettid()
279    
280     static
281     int thread_set_affinity(pid_t tid, int i)
282     {
283     cpu_set_t m;
284     CPU_ZERO(&m);
285     CPU_SET(i, &m);
286     return sched_setaffinity(tid, sizeof(m), &m);
287     }
288    
289     #else
290    
291     /* POSIX では、スレッド単位のスケジューリングに介入できない。 */
292    
293     #endif
294    
295     #else
296     #error "configuration not supported"
297     #endif
298    
299     struct THREAD_PARAM
300     {
301     /* 以下は共通情報のコピー */
302     CODE_T *code;
303 notanpe 253 long code_cmp;
304 notanpe 252 unsigned seed;
305 notanpe 148
306     /* 以下はスレッド固有 */
307     #ifdef thread_set_priority
308     int pri;
309     #endif
310     };
311    
312     static
313     uint64_t
314     thread_avail(void)
315     {
316     #if !USE_MT
317    
318     return 0x1U;
319    
320     #elif defined(WIN32) /* Win32 API */
321     DWORD_PTR mask, mask_s;
322     if (!GetProcessAffinityMask(GetCurrentProcess(),
323     &mask,
324     &mask_s)
325     || !mask
326     || !mask_s)
327     return 0x1U;
328     #if DEBUG>=1
329     fprintf(stderr,
330     "m=%08X s=%08X\n",
331     (unsigned)mask,
332     (unsigned)mask_s);
333     #endif
334     if (popcnt64(mask_s) == 1)
335     /* 何も言うまい */;
336     else if (mask == mask_s)
337     fprintf(stderr,
338     "通常の%d倍とはよく言ったものです。\n",
339     popcnt64(mask));
340     else
341     fprintf(stderr,
342     "最高速力の%g倍の力でてきとうにがんばるよ。\n",
343     (double)popcnt64(mask) / popcnt64(mask_s));
344     return mask;
345    
346     #elif defined(__linux__) /* sched.h 拡張 */
347    
348     int i;
349     uint64_t m = 0;
350     cpu_set_t am;
351     if (sched_getaffinity(getpid(), sizeof(am), &am) < 0)
352     return 0x1U;
353    
354     for (i = 0; i < 64 && i < CPU_SETSIZE; i++)
355     if (CPU_ISSET(i, &am))
356     m |= 1ULL << i;
357    
358     return m;
359     #else
360    
361     /* XXX プロセッサ数を調べ上げてください */
362     return 0x01U;
363    
364     #endif
365     }
366    
367     static
368     NORETURN
369 notanpe 252 thread_crypt64_new(void *a_param)
370 notanpe 148 {
371 notanpe 252 struct THREAD_PARAM *param = a_param;
372     CODE_T *code = param->code;
373     CODE_T *cmp = code + param->code_cmp;
374     struct KS_KEY key;
375     struct PACKET_CRYPT64 *pkt = packet_create(16, 1024, key.key);
376     uint64_t *ploop;
377     THREAD_TH_T th = thread_get_tid();
378 notanpe 148
379 notanpe 252 WaitForSingleObject(mutex_key, INFINITE);
380 notanpe 148
381 notanpe 252 ploop = &loop_cpu[n_cpus++];
382 notanpe 148
383 notanpe 252 srand(usec() ^ param->seed ^ (unsigned)th);
384     key_init(&key);
385     ReleaseMutex(mutex_key);
386 notanpe 148
387     #ifdef thread_set_priority
388 notanpe 252 thread_set_priority(th, param->pri);
389 notanpe 148 #endif
390    
391 notanpe 252 for (;;)
392     {
393     do
394 notanpe 148 {
395 notanpe 252 int j;
396     for (j = 0; j < 8; j++)
397 notanpe 148 {
398 notanpe 252 key_set64(&pkt->key64, j, key.key[j], key.key[j] ^ pkt->uk.key[j], 0);
399     pkt->uk.key[j] = key.key[j];
400 notanpe 148 }
401 notanpe 252 CALL_CRYPT64(code,
402     &pkt->key64,
403     &pkt->param64);
404     CALL_CMP64(cmp,
405     pkt->param64.hit,
406     pkt->param64.lr);
407     check_hit(pkt, pkt->param64.hit);
408     *ploop += N_ALU * ALU_BITS;
409 notanpe 148 }
410 notanpe 252 while (key_inc(&key, 6, 8) || key_inc(&key, KEY_SHUFFLE_POS, 8));
411 notanpe 148
412 notanpe 252 WaitForSingleObject(mutex_key, INFINITE);
413     key_reset(&key, 0);
414     ReleaseMutex(mutex_key);
415 notanpe 148 }
416    
417 notanpe 252 /* notreached */
418 notanpe 250 }
419    
420 notanpe 148 /***************************************************************
421     *
422     * メインループとか
423     *
424     */
425    
426     int
427 chapuni 1 main(int argc, char *argv[])
428     {
429 chapuni 74 int i;
430 chapuni 1 int mincnt;
431 notanpe 148 CODE_T *code = NULL;
432 notanpe 253 long code_cmp;
433 chapuni 46 FILE *sfp; /* scoreboard */
434     struct ITREE *root_expr;
435 notanpe 148 uint64_t proc_mask;
436     struct THREAD_PARAM *threads = NULL;
437     int nthreads;
438     int tn;
439 chapuni 1 int cr;
440    
441 notanpe 148 /* 鍵文字列 */
442 notanpe 252 struct KS_KEY key;
443 notanpe 148
444 notanpe 119 #define UPDATE_INTERVAL 8 /* 速度表示の間隔 秒 */
445 notanpe 115 struct status {
446 notanpe 192 uint64_t startTime; /* 開始時刻 ミリ秒 */
447     uint64_t lastTime; /* 最後に表示した時刻 ミリ秒 */
448     uint64_t loop; /* 総検索個数 */
449     uint64_t lastloop; /* 最後に表示した時の loop */
450 notanpe 115 } status;
451 notanpe 192 uint64_t curTime;
452     uint32_t upd_int = 0;
453 notanpe 252 /*
454     平均速度 (trips/s) * UPDATE_INTERVAL が UINT32_MAX を超えると発狂する。
455     UINT32_MAX = 4294967295, 平均速度 = 100Mtrips/s なら、
456     4294967295 / (100 * 1000 * 1000) = 42.949 秒まで。(和良
457     LOOP_FACTOR が平均速度より十分小さければ、ほぼ指定間隔になる。
458     LOOP_FACTOR * UINT32_MAX + LOOP_FACOTR 個検索するとオーバーフローする。w
459     */
460 chapuni 1
461 notanpe 252 if (!cpuid_issupported())
462     {
463     fprintf(stderr, "この環境で走らせることが想定されていません。\n");
464     exit(1);
465     }
466 notanpe 197
467 notanpe 252 assert((1 << N_STRIDE) == N_ALU * ALU_BITS);
468 notanpe 197
469 notanpe 252 mutex_key = CreateMutex(NULL, FALSE, NULL);
470 notanpe 197
471 chapuni 46 /* タゲ読み込み */
472 notanpe 252 root_expr = expr_parse("target.txt");
473 chapuni 2
474 notanpe 148 /* コードを生成・展開
475     起動予定スレッド数に応じて
476     生成するコードを変える */
477 chapuni 46 sfp = scoreboard_open();
478 notanpe 252 fwrite(crypt64_descs[0]->pro, 1, crypt64_descs[0]->cmp_pro - crypt64_descs[0]->pro, sfp); /* prologue & コアループ */
479     proc_mask = thread_avail();
480 notanpe 197
481 notanpe 252 #if 0
482     if (0&&proc_mask == 1U)
483     {
484     /* single */
485     code_cmp = 0;
486     }
487     else
488     #endif
489     {
490     /* multi */
491     fwrite(crypt64_descs[0]->ep, 1, crypt64_descs[0]->ep_end - crypt64_descs[0]->ep, sfp); /* epilogue */
492 notanpe 214
493 notanpe 252 /* 比較器のみを生成(前半) */
494     code_cmp = ftell(sfp);
495     fseek(sfp, (-code_cmp) & 63, SEEK_CUR);
496     code_cmp = ftell(sfp);
497     fwrite(crypt64_descs[0]->pro, 1, crypt64_descs[0]->crypt - crypt64_descs[0]->pro, sfp); /* prologue */
498     }
499 notanpe 214
500 notanpe 252 /* 比較部を生成 */
501     fwrite(crypt64_descs[0]->cmp_pro, 1, crypt64_descs[0]->cmp_ep - crypt64_descs[0]->cmp_pro, sfp); /* 比較器準備 */
502     tn = synth_synthesize(sfp, root_expr);
503     fwrite(crypt64_descs[0]->cmp_ep, 1, crypt64_descs[0]->ep_end - crypt64_descs[0]->cmp_ep, sfp); /* epilogue */
504 notanpe 214
505 chapuni 46 /* コードをメモリに貼り付ける */
506 notanpe 252 code = scoreboard_map(sfp);
507 chapuni 1
508     /* キーの初期化 */
509 notanpe 252 WaitForSingleObject(mutex_key, INFINITE);
510     srand(usec());
511     key_init(&key);
512     ReleaseMutex(mutex_key);
513     set_salt(code, crypt64_descs[0], key.key);
514 notanpe 222
515 notanpe 252 if (log_open("log.txt") != 0) return 1;
516 notanpe 222
517 notanpe 252 WaitForSingleObject(mutex_key, INFINITE);
518 notanpe 222
519 notanpe 148 /* 働くおじさんを量産 */
520     nthreads = 0;
521 notanpe 252 if (code_cmp)
522     {
523     THREAD_TH_T h;
524     int ots = -1;
525     threads = calloc(2 * popcnt64(proc_mask), sizeof(*threads));
526     for (i = 0; i < 64; i++)
527     if (proc_mask & (1ULL << i))
528     {
529     if (0&&ots < 0)
530     {
531     /* 自分自身のスケジューリング
532     こーゆー系のアプリは低めに設定するのが吉(かも) */
533 notanpe 148 #ifdef WIN32
534 notanpe 252 h = GetCurrentProcess();
535     SetPriorityClass(h, BELOW_NORMAL_PRIORITY_CLASS);
536 chapuni 1 #endif
537 notanpe 252 #if defined(thread_set_priority)
538     /* 心の隙間お埋めします */
539     threads[nthreads].code = code;
540     threads[nthreads].code_cmp = code_cmp;
541     threads[nthreads].seed = rand();
542     threads[nthreads].pri = THREAD_PRIORITY_IDLE;
543     thread_create(h, thread_crypt64_new, &threads[nthreads]);
544     nthreads++;
545 notanpe 148 #endif
546 notanpe 252 if (!code_cmp)
547     break;
548    
549     /* 自分自身の残りの設定を、あとでやる */
550     ots = i;
551     }
552     else
553     {
554     /* 他スレッドは、やや低めの優先度で。 */
555     threads[nthreads].code = code;
556     threads[nthreads].code_cmp = code_cmp;
557     threads[nthreads].seed = rand();
558 notanpe 148 #ifdef thread_set_priority
559 notanpe 252 //threads[nthreads].pri = THREAD_PRIORITY_BELOW_NORMAL;
560     threads[nthreads].pri = THREAD_PRIORITY_LOWEST;
561 notanpe 148 #endif
562 notanpe 252 thread_create(h, thread_crypt64_new, &threads[nthreads]);
563     #ifdef thread_get_tid
564     thread_set_affinity(h, i);
565     #endif
566     nthreads++;
567     #if 1
568     /* IDLE */
569     threads[nthreads].code = code;
570     threads[nthreads].code_cmp = code_cmp;
571     threads[nthreads].seed = rand();
572 notanpe 148 #ifdef thread_set_priority
573 notanpe 252 threads[nthreads].pri = THREAD_PRIORITY_IDLE;
574 notanpe 148 #endif
575 notanpe 252 thread_create(h, thread_crypt64_new, &threads[nthreads]);
576     #ifdef thread_get_tid
577     SetThreadAffinityMask(h, proc_mask);
578     #endif
579     nthreads++;
580     #endif
581     }
582     }
583     #ifdef thread_get_tid
584     if (ots)
585     thread_set_affinity(thread_get_tid(), ots);
586     #endif
587     }
588 notanpe 148
589 notanpe 252 fprintf(stderr, "検索開始!\n");
590     ReleaseMutex(mutex_key);
591 chapuni 1
592 notanpe 252 mincnt = 0x7FFFFFFF;
593 notanpe 198
594 chapuni 1 cr = 0;
595 notanpe 120 memset( &status, 0, sizeof( struct status ) );
596 notanpe 119 status.startTime = status.lastTime = usec();
597 notanpe 213
598 notanpe 252 /* 探索ループだぞっと */
599     for (;;)
600     {
601     Sleep(5000);
602 notanpe 213
603 notanpe 252 /* 速度計測 */
604     status.loop = 0;
605     for (i = 0; i < n_cpus; i++) status.loop += loop_cpu[i];
606 notanpe 237
607 notanpe 252 if (status.loop >= status.lastloop + upd_int
608     && (curTime = usec()) != status.lastTime)
609     {
610     uint64_t diffTime;
611     int a, b, c;
612     /* 通算(単位 ktrips/sec) */
613     diffTime = curTime - status.startTime;
614     a = status.loop / ((1000 / USEC_SEC) * diffTime);
615 notanpe 237
616 notanpe 252 /* 区間(単位 trips/sec) */
617     diffTime = curTime - status.lastTime;
618     b = USEC_SEC * (status.loop - status.lastloop) / diffTime;
619 chapuni 1
620 notanpe 252 /* 予測 */
621     c = UPDATE_INTERVAL * b;
622 notanpe 148
623 notanpe 252 /* 立ち上がりなど、誤差があり upd_int が小さすぎたときは
624     いきなり全補正せず 1 秒(==b)づつ収斂させる。 */
625     upd_int = (upd_int + b < c
626     ? upd_int + b
627     : c);
628 chapuni 1
629 notanpe 252 status.lastTime = curTime;
630     status.lastloop = status.loop;
631 notanpe 148 #if DEBUG>=1
632 notanpe 252 fprintf(stderr,
633     "%5d/%5d(%3d%%)",
634     nblk_hit, nblk_total, 100 * nblk_hit / nblk_total);
635     nblk_hit = nblk_total = 0;
636     if (nap_total)
637     fprintf(stderr,
638     " %5d/%5d(%3d%%)",
639     nap_hit, nap_total, 100 * nap_hit / nap_total);
640     else
641     fprintf(stderr,
642     " -----/-----(---%%)");
643     nap_hit = nap_total = 0;
644 notanpe 148 #endif
645 notanpe 252 fprintf(stderr,
646     "%4d.%03dMtrips/s [%4d.%06dMtrips/s]\r",
647     a / 1000, a % 1000,
648     b / 1000000, b % 1000000);
649     cr++;
650     }
651     }
652 notanpe 198
653 chapuni 1 return 0;
654     }
655    
656 chapuni 2 /*
657     * Local Variables:
658     * tab-width: 4
659     * End:
660     *
661     * EOF */

Properties

Name Value
svn:eol-style native
svn:keywords Author Date Id Rev URL

Back to OSDN">Back to OSDN
ViewVC Help
Powered by ViewVC 1.1.26