diff --git a/configure.ac b/configure.ac index 53f2797d2811f9add10dfcdd7555364eaa582201..d32acd80ecff69e9a3d4fe72810afaca195ad5b6 100644 --- a/configure.ac +++ b/configure.ac @@ -56,6 +56,12 @@ AC_ARG_ENABLE([examples], [enable_examples=yes]) AM_CONDITIONAL([ENABLE_EXAMPLES], [test x"$enable_examples" = xyes]) +AC_ARG_ENABLE([gmp], + [AC_HELP_STRING([--enable-gmp], + [use GNU multiprecision library in examples @<:@default=no@:>@])], [], + [enable_gmp=no]) +AM_CONDITIONAL([ENABLE_GMP], [test x"$enable_gmp" = xyes]) + AC_ARG_ENABLE([check], [AC_HELP_STRING([--enable-check], [enable unit testing with check library @<:@default=auto@:>@])], [], diff --git a/examples/Makefile.am b/examples/Makefile.am index 43276848de59bea4f450da9e3121261a9c45b7ed..9f204613a1ab209cd353f4b7cd6bdef330fbaf67 100644 --- a/examples/Makefile.am +++ b/examples/Makefile.am @@ -17,13 +17,19 @@ noinst_PROGRAMS = \ tas \ test_dace \ time_calculus \ - uniq + uniq \ + int_div_example endif ENABLE_EXAMPLES AM_CPPFLAGS = -I$(top_srcdir)/include AM_FCFLAGS = $(FCMODINC)$(top_builddir)/src LDADD = $(top_builddir)/src/libmtime.la +if ENABLE_GMP +CFLAGS += -DHAVE_GMP +LDADD += -lgmp +endif ENABLE_GMP + AM_DEFAULT_SOURCE_EXT = .f90 duration_SOURCES = duration.f90 mo_kind.f90 iconatm_SOURCES = iconatm.f90 mo_event_manager.f90 @@ -33,6 +39,7 @@ modulo_SOURCES = modulo.c recurrence_SOURCES = recurrence.c test_dace_SOURCES = test_dace.f90 mo_event_manager.f90 time_calculus_SOURCES = time_calculus.c +int_div_example_SOURCES = int_div_example.c if FCMODUC mo_event_manager_mod = MO_EVENT_MANAGER.$(FCMODEXT) diff --git a/examples/int_div_example.c b/examples/int_div_example.c new file mode 100644 index 0000000000000000000000000000000000000000..c0495e6cef0114b5bf04b05d07e0541a4c427c40 --- /dev/null +++ b/examples/int_div_example.c @@ -0,0 +1,136 @@ +/* -------------------------------------------------------------------------------- + * EXAMPLE.C + * + * 04/2019 : F. Prill, DWD + * + * Note: If the "mtime" library has been configured using --enable-gmp, + * then this example tests its results against the GNU multiprecision library. + * + * + * limitations: + * + * - the remainder in the mtime struct "_divisionquotienttimespan" is + * limited to int64_t msecs. + * + * -------------------------------------------------------------------------------- */ + +#include <stdio.h> +#include <stdlib.h> +#include <inttypes.h> +#include "int_div.h" + +#ifdef HAVE_GMP +#include <gmp.h> + +/* prototype */ +int divide_timespan_mpz(const t_int days1, const t_int day_fraction1, + const t_int days2, const t_int day_fraction2, + t_int *q_decimal, t_int *remainder_days, t_int *remainder_ms); +#endif + +int main(void) { + + int ret, i, cnt = 0; + t_int days1, day_fraction1, days2, day_fraction2; + t_int q_decimal0 = 0, remainder_days0 = 0, remainder_ms0 = 0; + t_int q_decimal = 0, remainder_days = 0, remainder_ms = 0; + + double f1 = 1728000000.0 / (double) RAND_MAX; + double f2 = 86400000.0 / (double) RAND_MAX; + +#ifdef HAVE_GMP + const int NREPEAT = 3000000; + printf("test program\n"); + printf(" checking %d random divisions against GNU Multiple Precision Arithmetic Library\n",NREPEAT); +#else + const int NREPEAT = 10; + printf("example program\n"); + printf(" calculating %d divisions.\n",NREPEAT); +#endif + + srand ( 123 ); + + for (i=0; i<NREPEAT; i++) { + /* test randomly generated input against GNU Multiple Precision + Arithmetic Library: */ + days1 = (t_int) ( f1 * (double) rand() ); + day_fraction1 = (t_int) ( f2 * (double) rand() ); + days2 = (t_int) ( f1 * (double) rand() ); + day_fraction2 = (t_int) ( f2 * (double) rand() ); + +#ifdef HAVE_GMP + ret = divide_timespan_mpz(days1, day_fraction1, days2, day_fraction2, + &q_decimal0, &remainder_days0, &remainder_ms0); +#endif + ret = divide_timespan(days1, day_fraction1, days2, day_fraction2, + &q_decimal, &remainder_days, &remainder_ms); + +#ifdef HAVE_GMP + if ((ret != 0) || + (q_decimal != q_decimal0) || + (remainder_days != remainder_days0) || + (remainder_ms != remainder_ms0)) +#endif + { + printf("dividend: %" PRId64 " : %" PRId64 " \n", days1, day_fraction1); + printf("divisor : %" PRId64 " : %" PRId64 " \n", days2, day_fraction2); +#ifdef HAVE_GMP + printf("comparison: quotient_out = %" PRId64 ", remainder = %" PRId64 " : %" PRId64 "\n", + q_decimal0, remainder_days0, remainder_ms0); +#endif + printf("quotient_out = %" PRId64 ", remainder = %" PRId64 " : %" PRId64 "\n", + q_decimal, remainder_days, remainder_ms); + printf("return code = %d\n",ret); + cnt++; + } + } + +#ifdef HAVE_GMP + printf(" %d discrepancies reported.\n", cnt); +#endif + printf("test program done after %d tests.\n", NREPEAT); + exit(0); +} + + +#ifdef HAVE_GMP +int divide_timespan_mpz(const t_int days1, const t_int day_fraction1, + const t_int days2, const t_int day_fraction2, + t_int *q_decimal, t_int *remainder_days, t_int *remainder_ms) +{ + mpz_t a0, a1, a2, b1, b2, q, r; + + mpz_init(a0); + mpz_init(a1); + mpz_init(a2); + mpz_init(b1); + mpz_init(b2); + mpz_init(q); + mpz_init(r); + + mpz_set_ui(a0, 86400000); + mpz_set_ui(a1,days1); + mpz_set_ui(a2,day_fraction1); + mpz_set_ui(b1,days2); + mpz_set_ui(b2,day_fraction2); + + mpz_addmul(a2,a1,a0); + mpz_addmul(b2,b1,a0); + mpz_fdiv_qr(q,r,a2,b2); + + *q_decimal = mpz_get_ui(q); + + mpz_fdiv_qr(a2,b2,r,a0); + *remainder_days = mpz_get_ui(a2); + *remainder_ms = mpz_get_ui(b2); + + mpz_clear(a0); + mpz_clear(a1); + mpz_clear(a2); + mpz_clear(b1); + mpz_clear(b2); + mpz_clear(q); + mpz_clear(r); + return 0; +} +#endif