version 1.1, 2000/09/09 14:13:19 |
version 1.1.1.2, 2003/08/25 16:06:03 |
|
|
/* Program for computing integer expressions using the GNU Multiple Precision |
/* Program for computing integer expressions using the GNU Multiple Precision |
Arithmetic Library. |
Arithmetic Library. |
|
|
Copyright (C) 1997, 1999, 2000 Free Software Foundation, Inc. |
Copyright 1997, 1999, 2000, 2001, 2002 Free Software Foundation, Inc. |
|
|
This program is free software; you can redistribute it and/or modify it under |
This program is free software; you can redistribute it and/or modify it under |
the terms of the GNU General Public License as published by the Free Software |
the terms of the GNU General Public License as published by the Free Software |
Line 30 Place - Suite 330, Boston, MA 02111-1307, USA. */ |
|
Line 30 Place - Suite 330, Boston, MA 02111-1307, USA. */ |
|
-o print output in octal |
-o print output in octal |
-d print output in decimal (the default) |
-d print output in decimal (the default) |
-x print output in hexadecimal |
-x print output in hexadecimal |
-<NUM> print output in base NUM |
-b<NUM> print output in base NUM |
-t print timing information |
-t print timing information |
-html output html |
-html output html |
|
-wml output wml |
-nosplit do not split long lines each 60th digit |
-nosplit do not split long lines each 60th digit |
*/ |
*/ |
|
|
Line 40 Place - Suite 330, Boston, MA 02111-1307, USA. */ |
|
Line 41 Place - Suite 330, Boston, MA 02111-1307, USA. */ |
|
use up extensive resources (cpu, memory). Useful for the GMP demo on the |
use up extensive resources (cpu, memory). Useful for the GMP demo on the |
GMP web site, since we cannot load the server too much. */ |
GMP web site, since we cannot load the server too much. */ |
|
|
#ifdef LIMIT_RESOURCE_USAGE |
#include "pexpr-config.h" |
#include <sys/types.h> |
|
#include <sys/time.h> |
|
#include <sys/resource.h> |
|
#endif |
|
|
|
#include <string.h> |
#include <string.h> |
#include <stdio.h> |
#include <stdio.h> |
Line 53 Place - Suite 330, Boston, MA 02111-1307, USA. */ |
|
Line 50 Place - Suite 330, Boston, MA 02111-1307, USA. */ |
|
#include <signal.h> |
#include <signal.h> |
#include <ctype.h> |
#include <ctype.h> |
|
|
|
#include <time.h> |
|
#include <sys/types.h> |
|
#include <sys/time.h> |
|
#if HAVE_SYS_RESOURCE_H |
|
#include <sys/resource.h> |
|
#endif |
|
|
#include "gmp.h" |
#include "gmp.h" |
|
|
|
/* SunOS 4 and HPUX 9 don't define a canonical SIGSTKSZ, use a default. */ |
|
#ifndef SIGSTKSZ |
|
#define SIGSTKSZ 4096 |
|
#endif |
|
|
|
|
|
#define TIME(t,func) \ |
|
do { int __t0, __times, __t, __tmp; \ |
|
__times = 1; \ |
|
__t0 = cputime (); \ |
|
{func;} \ |
|
__tmp = cputime () - __t0; \ |
|
while (__tmp < 100) \ |
|
{ \ |
|
__times <<= 1; \ |
|
__t0 = cputime (); \ |
|
for (__t = 0; __t < __times; __t++) \ |
|
{func;} \ |
|
__tmp = cputime () - __t0; \ |
|
} \ |
|
(t) = (double) __tmp / __times; \ |
|
} while (0) |
|
|
/* GMP version 1.x compatibility. */ |
/* GMP version 1.x compatibility. */ |
#if ! (__GNU_MP_VERSION >= 2) |
#if ! (__GNU_MP_VERSION >= 2) |
typedef MP_INT __mpz_struct; |
typedef MP_INT __mpz_struct; |
Line 76 jmp_buf errjmpbuf; |
|
Line 103 jmp_buf errjmpbuf; |
|
|
|
enum op_t {NOP, LIT, NEG, NOT, PLUS, MINUS, MULT, DIV, MOD, REM, INVMOD, POW, |
enum op_t {NOP, LIT, NEG, NOT, PLUS, MINUS, MULT, DIV, MOD, REM, INVMOD, POW, |
AND, IOR, XOR, SLL, SRA, POPCNT, HAMDIST, GCD, LCM, SQRT, ROOT, FAC, |
AND, IOR, XOR, SLL, SRA, POPCNT, HAMDIST, GCD, LCM, SQRT, ROOT, FAC, |
LOG, LOG2, FERMAT, MERSENNE, FIBONACCI}; |
LOG, LOG2, FERMAT, MERSENNE, FIBONACCI, RANDOM, NEXTPRIME, BINOM}; |
|
|
/* Type for the expression tree. */ |
/* Type for the expression tree. */ |
struct expr |
struct expr |
|
|
|
|
typedef struct expr *expr_t; |
typedef struct expr *expr_t; |
|
|
void cleanup_and_exit (int); |
void cleanup_and_exit __GMP_PROTO ((int)); |
|
|
char *skipspace (char *); |
char *skipspace __GMP_PROTO ((char *)); |
void makeexp (expr_t *, enum op_t, expr_t, expr_t); |
void makeexp __GMP_PROTO ((expr_t *, enum op_t, expr_t, expr_t)); |
void free_expr (expr_t); |
void free_expr __GMP_PROTO ((expr_t)); |
char *expr (char *, expr_t *); |
char *expr __GMP_PROTO ((char *, expr_t *)); |
char *term (char *, expr_t *); |
char *term __GMP_PROTO ((char *, expr_t *)); |
char *power (char *, expr_t *); |
char *power __GMP_PROTO ((char *, expr_t *)); |
char *factor (char *, expr_t *); |
char *factor __GMP_PROTO ((char *, expr_t *)); |
int match (char *, char *); |
int match __GMP_PROTO ((char *, char *)); |
int matchp (char *, char *); |
int matchp __GMP_PROTO ((char *, char *)); |
int cputime (void); |
int cputime __GMP_PROTO ((void)); |
|
|
void mpz_eval_expr (mpz_ptr, expr_t); |
void mpz_eval_expr __GMP_PROTO ((mpz_ptr, expr_t)); |
void mpz_eval_mod_expr (mpz_ptr, expr_t, mpz_ptr); |
void mpz_eval_mod_expr __GMP_PROTO ((mpz_ptr, expr_t, mpz_ptr)); |
|
|
char *error; |
char *error; |
int flag_print = 1; |
int flag_print = 1; |
int print_timing = 0; |
int print_timing = 0; |
int flag_html = 0; |
int flag_html = 0; |
|
int flag_wml = 0; |
int flag_splitup_output = 0; |
int flag_splitup_output = 0; |
char *newline = ""; |
char *newline = ""; |
|
gmp_randstate_t rstate; |
|
|
#ifdef _AIX |
|
#define sigaltstack sigstack |
|
|
/* cputime() returns user CPU time measured in milliseconds. */ |
|
#if ! HAVE_CPUTIME |
|
#if HAVE_GETRUSAGE |
|
int |
|
cputime (void) |
|
{ |
|
struct rusage rus; |
|
|
|
getrusage (0, &rus); |
|
return rus.ru_utime.tv_sec * 1000 + rus.ru_utime.tv_usec / 1000; |
|
} |
|
#else |
|
#if HAVE_CLOCK |
|
int |
|
cputime (void) |
|
{ |
|
if (CLOCKS_PER_SEC < 100000) |
|
return clock () * 1000 / CLOCKS_PER_SEC; |
|
return clock () / (CLOCKS_PER_SEC / 1000); |
|
} |
|
#else |
|
int |
|
cputime (void) |
|
{ |
|
return 0; |
|
} |
#endif |
#endif |
|
#endif |
|
#endif |
|
|
#if !defined(_WIN32) && !defined(__DJGPP__) |
|
|
int |
|
stack_downwards_helper (char *xp) |
|
{ |
|
char y; |
|
return &y < xp; |
|
} |
|
int |
|
stack_downwards_p (void) |
|
{ |
|
char x; |
|
return stack_downwards_helper (&x); |
|
} |
|
|
|
|
void |
void |
setup_error_handler () |
setup_error_handler (void) |
{ |
{ |
|
#if HAVE_SIGACTION |
struct sigaction act; |
struct sigaction act; |
struct sigaltstack sigstk; |
act.sa_handler = cleanup_and_exit; |
|
sigemptyset (&(act.sa_mask)); |
|
#define SIGNAL(sig) sigaction (sig, &act, NULL) |
|
#else |
|
struct { int sa_flags } act; |
|
#define SIGNAL(sig) signal (sig, cleanup_and_exit) |
|
#endif |
|
act.sa_flags = 0; |
|
|
/* Set up a stack for signal handling. A typical cause of error is stack |
/* Set up a stack for signal handling. A typical cause of error is stack |
overflow, and in such situation a signal can not be delivered on the |
overflow, and in such situation a signal can not be delivered on the |
overflown stack. */ |
overflown stack. */ |
sigstk.ss_sp = malloc (SIGSTKSZ); |
#if HAVE_SIGALTSTACK |
#ifndef _AIX |
{ |
sigstk.ss_size = SIGSTKSZ; |
/* AIX uses stack_t, MacOS uses struct sigaltstack, various other |
sigstk.ss_flags = 0; |
systems have both. */ |
#endif /* ! _AIX */ |
#if HAVE_STACK_T |
|
stack_t s; |
#ifndef _UNICOS |
#else |
if (sigaltstack (&sigstk, 0) < 0) |
struct sigaltstack s; |
perror("sigaltstack"); |
|
#endif |
#endif |
|
s.ss_sp = malloc (SIGSTKSZ); |
|
s.ss_size = SIGSTKSZ; |
|
s.ss_flags = 0; |
|
if (sigaltstack (&s, NULL) != 0) |
|
perror("sigaltstack"); |
|
act.sa_flags = SA_ONSTACK; |
|
} |
|
#else |
|
#if HAVE_SIGSTACK |
|
{ |
|
struct sigstack s; |
|
s.ss_sp = malloc (SIGSTKSZ); |
|
if (stack_downwards_p ()) |
|
s.ss_sp += SIGSTKSZ; |
|
s.ss_onstack = 0; |
|
if (sigstack (&s, NULL) != 0) |
|
perror("sigstack"); |
|
act.sa_flags = SA_ONSTACK; |
|
} |
|
#else |
|
#endif |
|
#endif |
|
|
/* Initialize structure for sigaction (called below). */ |
|
act.sa_handler = cleanup_and_exit; |
|
sigemptyset (&(act.sa_mask)); |
|
act.sa_flags = SA_ONSTACK; |
|
|
|
#ifdef LIMIT_RESOURCE_USAGE |
#ifdef LIMIT_RESOURCE_USAGE |
{ |
{ |
struct rlimit limit; |
struct rlimit limit; |
Line 155 setup_error_handler () |
|
Line 250 setup_error_handler () |
|
limit.rlim_max = 4; |
limit.rlim_max = 4; |
setrlimit (RLIMIT_CPU, &limit); |
setrlimit (RLIMIT_CPU, &limit); |
|
|
limit.rlim_cur = limit.rlim_max = 4 * 1024 * 1024; |
limit.rlim_cur = limit.rlim_max = 16 * 1024 * 1024; |
setrlimit (RLIMIT_DATA, &limit); |
setrlimit (RLIMIT_DATA, &limit); |
|
|
getrlimit (RLIMIT_STACK, &limit); |
getrlimit (RLIMIT_STACK, &limit); |
limit.rlim_cur = 1 * 1024 * 1024; |
limit.rlim_cur = 4 * 1024 * 1024; |
setrlimit (RLIMIT_STACK, &limit); |
setrlimit (RLIMIT_STACK, &limit); |
|
|
sigaction (SIGXCPU, &act, 0); |
SIGNAL (SIGXCPU); |
} |
} |
#endif /* LIMIT_RESOURCE_USAGE */ |
#endif /* LIMIT_RESOURCE_USAGE */ |
|
|
sigaction (SIGILL, &act, 0); |
SIGNAL (SIGILL); |
sigaction (SIGSEGV, &act, 0); |
SIGNAL (SIGSEGV); |
sigaction (SIGBUS, &act, 0); |
#ifdef SIGBUS /* not in mingw */ |
sigaction (SIGFPE, &act, 0); |
SIGNAL (SIGBUS); |
|
#endif |
|
SIGNAL (SIGFPE); |
|
SIGNAL (SIGABRT); |
} |
} |
#endif /* ! _WIN32 && ! __DJGPP__ */ |
|
|
|
|
int |
main (int argc, char **argv) |
main (int argc, char **argv) |
{ |
{ |
struct expr *e; |
struct expr *e; |
Line 182 main (int argc, char **argv) |
|
Line 280 main (int argc, char **argv) |
|
char *str; |
char *str; |
int base = 10; |
int base = 10; |
|
|
#if !defined(_WIN32) && !defined(__DJGPP__) |
|
setup_error_handler (); |
setup_error_handler (); |
|
|
|
gmp_randinit (rstate, GMP_RAND_ALG_LC, 128); |
|
|
|
{ |
|
#if HAVE_GETTIMEOFDAY |
|
struct timeval tv; |
|
gettimeofday (&tv, NULL); |
|
gmp_randseed_ui (rstate, tv.tv_sec + tv.tv_usec); |
|
#else |
|
time_t t; |
|
time (&t); |
|
gmp_randseed_ui (rstate, t); |
#endif |
#endif |
|
} |
|
|
mpz_init (r); |
mpz_init (r); |
|
|
Line 210 main (int argc, char **argv) |
|
Line 320 main (int argc, char **argv) |
|
base = 2; |
base = 2; |
else if (arg[1] == 'x' && arg[2] == 0) |
else if (arg[1] == 'x' && arg[2] == 0) |
base = 16; |
base = 16; |
|
else if (arg[1] == 'X' && arg[2] == 0) |
|
base = -16; |
else if (arg[1] == 'o' && arg[2] == 0) |
else if (arg[1] == 'o' && arg[2] == 0) |
base = 8; |
base = 8; |
else if (arg[1] == 'd' && arg[2] == 0) |
else if (arg[1] == 'd' && arg[2] == 0) |
Line 217 main (int argc, char **argv) |
|
Line 329 main (int argc, char **argv) |
|
else if (strcmp (arg, "-html") == 0) |
else if (strcmp (arg, "-html") == 0) |
{ |
{ |
flag_html = 1; |
flag_html = 1; |
newline = "<BR>"; |
newline = "<br>"; |
} |
} |
|
else if (strcmp (arg, "-wml") == 0) |
|
{ |
|
flag_wml = 1; |
|
newline = "<br/>"; |
|
} |
else if (strcmp (arg, "-split") == 0) |
else if (strcmp (arg, "-split") == 0) |
{ |
{ |
flag_splitup_output = 1; |
flag_splitup_output = 1; |
Line 303 main (int argc, char **argv) |
|
Line 420 main (int argc, char **argv) |
|
continue; |
continue; |
} |
} |
|
|
{ |
if (print_timing) |
int t0; |
{ |
|
double t; |
if (print_timing) |
TIME (t, mpz_eval_expr (r, e)); |
t0 = cputime (); |
printf ("computation took %.2f ms%s\n", t, newline); |
|
} |
|
else |
mpz_eval_expr (r, e); |
mpz_eval_expr (r, e); |
|
|
if (print_timing) |
|
printf ("computation took %d ms%s\n", cputime () - t0, newline); |
|
} |
|
|
|
if (flag_print) |
if (flag_print) |
{ |
{ |
size_t out_len; |
size_t out_len; |
char *tmp, *s; |
char *tmp, *s; |
int t0; |
|
|
|
out_len = mpz_sizeinbase (r, base) + 1; |
out_len = mpz_sizeinbase (r, base >= 0 ? base : -base) + 2; |
tmp = malloc (out_len); |
tmp = malloc (out_len); |
|
|
if (print_timing) |
if (print_timing) |
t0 = cputime (); |
{ |
|
double t; |
|
printf ("output conversion "); |
|
TIME (t, mpz_get_str (tmp, base, r)); |
|
printf ("took %.2f ms%s\n", t, newline); |
|
} |
|
else |
|
mpz_get_str (tmp, base, r); |
|
|
if (print_timing) |
|
/* Print first half of message... */ |
|
printf ("output conversion "); |
|
|
|
mpz_get_str (tmp, -base, r); |
|
|
|
if (print_timing) |
|
/* ...print 2nd half of message unless we caught a time limit |
|
and therefore longjmp'ed */ |
|
printf ("took %d ms%s\n", cputime () - t0, newline); |
|
|
|
out_len = strlen (tmp); |
out_len = strlen (tmp); |
if (flag_splitup_output) |
if (flag_splitup_output) |
{ |
{ |
Line 584 struct functions fns[] = |
|
Line 693 struct functions fns[] = |
|
#if __GNU_MP_VERSION >= 2 |
#if __GNU_MP_VERSION >= 2 |
{"root", ROOT, 2}, |
{"root", ROOT, 2}, |
{"popc", POPCNT, 1}, |
{"popc", POPCNT, 1}, |
|
{"hamdist", HAMDIST, 2}, |
#endif |
#endif |
{"gcd", GCD, 0}, |
{"gcd", GCD, 0}, |
#if __GNU_MP_VERSION > 2 || __GNU_MP_VERSION_MINOR >= 1 |
#if __GNU_MP_VERSION > 2 || __GNU_MP_VERSION_MINOR >= 1 |
Line 595 struct functions fns[] = |
|
Line 705 struct functions fns[] = |
|
{"xor", XOR, 0}, |
{"xor", XOR, 0}, |
#endif |
#endif |
{"plus", PLUS, 0}, |
{"plus", PLUS, 0}, |
|
{"pow", POW, 2}, |
{"minus", MINUS, 2}, |
{"minus", MINUS, 2}, |
{"mul", MULT, 0}, |
{"mul", MULT, 0}, |
{"div", DIV, 2}, |
{"div", DIV, 2}, |
Line 609 struct functions fns[] = |
|
Line 720 struct functions fns[] = |
|
{"M", MERSENNE, 1}, |
{"M", MERSENNE, 1}, |
{"fib", FIBONACCI, 1}, |
{"fib", FIBONACCI, 1}, |
{"Fib", FIBONACCI, 1}, |
{"Fib", FIBONACCI, 1}, |
|
{"random", RANDOM, 1}, |
|
{"nextprime", NEXTPRIME, 1}, |
|
{"binom", BINOM, 2}, |
|
{"binomial", BINOM, 2}, |
{"", NOP, 0} |
{"", NOP, 0} |
}; |
}; |
|
|
Line 849 mpz_eval_expr (mpz_ptr r, expr_t e) |
|
Line 964 mpz_eval_expr (mpz_ptr r, expr_t e) |
|
case POW: |
case POW: |
mpz_init (lhs); mpz_init (rhs); |
mpz_init (lhs); mpz_init (rhs); |
mpz_eval_expr (lhs, e->operands.ops.lhs); |
mpz_eval_expr (lhs, e->operands.ops.lhs); |
|
if (mpz_cmpabs_ui (lhs, 1) <= 0) |
|
{ |
|
/* For 0^rhs and 1^rhs, we just need to verify that |
|
rhs is well-defined. For (-1)^rhs we need to |
|
determine (rhs mod 2). For simplicity, compute |
|
(rhs mod 2) for all three cases. */ |
|
expr_t two, et; |
|
two = malloc (sizeof (struct expr)); |
|
two -> op = LIT; |
|
mpz_init_set_ui (two->operands.val, 2L); |
|
makeexp (&et, MOD, e->operands.ops.rhs, two); |
|
e->operands.ops.rhs = et; |
|
} |
|
|
mpz_eval_expr (rhs, e->operands.ops.rhs); |
mpz_eval_expr (rhs, e->operands.ops.rhs); |
if (mpz_cmp_si (rhs, 0L) == 0) |
if (mpz_cmp_si (rhs, 0L) == 0) |
/* x^0 is 1 */ |
/* x^0 is 1 */ |
Line 999 mpz_eval_expr (mpz_ptr r, expr_t e) |
|
Line 1128 mpz_eval_expr (mpz_ptr r, expr_t e) |
|
#if __GNU_MP_VERSION >= 2 |
#if __GNU_MP_VERSION >= 2 |
case POPCNT: |
case POPCNT: |
mpz_eval_expr (r, e->operands.ops.lhs); |
mpz_eval_expr (r, e->operands.ops.lhs); |
{ unsigned long int cnt; |
{ long int cnt; |
cnt = mpz_popcount (r); |
cnt = mpz_popcount (r); |
mpz_set_ui (r, cnt); |
mpz_set_si (r, cnt); |
} |
} |
return; |
return; |
|
case HAMDIST: |
|
{ long int cnt; |
|
mpz_init (lhs); mpz_init (rhs); |
|
mpz_eval_expr (lhs, e->operands.ops.lhs); |
|
mpz_eval_expr (rhs, e->operands.ops.rhs); |
|
cnt = mpz_hamdist (lhs, rhs); |
|
mpz_clear (lhs); mpz_clear (rhs); |
|
mpz_set_si (r, cnt); |
|
} |
|
return; |
#endif |
#endif |
case LOG2: |
case LOG2: |
mpz_eval_expr (r, e->operands.ops.lhs); |
mpz_eval_expr (r, e->operands.ops.lhs); |
Line 1105 mpz_eval_expr (mpz_ptr r, expr_t e) |
|
Line 1244 mpz_eval_expr (mpz_ptr r, expr_t e) |
|
#endif |
#endif |
} |
} |
return; |
return; |
|
case RANDOM: |
|
{ |
|
unsigned long int n; |
|
mpz_init (lhs); |
|
mpz_eval_expr (lhs, e->operands.ops.lhs); |
|
if (mpz_sgn (lhs) <= 0 || mpz_cmp_si (lhs, 1000000000) > 0) |
|
{ |
|
error = "random number size out of range"; |
|
mpz_clear (lhs); |
|
longjmp (errjmpbuf, 1); |
|
} |
|
n = mpz_get_ui (lhs); |
|
mpz_clear (lhs); |
|
mpz_urandomb (r, rstate, n); |
|
} |
|
return; |
|
case NEXTPRIME: |
|
{ |
|
mpz_eval_expr (r, e->operands.ops.lhs); |
|
mpz_nextprime (r, r); |
|
} |
|
return; |
|
case BINOM: |
|
mpz_init (lhs); mpz_init (rhs); |
|
mpz_eval_expr (lhs, e->operands.ops.lhs); |
|
mpz_eval_expr (rhs, e->operands.ops.rhs); |
|
{ |
|
unsigned long int k; |
|
if (mpz_cmp_ui (rhs, ~(unsigned long int) 0) > 0) |
|
{ |
|
error = "k too large in (n over k) expression"; |
|
mpz_clear (lhs); mpz_clear (rhs); |
|
longjmp (errjmpbuf, 1); |
|
} |
|
k = mpz_get_ui (rhs); |
|
mpz_bin_ui (r, lhs, k); |
|
} |
|
mpz_clear (lhs); mpz_clear (rhs); |
|
return; |
default: |
default: |
abort (); |
abort (); |
} |
} |
Line 1167 mpz_eval_mod_expr (mpz_ptr r, expr_t e, mpz_ptr mod) |
|
Line 1345 mpz_eval_mod_expr (mpz_ptr r, expr_t e, mpz_ptr mod) |
|
void |
void |
cleanup_and_exit (int sig) |
cleanup_and_exit (int sig) |
{ |
{ |
|
switch (sig) { |
#ifdef LIMIT_RESOURCE_USAGE |
#ifdef LIMIT_RESOURCE_USAGE |
if (sig == SIGXCPU) |
case SIGXCPU: |
printf ("expression took too long time to evaluate%s\n", newline); |
printf ("expression took too long to evaluate%s\n", newline); |
else if (sig == SIGFPE) |
break; |
printf ("divide by zero%s\n", newline); |
|
else |
|
#endif |
#endif |
|
case SIGFPE: |
|
printf ("divide by zero%s\n", newline); |
|
break; |
|
default: |
printf ("expression required too much memory to evaluate%s\n", newline); |
printf ("expression required too much memory to evaluate%s\n", newline); |
|
break; |
|
} |
exit (-2); |
exit (-2); |
} |
} |
|
|
/* Return user CPU time measured in milliseconds. */ |
|
|
|
#if defined (USG) || defined (__SVR4) || defined (_UNICOS) || defined (__hpux) |
|
#include <time.h> |
|
|
|
int |
|
cputime () |
|
{ |
|
if (CLOCKS_PER_SEC < 100000) |
|
return clock () * 1000 / CLOCKS_PER_SEC; |
|
return clock () / (CLOCKS_PER_SEC / 1000); |
|
} |
|
#else |
|
#include <sys/types.h> |
|
#include <sys/time.h> |
|
#include <sys/resource.h> |
|
|
|
int |
|
cputime () |
|
{ |
|
struct rusage rus; |
|
|
|
getrusage (0, &rus); |
|
return rus.ru_utime.tv_sec * 1000 + rus.ru_utime.tv_usec / 1000; |
|
} |
|
#endif |
|