diff --git a/src/Makefile b/src/Makefile index f73457cd508d36bca1583272a11376a64ef1042a..7b90707e60f3d865615b73602e2550aecd808ce6 100644 --- a/src/Makefile +++ b/src/Makefile @@ -4,7 +4,7 @@ # #------------------------------------------------------------------------------- # -# Copyright (C) 1998-2008 Hinnerk Stueben +# Copyright (C) 1998-2011 Hinnerk Stueben # 2006-2010 Yoshifumi Nakamura # # This file is part of BQCD -- Berlin Quantum ChromoDynamics program @@ -77,24 +77,26 @@ LIBF = fermi/lib_fermi.a LIBB = \ su3sc/lib_su3sc.a \ ildg/$(LIBILDG) \ - $(LIBRANDOM) + $(LIBRANDOM) \ + fermi/d/$(LIBD) \ + comm/$(LIBCOMM) \ + fermi/d/$(LIBD) \ + comm/$(LIBCOMM) -#ifdef libdi -#LIBB += comm/$(LIBCOMM) -#else -LIBB += fermi/d/$(LIBD) comm/$(LIBCOMM) -#endif -bqcd4: bqcdi.o $(MODULES) $(OBJS) lib_bqcdi.a - $(F90) -o $@ $(LDFLAGS) bqcdi.o $(MODULES) $(OBJS) lib_bqcdi.a $(SYSLIBS) +bqcd4: bqcdi.o $(MODULES) $(OBJS) $(LIBS) $(LIBF) $(LIBB) + $(F90) -o $@ $(LDFLAGS) bqcdi.o $(MODULES) $(OBJS) $(LIBS) $(LIBF) $(LIBB) $(SYSLIBS) +#bqcd4: bqcdi.o $(MODULES) $(OBJS) lib_bqcdi.a +# $(F90) -o $@ $(LDFLAGS) bqcdi.o $(MODULES) $(OBJS) lib_bqcdi.a $(SYSLIBS) fast: - make timing.h + make auto_headers cd modules && $(MAKE) cd comm && $(MAKE) fast cd fermi/d && $(MAKE) fast cd ildg && $(MAKE) fast cd ran/$(random) && $(MAKE) fast + cd fmlib && $(MAKE) fast cd su3sc && make cd boundary && make cd gauge && make @@ -104,9 +106,6 @@ fast: cd util && make $(FAST_MAKE) bqcd4 -timing.h: timing.H - awk 'NF > 0 {print $$0, ++count}' timing.H > ./include/$@ - clean: rm -f bqcd.[0-9][0-9][0-9].* diag.[0-9][0-9] core app.rif rm -f random_test random_test.dump random_test.out @@ -129,7 +128,16 @@ clobber: tidy -cd su3sc && $(MAKE) clobber -cd gauge && $(MAKE) clobber -cd fermi && $(MAKE) clobber - -rm -f ./include/timing.h + -cd fmlib && $(MAKE) clobber + -rm -f ./include_auto/*.h + +auto_headers: timing.H precision.H + @awk 'NF > 0 {print $$0, ++count}' timing.H > ./include_auto/timing.h + @awk 'NF > 0 {gsub(/#/, ""); gsub(/define/,"static const int"); print $$0, "=", ++count, ";"}' timing.H > ./include_auto/c_timing.h + @awk 'NF > 0 {if ( $$0 ~ "define") print $$0, $$3"_r4"; else print $0}' precision.H > ./include_auto/precision_r4.h + @awk 'NF > 0 {if ( $$0 ~ "define") print $$0, $$3"_r16"; else print $0}' precision.H > ./include_auto/precision_r16.h +# @awk 'NF > 0 {print $$0, $$3"_r4"}' precision.H > ./include_auto/precision_r4.h +# @awk 'NF > 0 {print $$0, $$3"_r16"}' precision.H > ./include_auto/precision_r16.h Modules: cd modules && $(MAKE) @@ -248,28 +256,20 @@ prep-htc: prep-gnu: $(MAKE) prep PLATFORM=gnu -prep-kekb: - $(MAKE) prep PLATFORM=kekb - prep-linux: $(MAKE) prep PLATFORM=linux -prep-riken: - $(MAKE) prep PLATFORM=riken - -prep-kpc4: - $(MAKE) prep PLATFORM=intel-kpc4 - -prep-zn: - $(MAKE) prep PLATFORM=intel-zn prep-qp: $(MAKE) prep PLATFORM=QPACE + prep-juice: $(MAKE) prep PLATFORM=juice -prep-rgbg: - $(MAKE) prep PLATFORM=rgbg -prep-athene: - $(MAKE) prep PLATFORM=athene + +prep-k: + $(MAKE) prep PLATFORM=k + +prep-supermig: + $(MAKE) prep PLATFORM=supermig gj_test: gj.o gj_test.o misc.o service.o ranf.o diff --git a/src/Makefile.in b/src/Makefile.in index ec2b373e6ee6f0d0cc44503193fef22cd1164d87..7e73496ac4debce9648b0dfd04795085762f2350 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -4,7 +4,7 @@ # #------------------------------------------------------------------------------- # -# Copyright (C) 2009 Yoshifumi Nakamura +# Copyright (C) 2009-2011 Yoshifumi Nakamura # # This file is part of BQCD -- Berlin Quantum ChromoDynamics program # @@ -25,24 +25,47 @@ include $(DIR)Makefile.var #------------------------------------------------------------------------------- # +# macro +# +M4=m4 +#------------------------------------------------------------------------------- +# # bqcdi options # omtdtd =1 -libdi = # [chroma|chiral|ddhmc|bqcd] empty means bqcd gamma = doedeo = flipsc = qpace = +quad = +# if tune Ration approximation, remove # +# FMLIB = ./fmlib + #------------------------------------------------------------------------------- # -# path for LIBs +# path for own LIBs. If unnecessary, comment out # -LIME = $(HOME)/opt/lime-1.3.1 -#FMLIB = $(HOME)/opt/FMLIB +COMPILER=gnu_mpich +ifndef LIME +LIME = $(HOME)/opt/lime-1.3.1 +endif + +ifndef LAPACK +LAPACK = $(HOME)/lib/$(COMPILER)/lapack.a $(HOME)/lib/$(COMPILER)/blas.a +endif + +ifndef SCALAPACK +SCALAPACK= $(HOME)/lib/$(COMPILER)/scalapack.a $(HOME)/lib/$(COMPILER)/blacs.a +endif + +ifndef ARPACK +#ARPACK = $(HOME)/lib/$(COMPILER)/arpack.a +endif + +#LEMON = $(HOME)/opt/lemon #BAGEL = $(HOME)/chroma/for_bqcd/install_146s -#ARPACK = $(HOME)/opt/ARPACK/libarpack_SUN4.a -#LAPACK = $(HOME)/work/opt/lapack-3.2.1/lapack_LINUX.a $(HOME)/work/opt/lapack-3.2.1/blas_LINUX.a + #------------------------------------------------------------------------------- # # debug options @@ -58,27 +81,39 @@ SYSLIBS += $(LIME)/lib/liblime.a LIBILDG = libildg.a endif +ifdef LEMON +CFLAGS_STD +=-I$(LEMON)/include +SYSLIBS += $(LEMON)/src/liblemon.a +MYFLAGS += -DLEMON +endif + ifdef FMLIB -MODULES_FLAG += -I$(FMLIB) +MODULES_FLAG += -I../../$(FMLIB) # from fermi/rhmc SYSLIBS += $(FMLIB)/lib_FM.a MYFLAGS += -DFMLIB endif +ifdef SCALAPACK +SYSLIBS += $(SCALAPACK) +MYFLAGS += -DSCALAPACK +endif + ifdef ARPACK -SYSLIBS += $(ARPACK) +SYSLIBS += $(ARPACK) +MYFLAGS += -DARPACK endif ifdef LAPACK -SYSLIBS += $(LAPACK) +SYSLIBS += $(LAPACK) +MYFLAGS += -DLAPACK endif -ifeq ($(libd),100) - libdi=100 +ifdef quad +MYFLAGS += -DQUAD endif ifdef BAGEL -libd =21 -libdi =100 +libd =100 gamma =chroma qmp =1 flipsc =1 @@ -89,6 +124,10 @@ SYSLIBS += $(BAGEL)/lib/libwfm.a \ $(BAGEL)/lib/libqmp.a -lstdc++ endif +ifeq ($(libd),100) + libdi=100 +endif + ifeq ($(libd),500) MYFLAGS += -DD500 endif diff --git a/src/Makefile.var b/src/Makefile.var index c8c738c48f08f20ffd01de755ac2178036523c87..edeaa9606132c03db7c1506644adcfa6c5f3ef0a 120000 --- a/src/Makefile.var +++ b/src/Makefile.var @@ -1 +1 @@ -platform/Makefile-linux.var \ No newline at end of file +platform/Makefile-gnu.var \ No newline at end of file diff --git a/src/boundary/Makefile b/src/boundary/Makefile index d9278c7fa04e4bde83734f1eea497b1b14d284a3..071ecb33b6cc25e7e5f1e93628d234b85dfbdb63 100644 --- a/src/boundary/Makefile +++ b/src/boundary/Makefile @@ -39,8 +39,6 @@ endif $(fpp) -I../include $(MYFLAGS) $< > $*.f90 $(F90) -c $(FFLAGS) $*.f90 - - OBJS = \ bc.o \ flip_bc_normal.o \ @@ -49,8 +47,8 @@ OBJS = \ flip_bc_schfun.o \ schr_boundary_gauge.o -lib_boundary.a: $(OBJS) $(OBJS_DSF) - $(AR) $(ARFLAGS) rv $@ $(OBJS) $(OBJS_DSF) +lib_boundary.a: $(OBJS) + $(AR) $(ARFLAGS) rv $@ $(OBJS) clobber: rm -f *.[Tiod] *.f90 *.mod work.pc work.pcl diff --git a/src/boundary/flip_bc_normal.F90 b/src/boundary/flip_bc_normal.F90 index 88ffcb897a7ec0cd98d3bf46f2223f373b8222d8..ddfd6d0382d31e0bc8f64b18423c47e792927cb4 100644 --- a/src/boundary/flip_bc_normal.F90 +++ b/src/boundary/flip_bc_normal.F90 @@ -125,31 +125,14 @@ end !------------------------------------------------------------------------------- subroutine flip_bc2_normal(u_flip, u) - - use module_flip_bc_normal - use module_lattice use module_vol implicit none GAUGE_FIELD, intent(in) :: u GAUGE_FIELD, intent(out) :: u_flip - integer :: mu, nu, count, i, eo, c1, c2 u_flip = u - - do mu = 1, DIM - nu = gamma_index(mu) - do eo = EVEN,ODD - do count = 1, flip_bc_len(mu,eo) - i = flip_bc_list(count, eo, mu) - do c2 = 1, NCOL - do c1 = 1, NCOL - u_flip(c1, c2, i, eo, nu) = -u(c1, c2, i, eo, nu) - enddo - enddo - enddo - enddo - enddo + call flip_bc1_normal(u_flip) end diff --git a/src/boundary/flip_bc_schfun.F90 b/src/boundary/flip_bc_schfun.F90 index 1ff31dde1573ffd4a57ec17aa0719831ca466d9e..a9ba11be36be8e77f13f8253131cd548ef9f45bf 100644 --- a/src/boundary/flip_bc_schfun.F90 +++ b/src/boundary/flip_bc_schfun.F90 @@ -25,95 +25,108 @@ # include "defs.h" !------------------------------------------------------------------------------- -subroutine flip_bc1_schfun(u_flip, u) - +subroutine flip_bc1_schfun(u) use module_schr_bc - use module_lattice use module_vol implicit none - integer, dimension(DIM) :: i_pe - GAUGE_FIELD, intent(in) :: u - GAUGE_FIELD, intent(out) :: u_flip - integer :: mu, nu, count, i, eo - - u_flip = u + GAUGE_FIELD, intent(inout) :: u + integer :: count, i, eo - mu = gamma_index(4) do eo = EVEN,ODD + ! + ! P+ psi(T)=0 + ! + !$omp parallel do private(i) - do count = 1, bc_len_bb(eo) - i = bc_list_bb(count, eo) - call u_zero(u_flip(1, 1, i, eo, mu)) + do count = 1, bc_len_t_all(eo) + i = bc_list_t_all(count, eo) + u(:, :, i, eo, 4)=ZERO enddo + ! + ! P- psi(0)=0 + ! + !$omp parallel do private(i) - do count = 1, bc_len_tt(eo) - i = bc_list_tt(count, eo) - call u_zero(u_flip(1, 1, i, eo, mu)) + do count = 1, bc_len_b_all(eo) + i = bc_list_b_all(count, eo) + u(:, :, i, eo, 1:4)=ZERO enddo + ! + ! out side of box + ! + !$omp parallel do private(i) - do count = 1, bc_len_b(eo) - i = bc_list_b(count, eo) - call u_zero(u_flip(1, 1, i, eo, mu)) + do count = 1, bc_len_bb(eo) + i = bc_list_bb(count, eo) + u(:, :, i, eo, 1:4)=ZERO enddo - !$omp parallel do private(i) - do count = 1, bc_len_t(eo) - i = bc_list_t(count, eo) - call u_zero(u_flip(1, 1, i, eo, mu)) + do count = 1, bc_len_tp(eo) + i = bc_list_tp(count, eo) + u(:, :, i, eo, 1:4)=ZERO enddo - enddo end !------------------------------------------------------------------------------- subroutine flip_bc2_schfun(u_flip, u) - - use module_schr_bc - use module_lattice use module_vol implicit none - integer, dimension(DIM) :: i_pe GAUGE_FIELD, intent(in) :: u GAUGE_FIELD, intent(out) :: u_flip - integer :: mu, nu, count, i, eo u_flip = u - - mu = gamma_index(4) - do eo = EVEN,ODD - - !$omp parallel do private(i) - do count = 1, bc_len_bb(eo) - i = bc_list_bb(count, eo) - call u_zero(u_flip(1, 1, i, eo, mu)) - enddo - - !$omp parallel do private(i) - do count = 1, bc_len_tt(eo) - i = bc_list_tt(count, eo) - call u_zero(u_flip(1, 1, i, eo, mu)) - enddo - - !$omp parallel do private(i) - do count = 1, bc_len_b(eo) - i = bc_list_b(count, eo) - call u_zero(u_flip(1, 1, i, eo, mu)) - enddo - - !$omp parallel do private(i) - do count = 1, bc_len_t(eo) - i = bc_list_t(count, eo) - call u_zero(u_flip(1, 1, i, eo, mu)) - enddo - - enddo + call flip_bc1_schfun(u_flip) end +!!!------------------------------------------------------------------------------- +!!subroutine flip_bc1_schfun_pcac(u) +!! use module_schr_bc +!! use module_vol +!! implicit none +!! +!! GAUGE_FIELD, intent(inout) :: u +!! integer :: mu, count, i, eo +!! +!! mu = 4 +!! do eo = EVEN,ODD +!! +!! ! +!! ! out side of box +!! ! +!! +!! !$omp parallel do private(i) +!! do count = 1, bc_len_bb(eo) +!! i = bc_list_bb(count, eo) +!! u(:, :, i, eo, 1:4)=ZERO +!! enddo +!! !$omp parallel do private(i) +!! do count = 1, bc_len_tp(eo) +!! i = bc_list_tp(count, eo) +!! u(:, :, i, eo, 1:4)=ZERO +!! enddo +!! enddo +!! +!!end +!! +!!!------------------------------------------------------------------------------- +!!subroutine flip_bc2_schfun_pcac(u_flip, u) +!! use module_vol +!! implicit none +!! +!! GAUGE_FIELD, intent(in) :: u +!! GAUGE_FIELD, intent(out) :: u_flip +!! +!! u_flip = u +!! call flip_bc1_schfun_pcac(u_flip) +!! +!!end +!! !=============================================================================== diff --git a/src/boundary/init_schr_bc.F90 b/src/boundary/init_schr_bc.F90 index 76e0dc3a56dca15b48803788a8787ca084c8be1b..7f43de8d60c8e81700bf5f71a8936703f0c8f1cc 100644 --- a/src/boundary/init_schr_bc.F90 +++ b/src/boundary/init_schr_bc.F90 @@ -27,60 +27,68 @@ !------------------------------------------------------------------------------- module module_schr_bc + INTEGER, dimension(:, :), pointer, save :: bc_list_1 INTEGER, dimension(:, :), pointer, save :: bc_list_b INTEGER, dimension(:, :), pointer, save :: bc_list_t INTEGER, dimension(:, :), pointer, save :: bc_list_bb - INTEGER, dimension(:, :), pointer, save :: bc_list_tt - INTEGER, dimension(:, :), pointer, save :: bc_list_in + INTEGER, dimension(:, :), pointer, save :: bc_list_tp + INTEGER, dimension(:, :), pointer, save :: bc_list_b_all + INTEGER, dimension(:, :), pointer, save :: bc_list_t_all - integer, dimension(EVEN:ODD), save :: bc_len_b - integer, dimension(EVEN:ODD), save :: bc_len_t - integer, dimension(EVEN:ODD), save :: bc_len_bb - integer, dimension(EVEN:ODD), save :: bc_len_tt - integer, dimension(EVEN:ODD), save :: bc_len_in + INTEGER, dimension(EVEN:ODD), save :: bc_len_1 + INTEGER, dimension(EVEN:ODD), save :: bc_len_b + INTEGER, dimension(EVEN:ODD), save :: bc_len_t + INTEGER, dimension(EVEN:ODD), save :: bc_len_bb + INTEGER, dimension(EVEN:ODD), save :: bc_len_tp + INTEGER, dimension(EVEN:ODD), save :: bc_len_b_all + INTEGER, dimension(EVEN:ODD), save :: bc_len_t_all + + REAL, save :: cps, cpt, crt end !------------------------------------------------------------------------------- subroutine init_schr_bc() - - use module_schr_bc - use module_function_decl - use module_lattice - use module_vol + use module_schr_bc + use module_function_decl + use module_lattice + use module_vol implicit none - integer, dimension(DIM) :: i0, i1, i_pe, j - integer :: me, mu, x, y, z, t, i, eo, count(EVEN:ODD) + integer, dimension(DIM) :: i_pe, j + integer :: mu, x, y, z, t, i, eo, dmin(3), dmax(3) integer, external :: xyzt2i, e_o + if (NPE(4) == 1 ) call die("so far schr bc does not work in NPE(4)=1 ") call my_coord(i_pe) - mu = gamma_index(4) - if (NPE(mu) == 1 ) call die("so far schr bc does not work in NPE(4)=1 ") - - allocate(bc_list_b(volh_tot, EVEN:ODD)) - allocate(bc_list_t(volh_tot, EVEN:ODD)) - allocate(bc_list_bb(volh_tot, EVEN:ODD)) - allocate(bc_list_tt(volh_tot, EVEN:ODD)) - allocate(bc_list_in(volh_tot, EVEN:ODD)) + + allocate(bc_list_1( (nx+2)*(ny+2)*(nz+2), EVEN:ODD)) + allocate(bc_list_b( (nx+2)*(ny+2)*(nz+2), EVEN:ODD)) + allocate(bc_list_t( (nx+2)*(ny+2)*(nz+2), EVEN:ODD)) + allocate(bc_list_bb((nx+2)*(ny+2)*(nz+2), EVEN:ODD)) + allocate(bc_list_tp((nx+2)*(ny+2)*(nz+2), EVEN:ODD)) + allocate(bc_list_b_all( (nx+2)*(ny+2)*(nz+2), EVEN:ODD)) + allocate(bc_list_t_all( (nx+2)*(ny+2)*(nz+2), EVEN:ODD)) + bc_len_1 = 0 bc_len_b = 0 bc_len_t = 0 bc_len_bb = 0 - bc_len_tt = 0 - bc_len_in = 0 - -!==========================================================t -!----------------------------------------------------------t - if (i_pe(mu) == (NPE(mu) - 1)) then - i0 = 0 - i1 = N - 1 - i0(mu) = N(mu) - 1 - i1(mu) = i0(mu) - do t = i0(4), i1(4) - do z = i0(3), i1(3) - do y = i0(2), i1(2) - do x = i0(1), i1(1) - j = (/x, y, z, t/) + bc_len_tp = 0 + bc_len_b_all = 0 + bc_len_t_all = 0 + + do mu = 1, 3 + dmin(mu) = 0 + dmax(mu) = n(mu) - 1 + if (NPE(mu) > 1) dmin(mu) = -1 + if (NPE(mu) > 1) dmax(mu) = n(mu) + enddo + + if ( i_pe(4) == (NPE(4) - 1) ) then !! t=T-1 + do x = 0, n(1) - 1 + do y = 0, n(2) - 1 + do z = 0, n(3) - 1 + j = (/x, y, z, nt-1/) i = xyzt2i(j) eo = e_o(j) bc_len_t(eo) = bc_len_t(eo) + 1 @@ -88,55 +96,35 @@ subroutine init_schr_bc() enddo enddo enddo - enddo -!----------------------------------------------------------tt - i0 = 0 - i1 = N - 1 - i0(mu) = N(mu) - i1(mu) = i0(mu) - do t = i0(4), i1(4) - do z = i0(3), i1(3) - do y = i0(2), i1(2) - do x = i0(1), i1(1) - j = (/x, y, z, t/) + do x = dmin(1), dmax(1) + do y = dmin(2), dmax(2) + do z = dmin(3), dmax(3) + j = (/x, y, z, nt-1/) i = xyzt2i(j) eo = e_o(j) - bc_len_tt(eo) = bc_len_tt(eo) + 1 - bc_list_tt(bc_len_tt(eo), eo) = i + bc_len_t_all(eo) = bc_len_t_all(eo) + 1 + bc_list_t_all(bc_len_t_all(eo), eo) = i enddo enddo enddo - enddo -!----------------------------------------------------------t in - i0 = 0 - i1 = N - 1 - i0(mu) = N(mu) -2 - i1(mu) = i0(mu) - do t = i0(4), i1(4) - do z = i0(3), i1(3) - do y = i0(2), i1(2) - do x = i0(1), i1(1) - j = (/x, y, z, t/) + + do x = dmin(1), dmax(1) + do y = dmin(2), dmax(2) + do z = dmin(3), dmax(3) + j = (/x, y, z, nt/) i = xyzt2i(j) eo = e_o(j) - bc_len_tt(eo) = bc_len_tt(eo) + 1 - bc_list_tt(bc_len_tt(eo), eo) = i - enddo + bc_len_tp(eo) = bc_len_tp(eo) + 1 + bc_list_tp(bc_len_tp(eo), eo) = i enddo enddo enddo -!==========================================================b -!----------------------------------------------------------b - elseif (i_pe(mu) == 0) then - i0 = 0 - i1 = N - 1 - i0(mu) = 0 - i1(mu) = i0(mu) - do t = i0(4), i1(4) - do z = i0(3), i1(3) - do y = i0(2), i1(2) - do x = i0(1), i1(1) - j = (/x, y, z, t/) + endif + if ( i_pe(4) == 0 ) then !! t=0 + do x = 0, n(1) - 1 + do y = 0, n(2) - 1 + do z = 0, n(3) - 1 + j = (/x, y, z, 0/) i = xyzt2i(j) eo = e_o(j) bc_len_b(eo) = bc_len_b(eo) + 1 @@ -144,17 +132,21 @@ subroutine init_schr_bc() enddo enddo enddo + do x = dmin(1), dmax(1) + do y = dmin(2), dmax(2) + do z = dmin(3), dmax(3) + j = (/x, y, z, 0/) + i = xyzt2i(j) + eo = e_o(j) + bc_len_b_all(eo) = bc_len_b_all(eo) + 1 + bc_list_b_all(bc_len_b_all(eo), eo) = i + enddo + enddo enddo -!----------------------------------------------------------bb - i0 = 0 - i1 = N - 1 - i0(mu) = -1 - i1(mu) = i0(mu) - do t = i0(4), i1(4) - do z = i0(3), i1(3) - do y = i0(2), i1(2) - do x = i0(1), i1(1) - j = (/x, y, z, t/) + do x = dmin(1), dmax(1) + do y = dmin(2), dmax(2) + do z = dmin(3), dmax(3) + j = (/x, y, z, -1/) i = xyzt2i(j) eo = e_o(j) bc_len_bb(eo) = bc_len_bb(eo) + 1 @@ -162,44 +154,42 @@ subroutine init_schr_bc() enddo enddo enddo - enddo -!----------------------------------------------------------b in - i0 = 0 - i1 = N - 1 - i0(mu) = 1 - i1(mu) = i0(mu) - do t = i0(4), i1(4) - do z = i0(3), i1(3) - do y = i0(2), i1(2) - do x = i0(1), i1(1) - j = (/x, y, z, t/) + endif + + if (nt > 1 .and. i_pe(4) == 0) then + do x = 0, n(1) - 1 + do y = 0, n(2) - 1 + do z = 0, n(3) - 1 + j = (/x, y, z, 1/) i = xyzt2i(j) eo = e_o(j) - bc_len_in(eo) = bc_len_in(eo) + 1 - bc_list_in(bc_len_in(eo), eo) = i - enddo + bc_len_1(eo) = bc_len_1(eo) + 1 + bc_list_1(bc_len_1(eo), eo) = i enddo enddo enddo - else -!==========================================================in - i0 = 0 - i1 = N - 1 - do t = i0(4), i1(4) - do z = i0(3), i1(3) - do y = i0(2), i1(2) - do x = i0(1), i1(1) - j = (/x, y, z, t/) + endif + if(nt==1 .and. i_pe(4) == 1) then + do x = 0, n(1) - 1 + do y = 0, n(2) - 1 + do z = 0, n(3) - 1 + j = (/x, y, z, 0/) i = xyzt2i(j) eo = e_o(j) - bc_len_in(eo) = bc_len_in(eo) + 1 - bc_list_in(bc_len_in(eo), eo) = i - enddo + bc_len_1(eo) = bc_len_1(eo) + 1 + bc_list_1(bc_len_1(eo), eo) = i enddo enddo enddo endif +!write(*,*)",bc_len_t e",my_pe(),bc_len_t(0) +!write(*,*)",bc_len_b o",my_pe(),bc_len_b(1) +!write(*,*)",bc_len_t o",my_pe(),bc_len_t(1) +!call flush(6) +!call comm_finalize() +!stop + end !=============================================================================== diff --git a/src/boundary/init_schr_weight.F90 b/src/boundary/init_schr_weight.F90 index 05cd12998c753802a4d332f48e5ef672464c0c49..cb8f624a3e80399597462e56190eed5066e01806 100644 --- a/src/boundary/init_schr_weight.F90 +++ b/src/boundary/init_schr_weight.F90 @@ -26,45 +26,40 @@ !------------------------------------------------------------------------------- subroutine init_schr_weight() - use module_schr_weight use module_schr_bc use module_vol - use module_lattice implicit none - REAL :: cpt,cps,crt - integer :: mu, nu, mu1, nu1, eo, i, count + integer :: mu, nu, eo, i, count - cps = 0.3_8 - cpt = 0.9_8 - crt = TWO/THREE + cps = 0.5_8 + cpt = ONE + crt = 1.5_8 allocate(cp(volh_tot, EVEN:ODD, DIM, DIM)) allocate(cr1(volh_tot, EVEN:ODD, DIM, DIM)) allocate(cr2(volh_tot, EVEN:ODD, DIM, DIM)) cp = ONE - cr1 = ONE - cr2 = ONE + cr1 = ONE ! horizontally long + cr2 = ONE ! vetically long do mu = 1, DIM do nu = 1, DIM if (mu /= nu) then - mu1 = gamma_index(mu) - nu1 = gamma_index(nu) if (mu == 4 .or. nu == 4) then do eo = EVEN,ODD do count = 1, bc_len_b(eo) i = bc_list_b(count, eo) - cp(i, eo, mu1, nu1) = cpt - cr1(i, eo, mu1, nu1) = crt - cr2(i, eo, mu1, nu1) = ONE + cp(i, eo, mu, nu) = cpt + cr1(i, eo, mu, nu) = crt + cr2(i, eo, mu, nu) = crt enddo do count = 1, bc_len_t(eo) i = bc_list_t(count, eo) - cp(i, eo, mu1, nu1) = cpt - cr1(i, eo, mu1, nu1) = crt - cr2(i, eo, mu1, nu1) = ZERO + cp(i, eo, mu, nu) = cpt + cr1(i, eo, mu, nu) = crt + cr2(i, eo, mu, nu) = ZERO enddo enddo endif @@ -72,9 +67,15 @@ subroutine init_schr_weight() do eo = EVEN,ODD do count = 1, bc_len_b(eo) i = bc_list_b(count, eo) - cp(i, eo, mu1, nu1) = cps - cr1(i, eo, mu1, nu1) = ZERO - cr2(i, eo, mu1, nu1) = ZERO + cp(i, eo, mu, nu) = cps + cr1(i, eo, mu, nu) = ZERO + cr2(i, eo, mu, nu) = ZERO + enddo + do count = 1, bc_len_tp(eo) + i = bc_list_tp(count, eo) + cp(i, eo, mu, nu) = cps + cr1(i, eo, mu, nu) = ZERO + cr2(i, eo, mu, nu) = ZERO enddo enddo endif diff --git a/src/boundary/schr_boundary_gauge.F90 b/src/boundary/schr_boundary_gauge.F90 index 010dfa0cb6b775856704afbcaf2baf00721c1638..1c277b369c2e2974793b7282dcf5105969704ec5 100644 --- a/src/boundary/schr_boundary_gauge.F90 +++ b/src/boundary/schr_boundary_gauge.F90 @@ -41,105 +41,511 @@ subroutine schr_boundary_gauge(u) GAUGE_FIELD, intent(inout) :: u integer :: mu, nu, count, i, eo, c1, c2, mu1 - COMPLEX :: bound, bound1(3), bound2(3) - -REAL,external :: Re_Tr_uu,sg - -SU3::uuu -integer::j1,j2,o,e -REAL::p - - - bound1(1) = cmplx(dcos(PI/SIX), -dsin(PI/SIX), kind = RKIND) - bound1(2) = cmplx(ONE, ZERO, kind = RKIND) - bound1(3) = cmplx(dcos(PI/SIX), dsin(PI/SIX), kind = RKIND) - bound2(1) = cmplx(dcos(5.0_8*PI/SIX), -dsin(5.0_8*PI/SIX), kind = RKIND) - bound2(2) = cmplx(dcos(PI/THREE), dsin(PI/THREE), kind = RKIND) - bound2(3) = cmplx(dcos(PI/TWO), dsin(PI/TWO), kind = RKIND) - -write(STDERR,*)sg(u) - do mu = 1, 1!4!3 !DIM - mu1 = gamma_index(mu) - do eo = EVEN,ODD - do count = 1, bc_len_b(eo) - i = bc_list_b(count, eo) - do c2 = 1, NCOL - do c1 = 1, NCOL - u(c1, c2, i, eo, mu1) = ZERO - enddo + REAL :: phi0(3), phi1(3), dl(3) + COMPLEX :: bound, bd1(3,3), bd2(3,3) + + phi0(1)=-PI/SIX + phi0(2)= ZERO + phi0(3)=-(phi0(1)+phi0(2)) + phi1(1)=-5.0_8*PI/SIX + phi1(2)= 2.0_8*PI/SIX + phi1(3)=-(phi1(1)+phi1(2)) + + dl(1)=dble(lx) + dl(2)=dble(ly) + dl(3)=dble(lz) + do c1 =1, 3 + do mu =1, 3 + bd1(c1,mu) = cmplx(dcos(phi0(c1)/dl(mu)), dsin(phi0(c1)/dl(mu)),kind=RKIND) + bd2(c1,mu) = cmplx(dcos(phi1(c1)/dl(mu)), dsin(phi1(c1)/dl(mu)),kind=RKIND) + enddo + enddo + + do eo = EVEN,ODD + ! + ! put 0 for links at t = -1 + ! + do mu = 1, 4 + do count = 1, bc_len_bb(eo) + i = bc_list_bb(count, eo) + u(:, :, i, eo, mu) = ZERO + enddo + enddo + ! + ! put Schr bound for (1,2,3)-dir links at t = 0 + ! + do mu = 1, 3 + do count = 1, bc_len_b_all(eo) + i = bc_list_b_all(count, eo) + u(:, :, i, eo, mu) = ZERO + do c1 = 1, NCOL + u(c1, c1, i, eo, mu) = bd1(c1,mu) + enddo + enddo + enddo + ! + ! put Schr bound for (1,2,3)-dir links at t = T+1 + ! + do mu = 1, 3 + do count = 1, bc_len_tp(eo) + i = bc_list_tp(count, eo) + u(:, :, i, eo, mu) = ZERO + do c1 = 1, NCOL + u(c1, c1, i, eo, mu) = bd2(c1,mu) enddo -! do c2 = 1, NCOL -! u(c2, c2, i, eo, mu1) = bound1(c2) -! enddo enddo -! do count = 1, bc_len_tt(eo) -!!write(STDERR,*)my_pe(),"ttttt" -! i = bc_list_tt(count, eo) -! do c2 = 1, NCOL -! do c1 = 1, NCOL -! u(c1, c2, i, eo, mu1) = ZERO -! enddo -! enddo -!! do c2 = 1, NCOL -!! u(c2, c2, i, eo, mu1) = bound2(c2) -!! enddo -! enddo + enddo + ! + ! put 0 for 4-dir links at t = T+1 + ! + do count = 1, bc_len_tp(eo) + i = bc_list_tp(count, eo) + u(:, :, i, eo, 4) = ZERO + enddo + enddo + +end + +!------------------------------------------------------------------------------- +subroutine schr_boundary_zero3(u) ! put 0 out of boundary + use module_schr_bc + use module_vol + implicit none + GAUGE_FIELD, intent(inout) :: u + integer :: mu, count, i, eo + + do eo = EVEN,ODD + ! + ! put 0 for spacial links at t = 0 + ! + do count = 1, bc_len_b_all(eo) + i = bc_list_b_all(count, eo) + u(:, :, i, eo, 1:3) = ZERO + enddo + enddo + +end + +!------------------------------------------------------------------------------- +subroutine schr_boundary_zero4(u) ! put 0 out of boundary + use module_schr_bc + use module_vol + implicit none + GAUGE_FIELD, intent(inout) :: u + integer :: mu, count, i, eo + + do eo = EVEN,ODD + ! + ! put 0 for links at t = -1 + ! + do count = 1, bc_len_bb(eo) + i = bc_list_bb(count, eo) + u(:, :, i, eo, 1:4) = ZERO + enddo + ! + ! put 0 for links at t = T+1 + ! + do count = 1, bc_len_tp(eo) + i = bc_list_tp(count, eo) + u(:, :, i, eo, 1:4) = ZERO enddo enddo -! do mu = 1, DIM -! do eo = EVEN,ODD -! do count = 1, bc_len_bb(eo) -! i = bc_list_bb(count, eo) -! do c2 = 1, NCOL -! do c1 = 1, NCOL -! u(c1, c2, i, eo, mu) = ZERO -! enddo -! enddo -! enddo -! enddo -! enddo +end + +!------------------------------------------------------------------------------- +subroutine schr_boundary_p(p) + use module_schr_bc + use module_vol + implicit none + GENERATOR_FIELD, intent(inout) :: p + integer :: eo, i, count -!STOP + ! + ! put 0 for (1,2,3)-dir links at t = 0 + ! + do eo = EVEN,ODD + do count = 1, bc_len_b(eo) + i = bc_list_b(count, eo) + p(:, i, eo, 1:3) = ZERO + enddo + enddo +end +!------------------------------------------------------------------------------- +REAL function s_plaq_sfdiff(u) ! returns S_g only diff by SF + use module_schr_weight + use module_schr_bc + use module_lattice + use module_nn + use module_vol + implicit none + GAUGE_FIELD :: u + REAL :: p + SU3 :: uuu + integer :: i, e, o, mu, nu, j1, j2, count + REAL, external :: Re_Tr_uu, global_sum + DEBUG2S("Start: s_plaq_sfdiff") + p = ZERO do mu = 1, DIM + do nu = mu + 1, DIM + if (mu /= 4 .and. nu /= 4) cycle + do e = EVEN, ODD + o = EVEN + ODD - e + !$omp parallel do reduction(+: p) private(i, j1, j2, uuu) + do count = 1, bc_len_b(e) + i = bc_list_b(count, e) + j1 = nn(i, e, mu, FWD) + j2 = nn(i, e, nu, FWD) + call udd_imp(uuu, u(1, 1, j1, o, nu), & + u(1, 1, j2, o, mu), & + u(1, 1, i, e, nu)) + p = p + (ONE - Re_Tr_uu(uuu, u(1, 1, i, e, mu))/THREE ) * ( cpt -ONE ) + enddo + + !$omp parallel do reduction(+: p) private(i, j1, j2, uuu) + do count = 1, bc_len_t(e) + i = bc_list_t(count, e) + j1 = nn(i, e, mu, FWD) + j2 = nn(i, e, nu, FWD) + call udd_imp(uuu, u(1, 1, j1, o, nu), & + u(1, 1, j2, o, mu), & + u(1, 1, i, e, nu)) + p = p + (ONE - Re_Tr_uu(uuu, u(1, 1, i, e, mu))/THREE ) * ( cpt -ONE ) + enddo + enddo + enddo + enddo + + s_plaq_sfdiff = global_sum(p) +!! call sf_classical_action() + DEBUG2S("End: s_plaq_sfdiff") + +end + +!------------------------------------------------------------------------------- +subroutine dsg_sfdiff(p, plaq, step) + use module_schr_weight + use module_schr_bc + use module_field + use module_action_type + use module_vol + use module_nn + implicit none + + GENERATOR_FIELD, intent(inout) :: p + type(type_plaq), intent(in) :: plaq + REAL, intent(in) :: step + REAL :: s + SU3 :: uuu, w + integer :: mu, nu, e, o, i, j1, j2, count + + s = - step * plaq%beta / THREE * ( cpt - ONE ) + + if (s == ZERO) return + + DEBUG2S("Start: dsg_sfdiff") + + do mu = 1, 3 do e = EVEN, ODD o = EVEN + ODD - e - do nu = mu + 1, DIM - p = ZERO - !$omp parallel do reduction(+: p) private(j1, j2, uuu) - do i = 1, VOLH - ! (j2,o) --<-- x nu - ! | | - ! v ^ ^ - ! | | | - ! (i,e) -->-- (j1,o) x--> mu + !$omp parallel do private(i, j1, j2, uuu, w) + do count = 1, bc_len_1(e) + i = bc_list_1(count, e) + j1 = nn(i, e, 4, BWD) + j2 = nn(j1, o, mu, FWD) + call ddu_imp(uuu, gauge(1)%u(1, 1,j2, e, 4), & + gauge(1)%u(1, 1,j1, o, mu), & + gauge(1)%u(1, 1,j1, o, 4)) + call uu(w, gauge(1)%u(1, 1, i, e, mu), uuu) + call im_tr_j(p(1, i, e, mu), w, s) + enddo + !$omp parallel do private(i, j1, j2, uuu, w) + do count = 1, bc_len_t(e) + i = bc_list_t(count, e) + j1 = nn(i, e, mu, FWD) + j2 = nn(i, e, 4, FWD) + call udd_imp(uuu, gauge(1)%u(1, 1, j1, o, 4), & + gauge(1)%u(1, 1, j2, o, mu), & + gauge(1)%u(1, 1, i, e, 4)) + call uu(w, gauge(1)%u(1, 1, i, e, mu), uuu) + call im_tr_j(p(1, i, e, mu), w, s) + enddo + enddo + enddo - j1 = nn(i, e, mu, FWD) - j2 = nn(i, e, nu, FWD) - - uuu = 0 - call uuu_fwd(uuu, u(1, 1, j1, o, nu), & - u(1, 1, j2, o, mu), & - u(1, 1, i, e, nu)) + do e = EVEN, ODD + !$omp parallel do private(i, j1, j2, uuu, w) + do count = 1, bc_len_b(e) + i = bc_list_b(count, e) + call staple(uuu, gauge(1)%u, i, e, 4) + call uu(w, gauge(1)%u(1, 1, i, e, 4), uuu) + call im_tr_j(p(1, i, e, 4), w, s) + enddo - p = Re_Tr_uu(uuu, u(1, 1, i, e, mu)) -if(p< 0.00001)write(STDERR,*)"zero u",my_pe(),i,& -"eo=",e,"munu=",mu,nu,u(1, 1, i, e, mu),u(1, 1, j1, o, nu), u(1, 1, j2, o, mu), u(1, 1, i, e, nu),j2 + !$omp parallel do private(i, j1, j2, uuu, w) + do count = 1, bc_len_t(e) + i = bc_list_t(count, e) + call staple(uuu, gauge(1)%u, i, e, 4) + call uu(w, gauge(1)%u(1, 1, i, e, 4), uuu) + call im_tr_j(p(1, i, e, 4), w, s) + enddo + enddo - enddo + DEBUG2S("End: dsg_sfdiff") +end + +!------------------------------------------------------------------------------- +REAL function s_rect_sfdiff(u) ! returns S_g only diff by SF + use module_schr_weight + use module_schr_bc + use module_lattice + use module_nn + use module_vol + use module_switches + implicit none + + GAUGE_FIELD :: u, w1, w2 + REAL :: p + SU3 :: uuu + integer :: i, e, o, mu, nu, j1, j2, count + REAL, external :: Re_Tr_uu, global_sum + + DEBUG2S("Start: s_rect_sfdiff") + + p = ZERO + do mu = 1, 3 + call r_staple(w1, u(1,1,1,0,1), mu) + if (switches%boundary_sf) call schr_boundary_zero4(w1) + + do e = EVEN, ODD + o = EVEN + ODD - e + + !$omp parallel do reduction(+: p) private(i, j1, j2, uuu) + do count = 1, bc_len_b(e) + i = bc_list_b(count, e) + j1 = nn(i , e, mu, FWD) + j2 = nn(i , e, 4, FWD) + uuu = ZERO + call uddp(uuu, w1(1, 1, j1, o, 4), & + u(1, 1, j2, o, mu), & + u(1, 1, i , e, 4)) + p = p + (ONE - Re_Tr_uu(uuu, u(1, 1, i, e, mu))/THREE ) * ( crt - ONE ) + enddo + + !$omp parallel do reduction(+: p) private(i, j1, j2, uuu) + do count = 1, bc_len_t(e) + i = bc_list_t(count, e) + j1 = nn(i , e, mu, FWD) + j2 = nn(i , e, 4, FWD) + uuu = ZERO + call uddp(uuu, w1(1, 1, j1, o, 4), & + u(1, 1, j2, o, mu), & + u(1, 1, i , e, 4)) + p = p + (ONE - Re_Tr_uu(uuu, u(1, 1, i, e, mu))/THREE ) * ( crt - ONE ) enddo + enddo enddo - -write(STDERR,*)sg(u) -STOP + + !! 3*lx*ly*lz subtruction for rectangle sticking out of t=T + s_rect_sfdiff = global_sum(p) - dble(3*lx*ly*lz) + + DEBUG2S("End: s_rect_sfdiff") end +!------------------------------------------------------------------------------- +subroutine dsig_sfdiff(p, impg, step) + use module_schr_weight + use module_schr_bc + use module_field + use module_action_type + use module_vol + use module_nn + use module_switches + implicit none + + GENERATOR_FIELD, intent(inout) :: p + type(type_impg), intent(in) :: impg + REAL, intent(in) :: step + REAL :: s + SU3 :: uuu, w + integer :: mu, nu, e, o, i, j1, j2, count + COMPLEX, allocatable :: w1(:, :, :, :, :) + COMPLEX, allocatable :: w2(:, :, :, :, :) + + s = -step * impg%beta1 / THREE * ( crt - ONE ) + + if (s == ZERO) return + + DEBUG2S("Start: dsig_sfdiff") + allocate(w1(NCOL, NCOL, volh_tot, EVEN:ODD, DIM)) + allocate(w2(NCOL, NCOL, volh_tot, EVEN:ODD, DIM)) + + ! + ! right staple + ! + + + do mu = 1, 3 + call r_staple(w1, gauge(1)%u(1,1,1,0,1), mu) + if (switches%boundary_sf) call schr_boundary_zero4(w1) + do e = EVEN, ODD + o = EVEN + ODD - e + + ! 4==>---x t=1 + ! | | + ! x------mu t=0 + + !$omp parallel do private(i, j1, j2, uuu, w) + do count = 1, bc_len_1(e) + i = bc_list_1(count, e) + j1 = nn(i, e, 4, BWD) + j2 = nn(j1, o, mu, FWD) + call ddu_imp(uuu, w1(1, 1,j2, e, 4), & + gauge(1)%u(1, 1,j1, o, mu), & + gauge(1)%u(1, 1,j1, o, 4)) + call uu(w, gauge(1)%u(1, 1, i, e, mu), uuu) + call im_tr_j(p(1, i, e, mu), w, s) + enddo + + ! 4------x t=T + ! | | + ! x==>---mu t=T-1 + + !$omp parallel do private(i, j1, j2, uuu, w) + do count = 1, bc_len_t(e) + i = bc_list_t(count, e) + j1 = nn(i, e, mu, FWD) + j2 = nn(i, e, 4, FWD) + call udd_imp(uuu, w1(1, 1, j1, o, 4), & + gauge(1)%u(1, 1, j2, o, mu), & + gauge(1)%u(1, 1, i, e, 4)) + call uu(w, gauge(1)%u(1, 1, i, e, mu), uuu) + call im_tr_j(p(1, i, e, mu), w, s) + enddo + enddo + enddo + + ! + ! left stable + ! + + + do mu = 1, 3 + call l_staple(w1, gauge(1)%u(1,1,1,0,1), mu) + if (switches%boundary_sf) call schr_boundary_zero4(w1) + do e = EVEN, ODD + o = EVEN + ODD - e + + ! 4---==>x t=1 + ! | | + ! x------mu t=0 + + !$omp parallel do private(i, j1, j2, uuu, w) + do count = 1, bc_len_1(e) + i = bc_list_1(count, e) + j1 = nn(i, e, 4, BWD) + j2 = nn(j1, o, mu, FWD) + call ddu_imp(uuu, gauge(1)%u(1, 1,j2, e, 4), & + gauge(1)%u(1, 1,j1, o, mu), & + w1(1, 1,j1, o, 4)) + call uu(w, gauge(1)%u(1, 1, i, e, mu), uuu) + call im_tr_j(p(1, i, e, mu), w, s) + enddo + + ! 4------x t=T + ! | | + ! x---==>mu t=T-1 + + !$omp parallel do private(i, j1, j2, uuu, w) + do count = 1, bc_len_t(e) + i = bc_list_t(count, e) + j1 = nn(i, e, mu, FWD) + j2 = nn(i, e, 4, FWD) + call udd_imp(uuu, gauge(1)%u(1, 1, j1, o, 4), & + gauge(1)%u(1, 1, j2, o, mu), & + w1(1, 1, i, e, 4)) + call uu(w, gauge(1)%u(1, 1, i, e, mu), uuu) + call im_tr_j(p(1, i, e, mu), w, s) + enddo + enddo + + enddo + + call u_staple(w1, gauge(1)%u(1,1,1,0,1), 4) + call d_staple(w2, gauge(1)%u(1,1,1,0,1), 4) + if (switches%boundary_sf) call schr_boundary_zero4(w1) + if (switches%boundary_sf) call schr_boundary_zero4(w2) + + do e = EVEN, ODD + !$omp parallel do private(i, uuu, w) + do count = 1, bc_len_b(e) + i = bc_list_b(count, e) + call staple_ud(uuu, gauge(1)%u, w1, w2, i, e, 4) + call uu(w, gauge(1)%u(1, 1, i, e, 4), uuu) + call im_tr_j(p(1, i, e, 4), w, s) + enddo + + !$omp parallel do private(i, uuu, w) + do count = 1, bc_len_t(e) + i = bc_list_t(count, e) + call staple_ud(uuu, gauge(1)%u, w1, w2, i, e, 4) + call uu(w, gauge(1)%u(1, 1, i, e, 4), uuu) + call im_tr_j(p(1, i, e, 4), w, s) + enddo + enddo + + deallocate(w1,w2) + DEBUG2S("End: dsig_sfdiff") +end + +!------------------------------------------------------------------------------- +subroutine schrfunc_cswkappa(fac) + use module_schr_bc + use module_vol + REAL, intent(inout) :: fac(EVEN:ODD, volh) + integer :: eo, i, count + + do eo = EVEN,ODD + do count = 1, bc_len_b(eo) + i = bc_list_b(count, eo) + fac(eo, i) = ZERO + enddo + enddo + +end + +!------------------------------------------------------------------------------- + +!! +!! below must be correct +!! +!!!------------------------------------------------------------------------------- +!!subroutine sf_classical_action() +!! use module_action +!! use module_lattice +!! REAL :: lt3, lt6, sin1, sin2, w, lll, ca +!! +!! w = 1.5_8 +!! lll=lx*ly*lz +!! lt3=PI/dble(3*lt*lx) +!! lt6=PI/dble(6*lt*lx) +!! +!! sin0=sin( lt3)**2 + TWO * sin(lt6)**2 +!! sin1=sin(TWO*lt3)**2 + TWO * sin(lt3)**2 +!! +!! ca = c0*sin0*lt + c1*sin1*(2*lt -3 + 2*w) +!! +!!write(0,*)"sf_classical_action",ca * lll * 12 / g2 +!!call flush(0) +!! +!!end +!! !=============================================================================== diff --git a/src/bqcdi.F90 b/src/bqcdi.F90 index ed7cdc4bc86b6bd210cb91e8679a83d3a1537e36..45efa0de520be24bb25b339cddb78f96a2975305 100644 --- a/src/bqcdi.F90 +++ b/src/bqcdi.F90 @@ -91,6 +91,9 @@ program bqcd call init_cg_para() call init_cg_stat_all() call init_xbound() +#ifdef QUAD + call init_xbound_r16() +#endif #ifndef D500 call init_xbound_r4() #endif @@ -137,6 +140,9 @@ subroutine init_para(para, flags) use module_bqcd use module_input use module_mre +#ifdef QUAD + use module_mre_r16 +#endif use module_mre2 use module_switches use module_switches @@ -174,7 +180,10 @@ subroutine init_para(para, flags) para%cg_log = input%solver_ignore_no_convergence para%cg_check = input%solver_check_solution mre_n_vec = input%solver_mre_vectors - mre2_n_vec = input%solver_mre_vectors +#ifdef QUAD + mre_n_vec_r16 = input%solver_mre_vectors +#endif + mre2_n_vec = input%solver_mre_vectors switches%measure_rhmc_forces = (input%measure_rhmc_forces /= 0) switches%measure_minmax = (input%measure_minmax /= 0) @@ -223,6 +232,7 @@ subroutine init_para(para, flags) para%c_hmc(i)%n_stout = input%n_stout(i) para%c_hmc(i)%alpha = input%alpha(i) para%c_hmc(i)%theta = input%theta(i) + para%c_hmc(i)%chemi = input%chemi(i) read(para%c_hmc(i)%kappa_strange, *) para%hmc(i)%kappa_strange read(para%c_hmc(i)%rho2, *) para%hmc(i)%rho2 @@ -235,7 +245,8 @@ subroutine init_para(para, flags) read(para%c_hmc(i)%n_stout ,*) para%hmc(i)%n_stout read(para%c_hmc(i)%alpha ,*) para%hmc(i)%alpha read(para%c_hmc(i)%theta ,*) para%hmc(i)%theta - + read(para%c_hmc(i)%chemi ,*) para%hmc(i)%chemi +chemi=para%hmc(1)%chemi if (para%hmc(i)%kappa == ZERO .and. para%hmc(i)%csw /= ZERO) then para%hmc(i)%csw_kappa = para%hmc(i)%csw para%c_hmc(i)%csw = "-1 (infinity)" @@ -372,10 +383,14 @@ subroutine init_para(para, flags) switches%tempering = .false. switches%measure_polyakov_loop = .false. switches%measure_traces = .false. + switches%measure_chemical = .false. + switches%measure_schrpcac = .false. if (input%ensembles > 1) switches%tempering = .true. if (input%measure_polyakov_loop /= 0) switches%measure_polyakov_loop = .true. if (input%measure_traces /= 0) switches%measure_traces = .true. + if (input%measure_chemical /= 0) switches%measure_chemical = .true. + if (input%measure_schrpcac /= 0) switches%measure_schrpcac = .true. switches%measurement_only = .false. switches%boundary_sf = .false. @@ -383,6 +398,11 @@ subroutine init_para(para, flags) if (input%boundary_sf /= 0) switches%boundary_sf = .true. + if (input%replay_trick_ntau /=0) then + if (input%replay_trick_ntau < para%hmc(1)%ntau) call die("replay_trick_ntau < ntau") + switches%replay = .true. + endif + if (input%hmc_test == 0) then switches%hmc_test = .false. else @@ -586,6 +606,7 @@ subroutine write_header(para, flags) write(UREC, fmt) "n_stout_", i, " ", trim(para%c_hmc(i)%n_stout) write(UREC, fmt) "alpha_", i, " ", trim(para%c_hmc(i)%alpha) write(UREC, fmt) "theta_", i, " ", trim(para%c_hmc(i)%theta) + write(UREC, fmt) "chemi_", i, " ", trim(para%c_hmc(i)%chemi) write(UREC, fmt) "h_", i, " ", trim(para%c_hmc(i)%h) write(UREC, fmt) "rho_", i, " ", trim(para%c_hmc(i)%rho) write(UREC, fmt) "rho2_", i, " ", trim(para%c_hmc(i)%rho2) @@ -607,6 +628,12 @@ if(nts>5)write(UREC, fmt) "m_scale5_", i, " ", trim(c_info_mdsteps(para !! write(UREC, *) "fraction_u1", input%rhmc_fraction_u1 !! write(UREC, *) "fraction_u2", input%rhmc_fraction_u2 !! write(UREC, *) "roughness_level", input%rhmc_roughness_level + + if (switches%replay) then + write(UREC, *) "HMC_replay_ntau ", input%replay_trick_ntau + write(UREC, *) "HMC_replay_threshold ", input%replay_trick_threshold + endif + write(UREC, *) "HMC_model ", para%hmc(1)%model write(UREC, *) "REAL_kind ", RKIND write(UREC, *) "Solver_outer ", trim(input%solver_outer_solver) diff --git a/src/cksum.c b/src/cksum.c index 356266227ee6f95251de9f9a45eb86aaf4d7b145..136cd71bd9cd8a66742cfd0e704350d28f3a797e 100644 --- a/src/cksum.c +++ b/src/cksum.c @@ -2,6 +2,7 @@ !=============================================================================== ! ! Copyright (C) 1998-2006 Hinnerk Stueben +! 2010 Yoshifumi Nakamura ! ! This file is part of BQCD -- Berlin Quantum ChromoDynamics program ! @@ -140,3 +141,53 @@ void CKSUM_GET(INT8 *total_crc, INT8 *total_bytes) *total_crc = (INT8) crc; *total_bytes = the_bytes; } + +/*--------------------------------------------------------------------------*/ +// +// add for para IO, 2010/07/01 yn +// +#ifndef NONMPI +#include <mpi.h> +#include <stdio.h> +/* +void CKSUM_ADD_MPI() +{ + int status; + unsigned INT8 the_crc_tmp; + INT8 the_bytes_tmp; + + + + unsigned long send= (unsigned long) the_crc; + unsigned long recv; + + fprintf(stderr,"CKSUM_ADD_MPI crc before %lu \n",send); + status = MPI_Allreduce( (void *)&send, (void *)&recv, 1, + MPI_UNSIGNED_LONG, MPI_BXOR, MPI_COMM_WORLD); + fprintf(stderr,"CKSUM_ADD_MPI crc after %lu \n",recv); + + status = MPI_Allreduce( (void *)&the_bytes, (void *)&the_bytes_tmp, 1, + MPI_LONG_LONG, MPI_SUM, MPI_COMM_WORLD); + + + + the_crc=(unsigned INT8) recv; + the_bytes=the_bytes_tmp; +} +*/ + +void CKSUM_BCAST(int *np) +{ +#ifdef MPI_1 + /* this may not work wtih MPI-1*/ + MPI_Bcast ( (void *)&the_crc, 1, MPI_DOUBLE, *np, MPI_COMM_WORLD ) ; +#else + MPI_Bcast ( (void *)&the_crc, 1, MPI_UNSIGNED_LONG_LONG, *np, MPI_COMM_WORLD ) ; +#endif + MPI_Bcast ( (void *)&the_bytes, 1, MPI_LONG_LONG, *np, MPI_COMM_WORLD ) ; +} + +#else +void CKSUM_ADD_MPI(){} +void CKSUM_BCAST(int *np){} +#endif diff --git a/src/comm/Makefile b/src/comm/Makefile index b85005cd9230d62b716b13cd561660329ec8b996..0d999bd7320abdd24f105047c2b82f77de70a449 100644 --- a/src/comm/Makefile +++ b/src/comm/Makefile @@ -26,16 +26,16 @@ DIR=../ include $(DIR)Makefile.in ifdef FPP2 - fpp = $(FPP2) + fpp = $(FPP2) -I../include $(MYFLAGS) else - fpp = $(FPP) + fpp = $(FPP) -I../include $(MYFLAGS) endif .SUFFIXES: .SUFFIXES: .a .o .F90 .cc .c .F90.o: - $(fpp) -I../include $(MYFLAGS) $< > $*.f90 + $(fpp) $< > $*.f90 $(F90) -c $(FFLAGS) $*.f90 .cc.o: @@ -65,13 +65,22 @@ OBJS_MPI = \ global_mpi.o \ global_eo_sum_vec_mpi.o \ bgl_process_mapping.o \ - bgl_cart_comm_create.o + bgl_cart_comm_create.o\ + ildg_io_lemon.o + +ifdef quad +OBJS_MPI += \ + allocate_r16.o \ + xbound_mpi_r16.o \ + reduction_mpi_r16.o +endif OBJS_BGL = \ dotprod.o \ comm_bgl.o \ allocate.o \ allocate_r4.o \ + allocate_r16.o \ field_io_bgl.o \ pes_bgl.o \ broadcast_bgl.o \ @@ -86,6 +95,7 @@ OBJS_SHMEM = \ comm_shmem.o \ allocate_shmem.o \ allocate_shmem_r4.o \ + allocate_shmem_r16.o \ field_io_shmem.o \ reduction_shmem.o \ seed_shmem.o \ @@ -98,6 +108,7 @@ OBJS_SHMEMPI = \ comm_shmempi.o \ allocate_shmem.o \ allocate_shmem_r4.o \ + allocate_shmem_r16.o \ field_io_mpi.o \ ildg_io_mpi_r4.o \ ildg_io_mpi_r8.o \ @@ -127,6 +138,13 @@ OBJS_SINGLE_PE = \ reduction_single_pe_r4.o \ module_reduction.o +ifdef quad +OBJS_SINGLE_PE += \ + allocate_r16.o \ + xbound_single_pe_r16.o \ + reduction_single_pe_r16.o +endif + ifdef qmp OBJS_MPI += init_qmp.o OBJS_SINGLE_PE += init_qmp.o @@ -155,20 +173,59 @@ lib_single_pe.a: $(OBJS_SINGLE_PE) allocate_r4.o: allocate.F90 + $(fpp) -DPRECISION_R4 $< > $*.f90 + $(F90) -c $(FFLAGS32) $*.f90 allocate_shmem_r4.o: allocate_shmem.F90 + $(fpp) -DPRECISION_R4 $< > $*.f90 + $(F90) -c $(FFLAGS32) $*.f90 + +allocate_r16.o: allocate.F90 + $(fpp) -DPRECISION_R16 $< > $*.f90 + $(F90) -c $(FFLAGS) $*.f90 + +allocate_shmem_r16.o: allocate_shmem.F90 + $(fpp) -DPRECISION_R16 $< > $*.f90 + $(F90) -c $(FFLAGS) $*.f90 + ildg_io_single_pe_r4.o: ildg_io_single_pe_r8.F90 ildg_io_mpi_r4.o: ildg_io_mpi_r8.F90 +reduction_single_pe_r4.o: reduction_single_pe.F90 + $(fpp) -DPRECISION_R4 $< > $*.f90 + $(F90) -c $(FFLAGS32) $*.f90 + +reduction_mpi_r4.o: reduction_mpi.F90 + $(fpp) -DPRECISION_R4 $< > $*.f90 + $(F90) -c $(FFLAGS32) $*.f90 + +reduction_single_pe_r16.o: reduction_single_pe.F90 + $(fpp) -DPRECISION_R16 $< > $*.f90 + $(F90) -c $(FFLAGS) $*.f90 + +reduction_mpi_r16.o: reduction_mpi.F90 + $(fpp) -DPRECISION_R16 $< > $*.f90 + $(F90) -c $(FFLAGS) $*.f90 + xbound_mpi.o: xbound_d_proj_mpi.F90 xbound_mpi_r4.o: xbound_mpi.F90 xbound_d_proj_mpi.F90 + $(fpp) -DPRECISION_R4 xbound_mpi.F90 > $*.f90 + $(F90) -c $(FFLAGS32) $*.f90 xbound_single_pe_r4.o: xbound_single_pe.F90 + $(fpp) -DPRECISION_R4 $< > $*.f90 + $(F90) -c $(FFLAGS32) $*.f90 +xbound_mpi_r16.o: xbound_mpi.F90 xbound_d_proj_mpi.F90 + $(fpp) -DPRECISION_R16 xbound_mpi.F90 > $*.f90 + $(F90) -c $(FFLAGS) $*.f90 +xbound_single_pe_r16.o: xbound_single_pe.F90 + $(fpp) -DPRECISION_R16 $< > $*.f90 + $(F90) -c $(FFLAGS) $*.f90 clobber: rm -f *.[Tiod] *.f90 *.mod work.pc work.pcl diff --git a/src/comm/ildg_io_lemon.F90 b/src/comm/ildg_io_lemon.F90 new file mode 100644 index 0000000000000000000000000000000000000000..f6fc9806bf248310fb57cb66a7cf02da05baa286 --- /dev/null +++ b/src/comm/ildg_io_lemon.F90 @@ -0,0 +1,96 @@ +!=============================================================================== +! +! ildg_io_lemon.F90 +! +!------------------------------------------------------------------------------- +! +! Copyright (C) 2010 Yoshifumi Nakamura +! +! This file is part of BQCD -- Berlin Quantum ChromoDynamics program +! +! BQCD 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 Foundation, either version 3 of the License, or +! (at your option) any later version. +! +! BQCD is distributed in the hope that it will be useful, +! but WITHOUT ANY WARRANTY; without even the implied warranty of +! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +! GNU General Public License for more details. +! +! You should have received a copy of the GNU General Public License +! along with BQCD. If not, see <http://www.gnu.org/licenses/>. +! +!------------------------------------------------------------------------------- +# include "defs.h" + +!------------------------------------------------------------------------------- +subroutine ildg_io_lemon(action, u, precision) + use module_function_decl + use module_lattice_io + use module_vol + implicit none + include 'mpif.h' + character(*), intent(in) :: action + GAUGE_FIELD_ILDG, intent(inout) :: u + integer, intent(in) :: precision + + integer :: x, y, z, t, ix, iy, iz, it + integer :: coord(DIM), ierror, my, gmy, my_tmp + INT8 :: words, words_in_u + + ! 8 is size of real [bytes] + words = SIZE_COMPLEX * NCOL * NCOL * DIM * NX * 8 + if (precision == 32) words = words / 2 + + words_in_u= SIZE_COMPLEX * NCOL * NCOL * DIM * vol + + call pe2coord(my_pe(), coord) + my=my_pe() + + if (action == "write") then + if (precision == 64)call swap_endian8(words_in_u, u) + if (precision == 32)call swap_endian4(words_in_u, u) + call ildg_write_lemon(u, l, vol, precision) + else + call ildg_read_lemon(u, l, vol, precision) + endif + + !! + !! now calculate crc cksum + !! + do t = 0, LT - 1 + do z = 0, LZ - 1 + do y = 0, LY - 1 + do x = 0, LX - 1, NX + it = t - nt*coord(4) + iz = z - nz*coord(3) + iy = y - ny*coord(2) + ix = x - nx*coord(1) + if ( 0<=it .and. it < nt .and. & + 0<=iz .and. iz < nz .and. & + 0<=iy .and. iy < ny .and. & + 0<=ix .and. ix < nx) then + call cksum_add(u(1,1,1,ix,iy,iz,it),words) + my_tmp=my + else + my_tmp=0 + endif + call mpi_allreduce(my_tmp, gmy, 1, & + MPI_INTEGER4, MPI_SUM, MPI_COMM_WORLD, ierror) + call cksum_bcast(gmy) + call mpi_barrier(MPI_COMM_WORLD, ierror) + enddo + enddo + enddo + enddo + + if (action == "read") then + if (precision == 64)call swap_endian8(words_in_u, u) + if (precision == 32)call swap_endian4(words_in_u, u) + endif + call mpi_barrier(MPI_COMM_WORLD, ierror) + +end + +!=============================================================================== diff --git a/src/comm/xbound_single_pe.F90 b/src/comm/xbound_single_pe.F90 index 4ff6e79bfbae5bcbe9d518aa0205aec70b18e6ec..8c4f4b88c8a1bc99835879101e4e7dfd8a124cee 100644 --- a/src/comm/xbound_single_pe.F90 +++ b/src/comm/xbound_single_pe.F90 @@ -91,4 +91,37 @@ subroutine xbound_g_rect_ind(u, eo, mu, nu, fb) return end + +subroutine init_xbound_d_proj() + return +end +subroutine xbound_d_proj(a, eo, dag) + use module_vol + implicit none + SPINCOL_FIELD :: a + integer :: eo, dag + return +end +subroutine xbound_d_proj_sr(a, eo, dag) + use module_vol + implicit none + SPINCOL_FIELD :: a + integer :: eo, dag + return +end +subroutine xbound_d_proj_i(a, eo, dag) + use module_vol + implicit none + SPINCOL_FIELD :: a + integer :: eo, dag + return +end + +subroutine xbound_sc(a, direction) + use module_vol + implicit none + integer :: direction + SPINCOL_FIELD :: a + return +end !=============================================================================== diff --git a/src/data/README b/src/data/README index d7fcbb3febf224d23b7c4f4b439cefda71f60a94..000667bcb62d64cba770d7e473b3ddc5405309d6 100644 --- a/src/data/README +++ b/src/data/README @@ -10,6 +10,18 @@ bqcd.200.output output for comparison bqcd.300.input test input for Nf = 2 + 1 bqcd.300.output output for comparison +bqcd.310.input test input for Nf = 2 + 1 with replay trick +bqcd.310.output output for comparison + +bqcd.320.input test input for Nf = 2 + 1 with RHMC tuning +rangelist parameter files for RHMC tuning +fractiontolerance parameter files for RHMC tuning +bqcd.320.output output for comparison + +bqcd.500.input test input for NF = 3 SLOC with SF boundary condition +bqcd.500.output output for comparison +fAfPhist.000001 output for comparison, correlation functions for cSW + cool.list a cooling list (see manual) qcdsf-configuration-04.xml an example ILDG metadata template for configurations diff --git a/src/data/bqcd.300.input b/src/data/bqcd.300.input index 0182f99c189988eec22c8ef896d9b48e9b53d546..0b25370916cc740a78d247478b55187a7072bfe4 100644 --- a/src/data/bqcd.300.input +++ b/src/data/bqcd.300.input @@ -1,3 +1,4 @@ +comment "Test for Nf=2+1" run 300 lattice 4 4 4 4 boundary_conditions_fermions 1 1 1 -1 diff --git a/src/data/bqcd.300.output b/src/data/bqcd.300.output index a1d40fa08da6d169984dd8c216b79af77ad06af9..12962b46881a9e0edb9c630c3e28a1eca2033b79 100644 --- a/src/data/bqcd.300.output +++ b/src/data/bqcd.300.output @@ -1,13 +1,14 @@ >BeginJob >BeginHeader - Program bqcd 4.0.0 (revision 259) + Comment Test for Nf=2+1 + Program bqcd 4.0.0 (revision 324) Version_of_D 100 - Communication single_pe + Communication MPI (sc:immediate) (g:immediate) RandomNumbers ranlux-3.2 level 2 Run 300 Job 1 - Host pc58588 - Date 2010-06-11 16:56:02.444 + Host m500 + Date 2011-09-21 14:28:37.415 L 4 4 4 4 DDL 1 1 1 1 NPE 1 1 1 1 @@ -42,6 +43,7 @@ n_stout_1 1 alpha_1 0.1 theta_1 0.0 + chemi_1 0.0 h_1 0.0 rho_1 0.1203 rho2_1 0.0 @@ -57,9 +59,6 @@ mpf_eo[m,l,s]: 2 0 2 mpf_dd[m,l,s]: 0 0 0 mpf_hh[m,l,s]: 0 0 0 - fraction_u1 40 - fraction_u2 0 - roughness_level 0 HMC_model F REAL_kind 8 Solver_outer cg @@ -93,7 +92,7 @@ %egnv -9 1 1 0.80547445E-01 2.2603050 73 41 1e-11 28.062 1.67 %egnv -9 1 2 0.74060643E-01 2.3117457 74 39 1e-11 31.214 1.72 %egnv -9 1 3 0.78792963E-01 2.2737198 73 41 1e-11 28.857 1.68 - %it -8 309 5274 1650 1179 0 0 0 0 0 0 + %it -8 309 5273 1650 1179 0 0 0 0 0 0 %it4 -8 0 0 0 0 0 0 0 0 0 0 %Favg -8 8.173 0.726 1.348 2.465 0.067 0.809 0.000 0.000 0.000 0.000 0.000 0.000 %Fmax -8 14.511 1.353 2.755 6.638 0.189 1.925 0.000 0.000 0.000 0.000 0.000 0.000 @@ -101,11 +100,11 @@ %Hold -8 0.9777570E+04 0.4030068E+04 0.5626949E+04 -0.5967133E+04 0.1485841E+04 0.1560926E+04 0.3040919E+04 %Hnew -8 0.9778114E+04 0.4628898E+04 0.5029892E+04 -0.5984421E+04 0.1505593E+04 0.1560220E+04 0.3037933E+04 %Hdif -8 0.5445722E+00 0.5988301E+03 -0.5970570E+03 -0.1728829E+02 0.1975166E+02 -0.7061834E+00 -0.2985696E+01 - %fa -8 1 0.6837585510 0.5800898725 203 6982 58 26 1430 65 0.316241448982582 + %fa -8 1 0.6837585510 0.5800898725 203 6981 58 26 1430 65 0.316241448982973 %egnv -8 1 1 0.71967912E-01 2.1601388 172 64 1e-11 30.015 1.70 %egnv -8 1 2 0.65996267E-01 2.2033538 176 62 1e-11 33.386 1.75 %egnv -8 1 3 0.70350902E-01 2.1714299 173 63 1e-11 30.866 1.71 - %it -7 367 6315 1972 1416 0 0 0 0 0 0 + %it -7 367 6315 1972 1417 0 0 0 0 0 0 %it4 -7 0 0 0 0 0 0 0 0 0 0 %Favg -7 8.463 0.775 1.341 2.442 0.071 0.862 0.000 0.000 0.000 0.000 0.000 0.000 %Fmax -7 15.009 1.430 2.738 6.868 0.236 2.102 0.000 0.000 0.000 0.000 0.000 0.000 @@ -113,11 +112,11 @@ %Hold -7 0.9293270E+04 0.4094299E+04 0.5029892E+04 -0.5984421E+04 0.1512332E+04 0.1487833E+04 0.3153335E+04 %Hnew -7 0.9292577E+04 0.4531932E+04 0.4556032E+04 -0.5956843E+04 0.1510334E+04 0.1488096E+04 0.3163026E+04 %Hdif -7 -0.6925139E+00 0.4376328E+03 -0.4738597E+03 0.2757784E+02 -0.1997839E+01 0.2632195E+00 0.9691159E+01 - %fa -7 1 0.6247996765 1.9987337431 203 8348 72 26 1722 88 0.375200323526387 + %fa -7 1 0.6247996765 1.9987337429 203 8348 72 26 1723 88 0.375200323526924 %egnv -7 1 1 0.35981194E-01 2.4918009 109 27 1e-11 69.253 2.12 %egnv -7 1 2 0.31457047E-01 2.5556502 113 27 1e-11 81.243 2.20 %egnv -7 1 3 0.34743068E-01 2.5084717 110 27 1e-11 72.201 2.14 - %it -6 415 6439 1996 1435 0 0 0 0 0 0 + %it -6 415 6439 1995 1435 0 0 0 0 0 0 %it4 -6 0 0 0 0 0 0 0 0 0 0 %Favg -6 8.588 0.801 1.341 2.583 0.073 0.848 0.000 0.000 0.000 0.000 0.000 0.000 %Fmax -6 15.164 1.485 2.883 6.699 0.201 2.233 0.000 0.000 0.000 0.000 0.000 0.000 @@ -125,11 +124,11 @@ %Hold -6 0.8871121E+04 0.4101907E+04 0.4556032E+04 -0.5956843E+04 0.1567070E+04 0.1524604E+04 0.3078351E+04 %Hnew -6 0.8870834E+04 0.4182358E+04 0.4478885E+04 -0.5981559E+04 0.1590364E+04 0.1524322E+04 0.3076463E+04 %Hdif -6 -0.2872979E+00 0.8045069E+02 -0.7714721E+02 -0.2471533E+02 0.2329443E+02 -0.2821219E+00 -0.1887758E+01 - %fa -6 1 0.6141827704 1.3328212627 203 8518 83 26 1767 89 0.385817229617386 + %fa -6 1 0.6141827704 1.3328212641 203 8517 83 26 1767 89 0.385817229616329 %egnv -6 1 1 0.44963111E-01 2.2734221 88 50 1e-11 50.562 1.96 %egnv -6 1 2 0.39975905E-01 2.3294476 90 48 1e-11 58.271 2.03 %egnv -6 1 3 0.43602824E-01 2.2880091 89 50 1e-11 52.474 1.98 - %it -5 408 6831 2127 1499 0 0 0 0 0 0 + %it -5 407 6831 2127 1499 0 0 0 0 0 0 %it4 -5 0 0 0 0 0 0 0 0 0 0 %Favg -5 8.537 0.810 1.325 2.374 0.073 0.792 0.000 0.000 0.000 0.000 0.000 0.000 %Fmax -5 15.199 1.518 2.779 5.839 0.240 1.881 0.000 0.000 0.000 0.000 0.000 0.000 @@ -137,19 +136,19 @@ %Hold -5 0.8651157E+04 0.4089832E+04 0.4478885E+04 -0.5981559E+04 0.1533584E+04 0.1538412E+04 0.2992002E+04 %Hnew -5 0.8651211E+04 0.4106159E+04 0.4427728E+04 -0.5966972E+04 0.1552947E+04 0.1538339E+04 0.2993011E+04 %Hdif -5 0.5466773E-01 0.1632681E+02 -0.5115719E+02 0.1458633E+02 0.1936275E+02 -0.7251007E-01 0.1008478E+01 - %fa -5 1 0.6078148517 0.9467996885 203 9032 74 26 1833 89 0.392185148346159 + %fa -5 1 0.6078148517 0.9467996866 203 9032 74 26 1832 89 0.392185148343124 %egnv -5 1 1 0.22021276E-01 2.4372806 104 107 1e-11 110.678 2.35 %egnv -5 1 2 0.18136345E-01 2.5058991 109 102 1e-11 138.170 2.46 %egnv -5 1 3 0.20945916E-01 2.4551219 105 104 1e-11 117.212 2.38 - %it -4 430 6845 2158 1507 0 0 0 0 0 0 + %it -4 429 6844 2157 1507 0 0 0 0 0 0 %it4 -4 0 0 0 0 0 0 0 0 0 0 %Favg -4 8.590 0.817 1.341 2.382 0.075 0.815 0.000 0.000 0.000 0.000 0.000 0.000 %Fmax -4 15.030 1.533 2.840 6.062 0.241 1.996 0.000 0.000 0.000 0.000 0.000 0.000 %Frat -4 62.306 6.354 11.771 25.130 1.000 8.273 0.000 0.000 0.000 0.000 0.000 0.000 %Hold -4 0.8583368E+04 0.4091101E+04 0.4427728E+04 -0.5966972E+04 0.1500592E+04 0.1498237E+04 0.3032683E+04 %Hnew -4 0.8583295E+04 0.4195410E+04 0.4340990E+04 -0.5972497E+04 0.1494524E+04 0.1498127E+04 0.3026742E+04 - %Hdif -4 -0.7338697E-01 0.1043087E+03 -0.8673771E+02 -0.5524790E+01 -0.6068144E+01 -0.1098792E+00 -0.5941606E+01 - %fa -4 1 0.5963913539 1.0761468895 203 9087 84 26 1853 89 0.403608646128713 + %Hdif -4 -0.7338696E-01 0.1043087E+03 -0.8673771E+02 -0.5524790E+01 -0.6068144E+01 -0.1098792E+00 -0.5941606E+01 + %fa -4 1 0.5963913539 1.0761468837 203 9085 84 26 1852 89 0.403608646129048 %egnv -4 1 1 0.30188146E-01 2.1647039 72 43 1e-11 71.707 2.14 %egnv -4 1 2 0.25911790E-01 2.2091304 74 42 1e-11 85.256 2.22 %egnv -4 1 3 0.29014812E-01 2.1763156 73 43 1e-11 75.007 2.16 @@ -161,140 +160,140 @@ %Hold -3 0.8614961E+04 0.4145810E+04 0.4340990E+04 -0.5972497E+04 0.1528241E+04 0.1522367E+04 0.3050051E+04 %Hnew -3 0.8614829E+04 0.4253580E+04 0.4279266E+04 -0.5991784E+04 0.1500857E+04 0.1521232E+04 0.3051678E+04 %Hdif -3 -0.1322210E+00 0.1077699E+03 -0.6172370E+02 -0.1928727E+02 -0.2738316E+02 -0.1135419E+01 0.1627457E+01 - %fa -3 1 0.5874912538 1.1413604914 203 9010 81 26 1820 85 0.412508746190435 + %fa -3 1 0.5874912538 1.1413604891 203 9010 81 26 1820 85 0.412508746210098 %egnv -3 1 1 0.43832510E-01 2.0903463 114 69 1e-11 47.689 1.93 %egnv -3 1 2 0.39086798E-01 2.1258883 115 68 1e-11 54.389 2.00 %egnv -3 1 3 0.42539420E-01 2.0996774 114 68 1e-11 49.358 1.95 - %it -2 396 7076 2167 1526 0 0 0 0 0 0 + %it -2 396 7073 2166 1525 0 0 0 0 0 0 %it4 -2 0 0 0 0 0 0 0 0 0 0 %Favg -2 8.913 0.864 1.305 2.441 0.078 0.774 0.000 0.000 0.000 0.000 0.000 0.000 %Fmax -2 15.503 1.622 2.583 6.663 0.219 1.881 0.000 0.000 0.000 0.000 0.000 0.000 %Frat -2 70.650 7.390 11.770 30.364 1.000 8.574 0.000 0.000 0.000 0.000 0.000 0.000 %Hold -2 0.8505403E+04 0.4191183E+04 0.4279266E+04 -0.5991784E+04 0.1438738E+04 0.1538052E+04 0.3049948E+04 %Hnew -2 0.8505738E+04 0.4375280E+04 0.4115031E+04 -0.5998951E+04 0.1429808E+04 0.1538295E+04 0.3046276E+04 - %Hdif -2 0.3356661E+00 0.1840966E+03 -0.1642358E+03 -0.7166638E+01 -0.8930498E+01 0.2437761E+00 -0.3671725E+01 - %fa -2 1 0.5665928637 0.7148617392 203 9316 73 26 1849 83 0.433407136283996 + %Hdif -2 0.3356661E+00 0.1840966E+03 -0.1642358E+03 -0.7166638E+01 -0.8930499E+01 0.2437761E+00 -0.3671725E+01 + %fa -2 1 0.5665928635 0.7148617414 203 9312 73 26 1848 83 0.433407136480923 %egnv -2 1 1 0.36920645E-01 2.2540469 93 63 1e-11 61.051 2.06 %egnv -2 1 2 0.32990186E-01 2.3051667 96 61 1e-11 69.874 2.12 - %egnv -2 1 3 0.35843876E-01 2.2674050 93 62 1e-11 63.258 2.07 - %it -1 442 8015 2455 1689 0 0 0 0 0 0 + %egnv -2 1 3 0.35843876E-01 2.2674049 93 62 1e-11 63.258 2.07 + %it -1 442 8015 2454 1689 0 0 0 0 0 0 %it4 -1 0 0 0 0 0 0 0 0 0 0 %Favg -1 8.930 0.880 1.321 2.692 0.078 0.817 0.000 0.000 0.000 0.000 0.000 0.000 %Fmax -1 15.259 1.577 2.784 7.084 0.243 1.970 0.000 0.000 0.000 0.000 0.000 0.000 %Frat -1 62.866 6.495 11.468 29.186 1.000 8.115 0.000 0.000 0.000 0.000 0.000 0.000 %Hold -1 0.8457890E+04 0.4133751E+04 0.4115031E+04 -0.5998951E+04 0.1543906E+04 0.1550057E+04 0.3114096E+04 %Hnew -1 0.8458024E+04 0.4133266E+04 0.4063189E+04 -0.5982004E+04 0.1572060E+04 0.1549422E+04 0.3122091E+04 - %Hdif -1 0.1340929E+00 -0.4850769E+00 -0.5184203E+02 0.1694690E+02 0.2815357E+02 -0.6347644E+00 0.7995497E+01 - %fa -1 1 0.5600325226 0.8745088056 203 10549 84 26 2052 99 0.439967477374255 - %egnv -1 1 1 0.20043751E-01 2.6191537 175 22 1e-11 130.672 2.44 - %egnv -1 1 2 0.16816987E-01 2.7011716 181 21 1e-11 160.622 2.54 - %egnv -1 1 3 0.19150390E-01 2.6404756 176 22 1e-11 137.881 2.46 - %it 0 479 8213 2551 1736 0 0 0 0 0 0 + %Hdif -1 0.1340929E+00 -0.4850763E+00 -0.5184203E+02 0.1694690E+02 0.2815357E+02 -0.6347645E+00 0.7995497E+01 + %fa -1 1 0.5600325225 0.8745087766 203 10548 84 26 2052 99 0.439967477457935 + %egnv -1 1 1 0.20043752E-01 2.6191537 175 22 1e-11 130.672 2.44 + %egnv -1 1 2 0.16816988E-01 2.7011717 181 21 1e-11 160.622 2.54 + %egnv -1 1 3 0.19150390E-01 2.6404757 176 22 1e-11 137.881 2.46 + %it 0 479 8211 2551 1733 0 0 0 0 0 0 %it4 0 0 0 0 0 0 0 0 0 0 0 %Favg 0 8.948 0.890 1.310 2.576 0.079 0.785 0.000 0.000 0.000 0.000 0.000 0.000 %Fmax 0 14.994 1.600 2.652 7.318 0.257 1.987 0.000 0.000 0.000 0.000 0.000 0.000 %Frat 0 58.398 6.233 10.329 28.504 1.000 7.738 0.000 0.000 0.000 0.000 0.000 0.000 %Hold 0 0.8333887E+04 0.4060687E+04 0.4063189E+04 -0.5982004E+04 0.1622086E+04 0.1520595E+04 0.3049334E+04 %Hnew 0 0.8334043E+04 0.4222562E+04 0.3927864E+04 -0.5981657E+04 0.1589964E+04 0.1519281E+04 0.3056029E+04 - %Hdif 0 0.1560966E+00 0.1618753E+03 -0.1353246E+03 0.3474536E+00 -0.3212248E+02 -0.1314227E+01 0.6694721E+01 - %fa 0 1 0.5423191696 0.8554765110 203 10858 94 26 2121 100 0.457680830362908 - %egnv 0 1 1 0.21786046E-01 2.0954561 183 71 1e-11 96.183 2.28 - %egnv 0 1 2 0.18395558E-01 2.1338142 187 70 1e-11 115.996 2.38 - %egnv 0 1 3 0.20849283E-01 2.1055060 184 71 1e-11 100.987 2.31 + %Hdif 0 0.1560966E+00 0.1618753E+03 -0.1353247E+03 0.3474509E+00 -0.3212248E+02 -0.1314227E+01 0.6694722E+01 + %fa 0 1 0.5423191678 0.8554765410 203 10856 94 26 2118 100 0.457680832187485 + %egnv 0 1 1 0.21786047E-01 2.0954562 183 71 1e-11 96.183 2.28 + %egnv 0 1 2 0.18395558E-01 2.1338143 187 70 1e-11 115.996 2.38 + %egnv 0 1 3 0.20849284E-01 2.1055060 184 71 1e-11 100.987 2.31 >EndForceAcceptance >BeginILDGwrite ildg-write file bqcd.300.lime ildg-write precision 64 ildg-write bytes 147456 - ildg-write cksum 886460001 - ildg-write lfn bqcd-restart bqcd.300.lime 886460001 147456 300 1 0 + ildg-write cksum 889189260 + ildg-write lfn bqcd-restart bqcd.300.lime 889189260 147456 300 1 0 >EndILDGwrite >BeginFooter - Date 2010-06-11 16:58:33.680 + Date 2011-09-21 14:30:51.744 Seed -1 - CPU-Time 151.2 s on 1 CPUs + CPU-Time 134.3 s on 1 CPUs >BeginTiming Performance region #calls time mean min max Total s Mflop/s Mflop/s Mflop/s Gflop/s - d_xf 529058 8.59 2269.78 2269.78 2269.78 2.27 + d_xf 528994 7.32 2664.45 2664.45 2664.45 2.66 d_xb 0 - d_yf 529058 8.40 2515.14 2515.14 2515.14 2.52 + d_yf 528994 6.12 3451.89 3451.89 3451.89 3.45 d_yb 0 - d_zf 529058 8.76 2411.77 2411.77 2411.77 2.41 + d_zf 528994 5.92 3571.53 3571.53 3571.53 3.57 d_zb 0 - d_t 529058 8.97 2354.78 2354.78 2354.78 2.35 + d_t 528994 6.24 3384.98 3384.98 3384.98 3.38 d_fb 0 d_dag_fb 0 d_xyzt 0 - sc2_projection 529058 6.93 703.74 703.74 703.74 0.70 - D_TOTAL 529058 42.83 2049.29 2049.29 2049.29 2.05 + sc2_projection 528994 7.22 675.62 675.62 675.62 0.68 + D_TOTAL 528994 40.75 2153.53 2153.53 2153.53 2.15 d_dd 0 d_eo 0 - MTDAGMT 114697 57.08 1926.09 1926.09 1926.09 1.93 - CG 2030 46.49 1912.32 1912.32 1912.32 1.91 + MTDAGMT 114681 50.11 2193.42 2193.42 2193.42 2.19 + CG 2030 40.86 2175.43 2175.43 2175.43 2.18 CG_DD 0 CG_HH 0 cg_global_sum 0 - global_sum 0 - global_sum_vec 0 - sc_zero 39896 0.83 - sc_copy 12140 0.10 - sc_scale 9902 0.03 950.53 950.53 950.53 0.95 - sc_norm2 44608 0.21 1292.72 1292.72 1292.72 1.29 - sc_dot 51190 0.21 1511.96 1511.96 1511.96 1.51 - sc_axpy 360804 1.64 1354.93 1354.93 1354.93 1.35 - sc_xpby 352627 1.27 1703.16 1703.16 1703.16 1.70 - sc_axpby 326804 1.23 2444.50 2444.50 2444.50 2.44 - sc_cdotc 29180 0.17 2134.17 2134.17 2134.17 2.13 - sc_caxpy 1940 0.01 2979.47 2979.47 2979.47 2.98 - sc_caxpy2 1940 0.02 2979.47 2979.47 2979.47 2.98 - sc_cax2 1980 0.01 4055.04 4055.04 4055.04 4.06 - clover_init 2403 4.43 + global_sum 104061 0.06 + global_sum_vec 181776 0.57 + sc_zero 39900 0.42 + sc_copy 137381 0.21 + sc_scale 9902 0.00 10146.41 10146.41 10146.41 10.15 + sc_norm2 44603 0.03 8840.60 8840.60 8840.60 8.84 + sc_dot 51185 0.03 10846.78 10846.78 10846.78 10.85 + sc_axpy 360714 0.29 7617.05 7617.05 7617.05 7.62 + sc_xpby 352579 0.15 13978.48 13978.48 13978.48 13.98 + sc_axpby 326719 0.42 7204.47 7204.47 7204.47 7.20 + sc_cdotc 29180 0.05 7796.22 7796.22 7796.22 7.80 + sc_caxpy 1940 0.00 +Inf +Inf +Inf +Inf + sc_caxpy2 1940 0.00 23838.72 23838.72 23838.72 23.84 + sc_cax2 1980 0.02 2862.89 2862.89 2862.89 2.86 + clover_init 2403 3.78 clover_mult_a 0 - clover_mult_ao 498668 18.03 1954.71 1954.71 1954.71 1.95 - clover_mult_b 60200 2.53 1679.79 1679.79 1679.79 1.68 - clover_dsd 410 4.16 + clover_mult_ao 498604 13.17 2674.56 2674.56 2674.56 2.67 + clover_mult_b 60200 1.97 2163.87 2163.87 2163.87 2.16 + clover_dsd 410 4.05 clover_dsf 0 - hmc_init 10 0.03 - hmc_init_p 10 0.03 - hmc_u 6400 6.58 + hmc_init 10 0.02 + hmc_init_p 10 0.01 + hmc_u 6400 5.94 hmc_momenta 0 - hmc_phi 10 1.62 - hmc_h_old 10 1.68 + hmc_phi 10 1.37 + hmc_h_old 10 1.40 hmc_backup 10 0.00 hmc_half_step0 0 hmc_half_step1 0 hmc_xbound_g 10541 0.01 - hmc_steps 8540 140.02 - hmc_h_new 10 0.01 + hmc_steps 8540 124.41 + hmc_h_new 10 0.02 hmc_rest 10 0.00 - HMC 10 148.35 + HMC 10 131.82 h_mult_a 0 h_mult_b 0 h_mult_c 0 - dsg 6410 8.32 - dsf 2020 33.43 - plaquette 21 0.00 +Inf +Inf +Inf +Inf + dsg 6410 6.72 + dsf 2020 29.66 + plaquette 21 0.01 1745.86 1745.86 1745.86 1.75 cooling 0 - ran_gauss_volh 128 0.06 + ran_gauss_volh 128 0.04 MTDAGMT_r4 0 - dsig 1610 10.17 - rectangle 20 0.03 1778.41 1778.41 1778.41 1.78 + dsig 1610 9.09 + rectangle 20 0.02 2263.81 2263.81 2263.81 2.26 chair 0 parallelogram 0 - stout_smear 1601 4.06 1548.38 1548.38 1548.38 1.55 - stout_diffe 2540 12.68 2316.61 2316.61 2316.61 2.32 - clover_bsa_w 20260 2.37 2010.52 2010.52 2010.52 2.01 - clover_dsd_w 1640 1.50 1141.57 1141.57 1141.57 1.14 - clover_d_w 5900 13.74 2198.19 2198.19 2198.19 2.20 - dsf_at_bt 10130 3.25 1473.58 1473.58 1473.58 1.47 - dsf_xyztfb_w 10130 4.56 2263.58 2263.58 2263.58 2.26 - dsf_sum 10130 13.14 1512.78 1512.78 1512.78 1.51 - dsf_w2gen 2540 26.73 2095.20 2095.20 2095.20 2.10 - cgm 260 12.06 1839.82 1839.82 1839.82 1.84 - cg_ritz 82 3.93 1859.83 1859.83 1859.83 1.86 + stout_smear 1601 3.10 2027.62 2027.62 2027.62 2.03 + stout_diffe 2540 10.58 2778.42 2778.42 2778.42 2.78 + clover_bsa_w 20260 3.05 1560.80 1560.80 1560.80 1.56 + clover_dsd_w 1640 1.26 1360.02 1360.02 1360.02 1.36 + clover_d_w 5900 13.21 2287.22 2287.22 2287.22 2.29 + dsf_at_bt 10130 2.68 1786.46 1786.46 1786.46 1.79 + dsf_xyztfb_w 10130 5.11 2020.18 2020.18 2020.18 2.02 + dsf_sum 10130 14.18 1402.26 1402.26 1402.26 1.40 + dsf_w2gen 2540 23.58 2375.32 2375.32 2375.32 2.38 + cgm 260 10.65 2082.88 2082.88 2082.88 2.08 + cg_ritz 82 3.36 2175.34 2175.34 2175.34 2.18 cg_mix 0 bicgstab 0 bicgstab_mix 0 @@ -302,13 +301,13 @@ unprec_mmul 0 unprec_dsf 0 dsf_un 0 - dsf_mtmp 2020 92.45 - cg_mre_mtmp 2020 49.18 - dsf_wmul_r8 2020 0.52 - dsf_wdag_r8 410 0.15 - integrator 10 146.62 + dsf_mtmp 2020 79.97 + cg_mre_mtmp 2020 43.16 + dsf_wmul_r8 2020 0.45 + dsf_wdag_r8 410 0.09 + integrator 10 130.38 bagel_d 0 - TOTAL 1 151.23 + TOTAL 1 134.32 Performance region #calls time mean min max Total @@ -320,20 +319,20 @@ u_read_bqcd 0 u_write_bqcd 0 u_read_ildg 0 - u_write_ildg 1 0.00 +Inf +Inf +Inf +Inf + u_write_ildg 1 0.00 147.46 147.46 147.46 0.15 >EndTiming >EndFooter >EndJob >BeginJob >BeginHeader - Program bqcd 4.0.0 (revision 259) + Program bqcd 4.0.0 (revision 324) Version_of_D 100 - Communication single_pe + Communication MPI (sc:immediate) (g:immediate) RandomNumbers ranlux-3.2 level 2 Run 300 Job 2 - Host pc58588 - Date 2010-06-11 16:59:21.622 + Host m500 + Date 2011-09-21 14:39:59.024 L 4 4 4 4 DDL 1 1 1 1 NPE 1 1 1 1 @@ -368,6 +367,7 @@ n_stout_1 1 alpha_1 0.1 theta_1 0.0 + chemi_1 0.0 h_1 0.0 rho_1 0.1203 rho2_1 0.0 @@ -383,9 +383,6 @@ mpf_eo[m,l,s]: 2 0 2 mpf_dd[m,l,s]: 0 0 0 mpf_hh[m,l,s]: 0 0 0 - fraction_u1 40 - fraction_u2 0 - roughness_level 0 HMC_model F REAL_kind 8 Solver_outer cg @@ -401,14 +398,14 @@ ildg-read file bqcd.300.lime ildg-read precision 64 ildg-read bytes 147456 - ildg-read cksum 886460001 - ildg-read lfn bqcd-restart bqcd.300.lime 886460001 147456 300 1 0 + ildg-read cksum 889189260 + ildg-read lfn bqcd-restart bqcd.300.lime 889189260 147456 300 1 0 >EndILDGread >BeginMC T%mc traj e f PlaqEnergy exp(-Delta_H) Acc CGcalls CGitTot CGitMax CGMcalls CGMitTotCGMitMax Plaquette T%pr traj Plaquette PlaquetteS PlaquetteT Rectangle RectangleS RectangleT T%it traj iter_SF iter_F1 iter_F2 iter_F3 iter_F4 iter_F5 iter_F6 iter_F7 iter_F8 iter_F9 - %it 1 466 9160 2766 1827 0 0 0 0 0 0 + %it 1 468 9158 2766 1827 0 0 0 0 0 0 %it4 1 0 0 0 0 0 0 0 0 0 0 T%Favg traj F_gauge F_impg F_det F_F1 F_F2 F_F3 F_F4 F_F5 F_F6 F_F7 F_F8 F_F9 T%Fmax traj F_gauge F_impg F_det F_F1 F_F2 F_F3 F_F4 F_F5 F_F6 F_F7 F_F8 F_F9 @@ -420,103 +417,103 @@ T%Hnew traj H_total H_generator H_gauge H_det H_fermion_1 H_fermion_2 H_fermion_3 T%Hdif traj H_total H_generator H_gauge H_det H_fermion_1 H_fermion_2 H_fermion_3 %Hold 1 0.8059372E+04 0.3981543E+04 0.3927864E+04 -0.5981657E+04 0.1572569E+04 0.1491144E+04 0.3067908E+04 - %Hnew 1 0.8059149E+04 0.4134470E+04 0.3802579E+04 -0.5991136E+04 0.1561179E+04 0.1491647E+04 0.3060409E+04 - %Hdif 1 -0.2222102E+00 0.1529275E+03 -0.1252850E+03 -0.9479002E+01 -0.1138985E+02 0.5033574E+00 -0.7499230E+01 - %mc 1 1 1 0.5256287819 1.2488337936 1 203 12014 88 26 2205 96 0.474371218105791 - %pr 1 0.4743712181058 0.4726444579752 0.4760979782364 0.2448709195136 0.2412306449670 0.2485111940602 + %Hnew 1 0.8059149E+04 0.4134471E+04 0.3802579E+04 -0.5991136E+04 0.1561179E+04 0.1491647E+04 0.3060409E+04 + %Hdif 1 -0.2222101E+00 0.1529275E+03 -0.1252850E+03 -0.9479001E+01 -0.1138985E+02 0.5033573E+00 -0.7499235E+01 + %mc 1 1 1 0.5256287770 1.2488337049 1 203 12012 88 26 2207 97 0.474371223046195 + %pr 1 0.4743712230462 0.4726444624484 0.4760979836440 0.2448709265833 0.2412306527605 0.2485112004061 T%egnv traj type mid min max it_min it_max tol condi n_opt - %egnv 1 1 1 0.11201689E-01 2.1239394 92 55 1e-11 189.609 2.62 - %egnv 1 1 2 0.88566368E-02 2.1649865 94 54 1e-11 244.448 2.75 - %egnv 1 1 3 0.10542698E-01 2.1346871 92 55 1e-11 202.480 2.66 + %egnv 1 1 1 0.11201679E-01 2.1239394 92 55 1e-11 189.609 2.62 + %egnv 1 1 2 0.88566285E-02 2.1649865 94 54 1e-11 244.448 2.75 + %egnv 1 1 3 0.10542689E-01 2.1346870 92 55 1e-11 202.480 2.66 T%tr traj e f Re(pbp) Im(pbp) Re(p5p) -Im(p5p) PionNorm CGiter - %tr 1 1 1 1.096700490 -0.1407549329E-01 0.2229626393E-01 -0.7190087646E-12 2.751909090 98 + %tr 1 1 1 1.096700470 -0.1407549757E-01 0.2229625706E-01 -0.7183356919E-12 2.751909058 98 T%pl traj e f Re(Polyakov_Loop) Im(Polyakov_Loop) - %pl 1 1 1 -0.2789723339E-01 0.5139161873E-01 + %pl 1 1 1 -0.2789723450E-01 0.5139162926E-01 >BeginCooling T%Qc traj e f i_cool Q_cool PlaqEnergy - %Qc 1 1 1 0 0.048126 0.5256287819 - %Qc 1 1 1 1 0.020771 0.1313428205 - %Qc 1 1 1 2 0.182281 0.0511502439 - %Qc 1 1 1 3 0.219577 0.0309807565 - %Qc 1 1 1 4 0.142080 0.0218651570 - %Qc 1 1 1 5 0.052773 0.0161620071 - %Qc 1 1 1 6 0.009561 0.0114304799 - %Qc 1 1 1 7 0.002320 0.0075411392 - %Qc 1 1 1 8 0.001251 0.0046428300 - %Qc 1 1 1 9 0.000558 0.0026599216 - %Qc 1 1 1 10 0.000203 0.0014373723 + %Qc 1 1 1 0 0.048126 0.5256287770 + %Qc 1 1 1 1 0.020771 0.1313428137 + %Qc 1 1 1 2 0.182281 0.0511502420 + %Qc 1 1 1 3 0.219577 0.0309807569 + %Qc 1 1 1 4 0.142079 0.0218651553 + %Qc 1 1 1 5 0.052772 0.0161620044 + %Qc 1 1 1 6 0.009561 0.0114304766 + %Qc 1 1 1 7 0.002320 0.0075411352 + %Qc 1 1 1 8 0.001251 0.0046428261 + %Qc 1 1 1 9 0.000558 0.0026599186 + %Qc 1 1 1 10 0.000203 0.0014373703 %Qc 1 1 1 20 0.000000 0.0000057767 - %Qc 1 1 1 30 -0.000000 0.0000001381 + %Qc 1 1 1 30 0.000000 0.0000001381 %Qc 1 1 1 40 0.000000 0.0000000048 %Qc 1 1 1 50 0.000000 0.0000000002 >EndCooling - %it 2 455 7725 2355 1642 0 0 0 0 0 0 + %it 2 455 7713 2353 1642 0 0 0 0 0 0 %it4 2 0 0 0 0 0 0 0 0 0 0 %Favg 2 9.177 0.940 1.294 2.393 0.063 0.763 0.000 0.000 0.000 0.000 0.000 0.000 %Fmax 2 15.786 1.705 2.628 6.960 0.203 2.201 0.000 0.000 0.000 0.000 0.000 0.000 %Frat 2 77.904 8.415 12.971 34.348 1.000 10.863 0.000 0.000 0.000 0.000 0.000 0.000 %Hold 2 0.8090140E+04 0.4136443E+04 0.3802579E+04 -0.5991136E+04 0.1557003E+04 0.1537098E+04 0.3048153E+04 %Hnew 2 0.8089947E+04 0.4104749E+04 0.3861978E+04 -0.5997383E+04 0.1531613E+04 0.1537314E+04 0.3051676E+04 - %Hdif 2 -0.1930398E+00 -0.3169372E+02 0.5939898E+02 -0.6247830E+01 -0.2538992E+02 0.2159010E+00 0.3523546E+01 - %mc 2 1 1 0.5329972801 1.2129310686 1 203 10172 92 26 2005 98 0.467002719935582 - %pr 2 0.4670027199356 0.4683780993849 0.4656273404862 0.2414972288243 0.2417406808935 0.2412537767551 - %egnv 2 1 1 0.22479273E-01 2.2750864 88 38 1e-11 101.208 2.31 - %egnv 2 1 2 0.19130153E-01 2.3261450 89 37 1e-11 121.596 2.40 - %egnv 2 1 3 0.21554334E-01 2.2884333 88 38 1e-11 106.170 2.33 - %tr 2 1 1 1.057820167 -0.6021855563E-02 0.1866932235E-01 0.2982776063E-12 2.375531424 83 + %Hdif 2 -0.1930397E+00 -0.3169376E+02 0.5939898E+02 -0.6247813E+01 -0.2538990E+02 0.2159003E+00 0.3523551E+01 + %mc 2 1 1 0.5329972758 1.2129309274 1 203 10158 92 26 2005 98 0.467002724201304 + %pr 2 0.4670027242013 0.4683781065808 0.4656273418218 0.2414972304105 0.2417406884514 0.2412537723697 + %egnv 2 1 1 0.22479261E-01 2.2750867 88 38 1e-11 101.208 2.31 + %egnv 2 1 2 0.19130143E-01 2.3261452 89 37 1e-11 121.596 2.40 + %egnv 2 1 3 0.21554323E-01 2.2884335 88 38 1e-11 106.171 2.33 + %tr 2 1 1 1.057820190 -0.6021862974E-02 0.1866931362E-01 0.3615741965E-12 2.375531840 83 T%pl traj e f Re(Polyakov_Loop) Im(Polyakov_Loop) - %pl 2 1 1 -0.1273482066E-01 -0.2853310257E-02 + %pl 2 1 1 -0.1273484913E-01 -0.2853321515E-02 >BeginCooling T%Qc traj e f i_cool Q_cool PlaqEnergy - %Qc 2 1 1 0 -0.009762 0.5329972801 - %Qc 2 1 1 1 -0.005589 0.1193819388 - %Qc 2 1 1 2 0.280278 0.0339020463 - %Qc 2 1 1 3 0.458564 0.0186745744 - %Qc 2 1 1 4 0.515329 0.0133907635 - %Qc 2 1 1 5 0.494449 0.0106876369 - %Qc 2 1 1 6 0.412660 0.0089590302 - %Qc 2 1 1 7 0.243721 0.0071402566 - %Qc 2 1 1 8 0.051628 0.0041254140 - %Qc 2 1 1 9 0.004785 0.0017870795 - %Qc 2 1 1 10 0.000654 0.0008693693 - %Qc 2 1 1 20 -0.000000 0.0000149504 - %Qc 2 1 1 30 -0.000000 0.0000007825 - %Qc 2 1 1 40 -0.000000 0.0000000488 - %Qc 2 1 1 50 -0.000000 0.0000000034 + %Qc 2 1 1 0 -0.009762 0.5329972758 + %Qc 2 1 1 1 -0.005589 0.1193819288 + %Qc 2 1 1 2 0.280278 0.0339020377 + %Qc 2 1 1 3 0.458564 0.0186745698 + %Qc 2 1 1 4 0.515328 0.0133907596 + %Qc 2 1 1 5 0.494448 0.0106876320 + %Qc 2 1 1 6 0.412659 0.0089590221 + %Qc 2 1 1 7 0.243719 0.0071402369 + %Qc 2 1 1 8 0.051627 0.0041253851 + %Qc 2 1 1 9 0.004785 0.0017870676 + %Qc 2 1 1 10 0.000654 0.0008693651 + %Qc 2 1 1 20 0.000000 0.0000149504 + %Qc 2 1 1 30 0.000000 0.0000007825 + %Qc 2 1 1 40 0.000000 0.0000000488 + %Qc 2 1 1 50 0.000000 0.0000000034 >EndCooling - %it 3 402 7600 2291 1560 0 0 0 0 0 0 + %it 3 401 7600 2291 1560 0 0 0 0 0 0 %it4 3 0 0 0 0 0 0 0 0 0 0 %Favg 3 9.316 0.968 1.278 2.307 0.059 0.758 0.000 0.000 0.000 0.000 0.000 0.000 %Fmax 3 15.815 1.684 2.594 6.295 0.182 1.919 0.000 0.000 0.000 0.000 0.000 0.000 %Frat 3 86.712 9.230 14.222 34.514 1.000 10.520 0.000 0.000 0.000 0.000 0.000 0.000 %Hold 3 0.8167467E+04 0.4128298E+04 0.3861978E+04 -0.5997383E+04 0.1564709E+04 0.1498362E+04 0.3111503E+04 %Hnew 3 0.8167623E+04 0.4163487E+04 0.3834727E+04 -0.6003886E+04 0.1563891E+04 0.1498577E+04 0.3110827E+04 - %Hdif 3 0.1561674E+00 0.3518970E+02 -0.2725048E+02 -0.6502840E+01 -0.8185873E+00 0.2147341E+00 -0.6763635E+00 - %mc 3 1 1 0.5292769819 0.8554159753 1 203 9971 80 26 1882 84 0.470723018098662 - %pr 3 0.4707230180987 0.4681862080567 0.4732598281407 0.2464434901217 0.2415090083184 0.2513779719250 - %egnv 3 1 1 0.30015044E-01 2.1062975 104 54 1e-11 70.175 2.13 - %egnv 3 1 2 0.26192101E-01 2.1456848 105 54 1e-11 81.921 2.20 - %egnv 3 1 3 0.28967864E-01 2.1166148 105 54 1e-11 73.068 2.15 - %tr 3 1 1 1.021762823 -0.2042151733E-01 -0.4749031798E-01 0.4647902433E-14 2.277549541 77 + %Hdif 3 0.1561684E+00 0.3518979E+02 -0.2725051E+02 -0.6502838E+01 -0.8186301E+00 0.2147334E+00 -0.6763733E+00 + %mc 3 1 1 0.5292769730 0.8554151541 1 203 9971 80 26 1881 84 0.470723026987640 + %pr 3 0.4707230269876 0.4681862142698 0.4732598397055 0.2464434949806 0.2415090164368 0.2513779735243 + %egnv 3 1 1 0.30015001E-01 2.1062975 104 54 1e-11 70.175 2.13 + %egnv 3 1 2 0.26192060E-01 2.1456848 105 54 1e-11 81.921 2.20 + %egnv 3 1 3 0.28967822E-01 2.1166148 105 54 1e-11 73.068 2.15 + %tr 3 1 1 1.021762802 -0.2042146706E-01 -0.4749026802E-01 0.3708838792E-14 2.277549660 77 T%pl traj e f Re(Polyakov_Loop) Im(Polyakov_Loop) - %pl 3 1 1 0.1773357402E-02 -0.6020302397E-02 + %pl 3 1 1 0.1773340717E-02 -0.6020339663E-02 >BeginCooling T%Qc traj e f i_cool Q_cool PlaqEnergy - %Qc 3 1 1 0 0.082096 0.5292769819 - %Qc 3 1 1 1 0.130736 0.1094908249 - %Qc 3 1 1 2 0.348311 0.0290075332 - %Qc 3 1 1 3 0.482537 0.0148645258 - %Qc 3 1 1 4 0.532008 0.0109541619 - %Qc 3 1 1 5 0.531717 0.0093610450 - %Qc 3 1 1 6 0.496172 0.0084716148 - %Qc 3 1 1 7 0.418683 0.0077233870 - %Qc 3 1 1 8 0.256949 0.0064885255 - %Qc 3 1 1 9 0.051149 0.0036024180 - %Qc 3 1 1 10 0.004666 0.0014501003 - %Qc 3 1 1 20 -0.000001 0.0000733980 - %Qc 3 1 1 30 -0.000000 0.0000200829 - %Qc 3 1 1 40 -0.000000 0.0000066622 - %Qc 3 1 1 50 -0.000000 0.0000023273 + %Qc 3 1 1 0 0.082096 0.5292769730 + %Qc 3 1 1 1 0.130736 0.1094908154 + %Qc 3 1 1 2 0.348311 0.0290075334 + %Qc 3 1 1 3 0.482538 0.0148645273 + %Qc 3 1 1 4 0.532008 0.0109541635 + %Qc 3 1 1 5 0.531718 0.0093610467 + %Qc 3 1 1 6 0.496172 0.0084716167 + %Qc 3 1 1 7 0.418684 0.0077233903 + %Qc 3 1 1 8 0.256950 0.0064885359 + %Qc 3 1 1 9 0.051150 0.0036024366 + %Qc 3 1 1 10 0.004666 0.0014501075 + %Qc 3 1 1 20 -0.000001 0.0000733981 + %Qc 3 1 1 30 0.000000 0.0000200830 + %Qc 3 1 1 40 0.000000 0.0000066622 + %Qc 3 1 1 50 0.000000 0.0000023273 >EndCooling %it 4 359 6627 2011 1413 0 0 0 0 0 0 %it4 4 0 0 0 0 0 0 0 0 0 0 @@ -524,332 +521,332 @@ %Fmax 4 15.430 1.680 2.590 5.796 0.235 1.829 0.000 0.000 0.000 0.000 0.000 0.000 %Frat 4 65.672 7.152 11.026 24.668 1.000 7.786 0.000 0.000 0.000 0.000 0.000 0.000 %Hold 4 0.8032018E+04 0.4044664E+04 0.3834727E+04 -0.6003886E+04 0.1492007E+04 0.1535946E+04 0.3128561E+04 - %Hnew 4 0.8031830E+04 0.4209353E+04 0.3696939E+04 -0.6021735E+04 0.1497246E+04 0.1535235E+04 0.3114790E+04 - %Hdif 4 -0.1882389E+00 0.1646888E+03 -0.1377879E+03 -0.1784827E+02 0.5239810E+01 -0.7103588E+00 -0.1377034E+02 - %mc 4 1 1 0.5098751753 1.2071218126 1 203 8712 74 26 1698 77 0.490124824737818 - %pr 4 0.4901248247378 0.4871551218511 0.4930945276245 0.2773603205663 0.2734506483273 0.2812699928054 - %egnv 4 1 1 0.65502609E-01 2.0458115 171 64 1e-11 31.233 1.72 - %egnv 4 1 2 0.61459935E-01 2.0819227 136 63 1e-11 33.874 1.76 - %egnv 4 1 3 0.64416896E-01 2.0552798 169 64 1e-11 31.906 1.73 - %tr 4 1 1 1.007907845 -0.7601643054E-02 0.2443747534E-01 0.1701113209E-12 2.040834341 63 + %Hnew 4 0.8031830E+04 0.4209353E+04 0.3696940E+04 -0.6021735E+04 0.1497246E+04 0.1535235E+04 0.3114790E+04 + %Hdif 4 -0.1882383E+00 0.1646887E+03 -0.1377878E+03 -0.1784831E+02 0.5239860E+01 -0.7103572E+00 -0.1377036E+02 + %mc 4 1 1 0.5098751838 1.2071211928 1 203 8712 74 26 1698 77 0.490124816237965 + %pr 4 0.4901248162380 0.4871551144651 0.4930945180108 0.2773603035793 0.2734506445581 0.2812699626005 + %egnv 4 1 1 0.65502654E-01 2.0458122 171 64 1e-11 31.233 1.72 + %egnv 4 1 2 0.61460003E-01 2.0819235 136 63 1e-11 33.874 1.76 + %egnv 4 1 3 0.64416952E-01 2.0552805 169 64 1e-11 31.906 1.73 + %tr 4 1 1 1.007907740 -0.7601657422E-02 0.2443749522E-01 0.1701416785E-12 2.040833175 63 T%pl traj e f Re(Polyakov_Loop) Im(Polyakov_Loop) - %pl 4 1 1 0.7951725245E-01 0.5623780163E-01 + %pl 4 1 1 0.7951735428E-01 0.5623785358E-01 >BeginCooling T%Qc traj e f i_cool Q_cool PlaqEnergy - %Qc 4 1 1 0 0.045646 0.5098751753 - %Qc 4 1 1 1 -0.029235 0.0931408422 - %Qc 4 1 1 2 0.001388 0.0184513185 - %Qc 4 1 1 3 0.003494 0.0052928934 - %Qc 4 1 1 4 0.001061 0.0023353861 - %Qc 4 1 1 5 0.000387 0.0012942043 - %Qc 4 1 1 6 0.000180 0.0008218519 - %Qc 4 1 1 7 0.000100 0.0005731850 - %Qc 4 1 1 8 0.000059 0.0004276599 + %Qc 4 1 1 0 0.045646 0.5098751838 + %Qc 4 1 1 1 -0.029234 0.0931408520 + %Qc 4 1 1 2 0.001388 0.0184513252 + %Qc 4 1 1 3 0.003494 0.0052928955 + %Qc 4 1 1 4 0.001061 0.0023353871 + %Qc 4 1 1 5 0.000387 0.0012942050 + %Qc 4 1 1 6 0.000180 0.0008218524 + %Qc 4 1 1 7 0.000100 0.0005731852 + %Qc 4 1 1 8 0.000059 0.0004276600 %Qc 4 1 1 9 0.000037 0.0003349832 - %Qc 4 1 1 10 0.000023 0.0002717444 - %Qc 4 1 1 20 -0.000000 0.0000711819 - %Qc 4 1 1 30 -0.000000 0.0000293477 - %Qc 4 1 1 40 -0.000000 0.0000144832 - %Qc 4 1 1 50 -0.000000 0.0000078682 + %Qc 4 1 1 10 0.000023 0.0002717443 + %Qc 4 1 1 20 0.000000 0.0000711818 + %Qc 4 1 1 30 0.000000 0.0000293476 + %Qc 4 1 1 40 0.000000 0.0000144831 + %Qc 4 1 1 50 0.000000 0.0000078681 >EndCooling %it 5 314 5524 1698 1202 0 0 0 0 0 0 %it4 5 0 0 0 0 0 0 0 0 0 0 %Favg 5 9.482 1.018 1.283 2.051 0.066 0.702 0.000 0.000 0.000 0.000 0.000 0.000 %Fmax 5 15.906 1.765 2.497 5.144 0.220 1.751 0.000 0.000 0.000 0.000 0.000 0.000 %Frat 5 72.376 8.032 11.363 23.406 1.000 7.968 0.000 0.000 0.000 0.000 0.000 0.000 - %Hold 5 0.7907837E+04 0.4124302E+04 0.3696939E+04 -0.6021735E+04 0.1493893E+04 0.1589574E+04 0.3024863E+04 - %Hnew 5 0.7907717E+04 0.4170782E+04 0.3640564E+04 -0.6017343E+04 0.1500153E+04 0.1589358E+04 0.3024205E+04 - %Hdif 5 -0.1194158E+00 0.4647944E+02 -0.5637588E+02 0.4391044E+01 0.6260341E+01 -0.2158011E+00 -0.6585559E+00 - %mc 5 1 1 0.5031014784 1.1268383552 1 203 7284 62 26 1454 65 0.496898521559694 - %pr 5 0.4968985215597 0.4932022938734 0.5005947492460 0.2783644727806 0.2752902984062 0.2814386471549 - %egnv 5 1 1 0.55985783E-01 2.1002743 57 79 1e-11 37.514 1.81 - %egnv 5 1 2 0.52921759E-01 2.1423924 58 75 1e-11 40.482 1.85 - %egnv 5 1 3 0.55143429E-01 2.1112897 58 78 1e-11 38.287 1.82 - %tr 5 1 1 1.001996987 0.3439318868E-01 0.8709399251E-02 0.2187463174E-12 2.079031150 59 + %Hold 5 0.7907837E+04 0.4124302E+04 0.3696940E+04 -0.6021735E+04 0.1493893E+04 0.1589574E+04 0.3024863E+04 + %Hnew 5 0.7907717E+04 0.4170782E+04 0.3640564E+04 -0.6017344E+04 0.1500153E+04 0.1589358E+04 0.3024205E+04 + %Hdif 5 -0.1194159E+00 0.4647945E+02 -0.5637582E+02 0.4390938E+01 0.6260358E+01 -0.2158074E+00 -0.6585272E+00 + %mc 5 1 1 0.5031014919 1.1268384922 1 203 7284 62 26 1454 65 0.496898508071844 + %pr 5 0.4968985080718 0.4932023050255 0.5005947111182 0.2783644750499 0.2752902995812 0.2814386505187 + %egnv 5 1 1 0.55985947E-01 2.1002751 57 79 1e-11 37.514 1.81 + %egnv 5 1 2 0.52921920E-01 2.1423933 58 75 1e-11 40.482 1.85 + %egnv 5 1 3 0.55143592E-01 2.1112906 58 78 1e-11 38.287 1.82 + %tr 5 1 1 1.001996920 0.3439334613E-01 0.8709501380E-02 0.2185751580E-12 2.079030151 59 T%pl traj e f Re(Polyakov_Loop) Im(Polyakov_Loop) - %pl 5 1 1 0.1138802121 0.4482838698E-02 + %pl 5 1 1 0.1138805534 0.4482829392E-02 >BeginCooling T%Qc traj e f i_cool Q_cool PlaqEnergy - %Qc 5 1 1 0 0.027003 0.5031014784 - %Qc 5 1 1 1 -0.080645 0.0867700263 - %Qc 5 1 1 2 -0.054680 0.0171108504 - %Qc 5 1 1 3 -0.007190 0.0055779860 - %Qc 5 1 1 4 -0.001143 0.0023577164 - %Qc 5 1 1 5 -0.000409 0.0012326226 - %Qc 5 1 1 6 -0.000174 0.0007421948 - %Qc 5 1 1 7 -0.000077 0.0004950696 - %Qc 5 1 1 8 -0.000036 0.0003559673 - %Qc 5 1 1 9 -0.000018 0.0002700183 + %Qc 5 1 1 0 0.027002 0.5031014919 + %Qc 5 1 1 1 -0.080644 0.0867700000 + %Qc 5 1 1 2 -0.054677 0.0171107429 + %Qc 5 1 1 3 -0.007189 0.0055779297 + %Qc 5 1 1 4 -0.001143 0.0023577075 + %Qc 5 1 1 5 -0.000409 0.0012326219 + %Qc 5 1 1 6 -0.000174 0.0007421952 + %Qc 5 1 1 7 -0.000077 0.0004950700 + %Qc 5 1 1 8 -0.000036 0.0003559675 + %Qc 5 1 1 9 -0.000018 0.0002700184 %Qc 5 1 1 10 -0.000010 0.0002125880 - %Qc 5 1 1 20 -0.000001 0.0000387951 - %Qc 5 1 1 30 -0.000000 0.0000102065 - %Qc 5 1 1 40 -0.000000 0.0000032597 - %Qc 5 1 1 50 -0.000000 0.0000011935 + %Qc 5 1 1 20 -0.000001 0.0000387950 + %Qc 5 1 1 30 0.000000 0.0000102066 + %Qc 5 1 1 40 0.000000 0.0000032598 + %Qc 5 1 1 50 0.000000 0.0000011935 >EndCooling - %it 6 284 4843 1476 1074 0 0 0 0 0 0 + %it 6 284 4840 1476 1074 0 0 0 0 0 0 %it4 6 0 0 0 0 0 0 0 0 0 0 %Favg 6 9.655 1.064 1.253 2.035 0.053 0.680 0.000 0.000 0.000 0.000 0.000 0.000 %Fmax 6 16.137 1.794 2.508 5.690 0.163 1.586 0.000 0.000 0.000 0.000 0.000 0.000 %Frat 6 99.208 11.027 15.421 34.982 1.000 9.750 0.000 0.000 0.000 0.000 0.000 0.000 - %Hold 6 0.7711427E+04 0.4021976E+04 0.3640564E+04 -0.6017343E+04 0.1557628E+04 0.1489029E+04 0.3019573E+04 - %Hnew 6 0.7711868E+04 0.4145540E+04 0.3545618E+04 -0.6029318E+04 0.1542523E+04 0.1489057E+04 0.3018447E+04 - %Hdif 6 0.4417190E+00 0.1235644E+03 -0.9494551E+02 -0.1197408E+02 -0.1510536E+02 0.2809388E-01 -0.1125836E+01 - %mc 6 1 1 0.5031014784 0.6429302791 0 203 6377 58 26 1300 61 0.496898521559694 - %pr 6 0.4968985215597 0.4932022938734 0.5005947492460 0.2783644727806 0.2752902984062 0.2814386471549 - %egnv 6 1 1 0.55985783E-01 2.1002743 57 79 1e-11 37.514 1.81 - %egnv 6 1 2 0.52921759E-01 2.1423924 58 75 1e-11 40.482 1.85 - %egnv 6 1 3 0.55143429E-01 2.1112897 58 78 1e-11 38.287 1.82 - %tr 6 1 1 1.021818852 -0.8049552490E-02 0.1859040886E-01 0.2879403891E-12 2.002771437 60 + %Hold 6 0.7711427E+04 0.4021976E+04 0.3640564E+04 -0.6017344E+04 0.1557628E+04 0.1489029E+04 0.3019573E+04 + %Hnew 6 0.7711868E+04 0.4145540E+04 0.3545618E+04 -0.6029317E+04 0.1542523E+04 0.1489057E+04 0.3018448E+04 + %Hdif 6 0.4417224E+00 0.1235641E+03 -0.9494574E+02 -0.1197384E+02 -0.1510522E+02 0.2810082E-01 -0.1125694E+01 + %mc 6 1 1 0.5031014919 0.6429280999 0 203 6374 58 26 1300 61 0.496898508071844 + %pr 6 0.4968985080718 0.4932023050255 0.5005947111182 0.2783644750499 0.2752902995812 0.2814386505187 + %egnv 6 1 1 0.55985947E-01 2.1002751 57 79 1e-11 37.514 1.81 + %egnv 6 1 2 0.52921920E-01 2.1423933 58 75 1e-11 40.482 1.85 + %egnv 6 1 3 0.55143592E-01 2.1112906 58 78 1e-11 38.287 1.82 + %tr 6 1 1 1.021818811 -0.8049552374E-02 0.1859023707E-01 0.2879224636E-12 2.002770834 60 T%pl traj e f Re(Polyakov_Loop) Im(Polyakov_Loop) - %pl 6 1 1 0.1138802121 0.4482838698E-02 + %pl 6 1 1 0.1138805534 0.4482829392E-02 >BeginCooling T%Qc traj e f i_cool Q_cool PlaqEnergy - %Qc 6 1 1 0 0.027003 0.5031014784 - %Qc 6 1 1 1 -0.080645 0.0867700263 - %Qc 6 1 1 2 -0.054680 0.0171108504 - %Qc 6 1 1 3 -0.007190 0.0055779860 - %Qc 6 1 1 4 -0.001143 0.0023577164 - %Qc 6 1 1 5 -0.000409 0.0012326226 - %Qc 6 1 1 6 -0.000174 0.0007421948 - %Qc 6 1 1 7 -0.000077 0.0004950696 - %Qc 6 1 1 8 -0.000036 0.0003559673 - %Qc 6 1 1 9 -0.000018 0.0002700183 + %Qc 6 1 1 0 0.027002 0.5031014919 + %Qc 6 1 1 1 -0.080644 0.0867700000 + %Qc 6 1 1 2 -0.054677 0.0171107429 + %Qc 6 1 1 3 -0.007189 0.0055779297 + %Qc 6 1 1 4 -0.001143 0.0023577075 + %Qc 6 1 1 5 -0.000409 0.0012326219 + %Qc 6 1 1 6 -0.000174 0.0007421952 + %Qc 6 1 1 7 -0.000077 0.0004950700 + %Qc 6 1 1 8 -0.000036 0.0003559675 + %Qc 6 1 1 9 -0.000018 0.0002700184 %Qc 6 1 1 10 -0.000010 0.0002125880 - %Qc 6 1 1 20 -0.000001 0.0000387951 - %Qc 6 1 1 30 -0.000000 0.0000102065 - %Qc 6 1 1 40 -0.000000 0.0000032597 - %Qc 6 1 1 50 -0.000000 0.0000011935 + %Qc 6 1 1 20 -0.000001 0.0000387950 + %Qc 6 1 1 30 0.000000 0.0000102066 + %Qc 6 1 1 40 0.000000 0.0000032598 + %Qc 6 1 1 50 0.000000 0.0000011935 >EndCooling - %it 7 307 5336 1618 1164 0 0 0 0 0 0 + %it 7 307 5336 1618 1162 0 0 0 0 0 0 %it4 7 0 0 0 0 0 0 0 0 0 0 %Favg 7 9.477 1.033 1.265 2.097 0.056 0.707 0.000 0.000 0.000 0.000 0.000 0.000 %Fmax 7 15.923 1.808 2.602 5.365 0.152 1.725 0.000 0.000 0.000 0.000 0.000 0.000 %Frat 7 104.582 11.874 17.091 35.238 1.000 11.327 0.000 0.000 0.000 0.000 0.000 0.000 - %Hold 7 0.8015286E+04 0.4099800E+04 0.3640564E+04 -0.6017343E+04 0.1590498E+04 0.1568021E+04 0.3133748E+04 - %Hnew 7 0.8015235E+04 0.4183155E+04 0.3571096E+04 -0.6012626E+04 0.1584634E+04 0.1567366E+04 0.3121610E+04 - %Hdif 7 -0.5113948E-01 0.8335553E+02 -0.6946721E+02 0.4717735E+01 -0.5864061E+01 -0.6556146E+00 -0.1213753E+02 - %mc 7 1 1 0.4940644414 1.0524696860 1 203 7012 58 26 1413 64 0.505935558570389 - %pr 7 0.5059355585704 0.5058614794300 0.5060096377108 0.2865056687715 0.2908622534745 0.2821490840686 - %egnv 7 1 1 0.54562660E-01 2.1441410 139 46 1e-11 39.297 1.84 - %egnv 7 1 2 0.50838984E-01 2.1892239 135 45 1e-11 43.062 1.88 - %egnv 7 1 3 0.53545687E-01 2.1559265 137 46 1e-11 40.263 1.85 - %tr 7 1 1 1.038466593 0.1605924825E-01 0.3407742008E-01 0.4800454016E-12 2.153321764 63 + %Hold 7 0.8015286E+04 0.4099800E+04 0.3640564E+04 -0.6017344E+04 0.1590498E+04 0.1568021E+04 0.3133748E+04 + %Hnew 7 0.8015235E+04 0.4183154E+04 0.3571097E+04 -0.6012626E+04 0.1584634E+04 0.1567366E+04 0.3121610E+04 + %Hdif 7 -0.5114375E-01 0.8335450E+02 -0.6946645E+02 0.4717881E+01 -0.5863984E+01 -0.6556227E+00 -0.1213747E+02 + %mc 7 1 1 0.4940645550 1.0524741801 1 203 7012 58 26 1411 64 0.505935444971773 + %pr 7 0.5059354449718 0.5058614714847 0.5060094184589 0.2865055656035 0.2908621877491 0.2821489434578 + %egnv 7 1 1 0.54562852E-01 2.1441359 139 46 1e-11 39.297 1.84 + %egnv 7 1 2 0.50839167E-01 2.1892184 135 45 1e-11 43.062 1.88 + %egnv 7 1 3 0.53545877E-01 2.1559214 137 46 1e-11 40.263 1.85 + %tr 7 1 1 1.038466540 0.1605938750E-01 0.3407762013E-01 0.4752147749E-12 2.153323043 63 T%pl traj e f Re(Polyakov_Loop) Im(Polyakov_Loop) - %pl 7 1 1 0.1059552749 0.4013742461E-01 + %pl 7 1 1 0.1059549123 0.4013756611E-01 >BeginCooling T%Qc traj e f i_cool Q_cool PlaqEnergy - %Qc 7 1 1 0 0.039829 0.4940644414 - %Qc 7 1 1 1 -0.077202 0.0875074447 - %Qc 7 1 1 2 -0.009690 0.0174920790 - %Qc 7 1 1 3 0.001651 0.0054441039 - %Qc 7 1 1 4 0.000961 0.0023981248 - %Qc 7 1 1 5 0.000521 0.0013220648 - %Qc 7 1 1 6 0.000299 0.0008278102 - %Qc 7 1 1 7 0.000182 0.0005630218 - %Qc 7 1 1 8 0.000117 0.0004060663 - %Qc 7 1 1 9 0.000078 0.0003059132 - %Qc 7 1 1 10 0.000054 0.0002381615 - %Qc 7 1 1 20 0.000002 0.0000411097 - %Qc 7 1 1 30 0.000000 0.0000101558 + %Qc 7 1 1 0 0.039831 0.4940645550 + %Qc 7 1 1 1 -0.077203 0.0875075687 + %Qc 7 1 1 2 -0.009691 0.0174921751 + %Qc 7 1 1 3 0.001651 0.0054441412 + %Qc 7 1 1 4 0.000961 0.0023981364 + %Qc 7 1 1 5 0.000521 0.0013220685 + %Qc 7 1 1 6 0.000299 0.0008278110 + %Qc 7 1 1 7 0.000182 0.0005630213 + %Qc 7 1 1 8 0.000117 0.0004060652 + %Qc 7 1 1 9 0.000078 0.0003059119 + %Qc 7 1 1 10 0.000054 0.0002381602 + %Qc 7 1 1 20 0.000002 0.0000411089 + %Qc 7 1 1 30 0.000000 0.0000101555 %Qc 7 1 1 40 0.000000 0.0000026919 - %Qc 7 1 1 50 0.000000 0.0000007363 + %Qc 7 1 1 50 0.000000 0.0000007362 >EndCooling %it 8 302 4696 1431 1063 0 0 0 0 0 0 %it4 8 0 0 0 0 0 0 0 0 0 0 %Favg 8 9.507 1.048 1.262 2.120 0.049 0.691 0.000 0.000 0.000 0.000 0.000 0.000 %Fmax 8 15.685 1.748 2.664 5.060 0.139 1.547 0.000 0.000 0.000 0.000 0.000 0.000 %Frat 8 112.648 12.552 19.131 36.341 1.000 11.110 0.000 0.000 0.000 0.000 0.000 0.000 - %Hold 8 0.7775594E+04 0.4076839E+04 0.3571096E+04 -0.6012626E+04 0.1539474E+04 0.1536608E+04 0.3064202E+04 - %Hnew 8 0.7775299E+04 0.4189634E+04 0.3454245E+04 -0.6021089E+04 0.1552887E+04 0.1535884E+04 0.3063738E+04 - %Hdif 8 -0.2944022E+00 0.1127952E+03 -0.1168511E+03 -0.8463289E+01 0.1341280E+02 -0.7246042E+00 -0.4634163E+00 - %mc 8 1 1 0.4784649756 1.3423236869 1 203 6187 60 26 1305 64 0.521535024389628 - %pr 8 0.5215350243896 0.5201126083548 0.5229574404244 0.3041822322966 0.3066437871460 0.3017206774472 - %egnv 8 1 1 0.89804417E-01 2.1318832 402 49 1e-11 23.739 1.58 - %egnv 8 1 2 0.87969935E-01 2.1776359 458 47 1e-11 24.754 1.60 - %egnv 8 1 3 0.89284234E-01 2.1438379 410 49 1e-11 24.011 1.59 - %tr 8 1 1 1.005232580 -0.1776836719E-01 0.1515187603E-01 0.9981830177E-13 1.925465958 56 + %Hold 8 0.7775594E+04 0.4076839E+04 0.3571097E+04 -0.6012626E+04 0.1539474E+04 0.1536608E+04 0.3064202E+04 + %Hnew 8 0.7775300E+04 0.4189633E+04 0.3454247E+04 -0.6021089E+04 0.1552886E+04 0.1535884E+04 0.3063738E+04 + %Hdif 8 -0.2944143E+00 0.1127944E+03 -0.1168503E+03 -0.8463230E+01 0.1341267E+02 -0.7246035E+00 -0.4633272E+00 + %mc 8 1 1 0.4784652040 1.3423399820 1 203 6187 60 26 1305 64 0.521534795979921 + %pr 8 0.5215347959799 0.5201125895339 0.5229570024259 0.3041819451087 0.3066437102312 0.3017201799862 + %egnv 8 1 1 0.89804536E-01 2.1318790 402 49 1e-11 23.739 1.58 + %egnv 8 1 2 0.87970045E-01 2.1776315 458 47 1e-11 24.754 1.60 + %egnv 8 1 3 0.89284351E-01 2.1438337 410 49 1e-11 24.011 1.59 + %tr 8 1 1 1.005232548 -0.1776789782E-01 0.1515165817E-01 0.9984258790E-13 1.925466705 56 T%pl traj e f Re(Polyakov_Loop) Im(Polyakov_Loop) - %pl 8 1 1 0.2075269581 -0.2875034199E-02 + %pl 8 1 1 0.2075281073 -0.2875211505E-02 >BeginCooling T%Qc traj e f i_cool Q_cool PlaqEnergy - %Qc 8 1 1 0 0.002028 0.4784649756 - %Qc 8 1 1 1 0.015649 0.0739165664 - %Qc 8 1 1 2 -0.000337 0.0117042590 - %Qc 8 1 1 3 0.001183 0.0041610990 - %Qc 8 1 1 4 0.000999 0.0021419626 - %Qc 8 1 1 5 0.000624 0.0012944200 - %Qc 8 1 1 6 0.000384 0.0008672893 - %Qc 8 1 1 7 0.000246 0.0006281566 - %Qc 8 1 1 8 0.000165 0.0004827686 - %Qc 8 1 1 9 0.000115 0.0003880828 - %Qc 8 1 1 10 0.000083 0.0003226650 - %Qc 8 1 1 20 0.000006 0.0001077947 - %Qc 8 1 1 30 0.000000 0.0000541516 - %Qc 8 1 1 40 -0.000000 0.0000309701 - %Qc 8 1 1 50 -0.000000 0.0000189534 + %Qc 8 1 1 0 0.002027 0.4784652040 + %Qc 8 1 1 1 0.015649 0.0739168346 + %Qc 8 1 1 2 -0.000337 0.0117043398 + %Qc 8 1 1 3 0.001183 0.0041611320 + %Qc 8 1 1 4 0.000999 0.0021419796 + %Qc 8 1 1 5 0.000624 0.0012944292 + %Qc 8 1 1 6 0.000384 0.0008672942 + %Qc 8 1 1 7 0.000246 0.0006281591 + %Qc 8 1 1 8 0.000165 0.0004827697 + %Qc 8 1 1 9 0.000115 0.0003880831 + %Qc 8 1 1 10 0.000083 0.0003226648 + %Qc 8 1 1 20 0.000006 0.0001077940 + %Qc 8 1 1 30 0.000000 0.0000541512 + %Qc 8 1 1 40 0.000000 0.0000309698 + %Qc 8 1 1 50 0.000000 0.0000189532 >EndCooling %it 9 278 4611 1400 1029 0 0 0 0 0 0 %it4 9 0 0 0 0 0 0 0 0 0 0 %Favg 9 9.639 1.071 1.268 1.943 0.053 0.713 0.000 0.000 0.000 0.000 0.000 0.000 %Fmax 9 15.785 1.806 2.600 4.739 0.143 1.810 0.000 0.000 0.000 0.000 0.000 0.000 - %Frat 9 110.570 12.650 18.212 33.199 1.000 12.678 0.000 0.000 0.000 0.000 0.000 0.000 - %Hold 9 0.7850211E+04 0.4133535E+04 0.3454245E+04 -0.6021089E+04 0.1494688E+04 0.1594648E+04 0.3194184E+04 - %Hnew 9 0.7850568E+04 0.4138992E+04 0.3457535E+04 -0.6034924E+04 0.1511286E+04 0.1595209E+04 0.3182469E+04 - %Hdif 9 0.3565416E+00 0.5456571E+01 0.3289833E+01 -0.1383473E+02 0.1659775E+02 0.5614769E+00 -0.1171437E+02 - %mc 9 1 1 0.4783439102 0.7000933530 1 203 6066 55 26 1252 58 0.521656089758662 - %pr 9 0.5216560897587 0.5175579692613 0.5257542102560 0.3092871013305 0.2946128306597 0.3239613720014 - %egnv 9 1 1 0.79339562E-01 2.1200901 60 38 1e-11 26.722 1.64 - %egnv 9 1 2 0.76287012E-01 2.1642184 61 37 1e-11 28.369 1.67 - %egnv 9 1 3 0.78499302E-01 2.1316285 60 38 1e-11 27.155 1.65 - %tr 9 1 1 1.017316061 0.1019396879E-01 -0.3873125184E-02 0.3965323440E-12 1.988905552 53 + %Frat 9 110.569 12.650 18.212 33.199 1.000 12.678 0.000 0.000 0.000 0.000 0.000 0.000 + %Hold 9 0.7850213E+04 0.4133535E+04 0.3454247E+04 -0.6021089E+04 0.1494688E+04 0.1594648E+04 0.3194184E+04 + %Hnew 9 0.7850570E+04 0.4138991E+04 0.3457538E+04 -0.6034924E+04 0.1511286E+04 0.1595209E+04 0.3182469E+04 + %Hdif 9 0.3565431E+00 0.5455512E+01 0.3291321E+01 -0.1383545E+02 0.1659824E+02 0.5615024E+00 -0.1171458E+02 + %mc 9 1 1 0.4783442927 0.7000922742 1 203 6066 55 26 1252 58 0.521655707272326 + %pr 9 0.5216557072723 0.5175574633608 0.5257539511838 0.3092870341369 0.2946129849990 0.3239610832748 + %egnv 9 1 1 0.79341387E-01 2.1200690 60 38 1e-11 26.721 1.64 + %egnv 9 1 2 0.76288790E-01 2.1641957 61 37 1e-11 28.368 1.67 + %egnv 9 1 3 0.78501115E-01 2.1316070 60 38 1e-11 27.154 1.65 + %tr 9 1 1 1.017315715 0.1019447404E-01 -0.3872964918E-02 0.3966439445E-12 1.988903398 53 T%pl traj e f Re(Polyakov_Loop) Im(Polyakov_Loop) - %pl 9 1 1 0.2796975100 0.7808683790E-02 + %pl 9 1 1 0.2796950282 0.7809490015E-02 >BeginCooling T%Qc traj e f i_cool Q_cool PlaqEnergy - %Qc 9 1 1 0 0.015460 0.4783439102 - %Qc 9 1 1 1 -0.031638 0.0709671563 - %Qc 9 1 1 2 -0.004020 0.0099617757 - %Qc 9 1 1 3 -0.000717 0.0031588151 - %Qc 9 1 1 4 -0.000133 0.0014990532 - %Qc 9 1 1 5 -0.000030 0.0008893425 - %Qc 9 1 1 6 -0.000018 0.0006135112 - %Qc 9 1 1 7 -0.000020 0.0004674604 - %Qc 9 1 1 8 -0.000021 0.0003788013 - %Qc 9 1 1 9 -0.000021 0.0003186521 - %Qc 9 1 1 10 -0.000019 0.0002743553 - %Qc 9 1 1 20 -0.000005 0.0000937959 - %Qc 9 1 1 30 -0.000001 0.0000408909 - %Qc 9 1 1 40 -0.000000 0.0000197091 - %Qc 9 1 1 50 -0.000000 0.0000101358 + %Qc 9 1 1 0 0.015458 0.4783442927 + %Qc 9 1 1 1 -0.031634 0.0709672566 + %Qc 9 1 1 2 -0.004020 0.0099618190 + %Qc 9 1 1 3 -0.000717 0.0031588453 + %Qc 9 1 1 4 -0.000133 0.0014990782 + %Qc 9 1 1 5 -0.000030 0.0008893626 + %Qc 9 1 1 6 -0.000018 0.0006135269 + %Qc 9 1 1 7 -0.000020 0.0004674728 + %Qc 9 1 1 8 -0.000021 0.0003788112 + %Qc 9 1 1 9 -0.000021 0.0003186601 + %Qc 9 1 1 10 -0.000019 0.0002743619 + %Qc 9 1 1 20 -0.000005 0.0000937979 + %Qc 9 1 1 30 -0.000001 0.0000408921 + %Qc 9 1 1 40 0.000000 0.0000197099 + %Qc 9 1 1 50 0.000000 0.0000101365 >EndCooling %it 10 268 4598 1388 1018 0 0 0 0 0 0 %it4 10 0 0 0 0 0 0 0 0 0 0 %Favg 10 9.724 1.094 1.257 2.038 0.051 0.670 0.000 0.000 0.000 0.000 0.000 0.000 %Fmax 10 15.974 1.861 2.511 5.364 0.151 1.614 0.000 0.000 0.000 0.000 0.000 0.000 - %Frat 10 105.778 12.326 16.627 35.521 1.000 10.690 0.000 0.000 0.000 0.000 0.000 0.000 - %Hold 10 0.7651666E+04 0.4096361E+04 0.3457535E+04 -0.6034924E+04 0.1594950E+04 0.1543888E+04 0.2993857E+04 - %Hnew 10 0.7651844E+04 0.4112810E+04 0.3453801E+04 -0.6026672E+04 0.1576267E+04 0.1544064E+04 0.2991575E+04 - %Hdif 10 0.1781014E+00 0.1644903E+02 -0.3733711E+01 0.8252019E+01 -0.1868320E+02 0.1756377E+00 -0.2281678E+01 - %mc 10 1 1 0.4782961713 0.8368575590 1 203 6038 52 26 1234 54 0.521703828699875 - %pr 10 0.5217038286999 0.5220441959034 0.5213634614963 0.3053448518001 0.3028146382562 0.3078750653441 - %egnv 10 1 1 0.86328110E-01 2.0804812 68 49 1e-11 24.100 1.59 - %egnv 10 1 2 0.84184902E-01 2.1219390 69 48 1e-11 25.206 1.61 - %egnv 10 1 3 0.85726953E-01 2.0913289 68 48 1e-11 24.395 1.60 - %tr 10 1 1 1.022055159 0.5521503278E-02 -0.2998286013E-01 0.8873341876E-13 2.027423632 53 + %Frat 10 105.786 12.327 16.628 35.524 1.000 10.691 0.000 0.000 0.000 0.000 0.000 0.000 + %Hold 10 0.7651669E+04 0.4096361E+04 0.3457538E+04 -0.6034924E+04 0.1594950E+04 0.1543888E+04 0.2993857E+04 + %Hnew 10 0.7651847E+04 0.4112810E+04 0.3453802E+04 -0.6026671E+04 0.1576267E+04 0.1544064E+04 0.2991576E+04 + %Hdif 10 0.1780956E+00 0.1644972E+02 -0.3736125E+01 0.8253212E+01 -0.1868316E+02 0.1756585E+00 -0.2281204E+01 + %mc 10 1 1 0.4782963023 0.8368624258 1 203 6038 52 26 1234 54 0.521703697718456 + %pr 10 0.5217036977185 0.5220436866234 0.5213637088135 0.3053444417748 0.3028137078901 0.3078751756595 + %egnv 10 1 1 0.86329054E-01 2.0804691 68 49 1e-11 24.099 1.59 + %egnv 10 1 2 0.84185814E-01 2.1219260 69 48 1e-11 25.205 1.61 + %egnv 10 1 3 0.85727889E-01 2.0913165 68 48 1e-11 24.395 1.60 + %tr 10 1 1 1.022055607 0.5523151529E-02 -0.2998225125E-01 0.8880859011E-13 2.027435705 53 T%pl traj e f Re(Polyakov_Loop) Im(Polyakov_Loop) - %pl 10 1 1 0.1284477377 0.6387078416E-02 + %pl 10 1 1 0.1284470852 0.6393035583E-02 >BeginCooling T%Qc traj e f i_cool Q_cool PlaqEnergy - %Qc 10 1 1 0 -0.116389 0.4782961713 - %Qc 10 1 1 1 -0.007454 0.0669723197 - %Qc 10 1 1 2 -0.003763 0.0090384656 - %Qc 10 1 1 3 -0.001751 0.0027058642 - %Qc 10 1 1 4 -0.000821 0.0012937578 - %Qc 10 1 1 5 -0.000389 0.0007832207 - %Qc 10 1 1 6 -0.000190 0.0005480911 - %Qc 10 1 1 7 -0.000095 0.0004200246 - %Qc 10 1 1 8 -0.000049 0.0003401863 - %Qc 10 1 1 9 -0.000026 0.0002849915 - %Qc 10 1 1 10 -0.000014 0.0002438627 - %Qc 10 1 1 20 0.000000 0.0000756183 - %Qc 10 1 1 30 0.000000 0.0000302082 - %Qc 10 1 1 40 0.000000 0.0000140579 - %Qc 10 1 1 50 0.000000 0.0000073432 + %Qc 10 1 1 0 -0.116392 0.4782963023 + %Qc 10 1 1 1 -0.007457 0.0669725915 + %Qc 10 1 1 2 -0.003763 0.0090385244 + %Qc 10 1 1 3 -0.001751 0.0027058910 + %Qc 10 1 1 4 -0.000821 0.0012937810 + %Qc 10 1 1 5 -0.000389 0.0007832382 + %Qc 10 1 1 6 -0.000190 0.0005481038 + %Qc 10 1 1 7 -0.000095 0.0004200338 + %Qc 10 1 1 8 -0.000049 0.0003401928 + %Qc 10 1 1 9 -0.000026 0.0002849962 + %Qc 10 1 1 10 -0.000014 0.0002438660 + %Qc 10 1 1 20 0.000000 0.0000756167 + %Qc 10 1 1 30 0.000000 0.0000302060 + %Qc 10 1 1 40 0.000000 0.0000140558 + %Qc 10 1 1 50 0.000000 0.0000073414 >EndCooling >EndMC >BeginILDGwrite ildg-write file bqcd.300.lime ildg-write precision 64 ildg-write bytes 147456 - ildg-write cksum 3484010393 - ildg-write lfn bqcd-restart bqcd.300.lime 3484010393 147456 300 2 10 + ildg-write cksum 3360731158 + ildg-write lfn bqcd-restart bqcd.300.lime 3360731158 147456 300 2 10 >EndILDGwrite >BeginFooter - Date 2010-06-11 17:01:50.403 + Date 2011-09-21 14:42:10.352 Seed -1 - CPU-Time 148.8 s on 1 CPUs + CPU-Time 131.3 s on 1 CPUs >BeginTiming Performance region #calls time mean min max Total s Mflop/s Mflop/s Mflop/s Gflop/s - d_xf 493370 7.95 2288.18 2288.18 2288.18 2.29 + d_xf 493290 6.63 2744.03 2744.03 2744.03 2.74 d_xb 0 - d_yf 493370 8.12 2427.55 2427.55 2427.55 2.43 + d_yf 493290 5.72 3442.21 3442.21 3442.21 3.44 d_yb 0 - d_zf 493370 8.33 2365.75 2365.75 2365.75 2.37 + d_zf 493290 5.39 3657.54 3657.54 3657.54 3.66 d_zb 0 - d_t 493370 8.06 2445.64 2445.64 2445.64 2.45 + d_t 493290 5.83 3377.26 3377.26 3377.26 3.38 d_fb 0 d_dag_fb 0 d_xyzt 0 - sc2_projection 493370 6.26 726.30 726.30 726.30 0.73 - D_TOTAL 493370 39.66 2063.72 2063.72 2063.72 2.06 + sc2_projection 493290 6.64 684.97 684.97 684.97 0.68 + D_TOTAL 493290 37.89 2159.68 2159.68 2159.68 2.16 d_dd 0 d_eo 0 - MTDAGMT 105760 52.88 1917.10 1917.10 1917.10 1.92 - CG 2040 42.47 1921.47 1921.47 1921.47 1.92 + MTDAGMT 105740 46.19 2194.25 2194.25 2194.25 2.19 + CG 2040 37.45 2179.05 2179.05 2179.05 2.18 CG_DD 0 CG_HH 0 cg_global_sum 0 - global_sum 0 - global_sum_vec 0 - sc_zero 39910 0.86 - sc_copy 12140 0.09 - sc_scale 9902 0.02 1520.87 1520.87 1520.87 1.52 - sc_norm2 43082 0.28 958.98 958.98 958.98 0.96 - sc_dot 50034 0.26 1182.28 1182.28 1182.28 1.18 - sc_axpy 329830 1.40 1443.27 1443.27 1443.27 1.44 - sc_xpby 325446 1.13 1772.52 1772.52 1772.52 1.77 - sc_axpby 298576 1.16 2371.98 2371.98 2371.98 2.37 - sc_cdotc 29220 0.15 2425.80 2425.80 2425.80 2.43 - sc_caxpy 1940 0.00 +Inf +Inf +Inf +Inf - sc_caxpy2 1940 0.03 1702.64 1702.64 1702.64 1.70 - sc_cax2 1980 0.03 1737.87 1737.87 1737.87 1.74 - clover_init 2436 4.59 - clover_mult_a 20 0.00 +Inf +Inf +Inf +Inf - clover_mult_ao 462970 16.62 1968.09 1968.09 1968.09 1.97 - clover_mult_b 60200 2.36 1799.17 1799.17 1799.17 1.80 - clover_dsd 410 4.45 + global_sum 102051 0.08 + global_sum_vec 167038 0.52 + sc_zero 39914 0.45 + sc_copy 128450 0.17 + sc_scale 9902 0.00 10139.65 10139.65 10139.65 10.14 + sc_norm2 43081 0.04 6458.05 6458.05 6458.05 6.46 + sc_dot 50033 0.04 8309.75 8309.75 8309.75 8.31 + sc_axpy 329780 0.28 7315.56 7315.56 7315.56 7.32 + sc_xpby 325386 0.15 13330.48 13330.48 13330.48 13.33 + sc_axpby 298527 0.36 7643.74 7643.74 7643.74 7.64 + sc_cdotc 29220 0.04 8161.65 8161.65 8161.65 8.16 + sc_caxpy 1940 0.00 5962.66 5962.66 5962.66 5.96 + sc_caxpy2 1940 0.01 3668.62 3668.62 3668.62 3.67 + sc_cax2 1980 0.01 5407.32 5407.32 5407.32 5.41 + clover_init 2436 3.85 + clover_mult_a 20 0.00 1413.12 1413.12 1413.12 1.41 + clover_mult_ao 462890 12.37 2643.52 2643.52 2643.52 2.64 + clover_mult_b 60200 1.96 2172.69 2172.69 2172.69 2.17 + clover_dsd 410 4.04 clover_dsf 0 hmc_init 10 0.03 - hmc_init_p 10 0.02 - hmc_u 6400 6.40 + hmc_init_p 10 0.01 + hmc_u 6400 5.95 hmc_momenta 0 - hmc_phi 10 1.70 - hmc_h_old 10 1.73 + hmc_phi 10 1.35 + hmc_h_old 10 1.38 hmc_backup 10 0.00 hmc_half_step0 0 hmc_half_step1 0 - hmc_xbound_g 10552 0.00 - hmc_steps 8540 135.73 - hmc_h_new 10 0.02 + hmc_xbound_g 10552 0.01 + hmc_steps 8540 119.79 + hmc_h_new 10 0.01 hmc_rest 10 0.00 - HMC 10 143.93 + HMC 10 127.19 h_mult_a 0 h_mult_b 0 h_mult_c 0 - dsg 6410 8.40 - dsf 2020 33.80 - plaquette 22 0.02 914.50 914.50 914.50 0.91 - cooling 10 1.41 - ran_gauss_volh 140 0.06 + dsg 6410 6.73 + dsf 2020 29.74 + plaquette 22 0.01 2090.58 2090.58 2090.58 2.09 + cooling 10 1.15 + ran_gauss_volh 140 0.03 MTDAGMT_r4 0 - dsig 1610 10.50 - rectangle 21 0.03 1867.26 1867.26 1867.26 1.87 + dsig 1610 9.10 + rectangle 21 0.02 2273.94 2273.94 2273.94 2.27 chair 0 parallelogram 0 - stout_smear 1612 4.08 1549.85 1549.85 1549.85 1.55 - stout_diffe 2540 12.68 2317.33 2317.33 2317.33 2.32 - clover_bsa_w 20260 2.53 1883.30 1883.30 1883.30 1.88 - clover_dsd_w 1640 1.46 1166.54 1166.54 1166.54 1.17 - clover_d_w 5900 13.90 2172.26 2172.26 2172.26 2.17 - dsf_at_bt 10130 3.28 1461.00 1461.00 1461.00 1.46 - dsf_xyztfb_w 10130 4.43 2333.09 2333.09 2333.09 2.33 - dsf_sum 10130 13.34 1490.11 1490.11 1490.11 1.49 - dsf_w2gen 2540 26.41 2120.58 2120.58 2120.58 2.12 - cgm 260 10.92 1815.99 1815.99 1815.99 1.82 - cg_ritz 82 4.15 1855.29 1855.29 1855.29 1.86 + stout_smear 1612 3.13 2021.97 2021.97 2021.97 2.02 + stout_diffe 2540 10.62 2765.87 2765.87 2765.87 2.77 + clover_bsa_w 20260 3.03 1572.15 1572.15 1572.15 1.57 + clover_dsd_w 1640 1.27 1346.06 1346.06 1346.06 1.35 + clover_d_w 5900 13.11 2303.44 2303.44 2303.44 2.30 + dsf_at_bt 10130 2.65 1805.33 1805.33 1805.33 1.81 + dsf_xyztfb_w 10130 5.17 1997.52 1997.52 1997.52 2.00 + dsf_sum 10130 14.12 1408.22 1408.22 1408.22 1.41 + dsf_w2gen 2540 23.67 2365.99 2365.99 2365.99 2.37 + cgm 260 9.53 2081.45 2081.45 2081.45 2.08 + cg_ritz 82 3.55 2171.59 2171.59 2171.59 2.17 cg_mix 0 bicgstab 0 bicgstab_mix 0 @@ -857,13 +854,13 @@ unprec_mmul 0 unprec_dsf 0 dsf_un 0 - dsf_mtmp 2020 88.52 - cg_mre_mtmp 2020 44.83 - dsf_wmul_r8 2020 0.48 - dsf_wdag_r8 410 0.18 - integrator 10 142.14 + dsf_mtmp 2020 76.35 + cg_mre_mtmp 2020 39.43 + dsf_wmul_r8 2020 0.43 + dsf_wdag_r8 410 0.10 + integrator 10 125.77 bagel_d 0 - TOTAL 1 148.77 + TOTAL 1 131.32 Performance region #calls time mean min max Total @@ -874,8 +871,8 @@ xbound_sc2 0 u_read_bqcd 0 u_write_bqcd 0 - u_read_ildg 1 0.00 36.86 36.86 36.86 0.04 - u_write_ildg 1 0.00 +Inf +Inf +Inf +Inf + u_read_ildg 1 0.00 49.15 49.15 49.15 0.05 + u_write_ildg 1 0.00 147.46 147.46 147.46 0.15 >EndTiming >EndFooter >EndJob diff --git a/src/data/bqcd.300.output.r259 b/src/data/bqcd.300.output.r259 new file mode 100644 index 0000000000000000000000000000000000000000..a1d40fa08da6d169984dd8c216b79af77ad06af9 --- /dev/null +++ b/src/data/bqcd.300.output.r259 @@ -0,0 +1,881 @@ + >BeginJob + >BeginHeader + Program bqcd 4.0.0 (revision 259) + Version_of_D 100 + Communication single_pe + RandomNumbers ranlux-3.2 level 2 + Run 300 + Job 1 + Host pc58588 + Date 2010-06-11 16:56:02.444 + L 4 4 4 4 + DDL 1 1 1 1 + NPE 1 1 1 1 + process_mapping 1 2 3 4 + bc_fermions 1 1 1 -1 + gamma_index 1 2 3 4 + Gauge Action TREE + Fermi Action SLRC + tilde M 1 - T^-1 D T^-1 D + Gamma notation BQCD + eo-prec DeoDoe + BoundaryCondition normal + Threads 1 + Start 0 + Seed 319503 + Swap_seq 0 + N_force 10 + N_traj 10 + N_save 0 + N_temper 1 + beta_1 5.5 + c0_1 0.0 + c1_1 0.0 + c2_1 0.0 + c3_1 0.0 + u04_1 0.0 + kappa_1 0.121095 + kappa_strange_1 0.120512 + csw_1 2.65 + csw_kappa_1 0.320901750000000 + csw_kappa_strange_1 0.319356800000000 + n_stout_1 1 + alpha_1 0.1 + theta_1 0.0 + h_1 0.0 + rho_1 0.1203 + rho2_1 0.0 + rho3_1 0.0 + rho4_1 0.0 + traj_length_1 1.0 + tau_1 0.200000000000000 + N_tau_1 5 2MNSTS ers + m_scale_1 2 2MNSTS eo2 dat + m_scale2_1 2 2MNSTS eo1 ig + m_scale3_1 2 2MNSTS g + hkappa 1 + mpf_eo[m,l,s]: 2 0 2 + mpf_dd[m,l,s]: 0 0 0 + mpf_hh[m,l,s]: 0 0 0 + fraction_u1 40 + fraction_u2 0 + roughness_level 0 + HMC_model F + REAL_kind 8 + Solver_outer cg + Solver_inner cg + CG_rest 1e-11 + CG_rest_md 1e-9 + CG_stopping_criterion 1 + CG_outer_steps 0 + MRE_vectors 5 + Fullsolver eo + >EndHeader + >BeginForceAcceptance + T%fa i_fa e PlaqEnergy exp(-Delta_H) CGcalls CGitTot CGitMax CGMcalls CGMitTotCGMitMax Plaquette + T%it traj iter_SF iter_F1 iter_F2 iter_F3 iter_F4 iter_F5 iter_F6 iter_F7 iter_F8 iter_F9 + %it -9 260 4665 1469 1042 0 0 0 0 0 0 + %it4 -9 0 0 0 0 0 0 0 0 0 0 + T%Favg traj F_gauge F_impg F_det F_F1 F_F2 F_F3 F_F4 F_F5 F_F6 F_F7 F_F8 F_F9 + T%Fmax traj F_gauge F_impg F_det F_F1 F_F2 F_F3 F_F4 F_F5 F_F6 F_F7 F_F8 F_F9 + T%Frat traj F_gauge F_impg F_det F_F1 F_F2 F_F3 F_F4 F_F5 F_F6 F_F7 F_F8 F_F9 + %Favg -9 7.822 0.666 1.340 2.775 0.067 0.823 0.000 0.000 0.000 0.000 0.000 0.000 + %Fmax -9 14.008 1.247 2.702 7.549 0.193 1.961 0.000 0.000 0.000 0.000 0.000 0.000 + %Frat -9 72.626 6.464 14.006 39.139 1.000 10.165 0.000 0.000 0.000 0.000 0.000 0.000 + T%Hold traj H_total H_generator H_gauge H_det H_fermion_1 H_fermion_2 H_fermion_3 + T%Hnew traj H_total H_generator H_gauge H_det H_fermion_1 H_fermion_2 H_fermion_3 + T%Hdif traj H_total H_generator H_gauge H_det H_fermion_1 H_fermion_2 H_fermion_3 + %Hold -9 0.1175206E+05 0.4065964E+04 0.7585522E+04 -0.6000883E+04 0.1567305E+04 0.1517629E+04 0.3016521E+04 + %Hnew -9 0.1175243E+05 0.5957390E+04 0.5626949E+04 -0.5967133E+04 0.1595594E+04 0.1515925E+04 0.3023703E+04 + %Hdif -9 0.3697911E+00 0.1891426E+04 -0.1958573E+04 0.3375016E+02 0.2828917E+02 -0.1704640E+01 0.7182088E+01 + %fa -9 1 0.7596780818 0.6908786269 203 6179 48 26 1257 61 0.240321918219764 + T%egnv traj type mid min max it_min it_max tol condi n_opt + %egnv -9 1 1 0.80547445E-01 2.2603050 73 41 1e-11 28.062 1.67 + %egnv -9 1 2 0.74060643E-01 2.3117457 74 39 1e-11 31.214 1.72 + %egnv -9 1 3 0.78792963E-01 2.2737198 73 41 1e-11 28.857 1.68 + %it -8 309 5274 1650 1179 0 0 0 0 0 0 + %it4 -8 0 0 0 0 0 0 0 0 0 0 + %Favg -8 8.173 0.726 1.348 2.465 0.067 0.809 0.000 0.000 0.000 0.000 0.000 0.000 + %Fmax -8 14.511 1.353 2.755 6.638 0.189 1.925 0.000 0.000 0.000 0.000 0.000 0.000 + %Frat -8 76.618 7.144 14.547 35.048 1.000 10.166 0.000 0.000 0.000 0.000 0.000 0.000 + %Hold -8 0.9777570E+04 0.4030068E+04 0.5626949E+04 -0.5967133E+04 0.1485841E+04 0.1560926E+04 0.3040919E+04 + %Hnew -8 0.9778114E+04 0.4628898E+04 0.5029892E+04 -0.5984421E+04 0.1505593E+04 0.1560220E+04 0.3037933E+04 + %Hdif -8 0.5445722E+00 0.5988301E+03 -0.5970570E+03 -0.1728829E+02 0.1975166E+02 -0.7061834E+00 -0.2985696E+01 + %fa -8 1 0.6837585510 0.5800898725 203 6982 58 26 1430 65 0.316241448982582 + %egnv -8 1 1 0.71967912E-01 2.1601388 172 64 1e-11 30.015 1.70 + %egnv -8 1 2 0.65996267E-01 2.2033538 176 62 1e-11 33.386 1.75 + %egnv -8 1 3 0.70350902E-01 2.1714299 173 63 1e-11 30.866 1.71 + %it -7 367 6315 1972 1416 0 0 0 0 0 0 + %it4 -7 0 0 0 0 0 0 0 0 0 0 + %Favg -7 8.463 0.775 1.341 2.442 0.071 0.862 0.000 0.000 0.000 0.000 0.000 0.000 + %Fmax -7 15.009 1.430 2.738 6.868 0.236 2.102 0.000 0.000 0.000 0.000 0.000 0.000 + %Frat -7 63.708 6.071 11.622 29.153 1.000 8.920 0.000 0.000 0.000 0.000 0.000 0.000 + %Hold -7 0.9293270E+04 0.4094299E+04 0.5029892E+04 -0.5984421E+04 0.1512332E+04 0.1487833E+04 0.3153335E+04 + %Hnew -7 0.9292577E+04 0.4531932E+04 0.4556032E+04 -0.5956843E+04 0.1510334E+04 0.1488096E+04 0.3163026E+04 + %Hdif -7 -0.6925139E+00 0.4376328E+03 -0.4738597E+03 0.2757784E+02 -0.1997839E+01 0.2632195E+00 0.9691159E+01 + %fa -7 1 0.6247996765 1.9987337431 203 8348 72 26 1722 88 0.375200323526387 + %egnv -7 1 1 0.35981194E-01 2.4918009 109 27 1e-11 69.253 2.12 + %egnv -7 1 2 0.31457047E-01 2.5556502 113 27 1e-11 81.243 2.20 + %egnv -7 1 3 0.34743068E-01 2.5084717 110 27 1e-11 72.201 2.14 + %it -6 415 6439 1996 1435 0 0 0 0 0 0 + %it4 -6 0 0 0 0 0 0 0 0 0 0 + %Favg -6 8.588 0.801 1.341 2.583 0.073 0.848 0.000 0.000 0.000 0.000 0.000 0.000 + %Fmax -6 15.164 1.485 2.883 6.699 0.201 2.233 0.000 0.000 0.000 0.000 0.000 0.000 + %Frat -6 75.365 7.378 14.327 33.291 1.000 11.097 0.000 0.000 0.000 0.000 0.000 0.000 + %Hold -6 0.8871121E+04 0.4101907E+04 0.4556032E+04 -0.5956843E+04 0.1567070E+04 0.1524604E+04 0.3078351E+04 + %Hnew -6 0.8870834E+04 0.4182358E+04 0.4478885E+04 -0.5981559E+04 0.1590364E+04 0.1524322E+04 0.3076463E+04 + %Hdif -6 -0.2872979E+00 0.8045069E+02 -0.7714721E+02 -0.2471533E+02 0.2329443E+02 -0.2821219E+00 -0.1887758E+01 + %fa -6 1 0.6141827704 1.3328212627 203 8518 83 26 1767 89 0.385817229617386 + %egnv -6 1 1 0.44963111E-01 2.2734221 88 50 1e-11 50.562 1.96 + %egnv -6 1 2 0.39975905E-01 2.3294476 90 48 1e-11 58.271 2.03 + %egnv -6 1 3 0.43602824E-01 2.2880091 89 50 1e-11 52.474 1.98 + %it -5 408 6831 2127 1499 0 0 0 0 0 0 + %it4 -5 0 0 0 0 0 0 0 0 0 0 + %Favg -5 8.537 0.810 1.325 2.374 0.073 0.792 0.000 0.000 0.000 0.000 0.000 0.000 + %Fmax -5 15.199 1.518 2.779 5.839 0.240 1.881 0.000 0.000 0.000 0.000 0.000 0.000 + %Frat -5 63.304 6.323 11.576 24.320 1.000 7.834 0.000 0.000 0.000 0.000 0.000 0.000 + %Hold -5 0.8651157E+04 0.4089832E+04 0.4478885E+04 -0.5981559E+04 0.1533584E+04 0.1538412E+04 0.2992002E+04 + %Hnew -5 0.8651211E+04 0.4106159E+04 0.4427728E+04 -0.5966972E+04 0.1552947E+04 0.1538339E+04 0.2993011E+04 + %Hdif -5 0.5466773E-01 0.1632681E+02 -0.5115719E+02 0.1458633E+02 0.1936275E+02 -0.7251007E-01 0.1008478E+01 + %fa -5 1 0.6078148517 0.9467996885 203 9032 74 26 1833 89 0.392185148346159 + %egnv -5 1 1 0.22021276E-01 2.4372806 104 107 1e-11 110.678 2.35 + %egnv -5 1 2 0.18136345E-01 2.5058991 109 102 1e-11 138.170 2.46 + %egnv -5 1 3 0.20945916E-01 2.4551219 105 104 1e-11 117.212 2.38 + %it -4 430 6845 2158 1507 0 0 0 0 0 0 + %it4 -4 0 0 0 0 0 0 0 0 0 0 + %Favg -4 8.590 0.817 1.341 2.382 0.075 0.815 0.000 0.000 0.000 0.000 0.000 0.000 + %Fmax -4 15.030 1.533 2.840 6.062 0.241 1.996 0.000 0.000 0.000 0.000 0.000 0.000 + %Frat -4 62.306 6.354 11.771 25.130 1.000 8.273 0.000 0.000 0.000 0.000 0.000 0.000 + %Hold -4 0.8583368E+04 0.4091101E+04 0.4427728E+04 -0.5966972E+04 0.1500592E+04 0.1498237E+04 0.3032683E+04 + %Hnew -4 0.8583295E+04 0.4195410E+04 0.4340990E+04 -0.5972497E+04 0.1494524E+04 0.1498127E+04 0.3026742E+04 + %Hdif -4 -0.7338697E-01 0.1043087E+03 -0.8673771E+02 -0.5524790E+01 -0.6068144E+01 -0.1098792E+00 -0.5941606E+01 + %fa -4 1 0.5963913539 1.0761468895 203 9087 84 26 1853 89 0.403608646128713 + %egnv -4 1 1 0.30188146E-01 2.1647039 72 43 1e-11 71.707 2.14 + %egnv -4 1 2 0.25911790E-01 2.2091304 74 42 1e-11 85.256 2.22 + %egnv -4 1 3 0.29014812E-01 2.1763156 73 43 1e-11 75.007 2.16 + %it -3 405 6806 2123 1496 0 0 0 0 0 0 + %it4 -3 0 0 0 0 0 0 0 0 0 0 + %Favg -3 8.812 0.851 1.322 2.317 0.076 0.815 0.000 0.000 0.000 0.000 0.000 0.000 + %Fmax -3 15.659 1.548 2.832 6.624 0.240 2.042 0.000 0.000 0.000 0.000 0.000 0.000 + %Frat -3 65.194 6.446 11.792 27.579 1.000 8.503 0.000 0.000 0.000 0.000 0.000 0.000 + %Hold -3 0.8614961E+04 0.4145810E+04 0.4340990E+04 -0.5972497E+04 0.1528241E+04 0.1522367E+04 0.3050051E+04 + %Hnew -3 0.8614829E+04 0.4253580E+04 0.4279266E+04 -0.5991784E+04 0.1500857E+04 0.1521232E+04 0.3051678E+04 + %Hdif -3 -0.1322210E+00 0.1077699E+03 -0.6172370E+02 -0.1928727E+02 -0.2738316E+02 -0.1135419E+01 0.1627457E+01 + %fa -3 1 0.5874912538 1.1413604914 203 9010 81 26 1820 85 0.412508746190435 + %egnv -3 1 1 0.43832510E-01 2.0903463 114 69 1e-11 47.689 1.93 + %egnv -3 1 2 0.39086798E-01 2.1258883 115 68 1e-11 54.389 2.00 + %egnv -3 1 3 0.42539420E-01 2.0996774 114 68 1e-11 49.358 1.95 + %it -2 396 7076 2167 1526 0 0 0 0 0 0 + %it4 -2 0 0 0 0 0 0 0 0 0 0 + %Favg -2 8.913 0.864 1.305 2.441 0.078 0.774 0.000 0.000 0.000 0.000 0.000 0.000 + %Fmax -2 15.503 1.622 2.583 6.663 0.219 1.881 0.000 0.000 0.000 0.000 0.000 0.000 + %Frat -2 70.650 7.390 11.770 30.364 1.000 8.574 0.000 0.000 0.000 0.000 0.000 0.000 + %Hold -2 0.8505403E+04 0.4191183E+04 0.4279266E+04 -0.5991784E+04 0.1438738E+04 0.1538052E+04 0.3049948E+04 + %Hnew -2 0.8505738E+04 0.4375280E+04 0.4115031E+04 -0.5998951E+04 0.1429808E+04 0.1538295E+04 0.3046276E+04 + %Hdif -2 0.3356661E+00 0.1840966E+03 -0.1642358E+03 -0.7166638E+01 -0.8930498E+01 0.2437761E+00 -0.3671725E+01 + %fa -2 1 0.5665928637 0.7148617392 203 9316 73 26 1849 83 0.433407136283996 + %egnv -2 1 1 0.36920645E-01 2.2540469 93 63 1e-11 61.051 2.06 + %egnv -2 1 2 0.32990186E-01 2.3051667 96 61 1e-11 69.874 2.12 + %egnv -2 1 3 0.35843876E-01 2.2674050 93 62 1e-11 63.258 2.07 + %it -1 442 8015 2455 1689 0 0 0 0 0 0 + %it4 -1 0 0 0 0 0 0 0 0 0 0 + %Favg -1 8.930 0.880 1.321 2.692 0.078 0.817 0.000 0.000 0.000 0.000 0.000 0.000 + %Fmax -1 15.259 1.577 2.784 7.084 0.243 1.970 0.000 0.000 0.000 0.000 0.000 0.000 + %Frat -1 62.866 6.495 11.468 29.186 1.000 8.115 0.000 0.000 0.000 0.000 0.000 0.000 + %Hold -1 0.8457890E+04 0.4133751E+04 0.4115031E+04 -0.5998951E+04 0.1543906E+04 0.1550057E+04 0.3114096E+04 + %Hnew -1 0.8458024E+04 0.4133266E+04 0.4063189E+04 -0.5982004E+04 0.1572060E+04 0.1549422E+04 0.3122091E+04 + %Hdif -1 0.1340929E+00 -0.4850769E+00 -0.5184203E+02 0.1694690E+02 0.2815357E+02 -0.6347644E+00 0.7995497E+01 + %fa -1 1 0.5600325226 0.8745088056 203 10549 84 26 2052 99 0.439967477374255 + %egnv -1 1 1 0.20043751E-01 2.6191537 175 22 1e-11 130.672 2.44 + %egnv -1 1 2 0.16816987E-01 2.7011716 181 21 1e-11 160.622 2.54 + %egnv -1 1 3 0.19150390E-01 2.6404756 176 22 1e-11 137.881 2.46 + %it 0 479 8213 2551 1736 0 0 0 0 0 0 + %it4 0 0 0 0 0 0 0 0 0 0 0 + %Favg 0 8.948 0.890 1.310 2.576 0.079 0.785 0.000 0.000 0.000 0.000 0.000 0.000 + %Fmax 0 14.994 1.600 2.652 7.318 0.257 1.987 0.000 0.000 0.000 0.000 0.000 0.000 + %Frat 0 58.398 6.233 10.329 28.504 1.000 7.738 0.000 0.000 0.000 0.000 0.000 0.000 + %Hold 0 0.8333887E+04 0.4060687E+04 0.4063189E+04 -0.5982004E+04 0.1622086E+04 0.1520595E+04 0.3049334E+04 + %Hnew 0 0.8334043E+04 0.4222562E+04 0.3927864E+04 -0.5981657E+04 0.1589964E+04 0.1519281E+04 0.3056029E+04 + %Hdif 0 0.1560966E+00 0.1618753E+03 -0.1353246E+03 0.3474536E+00 -0.3212248E+02 -0.1314227E+01 0.6694721E+01 + %fa 0 1 0.5423191696 0.8554765110 203 10858 94 26 2121 100 0.457680830362908 + %egnv 0 1 1 0.21786046E-01 2.0954561 183 71 1e-11 96.183 2.28 + %egnv 0 1 2 0.18395558E-01 2.1338142 187 70 1e-11 115.996 2.38 + %egnv 0 1 3 0.20849283E-01 2.1055060 184 71 1e-11 100.987 2.31 + >EndForceAcceptance + >BeginILDGwrite + ildg-write file bqcd.300.lime + ildg-write precision 64 + ildg-write bytes 147456 + ildg-write cksum 886460001 + ildg-write lfn bqcd-restart bqcd.300.lime 886460001 147456 300 1 0 + >EndILDGwrite + >BeginFooter + Date 2010-06-11 16:58:33.680 + Seed -1 + CPU-Time 151.2 s on 1 CPUs + >BeginTiming + Performance + region #calls time mean min max Total + s Mflop/s Mflop/s Mflop/s Gflop/s + + d_xf 529058 8.59 2269.78 2269.78 2269.78 2.27 + d_xb 0 + d_yf 529058 8.40 2515.14 2515.14 2515.14 2.52 + d_yb 0 + d_zf 529058 8.76 2411.77 2411.77 2411.77 2.41 + d_zb 0 + d_t 529058 8.97 2354.78 2354.78 2354.78 2.35 + d_fb 0 + d_dag_fb 0 + d_xyzt 0 + sc2_projection 529058 6.93 703.74 703.74 703.74 0.70 + D_TOTAL 529058 42.83 2049.29 2049.29 2049.29 2.05 + d_dd 0 + d_eo 0 + MTDAGMT 114697 57.08 1926.09 1926.09 1926.09 1.93 + CG 2030 46.49 1912.32 1912.32 1912.32 1.91 + CG_DD 0 + CG_HH 0 + cg_global_sum 0 + global_sum 0 + global_sum_vec 0 + sc_zero 39896 0.83 + sc_copy 12140 0.10 + sc_scale 9902 0.03 950.53 950.53 950.53 0.95 + sc_norm2 44608 0.21 1292.72 1292.72 1292.72 1.29 + sc_dot 51190 0.21 1511.96 1511.96 1511.96 1.51 + sc_axpy 360804 1.64 1354.93 1354.93 1354.93 1.35 + sc_xpby 352627 1.27 1703.16 1703.16 1703.16 1.70 + sc_axpby 326804 1.23 2444.50 2444.50 2444.50 2.44 + sc_cdotc 29180 0.17 2134.17 2134.17 2134.17 2.13 + sc_caxpy 1940 0.01 2979.47 2979.47 2979.47 2.98 + sc_caxpy2 1940 0.02 2979.47 2979.47 2979.47 2.98 + sc_cax2 1980 0.01 4055.04 4055.04 4055.04 4.06 + clover_init 2403 4.43 + clover_mult_a 0 + clover_mult_ao 498668 18.03 1954.71 1954.71 1954.71 1.95 + clover_mult_b 60200 2.53 1679.79 1679.79 1679.79 1.68 + clover_dsd 410 4.16 + clover_dsf 0 + hmc_init 10 0.03 + hmc_init_p 10 0.03 + hmc_u 6400 6.58 + hmc_momenta 0 + hmc_phi 10 1.62 + hmc_h_old 10 1.68 + hmc_backup 10 0.00 + hmc_half_step0 0 + hmc_half_step1 0 + hmc_xbound_g 10541 0.01 + hmc_steps 8540 140.02 + hmc_h_new 10 0.01 + hmc_rest 10 0.00 + HMC 10 148.35 + h_mult_a 0 + h_mult_b 0 + h_mult_c 0 + dsg 6410 8.32 + dsf 2020 33.43 + plaquette 21 0.00 +Inf +Inf +Inf +Inf + cooling 0 + ran_gauss_volh 128 0.06 + MTDAGMT_r4 0 + dsig 1610 10.17 + rectangle 20 0.03 1778.41 1778.41 1778.41 1.78 + chair 0 + parallelogram 0 + stout_smear 1601 4.06 1548.38 1548.38 1548.38 1.55 + stout_diffe 2540 12.68 2316.61 2316.61 2316.61 2.32 + clover_bsa_w 20260 2.37 2010.52 2010.52 2010.52 2.01 + clover_dsd_w 1640 1.50 1141.57 1141.57 1141.57 1.14 + clover_d_w 5900 13.74 2198.19 2198.19 2198.19 2.20 + dsf_at_bt 10130 3.25 1473.58 1473.58 1473.58 1.47 + dsf_xyztfb_w 10130 4.56 2263.58 2263.58 2263.58 2.26 + dsf_sum 10130 13.14 1512.78 1512.78 1512.78 1.51 + dsf_w2gen 2540 26.73 2095.20 2095.20 2095.20 2.10 + cgm 260 12.06 1839.82 1839.82 1839.82 1.84 + cg_ritz 82 3.93 1859.83 1859.83 1859.83 1.86 + cg_mix 0 + bicgstab 0 + bicgstab_mix 0 + ddbqnohat 0 + unprec_mmul 0 + unprec_dsf 0 + dsf_un 0 + dsf_mtmp 2020 92.45 + cg_mre_mtmp 2020 49.18 + dsf_wmul_r8 2020 0.52 + dsf_wdag_r8 410 0.15 + integrator 10 146.62 + bagel_d 0 + TOTAL 1 151.23 + + Performance + region #calls time mean min max Total + s MByte/s MByte/s MByte/s GByte/s + + xbound_g 0 + xbound_sc 0 + xbound_sc2 0 + u_read_bqcd 0 + u_write_bqcd 0 + u_read_ildg 0 + u_write_ildg 1 0.00 +Inf +Inf +Inf +Inf + >EndTiming + >EndFooter + >EndJob + >BeginJob + >BeginHeader + Program bqcd 4.0.0 (revision 259) + Version_of_D 100 + Communication single_pe + RandomNumbers ranlux-3.2 level 2 + Run 300 + Job 2 + Host pc58588 + Date 2010-06-11 16:59:21.622 + L 4 4 4 4 + DDL 1 1 1 1 + NPE 1 1 1 1 + process_mapping 1 2 3 4 + bc_fermions 1 1 1 -1 + gamma_index 1 2 3 4 + Gauge Action TREE + Fermi Action SLRC + tilde M 1 - T^-1 D T^-1 D + Gamma notation BQCD + eo-prec DeoDoe + BoundaryCondition normal + Threads 1 + Start 2 + Seed -1 + Swap_seq 0 + N_force 10 + N_traj 10 + N_save 0 + N_temper 1 + beta_1 5.5 + c0_1 0.0 + c1_1 0.0 + c2_1 0.0 + c3_1 0.0 + u04_1 0.0 + kappa_1 0.121095 + kappa_strange_1 0.120512 + csw_1 2.65 + csw_kappa_1 0.320901750000000 + csw_kappa_strange_1 0.319356800000000 + n_stout_1 1 + alpha_1 0.1 + theta_1 0.0 + h_1 0.0 + rho_1 0.1203 + rho2_1 0.0 + rho3_1 0.0 + rho4_1 0.0 + traj_length_1 1.0 + tau_1 0.200000000000000 + N_tau_1 5 2MNSTS ers + m_scale_1 2 2MNSTS eo2 dat + m_scale2_1 2 2MNSTS eo1 ig + m_scale3_1 2 2MNSTS g + hkappa 1 + mpf_eo[m,l,s]: 2 0 2 + mpf_dd[m,l,s]: 0 0 0 + mpf_hh[m,l,s]: 0 0 0 + fraction_u1 40 + fraction_u2 0 + roughness_level 0 + HMC_model F + REAL_kind 8 + Solver_outer cg + Solver_inner cg + CG_rest 1e-11 + CG_rest_md 1e-9 + CG_stopping_criterion 1 + CG_outer_steps 0 + MRE_vectors 5 + Fullsolver eo + >EndHeader + >BeginILDGread + ildg-read file bqcd.300.lime + ildg-read precision 64 + ildg-read bytes 147456 + ildg-read cksum 886460001 + ildg-read lfn bqcd-restart bqcd.300.lime 886460001 147456 300 1 0 + >EndILDGread + >BeginMC + T%mc traj e f PlaqEnergy exp(-Delta_H) Acc CGcalls CGitTot CGitMax CGMcalls CGMitTotCGMitMax Plaquette + T%pr traj Plaquette PlaquetteS PlaquetteT Rectangle RectangleS RectangleT + T%it traj iter_SF iter_F1 iter_F2 iter_F3 iter_F4 iter_F5 iter_F6 iter_F7 iter_F8 iter_F9 + %it 1 466 9160 2766 1827 0 0 0 0 0 0 + %it4 1 0 0 0 0 0 0 0 0 0 0 + T%Favg traj F_gauge F_impg F_det F_F1 F_F2 F_F3 F_F4 F_F5 F_F6 F_F7 F_F8 F_F9 + T%Fmax traj F_gauge F_impg F_det F_F1 F_F2 F_F3 F_F4 F_F5 F_F6 F_F7 F_F8 F_F9 + T%Frat traj F_gauge F_impg F_det F_F1 F_F2 F_F3 F_F4 F_F5 F_F6 F_F7 F_F8 F_F9 + %Favg 1 9.045 0.914 1.310 2.609 0.074 0.780 0.000 0.000 0.000 0.000 0.000 0.000 + %Fmax 1 15.598 1.700 2.656 7.611 0.211 1.853 0.000 0.000 0.000 0.000 0.000 0.000 + %Frat 1 73.953 8.060 12.594 36.086 1.000 8.788 0.000 0.000 0.000 0.000 0.000 0.000 + T%Hold traj H_total H_generator H_gauge H_det H_fermion_1 H_fermion_2 H_fermion_3 + T%Hnew traj H_total H_generator H_gauge H_det H_fermion_1 H_fermion_2 H_fermion_3 + T%Hdif traj H_total H_generator H_gauge H_det H_fermion_1 H_fermion_2 H_fermion_3 + %Hold 1 0.8059372E+04 0.3981543E+04 0.3927864E+04 -0.5981657E+04 0.1572569E+04 0.1491144E+04 0.3067908E+04 + %Hnew 1 0.8059149E+04 0.4134470E+04 0.3802579E+04 -0.5991136E+04 0.1561179E+04 0.1491647E+04 0.3060409E+04 + %Hdif 1 -0.2222102E+00 0.1529275E+03 -0.1252850E+03 -0.9479002E+01 -0.1138985E+02 0.5033574E+00 -0.7499230E+01 + %mc 1 1 1 0.5256287819 1.2488337936 1 203 12014 88 26 2205 96 0.474371218105791 + %pr 1 0.4743712181058 0.4726444579752 0.4760979782364 0.2448709195136 0.2412306449670 0.2485111940602 + T%egnv traj type mid min max it_min it_max tol condi n_opt + %egnv 1 1 1 0.11201689E-01 2.1239394 92 55 1e-11 189.609 2.62 + %egnv 1 1 2 0.88566368E-02 2.1649865 94 54 1e-11 244.448 2.75 + %egnv 1 1 3 0.10542698E-01 2.1346871 92 55 1e-11 202.480 2.66 + T%tr traj e f Re(pbp) Im(pbp) Re(p5p) -Im(p5p) PionNorm CGiter + %tr 1 1 1 1.096700490 -0.1407549329E-01 0.2229626393E-01 -0.7190087646E-12 2.751909090 98 + T%pl traj e f Re(Polyakov_Loop) Im(Polyakov_Loop) + %pl 1 1 1 -0.2789723339E-01 0.5139161873E-01 + >BeginCooling + T%Qc traj e f i_cool Q_cool PlaqEnergy + %Qc 1 1 1 0 0.048126 0.5256287819 + %Qc 1 1 1 1 0.020771 0.1313428205 + %Qc 1 1 1 2 0.182281 0.0511502439 + %Qc 1 1 1 3 0.219577 0.0309807565 + %Qc 1 1 1 4 0.142080 0.0218651570 + %Qc 1 1 1 5 0.052773 0.0161620071 + %Qc 1 1 1 6 0.009561 0.0114304799 + %Qc 1 1 1 7 0.002320 0.0075411392 + %Qc 1 1 1 8 0.001251 0.0046428300 + %Qc 1 1 1 9 0.000558 0.0026599216 + %Qc 1 1 1 10 0.000203 0.0014373723 + %Qc 1 1 1 20 0.000000 0.0000057767 + %Qc 1 1 1 30 -0.000000 0.0000001381 + %Qc 1 1 1 40 0.000000 0.0000000048 + %Qc 1 1 1 50 0.000000 0.0000000002 + >EndCooling + %it 2 455 7725 2355 1642 0 0 0 0 0 0 + %it4 2 0 0 0 0 0 0 0 0 0 0 + %Favg 2 9.177 0.940 1.294 2.393 0.063 0.763 0.000 0.000 0.000 0.000 0.000 0.000 + %Fmax 2 15.786 1.705 2.628 6.960 0.203 2.201 0.000 0.000 0.000 0.000 0.000 0.000 + %Frat 2 77.904 8.415 12.971 34.348 1.000 10.863 0.000 0.000 0.000 0.000 0.000 0.000 + %Hold 2 0.8090140E+04 0.4136443E+04 0.3802579E+04 -0.5991136E+04 0.1557003E+04 0.1537098E+04 0.3048153E+04 + %Hnew 2 0.8089947E+04 0.4104749E+04 0.3861978E+04 -0.5997383E+04 0.1531613E+04 0.1537314E+04 0.3051676E+04 + %Hdif 2 -0.1930398E+00 -0.3169372E+02 0.5939898E+02 -0.6247830E+01 -0.2538992E+02 0.2159010E+00 0.3523546E+01 + %mc 2 1 1 0.5329972801 1.2129310686 1 203 10172 92 26 2005 98 0.467002719935582 + %pr 2 0.4670027199356 0.4683780993849 0.4656273404862 0.2414972288243 0.2417406808935 0.2412537767551 + %egnv 2 1 1 0.22479273E-01 2.2750864 88 38 1e-11 101.208 2.31 + %egnv 2 1 2 0.19130153E-01 2.3261450 89 37 1e-11 121.596 2.40 + %egnv 2 1 3 0.21554334E-01 2.2884333 88 38 1e-11 106.170 2.33 + %tr 2 1 1 1.057820167 -0.6021855563E-02 0.1866932235E-01 0.2982776063E-12 2.375531424 83 + T%pl traj e f Re(Polyakov_Loop) Im(Polyakov_Loop) + %pl 2 1 1 -0.1273482066E-01 -0.2853310257E-02 + >BeginCooling + T%Qc traj e f i_cool Q_cool PlaqEnergy + %Qc 2 1 1 0 -0.009762 0.5329972801 + %Qc 2 1 1 1 -0.005589 0.1193819388 + %Qc 2 1 1 2 0.280278 0.0339020463 + %Qc 2 1 1 3 0.458564 0.0186745744 + %Qc 2 1 1 4 0.515329 0.0133907635 + %Qc 2 1 1 5 0.494449 0.0106876369 + %Qc 2 1 1 6 0.412660 0.0089590302 + %Qc 2 1 1 7 0.243721 0.0071402566 + %Qc 2 1 1 8 0.051628 0.0041254140 + %Qc 2 1 1 9 0.004785 0.0017870795 + %Qc 2 1 1 10 0.000654 0.0008693693 + %Qc 2 1 1 20 -0.000000 0.0000149504 + %Qc 2 1 1 30 -0.000000 0.0000007825 + %Qc 2 1 1 40 -0.000000 0.0000000488 + %Qc 2 1 1 50 -0.000000 0.0000000034 + >EndCooling + %it 3 402 7600 2291 1560 0 0 0 0 0 0 + %it4 3 0 0 0 0 0 0 0 0 0 0 + %Favg 3 9.316 0.968 1.278 2.307 0.059 0.758 0.000 0.000 0.000 0.000 0.000 0.000 + %Fmax 3 15.815 1.684 2.594 6.295 0.182 1.919 0.000 0.000 0.000 0.000 0.000 0.000 + %Frat 3 86.712 9.230 14.222 34.514 1.000 10.520 0.000 0.000 0.000 0.000 0.000 0.000 + %Hold 3 0.8167467E+04 0.4128298E+04 0.3861978E+04 -0.5997383E+04 0.1564709E+04 0.1498362E+04 0.3111503E+04 + %Hnew 3 0.8167623E+04 0.4163487E+04 0.3834727E+04 -0.6003886E+04 0.1563891E+04 0.1498577E+04 0.3110827E+04 + %Hdif 3 0.1561674E+00 0.3518970E+02 -0.2725048E+02 -0.6502840E+01 -0.8185873E+00 0.2147341E+00 -0.6763635E+00 + %mc 3 1 1 0.5292769819 0.8554159753 1 203 9971 80 26 1882 84 0.470723018098662 + %pr 3 0.4707230180987 0.4681862080567 0.4732598281407 0.2464434901217 0.2415090083184 0.2513779719250 + %egnv 3 1 1 0.30015044E-01 2.1062975 104 54 1e-11 70.175 2.13 + %egnv 3 1 2 0.26192101E-01 2.1456848 105 54 1e-11 81.921 2.20 + %egnv 3 1 3 0.28967864E-01 2.1166148 105 54 1e-11 73.068 2.15 + %tr 3 1 1 1.021762823 -0.2042151733E-01 -0.4749031798E-01 0.4647902433E-14 2.277549541 77 + T%pl traj e f Re(Polyakov_Loop) Im(Polyakov_Loop) + %pl 3 1 1 0.1773357402E-02 -0.6020302397E-02 + >BeginCooling + T%Qc traj e f i_cool Q_cool PlaqEnergy + %Qc 3 1 1 0 0.082096 0.5292769819 + %Qc 3 1 1 1 0.130736 0.1094908249 + %Qc 3 1 1 2 0.348311 0.0290075332 + %Qc 3 1 1 3 0.482537 0.0148645258 + %Qc 3 1 1 4 0.532008 0.0109541619 + %Qc 3 1 1 5 0.531717 0.0093610450 + %Qc 3 1 1 6 0.496172 0.0084716148 + %Qc 3 1 1 7 0.418683 0.0077233870 + %Qc 3 1 1 8 0.256949 0.0064885255 + %Qc 3 1 1 9 0.051149 0.0036024180 + %Qc 3 1 1 10 0.004666 0.0014501003 + %Qc 3 1 1 20 -0.000001 0.0000733980 + %Qc 3 1 1 30 -0.000000 0.0000200829 + %Qc 3 1 1 40 -0.000000 0.0000066622 + %Qc 3 1 1 50 -0.000000 0.0000023273 + >EndCooling + %it 4 359 6627 2011 1413 0 0 0 0 0 0 + %it4 4 0 0 0 0 0 0 0 0 0 0 + %Favg 4 9.366 0.992 1.286 2.203 0.068 0.750 0.000 0.000 0.000 0.000 0.000 0.000 + %Fmax 4 15.430 1.680 2.590 5.796 0.235 1.829 0.000 0.000 0.000 0.000 0.000 0.000 + %Frat 4 65.672 7.152 11.026 24.668 1.000 7.786 0.000 0.000 0.000 0.000 0.000 0.000 + %Hold 4 0.8032018E+04 0.4044664E+04 0.3834727E+04 -0.6003886E+04 0.1492007E+04 0.1535946E+04 0.3128561E+04 + %Hnew 4 0.8031830E+04 0.4209353E+04 0.3696939E+04 -0.6021735E+04 0.1497246E+04 0.1535235E+04 0.3114790E+04 + %Hdif 4 -0.1882389E+00 0.1646888E+03 -0.1377879E+03 -0.1784827E+02 0.5239810E+01 -0.7103588E+00 -0.1377034E+02 + %mc 4 1 1 0.5098751753 1.2071218126 1 203 8712 74 26 1698 77 0.490124824737818 + %pr 4 0.4901248247378 0.4871551218511 0.4930945276245 0.2773603205663 0.2734506483273 0.2812699928054 + %egnv 4 1 1 0.65502609E-01 2.0458115 171 64 1e-11 31.233 1.72 + %egnv 4 1 2 0.61459935E-01 2.0819227 136 63 1e-11 33.874 1.76 + %egnv 4 1 3 0.64416896E-01 2.0552798 169 64 1e-11 31.906 1.73 + %tr 4 1 1 1.007907845 -0.7601643054E-02 0.2443747534E-01 0.1701113209E-12 2.040834341 63 + T%pl traj e f Re(Polyakov_Loop) Im(Polyakov_Loop) + %pl 4 1 1 0.7951725245E-01 0.5623780163E-01 + >BeginCooling + T%Qc traj e f i_cool Q_cool PlaqEnergy + %Qc 4 1 1 0 0.045646 0.5098751753 + %Qc 4 1 1 1 -0.029235 0.0931408422 + %Qc 4 1 1 2 0.001388 0.0184513185 + %Qc 4 1 1 3 0.003494 0.0052928934 + %Qc 4 1 1 4 0.001061 0.0023353861 + %Qc 4 1 1 5 0.000387 0.0012942043 + %Qc 4 1 1 6 0.000180 0.0008218519 + %Qc 4 1 1 7 0.000100 0.0005731850 + %Qc 4 1 1 8 0.000059 0.0004276599 + %Qc 4 1 1 9 0.000037 0.0003349832 + %Qc 4 1 1 10 0.000023 0.0002717444 + %Qc 4 1 1 20 -0.000000 0.0000711819 + %Qc 4 1 1 30 -0.000000 0.0000293477 + %Qc 4 1 1 40 -0.000000 0.0000144832 + %Qc 4 1 1 50 -0.000000 0.0000078682 + >EndCooling + %it 5 314 5524 1698 1202 0 0 0 0 0 0 + %it4 5 0 0 0 0 0 0 0 0 0 0 + %Favg 5 9.482 1.018 1.283 2.051 0.066 0.702 0.000 0.000 0.000 0.000 0.000 0.000 + %Fmax 5 15.906 1.765 2.497 5.144 0.220 1.751 0.000 0.000 0.000 0.000 0.000 0.000 + %Frat 5 72.376 8.032 11.363 23.406 1.000 7.968 0.000 0.000 0.000 0.000 0.000 0.000 + %Hold 5 0.7907837E+04 0.4124302E+04 0.3696939E+04 -0.6021735E+04 0.1493893E+04 0.1589574E+04 0.3024863E+04 + %Hnew 5 0.7907717E+04 0.4170782E+04 0.3640564E+04 -0.6017343E+04 0.1500153E+04 0.1589358E+04 0.3024205E+04 + %Hdif 5 -0.1194158E+00 0.4647944E+02 -0.5637588E+02 0.4391044E+01 0.6260341E+01 -0.2158011E+00 -0.6585559E+00 + %mc 5 1 1 0.5031014784 1.1268383552 1 203 7284 62 26 1454 65 0.496898521559694 + %pr 5 0.4968985215597 0.4932022938734 0.5005947492460 0.2783644727806 0.2752902984062 0.2814386471549 + %egnv 5 1 1 0.55985783E-01 2.1002743 57 79 1e-11 37.514 1.81 + %egnv 5 1 2 0.52921759E-01 2.1423924 58 75 1e-11 40.482 1.85 + %egnv 5 1 3 0.55143429E-01 2.1112897 58 78 1e-11 38.287 1.82 + %tr 5 1 1 1.001996987 0.3439318868E-01 0.8709399251E-02 0.2187463174E-12 2.079031150 59 + T%pl traj e f Re(Polyakov_Loop) Im(Polyakov_Loop) + %pl 5 1 1 0.1138802121 0.4482838698E-02 + >BeginCooling + T%Qc traj e f i_cool Q_cool PlaqEnergy + %Qc 5 1 1 0 0.027003 0.5031014784 + %Qc 5 1 1 1 -0.080645 0.0867700263 + %Qc 5 1 1 2 -0.054680 0.0171108504 + %Qc 5 1 1 3 -0.007190 0.0055779860 + %Qc 5 1 1 4 -0.001143 0.0023577164 + %Qc 5 1 1 5 -0.000409 0.0012326226 + %Qc 5 1 1 6 -0.000174 0.0007421948 + %Qc 5 1 1 7 -0.000077 0.0004950696 + %Qc 5 1 1 8 -0.000036 0.0003559673 + %Qc 5 1 1 9 -0.000018 0.0002700183 + %Qc 5 1 1 10 -0.000010 0.0002125880 + %Qc 5 1 1 20 -0.000001 0.0000387951 + %Qc 5 1 1 30 -0.000000 0.0000102065 + %Qc 5 1 1 40 -0.000000 0.0000032597 + %Qc 5 1 1 50 -0.000000 0.0000011935 + >EndCooling + %it 6 284 4843 1476 1074 0 0 0 0 0 0 + %it4 6 0 0 0 0 0 0 0 0 0 0 + %Favg 6 9.655 1.064 1.253 2.035 0.053 0.680 0.000 0.000 0.000 0.000 0.000 0.000 + %Fmax 6 16.137 1.794 2.508 5.690 0.163 1.586 0.000 0.000 0.000 0.000 0.000 0.000 + %Frat 6 99.208 11.027 15.421 34.982 1.000 9.750 0.000 0.000 0.000 0.000 0.000 0.000 + %Hold 6 0.7711427E+04 0.4021976E+04 0.3640564E+04 -0.6017343E+04 0.1557628E+04 0.1489029E+04 0.3019573E+04 + %Hnew 6 0.7711868E+04 0.4145540E+04 0.3545618E+04 -0.6029318E+04 0.1542523E+04 0.1489057E+04 0.3018447E+04 + %Hdif 6 0.4417190E+00 0.1235644E+03 -0.9494551E+02 -0.1197408E+02 -0.1510536E+02 0.2809388E-01 -0.1125836E+01 + %mc 6 1 1 0.5031014784 0.6429302791 0 203 6377 58 26 1300 61 0.496898521559694 + %pr 6 0.4968985215597 0.4932022938734 0.5005947492460 0.2783644727806 0.2752902984062 0.2814386471549 + %egnv 6 1 1 0.55985783E-01 2.1002743 57 79 1e-11 37.514 1.81 + %egnv 6 1 2 0.52921759E-01 2.1423924 58 75 1e-11 40.482 1.85 + %egnv 6 1 3 0.55143429E-01 2.1112897 58 78 1e-11 38.287 1.82 + %tr 6 1 1 1.021818852 -0.8049552490E-02 0.1859040886E-01 0.2879403891E-12 2.002771437 60 + T%pl traj e f Re(Polyakov_Loop) Im(Polyakov_Loop) + %pl 6 1 1 0.1138802121 0.4482838698E-02 + >BeginCooling + T%Qc traj e f i_cool Q_cool PlaqEnergy + %Qc 6 1 1 0 0.027003 0.5031014784 + %Qc 6 1 1 1 -0.080645 0.0867700263 + %Qc 6 1 1 2 -0.054680 0.0171108504 + %Qc 6 1 1 3 -0.007190 0.0055779860 + %Qc 6 1 1 4 -0.001143 0.0023577164 + %Qc 6 1 1 5 -0.000409 0.0012326226 + %Qc 6 1 1 6 -0.000174 0.0007421948 + %Qc 6 1 1 7 -0.000077 0.0004950696 + %Qc 6 1 1 8 -0.000036 0.0003559673 + %Qc 6 1 1 9 -0.000018 0.0002700183 + %Qc 6 1 1 10 -0.000010 0.0002125880 + %Qc 6 1 1 20 -0.000001 0.0000387951 + %Qc 6 1 1 30 -0.000000 0.0000102065 + %Qc 6 1 1 40 -0.000000 0.0000032597 + %Qc 6 1 1 50 -0.000000 0.0000011935 + >EndCooling + %it 7 307 5336 1618 1164 0 0 0 0 0 0 + %it4 7 0 0 0 0 0 0 0 0 0 0 + %Favg 7 9.477 1.033 1.265 2.097 0.056 0.707 0.000 0.000 0.000 0.000 0.000 0.000 + %Fmax 7 15.923 1.808 2.602 5.365 0.152 1.725 0.000 0.000 0.000 0.000 0.000 0.000 + %Frat 7 104.582 11.874 17.091 35.238 1.000 11.327 0.000 0.000 0.000 0.000 0.000 0.000 + %Hold 7 0.8015286E+04 0.4099800E+04 0.3640564E+04 -0.6017343E+04 0.1590498E+04 0.1568021E+04 0.3133748E+04 + %Hnew 7 0.8015235E+04 0.4183155E+04 0.3571096E+04 -0.6012626E+04 0.1584634E+04 0.1567366E+04 0.3121610E+04 + %Hdif 7 -0.5113948E-01 0.8335553E+02 -0.6946721E+02 0.4717735E+01 -0.5864061E+01 -0.6556146E+00 -0.1213753E+02 + %mc 7 1 1 0.4940644414 1.0524696860 1 203 7012 58 26 1413 64 0.505935558570389 + %pr 7 0.5059355585704 0.5058614794300 0.5060096377108 0.2865056687715 0.2908622534745 0.2821490840686 + %egnv 7 1 1 0.54562660E-01 2.1441410 139 46 1e-11 39.297 1.84 + %egnv 7 1 2 0.50838984E-01 2.1892239 135 45 1e-11 43.062 1.88 + %egnv 7 1 3 0.53545687E-01 2.1559265 137 46 1e-11 40.263 1.85 + %tr 7 1 1 1.038466593 0.1605924825E-01 0.3407742008E-01 0.4800454016E-12 2.153321764 63 + T%pl traj e f Re(Polyakov_Loop) Im(Polyakov_Loop) + %pl 7 1 1 0.1059552749 0.4013742461E-01 + >BeginCooling + T%Qc traj e f i_cool Q_cool PlaqEnergy + %Qc 7 1 1 0 0.039829 0.4940644414 + %Qc 7 1 1 1 -0.077202 0.0875074447 + %Qc 7 1 1 2 -0.009690 0.0174920790 + %Qc 7 1 1 3 0.001651 0.0054441039 + %Qc 7 1 1 4 0.000961 0.0023981248 + %Qc 7 1 1 5 0.000521 0.0013220648 + %Qc 7 1 1 6 0.000299 0.0008278102 + %Qc 7 1 1 7 0.000182 0.0005630218 + %Qc 7 1 1 8 0.000117 0.0004060663 + %Qc 7 1 1 9 0.000078 0.0003059132 + %Qc 7 1 1 10 0.000054 0.0002381615 + %Qc 7 1 1 20 0.000002 0.0000411097 + %Qc 7 1 1 30 0.000000 0.0000101558 + %Qc 7 1 1 40 0.000000 0.0000026919 + %Qc 7 1 1 50 0.000000 0.0000007363 + >EndCooling + %it 8 302 4696 1431 1063 0 0 0 0 0 0 + %it4 8 0 0 0 0 0 0 0 0 0 0 + %Favg 8 9.507 1.048 1.262 2.120 0.049 0.691 0.000 0.000 0.000 0.000 0.000 0.000 + %Fmax 8 15.685 1.748 2.664 5.060 0.139 1.547 0.000 0.000 0.000 0.000 0.000 0.000 + %Frat 8 112.648 12.552 19.131 36.341 1.000 11.110 0.000 0.000 0.000 0.000 0.000 0.000 + %Hold 8 0.7775594E+04 0.4076839E+04 0.3571096E+04 -0.6012626E+04 0.1539474E+04 0.1536608E+04 0.3064202E+04 + %Hnew 8 0.7775299E+04 0.4189634E+04 0.3454245E+04 -0.6021089E+04 0.1552887E+04 0.1535884E+04 0.3063738E+04 + %Hdif 8 -0.2944022E+00 0.1127952E+03 -0.1168511E+03 -0.8463289E+01 0.1341280E+02 -0.7246042E+00 -0.4634163E+00 + %mc 8 1 1 0.4784649756 1.3423236869 1 203 6187 60 26 1305 64 0.521535024389628 + %pr 8 0.5215350243896 0.5201126083548 0.5229574404244 0.3041822322966 0.3066437871460 0.3017206774472 + %egnv 8 1 1 0.89804417E-01 2.1318832 402 49 1e-11 23.739 1.58 + %egnv 8 1 2 0.87969935E-01 2.1776359 458 47 1e-11 24.754 1.60 + %egnv 8 1 3 0.89284234E-01 2.1438379 410 49 1e-11 24.011 1.59 + %tr 8 1 1 1.005232580 -0.1776836719E-01 0.1515187603E-01 0.9981830177E-13 1.925465958 56 + T%pl traj e f Re(Polyakov_Loop) Im(Polyakov_Loop) + %pl 8 1 1 0.2075269581 -0.2875034199E-02 + >BeginCooling + T%Qc traj e f i_cool Q_cool PlaqEnergy + %Qc 8 1 1 0 0.002028 0.4784649756 + %Qc 8 1 1 1 0.015649 0.0739165664 + %Qc 8 1 1 2 -0.000337 0.0117042590 + %Qc 8 1 1 3 0.001183 0.0041610990 + %Qc 8 1 1 4 0.000999 0.0021419626 + %Qc 8 1 1 5 0.000624 0.0012944200 + %Qc 8 1 1 6 0.000384 0.0008672893 + %Qc 8 1 1 7 0.000246 0.0006281566 + %Qc 8 1 1 8 0.000165 0.0004827686 + %Qc 8 1 1 9 0.000115 0.0003880828 + %Qc 8 1 1 10 0.000083 0.0003226650 + %Qc 8 1 1 20 0.000006 0.0001077947 + %Qc 8 1 1 30 0.000000 0.0000541516 + %Qc 8 1 1 40 -0.000000 0.0000309701 + %Qc 8 1 1 50 -0.000000 0.0000189534 + >EndCooling + %it 9 278 4611 1400 1029 0 0 0 0 0 0 + %it4 9 0 0 0 0 0 0 0 0 0 0 + %Favg 9 9.639 1.071 1.268 1.943 0.053 0.713 0.000 0.000 0.000 0.000 0.000 0.000 + %Fmax 9 15.785 1.806 2.600 4.739 0.143 1.810 0.000 0.000 0.000 0.000 0.000 0.000 + %Frat 9 110.570 12.650 18.212 33.199 1.000 12.678 0.000 0.000 0.000 0.000 0.000 0.000 + %Hold 9 0.7850211E+04 0.4133535E+04 0.3454245E+04 -0.6021089E+04 0.1494688E+04 0.1594648E+04 0.3194184E+04 + %Hnew 9 0.7850568E+04 0.4138992E+04 0.3457535E+04 -0.6034924E+04 0.1511286E+04 0.1595209E+04 0.3182469E+04 + %Hdif 9 0.3565416E+00 0.5456571E+01 0.3289833E+01 -0.1383473E+02 0.1659775E+02 0.5614769E+00 -0.1171437E+02 + %mc 9 1 1 0.4783439102 0.7000933530 1 203 6066 55 26 1252 58 0.521656089758662 + %pr 9 0.5216560897587 0.5175579692613 0.5257542102560 0.3092871013305 0.2946128306597 0.3239613720014 + %egnv 9 1 1 0.79339562E-01 2.1200901 60 38 1e-11 26.722 1.64 + %egnv 9 1 2 0.76287012E-01 2.1642184 61 37 1e-11 28.369 1.67 + %egnv 9 1 3 0.78499302E-01 2.1316285 60 38 1e-11 27.155 1.65 + %tr 9 1 1 1.017316061 0.1019396879E-01 -0.3873125184E-02 0.3965323440E-12 1.988905552 53 + T%pl traj e f Re(Polyakov_Loop) Im(Polyakov_Loop) + %pl 9 1 1 0.2796975100 0.7808683790E-02 + >BeginCooling + T%Qc traj e f i_cool Q_cool PlaqEnergy + %Qc 9 1 1 0 0.015460 0.4783439102 + %Qc 9 1 1 1 -0.031638 0.0709671563 + %Qc 9 1 1 2 -0.004020 0.0099617757 + %Qc 9 1 1 3 -0.000717 0.0031588151 + %Qc 9 1 1 4 -0.000133 0.0014990532 + %Qc 9 1 1 5 -0.000030 0.0008893425 + %Qc 9 1 1 6 -0.000018 0.0006135112 + %Qc 9 1 1 7 -0.000020 0.0004674604 + %Qc 9 1 1 8 -0.000021 0.0003788013 + %Qc 9 1 1 9 -0.000021 0.0003186521 + %Qc 9 1 1 10 -0.000019 0.0002743553 + %Qc 9 1 1 20 -0.000005 0.0000937959 + %Qc 9 1 1 30 -0.000001 0.0000408909 + %Qc 9 1 1 40 -0.000000 0.0000197091 + %Qc 9 1 1 50 -0.000000 0.0000101358 + >EndCooling + %it 10 268 4598 1388 1018 0 0 0 0 0 0 + %it4 10 0 0 0 0 0 0 0 0 0 0 + %Favg 10 9.724 1.094 1.257 2.038 0.051 0.670 0.000 0.000 0.000 0.000 0.000 0.000 + %Fmax 10 15.974 1.861 2.511 5.364 0.151 1.614 0.000 0.000 0.000 0.000 0.000 0.000 + %Frat 10 105.778 12.326 16.627 35.521 1.000 10.690 0.000 0.000 0.000 0.000 0.000 0.000 + %Hold 10 0.7651666E+04 0.4096361E+04 0.3457535E+04 -0.6034924E+04 0.1594950E+04 0.1543888E+04 0.2993857E+04 + %Hnew 10 0.7651844E+04 0.4112810E+04 0.3453801E+04 -0.6026672E+04 0.1576267E+04 0.1544064E+04 0.2991575E+04 + %Hdif 10 0.1781014E+00 0.1644903E+02 -0.3733711E+01 0.8252019E+01 -0.1868320E+02 0.1756377E+00 -0.2281678E+01 + %mc 10 1 1 0.4782961713 0.8368575590 1 203 6038 52 26 1234 54 0.521703828699875 + %pr 10 0.5217038286999 0.5220441959034 0.5213634614963 0.3053448518001 0.3028146382562 0.3078750653441 + %egnv 10 1 1 0.86328110E-01 2.0804812 68 49 1e-11 24.100 1.59 + %egnv 10 1 2 0.84184902E-01 2.1219390 69 48 1e-11 25.206 1.61 + %egnv 10 1 3 0.85726953E-01 2.0913289 68 48 1e-11 24.395 1.60 + %tr 10 1 1 1.022055159 0.5521503278E-02 -0.2998286013E-01 0.8873341876E-13 2.027423632 53 + T%pl traj e f Re(Polyakov_Loop) Im(Polyakov_Loop) + %pl 10 1 1 0.1284477377 0.6387078416E-02 + >BeginCooling + T%Qc traj e f i_cool Q_cool PlaqEnergy + %Qc 10 1 1 0 -0.116389 0.4782961713 + %Qc 10 1 1 1 -0.007454 0.0669723197 + %Qc 10 1 1 2 -0.003763 0.0090384656 + %Qc 10 1 1 3 -0.001751 0.0027058642 + %Qc 10 1 1 4 -0.000821 0.0012937578 + %Qc 10 1 1 5 -0.000389 0.0007832207 + %Qc 10 1 1 6 -0.000190 0.0005480911 + %Qc 10 1 1 7 -0.000095 0.0004200246 + %Qc 10 1 1 8 -0.000049 0.0003401863 + %Qc 10 1 1 9 -0.000026 0.0002849915 + %Qc 10 1 1 10 -0.000014 0.0002438627 + %Qc 10 1 1 20 0.000000 0.0000756183 + %Qc 10 1 1 30 0.000000 0.0000302082 + %Qc 10 1 1 40 0.000000 0.0000140579 + %Qc 10 1 1 50 0.000000 0.0000073432 + >EndCooling + >EndMC + >BeginILDGwrite + ildg-write file bqcd.300.lime + ildg-write precision 64 + ildg-write bytes 147456 + ildg-write cksum 3484010393 + ildg-write lfn bqcd-restart bqcd.300.lime 3484010393 147456 300 2 10 + >EndILDGwrite + >BeginFooter + Date 2010-06-11 17:01:50.403 + Seed -1 + CPU-Time 148.8 s on 1 CPUs + >BeginTiming + Performance + region #calls time mean min max Total + s Mflop/s Mflop/s Mflop/s Gflop/s + + d_xf 493370 7.95 2288.18 2288.18 2288.18 2.29 + d_xb 0 + d_yf 493370 8.12 2427.55 2427.55 2427.55 2.43 + d_yb 0 + d_zf 493370 8.33 2365.75 2365.75 2365.75 2.37 + d_zb 0 + d_t 493370 8.06 2445.64 2445.64 2445.64 2.45 + d_fb 0 + d_dag_fb 0 + d_xyzt 0 + sc2_projection 493370 6.26 726.30 726.30 726.30 0.73 + D_TOTAL 493370 39.66 2063.72 2063.72 2063.72 2.06 + d_dd 0 + d_eo 0 + MTDAGMT 105760 52.88 1917.10 1917.10 1917.10 1.92 + CG 2040 42.47 1921.47 1921.47 1921.47 1.92 + CG_DD 0 + CG_HH 0 + cg_global_sum 0 + global_sum 0 + global_sum_vec 0 + sc_zero 39910 0.86 + sc_copy 12140 0.09 + sc_scale 9902 0.02 1520.87 1520.87 1520.87 1.52 + sc_norm2 43082 0.28 958.98 958.98 958.98 0.96 + sc_dot 50034 0.26 1182.28 1182.28 1182.28 1.18 + sc_axpy 329830 1.40 1443.27 1443.27 1443.27 1.44 + sc_xpby 325446 1.13 1772.52 1772.52 1772.52 1.77 + sc_axpby 298576 1.16 2371.98 2371.98 2371.98 2.37 + sc_cdotc 29220 0.15 2425.80 2425.80 2425.80 2.43 + sc_caxpy 1940 0.00 +Inf +Inf +Inf +Inf + sc_caxpy2 1940 0.03 1702.64 1702.64 1702.64 1.70 + sc_cax2 1980 0.03 1737.87 1737.87 1737.87 1.74 + clover_init 2436 4.59 + clover_mult_a 20 0.00 +Inf +Inf +Inf +Inf + clover_mult_ao 462970 16.62 1968.09 1968.09 1968.09 1.97 + clover_mult_b 60200 2.36 1799.17 1799.17 1799.17 1.80 + clover_dsd 410 4.45 + clover_dsf 0 + hmc_init 10 0.03 + hmc_init_p 10 0.02 + hmc_u 6400 6.40 + hmc_momenta 0 + hmc_phi 10 1.70 + hmc_h_old 10 1.73 + hmc_backup 10 0.00 + hmc_half_step0 0 + hmc_half_step1 0 + hmc_xbound_g 10552 0.00 + hmc_steps 8540 135.73 + hmc_h_new 10 0.02 + hmc_rest 10 0.00 + HMC 10 143.93 + h_mult_a 0 + h_mult_b 0 + h_mult_c 0 + dsg 6410 8.40 + dsf 2020 33.80 + plaquette 22 0.02 914.50 914.50 914.50 0.91 + cooling 10 1.41 + ran_gauss_volh 140 0.06 + MTDAGMT_r4 0 + dsig 1610 10.50 + rectangle 21 0.03 1867.26 1867.26 1867.26 1.87 + chair 0 + parallelogram 0 + stout_smear 1612 4.08 1549.85 1549.85 1549.85 1.55 + stout_diffe 2540 12.68 2317.33 2317.33 2317.33 2.32 + clover_bsa_w 20260 2.53 1883.30 1883.30 1883.30 1.88 + clover_dsd_w 1640 1.46 1166.54 1166.54 1166.54 1.17 + clover_d_w 5900 13.90 2172.26 2172.26 2172.26 2.17 + dsf_at_bt 10130 3.28 1461.00 1461.00 1461.00 1.46 + dsf_xyztfb_w 10130 4.43 2333.09 2333.09 2333.09 2.33 + dsf_sum 10130 13.34 1490.11 1490.11 1490.11 1.49 + dsf_w2gen 2540 26.41 2120.58 2120.58 2120.58 2.12 + cgm 260 10.92 1815.99 1815.99 1815.99 1.82 + cg_ritz 82 4.15 1855.29 1855.29 1855.29 1.86 + cg_mix 0 + bicgstab 0 + bicgstab_mix 0 + ddbqnohat 0 + unprec_mmul 0 + unprec_dsf 0 + dsf_un 0 + dsf_mtmp 2020 88.52 + cg_mre_mtmp 2020 44.83 + dsf_wmul_r8 2020 0.48 + dsf_wdag_r8 410 0.18 + integrator 10 142.14 + bagel_d 0 + TOTAL 1 148.77 + + Performance + region #calls time mean min max Total + s MByte/s MByte/s MByte/s GByte/s + + xbound_g 0 + xbound_sc 0 + xbound_sc2 0 + u_read_bqcd 0 + u_write_bqcd 0 + u_read_ildg 1 0.00 36.86 36.86 36.86 0.04 + u_write_ildg 1 0.00 +Inf +Inf +Inf +Inf + >EndTiming + >EndFooter + >EndJob diff --git a/src/data/bqcd.310.input b/src/data/bqcd.310.input new file mode 100644 index 0000000000000000000000000000000000000000..1d81c3c40d0d189b2c0a71fa684afef860380d69 --- /dev/null +++ b/src/data/bqcd.310.input @@ -0,0 +1,85 @@ +comment "Test for Nf=2+1 with replay trick" +run 310 +lattice 4 4 4 4 +boundary_conditions_fermions 1 1 1 -1 +process_mapping 1 2 3 4 +processes 1 1 1 1 + +gauge_action TREE +beta 5.5 +fermi_action SLRC +kappa 0.121095 +kappa_strange 0.120512 +csw 2.65 +n_stout 1 +alpha 0.1 + +hmc_test 0 +hmc_integrator1 2MNSTS +hmc_integrator2 2MNSTS +hmc_integrator3 2MNSTS +hmc_integrator4 2MNSTS + +hmc_model F +hmc_mpf_mass 2 +hmc_mpf_rhmc_s 2 +hmc_hkappa 1 +hmc_rho 0.1203 +hmc_accept_first 10 +hmc_trajectory_length 1.0 + +hmc_steps 5 +hmc_m_scale 2 +hmc_m_scale2 2 +hmc_m_scale3 2 + +hmc_dsf1_mtmp 3 +hmc_dsf2_mtmp 2 +hmc_dsf_ers 1 +hmc_dsd 2 +hmc_dsig 3 +hmc_dsg 4 + +start_configuration hot +io_restart_format ildg +#start_ildg_file qcdsf.699.00550.lime + +start_random 319503 +mc_steps 20 +mc_total_steps 20000 +mc_save_frequency 0 + +solver_rest 1e-11 +solver_rest_md 1e-9 +solver_rest_cg_ritz 1e-11 +solver_maxiter 1200000 +solver_stopping_criterion 1 +solver_ignore_no_convergence 0 +solver_mre_vectors 5 +solver_check_solution 0 +solver_outer_solver cg +solver_inner_solver cg +solver_outer_steps 0 + +measure_traces 1 +measure_minmax 1 +measure_polyakov_loop 1 +measure_rhmc_forces 0 +measure_cooling_list "cool.list" + +io_conf_format "ildg" +ildg_filename_prefix "qcdsf" +ildg_filename_extension "lime" +ildg_precision 64 +ildg_template_ensemble "qcdsf-ensemble-05.xml" +ildg_template_conf "qcdsf-configuration-04.xml" +ildg_markov_chain_uri "mc://ldg/qcd_collaboration/clover_nf2p1/b5p50kp121095kp120512-32x64" +ildg_data_lfn_path "lfn://ldg/qcd_collaboration/clover_nf2p1/b5p50kp121095kp120512-32x64" +ildg_participant_name "Your Name" +ildg_participant_institution "Your Institute" +ildg_machine_name "fast_runner" +ildg_machine_institution "Your Computing Centre" +ildg_machine_type "fast_computer" + +replay_trick_ntau 10 +replay_trick_threshold 0.3 diff --git a/src/data/bqcd.310.output b/src/data/bqcd.310.output new file mode 100644 index 0000000000000000000000000000000000000000..8efa1fea34b1d9f34602183669bf3b014b000760 --- /dev/null +++ b/src/data/bqcd.310.output @@ -0,0 +1,680 @@ + >BeginJob + >BeginHeader + Comment Test for Nf=2+1 with replay trick + Program bqcd 4.0.0 (revision 332) + Version_of_D 100 + Communication single_pe + RandomNumbers ranlux-3.2 level 2 + Run 310 + Job 1 + Host ubuntu + Date 2011-09-21 22:27:52.571 + L 4 4 4 4 + DDL 1 1 1 1 + NPE 1 1 1 1 + process_mapping 1 2 3 4 + bc_fermions 1 1 1 -1 + gamma_index 1 2 3 4 + Gauge Action TREE + Fermi Action SLRC + tilde M 1 - T^-1 D T^-1 D + Gamma notation BQCD + eo-prec DeoDoe + BoundaryCondition normal + Threads 1 + Start 0 + Seed 319503 + Swap_seq 0 + N_force 10 + N_traj 20 + N_save 0 + N_temper 1 + beta_1 5.5 + c0_1 0.0 + c1_1 0.0 + c2_1 0.0 + c3_1 0.0 + u04_1 0.0 + kappa_1 0.121095 + kappa_strange_1 0.120512 + csw_1 2.65 + csw_kappa_1 0.320901750000000 + csw_kappa_strange_1 0.319356800000000 + n_stout_1 1 + alpha_1 0.1 + theta_1 0.0 + chemi_1 0.0 + h_1 0.0 + rho_1 0.1203 + rho2_1 0.0 + rho3_1 0.0 + rho4_1 0.0 + traj_length_1 1.0 + tau_1 0.200000000000000 + N_tau_1 5 2MNSTS ers + m_scale_1 2 2MNSTS eo2 dat + m_scale2_1 2 2MNSTS eo1 ig + m_scale3_1 2 2MNSTS g + hkappa 1 + mpf_eo[m,l,s]: 2 0 2 + mpf_dd[m,l,s]: 0 0 0 + mpf_hh[m,l,s]: 0 0 0 + HMC_replay_ntau 10 + HMC_replay_threshold 0.3 + HMC_model F + REAL_kind 8 + Solver_outer cg + Solver_inner cg + CG_rest 1e-11 + CG_rest_md 1e-9 + CG_stopping_criterion 1 + CG_outer_steps 0 + MRE_vectors 5 + Fullsolver eo + >EndHeader + >BeginForceAcceptance + T%fa i_fa e PlaqEnergy exp(-Delta_H) CGcalls CGitTot CGitMax CGMcalls CGMitTotCGMitMax Plaquette + T%it traj iter_SF iter_F1 iter_F2 iter_F3 iter_F4 iter_F5 iter_F6 iter_F7 iter_F8 iter_F9 + %it -9 260 4665 1469 1042 0 0 0 0 0 0 + %it4 -9 0 0 0 0 0 0 0 0 0 0 + T%Favg traj F_gauge F_impg F_det F_F1 F_F2 F_F3 F_F4 F_F5 F_F6 F_F7 F_F8 F_F9 + T%Fmax traj F_gauge F_impg F_det F_F1 F_F2 F_F3 F_F4 F_F5 F_F6 F_F7 F_F8 F_F9 + T%Frat traj F_gauge F_impg F_det F_F1 F_F2 F_F3 F_F4 F_F5 F_F6 F_F7 F_F8 F_F9 + %Favg -9 7.822 0.666 1.340 2.775 0.067 0.823 0.000 0.000 0.000 0.000 0.000 0.000 + %Fmax -9 14.008 1.247 2.702 7.549 0.193 1.961 0.000 0.000 0.000 0.000 0.000 0.000 + %Frat -9 72.626 6.464 14.006 39.139 1.000 10.165 0.000 0.000 0.000 0.000 0.000 0.000 + T%Hold traj H_total H_generator H_gauge H_det H_fermion_1 H_fermion_2 H_fermion_3 + T%Hnew traj H_total H_generator H_gauge H_det H_fermion_1 H_fermion_2 H_fermion_3 + T%Hdif traj H_total H_generator H_gauge H_det H_fermion_1 H_fermion_2 H_fermion_3 + %Hold -9 0.1175206E+05 0.4065964E+04 0.7585522E+04 -0.6000883E+04 0.1567305E+04 0.1517629E+04 0.3016521E+04 + %Hnew -9 0.1175243E+05 0.5957390E+04 0.5626949E+04 -0.5967133E+04 0.1595594E+04 0.1515925E+04 0.3023703E+04 + %Hdif -9 0.3697911E+00 0.1891426E+04 -0.1958573E+04 0.3375016E+02 0.2828917E+02 -0.1704640E+01 0.7182088E+01 + %fa -9 1 0.7596780818 0.6908786269 203 6179 48 26 1257 61 0.240321918219764 + T%egnv traj type mid min max it_min it_max tol condi n_opt + %egnv -9 1 1 0.80547445E-01 2.2603050 73 41 1e-11 28.062 1.67 + %egnv -9 1 2 0.74060643E-01 2.3117457 74 39 1e-11 31.214 1.72 + %egnv -9 1 3 0.78792963E-01 2.2737198 73 41 1e-11 28.857 1.68 + %it -8 309 5273 1650 1179 0 0 0 0 0 0 + %it4 -8 0 0 0 0 0 0 0 0 0 0 + %Favg -8 8.173 0.726 1.348 2.465 0.067 0.809 0.000 0.000 0.000 0.000 0.000 0.000 + %Fmax -8 14.511 1.353 2.755 6.638 0.189 1.925 0.000 0.000 0.000 0.000 0.000 0.000 + %Frat -8 76.618 7.144 14.547 35.048 1.000 10.166 0.000 0.000 0.000 0.000 0.000 0.000 + %Hold -8 0.9777570E+04 0.4030068E+04 0.5626949E+04 -0.5967133E+04 0.1485841E+04 0.1560926E+04 0.3040919E+04 + %Hnew -8 0.9778114E+04 0.4628898E+04 0.5029892E+04 -0.5984421E+04 0.1505593E+04 0.1560220E+04 0.3037933E+04 + %Hdif -8 0.5445722E+00 0.5988301E+03 -0.5970570E+03 -0.1728829E+02 0.1975166E+02 -0.7061834E+00 -0.2985696E+01 + %fa -8 1 0.6837585510 0.5800898725 203 6981 58 26 1430 65 0.316241448982835 + %egnv -8 1 1 0.71967912E-01 2.1601388 172 64 1e-11 30.015 1.70 + %egnv -8 1 2 0.65996267E-01 2.2033538 176 62 1e-11 33.386 1.75 + %egnv -8 1 3 0.70350902E-01 2.1714299 173 63 1e-11 30.866 1.71 + %it -7 367 6315 1972 1416 0 0 0 0 0 0 + %it4 -7 0 0 0 0 0 0 0 0 0 0 + %Favg -7 8.463 0.775 1.341 2.442 0.071 0.862 0.000 0.000 0.000 0.000 0.000 0.000 + %Fmax -7 15.009 1.430 2.738 6.868 0.236 2.102 0.000 0.000 0.000 0.000 0.000 0.000 + %Frat -7 63.708 6.071 11.622 29.153 1.000 8.920 0.000 0.000 0.000 0.000 0.000 0.000 + %Hold -7 0.9293270E+04 0.4094299E+04 0.5029892E+04 -0.5984421E+04 0.1512332E+04 0.1487833E+04 0.3153335E+04 + %Hnew -7 0.9292577E+04 0.4531932E+04 0.4556032E+04 -0.5956843E+04 0.1510334E+04 0.1488096E+04 0.3163026E+04 + %Hdif -7 -0.6925139E+00 0.4376328E+03 -0.4738597E+03 0.2757784E+02 -0.1997839E+01 0.2632195E+00 0.9691159E+01 + %fa -7 1 0.6247996765 1.9987337431 203 8348 72 26 1722 88 0.375200323527170 + %egnv -7 1 1 0.35981194E-01 2.4918009 109 27 1e-11 69.253 2.12 + %egnv -7 1 2 0.31457047E-01 2.5556502 113 27 1e-11 81.243 2.20 + %egnv -7 1 3 0.34743068E-01 2.5084717 110 27 1e-11 72.201 2.14 + %it -6 415 6439 1996 1435 0 0 0 0 0 0 + %it4 -6 0 0 0 0 0 0 0 0 0 0 + %Favg -6 8.588 0.801 1.341 2.583 0.073 0.848 0.000 0.000 0.000 0.000 0.000 0.000 + %Fmax -6 15.164 1.485 2.883 6.699 0.201 2.233 0.000 0.000 0.000 0.000 0.000 0.000 + %Frat -6 75.365 7.378 14.327 33.291 1.000 11.097 0.000 0.000 0.000 0.000 0.000 0.000 + %Hold -6 0.8871121E+04 0.4101907E+04 0.4556032E+04 -0.5956843E+04 0.1567070E+04 0.1524604E+04 0.3078351E+04 + %Hnew -6 0.8870834E+04 0.4182358E+04 0.4478885E+04 -0.5981559E+04 0.1590364E+04 0.1524322E+04 0.3076463E+04 + %Hdif -6 -0.2872979E+00 0.8045069E+02 -0.7714721E+02 -0.2471533E+02 0.2329443E+02 -0.2821219E+00 -0.1887758E+01 + %fa -6 1 0.6141827704 1.3328212611 203 8518 83 26 1767 89 0.385817229614800 + %egnv -6 1 1 0.44963111E-01 2.2734221 88 50 1e-11 50.562 1.96 + %egnv -6 1 2 0.39975905E-01 2.3294476 90 48 1e-11 58.271 2.03 + %egnv -6 1 3 0.43602824E-01 2.2880091 89 50 1e-11 52.474 1.98 + %it -5 408 6831 2127 1499 0 0 0 0 0 0 + %it4 -5 0 0 0 0 0 0 0 0 0 0 + %Favg -5 8.537 0.810 1.325 2.374 0.073 0.792 0.000 0.000 0.000 0.000 0.000 0.000 + %Fmax -5 15.199 1.518 2.779 5.839 0.240 1.881 0.000 0.000 0.000 0.000 0.000 0.000 + %Frat -5 63.304 6.323 11.576 24.320 1.000 7.834 0.000 0.000 0.000 0.000 0.000 0.000 + %Hold -5 0.8651157E+04 0.4089832E+04 0.4478885E+04 -0.5981559E+04 0.1533584E+04 0.1538412E+04 0.2992002E+04 + %Hnew -5 0.8651211E+04 0.4106159E+04 0.4427728E+04 -0.5966972E+04 0.1552947E+04 0.1538339E+04 0.2993011E+04 + %Hdif -5 0.5466773E-01 0.1632681E+02 -0.5115719E+02 0.1458633E+02 0.1936275E+02 -0.7251007E-01 0.1008478E+01 + %fa -5 1 0.6078148517 0.9467996843 203 9032 74 26 1833 89 0.392185148344773 + %egnv -5 1 1 0.22021276E-01 2.4372806 104 107 1e-11 110.678 2.35 + %egnv -5 1 2 0.18136345E-01 2.5058991 109 102 1e-11 138.170 2.46 + %egnv -5 1 3 0.20945916E-01 2.4551219 105 104 1e-11 117.212 2.38 + %it -4 429 6844 2157 1507 0 0 0 0 0 0 + %it4 -4 0 0 0 0 0 0 0 0 0 0 + %Favg -4 8.590 0.817 1.341 2.382 0.075 0.815 0.000 0.000 0.000 0.000 0.000 0.000 + %Fmax -4 15.030 1.533 2.840 6.062 0.241 1.996 0.000 0.000 0.000 0.000 0.000 0.000 + %Frat -4 62.306 6.354 11.771 25.130 1.000 8.273 0.000 0.000 0.000 0.000 0.000 0.000 + %Hold -4 0.8583368E+04 0.4091101E+04 0.4427728E+04 -0.5966972E+04 0.1500592E+04 0.1498237E+04 0.3032683E+04 + %Hnew -4 0.8583295E+04 0.4195410E+04 0.4340990E+04 -0.5972497E+04 0.1494524E+04 0.1498127E+04 0.3026742E+04 + %Hdif -4 -0.7338696E-01 0.1043087E+03 -0.8673771E+02 -0.5524790E+01 -0.6068144E+01 -0.1098792E+00 -0.5941606E+01 + %fa -4 1 0.5963913539 1.0761468820 203 9085 84 26 1852 89 0.403608646117285 + %egnv -4 1 1 0.30188146E-01 2.1647039 72 43 1e-11 71.707 2.14 + %egnv -4 1 2 0.25911790E-01 2.2091304 74 42 1e-11 85.256 2.22 + %egnv -4 1 3 0.29014812E-01 2.1763156 73 43 1e-11 75.007 2.16 + %it -3 405 6806 2123 1496 0 0 0 0 0 0 + %it4 -3 0 0 0 0 0 0 0 0 0 0 + %Favg -3 8.812 0.851 1.322 2.317 0.076 0.815 0.000 0.000 0.000 0.000 0.000 0.000 + %Fmax -3 15.659 1.548 2.832 6.624 0.240 2.042 0.000 0.000 0.000 0.000 0.000 0.000 + %Frat -3 65.194 6.446 11.792 27.579 1.000 8.503 0.000 0.000 0.000 0.000 0.000 0.000 + %Hold -3 0.8614961E+04 0.4145810E+04 0.4340990E+04 -0.5972497E+04 0.1528241E+04 0.1522367E+04 0.3050051E+04 + %Hnew -3 0.8614829E+04 0.4253580E+04 0.4279266E+04 -0.5991784E+04 0.1500857E+04 0.1521232E+04 0.3051678E+04 + %Hdif -3 -0.1322210E+00 0.1077699E+03 -0.6172370E+02 -0.1928727E+02 -0.2738316E+02 -0.1135419E+01 0.1627457E+01 + %fa -3 1 0.5874912538 1.1413604899 203 9010 81 26 1820 85 0.412508746225394 + %egnv -3 1 1 0.43832510E-01 2.0903463 114 69 1e-11 47.689 1.93 + %egnv -3 1 2 0.39086798E-01 2.1258883 115 68 1e-11 54.389 2.00 + %egnv -3 1 3 0.42539420E-01 2.0996774 114 68 1e-11 49.358 1.95 + %it -2 396 7072 2166 1525 0 0 0 0 0 0 + %it4 -2 0 0 0 0 0 0 0 0 0 0 + %Favg -2 8.913 0.864 1.305 2.441 0.078 0.774 0.000 0.000 0.000 0.000 0.000 0.000 + %Fmax -2 15.503 1.622 2.583 6.663 0.219 1.881 0.000 0.000 0.000 0.000 0.000 0.000 + %Frat -2 70.650 7.390 11.770 30.364 1.000 8.574 0.000 0.000 0.000 0.000 0.000 0.000 + %Hold -2 0.8505403E+04 0.4191183E+04 0.4279266E+04 -0.5991784E+04 0.1438738E+04 0.1538052E+04 0.3049948E+04 + %Hnew -2 0.8505738E+04 0.4375280E+04 0.4115031E+04 -0.5998951E+04 0.1429808E+04 0.1538295E+04 0.3046276E+04 + %Hdif -2 0.3356661E+00 0.1840966E+03 -0.1642358E+03 -0.7166638E+01 -0.8930499E+01 0.2437761E+00 -0.3671725E+01 + %fa -2 1 0.5665928635 0.7148617486 203 9311 73 26 1848 83 0.433407136503992 + %egnv -2 1 1 0.36920646E-01 2.2540469 93 63 1e-11 61.051 2.06 + %egnv -2 1 2 0.32990186E-01 2.3051667 96 61 1e-11 69.874 2.12 + %egnv -2 1 3 0.35843877E-01 2.2674049 93 62 1e-11 63.258 2.07 + %it -1 443 8015 2453 1689 0 0 0 0 0 0 + %it4 -1 0 0 0 0 0 0 0 0 0 0 + %Favg -1 8.930 0.880 1.321 2.692 0.078 0.817 0.000 0.000 0.000 0.000 0.000 0.000 + %Fmax -1 15.259 1.577 2.784 7.084 0.243 1.970 0.000 0.000 0.000 0.000 0.000 0.000 + %Frat -1 62.866 6.495 11.468 29.186 1.000 8.115 0.000 0.000 0.000 0.000 0.000 0.000 + %Hold -1 0.8457890E+04 0.4133751E+04 0.4115031E+04 -0.5998951E+04 0.1543906E+04 0.1550057E+04 0.3114096E+04 + %Hnew -1 0.8458024E+04 0.4133266E+04 0.4063189E+04 -0.5982004E+04 0.1572060E+04 0.1549422E+04 0.3122091E+04 + %Hdif -1 0.1340930E+00 -0.4850760E+00 -0.5184203E+02 0.1694690E+02 0.2815357E+02 -0.6347645E+00 0.7995496E+01 + %fa -1 1 0.5600325226 0.8745087585 203 10547 84 26 2053 99 0.439967477354792 + %egnv -1 1 1 0.20043752E-01 2.6191537 175 22 1e-11 130.672 2.44 + %egnv -1 1 2 0.16816988E-01 2.7011716 181 21 1e-11 160.622 2.54 + %egnv -1 1 3 0.19150390E-01 2.6404757 176 22 1e-11 137.881 2.46 + %it 0 479 8211 2550 1734 0 0 0 0 0 0 + %it4 0 0 0 0 0 0 0 0 0 0 0 + %Favg 0 8.948 0.890 1.310 2.576 0.079 0.785 0.000 0.000 0.000 0.000 0.000 0.000 + %Fmax 0 14.994 1.600 2.652 7.318 0.257 1.987 0.000 0.000 0.000 0.000 0.000 0.000 + %Frat 0 58.398 6.233 10.329 28.504 1.000 7.738 0.000 0.000 0.000 0.000 0.000 0.000 + %Hold 0 0.8333887E+04 0.4060687E+04 0.4063189E+04 -0.5982004E+04 0.1622086E+04 0.1520595E+04 0.3049334E+04 + %Hnew 0 0.8334043E+04 0.4222562E+04 0.3927864E+04 -0.5981657E+04 0.1589964E+04 0.1519281E+04 0.3056029E+04 + %Hdif 0 0.1560966E+00 0.1618753E+03 -0.1353247E+03 0.3474518E+00 -0.3212248E+02 -0.1314227E+01 0.6694721E+01 + %fa 0 1 0.5423191675 0.8554765278 203 10855 94 26 2119 100 0.457680832487830 + %egnv 0 1 1 0.21786046E-01 2.0954562 183 71 1e-11 96.183 2.28 + %egnv 0 1 2 0.18395558E-01 2.1338143 187 70 1e-11 115.996 2.38 + %egnv 0 1 3 0.20849284E-01 2.1055060 184 71 1e-11 100.987 2.31 + >EndForceAcceptance + >BeginMC + T%mc traj e f PlaqEnergy exp(-Delta_H) Acc CGcalls CGitTot CGitMax CGMcalls CGMitTotCGMitMax Plaquette + T%pr traj Plaquette PlaquetteS PlaquetteT Rectangle RectangleS RectangleT + %it 1 468 9157 2766 1827 0 0 0 0 0 0 + %it4 1 0 0 0 0 0 0 0 0 0 0 + %Favg 1 9.045 0.914 1.310 2.609 0.074 0.780 0.000 0.000 0.000 0.000 0.000 0.000 + %Fmax 1 15.598 1.700 2.656 7.611 0.211 1.853 0.000 0.000 0.000 0.000 0.000 0.000 + %Frat 1 73.953 8.060 12.594 36.086 1.000 8.788 0.000 0.000 0.000 0.000 0.000 0.000 + %Hold 1 0.8059372E+04 0.3981543E+04 0.3927864E+04 -0.5981657E+04 0.1572569E+04 0.1491144E+04 0.3067908E+04 + %Hnew 1 0.8059149E+04 0.4134471E+04 0.3802579E+04 -0.5991136E+04 0.1561179E+04 0.1491647E+04 0.3060409E+04 + %Hdif 1 -0.2222102E+00 0.1529275E+03 -0.1252850E+03 -0.9479001E+01 -0.1138985E+02 0.5033573E+00 -0.7499237E+01 + %mc 1 1 1 0.5256287766 1.2488338160 1 203 12011 88 26 2207 97 0.474371223366952 + %pr 1 0.4743712233670 0.4726444614416 0.4760979852923 0.2448709263519 0.2412306523393 0.2485112003645 + %egnv 1 1 1 0.11201679E-01 2.1239394 92 55 1e-11 189.609 2.62 + %egnv 1 1 2 0.88566281E-02 2.1649865 94 54 1e-11 244.448 2.75 + %egnv 1 1 3 0.10542689E-01 2.1346870 92 55 1e-11 202.480 2.66 + T%tr traj e f Re(pbp) Im(pbp) Re(p5p) -Im(p5p) PionNorm CGiter + %tr 1 1 1 1.096700462 -0.1407549483E-01 0.2229625636E-01 -0.7157087423E-12 2.751908895 98 + T%pl traj e f Re(Polyakov_Loop) Im(Polyakov_Loop) + %pl 1 1 1 -0.2789722073E-01 0.5139163744E-01 + >BeginCooling + T%Qc traj e f i_cool Q_cool PlaqEnergy + %Qc 1 1 1 0 0.048126 0.5256287766 + %Qc 1 1 1 1 0.020771 0.1313428133 + %Qc 1 1 1 2 0.182281 0.0511502413 + %Qc 1 1 1 3 0.219576 0.0309807577 + %Qc 1 1 1 4 0.142079 0.0218651580 + %Qc 1 1 1 5 0.052772 0.0161620086 + %Qc 1 1 1 6 0.009561 0.0114304824 + %Qc 1 1 1 7 0.002320 0.0075411411 + %Qc 1 1 1 8 0.001251 0.0046428307 + %Qc 1 1 1 9 0.000558 0.0026599217 + %Qc 1 1 1 10 0.000203 0.0014373722 + %Qc 1 1 1 20 0.000000 0.0000057767 + %Qc 1 1 1 30 -0.000000 0.0000001381 + %Qc 1 1 1 40 0.000000 0.0000000048 + %Qc 1 1 1 50 0.000000 0.0000000002 + >EndCooling + %it 2 455 7713 2354 1642 0 0 0 0 0 0 + %it4 2 0 0 0 0 0 0 0 0 0 0 + %Favg 2 9.177 0.940 1.294 2.393 0.063 0.763 0.000 0.000 0.000 0.000 0.000 0.000 + %Fmax 2 15.786 1.705 2.628 6.960 0.203 2.201 0.000 0.000 0.000 0.000 0.000 0.000 + %Frat 2 77.904 8.415 12.971 34.348 1.000 10.863 0.000 0.000 0.000 0.000 0.000 0.000 + %Hold 2 0.8090140E+04 0.4136443E+04 0.3802579E+04 -0.5991136E+04 0.1557003E+04 0.1537098E+04 0.3048153E+04 + %Hnew 2 0.8089947E+04 0.4104749E+04 0.3861978E+04 -0.5997383E+04 0.1531613E+04 0.1537314E+04 0.3051676E+04 + %Hdif 2 -0.1930394E+00 -0.3169377E+02 0.5939897E+02 -0.6247810E+01 -0.2538989E+02 0.2159002E+00 0.3523552E+01 + %mc 2 1 1 0.5329972738 1.2129305712 1 203 10159 92 26 2005 98 0.467002726200149 + %pr 2 0.4670027262001 0.4683781125821 0.4656273398182 0.2414972351911 0.2417406997376 0.2412537706446 + %egnv 2 1 1 0.22479266E-01 2.2750867 88 38 1e-11 101.208 2.31 + %egnv 2 1 2 0.19130147E-01 2.3261453 89 37 1e-11 121.596 2.40 + %egnv 2 1 3 0.21554327E-01 2.2884336 88 38 1e-11 106.170 2.33 + %tr 2 1 1 1.057820178 -0.6021840548E-02 0.1866930893E-01 0.3389672802E-12 2.375531736 83 + T%pl traj e f Re(Polyakov_Loop) Im(Polyakov_Loop) + %pl 2 1 1 -0.1273484595E-01 -0.2853351752E-02 + >BeginCooling + T%Qc traj e f i_cool Q_cool PlaqEnergy + %Qc 2 1 1 0 -0.009762 0.5329972738 + %Qc 2 1 1 1 -0.005589 0.1193819284 + %Qc 2 1 1 2 0.280278 0.0339020381 + %Qc 2 1 1 3 0.458564 0.0186745713 + %Qc 2 1 1 4 0.515329 0.0133907613 + %Qc 2 1 1 5 0.494449 0.0106876341 + %Qc 2 1 1 6 0.412659 0.0089590257 + %Qc 2 1 1 7 0.243720 0.0071402461 + %Qc 2 1 1 8 0.051627 0.0041253981 + %Qc 2 1 1 9 0.004785 0.0017870726 + %Qc 2 1 1 10 0.000654 0.0008693666 + %Qc 2 1 1 20 -0.000000 0.0000149504 + %Qc 2 1 1 30 -0.000000 0.0000007825 + %Qc 2 1 1 40 -0.000000 0.0000000488 + %Qc 2 1 1 50 -0.000000 0.0000000034 + >EndCooling + %it 3 401 7600 2292 1560 0 0 0 0 0 0 + %it4 3 0 0 0 0 0 0 0 0 0 0 + %Favg 3 9.316 0.968 1.278 2.307 0.059 0.758 0.000 0.000 0.000 0.000 0.000 0.000 + %Fmax 3 15.815 1.684 2.594 6.295 0.182 1.919 0.000 0.000 0.000 0.000 0.000 0.000 + %Frat 3 86.712 9.230 14.222 34.514 1.000 10.520 0.000 0.000 0.000 0.000 0.000 0.000 + %Hold 3 0.8167467E+04 0.4128298E+04 0.3861978E+04 -0.5997383E+04 0.1564709E+04 0.1498362E+04 0.3111503E+04 + %Hnew 3 0.8167623E+04 0.4163487E+04 0.3834727E+04 -0.6003886E+04 0.1563891E+04 0.1498577E+04 0.3110827E+04 + %Hdif 3 0.1561686E+00 0.3518982E+02 -0.2725052E+02 -0.6502846E+01 -0.8186534E+00 0.2147323E+00 -0.6763621E+00 + %mc 3 1 1 0.5292769709 0.8554149516 1 203 9972 80 26 1881 84 0.470723029146328 + %pr 3 0.4707230291463 0.4681862119893 0.4732598463034 0.2464434953329 0.2415090174780 0.2513779731878 + %egnv 3 1 1 0.30014974E-01 2.1062972 104 54 1e-11 70.175 2.13 + %egnv 3 1 2 0.26192034E-01 2.1456845 105 54 1e-11 81.921 2.20 + %egnv 3 1 3 0.28967795E-01 2.1166145 105 54 1e-11 73.068 2.15 + %tr 3 1 1 1.021762789 -0.2042146031E-01 -0.4749027568E-01 0.3973673242E-14 2.277549460 77 + T%pl traj e f Re(Polyakov_Loop) Im(Polyakov_Loop) + %pl 3 1 1 0.1773374000E-02 -0.6020273049E-02 + >BeginCooling + T%Qc traj e f i_cool Q_cool PlaqEnergy + %Qc 3 1 1 0 0.082096 0.5292769709 + %Qc 3 1 1 1 0.130736 0.1094908049 + %Qc 3 1 1 2 0.348310 0.0290075306 + %Qc 3 1 1 3 0.482536 0.0148645267 + %Qc 3 1 1 4 0.532007 0.0109541621 + %Qc 3 1 1 5 0.531717 0.0093610445 + %Qc 3 1 1 6 0.496172 0.0084716141 + %Qc 3 1 1 7 0.418683 0.0077233872 + %Qc 3 1 1 8 0.256949 0.0064885283 + %Qc 3 1 1 9 0.051149 0.0036024191 + %Qc 3 1 1 10 0.004666 0.0014500989 + %Qc 3 1 1 20 -0.000001 0.0000733980 + %Qc 3 1 1 30 -0.000000 0.0000200830 + %Qc 3 1 1 40 -0.000000 0.0000066622 + %Qc 3 1 1 50 -0.000000 0.0000023273 + >EndCooling + %it 4 359 6627 2011 1413 0 0 0 0 0 0 + %it4 4 0 0 0 0 0 0 0 0 0 0 + %Favg 4 9.366 0.992 1.286 2.203 0.068 0.750 0.000 0.000 0.000 0.000 0.000 0.000 + %Fmax 4 15.430 1.680 2.590 5.796 0.235 1.829 0.000 0.000 0.000 0.000 0.000 0.000 + %Frat 4 65.672 7.152 11.026 24.668 1.000 7.786 0.000 0.000 0.000 0.000 0.000 0.000 + %Hold 4 0.8032018E+04 0.4044664E+04 0.3834727E+04 -0.6003886E+04 0.1492007E+04 0.1535946E+04 0.3128561E+04 + %Hnew 4 0.8031830E+04 0.4209353E+04 0.3696939E+04 -0.6021735E+04 0.1497246E+04 0.1535235E+04 0.3114790E+04 + %Hdif 4 -0.1882387E+00 0.1646889E+03 -0.1377879E+03 -0.1784834E+02 0.5239836E+01 -0.7103568E+00 -0.1377038E+02 + %mc 4 1 1 0.5098751696 1.2071215764 1 203 8712 74 26 1698 77 0.490124830404474 + %pr 4 0.4901248304045 0.4871551126951 0.4930945481138 0.2773603468371 0.2734506793642 0.2812700143101 + %egnv 4 1 1 0.65502739E-01 2.0458128 171 64 1e-11 31.232 1.72 + %egnv 4 1 2 0.61460094E-01 2.0819241 136 63 1e-11 33.874 1.76 + %egnv 4 1 3 0.64417039E-01 2.0552811 169 64 1e-11 31.906 1.73 + %tr 4 1 1 1.007907734 -0.7601675140E-02 0.2443749946E-01 0.1701263551E-12 2.040833006 63 + T%pl traj e f Re(Polyakov_Loop) Im(Polyakov_Loop) + %pl 4 1 1 0.7951758767E-01 0.5623775904E-01 + >BeginCooling + T%Qc traj e f i_cool Q_cool PlaqEnergy + %Qc 4 1 1 0 0.045646 0.5098751696 + %Qc 4 1 1 1 -0.029234 0.0931408157 + %Qc 4 1 1 2 0.001388 0.0184512823 + %Qc 4 1 1 3 0.003494 0.0052928828 + %Qc 4 1 1 4 0.001061 0.0023353821 + %Qc 4 1 1 5 0.000387 0.0012942022 + %Qc 4 1 1 6 0.000180 0.0008218505 + %Qc 4 1 1 7 0.000100 0.0005731839 + %Qc 4 1 1 8 0.000059 0.0004276590 + %Qc 4 1 1 9 0.000037 0.0003349825 + %Qc 4 1 1 10 0.000023 0.0002717438 + %Qc 4 1 1 20 -0.000000 0.0000711818 + %Qc 4 1 1 30 -0.000000 0.0000293477 + %Qc 4 1 1 40 -0.000000 0.0000144832 + %Qc 4 1 1 50 -0.000000 0.0000078682 + >EndCooling + %it 5 314 5524 1698 1202 0 0 0 0 0 0 + %it4 5 0 0 0 0 0 0 0 0 0 0 + %Favg 5 9.482 1.018 1.283 2.051 0.066 0.702 0.000 0.000 0.000 0.000 0.000 0.000 + %Fmax 5 15.906 1.765 2.497 5.144 0.220 1.751 0.000 0.000 0.000 0.000 0.000 0.000 + %Frat 5 72.376 8.032 11.363 23.406 1.000 7.968 0.000 0.000 0.000 0.000 0.000 0.000 + %Hold 5 0.7907837E+04 0.4124302E+04 0.3696939E+04 -0.6021735E+04 0.1493893E+04 0.1589574E+04 0.3024863E+04 + %Hnew 5 0.7907717E+04 0.4170782E+04 0.3640564E+04 -0.6017344E+04 0.1500153E+04 0.1589358E+04 0.3024205E+04 + %Hdif 5 -0.1194174E+00 0.4647936E+02 -0.5637582E+02 0.4391006E+01 0.6260365E+01 -0.2158112E+00 -0.6585196E+00 + %mc 5 1 1 0.5031014837 1.1268401568 1 203 7284 62 26 1454 65 0.496898516346528 + %pr 5 0.4968985163465 0.4932023561982 0.5005946764949 0.2783644677154 0.2752903495813 0.2814385858495 + %egnv 5 1 1 0.55985794E-01 2.1002748 57 79 1e-11 37.514 1.81 + %egnv 5 1 2 0.52921769E-01 2.1423930 58 75 1e-11 40.482 1.85 + %egnv 5 1 3 0.55143439E-01 2.1112902 58 78 1e-11 38.287 1.82 + %tr 5 1 1 1.001997007 0.3439332297E-01 0.8709493911E-02 0.2186260432E-12 2.079031451 59 + T%pl traj e f Re(Polyakov_Loop) Im(Polyakov_Loop) + %pl 5 1 1 0.1138803811 0.4482985504E-02 + >BeginCooling + T%Qc traj e f i_cool Q_cool PlaqEnergy + %Qc 5 1 1 0 0.027002 0.5031014837 + %Qc 5 1 1 1 -0.080645 0.0867699973 + %Qc 5 1 1 2 -0.054679 0.0171107966 + %Qc 5 1 1 3 -0.007190 0.0055779637 + %Qc 5 1 1 4 -0.001143 0.0023577124 + %Qc 5 1 1 5 -0.000409 0.0012326215 + %Qc 5 1 1 6 -0.000174 0.0007421942 + %Qc 5 1 1 7 -0.000077 0.0004950691 + %Qc 5 1 1 8 -0.000036 0.0003559669 + %Qc 5 1 1 9 -0.000018 0.0002700179 + %Qc 5 1 1 10 -0.000010 0.0002125877 + %Qc 5 1 1 20 -0.000001 0.0000387950 + %Qc 5 1 1 30 -0.000000 0.0000102065 + %Qc 5 1 1 40 -0.000000 0.0000032597 + %Qc 5 1 1 50 -0.000000 0.0000011935 + >EndCooling + replay_trcik: start replay mode + replay_trcik: h_dif before replaying = 0.44172592934523891 + replay_trcik: replayed h_dif = 4.29239621057604381E-002 + replay_trcik: reversibility is ok + %it 6 509 18024 5449 4204 0 0 0 0 0 0 + %it4 6 0 0 0 0 0 0 0 0 0 0 + %Favg 6 9.655 1.064 1.253 2.035 0.052 0.679 0.000 0.000 0.000 0.000 0.000 0.000 + %Fmax 6 16.137 1.794 2.506 5.691 0.163 1.587 0.000 0.000 0.000 0.000 0.000 0.000 + %Frat 6 99.302 11.037 15.424 35.021 1.000 9.768 0.000 0.000 0.000 0.000 0.000 0.000 + %Hold 6 0.7711426E+04 0.4021976E+04 0.3640564E+04 -0.6017344E+04 0.1557628E+04 0.1489029E+04 0.3019573E+04 + %Hnew 6 0.7711469E+04 0.4145317E+04 0.3545489E+04 -0.6029303E+04 0.1542500E+04 0.1489057E+04 0.3018410E+04 + %Hdif 6 0.4292396E-01 0.1233405E+03 -0.9507433E+02 -0.1195946E+02 -0.1512790E+02 0.2756884E-01 -0.1163497E+01 + %mc 6 1 1 0.4899120698 0.9579842304 1 807 23531 58 94 4655 61 0.510087930209968 + %pr 6 0.5100879302100 0.5039894148151 0.5161864456048 0.2977179722441 0.2893726814300 0.3060632630583 + %egnv 6 1 1 0.56001623E-01 2.1000720 57 79 1e-11 37.500 1.81 + %egnv 6 1 2 0.52939033E-01 2.1421753 58 76 1e-11 40.465 1.85 + %egnv 6 1 3 0.55159652E-01 2.1110836 58 79 1e-11 38.272 1.82 + %tr 6 1 1 1.021805588 -0.8061190176E-02 0.1861780366E-01 0.2880881297E-12 2.002666822 60 + T%pl traj e f Re(Polyakov_Loop) Im(Polyakov_Loop) + %pl 6 1 1 0.1139995601 0.4436629194E-02 + >BeginCooling + T%Qc traj e f i_cool Q_cool PlaqEnergy + %Qc 6 1 1 0 0.027022 0.5030705621 + %Qc 6 1 1 1 -0.080630 0.0867494720 + %Qc 6 1 1 2 -0.054720 0.0171038254 + %Qc 6 1 1 3 -0.007191 0.0055745286 + %Qc 6 1 1 4 -0.001142 0.0023557693 + %Qc 6 1 1 5 -0.000409 0.0012315836 + %Qc 6 1 1 6 -0.000174 0.0007416228 + %Qc 6 1 1 7 -0.000077 0.0004947387 + %Qc 6 1 1 8 -0.000036 0.0003557664 + %Qc 6 1 1 9 -0.000018 0.0002698915 + %Qc 6 1 1 10 -0.000010 0.0002125057 + %Qc 6 1 1 20 -0.000001 0.0000387985 + %Qc 6 1 1 30 -0.000000 0.0000102099 + %Qc 6 1 1 40 -0.000000 0.0000032612 + %Qc 6 1 1 50 -0.000000 0.0000011941 + >EndCooling + %it 7 307 5333 1618 1163 0 0 0 0 0 0 + %it4 7 0 0 0 0 0 0 0 0 0 0 + %Favg 7 9.477 1.033 1.265 2.096 0.056 0.707 0.000 0.000 0.000 0.000 0.000 0.000 + %Fmax 7 15.922 1.808 2.602 5.363 0.152 1.724 0.000 0.000 0.000 0.000 0.000 0.000 + %Frat 7 104.604 11.877 17.096 35.237 1.000 11.329 0.000 0.000 0.000 0.000 0.000 0.000 + %Hold 7 0.8015038E+04 0.4099800E+04 0.3640345E+04 -0.6017373E+04 0.1590498E+04 0.1568021E+04 0.3133748E+04 + %Hnew 7 0.8014986E+04 0.4183110E+04 0.3570930E+04 -0.6012642E+04 0.1584620E+04 0.1567366E+04 0.3121602E+04 + %Hdif 7 -0.5200006E-01 0.8331074E+02 -0.6941488E+02 0.4730904E+01 -0.5877344E+01 -0.6555696E+00 -0.1214585E+02 + %mc 7 1 1 0.4940437079 1.0533758104 1 203 7009 58 26 1412 64 0.505956292117162 + %pr 7 0.5059562921172 0.5058849656887 0.5060276185456 0.2865159176321 0.2908687432589 0.2821630920052 + %egnv 7 1 1 0.54610211E-01 2.1438095 139 46 1e-11 39.257 1.84 + %egnv 7 1 2 0.50884876E-01 2.1888613 135 45 1e-11 43.016 1.88 + %egnv 7 1 3 0.53592794E-01 2.1555870 137 46 1e-11 40.222 1.85 + %tr 7 1 1 1.038443506 0.1600582102E-01 0.3407846420E-01 0.4839872716E-12 2.153266182 63 + T%pl traj e f Re(Polyakov_Loop) Im(Polyakov_Loop) + %pl 7 1 1 0.1059826774 0.4003929450E-01 + >BeginCooling + T%Qc traj e f i_cool Q_cool PlaqEnergy + %Qc 7 1 1 0 0.039811 0.4940437079 + %Qc 7 1 1 1 -0.076854 0.0874759097 + %Qc 7 1 1 2 -0.009481 0.0174635439 + %Qc 7 1 1 3 0.001655 0.0054334709 + %Qc 7 1 1 4 0.000959 0.0023947757 + %Qc 7 1 1 5 0.000520 0.0013207805 + %Qc 7 1 1 6 0.000298 0.0008272406 + %Qc 7 1 1 7 0.000182 0.0005627423 + %Qc 7 1 1 8 0.000117 0.0004059155 + %Qc 7 1 1 9 0.000078 0.0003058232 + %Qc 7 1 1 10 0.000054 0.0002381022 + %Qc 7 1 1 20 0.000002 0.0000411009 + %Qc 7 1 1 30 0.000000 0.0000101513 + %Qc 7 1 1 40 0.000000 0.0000026894 + %Qc 7 1 1 50 0.000000 0.0000007351 + >EndCooling + %it 8 302 4694 1431 1063 0 0 0 0 0 0 + %it4 8 0 0 0 0 0 0 0 0 0 0 + %Favg 8 9.507 1.048 1.262 2.120 0.049 0.691 0.000 0.000 0.000 0.000 0.000 0.000 + %Fmax 8 15.687 1.748 2.662 5.060 0.139 1.547 0.000 0.000 0.000 0.000 0.000 0.000 + %Frat 8 112.742 12.563 19.133 36.363 1.000 11.118 0.000 0.000 0.000 0.000 0.000 0.000 + %Hold 8 0.7775411E+04 0.4076839E+04 0.3570930E+04 -0.6012642E+04 0.1539474E+04 0.1536608E+04 0.3064202E+04 + %Hnew 8 0.7775116E+04 0.4189293E+04 0.3454433E+04 -0.6021064E+04 0.1552837E+04 0.1535885E+04 0.3063732E+04 + %Hdif 8 -0.2943737E+00 0.1124539E+03 -0.1164968E+03 -0.8421251E+01 0.1336344E+02 -0.7233774E+00 -0.4702051E+00 + %mc 8 1 1 0.4784909580 1.3422854279 1 203 6185 60 26 1305 64 0.521509041989961 + %pr 8 0.5215090419900 0.5200820783909 0.5229360055890 0.3041447054901 0.3066112596803 0.3016781513000 + %egnv 8 1 1 0.89799448E-01 2.1321057 401 49 1e-11 23.743 1.58 + %egnv 8 1 2 0.87965151E-01 2.1778884 454 47 1e-11 24.759 1.60 + %egnv 8 1 3 0.89279303E-01 2.1440681 409 48 1e-11 24.015 1.59 + %tr 8 1 1 1.005222676 -0.1776428302E-01 0.1522476550E-01 0.9026807080E-13 1.924950517 56 + T%pl traj e f Re(Polyakov_Loop) Im(Polyakov_Loop) + %pl 8 1 1 0.2075425382 -0.3198528415E-02 + >BeginCooling + T%Qc traj e f i_cool Q_cool PlaqEnergy + %Qc 8 1 1 0 0.001633 0.4784909580 + %Qc 8 1 1 1 0.015612 0.0739140977 + %Qc 8 1 1 2 -0.000323 0.0117005162 + %Qc 8 1 1 3 0.001189 0.0041608023 + %Qc 8 1 1 4 0.001001 0.0021424802 + %Qc 8 1 1 5 0.000624 0.0012949879 + %Qc 8 1 1 6 0.000384 0.0008677716 + %Qc 8 1 1 7 0.000246 0.0006285518 + %Qc 8 1 1 8 0.000165 0.0004830964 + %Qc 8 1 1 9 0.000115 0.0003883603 + %Qc 8 1 1 10 0.000083 0.0003229043 + %Qc 8 1 1 20 0.000006 0.0001078803 + %Qc 8 1 1 30 0.000000 0.0000541871 + %Qc 8 1 1 40 -0.000000 0.0000309797 + %Qc 8 1 1 50 -0.000000 0.0000189483 + >EndCooling + replay_trcik: start replay mode + replay_trcik: h_dif before replaying = 0.35994678609176844 + replay_trcik: replayed h_dif = -3.13361914595589042E-003 + replay_trcik: reversibility is ok + %it 9 499 17127 5193 4029 0 0 0 0 0 0 + %it4 9 0 0 0 0 0 0 0 0 0 0 + %Favg 9 9.639 1.071 1.268 1.943 0.053 0.712 0.000 0.000 0.000 0.000 0.000 0.000 + %Fmax 9 15.788 1.806 2.599 4.736 0.143 1.810 0.000 0.000 0.000 0.000 0.000 0.000 + %Frat 9 110.593 12.651 18.205 33.174 1.000 12.682 0.000 0.000 0.000 0.000 0.000 0.000 + %Hold 9 0.7850425E+04 0.4133535E+04 0.3454433E+04 -0.6021064E+04 0.1494688E+04 0.1594648E+04 0.3194184E+04 + %Hnew 9 0.7850421E+04 0.4138680E+04 0.3457675E+04 -0.6034941E+04 0.1511289E+04 0.1595214E+04 0.3182505E+04 + %Hdif 9 -0.3133619E-02 0.5144314E+01 0.3241921E+01 -0.1387744E+02 0.1660076E+02 0.5657190E+00 -0.1167841E+02 + %mc 9 1 1 0.4783628696 1.0031385341 1 807 22375 55 94 4473 58 0.521637130358626 + %pr 9 0.5216371303586 0.5175422601170 0.5257320006002 0.3092630899021 0.2946022782536 0.3239239015505 + %egnv 9 1 1 0.89840994E-01 2.1319465 401 48 1e-11 23.730 1.58 + %egnv 9 1 2 0.88005317E-01 2.1777243 455 47 1e-11 24.745 1.60 + %egnv 9 1 3 0.89320501E-01 2.1439077 410 48 1e-11 24.002 1.59 + %tr 9 1 1 1.033743959 0.1418372126E-01 0.1773518737E-01 0.2437182400E-12 2.136426205 57 + T%pl traj e f Re(Polyakov_Loop) Im(Polyakov_Loop) + %pl 9 1 1 0.2076343853 -0.3202561565E-02 + >BeginCooling + T%Qc traj e f i_cool Q_cool PlaqEnergy + %Qc 9 1 1 0 0.001631 0.4784622803 + %Qc 9 1 1 1 0.015684 0.0738970966 + %Qc 9 1 1 2 -0.000315 0.0116939039 + %Qc 9 1 1 3 0.001190 0.0041578798 + %Qc 9 1 1 4 0.001001 0.0021409311 + %Qc 9 1 1 5 0.000624 0.0012940821 + %Qc 9 1 1 6 0.000384 0.0008672161 + %Qc 9 1 1 7 0.000246 0.0006281990 + %Qc 9 1 1 8 0.000165 0.0004828658 + %Qc 9 1 1 9 0.000116 0.0003882058 + %Qc 9 1 1 10 0.000084 0.0003227986 + %Qc 9 1 1 20 0.000006 0.0001078830 + %Qc 9 1 1 30 0.000000 0.0000542000 + %Qc 9 1 1 40 -0.000000 0.0000309944 + %Qc 9 1 1 50 -0.000000 0.0000189627 + >EndCooling + %it 10 276 4373 1353 1023 0 0 0 0 0 0 + %it4 10 0 0 0 0 0 0 0 0 0 0 + %Favg 10 9.652 1.077 1.257 1.944 0.053 0.680 0.000 0.000 0.000 0.000 0.000 0.000 + %Fmax 10 15.905 1.840 2.631 4.810 0.159 1.721 0.000 0.000 0.000 0.000 0.000 0.000 + %Frat 10 100.031 11.575 16.548 30.249 1.000 10.825 0.000 0.000 0.000 0.000 0.000 0.000 + %Hold 10 0.7662171E+04 0.4096361E+04 0.3454229E+04 -0.6021114E+04 0.1594950E+04 0.1543888E+04 0.2993857E+04 + %Hnew 10 0.7662219E+04 0.4115513E+04 0.3451672E+04 -0.6032564E+04 0.1595036E+04 0.1544497E+04 0.2988065E+04 + %Hdif 10 0.4844474E-01 0.1915216E+02 -0.2557151E+01 -0.1145054E+02 0.8667463E-01 0.6094854E+00 -0.5792184E+01 + %mc 10 1 1 0.4776125109 0.9527099859 1 203 5781 55 26 1244 58 0.522387489085741 + %pr 10 0.5223874890857 0.5201161708789 0.5246588072926 0.3096610602803 0.3087144282286 0.3106076923319 + %egnv 10 1 1 0.95202887E-01 2.0541882 126 33 1e-11 21.577 1.54 + %egnv 10 1 2 0.93121432E-01 2.0922909 125 32 1e-11 22.468 1.56 + %egnv 10 1 3 0.94623418E-01 2.0641689 126 32 1e-11 21.815 1.54 + %tr 10 1 1 0.9947831625 0.9106074977E-02 -0.1817837948E-01 0.1067809036E-13 1.936077965 52 + T%pl traj e f Re(Polyakov_Loop) Im(Polyakov_Loop) + %pl 10 1 1 0.2104837252 -0.7062826354E-01 + >BeginCooling + T%Qc traj e f i_cool Q_cool PlaqEnergy + %Qc 10 1 1 0 -0.005531 0.4776125109 + %Qc 10 1 1 1 -0.024231 0.0689734718 + %Qc 10 1 1 2 -0.006609 0.0121285172 + %Qc 10 1 1 3 -0.001572 0.0045666920 + %Qc 10 1 1 4 -0.000583 0.0023255207 + %Qc 10 1 1 5 -0.000292 0.0013762327 + %Qc 10 1 1 6 -0.000164 0.0009176696 + %Qc 10 1 1 7 -0.000097 0.0006720028 + %Qc 10 1 1 8 -0.000061 0.0005266109 + %Qc 10 1 1 9 -0.000041 0.0004323089 + %Qc 10 1 1 10 -0.000029 0.0003661488 + %Qc 10 1 1 20 -0.000003 0.0001231469 + %Qc 10 1 1 30 -0.000001 0.0000556736 + %Qc 10 1 1 40 -0.000000 0.0000280411 + %Qc 10 1 1 50 -0.000000 0.0000150627 + >EndCooling + >EndMC + >BeginILDGwrite + ildg-write file bqcd.310.lime + ildg-write precision 64 + ildg-write bytes 147456 + ildg-write cksum 4073776015 + ildg-write lfn bqcd-restart bqcd.310.lime 4073776015 147456 310 1 10 + >EndILDGwrite + >BeginFooter + Date 2011-09-21 22:34:41.413 + Seed -1 + CPU-Time 404.4 s on 1 CPUs + >BeginTiming + Performance + region #calls time mean min max Total + s Mflop/s Mflop/s Mflop/s Gflop/s + + d_xf 1235348 21.54 2114.46 2114.46 2114.46 2.11 + d_xb 0 + d_yf 1235348 27.44 1798.07 1798.07 1798.07 1.80 + d_yb 0 + d_zf 1235348 26.71 1847.36 1847.36 1847.36 1.85 + d_zb 0 + d_t 1235348 25.82 1910.60 1910.60 1910.60 1.91 + d_fb 0 + d_dag_fb 0 + d_xyzt 0 + sc2_projection 1235348 19.11 595.91 595.91 595.91 0.60 + D_TOTAL 1235348 124.04 1652.18 1652.18 1652.18 1.65 + d_dd 0 + d_eo 0 + MTDAGMT 263316 149.73 1685.52 1685.52 1685.52 1.69 + CG 5278 120.34 1699.47 1699.47 1699.47 1.70 + CG_DD 0 + CG_HH 0 + cg_global_sum 0 + global_sum 0 + global_sum_vec 0 + sc_zero 102200 2.37 + sc_copy 321326 1.04 + sc_scale 25730 0.14 548.87 548.87 548.87 0.55 + sc_norm2 108125 0.43 1552.07 1552.07 1552.07 1.55 + sc_dot 123345 0.62 1222.24 1222.24 1222.24 1.22 + sc_axpy 831615 3.78 1351.62 1351.62 1351.62 1.35 + sc_xpby 814050 3.28 1522.89 1522.89 1522.89 1.52 + sc_axpby 746670 3.73 1845.73 1845.73 1845.73 1.85 + sc_cdotc 76072 0.41 2268.72 2268.72 2268.72 2.27 + sc_caxpy 5056 0.02 2588.35 2588.35 2588.35 2.59 + sc_caxpy2 5056 0.02 7766.02 7766.02 7766.02 7.77 + sc_cax2 5152 0.05 2434.82 2434.82 2434.82 2.43 + clover_init 6279 11.40 + clover_mult_a 20 0.00 +Inf +Inf +Inf +Inf + clover_mult_ao 1156762 44.07 1854.73 1854.73 1854.73 1.85 + clover_mult_b 155840 5.93 1857.35 1857.35 1857.35 1.86 + clover_dsd 1064 11.77 + clover_dsf 0 + hmc_init 20 0.04 + hmc_init_p 20 0.02 + hmc_u 16640 17.11 + hmc_momenta 0 + hmc_phi 20 3.49 + hmc_h_old 20 3.56 + hmc_backup 20 0.02 + hmc_half_step0 0 + hmc_half_step1 0 + hmc_xbound_g 27409 0.02 + hmc_steps 22196 374.50 + hmc_h_new 20 0.04 + hmc_rest 20 81.60 + HMC 20 395.35 + h_mult_a 0 + h_mult_b 0 + h_mult_c 0 + dsg 16664 21.14 + dsf 5248 90.91 + plaquette 46 0.02 1529.63 1529.63 1529.63 1.53 + cooling 10 1.27 + ran_gauss_volh 268 0.04 + MTDAGMT_r4 0 + dsig 4184 26.45 + rectangle 45 0.06 2000.63 2000.63 2000.63 2.00 + chair 0 + parallelogram 0 + stout_smear 4173 10.23 1599.83 1599.83 1599.83 1.60 + stout_diffe 6596 35.03 2178.41 2178.41 2178.41 2.18 + clover_bsa_w 52384 9.14 1346.82 1346.82 1346.82 1.35 + clover_dsd_w 4256 3.48 1273.55 1273.55 1273.55 1.27 + clover_d_w 15320 38.86 2018.37 2018.37 2018.37 2.02 + dsf_at_bt 26192 9.22 1343.27 1343.27 1343.27 1.34 + dsf_xyztfb_w 26192 15.02 1778.88 1778.88 1778.88 1.78 + dsf_sum 26192 40.23 1278.01 1278.01 1278.01 1.28 + dsf_w2gen 6596 73.94 1967.01 1967.01 1967.01 1.97 + cgm 656 32.28 1558.73 1558.73 1558.73 1.56 + cg_ritz 170 10.02 1690.34 1690.34 1690.34 1.69 + cg_mix 0 + bicgstab 0 + bicgstab_mix 0 + ddbqnohat 0 + unprec_mmul 0 + unprec_dsf 0 + dsf_un 0 + dsf_mtmp 5248 242.27 + cg_mre_mtmp 5248 128.23 + dsf_wmul_r8 5248 1.41 + dsf_wdag_r8 1064 0.38 + integrator 24 391.66 + bagel_d 0 + TOTAL 1 404.41 + + Performance + region #calls time mean min max Total + s MByte/s MByte/s MByte/s GByte/s + + xbound_g 0 + xbound_sc 0 + xbound_sc2 0 + u_read_bqcd 0 + u_write_bqcd 0 + u_read_ildg 0 + u_write_ildg 1 0.00 +Inf +Inf +Inf +Inf + >EndTiming + >EndFooter + >EndJob diff --git a/src/data/bqcd.320.input b/src/data/bqcd.320.input new file mode 100644 index 0000000000000000000000000000000000000000..ceff2ca875464c44854d2bd9815d3394854f20c9 --- /dev/null +++ b/src/data/bqcd.320.input @@ -0,0 +1,86 @@ +comment "Test for Nf=2+1 with RHMC tuning" +run 320 +lattice 4 4 4 4 +boundary_conditions_fermions 1 1 1 -1 +process_mapping 1 2 3 4 +processes 1 1 1 1 + +gauge_action TREE +beta 5.5 +fermi_action SLRC +kappa 0.121095 +kappa_strange 0.120512 +csw 2.65 +n_stout 1 +alpha 0.1 + +hmc_test 0 +hmc_integrator1 2MNSTS +hmc_integrator2 2MNSTS +hmc_integrator3 2MNSTS +hmc_integrator4 2MNSTS + +hmc_model F +hmc_mpf_mass 2 +hmc_mpf_rhmc_s 2 +hmc_hkappa 1 +hmc_rho 0.1203 +hmc_accept_first 10 +hmc_trajectory_length 1.0 + +hmc_steps 5 +hmc_m_scale 2 +hmc_m_scale2 2 +hmc_m_scale3 2 + +hmc_dsf1_mtmp 3 +hmc_dsf2_mtmp 2 +hmc_dsf_ers 1 +hmc_dsd 2 +hmc_dsig 3 +hmc_dsg 4 + +start_configuration hot +io_restart_format ildg +#start_ildg_file qcdsf.699.00550.lime + +start_random 319503 +mc_steps 10 +mc_total_steps 20000 +mc_save_frequency 0 + +solver_rest 1e-11 +solver_rest_md 1e-9 +solver_rest_cg_ritz 1e-11 +solver_maxiter 1200000 +solver_stopping_criterion 1 +solver_ignore_no_convergence 0 +solver_mre_vectors 5 +solver_check_solution 0 +solver_outer_solver cg +solver_inner_solver cg +solver_outer_steps 0 + +measure_traces 1 +measure_minmax 1 +measure_polyakov_loop 1 +measure_rhmc_forces 0 +measure_cooling_list "cool.list" + +io_conf_format "ildg" +ildg_filename_prefix "qcdsf" +ildg_filename_extension "lime" +ildg_precision 64 +ildg_template_ensemble "qcdsf-ensemble-05.xml" +ildg_template_conf "qcdsf-configuration-04.xml" +ildg_markov_chain_uri "mc://ldg/qcd_collaboration/clover_nf2p1/b5p50kp121095kp120512-32x64" +ildg_data_lfn_path "lfn://ldg/qcd_collaboration/clover_nf2p1/b5p50kp121095kp120512-32x64" +ildg_participant_name "Your Name" +ildg_participant_institution "Your Institute" +ildg_machine_name "fast_runner" +ildg_machine_institution "Your Computing Centre" +ildg_machine_type "fast_computer" + +tuning_approx_range 1 +tuning_approx_range_list "rangelist" +tuning_fraction_tolerance "fractiontolerance" diff --git a/src/data/bqcd.320.output b/src/data/bqcd.320.output new file mode 100644 index 0000000000000000000000000000000000000000..00ae15ff7e7c3ed4df322b62d8df892c6e8745c8 --- /dev/null +++ b/src/data/bqcd.320.output @@ -0,0 +1,325 @@ + >BeginJob + >BeginHeader + Comment Test for Nf=2+1 with RHMC tuning + Program bqcd 4.0.0 (revision 332) + Version_of_D 100 + Communication single_pe + RandomNumbers ranlux-3.2 level 2 + Run 320 + Job 1 + Host ubuntu + Date 2011-09-22 19:05:14.740 + L 4 4 4 4 + DDL 1 1 1 1 + NPE 1 1 1 1 + process_mapping 1 2 3 4 + bc_fermions 1 1 1 -1 + gamma_index 1 2 3 4 + Gauge Action TREE + Fermi Action SLRC + tilde M 1 - T^-1 D T^-1 D + Gamma notation BQCD + eo-prec DeoDoe + BoundaryCondition normal + Threads 1 + Start 0 + Seed 319503 + Swap_seq 0 + N_force 10 + N_traj 10 + N_save 0 + N_temper 1 + beta_1 5.5 + c0_1 0.0 + c1_1 0.0 + c2_1 0.0 + c3_1 0.0 + u04_1 0.0 + kappa_1 0.121095 + kappa_strange_1 0.120512 + csw_1 2.65 + csw_kappa_1 0.320901750000000 + csw_kappa_strange_1 0.319356800000000 + n_stout_1 1 + alpha_1 0.1 + theta_1 0.0 + chemi_1 0.0 + h_1 0.0 + rho_1 0.1203 + rho2_1 0.0 + rho3_1 0.0 + rho4_1 0.0 + traj_length_1 1.0 + tau_1 0.200000000000000 + N_tau_1 5 2MNSTS ers + m_scale_1 2 2MNSTS eo2 dat + m_scale2_1 2 2MNSTS eo1 ig + m_scale3_1 2 2MNSTS g + hkappa 1 + mpf_eo[m,l,s]: 2 0 2 + mpf_dd[m,l,s]: 0 0 0 + mpf_hh[m,l,s]: 0 0 0 + HMC_model F + REAL_kind 8 + Solver_outer cg + Solver_inner cg + CG_rest 1e-11 + CG_rest_md 1e-9 + CG_stopping_criterion 1 + CG_outer_steps 0 + MRE_vectors 5 + Fullsolver eo + >EndHeader + >BeginForceAcceptance + T%fa i_fa e PlaqEnergy exp(-Delta_H) CGcalls CGitTot CGitMax CGMcalls CGMitTotCGMitMax Plaquette + T%it traj iter_SF iter_F1 iter_F2 iter_F3 iter_F4 iter_F5 iter_F6 iter_F7 iter_F8 iter_F9 + %it -9 256 4665 1469 897 0 0 0 0 0 0 + %it4 -9 0 0 0 0 0 0 0 0 0 0 + T%Favg traj F_gauge F_impg F_det F_F1 F_F2 F_F3 F_F4 F_F5 F_F6 F_F7 F_F8 F_F9 + T%Fmax traj F_gauge F_impg F_det F_F1 F_F2 F_F3 F_F4 F_F5 F_F6 F_F7 F_F8 F_F9 + T%Frat traj F_gauge F_impg F_det F_F1 F_F2 F_F3 F_F4 F_F5 F_F6 F_F7 F_F8 F_F9 + %Favg -9 7.822 0.666 1.340 2.775 0.067 0.823 0.000 0.000 0.000 0.000 0.000 0.000 + %Fmax -9 14.008 1.247 2.702 7.549 0.193 1.961 0.000 0.000 0.000 0.000 0.000 0.000 + %Frat -9 72.626 6.464 14.006 39.139 1.000 10.165 0.000 0.000 0.000 0.000 0.000 0.000 + T%Hold traj H_total H_generator H_gauge H_det H_fermion_1 H_fermion_2 H_fermion_3 + T%Hnew traj H_total H_generator H_gauge H_det H_fermion_1 H_fermion_2 H_fermion_3 + T%Hdif traj H_total H_generator H_gauge H_det H_fermion_1 H_fermion_2 H_fermion_3 + %Hold -9 0.1175206E+05 0.4065964E+04 0.7585522E+04 -0.6000883E+04 0.1567305E+04 0.1517629E+04 0.3016521E+04 + %Hnew -9 0.1175243E+05 0.5957390E+04 0.5626949E+04 -0.5967133E+04 0.1595594E+04 0.1515925E+04 0.3023703E+04 + %Hdif -9 0.3697904E+00 0.1891426E+04 -0.1958573E+04 0.3375016E+02 0.2828917E+02 -0.1704640E+01 0.7182088E+01 + %fa -9 1 0.7596780815 0.6908791076 203 6179 48 26 1108 60 0.240321918533823 + T%egnv traj type mid min max it_min it_max tol condi n_opt + %egnv -9 1 1 0.80547444E-01 2.2603050 73 41 1e-11 28.062 1.67 + %egnv -9 1 2 0.74060642E-01 2.3117457 74 39 1e-11 31.214 1.72 + %egnv -9 1 3 0.78792962E-01 2.2737198 73 41 1e-11 28.857 1.68 + %it -8 305 5273 1650 1021 0 0 0 0 0 0 + %it4 -8 0 0 0 0 0 0 0 0 0 0 + %Favg -8 8.173 0.726 1.348 2.465 0.067 0.809 0.000 0.000 0.000 0.000 0.000 0.000 + %Fmax -8 14.511 1.353 2.755 6.638 0.189 1.925 0.000 0.000 0.000 0.000 0.000 0.000 + %Frat -8 76.618 7.144 14.547 35.048 1.000 10.166 0.000 0.000 0.000 0.000 0.000 0.000 + %Hold -8 0.9777570E+04 0.4030068E+04 0.5626949E+04 -0.5967133E+04 0.1485841E+04 0.1560926E+04 0.3040919E+04 + %Hnew -8 0.9778114E+04 0.4628898E+04 0.5029892E+04 -0.5984421E+04 0.1505593E+04 0.1560220E+04 0.3037933E+04 + %Hdif -8 0.5445720E+00 0.5988301E+03 -0.5970570E+03 -0.1728829E+02 0.1975166E+02 -0.7061834E+00 -0.2985696E+01 + %fa -8 1 0.6837585513 0.5800900368 203 6981 58 26 1268 64 0.316241448723477 + %egnv -8 1 1 0.71967912E-01 2.1601388 172 64 1e-11 30.015 1.70 + %egnv -8 1 2 0.65996267E-01 2.2033538 176 62 1e-11 33.386 1.75 + %egnv -8 1 3 0.70350902E-01 2.1714299 173 63 1e-11 30.866 1.71 + %it -7 362 6315 1972 1220 0 0 0 0 0 0 + %it4 -7 0 0 0 0 0 0 0 0 0 0 + %Favg -7 8.463 0.775 1.341 2.442 0.071 0.862 0.000 0.000 0.000 0.000 0.000 0.000 + %Fmax -7 15.009 1.430 2.738 6.868 0.236 2.102 0.000 0.000 0.000 0.000 0.000 0.000 + %Frat -7 63.708 6.071 11.622 29.153 1.000 8.920 0.000 0.000 0.000 0.000 0.000 0.000 + %Hold -7 0.9293270E+04 0.4094299E+04 0.5029892E+04 -0.5984421E+04 0.1512332E+04 0.1487833E+04 0.3153335E+04 + %Hnew -7 0.9292577E+04 0.4531932E+04 0.4556032E+04 -0.5956843E+04 0.1510334E+04 0.1488096E+04 0.3163026E+04 + %Hdif -7 -0.6924984E+00 0.4376329E+03 -0.4738598E+03 0.2757786E+02 -0.1997844E+01 0.2632200E+00 0.9691162E+01 + %fa -7 1 0.6247996693 1.9987028544 203 8348 72 26 1521 87 0.375200330691069 + %egnv -7 1 1 0.35981141E-01 2.4918010 109 27 1e-11 69.253 2.12 + %egnv -7 1 2 0.31456996E-01 2.5556503 113 27 1e-11 81.243 2.20 + %egnv -7 1 3 0.34743015E-01 2.5084718 110 27 1e-11 72.201 2.14 + %it -6 409 6439 1996 1256 0 0 0 0 0 0 + %it4 -6 0 0 0 0 0 0 0 0 0 0 + %Favg -6 8.588 0.801 1.341 2.583 0.073 0.848 0.000 0.000 0.000 0.000 0.000 0.000 + %Fmax -6 15.164 1.485 2.883 6.699 0.201 2.233 0.000 0.000 0.000 0.000 0.000 0.000 + %Frat -6 75.365 7.378 14.327 33.291 1.000 11.097 0.000 0.000 0.000 0.000 0.000 0.000 + %Hold -6 0.8871121E+04 0.4101907E+04 0.4556032E+04 -0.5956843E+04 0.1567070E+04 0.1524604E+04 0.3078351E+04 + %Hnew -6 0.8870834E+04 0.4182358E+04 0.4478885E+04 -0.5981559E+04 0.1590364E+04 0.1524322E+04 0.3076463E+04 + %Hdif -6 -0.2872986E+00 0.8045064E+02 -0.7714713E+02 -0.2471534E+02 0.2329441E+02 -0.2821228E+00 -0.1887754E+01 + %fa -6 1 0.6141827725 1.3328220986 203 8518 83 26 1582 87 0.385817227526101 + %egnv -6 1 1 0.44963138E-01 2.2734220 88 50 1e-11 50.562 1.96 + %egnv -6 1 2 0.39975932E-01 2.3294475 90 48 1e-11 58.271 2.03 + %egnv -6 1 3 0.43602852E-01 2.2880089 89 50 1e-11 52.474 1.98 + %it -5 401 6831 2127 1302 0 0 0 0 0 0 + %it4 -5 0 0 0 0 0 0 0 0 0 0 + %Favg -5 8.537 0.810 1.325 2.374 0.073 0.792 0.000 0.000 0.000 0.000 0.000 0.000 + %Fmax -5 15.199 1.518 2.779 5.839 0.240 1.881 0.000 0.000 0.000 0.000 0.000 0.000 + %Frat -5 63.303 6.323 11.576 24.320 1.000 7.834 0.000 0.000 0.000 0.000 0.000 0.000 + %Hold -5 0.8651157E+04 0.4089832E+04 0.4478885E+04 -0.5981559E+04 0.1533584E+04 0.1538412E+04 0.2992002E+04 + %Hnew -5 0.8651211E+04 0.4106159E+04 0.4427728E+04 -0.5966972E+04 0.1552947E+04 0.1538339E+04 0.2993011E+04 + %Hdif -5 0.5477337E-01 0.1632714E+02 -0.5115747E+02 0.1458638E+02 0.1936273E+02 -0.7250489E-01 0.1008497E+01 + %fa -5 1 0.6078148188 0.9466996718 203 9032 74 26 1629 88 0.392185181189589 + %egnv -5 1 1 0.22020686E-01 2.4372908 104 108 1e-11 110.682 2.35 + %egnv -5 1 2 0.18135798E-01 2.5059099 109 102 1e-11 138.175 2.46 + %egnv -5 1 3 0.20945337E-01 2.4551323 105 104 1e-11 117.216 2.38 + %it -4 425 6844 2157 1326 0 0 0 0 0 0 + %it4 -4 0 0 0 0 0 0 0 0 0 0 + %Favg -4 8.590 0.817 1.341 2.382 0.075 0.815 0.000 0.000 0.000 0.000 0.000 0.000 + %Fmax -4 15.030 1.533 2.840 6.062 0.241 1.996 0.000 0.000 0.000 0.000 0.000 0.000 + %Frat -4 62.306 6.354 11.771 25.129 1.000 8.273 0.000 0.000 0.000 0.000 0.000 0.000 + %Hold -4 0.8583368E+04 0.4091101E+04 0.4427728E+04 -0.5966972E+04 0.1500592E+04 0.1498237E+04 0.3032683E+04 + %Hnew -4 0.8583295E+04 0.4195410E+04 0.4340990E+04 -0.5972497E+04 0.1494523E+04 0.1498127E+04 0.3026742E+04 + %Hdif -4 -0.7338959E-01 0.1043085E+03 -0.8673745E+02 -0.5524798E+01 -0.6068206E+01 -0.1098821E+00 -0.5941585E+01 + %fa -4 1 0.5963913517 1.0761497072 203 9085 84 26 1667 88 0.403608648280112 + %egnv -4 1 1 0.30188256E-01 2.1647060 72 43 1e-11 71.707 2.14 + %egnv -4 1 2 0.25911897E-01 2.2091327 74 42 1e-11 85.256 2.22 + %egnv -4 1 3 0.29014922E-01 2.1763178 73 43 1e-11 75.007 2.16 + %it -3 399 6806 2123 1314 0 0 0 0 0 0 + %it4 -3 0 0 0 0 0 0 0 0 0 0 + %Favg -3 8.812 0.851 1.322 2.317 0.076 0.815 0.000 0.000 0.000 0.000 0.000 0.000 + %Fmax -3 15.659 1.548 2.832 6.624 0.240 2.042 0.000 0.000 0.000 0.000 0.000 0.000 + %Frat -3 65.194 6.446 11.792 27.579 1.000 8.503 0.000 0.000 0.000 0.000 0.000 0.000 + %Hold -3 0.8614961E+04 0.4145810E+04 0.4340990E+04 -0.5972497E+04 0.1528241E+04 0.1522367E+04 0.3050051E+04 + %Hnew -3 0.8614829E+04 0.4253579E+04 0.4279267E+04 -0.5991784E+04 0.1500858E+04 0.1521232E+04 0.3051678E+04 + %Hdif -3 -0.1322136E+00 0.1077693E+03 -0.6172324E+02 -0.1928734E+02 -0.2738286E+02 -0.1135432E+01 0.1627398E+01 + %fa -3 1 0.5874913047 1.1413521318 203 9010 81 26 1632 83 0.412508695290138 + %egnv -3 1 1 0.43832460E-01 2.0903440 114 69 1e-11 47.689 1.93 + %egnv -3 1 2 0.39086749E-01 2.1258858 115 68 1e-11 54.389 2.00 + %egnv -3 1 3 0.42539370E-01 2.0996751 114 68 1e-11 49.358 1.95 + %it -2 390 7072 2166 1328 0 0 0 0 0 0 + %it4 -2 0 0 0 0 0 0 0 0 0 0 + %Favg -2 8.913 0.864 1.305 2.441 0.078 0.774 0.000 0.000 0.000 0.000 0.000 0.000 + %Fmax -2 15.503 1.622 2.583 6.663 0.219 1.881 0.000 0.000 0.000 0.000 0.000 0.000 + %Frat -2 70.650 7.390 11.770 30.363 1.000 8.574 0.000 0.000 0.000 0.000 0.000 0.000 + %Hold -2 0.8505403E+04 0.4191183E+04 0.4279267E+04 -0.5991784E+04 0.1438738E+04 0.1538052E+04 0.3049948E+04 + %Hnew -2 0.8505739E+04 0.4375281E+04 0.4115030E+04 -0.5998951E+04 0.1429807E+04 0.1538295E+04 0.3046276E+04 + %Hdif -2 0.3357357E+00 0.1840982E+03 -0.1642367E+03 -0.7167187E+01 -0.8930730E+01 0.2437728E+00 -0.3671618E+01 + %fa -2 1 0.5665927626 0.7148119804 203 9311 73 26 1645 82 0.433407237358159 + %egnv -2 1 1 0.36920538E-01 2.2540348 93 63 1e-11 61.051 2.06 + %egnv -2 1 2 0.32990080E-01 2.3051535 96 61 1e-11 69.874 2.12 + %egnv -2 1 3 0.35843769E-01 2.2673925 93 62 1e-11 63.258 2.07 + %it -1 437 8015 2453 1468 0 0 0 0 0 0 + %it4 -1 0 0 0 0 0 0 0 0 0 0 + %Favg -1 8.930 0.880 1.321 2.692 0.078 0.817 0.000 0.000 0.000 0.000 0.000 0.000 + %Fmax -1 15.259 1.577 2.784 7.084 0.243 1.970 0.000 0.000 0.000 0.000 0.000 0.000 + %Frat -1 62.868 6.496 11.469 29.187 1.000 8.115 0.000 0.000 0.000 0.000 0.000 0.000 + %Hold -1 0.8457889E+04 0.4133751E+04 0.4115030E+04 -0.5998951E+04 0.1543906E+04 0.1550057E+04 0.3114096E+04 + %Hnew -1 0.8458023E+04 0.4133266E+04 0.4063185E+04 -0.5982003E+04 0.1572062E+04 0.1549422E+04 0.3122091E+04 + %Hdif -1 0.1340397E+00 -0.4850214E+00 -0.5184522E+02 0.1694845E+02 0.2815570E+02 -0.6349218E+00 0.7995054E+01 + %fa -1 1 0.5600319796 0.8745553183 203 10547 84 26 1826 98 0.439968020414765 + %egnv -1 1 1 0.20042774E-01 2.6194113 175 22 1e-11 130.691 2.44 + %egnv -1 1 2 0.16816033E-01 2.7014528 181 21 1e-11 160.647 2.54 + %egnv -1 1 3 0.19149417E-01 2.6407393 176 22 1e-11 137.902 2.46 + %it 0 472 8210 2550 1532 0 0 0 0 0 0 + %it4 0 0 0 0 0 0 0 0 0 0 0 + %Favg 0 8.948 0.890 1.310 2.576 0.079 0.785 0.000 0.000 0.000 0.000 0.000 0.000 + %Fmax 0 14.994 1.600 2.652 7.319 0.257 1.987 0.000 0.000 0.000 0.000 0.000 0.000 + %Frat 0 58.396 6.233 10.328 28.503 1.000 7.738 0.000 0.000 0.000 0.000 0.000 0.000 + %Hold 0 0.8333884E+04 0.4060687E+04 0.4063185E+04 -0.5982003E+04 0.1622086E+04 0.1520595E+04 0.3049334E+04 + %Hnew 0 0.8334040E+04 0.4222592E+04 0.3927838E+04 -0.5981661E+04 0.1589964E+04 0.1519281E+04 0.3056026E+04 + %Hdif 0 0.1560512E+00 0.1619053E+03 -0.1353465E+03 0.3424912E+00 -0.3212229E+02 -0.1314248E+01 0.6691298E+01 + %fa 0 1 0.5423157268 0.8555154010 203 10854 94 26 1910 98 0.457684273243757 + %egnv 0 1 1 0.21789647E-01 2.0954160 183 71 1e-11 96.166 2.28 + %egnv 0 1 2 0.18398977E-01 2.1337724 187 70 1e-11 115.972 2.38 + %egnv 0 1 3 0.20852837E-01 2.1054654 184 71 1e-11 100.968 2.31 + >EndForceAcceptance + >BeginILDGwrite + ildg-write file bqcd.320.lime + ildg-write precision 64 + ildg-write bytes 147456 + ildg-write cksum 623338568 + ildg-write lfn bqcd-restart bqcd.320.lime 623338568 147456 320 1 0 + >EndILDGwrite + >BeginFooter + Date 2011-09-22 19:10:06.135 + Seed -1 + CPU-Time 289.6 s on 1 CPUs + >BeginTiming + Performance + region #calls time mean min max Total + s Mflop/s Mflop/s Mflop/s Gflop/s + + d_xf 490542 8.81 2052.93 2052.93 2052.93 2.05 + d_xb 0 + d_yf 490542 11.18 1751.53 1751.53 1751.53 1.75 + d_yb 0 + d_zf 490542 10.92 1794.52 1794.52 1794.52 1.79 + d_zb 0 + d_t 490542 10.37 1888.65 1888.65 1888.65 1.89 + d_fb 0 + d_dag_fb 0 + d_xyzt 0 + sc2_projection 490542 7.45 606.95 606.95 606.95 0.61 + D_TOTAL 490542 50.16 1622.47 1622.47 1622.47 1.62 + d_dd 0 + d_eo 0 + MTDAGMT 112768 65.77 1643.41 1643.41 1643.41 1.64 + CG 2030 54.14 1641.78 1641.78 1641.78 1.64 + CG_DD 0 + CG_HH 0 + cg_global_sum 0 + global_sum 0 + global_sum_vec 0 + sc_zero 14060 0.46 + sc_copy 121948 0.45 + sc_scale 9902 0.05 633.68 633.68 633.68 0.63 + sc_norm2 42693 0.18 1457.14 1457.14 1457.14 1.46 + sc_dot 49276 0.25 1220.69 1220.69 1220.69 1.22 + sc_axpy 97908 0.43 1392.39 1392.39 1392.39 1.39 + sc_xpby 340679 1.62 1291.99 1291.99 1291.99 1.29 + sc_axpby 74386 0.54 1278.92 1278.92 1278.92 1.28 + sc_cdotc 29180 0.17 2084.55 2084.55 2084.55 2.08 + sc_caxpy 1940 0.02 1489.92 1489.92 1489.92 1.49 + sc_caxpy2 1940 0.03 1489.83 1489.83 1489.83 1.49 + sc_cax2 1980 0.02 3041.09 3041.09 3041.09 3.04 + clover_init 2403 4.72 + clover_mult_a 0 + clover_mult_ao 478632 18.53 1825.14 1825.14 1825.14 1.83 + clover_mult_b 35560 1.40 1799.69 1799.69 1799.69 1.80 + clover_dsd 410 4.76 + clover_dsf 0 + hmc_init 10 0.07 + hmc_init_p 10 0.01 + hmc_u 6400 6.65 + hmc_momenta 0 + hmc_phi 10 12.70 + hmc_h_old 10 12.74 + hmc_backup 10 0.01 + hmc_half_step0 0 + hmc_half_step1 0 + hmc_xbound_g 10541 0.00 + hmc_steps 8540 266.77 + hmc_h_new 10 0.02 + hmc_rest 10 0.01 + HMC 10 286.29 + h_mult_a 0 + h_mult_b 0 + h_mult_c 0 + dsg 6410 8.38 + dsf 2020 36.03 + plaquette 21 0.00 +Inf +Inf +Inf +Inf + cooling 0 + ran_gauss_volh 128 0.01 + MTDAGMT_r4 0 + dsig 1610 10.54 + rectangle 20 0.04 1244.90 1244.90 1244.90 1.24 + chair 0 + parallelogram 0 + stout_smear 1601 4.02 1560.69 1560.69 1560.69 1.56 + stout_diffe 2540 13.62 2156.77 2156.77 2156.77 2.16 + clover_bsa_w 7940 1.50 1243.90 1243.90 1243.90 1.24 + clover_dsd_w 1640 1.24 1381.71 1381.71 1381.71 1.38 + clover_d_w 5900 15.46 1953.13 1953.13 1953.13 1.95 + dsf_at_bt 3970 1.58 1188.63 1188.63 1188.63 1.19 + dsf_xyztfb_w 3970 2.30 1757.28 1757.28 1757.28 1.76 + dsf_sum 3970 6.87 1134.63 1134.63 1134.63 1.13 + dsf_w2gen 2540 28.96 1933.72 1933.72 1933.72 1.93 + cgm 260 10.18 1603.75 1603.75 1603.75 1.60 + cg_ritz 82 4.41 1657.54 1657.54 1657.54 1.66 + cg_mix 0 + bicgstab 0 + bicgstab_mix 0 + ddbqnohat 0 + unprec_mmul 0 + unprec_dsf 0 + dsf_un 0 + dsf_mtmp 2020 102.46 + cg_mre_mtmp 2020 57.25 + dsf_wmul_r8 2020 0.52 + dsf_wdag_r8 410 0.22 + integrator 10 273.44 + bagel_d 0 + TOTAL 1 289.59 + + Performance + region #calls time mean min max Total + s MByte/s MByte/s MByte/s GByte/s + + xbound_g 0 + xbound_sc 0 + xbound_sc2 0 + u_read_bqcd 0 + u_write_bqcd 0 + u_read_ildg 0 + u_write_ildg 1 0.00 +Inf +Inf +Inf +Inf + >EndTiming + >EndFooter + >EndJob diff --git a/src/data/bqcd.500.input b/src/data/bqcd.500.input new file mode 100644 index 0000000000000000000000000000000000000000..b8edda39936a3d6f6876fe5c05f9d239f344b53d --- /dev/null +++ b/src/data/bqcd.500.input @@ -0,0 +1,84 @@ +comment "Test for NF = 3 SLOC with SF boundary condition" +run 500 +lattice 4 4 4 4 +boundary_conditions_fermions 1 1 1 -1 +boundary_sf 1 +process_mapping 1 2 3 4 +processes 1 1 1 2 + +gauge_action IWASAKI +beta 2.6 +fermi_action SLOC +kappa 0.125 +kappa_strange 0.125 +csw 1.00 +n_stout 1 +alpha 0.1 + +hmc_test 0 +hmc_integrator1 2MNSTS +hmc_integrator2 2MNSTS +hmc_integrator3 2MNSTS +hmc_integrator4 2MNSTS + +hmc_model F +hmc_mpf_mass 2 +hmc_mpf_rhmc_s 2 +hmc_hkappa 1 +hmc_rho 0.12 +hmc_accept_first 5 +hmc_trajectory_length 1.0 + +hmc_steps 5 +hmc_m_scale 2 +hmc_m_scale2 2 +hmc_m_scale3 2 + +hmc_dsf1_mtmp 3 +hmc_dsf2_mtmp 2 +hmc_dsf_ers 1 +hmc_dsd 2 +hmc_dsig 3 +hmc_dsg 4 + +start_configuration hot +io_restart_format ildg +#start_ildg_file qcdsf.699.00550.lime + +start_random 319503 +mc_steps 10 +mc_total_steps 20000 +mc_save_frequency 0 + +solver_rest 1e-11 +solver_rest_md 1e-9 +solver_rest_cg_ritz 1e-11 +solver_maxiter 1200000 +solver_stopping_criterion 1 +solver_ignore_no_convergence 0 +solver_mre_vectors 5 +solver_check_solution 0 +solver_outer_solver cg +solver_inner_solver cg +solver_outer_steps 0 + +measure_traces 1 +measure_minmax 1 +measure_polyakov_loop 1 +measure_rhmc_forces 0 +measure_cooling_list "cool.list" +measure_schrpcac 2 + +io_conf_format "ildg" +ildg_filename_prefix "sloc_sf_nf2p1" +ildg_filename_extension "lime" +ildg_precision 64 +ildg_template_ensemble "qcdsf-ensemble-05.xml" +ildg_template_conf "qcdsf-configuration-04.xml" +ildg_markov_chain_uri "mc://ldg/qcd_collaboration/sloc_nf2p1/b2p60kp125000kp125000-4x4" +ildg_data_lfn_path "lfn://ldg/qcd_collaboration/sloc_nf2p1/b2p60kp125000kp125000-4x4" +ildg_participant_name "Your Name" +ildg_participant_institution "Your Institute" +ildg_machine_name "fast_runner" +ildg_machine_institution "Your Computing Centre" +ildg_machine_type "fast_computer" diff --git a/src/data/bqcd.500.output b/src/data/bqcd.500.output new file mode 100644 index 0000000000000000000000000000000000000000..cf77a9d7c15f485d8918b7904b87515687a4197e --- /dev/null +++ b/src/data/bqcd.500.output @@ -0,0 +1,430 @@ + >BeginJob + >BeginHeader + Comment Test for NF = 3 SLOC with SF boundary condition + Program bqcd 4.0.0 (revision 324) + Version_of_D 100 + Communication MPI (sc:immediate) (g:immediate) + RandomNumbers ranlux-3.2 level 2 + Run 500 + Job 1 + Host m500 + Date 2011-09-21 14:58:36.031 + L 4 4 4 4 + DDL 1 1 1 1 + NPE 1 1 1 2 + process_mapping 1 2 3 4 + bc_fermions 1 1 1 -1 + gamma_index 1 2 3 4 + Gauge Action IWASAKI + Fermi Action SLOC + tilde M 1 - T^-1 D T^-1 D + Gamma notation BQCD + eo-prec DeoDoe + BoundaryCondition schr + Threads 1 + Start 0 + Seed 319503 + Swap_seq 0 + N_force 5 + N_traj 10 + N_save 0 + N_temper 1 + beta_1 2.6 + c0_1 0.0 + c1_1 0.0 + c2_1 0.0 + c3_1 0.0 + u04_1 0.0 + kappa_1 0.125 + kappa_strange_1 0.125 + csw_1 1.00 + csw_kappa_1 0.125000000000000 + csw_kappa_strange_1 0.125000000000000 + n_stout_1 1 + alpha_1 0.1 + theta_1 0.0 + chemi_1 0.0 + h_1 0.0 + rho_1 0.12 + rho2_1 0.0 + rho3_1 0.0 + rho4_1 0.0 + traj_length_1 1.0 + tau_1 0.200000000000000 + N_tau_1 5 2MNSTS ers + m_scale_1 2 2MNSTS eo2 dat + m_scale2_1 2 2MNSTS eo1 ig + m_scale3_1 2 2MNSTS g + hkappa 1 + mpf_eo[m,l,s]: 2 0 2 + mpf_dd[m,l,s]: 0 0 0 + mpf_hh[m,l,s]: 0 0 0 + HMC_model F + REAL_kind 8 + Solver_outer cg + Solver_inner cg + CG_rest 1e-11 + CG_rest_md 1e-9 + CG_stopping_criterion 1 + CG_outer_steps 0 + MRE_vectors 5 + Fullsolver eo + >EndHeader + >BeginForceAcceptance + T%fa i_fa e PlaqEnergy exp(-Delta_H) CGcalls CGitTot CGitMax CGMcalls CGMitTotCGMitMax Plaquette + T%it traj iter_SF iter_F1 iter_F2 iter_F3 iter_F4 iter_F5 iter_F6 iter_F7 iter_F8 iter_F9 + %it -4 140 1813 676 543 0 0 0 0 0 0 + %it4 -4 0 0 0 0 0 0 0 0 0 0 + T%Favg traj F_gauge F_impg F_det F_F1 F_F2 F_F3 F_F4 F_F5 F_F6 F_F7 F_F8 F_F9 + T%Fmax traj F_gauge F_impg F_det F_F1 F_F2 F_F3 F_F4 F_F5 F_F6 F_F7 F_F8 F_F9 + T%Frat traj F_gauge F_impg F_det F_F1 F_F2 F_F3 F_F4 F_F5 F_F6 F_F7 F_F8 F_F9 + %Favg -4 11.969 1.907 0.133 1.015 0.093 0.343 0.000 0.000 0.000 0.000 0.000 0.000 + %Fmax -4 23.962 3.999 0.390 3.814 0.305 1.098 0.000 0.000 0.000 0.000 0.000 0.000 + %Frat -4 78.527 13.105 1.277 12.500 1.000 3.598 0.000 0.000 0.000 0.000 0.000 0.000 + T%Hold traj H_total H_generator H_gauge H_det H_fermion_1 H_fermion_2 H_fermion_3 + T%Hnew traj H_total H_generator H_gauge H_det H_fermion_1 H_fermion_2 H_fermion_3 + T%Hdif traj H_total H_generator H_gauge H_det H_fermion_1 H_fermion_2 H_fermion_3 + %Hold -4 0.1353317E+05 0.3328837E+04 0.1044373E+05 -0.6340852E+04 0.1567305E+04 0.1517629E+04 0.3016521E+04 + %Hnew -4 0.1353309E+05 0.6587449E+04 0.7122485E+04 -0.6333897E+04 0.1624378E+04 0.1514455E+04 0.3018221E+04 + %Hdif -4 -0.7839827E-01 0.3258611E+04 -0.3321243E+04 0.6954870E+01 0.5707333E+02 -0.3174790E+01 0.1700152E+01 + %fa -4 1 0.6403763201 1.0815533263 203 2513 24 26 659 31 0.359623679903077 + T%egnv traj type mid min max it_min it_max tol condi n_opt + %egnv -4 1 1 0.28834255 1.5954759 208 201 1e-11 5.533 0.86 + %egnv -4 1 2 0.24655254 1.6618200 184 174 1e-11 6.740 0.95 + %it -3 158 1953 721 604 0 0 0 0 0 0 + %it4 -3 0 0 0 0 0 0 0 0 0 0 + %Favg -3 12.553 2.201 0.120 0.821 0.091 0.326 0.000 0.000 0.000 0.000 0.000 0.000 + %Fmax -3 25.092 4.704 0.354 2.951 0.336 1.095 0.000 0.000 0.000 0.000 0.000 0.000 + %Frat -3 74.652 13.994 1.054 8.780 1.000 3.259 0.000 0.000 0.000 0.000 0.000 0.000 + %Hold -3 0.1012980E+05 0.3253521E+04 0.7122485E+04 -0.6333897E+04 0.1485841E+04 0.1560926E+04 0.3040919E+04 + %Hnew -3 0.1012977E+05 0.4892391E+04 0.5466292E+04 -0.6336889E+04 0.1505175E+04 0.1559668E+04 0.3043132E+04 + %Hdif -3 -0.2603294E-01 0.1638870E+04 -0.1656193E+04 -0.2992339E+01 0.1933409E+02 -0.1258284E+01 0.2213295E+01 + %fa -3 1 0.5095041109 1.0263747607 203 2700 26 26 736 35 0.490495889066937 + %egnv -3 1 1 0.22292913 1.5352529 136 117 1e-11 6.887 0.96 + %egnv -3 1 2 0.18196947 1.5951492 114 106 1e-11 8.766 1.09 + %it -2 180 2148 814 694 0 0 0 0 0 0 + %it4 -2 0 0 0 0 0 0 0 0 0 0 + %Favg -2 13.333 2.602 0.110 0.790 0.077 0.299 0.000 0.000 0.000 0.000 0.000 0.000 + %Fmax -2 26.488 5.253 0.347 2.737 0.268 0.922 0.000 0.000 0.000 0.000 0.000 0.000 + %Frat -2 98.896 19.611 1.296 10.218 1.000 3.442 0.000 0.000 0.000 0.000 0.000 0.000 + %Hold -2 0.8551774E+04 0.3268872E+04 0.5466292E+04 -0.6336889E+04 0.1512332E+04 0.1487833E+04 0.3153335E+04 + %Hnew -2 0.8551737E+04 0.4281175E+04 0.4423581E+04 -0.6342926E+04 0.1546757E+04 0.1487999E+04 0.3155153E+04 + %Hdif -2 -0.3675218E-01 0.1012303E+04 -0.1042711E+04 -0.6036714E+01 0.3442507E+02 0.1658554E+00 0.1817786E+01 + %fa -2 1 0.4221582027 1.0374358890 203 2991 29 26 845 40 0.577841797250672 + %egnv -2 1 1 0.17321410 1.5045685 83 101 1e-11 8.686 1.08 + %egnv -2 1 2 0.13402399 1.5608876 84 99 1e-11 11.646 1.23 + %it -1 200 2403 924 791 0 0 0 0 0 0 + %it4 -1 0 0 0 0 0 0 0 0 0 0 + %Favg -1 13.738 2.935 0.102 0.787 0.074 0.278 0.000 0.000 0.000 0.000 0.000 0.000 + %Fmax -1 26.693 5.888 0.314 2.626 0.246 0.944 0.000 0.000 0.000 0.000 0.000 0.000 + %Frat -1 108.583 23.952 1.278 10.682 1.000 3.838 0.000 0.000 0.000 0.000 0.000 0.000 + %Hold -1 0.7535292E+04 0.3284612E+04 0.4423581E+04 -0.6342926E+04 0.1567070E+04 0.1524604E+04 0.3078351E+04 + %Hnew -1 0.7535287E+04 0.3855255E+04 0.3821653E+04 -0.6352040E+04 0.1607377E+04 0.1521737E+04 0.3081305E+04 + %Hdif -1 -0.5262236E-02 0.5706422E+03 -0.6019280E+03 -0.9113573E+01 0.4030737E+02 -0.2867415E+01 0.2954164E+01 + %fa -1 1 0.3669784832 1.0052761059 203 3360 33 26 958 43 0.633021516761825 + %egnv -1 1 1 0.14037653 1.4771079 51 125 1e-11 10.522 1.18 + %egnv -1 1 2 0.10385173 1.5298162 53 131 1e-11 14.731 1.34 + %it 0 210 2417 934 811 0 0 0 0 0 0 + %it4 0 0 0 0 0 0 0 0 0 0 0 + %Favg 0 13.894 3.116 0.095 0.703 0.073 0.265 0.000 0.000 0.000 0.000 0.000 0.000 + %Fmax 0 27.319 6.172 0.285 2.353 0.258 0.772 0.000 0.000 0.000 0.000 0.000 0.000 + %Frat 0 105.926 23.930 1.105 9.124 1.000 2.995 0.000 0.000 0.000 0.000 0.000 0.000 + %Hold 0 0.6858386E+04 0.3324775E+04 0.3821653E+04 -0.6352040E+04 0.1533584E+04 0.1538412E+04 0.2992002E+04 + %Hnew 0 0.6858434E+04 0.3737309E+04 0.3405203E+04 -0.6355276E+04 0.1544475E+04 0.1536458E+04 0.2990265E+04 + %Hdif 0 0.4775611E-01 0.4125340E+03 -0.4164499E+03 -0.3236873E+01 0.1089132E+02 -0.1953300E+01 -0.1737470E+01 + %fa 0 1 0.3308996721 0.9533662705 203 3387 36 26 985 44 0.669100327909929 + %egnv 0 1 1 0.13398230 1.4625602 66 172 1e-11 10.916 1.20 + %egnv 0 1 2 0.98898742E-01 1.5141982 69 144 1e-11 15.311 1.36 + >EndForceAcceptance + >BeginMC + T%mc traj e f PlaqEnergy exp(-Delta_H) Acc CGcalls CGitTot CGitMax CGMcalls CGMitTotCGMitMax Plaquette + T%pr traj Plaquette PlaquetteS PlaquetteT Rectangle RectangleS RectangleT + %it 1 217 2558 989 844 0 0 0 0 0 0 + %it4 1 0 0 0 0 0 0 0 0 0 0 + %Favg 1 13.872 3.229 0.092 0.681 0.067 0.251 0.000 0.000 0.000 0.000 0.000 0.000 + %Fmax 1 26.320 6.386 0.294 2.050 0.237 0.731 0.000 0.000 0.000 0.000 0.000 0.000 + %Frat 1 111.051 26.945 1.240 8.651 1.000 3.083 0.000 0.000 0.000 0.000 0.000 0.000 + %Hold 1 0.6439580E+04 0.3358143E+04 0.3405203E+04 -0.6355276E+04 0.1500592E+04 0.1498237E+04 0.3032683E+04 + %Hnew 1 0.6439607E+04 0.3598377E+04 0.3160033E+04 -0.6359956E+04 0.1502431E+04 0.1497283E+04 0.3041440E+04 + %Hdif 1 0.2629737E-01 0.2402337E+03 -0.2451698E+03 -0.4679659E+01 0.1839244E+01 -0.9537493E+00 0.8756494E+01 + %mc 1 1 1 0.3308996721 0.9740453962 0 203 3583 36 26 1025 47 0.669100327909929 + %pr 1 0.6691003279099 0.7103594558126 0.6278412000072 0.4361414142395 0.5404177165891 0.3318651118898 + %egnv 1 1 1 0.13398230 1.4625602 66 172 1e-11 10.916 1.20 + %egnv 1 1 2 0.98898742E-01 1.5141982 69 144 1e-11 15.311 1.36 + T%tr traj e f Re(pbp) Im(pbp) Re(p5p) -Im(p5p) PionNorm CGiter + %tr 1 1 1 0.9999381170 0.6847212568E-02 0.2858814583E-01 -0.2984331532E-13 1.339078457 42 + T%pl traj e f Re(Polyakov_Loop) Im(Polyakov_Loop) + %pl 1 1 1 0.3016057535E-01 -0.4070000346E-01 + >BeginCooling + T%Qc traj e f i_cool Q_cool PlaqEnergy + %Qc 1 1 1 0 0.100011 0.3308996721 + %Qc 1 1 1 1 -0.165165 0.0739625797 + %Qc 1 1 1 2 -0.205936 0.0319064791 + %Qc 1 1 1 3 -0.183866 0.0220630186 + %Qc 1 1 1 4 -0.048702 0.0148323759 + %Qc 1 1 1 5 0.002249 0.0085176063 + %Qc 1 1 1 6 0.001282 0.0058336262 + %Qc 1 1 1 7 0.000569 0.0041532745 + %Qc 1 1 1 8 0.000282 0.0029480171 + %Qc 1 1 1 9 0.000156 0.0020859537 + %Qc 1 1 1 10 0.000092 0.0014810796 + %Qc 1 1 1 20 0.000001 0.0000991833 + %Qc 1 1 1 30 0.000000 0.0000244502 + %Qc 1 1 1 40 0.000000 0.0000099754 + %Qc 1 1 1 50 0.000000 0.0000046650 + >EndCooling + %it 2 211 2556 958 812 0 0 0 0 0 0 + %it4 2 0 0 0 0 0 0 0 0 0 0 + %Favg 2 13.828 3.195 0.093 0.650 0.062 0.268 0.000 0.000 0.000 0.000 0.000 0.000 + %Fmax 2 27.707 6.262 0.271 2.115 0.222 0.879 0.000 0.000 0.000 0.000 0.000 0.000 + %Frat 2 124.799 28.205 1.219 9.526 1.000 3.958 0.000 0.000 0.000 0.000 0.000 0.000 + %Hold 2 0.6486785E+04 0.3312116E+04 0.3405203E+04 -0.6355276E+04 0.1472883E+04 0.1513182E+04 0.3138677E+04 + %Hnew 2 0.6486778E+04 0.3551641E+04 0.3164872E+04 -0.6358044E+04 0.1473591E+04 0.1512692E+04 0.3142025E+04 + %Hdif 2 -0.6510001E-02 0.2395252E+03 -0.2403305E+03 -0.2767806E+01 0.7084518E+00 -0.4897941E+00 0.3348034E+01 + %mc 2 1 1 0.3089093866 1.0065312371 1 203 3550 36 26 987 44 0.691090613380691 + %pr 2 0.6910906133807 0.7292952490493 0.6528859777121 0.4664056383772 0.5594542291118 0.3733570476425 + %egnv 2 1 1 0.11964747 1.4555103 44 190 1e-11 12.165 1.25 + %egnv 2 1 2 0.84075806E-01 1.5056874 44 150 1e-11 17.909 1.44 + %tr 2 1 1 0.9626272480 0.6054419022E-02 -0.1158633808E-01 0.2479960681E-12 1.291148724 43 + T%pl traj e f Re(Polyakov_Loop) Im(Polyakov_Loop) + %pl 2 1 1 0.4925754427E-01 -0.1780255773E-01 + >BeginCooling + T%Qc traj e f i_cool Q_cool PlaqEnergy + %Qc 2 1 1 0 0.018397 0.3089093866 + %Qc 2 1 1 1 -0.240196 0.0647824863 + %Qc 2 1 1 2 -0.107894 0.0261583439 + %Qc 2 1 1 3 -0.002293 0.0169589792 + %Qc 2 1 1 4 0.002243 0.0132628318 + %Qc 2 1 1 5 0.000698 0.0115473548 + %Qc 2 1 1 6 0.000064 0.0104928863 + %Qc 2 1 1 7 -0.000101 0.0097335443 + %Qc 2 1 1 8 -0.000110 0.0091403237 + %Qc 2 1 1 9 -0.000086 0.0086579321 + %Qc 2 1 1 10 -0.000062 0.0082578917 + %Qc 2 1 1 20 -0.000001 0.0065495476 + %Qc 2 1 1 30 0.000000 0.0063734802 + %Qc 2 1 1 40 0.000000 0.0063643737 + %Qc 2 1 1 50 0.000000 0.0063639128 + >EndCooling + %it 3 219 2653 995 848 0 0 0 0 0 0 + %it4 3 0 0 0 0 0 0 0 0 0 0 + %Favg 3 13.701 3.223 0.093 0.634 0.067 0.256 0.000 0.000 0.000 0.000 0.000 0.000 + %Fmax 3 27.302 6.219 0.268 2.011 0.230 0.718 0.000 0.000 0.000 0.000 0.000 0.000 + %Frat 3 118.859 27.076 1.165 8.755 1.000 3.125 0.000 0.000 0.000 0.000 0.000 0.000 + %Hold 3 0.6288030E+04 0.3274797E+04 0.3164872E+04 -0.6358044E+04 0.1538466E+04 0.1598029E+04 0.3069910E+04 + %Hnew 3 0.6288033E+04 0.3520550E+04 0.2930023E+04 -0.6360813E+04 0.1530841E+04 0.1597144E+04 0.3070288E+04 + %Hdif 3 0.2170062E-02 0.2457526E+03 -0.2348488E+03 -0.2768719E+01 -0.7625328E+01 -0.8851877E+00 0.3776214E+00 + %mc 3 1 1 0.2877975361 0.9978322904 1 203 3685 37 26 1030 47 0.712202463855429 + %pr 3 0.7122024638554 0.7457785420516 0.6786263856593 0.4909658922262 0.5805268609120 0.4014049235404 + %egnv 3 1 1 0.10359238 1.4544668 52 90 1e-11 14.040 1.32 + %egnv 3 1 2 0.70809733E-01 1.5044999 53 87 1e-11 21.247 1.53 + %tr 3 1 1 0.9979471357 -0.1349950405E-01 -0.1656489454E-01 -0.1794951629E-12 1.332780917 46 + T%pl traj e f Re(Polyakov_Loop) Im(Polyakov_Loop) + %pl 3 1 1 -0.3301207588E-02 0.2980887108E-01 + >BeginCooling + T%Qc traj e f i_cool Q_cool PlaqEnergy + %Qc 3 1 1 0 -0.140438 0.2877975361 + %Qc 3 1 1 1 -0.129074 0.0562804469 + %Qc 3 1 1 2 -0.026330 0.0212599437 + %Qc 3 1 1 3 -0.003973 0.0146786235 + %Qc 3 1 1 4 -0.000766 0.0120516379 + %Qc 3 1 1 5 -0.000084 0.0104835686 + %Qc 3 1 1 6 0.000129 0.0093645081 + %Qc 3 1 1 7 0.000171 0.0085185980 + %Qc 3 1 1 8 0.000148 0.0078720753 + %Qc 3 1 1 9 0.000108 0.0073775620 + %Qc 3 1 1 10 0.000074 0.0069954100 + %Qc 3 1 1 20 0.000021 0.0038478929 + %Qc 3 1 1 30 0.000000 0.0007432523 + %Qc 3 1 1 40 0.000000 0.0001803892 + %Qc 3 1 1 50 0.000000 0.0000521749 + >EndCooling + %it 4 228 2705 1064 892 0 0 0 0 0 0 + %it4 4 0 0 0 0 0 0 0 0 0 0 + %Favg 4 13.786 3.308 0.091 0.625 0.066 0.240 0.000 0.000 0.000 0.000 0.000 0.000 + %Fmax 4 27.127 6.298 0.257 2.039 0.227 0.669 0.000 0.000 0.000 0.000 0.000 0.000 + %Frat 4 119.667 27.781 1.133 8.995 1.000 2.953 0.000 0.000 0.000 0.000 0.000 0.000 + %Hold 4 0.5939915E+04 0.3344712E+04 0.2930023E+04 -0.6360813E+04 0.1470273E+04 0.1503656E+04 0.3052064E+04 + %Hnew 4 0.5939903E+04 0.3419307E+04 0.2857422E+04 -0.6364466E+04 0.1468675E+04 0.1502515E+04 0.3056452E+04 + %Hdif 4 -0.1205339E-01 0.7459468E+02 -0.7260170E+02 -0.3653531E+01 -0.1597750E+01 -0.1141256E+01 0.4387499E+01 + %mc 4 1 1 0.2794366907 1.0121263279 1 203 3808 39 26 1081 48 0.720563309324562 + %pr 4 0.7205633093246 0.7568515371242 0.6842750815249 0.5085721133937 0.6007310495502 0.4164131772373 + %egnv 4 1 1 0.93922095E-01 1.4387702 109 165 1e-11 15.319 1.36 + %egnv 4 1 2 0.64538209E-01 1.4842517 112 157 1e-11 22.998 1.57 + %tr 4 1 1 0.9638769916 0.2222270705E-02 0.1376794116E-01 0.7289365870E-13 1.368055721 47 + T%pl traj e f Re(Polyakov_Loop) Im(Polyakov_Loop) + %pl 4 1 1 -0.9120799282E-01 -0.4153638231E-01 + >BeginCooling + T%Qc traj e f i_cool Q_cool PlaqEnergy + %Qc 4 1 1 0 0.055734 0.2794366907 + %Qc 4 1 1 1 0.003262 0.0517110339 + %Qc 4 1 1 2 -0.004106 0.0187900157 + %Qc 4 1 1 3 -0.004067 0.0140341068 + %Qc 4 1 1 4 -0.002966 0.0122466265 + %Qc 4 1 1 5 -0.001872 0.0111330628 + %Qc 4 1 1 6 -0.001118 0.0102962633 + %Qc 4 1 1 7 -0.000651 0.0096219791 + %Qc 4 1 1 8 -0.000380 0.0090631132 + %Qc 4 1 1 9 -0.000226 0.0085939522 + %Qc 4 1 1 10 -0.000137 0.0081968897 + %Qc 4 1 1 20 0.000000 0.0065305824 + %Qc 4 1 1 30 0.000000 0.0063895949 + %Qc 4 1 1 40 0.000000 0.0063736269 + %Qc 4 1 1 50 0.000000 0.0063688610 + >EndCooling + %it 5 229 2604 1021 871 0 0 0 0 0 0 + %it4 5 0 0 0 0 0 0 0 0 0 0 + %Favg 5 13.769 3.318 0.089 0.623 0.064 0.245 0.000 0.000 0.000 0.000 0.000 0.000 + %Fmax 5 27.575 6.460 0.245 1.973 0.211 0.736 0.000 0.000 0.000 0.000 0.000 0.000 + %Frat 5 130.700 30.619 1.161 9.352 1.000 3.489 0.000 0.000 0.000 0.000 0.000 0.000 + %Hold 5 0.5885801E+04 0.3322794E+04 0.2857422E+04 -0.6364466E+04 0.1482208E+04 0.1552593E+04 0.3035250E+04 + %Hnew 5 0.5885814E+04 0.3346498E+04 0.2816848E+04 -0.6364621E+04 0.1487581E+04 0.1552820E+04 0.3046688E+04 + %Hdif 5 0.1335233E-01 0.2370463E+02 -0.4057337E+02 -0.1545538E+00 0.5372505E+01 0.2261831E+00 0.1143796E+02 + %mc 5 1 1 0.2754950257 0.9867364154 1 203 3665 40 26 1060 48 0.724504974250426 + %pr 5 0.7245049742504 0.7597969141072 0.6892130343936 0.5138221231837 0.6064981158920 0.4211461304753 + %egnv 5 1 1 0.11162166 1.4403753 126 100 1e-11 12.904 1.28 + %egnv 5 1 2 0.80293203E-01 1.4859246 161 99 1e-11 18.506 1.46 + %tr 5 1 1 1.006534943 0.9327805670E-02 -0.7410992775E-02 0.6217191114E-13 1.377875934 44 + T%pl traj e f Re(Polyakov_Loop) Im(Polyakov_Loop) + %pl 5 1 1 -0.6897297645E-02 -0.6018785038E-01 + >BeginCooling + T%Qc traj e f i_cool Q_cool PlaqEnergy + %Qc 5 1 1 0 -0.013628 0.2754950257 + %Qc 5 1 1 1 -0.006776 0.0483737677 + %Qc 5 1 1 2 0.006194 0.0173583212 + %Qc 5 1 1 3 0.002384 0.0125600902 + %Qc 5 1 1 4 0.000844 0.0106245124 + %Qc 5 1 1 5 0.000338 0.0094371793 + %Qc 5 1 1 6 0.000156 0.0085793905 + %Qc 5 1 1 7 0.000084 0.0079107498 + %Qc 5 1 1 8 0.000054 0.0073601425 + %Qc 5 1 1 9 0.000041 0.0068781819 + %Qc 5 1 1 10 0.000036 0.0064257806 + %Qc 5 1 1 20 0.000005 0.0014611870 + %Qc 5 1 1 30 0.000000 0.0002225256 + %Qc 5 1 1 40 0.000000 0.0000446238 + %Qc 5 1 1 50 0.000000 0.0000110227 + >EndCooling + >EndMC + >BeginILDGwrite + ildg-write file bqcd.500.lime + ildg-write precision 64 + ildg-write bytes 147456 + ildg-write cksum 3744829595 + ildg-write lfn bqcd-restart bqcd.500.lime 3744829595 147456 500 1 5 + >EndILDGwrite + >BeginFooter + Date 2011-09-21 14:59:40.073 + Seed -1 + CPU-Time 64.0 s on 2 CPUs + >BeginTiming + Performance + region #calls time mean min max Total + s Mflop/s Mflop/s Mflop/s Gflop/s + + d_xf 283140 1.82 2871.87 2867.91 2875.83 5.74 + d_xb 0 + d_yf 283140 1.48 3820.61 3805.19 3836.16 7.64 + d_yb 0 + d_zf 283140 1.35 4191.68 4179.34 4204.11 8.38 + d_zb 0 + d_t 283140 1.50 3781.04 3747.21 3815.48 7.56 + d_fb 0 + d_dag_fb 0 + d_xyzt 0 + sc2_projection 283140 1.68 778.82 776.27 781.38 1.56 + D_TOTAL 283140 13.64 1721.13 1720.88 1721.38 3.44 + d_dd 0 + d_eo 0 + MTDAGMT 53162 13.69 1861.20 1858.69 1863.72 3.72 + CG 2083 9.94 1824.37 1822.81 1825.93 3.65 + CG_DD 0 + CG_HH 0 + cg_global_sum 0 + global_sum 87814 0.15 + global_sum_vec 75308 0.23 + sc_zero 39914 0.33 + sc_copy 75915 0.11 + sc_scale 9882 0.01 2335.55 2168.70 2530.21 4.67 + sc_norm2 36347 0.04 3146.14 3018.84 3284.64 6.29 + sc_dot 42996 0.02 5621.18 5284.19 6004.08 11.24 + sc_axpy 214318 0.07 8838.92 8664.21 9020.82 17.68 + sc_xpby 167999 0.06 8325.09 8193.12 8461.37 16.65 + sc_axpby 188863 0.08 11377.48 9670.86 13815.51 22.75 + sc_cdotc 29200 0.01 14951.65 12815.54 17942.27 29.90 + sc_caxpy 1940 0.00 +Inf +Inf +Inf +Inf + sc_caxpy2 1940 0.00 23838.72 23838.72 23838.72 47.68 + sc_cax2 1980 0.01 2704.26 2704.26 2704.26 5.41 + clover_init 2014 1.70 + clover_mult_a 10 0.00 +Inf +Inf +Inf +Inf + clover_mult_ao 252793 3.18 2808.82 2787.78 2830.19 5.62 + clover_mult_b 50360 0.76 2329.05 2316.94 2341.28 4.66 + clover_dsd 410 3.54 + clover_dsf 0 + hmc_init 10 0.01 + hmc_init_p 10 0.01 + hmc_u 6400 3.09 + hmc_momenta 0 + hmc_phi 10 0.49 + hmc_h_old 10 0.51 + hmc_backup 10 0.00 + hmc_half_step0 0 + hmc_half_step1 0 + hmc_xbound_g 11367 0.33 + hmc_steps 8540 58.17 + hmc_h_new 10 0.01 + hmc_rest 10 0.00 + HMC 10 62.00 + h_mult_a 0 + h_mult_b 0 + h_mult_c 0 + dsg 6410 3.50 + dsf 2020 16.78 + plaquette 22 0.00 1828.99 1828.99 1828.99 3.66 + cooling 5 0.31 + ran_gauss_volh 138 0.03 + MTDAGMT_r4 0 + dsig 1610 6.91 + rectangle 21 0.01 2011.58 2011.50 2011.66 4.02 + chair 0 + parallelogram 0 + stout_smear 1607 1.66 1895.16 1894.56 1895.75 3.79 + stout_diffe 3360 7.49 2594.48 2589.47 2599.51 5.19 + clover_bsa_w 20260 1.70 1403.48 1403.07 1403.89 2.81 + clover_dsd_w 820 0.38 1125.27 1123.79 1126.75 2.25 + clover_d_w 5900 7.56 1997.19 1995.61 1998.77 3.99 + dsf_at_bt 10130 1.84 1303.54 1301.76 1305.31 2.61 + dsf_xyztfb_w 10130 2.99 1727.10 1705.72 1749.03 3.45 + dsf_sum 10130 8.71 1141.10 1141.04 1141.17 2.28 + dsf_w2gen 2540 12.43 2250.96 2247.97 2253.95 4.50 + cgm 260 3.46 1727.09 1726.84 1727.34 3.45 + cg_ritz 62 2.01 1823.58 1823.58 1823.59 3.65 + cg_mix 0 + bicgstab 0 + bicgstab_mix 0 + ddbqnohat 0 + unprec_mmul 0 + unprec_dsf 0 + dsf_un 0 + dsf_mtmp 2020 31.83 + cg_mre_mtmp 2020 11.04 + dsf_wmul_r8 2020 0.27 + dsf_wdag_r8 410 0.07 + integrator 10 61.47 + bagel_d 0 + TOTAL 1 64.04 + + Performance + region #calls time mean min max Total + s MByte/s MByte/s MByte/s GByte/s + + xbound_g 11368 0.29 2860.97 2721.64 3015.33 5.72 + xbound_sc 60780 0.11 7046.99 6669.74 7469.47 14.09 + xbound_sc2 283140 0.67 2594.86 2581.38 2608.47 5.19 + u_read_bqcd 0 + u_write_bqcd 0 + u_read_ildg 0 + u_write_ildg 1 0.00 73.80 73.73 73.80 0.15 + >EndTiming + >EndFooter + >EndJob diff --git a/src/data/fAfPhist.000001 b/src/data/fAfPhist.000001 new file mode 100644 index 0000000000000000000000000000000000000000..6b0740dfa5fbf1cca1b3d43db92fb755fe37acdf --- /dev/null +++ b/src/data/fAfPhist.000001 @@ -0,0 +1,6 @@ + 2 2 -0.1093922664909526E+02 0.3226655326743535E+02 -0.5690947076921602E+01 0.1778139124900939E+02 + 2 3 -0.3482655321981409E+01 0.8798795114149012E+01 -0.1999837887417912E+01 0.4056267385476374E+01 + 2 4 -0.1030793027835868E+01 0.1999752671170661E+01 -0.8747566385057118E+00 0.1181154569084714E+01 + 4 2 -0.1042765902160017E+02 0.3692756648981153E+02 -0.5762968403171802E+01 0.1885973619083830E+02 + 4 3 -0.4915729002104299E+01 0.1335250372777899E+02 -0.3101381604108358E+01 0.5460805459492596E+01 + 4 4 -0.1989742507969638E+01 0.3829683536458950E+01 -0.1894084381092628E+01 0.2325879701525509E+01 diff --git a/src/data/fractiontolerance b/src/data/fractiontolerance new file mode 100644 index 0000000000000000000000000000000000000000..bb92c57a0795d5aaefff35bcd3b0e8c17735658d --- /dev/null +++ b/src/data/fractiontolerance @@ -0,0 +1,4 @@ +0.1 +0.5 +1.0 +0.7 diff --git a/src/data/rangelist b/src/data/rangelist new file mode 100644 index 0000000000000000000000000000000000000000..ee40e0a27ea2115274047ff4367df1868dc89d30 --- /dev/null +++ b/src/data/rangelist @@ -0,0 +1 @@ +1 7 10 1.5 diff --git a/src/fermi/clover2/Makefile b/src/fermi/clover2/Makefile index c43899ea7f8b9c3ba2f8db936063d583762a94ca..f3c9c39e5cebf6de926600723983f1e016629600 100644 --- a/src/fermi/clover2/Makefile +++ b/src/fermi/clover2/Makefile @@ -27,16 +27,16 @@ include $(DIR)Makefile.in MODULES_DIR = $(DIR)/modules ifdef FPP2 - fpp = $(FPP2) + fpp = $(FPP2) -I$(DIR)include $(MYFLAGS) else - fpp = $(FPP) + fpp = $(FPP) -I$(DIR)include $(MYFLAGS) endif .SUFFIXES: .SUFFIXES: .a .o .F90 .F90.o: - $(fpp) -I$(DIR)include $(MYFLAGS) $< > $*.f90 + $(fpp) $< > $*.f90 $(F90) -c $(FFLAGS) $*.f90 OBJS = \ @@ -53,6 +53,10 @@ OBJS = \ clover_inv.o \ clover_t_init.o +ifdef quad +OBJS += clover_allocate_r16.o +endif + fast: $(FAST_MAKE) lib_clover2.a @@ -62,3 +66,10 @@ lib_clover2.a: $(OBJS) clobber: rm -f *.[Tiod] *.f90 *.mod rm -f lib_clover2.a + +clover_allocate_r4.o: clover_allocate.F90 + $(fpp) -DPRECISION_R4 $< > $*.f90 + $(F90) -c $(FFLAGS32) $*.f90 +clover_allocate_r16.o: clover_allocate.F90 + $(fpp) -DPRECISION_R16 $< > $*.f90 + $(F90) -c $(FFLAGS) $*.f90 diff --git a/src/fermi/clover2/clover_d.F90 b/src/fermi/clover2/clover_d.F90 index 42ab0800f1c612b411c135ca9ac79c5f3eb2a132..baadbbce6efed6d26db5123d2e4cbc77bd76ea56 100644 --- a/src/fermi/clover2/clover_d.F90 +++ b/src/fermi/clover2/clover_d.F90 @@ -69,6 +69,7 @@ end !------------------------------------------------------------------------------- subroutine clover_d_w(out, u, in, eo) use module_vol + use module_switches implicit none GAUGE_FIELD, intent(out) :: out @@ -102,6 +103,7 @@ subroutine clover_d_w(out, u, in, eo) call xbound_g(inh, EVEN, mu) call xbound_g(inh, ODD , mu) enddo + if (switches%boundary_sf) call schr_boundary_zero4(inh) out = ZERO call clover_d_mu_nu_w(eo, 1, 2, out, u, inh(1, 1, 1, EVEN, 1)) @@ -124,6 +126,8 @@ subroutine clover_d_w(out, u, in, eo) enddo enddo + if (switches%boundary_sf) call schr_boundary_zero3(out) + deallocate(inh, STAT = ierr) if (ierr /= 0) then call stderr2_int("deallocation failed", 1, ierr) diff --git a/src/fermi/clover2/clover_init.F90 b/src/fermi/clover2/clover_init.F90 index d6ab119860c07091e10c44bc65bec0e6a4e50db4..73ba200a86e102757cc4a80967e768bff0f9b639 100644 --- a/src/fermi/clover2/clover_init.F90 +++ b/src/fermi/clover2/clover_init.F90 @@ -30,6 +30,7 @@ subroutine clover_init(a, ainv, b, u, csw_kappa, m1, m2) use typedef_clover use module_vol + use module_switches implicit none CLOVER_FIELD_A, intent(out) :: a, ainv @@ -41,12 +42,13 @@ subroutine clover_init(a, ainv, b, u, csw_kappa, m1, m2) integer :: i, eo, mu1(6), mu2(6) SU3 :: f, g type(type_clover_a) :: p, q - REAL :: factor + REAL :: factor(EVEN:ODD, volh) DEBUG2S("Start: clover_init") TIMING_START(timing_bin_clover_init) factor = -csw_kappa / EIGHT + if (switches%boundary_sf) call schrfunc_cswkappa(factor) #ifdef GAMMA_NOTATION_CHROMA mu1(1)=1 ; mu1(2)=2 @@ -91,7 +93,7 @@ subroutine clover_init(a, ainv, b, u, csw_kappa, m1, m2) call clover_f_mu_nu_imp(f, mu2(3), mu2(4), i, eo, u) ! F14 = i(f14 - f14^{+}) [3x3] call clover_f_mu_nu_imp(g, mu2(5), mu2(6), i, eo, u) ! F42 = i(f42 - f42^{+}) [3x3] call clover_init2(q, f, g) ! FF4 - call clover_init3(a(1, i, eo), a(2, i, eo), p, q, factor) + call clover_init3(a(1, i, eo), a(2, i, eo), p, q, factor(eo, i)) call clover_init4(a(1, i, eo), m1) call clover_init4(a(2, i, eo), m2) call clover_inv(b(1, i, eo), ainv(1, i, eo), a(1, i, eo)) diff --git a/src/fermi/d/D100_g.F90 b/src/fermi/d/D100_g.F90 index 316e64260eeafb0268f23c4944c479852f96cc25..4eff41ebc7d6bbf3d403d6c406cf3e5e2022c3ba 100644 --- a/src/fermi/d/D100_g.F90 +++ b/src/fermi/d/D100_g.F90 @@ -27,22 +27,18 @@ module module_d_g_reorder complex(8), dimension(:,:, :, :, :),pointer,save :: u_reorder complex(4), dimension(:,:, :, :, :),pointer,save :: u_reorder_r4 +#ifdef QUAD + complex(16), dimension(:,:, :, :, :),pointer,save :: u_reorder_r16 +#endif integer :: mud(4), save end !------------------------------------------------------------------------------- -!subroutine d_g_init(u_orig) -! use module_vol -! implicit none -! GAUGE_FIELD :: u_orig -! -! return -!end - -!------------------------------------------------------------------------------- -!subroutine d_g_u_reorder(u) +#ifdef D520 +subroutine d_g_init100(u) +#else subroutine d_g_init(u) - +#endif use module_d_g_reorder use module_nn use module_vol @@ -81,11 +77,29 @@ subroutine d_g_init(u) enddo enddo +#ifdef QUAD + do eo = EVEN, ODD + do mu = 1, DIM + !$omp parallel do private(c1, c2) + do i = 1, volh + do c1 = 1, 3 + do c2 = 1, 6 + u_reorder_r16(c2, c1, i, mu, eo) = u_reorder(c2, c1, i, mu, eo) + enddo + enddo + enddo + enddo + enddo +#endif + end !------------------------------------------------------------------------------- -!subroutine init_d_g_u_reorder() +#ifdef D520 +subroutine init_d100() +#else subroutine init_d() +#endif use module_lattice use module_d_g_reorder use module_vol @@ -93,6 +107,9 @@ subroutine init_d() allocate(u_reorder(6,NCOL, volh, DIM, EVEN:ODD)) allocate(u_reorder_r4(6,NCOL, volh, DIM, EVEN:ODD)) +#ifdef QUAD + allocate(u_reorder_r16(6,NCOL, volh, DIM, EVEN:ODD)) +#endif mud(1) = decomp_direction(1) mud(2) = decomp_direction(2) mud(3) = decomp_direction(3) diff --git a/src/fermi/d/D100_util_block.m4 b/src/fermi/d/D100_util_block.m4 index 9dc9c9aa8d23d4f0491a39cf236156033d011779..19dc51b629b03be79148f68e4ed9ee30f29e060a 100644 --- a/src/fermi/d/D100_util_block.m4 +++ b/src/fermi/d/D100_util_block.m4 @@ -39,7 +39,6 @@ subroutine _STRCAT(d_,NAME,_block2)(out, a_fwd, a_bwd, u, nn_fwd, nn_bwd, i1, i2 #else COMPLEX, dimension (4, 3, *) :: out #endif - integer :: i, jf, jb, i1, i2 COMPLEX :: a1, a2 , bf11,bf21,bf12,bf22,bf13,bf23 COMPLEX :: bb11,bb21,bb12,bb22,bb13,bb23 diff --git a/src/measure/cdotc_12.F90 b/src/fermi/d/D103.c similarity index 55% rename from src/measure/cdotc_12.F90 rename to src/fermi/d/D103.c index bdca10f4d84ef0dfaf2499a73e7b0c2bf044332a..4cf873a5d6a34e8d5f3c49c67ae61870d5e85f68 100644 --- a/src/measure/cdotc_12.F90 +++ b/src/fermi/d/D103.c @@ -1,10 +1,11 @@ +/* !=============================================================================== ! -! cdotc_12.F90 +! D103.c ! !------------------------------------------------------------------------------- ! -! Copyright (C) 2007 Yoshifumi Nakamura +! Copyright (C) 2011 Hinnerk Stueben ! ! This file is part of BQCD -- Berlin Quantum ChromoDynamics program ! @@ -22,24 +23,55 @@ ! along with BQCD. If not, see <http://www.gnu.org/licenses/>. ! !------------------------------------------------------------------------------- -# include "defs.h" +*/ +#undef DAGGER -!------------------------------------------------------------------------------- -COMPLEX function cdotc_12(x, y) ! Sum_i conjg(x_i) * y_i +#undef NAME +#define NAME d_xf +#define DIR_X +#include "D103xyzt.c" +#undef DIR_X - implicit none - COMPLEX, intent(in) :: x(*), y(*) - COMPLEX :: tmp - integer :: i - - tmp = ZERO - !$omp parallel do reduction(+: tmp) - do i = 1, 12 - tmp = tmp + conjg(x(i)) * y(i) - enddo +#undef NAME +#define NAME d_yf +#define DIR_Y +#include "D103xyzt.c" +#undef DIR_Y - cdotc_12 = tmp +#undef NAME +#define NAME d_zf +#define DIR_Z +#include "D103xyzt.c" +#undef DIR_Z -end +#undef NAME +#define NAME d_t +#define DIR_T +#include "D103xyzt.c" +#undef DIR_T -!=============================================================================== +#define DAGGER + +#undef NAME +#define NAME d_dag_xf +#define DIR_X +#include "D103xyzt.c" +#undef DIR_X + +#undef NAME +#define NAME d_dag_yf +#define DIR_Y +#include "D103xyzt.c" +#undef DIR_Y + +#undef NAME +#define NAME d_dag_zf +#define DIR_Z +#include "D103xyzt.c" +#undef DIR_Z + +#undef NAME +#define NAME d_dag_t +#define DIR_T +#include "D103xyzt.c" +#undef DIR_T diff --git a/src/fermi/d/D103.m4 b/src/fermi/d/D103.m4 new file mode 100644 index 0000000000000000000000000000000000000000..1a9594fee54df868a0a6cff2f64771a490820d99 --- /dev/null +++ b/src/fermi/d/D103.m4 @@ -0,0 +1,274 @@ +include(`defs.m4') +include(`spin_proj.m4') +include(`d100_defs.m4') +!=============================================================================== +! +! D103.m4 - this version supports only GAMMA_NOTATION=BQCD +! +!------------------------------------------------------------------------------- +! +! Copyright (C) 2008 Yoshifumi Nakamura +! +! This file is part of BQCD -- Berlin Quantum ChromoDynamics program +! +! BQCD 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 Foundation, either version 3 of the License, or +! (at your option) any later version. +! +! BQCD is distributed in the hope that it will be useful, +! but WITHOUT ANY WARRANTY; without even the implied warranty of +! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +! GNU General Public License for more details. +! +! You should have received a copy of the GNU General Public License +! along with BQCD. If not, see <http://www.gnu.org/licenses/>. +! +!------------------------------------------------------------------------------- +#include "defs.h" +!------------------------------------------------------------------------------- +subroutine d(e, o, out, in, u) + use module_d_g_reorder + use module_vol + use module_lattice + use module_nn + use module_d21 + use module_p_interface + implicit none + integer :: e, o +#ifdef FLIPSC +# error FLIPSC is not supported in libd103 + !!COMPLEX, dimension (NCOL, NDIRAC, volh_tot) :: out, in +#else + SPINCOL_FIELD :: out, in +#endif + GAUGE_FIELD :: u + + TIMING_START(timing_bin_d) + ALLOCATE_SC2_FIELD(a) ! kept in 'module_d21' + call d_projection(a, in) + call xbound_sc2_field(a) + call d_xf(out,a(1,1,1,mud(1),0),a(1,1,1, mud(1),1),u_reorder(1,1,1,1,e),nn(1,e,1,0),nn(1,e,1,1), volh) + call d_yf(out,a(1,1,1,mud(2),0),a(1,1,1, mud(2),1),u_reorder(1,1,1,2,e),nn(1,e,2,0),nn(1,e,2,1), volh) + call d_zf(out,a(1,1,1,mud(3),0),a(1,1,1, mud(3),1),u_reorder(1,1,1,3,e),nn(1,e,3,0),nn(1,e,3,1), volh) + call d_t( out,a(1,1,1,mud(4),0),a(1,1,1, mud(4),1),u_reorder(1,1,1,4,e),nn(1,e,4,0),nn(1,e,4,1), volh) + TIMING_STOP(timing_bin_d) +end + +!------------------------------------------------------------------------------- +subroutine d_dag(e, o, out, in, u) + use module_d_g_reorder + use module_vol + use module_lattice + use module_nn + use module_d21 + use module_p_interface + implicit none + integer :: e, o +#ifdef FLIPSC + COMPLEX, dimension (NCOL, NDIRAC, volh_tot) :: out, in +#else + SPINCOL_FIELD :: out, in +#endif + GAUGE_FIELD :: u + + TIMING_START(timing_bin_d) + ALLOCATE_SC2_FIELD(a) ! kept in 'module_d21' + call d_dag_projection(a, in) + call xbound_sc2_field(a) + call d_dag_xf(out,a(1,1,1,mud(1),0),a(1,1,1, mud(1),1),u_reorder(1,1,1,1,e),nn(1,e,1,0),nn(1,e,1,1), volh) + call d_dag_yf(out,a(1,1,1,mud(2),0),a(1,1,1, mud(2),1),u_reorder(1,1,1,2,e),nn(1,e,2,0),nn(1,e,2,1), volh) + call d_dag_zf(out,a(1,1,1,mud(3),0),a(1,1,1, mud(3),1),u_reorder(1,1,1,3,e),nn(1,e,3,0),nn(1,e,3,1), volh) + call d_dag_t( out,a(1,1,1,mud(4),0),a(1,1,1, mud(4),1),u_reorder(1,1,1,4,e),nn(1,e,4,0),nn(1,e,4,1), volh) + TIMING_STOP(timing_bin_d) +end + +!------------------------------------------------------------------------------- +subroutine d_projection(out, in) + use module_d_g_reorder + use module_vol + implicit none + integer :: mu(4), i, col + SC2_FIELD :: out +#ifdef FLIPSC + COMPLEX, dimension (NCOL, NDIRAC, volh_tot) :: in +#else + SPINCOL_FIELD :: in +#endif + COMPLEX ci + + mu=mud + ci = dcmplx(1,1) + +# undef fwd +# undef bwd +# define fwd FWD +# define bwd BWD + + TIMING_START(timing_bin_sc2_projection) + +#ifdef IBM + call alignx(16, in(1,1,1) ) + call alignx(16, out(1,1,1,1,1)) +#endif + !$omp parallel do + do i = 1, volh +_D_PROJECTION1 +_D_PROJECTION2 +_D_PROJECTION3 +_D_PROJECTION4 + enddo + TIMING_STOP(timing_bin_sc2_projection) + +end + +!------------------------------------------------------------------------------- +subroutine d_dag_projection(out, in) + use module_d_g_reorder + use module_vol + implicit none + integer :: mu(4), i, col + SC2_FIELD :: out +#ifdef FLIPSC + COMPLEX, dimension (NCOL, NDIRAC, volh_tot) :: in +#else + SPINCOL_FIELD :: in +#endif + COMPLEX ci + + mu=mud + ci = dcmplx(1,1) + +# undef fwd +# undef bwd +# define bwd FWD +# define fwd BWD + + TIMING_START(timing_bin_sc2_projection) +#ifdef IBM + call alignx(16, in(1,1,1) ) + call alignx(16, out(1,1,1,1,1)) +#endif + !$omp parallel do + do i = 1, volh +_D_PROJECTION1 +_D_PROJECTION2 +_D_PROJECTION3 +_D_PROJECTION4 + enddo + TIMING_STOP(timing_bin_sc2_projection) + +end + +!------------------------------------------------------------------------------- +subroutine d_block(out, in, u, eo, i1, i2) + use module_d_g_reorder + use module_vol + use module_nn + implicit none + integer :: eo, i1, i2 + COMPLEX, dimension (4,3, volh_tot) :: out + COMPLEX, dimension (2,3, volh_tot, DIM, 0:1) :: in + GAUGE_FIELD :: u + call d_x_block(out, in, u_reorder(1,1,1,1,eo), nn(1,eo,1,FWD),nn(1,eo,1,BWD), i1,i2) + call d_y_block(out, in, u_reorder(1,1,1,2,eo), nn(1,eo,2,FWD),nn(1,eo,2,BWD), i1,i2) + call d_z_block(out, in, u_reorder(1,1,1,3,eo), nn(1,eo,3,FWD),nn(1,eo,3,BWD), i1,i2) + call d_t_block(out, in, u_reorder(1,1,1,4,eo), nn(1,eo,4,FWD),nn(1,eo,4,BWD), i1,i2) +end + +!------------------------------------------------------------------------------- +subroutine d_dag_block(out, in, u, eo, i1, i2) + use module_d_g_reorder + use module_vol + use module_nn + implicit none + integer :: eo, i1, i2 + COMPLEX, dimension (4,3, volh_tot) :: out + COMPLEX, dimension (2,3, volh_tot, DIM, 0:1) :: in + GAUGE_FIELD :: u + call d_dag_x_block(out, in, u_reorder(1,1,1,1,eo), nn(1,eo,1,FWD),nn(1,eo,1,BWD), i1,i2) + call d_dag_y_block(out, in, u_reorder(1,1,1,2,eo), nn(1,eo,2,FWD),nn(1,eo,2,BWD), i1,i2) + call d_dag_z_block(out, in, u_reorder(1,1,1,3,eo), nn(1,eo,3,FWD),nn(1,eo,3,BWD), i1,i2) + call d_dag_t_block(out, in, u_reorder(1,1,1,4,eo), nn(1,eo,4,FWD),nn(1,eo,4,BWD), i1,i2) +end + +!------------------------------------------------------------------------------- +subroutine d_projection_block(out, in, i1, i2) + use module_d_g_reorder + use module_vol + implicit none + integer :: mu(4), i1, i2 + integer :: i + SC2_FIELD :: out +#ifdef FLIPSC + COMPLEX, dimension (NCOL, NDIRAC, volh_tot) :: in +#else + SPINCOL_FIELD :: in +#endif + COMPLEX ci + +# undef fwd +# undef bwd +# define fwd FWD +# define bwd BWD + + mu=mud + ci = dcmplx(1,1) + +#ifdef IBM + call alignx(16, in(1,1,1) ) + call alignx(16, out(1,1,1,1,1)) +#endif + do i = i1, i2 +_D_PROJECTION1 +_D_PROJECTION2 +_D_PROJECTION3 +_D_PROJECTION4 + enddo +end +!------------------------------------------------------------------------------- +subroutine d_dag_projection_block(out, in, i1, i2) + use module_d_g_reorder + use module_vol + implicit none + integer :: mu(4), i1, i2 + integer :: i + SC2_FIELD :: out +#ifdef FLIPSC + COMPLEX, dimension (NCOL, NDIRAC, volh_tot) :: in +#else + SPINCOL_FIELD :: in +#endif + COMPLEX ci + +# undef fwd +# undef bwd +# define bwd FWD +# define fwd BWD + + mu=mud + ci = dcmplx(1,1) +#ifdef IBM + call alignx(16, in(1,1,1) ) + call alignx(16, out(1,1,1,1,1)) +#endif + do i = i1, i2 +_D_PROJECTION1 +_D_PROJECTION2 +_D_PROJECTION3 +_D_PROJECTION4 + enddo +end + +!------------------------------------------------------------------------------- +subroutine d_xbound(a) + + use module_vol + implicit none + SC2_FIELD, intent(inout) :: a + + call xbound_sc2_field(a) + +end + +!=============================================================================== diff --git a/src/fermi/d/D103_block.c b/src/fermi/d/D103_block.c new file mode 100644 index 0000000000000000000000000000000000000000..5e7ce13dc11070d2a2567f8a9fb6009244ddd037 --- /dev/null +++ b/src/fermi/d/D103_block.c @@ -0,0 +1,79 @@ +/* +!=============================================================================== +! +! D103_block.c +! +!------------------------------------------------------------------------------- +! +! Copyright (C) 2011 Hinnerk Stueben +! +! This file is part of BQCD -- Berlin Quantum ChromoDynamics program +! +! BQCD 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 Foundation, either version 3 of the License, or +! (at your option) any later version. +! +! BQCD is distributed in the hope that it will be useful, +! but WITHOUT ANY WARRANTY; without even the implied warranty of +! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +! GNU General Public License for more details. +! +! You should have received a copy of the GNU General Public License +! along with BQCD. If not, see <http://www.gnu.org/licenses/>. +! +!------------------------------------------------------------------------------- +*/ +#define BLOCK + +#undef DAGGER + +#undef NAME +#define NAME d_x_block2 +#define DIR_X +#include "D103xyzt.c" +#undef DIR_X + +#undef NAME +#define NAME d_y_block2 +#define DIR_Y +#include "D103xyzt.c" +#undef DIR_Y + +#undef NAME +#define NAME d_z_block2 +#define DIR_Z +#include "D103xyzt.c" +#undef DIR_Z + +#undef NAME +#define NAME d_t_block2 +#define DIR_T +#include "D103xyzt.c" +#undef DIR_T + +#define DAGGER + +#undef NAME +#define NAME d_dag_x_block2 +#define DIR_X +#include "D103xyzt.c" +#undef DIR_X + +#undef NAME +#define NAME d_dag_y_block2 +#define DIR_Y +#include "D103xyzt.c" +#undef DIR_Y + +#undef NAME +#define NAME d_dag_z_block2 +#define DIR_Z +#include "D103xyzt.c" +#undef DIR_Z + +#undef NAME +#define NAME d_dag_t_block2 +#define DIR_T +#include "D103xyzt.c" +#undef DIR_T diff --git a/src/fermi/d/D103_block_r4.c b/src/fermi/d/D103_block_r4.c new file mode 100644 index 0000000000000000000000000000000000000000..e7001b3b72768776ae175b29f05e28212d90bcc7 --- /dev/null +++ b/src/fermi/d/D103_block_r4.c @@ -0,0 +1,80 @@ +/* +!=============================================================================== +! +! D103_block_r4.c +! +!------------------------------------------------------------------------------- +! +! Copyright (C) 2011 Hinnerk Stueben +! +! This file is part of BQCD -- Berlin Quantum ChromoDynamics program +! +! BQCD 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 Foundation, either version 3 of the License, or +! (at your option) any later version. +! +! BQCD is distributed in the hope that it will be useful, +! but WITHOUT ANY WARRANTY; without even the implied warranty of +! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +! GNU General Public License for more details. +! +! You should have received a copy of the GNU General Public License +! along with BQCD. If not, see <http://www.gnu.org/licenses/>. +! +!------------------------------------------------------------------------------- +*/ +#define BLOCK +#define PRECISION_R4 +#undef DAGGER + +#undef NAME +#define NAME d_x_block2_r4 +#define DIR_X +#include "D103xyzt_r4.c" +#undef DIR_X + +#undef NAME +#define NAME d_y_block2_r4 +#define DIR_Y +#include "D103xyzt_r4.c" +#undef DIR_Y + +#undef NAME +#define NAME d_z_block2_r4 +#define DIR_Z +#include "D103xyzt_r4.c" +#undef DIR_Z + +#undef NAME +#define NAME d_t_block2_r4 +#define DIR_T +#include "D103xyzt_r4.c" +#undef DIR_T + +#define DAGGER + +#undef NAME +#define NAME d_dag_x_block2_r4 +#define DIR_X +#include "D103xyzt_r4.c" +#undef DIR_X + +#undef NAME +#define NAME d_dag_y_block2_r4 +#define DIR_Y +#include "D103xyzt_r4.c" +#undef DIR_Y + +#undef NAME +#define NAME d_dag_z_block2_r4 +#define DIR_Z +#include "D103xyzt_r4.c" +#undef DIR_Z + +#undef NAME +#define NAME d_dag_t_block2_r4 +#define DIR_T +#include "D103xyzt_r4.c" +#undef DIR_T + diff --git a/src/fermi/d/D103_r4.c b/src/fermi/d/D103_r4.c new file mode 100644 index 0000000000000000000000000000000000000000..eb95197a2f13c291a30818a9048828dc3e43c00b --- /dev/null +++ b/src/fermi/d/D103_r4.c @@ -0,0 +1,79 @@ +/* +!=============================================================================== +! +! D103_r4.c +! +!------------------------------------------------------------------------------- +! +! Copyright (C) 2011 Hinnerk Stueben +! +! This file is part of BQCD -- Berlin Quantum ChromoDynamics program +! +! BQCD 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 Foundation, either version 3 of the License, or +! (at your option) any later version. +! +! BQCD is distributed in the hope that it will be useful, +! but WITHOUT ANY WARRANTY; without even the implied warranty of +! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +! GNU General Public License for more details. +! +! You should have received a copy of the GNU General Public License +! along with BQCD. If not, see <http://www.gnu.org/licenses/>. +! +!------------------------------------------------------------------------------- +*/ +#define PRECISION_R4 +#undef DAGGER + +#undef NAME +#define NAME d_xf_r4 +#define DIR_X +#include "D103xyzt_r4.c" +#undef DIR_X + +#undef NAME +#define NAME d_yf_r4 +#define DIR_Y +#include "D103xyzt_r4.c" +#undef DIR_Y + +#undef NAME +#define NAME d_zf_r4 +#define DIR_Z +#include "D103xyzt_r4.c" +#undef DIR_Z + +#undef NAME +#define NAME d_t_r4 +#define DIR_T +#include "D103xyzt_r4.c" +#undef DIR_T + +#define DAGGER + +#undef NAME +#define NAME d_dag_xf_r4 +#define DIR_X +#include "D103xyzt_r4.c" +#undef DIR_X + +#undef NAME +#define NAME d_dag_yf_r4 +#define DIR_Y +#include "D103xyzt_r4.c" +#undef DIR_Y + +#undef NAME +#define NAME d_dag_zf_r4 +#define DIR_Z +#include "D103xyzt_r4.c" +#undef DIR_Z + +#undef NAME +#define NAME d_dag_t_r4 +#define DIR_T +#include "D103xyzt_r4.c" +#undef DIR_T + diff --git a/src/fermi/d/D103_util_block.m4 b/src/fermi/d/D103_util_block.m4 new file mode 100644 index 0000000000000000000000000000000000000000..f368b75acf40b300f7b4db5985edfbe4de3fe4c9 --- /dev/null +++ b/src/fermi/d/D103_util_block.m4 @@ -0,0 +1,31 @@ +include(`defs.m4') +include(`spin_sum.m4') +include(`d100_defs.m4') +ifelse(DIRECTION,X,`define(`_DIR',1)')dnl +ifelse(DIRECTION,Y,`define(`_DIR',2)')dnl +ifelse(DIRECTION,Z,`define(`_DIR',3)')dnl +ifelse(DIRECTION,T,`define(`_DIR',4)')dnl +!------------------------------------------------------------------------------- +#include "defs.h" +!------------------------------------------------------------------------------- +subroutine _STRCAT(d_,NAME,_block)(out, a, u, nn_fwd, nn_bwd, i1, i2) + use module_d_g_reorder + use module_vol + implicit none + COMPLEX, dimension (2, 3, volh_tot, DIM, 0:1) :: a + COMPLEX, dimension (6, 3, *) :: u + integer(4), dimension (*) :: nn_fwd, nn_bwd +#ifdef FLIPSC +# error FLIPSC is not supported in libd103 + !!COMPLEX, dimension (3, 4, *) :: out +#else + COMPLEX, dimension (4, 3, *) :: out +#endif + integer :: i1, i2 + + call _STRCAT(d_,NAME,_block2)(out, & + a(1,1,1,mud(_DIR),0), a(1,1,1,mud(_DIR),1), & + u, nn_fwd, nn_bwd, i1, i2) +end + +!=============================================================================== diff --git a/src/fermi/d/D103xyzt.c b/src/fermi/d/D103xyzt.c new file mode 100644 index 0000000000000000000000000000000000000000..86a768bafa4c24c1f64db9798787abaa8cd97732 --- /dev/null +++ b/src/fermi/d/D103xyzt.c @@ -0,0 +1,445 @@ +/* +!=============================================================================== +! +! D103xyzt.c +! +!------------------------------------------------------------------------------- +! +! Copyright (C) 2011 Hinnerk Stueben +! +! This file is part of BQCD -- Berlin Quantum ChromoDynamics program +! +! BQCD 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 Foundation, either version 3 of the License, or +! (at your option) any later version. +! +! BQCD is distributed in the hope that it will be useful, +! but WITHOUT ANY WARRANTY; without even the implied warranty of +! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +! GNU General Public License for more details. +! +! You should have received a copy of the GNU General Public License +! along with BQCD. If not, see <http://www.gnu.org/licenses/>. +! +!------------------------------------------------------------------------------- +*/ +# include <emmintrin.h> +# include <pmmintrin.h> +# include "c_defs.h" + +# define cAdd(a, b) a = _mm_add_pd(a, b) +# define cSum(a, b, c) a = _mm_add_pd(b, c) +# define cDiff(a, b, c) a = _mm_sub_pd(b, c) + +#ifdef DAGGER +# define cDiff2(a, b, c) cDiff(a, c, b) +#else +# define cDiff2(a, b, c) cDiff(a, b, c) +#endif + +#ifdef DAGGER +# define cDiff3(a, b, c) a = _mm_mul_pd(conjgr, _mm_sub_pd(b, c)) +#else +# define cDiff3(a, b, c) a = _mm_mul_pd(conjg, _mm_sub_pd(b, c)) +#endif + +# define cLoadAf(s, c) STRCAT3(af_ri,s,c) = _mm_load_pd((double*) &(a_fwd(s, c, jf))); \ + STRCAT3(af_ir,s,c) = _mm_loadr_pd((double*) &(a_fwd(s, c, jf))) + +# define cLoadAb(s, c) STRCAT3(ab_ri,s,c) = _mm_load_pd((double*) &(a_bwd(s, c, jb))); \ + STRCAT3(ab_ir,s,c) = _mm_loadr_pd((double*) &(a_bwd(s, c, jb))) + +# define cLoadU(c, d) STRCAT3(u_rr,c,d) = _mm_load1_pd((double*) &(Re(u(c, d, i)))); \ + STRCAT3(u_ii,c,d) = _mm_load1_pd((double*) &(Im(u(c, d, i)))) + +# define cProdAfU(s, c, d) STRCAT3(bf,s,c) = _mm_addsub_pd(_mm_mul_pd(STRCAT3(af_ri,s,d), STRCAT3(u_rr,c,d)), _mm_mul_pd(STRCAT3(af_ir,s,d), STRCAT3(u_ii,c,d))) +# define cProdAbU(s, c, d) STRCAT3(bb,s,c) = _mm_addsub_pd(_mm_mul_pd(STRCAT3(ab_ri,s,d), STRCAT3(u_rr,c,d)), _mm_mul_pd(STRCAT3(ab_ir,s,d), STRCAT3(u_ii,c,d))) + +# define cAddProdAfU(s, c, d) cAdd(STRCAT3(bf,s,c), _mm_addsub_pd(_mm_mul_pd(STRCAT3(af_ri,s,d), STRCAT3(u_rr,c,d)), _mm_mul_pd(STRCAT3(af_ir,s,d), STRCAT3(u_ii,c,d)))) +# define cAddProdAbU(s, c, d) cAdd(STRCAT3(bb,s,c), _mm_addsub_pd(_mm_mul_pd(STRCAT3(ab_ri,s,d), STRCAT3(u_rr,c,d)), _mm_mul_pd(STRCAT3(ab_ir,s,d), STRCAT3(u_ii,c,d)))) + +# define cLoadOut(s, c) STRCAT3(out,s,c) = _mm_load_pd((double*) &(out(s, c, i))) +# define cLoadrOut(s, c) STRCAT3(out,s,c) = _mm_loadr_pd((double*) &(out(s, c, i))) +# define cStoreOut(s, c) _mm_store_pd((double*) &(out(s, c, i)), STRCAT3(out,s,c)) +# define cStorerOut(s, c) _mm_storer_pd((double*) &(out(s, c, i)), STRCAT3(out,s,c)) + + +# define out(a, b, c) out_[c][b-1][a-1] +# define a_fwd(a, b, c) a_fwd_[c][b-1][a-1] +# define a_bwd(a, b, c) a_bwd_[c][b-1][a-1] +# define u(a, b, c) u_[c][b-1][a-1] +# define nn_fwd(c) nn_fwd_[c] +# define nn_bwd(c) nn_bwd_[c] + +/*------------------------------------------------------------------------*/ +void STRCAT(NAME, _)(SPINCOL_FIELD out_, + SC2_FLD a_fwd_, + SC2_FLD a_bwd_, + REORDERED_GAUGE_FIELD u_, + INTEGER nn_fwd_[], + INTEGER nn_bwd_[], +#ifdef BLOCK + int *i1, int *i2) +#else + int *volh) +#endif + +{ + int i, jf, jb; + __m128d af_ri11,af_ri21,af_ri12,af_ri22,af_ri13,af_ri23; + __m128d af_ir11,af_ir21,af_ir12,af_ir22,af_ir13,af_ir23; + __m128d ab_ri11,ab_ri21,ab_ri12,ab_ri22,ab_ri13,ab_ri23; + __m128d ab_ir11,ab_ir21,ab_ir12,ab_ir22,ab_ir13,ab_ir23; + __m128d u_rr11,u_rr12,u_rr13,u_rr21,u_rr22,u_rr23,u_rr31,u_rr32,u_rr33; + __m128d u_rr41,u_rr42,u_rr43,u_rr51,u_rr52,u_rr53,u_rr61,u_rr62,u_rr63; + __m128d u_ii11,u_ii12,u_ii13,u_ii21,u_ii22,u_ii23,u_ii31,u_ii32,u_ii33; + __m128d u_ii41,u_ii42,u_ii43,u_ii51,u_ii52,u_ii53,u_ii61,u_ii62,u_ii63; + __m128d bf11,bf21,bf12,bf22,bf13,bf23; + __m128d bb14,bb24,bb15,bb25,bb16,bb26; + __m128d out11, out21, out31, out41, out12, out22, out32, out42, out13, out23, out33, out43; + __m128d tmp11, tmp21, tmp31, tmp41, tmp12, tmp22, tmp32, tmp42, tmp13, tmp23, tmp33, tmp43; + + const __m128d conjg = _mm_setr_pd(ONE, -ONE); + const __m128d conjgr = _mm_set_pd(ONE, -ONE); + + +#ifndef PRECISION_R4 +#ifndef BLOCK + TIMING_START(STRCAT(timing_bin_, NAME)); +#endif +#endif + + out_--; + a_fwd_--; + a_bwd_--; + u_--; + nn_fwd_--; + nn_bwd_--; + + +#ifdef BLOCK + for (i = *i1; i <= *i2; i++) +#else + #pragma omp parallel for \ + private (i, jf, jb) \ + private (af_ri11,af_ri21,af_ri12,af_ri22,af_ri13,af_ri23) \ + private (af_ir11,af_ir21,af_ir12,af_ir22,af_ir13,af_ir23) \ + private (ab_ri11,ab_ri21,ab_ri12,ab_ri22,ab_ri13,ab_ri23) \ + private (ab_ir11,ab_ir21,ab_ir12,ab_ir22,ab_ir13,ab_ir23) \ + private (u_rr11,u_rr12,u_rr13,u_rr21,u_rr22,u_rr23,u_rr31,u_rr32,u_rr33) \ + private (u_rr41,u_rr42,u_rr43,u_rr51,u_rr52,u_rr53,u_rr61,u_rr62,u_rr63) \ + private (u_ii11,u_ii12,u_ii13,u_ii21,u_ii22,u_ii23,u_ii31,u_ii32,u_ii33) \ + private (u_ii41,u_ii42,u_ii43,u_ii51,u_ii52,u_ii53,u_ii61,u_ii62,u_ii63) \ + private (bf11,bf21,bf12,bf22,bf13,bf23) \ + private (bb14,bb24,bb15,bb25,bb16,bb26) \ + private (out11, out21, out31, out41, out12, out22, out32, out42, out13, out23, out33, out43) \ + private (tmp11, tmp21, tmp31, tmp41, tmp12, tmp22, tmp32, tmp42, tmp13, tmp23, tmp33, tmp43) + + for (i = 1; i <= *volh; i++) +#endif + { + jf=nn_fwd(i); + jb=nn_bwd(i); + + cLoadAf(1, 1); + cLoadAf(2, 1); + cLoadU(1, 1); + cLoadU(2, 1); + cLoadU(3, 1); + cProdAfU(1, 1, 1); + cProdAfU(2, 1, 1); + cProdAfU(1, 2, 1); + cProdAfU(2, 2, 1); + cProdAfU(1, 3, 1); + cProdAfU(2, 3, 1); + + cLoadAb(1, 1); + cLoadAb(2, 1); + cLoadU(4, 1); + cLoadU(5, 1); + cLoadU(6, 1); + cProdAbU(1, 4, 1); + cProdAbU(2, 4, 1); + cProdAbU(1, 5, 1); + cProdAbU(2, 5, 1); + cProdAbU(1, 6, 1); + cProdAbU(2, 6, 1); + + cLoadAf(1, 2); + cLoadAf(2, 2); + cLoadU(1, 2); + cLoadU(2, 2); + cLoadU(3, 2); + cAddProdAfU(1, 1, 2); + cAddProdAfU(2, 1, 2); + cAddProdAfU(1, 2, 2); + cAddProdAfU(2, 2, 2); + cAddProdAfU(1, 3, 2); + cAddProdAfU(2, 3, 2); + + cLoadAb(1, 2); + cLoadAb(2, 2); + cLoadU(4, 2); + cLoadU(5, 2); + cLoadU(6, 2); + cAddProdAbU(1, 4, 2); + cAddProdAbU(2, 4, 2); + cAddProdAbU(1, 5, 2); + cAddProdAbU(2, 5, 2); + cAddProdAbU(1, 6, 2); + cAddProdAbU(2, 6, 2); + + cLoadAf(1, 3); + cLoadAf(2, 3); + cLoadU(1, 3); + cLoadU(2, 3); + cLoadU(3, 3); + cAddProdAfU(1, 1, 3); + cAddProdAfU(2, 1, 3); + cAddProdAfU(1, 2, 3); + cAddProdAfU(2, 2, 3); + cAddProdAfU(1, 3, 3); + cAddProdAfU(2, 3, 3); + + cLoadAb(1, 3); + cLoadAb(2, 3); + cLoadU(4, 3); + cLoadU(5, 3); + cLoadU(6, 3); + cAddProdAbU(1, 4, 3); + cAddProdAbU(2, 4, 3); + cAddProdAbU(1, 5, 3); + cAddProdAbU(2, 5, 3); + cAddProdAbU(1, 6, 3); + cAddProdAbU(2, 6, 3); + + +#ifdef DIR_T + cLoadOut(1, 1); + cLoadOut(2, 1); + cLoadOut(3, 1); + cLoadOut(4, 1); + cLoadOut(1, 2); + cLoadOut(2, 2); + cLoadOut(3, 2); + cLoadOut(4, 2); + cLoadOut(1, 3); + cLoadOut(2, 3); + cLoadOut(3, 3); + cLoadOut(4, 3); +#ifdef DAGGER + cAdd(out11, bf11); + cAdd(out21, bf21); + cAdd(out31, bb14); + cAdd(out41, bb24); + cAdd(out12, bf12); + cAdd(out22, bf22); + cAdd(out32, bb15); + cAdd(out42, bb25); + cAdd(out13, bf13); + cAdd(out23, bf23); + cAdd(out33, bb16); + cAdd(out43, bb26); +#else + cAdd(out11, bb14); + cAdd(out21, bb24); + cAdd(out31, bf11); + cAdd(out41, bf21); + cAdd(out12, bb15); + cAdd(out22, bb25); + cAdd(out32, bf12); + cAdd(out42, bf22); + cAdd(out13, bb16); + cAdd(out23, bb26); + cAdd(out33, bf13); + cAdd(out43, bf23); +#endif + cStoreOut(1, 1); + cStoreOut(2, 1); + cStoreOut(3, 1); + cStoreOut(4, 1); + cStoreOut(1, 2); + cStoreOut(2, 2); + cStoreOut(3, 2); + cStoreOut(4, 2); + cStoreOut(1, 3); + cStoreOut(2, 3); + cStoreOut(3, 3); + cStoreOut(4, 3); +#endif + +#ifdef DIR_X + cSum(out11, bf11, bb14); + cSum(out21, bf21, bb24); + cDiff3(out31, bf21, bb24); + cDiff3(out41, bf11, bb14); + + cSum(out12, bf12, bb15); + cSum(out22, bf22, bb25); + cDiff3(out32, bf22, bb25); + cDiff3(out42, bf12, bb15); + + cSum(out13, bf13, bb16); + cSum(out23, bf23, bb26); + cDiff3(out33, bf23, bb26); + cDiff3(out43, bf13, bb16); + + cStoreOut(1, 1); + cStoreOut(2, 1); + cStorerOut(3, 1); + cStorerOut(4, 1); + cStoreOut(1, 2); + cStoreOut(2, 2); + cStorerOut(3, 2); + cStorerOut(4, 2); + cStoreOut(1, 3); + cStoreOut(2, 3); + cStorerOut(3, 3); + cStorerOut(4, 3); +#endif + + +#ifdef DIR_Y + cSum(tmp11, bf11, bb14); + cSum(tmp21, bf21, bb24); + cDiff2(tmp31, bf21, bb24); + cDiff2(tmp41, bb14, bf11); + + cSum(tmp12, bf12, bb15); + cSum(tmp22, bf22, bb25); + cDiff2(tmp32, bf22, bb25); + cDiff2(tmp42, bb15, bf12); + + cSum(tmp13, bf13, bb16); + cSum(tmp23, bf23, bb26); + cDiff2(tmp33, bf23, bb26); + cDiff2(tmp43, bb16, bf13); + + cLoadOut(1, 1); + cLoadOut(2, 1); + cLoadOut(3, 1); + cLoadOut(4, 1); + cLoadOut(1, 2); + cLoadOut(2, 2); + cLoadOut(3, 2); + cLoadOut(4, 2); + cLoadOut(1, 3); + cLoadOut(2, 3); + cLoadOut(3, 3); + cLoadOut(4, 3); + + cAdd(out11, tmp11); + cAdd(out21, tmp21); + cAdd(out31, tmp31); + cAdd(out41, tmp41); + cAdd(out12, tmp12); + cAdd(out22, tmp22); + cAdd(out32, tmp32); + cAdd(out42, tmp42); + cAdd(out13, tmp13); + cAdd(out23, tmp23); + cAdd(out33, tmp33); + cAdd(out43, tmp43); + + cStoreOut(1, 1); + cStoreOut(2, 1); + cStoreOut(3, 1); + cStoreOut(4, 1); + cStoreOut(1, 2); + cStoreOut(2, 2); + cStoreOut(3, 2); + cStoreOut(4, 2); + cStoreOut(1, 3); + cStoreOut(2, 3); + cStoreOut(3, 3); + cStoreOut(4, 3); +#endif + +#ifdef DIR_Z + cSum(tmp11, bf11, bb14); + cSum(tmp21, bf21, bb24); + cDiff3(tmp31, bf11, bb14); + cDiff3(tmp41, bb24, bf21); + + cSum(tmp12, bf12, bb15); + cSum(tmp22, bf22, bb25); + cDiff3(tmp32, bf12, bb15); + cDiff3(tmp42, bb25, bf22); + + cSum(tmp13, bf13, bb16); + cSum(tmp23, bf23, bb26); + cDiff3(tmp33, bf13, bb16); + cDiff3(tmp43, bb26, bf23); + + cLoadOut(1, 1); + cLoadOut(2, 1); + cLoadrOut(3, 1); + cLoadrOut(4, 1); + cLoadOut(1, 2); + cLoadOut(2, 2); + cLoadrOut(3, 2); + cLoadrOut(4, 2); + cLoadOut(1, 3); + cLoadOut(2, 3); + cLoadrOut(3, 3); + cLoadrOut(4, 3); + + cAdd(out11, tmp11); + cAdd(out21, tmp21); + cAdd(out31, tmp31); + cAdd(out41, tmp41); + cAdd(out12, tmp12); + cAdd(out22, tmp22); + cAdd(out32, tmp32); + cAdd(out42, tmp42); + cAdd(out13, tmp13); + cAdd(out23, tmp23); + cAdd(out33, tmp33); + cAdd(out43, tmp43); + + cStoreOut(1, 1); + cStoreOut(2, 1); + cStorerOut(3, 1); + cStorerOut(4, 1); + cStoreOut(1, 2); + cStoreOut(2, 2); + cStorerOut(3, 2); + cStorerOut(4, 2); + cStoreOut(1, 3); + cStoreOut(2, 3); + cStorerOut(3, 3); + cStorerOut(4, 3); +#endif + } + +#ifndef PRECISION_R4 +#ifndef BLOCK + TIMING_STOP(STRCAT(timing_bin_, NAME)); +#endif +#endif + +} + +# undef cCopy +# undef cCopyr +# undef cSum +# undef cDiff +# undef cDiff2 +# undef cDiff2 +# undef cDiff3 +# undef cProd +# undef cAdd +# undef cAddSum +# undef cAddProd +# undef cLoadAf +# undef cLoadAb +# undef cLoadU +# undef cProdAfU +# undef cProdAbU +# undef cAddProdAfU +# undef cAddProdAbU +# undef cLoadOut +# undef cLoadrOut +# undef cStoreOut +# undef cStorerOut diff --git a/src/fermi/d/D103xyzt_r4.c b/src/fermi/d/D103xyzt_r4.c new file mode 100644 index 0000000000000000000000000000000000000000..fafe2b7aed13a9142842866c341c0ab179d3eb49 --- /dev/null +++ b/src/fermi/d/D103xyzt_r4.c @@ -0,0 +1,335 @@ +/* +!=============================================================================== +! +! D103xyzt_r4.c +! +!------------------------------------------------------------------------------- +! +! Copyright (C) 2011 Hinnerk Stueben +! +! This file is part of BQCD -- Berlin Quantum ChromoDynamics program +! +! BQCD 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 Foundation, either version 3 of the License, or +! (at your option) any later version. +! +! BQCD is distributed in the hope that it will be useful, +! but WITHOUT ANY WARRANTY; without even the implied warranty of +! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +! GNU General Public License for more details. +! +! You should have received a copy of the GNU General Public License +! along with BQCD. If not, see <http://www.gnu.org/licenses/>. +! +!------------------------------------------------------------------------------- +*/ +# include <xmmintrin.h> +# include <emmintrin.h> +# include <pmmintrin.h> +# include "c_defs.h" + +# define cAdd(a, b) a = _mm_add_ps(a, b) +# define cSum(a, b, c) a = _mm_add_ps(b, c) +# define cDiff(a, b, c) a = _mm_sub_ps(b, c) + +#ifdef DAGGER +# define cDiff2(a, b, c) cDiff(a, c, b) +#else +# define cDiff2(a, b, c) cDiff(a, b, c) +#endif + +#ifdef DAGGER +# define cDiff3(a, b, c) a = _mm_mul_ps(conjgr, _mm_sub_ps(b, c)) +#else +# define cDiff3(a, b, c) a = _mm_mul_ps(conjg, _mm_sub_ps(b, c)) +#endif + +# define cLoadAf(s, c) STRCAT3(af_ri,s,c) = _mm_load_ps((float*) &(a_fwd(s, c, jf))); \ + STRCAT3(af_ir,s,c) = _mm_shuffle_ps(_mm_loadr_ps((float*) &(a_fwd(s, c, jf))), \ + _mm_loadr_ps((float*) &(a_fwd(s, c, jf))), _MM_SHUFFLE(1,0,3,2)) + +# define cLoadAb(s, c) STRCAT3(ab_ri,s,c) = _mm_load_ps((float*) &(a_bwd(s, c, jb))); \ + STRCAT3(ab_ir,s,c) = _mm_shuffle_ps(_mm_loadr_ps((float*) &(a_bwd(s, c, jb))), \ + _mm_loadr_ps((float*) &(a_bwd(s, c, jb))), _MM_SHUFFLE(1,0,3,2)) + +# define cLoadU(c, d) STRCAT3(u_rr,c,d) = _mm_load1_ps((float*) &(Re(u(c, d, i)))); \ + STRCAT3(u_ii,c,d) = _mm_load1_ps((float*) &(Im(u(c, d, i)))) + +# define cProdAfU(s, c, d) STRCAT3(bf,s,c) = _mm_addsub_ps(_mm_mul_ps(STRCAT3(af_ri,s,d), STRCAT3(u_rr,c,d)), _mm_mul_ps(STRCAT3(af_ir,s,d), STRCAT3(u_ii,c,d))) +# define cProdAbU(s, c, d) STRCAT3(bb,s,c) = _mm_addsub_ps(_mm_mul_ps(STRCAT3(ab_ri,s,d), STRCAT3(u_rr,c,d)), _mm_mul_ps(STRCAT3(ab_ir,s,d), STRCAT3(u_ii,c,d))) + +# define cAddProdAfU(s, c, d) cAdd(STRCAT3(bf,s,c), _mm_addsub_ps(_mm_mul_ps(STRCAT3(af_ri,s,d), STRCAT3(u_rr,c,d)), _mm_mul_ps(STRCAT3(af_ir,s,d), STRCAT3(u_ii,c,d)))) +# define cAddProdAbU(s, c, d) cAdd(STRCAT3(bb,s,c), _mm_addsub_ps(_mm_mul_ps(STRCAT3(ab_ri,s,d), STRCAT3(u_rr,c,d)), _mm_mul_ps(STRCAT3(ab_ir,s,d), STRCAT3(u_ii,c,d)))) + +# define cShuffleR(a) _mm_shuffle_ps(a, a, _MM_SHUFFLE(2,3,0,1)) + +# define cLoadOut(s, c) STRCAT3(out,s,c) = _mm_load_ps((float*) &(out(s, c, i))) +# define cLoadrOut(s, c) STRCAT3(out,s,c) = cShuffleR(_mm_load_ps((float*) &(out(s, c, i)))) +# define cStoreOut(s, c) _mm_store_ps((float*) &(out(s, c, i)), STRCAT3(out,s,c)) +# define cStorerOut(s, c) _mm_store_ps((float*) &(out(s, c, i)), cShuffleR(STRCAT3(out,s,c))) + + +# define out(a, b, c) out_[c][b-1][a-1] +# define a_fwd(a, b, c) a_fwd_[c][b-1][a-1] +# define a_bwd(a, b, c) a_bwd_[c][b-1][a-1] +# define u(a, b, c) u_[c][b-1][a-1] +# define nn_fwd(c) nn_fwd_[c] +# define nn_bwd(c) nn_bwd_[c] + +/*------------------------------------------------------------------------*/ +void STRCAT(NAME, _)(SPINCOL_FIELD out_, + SC2_FLD a_fwd_, + SC2_FLD a_bwd_, + REORDERED_GAUGE_FIELD u_, + INTEGER nn_fwd_[], + INTEGER nn_bwd_[], +#ifdef BLOCK + int *i1, int *i2) +#else + int *volh) +#endif + +{ + int i, jf, jb; + __m128 af_ri11,af_ri12,af_ri13; + __m128 af_ir11,af_ir12,af_ir13; + __m128 ab_ri11,ab_ri12,ab_ri13; + __m128 ab_ir11,ab_ir12,ab_ir13; + __m128 u_rr11,u_rr12,u_rr13,u_rr21,u_rr22,u_rr23,u_rr31,u_rr32,u_rr33; + __m128 u_rr41,u_rr42,u_rr43,u_rr51,u_rr52,u_rr53,u_rr61,u_rr62,u_rr63; + __m128 u_ii11,u_ii12,u_ii13,u_ii21,u_ii22,u_ii23,u_ii31,u_ii32,u_ii33; + __m128 u_ii41,u_ii42,u_ii43,u_ii51,u_ii52,u_ii53,u_ii61,u_ii62,u_ii63; + __m128 bf11,bf12,bf13; + __m128 bb14,bb15,bb16; + __m128 out11, out31, out12, out32, out13, out33; + __m128 tmp11, tmp31, tmp12, tmp32, tmp13, tmp33; + + const __m128 conjg = _mm_setr_ps(ONE, -ONE, ONE, -ONE); + const __m128 conjgr = _mm_set_ps(ONE, -ONE, ONE, -ONE); + + + out_--; + a_fwd_--; + a_bwd_--; + u_--; + nn_fwd_--; + nn_bwd_--; + +#ifdef BLOCK + for (i = *i1; i <= *i2; i++) +#else + #pragma omp parallel for \ + private (i, jf, jb) \ + private (af_ri11,af_ri12,af_ri13) \ + private (af_ir11,af_ir12,af_ir13) \ + private (ab_ri11,ab_ri12,ab_ri13) \ + private (ab_ir11,ab_ir12,ab_ir13) \ + private (u_rr11,u_rr12,u_rr13,u_rr21,u_rr22,u_rr23,u_rr31,u_rr32,u_rr33) \ + private (u_rr41,u_rr42,u_rr43,u_rr51,u_rr52,u_rr53,u_rr61,u_rr62,u_rr63) \ + private (u_ii11,u_ii12,u_ii13,u_ii21,u_ii22,u_ii23,u_ii31,u_ii32,u_ii33) \ + private (u_ii41,u_ii42,u_ii43,u_ii51,u_ii52,u_ii53,u_ii61,u_ii62,u_ii63) \ + private (bf11,bf12,bf13) \ + private (bb14,bb15,bb16) \ + private (out11, out31, out12, out32, out13, out33) \ + private (tmp11, tmp31, tmp12, tmp32, tmp13, tmp33) + + for (i = 1; i <= *volh; i++) +#endif + { + jf=nn_fwd(i); + jb=nn_bwd(i); + + cLoadAf(1, 1); + cLoadU(1, 1); + cLoadU(2, 1); + cLoadU(3, 1); + cProdAfU(1, 1, 1); + cProdAfU(1, 2, 1); + cProdAfU(1, 3, 1); + + cLoadAb(1, 1); + cLoadU(4, 1); + cLoadU(5, 1); + cLoadU(6, 1); + cProdAbU(1, 4, 1); + cProdAbU(1, 5, 1); + cProdAbU(1, 6, 1); + + cLoadAf(1, 2); + cLoadU(1, 2); + cLoadU(2, 2); + cLoadU(3, 2); + cAddProdAfU(1, 1, 2); + cAddProdAfU(1, 2, 2); + cAddProdAfU(1, 3, 2); + + cLoadAb(1, 2); + cLoadU(4, 2); + cLoadU(5, 2); + cLoadU(6, 2); + cAddProdAbU(1, 4, 2); + cAddProdAbU(1, 5, 2); + cAddProdAbU(1, 6, 2); + + cLoadAf(1, 3); + cLoadU(1, 3); + cLoadU(2, 3); + cLoadU(3, 3); + cAddProdAfU(1, 1, 3); + cAddProdAfU(1, 2, 3); + cAddProdAfU(1, 3, 3); + + cLoadAb(1, 3); + cLoadU(4, 3); + cLoadU(5, 3); + cLoadU(6, 3); + cAddProdAbU(1, 4, 3); + cAddProdAbU(1, 5, 3); + cAddProdAbU(1, 6, 3); + + +#ifdef DIR_T + cLoadOut(1, 1); + cLoadOut(3, 1); + cLoadOut(1, 2); + cLoadOut(3, 2); + cLoadOut(1, 3); + cLoadOut(3, 3); +#ifdef DAGGER + cAdd(out11, bf11); + cAdd(out31, bb14); + cAdd(out12, bf12); + cAdd(out32, bb15); + cAdd(out13, bf13); + cAdd(out33, bb16); +#else + cAdd(out11, bb14); + cAdd(out31, bf11); + cAdd(out12, bb15); + cAdd(out32, bf12); + cAdd(out13, bb16); + cAdd(out33, bf13); +#endif + cStoreOut(1, 1); + cStoreOut(3, 1); + cStoreOut(1, 2); + cStoreOut(3, 2); + cStoreOut(1, 3); + cStoreOut(3, 3); +#endif + +#ifdef DIR_X +# define cShuffleX(a) _mm_shuffle_ps(a, a, _MM_SHUFFLE(1,0,3,2)) + + cSum(out11, bf11, bb14); + cDiff3(out31, cShuffleX(bf11), cShuffleX(bb14)); + + cSum(out12, bf12, bb15); + cDiff3(out32, cShuffleX(bf12), cShuffleX(bb15)); + + cSum(out13, bf13, bb16); + cDiff3(out33, cShuffleX(bf13), cShuffleX(bb16)); + + cStoreOut(1, 1); + cStorerOut(3, 1); + cStoreOut(1, 2); + cStorerOut(3, 2); + cStoreOut(1, 3); + cStorerOut(3, 3); +#endif + + +#ifdef DIR_Y + +# define cShuffleY(a, b) _mm_shuffle_ps(a, b, _MM_SHUFFLE(1,0,3,2)) + + cSum(tmp11, bf11, bb14); + cDiff2(tmp31, cShuffleY(bf11, bb14), cShuffleY(bb14, bf11)); + + cSum(tmp12, bf12, bb15); + cDiff2(tmp32, cShuffleY(bf12, bb15), cShuffleY(bb15, bf12)); + + cSum(tmp13, bf13, bb16); + cDiff2(tmp33, cShuffleY(bf13, bb16), cShuffleY(bb16, bf13)); + + cLoadOut(1, 1); + cLoadOut(3, 1); + cLoadOut(1, 2); + cLoadOut(3, 2); + cLoadOut(1, 3); + cLoadOut(3, 3); + + cAdd(out11, tmp11); + cAdd(out31, tmp31); + cAdd(out12, tmp12); + cAdd(out32, tmp32); + cAdd(out13, tmp13); + cAdd(out33, tmp33); + + cStoreOut(1, 1); + cStoreOut(3, 1); + cStoreOut(1, 2); + cStoreOut(3, 2); + cStoreOut(1, 3); + cStoreOut(3, 3); +#endif + +#ifdef DIR_Z +# define cShuffleZ(a, b) _mm_shuffle_ps(a, b, _MM_SHUFFLE(3,2,1,0)) + + cSum(tmp11, bf11, bb14); + cDiff3(tmp31, cShuffleZ(bf11, bb14), cShuffleZ(bb14, bf11)); + + cSum(tmp12, bf12, bb15); + cDiff3(tmp32, cShuffleZ(bf12, bb15), cShuffleZ(bb15, bf12)); + + cSum(tmp13, bf13, bb16); + cDiff3(tmp33, cShuffleZ(bf13, bb16), cShuffleZ(bb16, bf13)); + + cLoadOut(1, 1); + cLoadrOut(3, 1); + cLoadOut(1, 2); + cLoadrOut(3, 2); + cLoadOut(1, 3); + cLoadrOut(3, 3); + + cAdd(out11, tmp11); + cAdd(out31, tmp31); + cAdd(out12, tmp12); + cAdd(out32, tmp32); + cAdd(out13, tmp13); + cAdd(out33, tmp33); + + cStoreOut(1, 1); + cStorerOut(3, 1); + cStoreOut(1, 2); + cStorerOut(3, 2); + cStoreOut(1, 3); + cStorerOut(3, 3); +#endif + } +} + +# undef cCopy +# undef cCopyr +# undef cSum +# undef cDiff +# undef cDiff2 +# undef cDiff2 +# undef cDiff3 +# undef cProd +# undef cAdd +# undef cAddSum +# undef cAddProd +# undef cLoadAf +# undef cLoadAb +# undef cLoadU +# undef cProdAfU +# undef cProdAbU +# undef cAddProdAfU +# undef cAddProdAbU +# undef cLoadOut +# undef cLoadrOut +# undef cStoreOut +# undef cStorerOut diff --git a/src/fermi/d/D520_g.F90 b/src/fermi/d/D520_g.F90 index c4996b38a73b205d96fea76e7af0912a4d09d59e..2c3b4cf3b6d430bfb74cc609cc2c4cf37211a33e 100644 --- a/src/fermi/d/D520_g.F90 +++ b/src/fermi/d/D520_g.F90 @@ -41,7 +41,9 @@ subroutine d_g_init(u_orig) ! copies the original gauge field to "wilson" !!call flip_bc(u_orig) !! call d_g_init_r4(u) - +#ifdef QUAD + call d_g_init100(u_orig) +#endif end !=============================================================================== diff --git a/src/fermi/d/D520_init.F90 b/src/fermi/d/D520_init.F90 index 313c9a14eb577b65f79593b3380713873fe4ec0f..8fb296dc13806de30d306955cbcee1880d1d2ac4 100644 --- a/src/fermi/d/D520_init.F90 +++ b/src/fermi/d/D520_init.F90 @@ -32,6 +32,9 @@ subroutine init_d() implicit none call wilson_init(n, npe, volh_tot, nn) +#ifdef QUAD + call init_d100() +#endif end !=============================================================================== diff --git a/src/fermi/d/Makefile b/src/fermi/d/Makefile index 5b9eef83f7eb3c82d04b8f5cea3dd2df1f8aea97..5fadb8e4630ee07a648b7b197e0bef178f23da91 100644 --- a/src/fermi/d/Makefile +++ b/src/fermi/d/Makefile @@ -4,7 +4,7 @@ # #------------------------------------------------------------------------------- # -# Copyright (C) 1998-2007 Hinnerk Stueben +# Copyright (C) 1998-2011 Hinnerk Stueben # # This file is part of BQCD -- Berlin Quantum ChromoDynamics program # @@ -34,16 +34,17 @@ endif .SUFFIXES: -.SUFFIXES: .a .o .f90 .F90 .m4 +.SUFFIXES: .a .o .f90 .F90 .c .m4 .f90.o: $(F90) -c $(FFLAGS) $< -MODULES_DIR = ../../modules +.c.o: + $(CC) -c -I../../include $(MYFLAGS) $(CFLAGS) $< + $(LIBD): -###include DSF.mk include D_PROJ.mk include $(LIBD:.a=.mk) @@ -69,9 +70,15 @@ d_r4.f90: D_r4.F90 d_xbound.f90: D_xbound.F90 $(fpp) D_xbound.F90 > $@ + +chemicalp.f90: chemicalp.F90; $(fpp) $< > $@ + clean: rm -f *.[Tiod] *.f90 *.mod work.pc work.pcl - -rm -f dxyzt.F90 dxyzt_block.F90 d100.F90 + rm -f dxyzt.F90 dxyzt_block.F90 d100.F90 d103.F90 + rm -f dxyzt.c dxyzt_r4.c + rm -f dxyzt_block.c dxyzt_block_r4.c dxyzt_block2.c dxyzt_block2_r4.c + rm -f dproj.c ddagproj.c dproj_r4.c ddagproj_r4.c clobber: clean rm -f libd*.a diff --git a/src/measure/chemicalp.F90 b/src/fermi/d/chemicalp.F90 similarity index 93% rename from src/measure/chemicalp.F90 rename to src/fermi/d/chemicalp.F90 index f8e5578eb5514610f6ffc52fb3319529618fa500..11463569d6f60cf23feb91e074c59a0b310ac94a 100644 --- a/src/measure/chemicalp.F90 +++ b/src/fermi/d/chemicalp.F90 @@ -50,22 +50,24 @@ subroutine apply_mp_chemu(oe, oo, ie, io, mid, chemu, i)! d^i M / (d mu)^i call d(EVEN, ODD, oe, io, gauge(2)%u) oo = - action%mtilde(mid)%kappa * oo oe = - action%mtilde(mid)%kappa * oe - call d_g_u_reorder(gauge(2)%u) + call d_g_init(gauge(2)%u) end !------------------------------------------------------------------------------- -subroutine emuu4(u, fac1, fac2) - use module_d_g_reorder +#ifdef LIBDI +subroutine emuu4(u, fac1, fac2, uzero) use module_nn use module_vol use module_lattice + use module_d_g_reorder implicit none GAUGE_FIELD, intent(in) :: u REAL, intent(in) :: fac1, fac2 + logical :: uzero integer :: eo, oe, i, j, mu, col, c1, c2 - u_reorder = 0 + if (uzero)u_reorder=0 mu = gamma_index(4) do eo = EVEN, ODD @@ -85,5 +87,9 @@ subroutine emuu4(u, fac1, fac2) enddo end - +#else +subroutine emuu4() +call die("emuu4: works only when LIBDI") +end +#endif !=============================================================================== diff --git a/src/fermi/d/libd.mk b/src/fermi/d/libd.mk index ffd80c8d8fc6ab301888ca5efcd915a9dbfd0db3..8945552fc3fbad3242e71ce77011f2e4352dd089 100644 --- a/src/fermi/d/libd.mk +++ b/src/fermi/d/libd.mk @@ -61,7 +61,8 @@ OBJS = \ d_version.o \ d_block.o \ d_projection.o \ - d_xbound.o + d_xbound.o \ + chemicalp.o R4_FLAGS = -DPRECISION_R4 -DD_R4_INTERNAL diff --git a/src/fermi/d/libd100.mk b/src/fermi/d/libd100.mk index 0d8cf3cb87d1bce0c2022b66cde9d3f9c6c41937..10458cf10679c475226415a7c230624e921d5707 100644 --- a/src/fermi/d/libd100.mk +++ b/src/fermi/d/libd100.mk @@ -29,7 +29,11 @@ M4=m4 MODULES = \ module_d21.o \ - module_d21_r4.o + module_d21_r4.o \ + +ifdef quad +MODULES += module_d21_r16.o +endif OBJS = \ d$(libd)_g.o \ @@ -39,9 +43,18 @@ OBJS = \ dxyzt_block.o \ dxyzt_r4.o \ d$(libd)_r4.o \ - dxyzt_block_r4.o + dxyzt_block_r4.o \ + chemicalp.o + +ifdef quad +OBJS += dxyzt_r16.o \ + d$(libd)_r16.o \ + dxyzt_block_r16.o +endif + + + -# d_init.o \ R4_FLAGS = -DPRECISION_R4 -DD_R4_INTERNAL @@ -50,7 +63,8 @@ fast: $(FAST_MAKE) module_d21.f90: module_d21.F90; $(fpp) $< > $@ -module_d21_r4.f90: module_d21.F90; $(fpp) $(R4_FLAGS) $< > $@ +module_d21_r4.f90: module_d21.F90; $(fpp) -DPRECISION_R4 $< > $@ +module_d21_r16.f90: module_d21.F90; $(fpp) -DPRECISION_R16 $< > $@ d100.F90: D100.m4; $(M4) -I../../include $(MYFLAGS) D100.m4 >d100.F90 @@ -81,6 +95,12 @@ d$(libd).f90: d$(libd).F90; $(fpp) d$(libd).F90 > d$(libd).f90 dxyzt.f90: dxyzt.F90; $(fpp) dxyzt.F90 > $@ dxyzt_block.f90: dxyzt_block.F90; $(fpp) dxyzt_block.F90 > $@ -d100_r4.f90: d100_r4.F90; $(fpp) d100_r4.F90 > $@ -dxyzt_r4.f90: dxyzt_r4.F90; $(fpp) dxyzt_r4.F90 > $@ -dxyzt_block_r4.f90: dxyzt_block_r4.F90; $(fpp) dxyzt_block_r4.F90 > $@ +d100_r4.f90: d100.F90; $(fpp) -DPRECISION_R4 $< > $@ +dxyzt_r4.f90: dxyzt.F90; $(fpp) -DPRECISION_R4 $< > $@ +dxyzt_block_r4.f90: dxyzt_block.F90; $(fpp) -DPRECISION_R4 $< > $@ + +d100_r16.f90: d100.F90; $(fpp) -DPRECISION_R16 $< > $@ +dxyzt_r16.f90: dxyzt.F90; $(fpp) -DPRECISION_R16 $< > $@ +dxyzt_block_r16.f90: dxyzt_block.F90; $(fpp) -DPRECISION_R16 $< > $@ + +#chemicalp.f90: chemicalp.F90; $(fpp) $< > $@ diff --git a/src/fermi/d/libd103.mk b/src/fermi/d/libd103.mk new file mode 100644 index 0000000000000000000000000000000000000000..f7135d6cfac988e6f9b1d9bd9bf207393f5eda06 --- /dev/null +++ b/src/fermi/d/libd103.mk @@ -0,0 +1,121 @@ +#=============================================================================== +# +# d/libd103.mk - libd100 with SSE for GAMMA_NOTATION=BQCD +# +#------------------------------------------------------------------------------- +# +# Copyright (C) 2008-2011 Yoshifumi Nakamura, Hinnerk Stueben +# +# This file is part of BQCD -- Berlin Quantum ChromoDynamics program +# +# BQCD 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 Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BQCD is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BQCD. If not, see <http://www.gnu.org/licenses/>. +# +#=============================================================================== + +FAST_MAKE = make -j 1 + +M4=m4 + +MODULES = \ + module_d21.o \ + module_d21_r4.o \ + +ifdef quad +MODULES += module_d21_r16.o +endif + +OBJS = \ + d100_g.o \ + d103_version.o \ + d103.o \ + dxyzt.o \ + dxyzt_block.o \ + dxyzt_block2.o \ + dxyzt_r4.o \ + d103_r4.o \ + dxyzt_block_r4.o \ + dxyzt_block2_r4.o \ + chemicalp.o + +ifdef quad +OBJS += dxyzt_r16.o \ + d100_r16.o \ + dxyzt_block_r16.o +endif + + +R4_FLAGS = -DPRECISION_R4 -DD_R4_INTERNAL + +fast: + $(MAKE) $(MODULES) + $(FAST_MAKE) + +module_d21.f90: module_d21.F90; $(fpp) $< > $@ +module_d21_r4.f90: module_d21.F90; $(fpp) -DPRECISION_R4 $< > $@ +module_d21_r16.f90: module_d21.F90; $(fpp) -DPRECISION_R16 $< > $@ + +d100.F90: D100.m4; $(M4) -I../../include $(MYFLAGS) D100.m4 >d100.F90 +d103.F90: D103.m4; $(M4) -I../../include $(MYFLAGS) D103.m4 >d103.F90 + +dxyzt.c: D103.c + $(CPP) -I../../include $(CFLAGS_STD) $(MYFLAGS) $< > $@ + +dxyzt_r4.c: D103_r4.c + $(CPP) -I../../include $(CFLAGS_STD) $(MYFLAGS) $< > $@ + +dxyzt_block2.c: D103_block.c + $(CPP) -I../../include $(CFLAGS_STD) $(MYFLAGS) $< > $@ + +dxyzt_block2_r4.c: D103_block_r4.c + $(CPP) -I../../include $(CFLAGS_STD) $(MYFLAGS) $< > $@ + +dxyzt.c: D103xyzt.c +dxyzt_r4.c: D103xyzt_r4.c +dxyzt_block2.c: D103xyzt.c +dxyzt_block2_r4.c: D103xyzt_r4.c + +dxyzt.F90: D100_util.m4 + $(M4) -I../../include $(MYFLAGS) -DNAME=xf -DDIRECTION=X D100_util.m4 > dxyzt.F90 + $(M4) -I../../include $(MYFLAGS) -DNAME=yf -DDIRECTION=Y D100_util.m4 >>dxyzt.F90 + $(M4) -I../../include $(MYFLAGS) -DNAME=zf -DDIRECTION=Z D100_util.m4 >>dxyzt.F90 + $(M4) -I../../include $(MYFLAGS) -DNAME=t -DDIRECTION=T D100_util.m4 >>dxyzt.F90 + $(M4) -I../../include $(MYFLAGS) -DNAME=dag_xf -DDIRECTION=X -DDAGGER D100_util.m4 >>dxyzt.F90 + $(M4) -I../../include $(MYFLAGS) -DNAME=dag_yf -DDIRECTION=Y -DDAGGER D100_util.m4 >>dxyzt.F90 + $(M4) -I../../include $(MYFLAGS) -DNAME=dag_zf -DDIRECTION=Z -DDAGGER D100_util.m4 >>dxyzt.F90 + $(M4) -I../../include $(MYFLAGS) -DNAME=dag_t -DDIRECTION=T -DDAGGER D100_util.m4 >>dxyzt.F90 + +dxyzt_block.F90: D103_util_block.m4 + $(M4) -I../../include $(MYFLAGS) -DNAME=x -DDIRECTION=X D103_util_block.m4 > dxyzt_block.F90 + $(M4) -I../../include $(MYFLAGS) -DNAME=y -DDIRECTION=Y D103_util_block.m4 >>dxyzt_block.F90 + $(M4) -I../../include $(MYFLAGS) -DNAME=z -DDIRECTION=Z D103_util_block.m4 >>dxyzt_block.F90 + $(M4) -I../../include $(MYFLAGS) -DNAME=t -DDIRECTION=T D103_util_block.m4 >>dxyzt_block.F90 + $(M4) -I../../include $(MYFLAGS) -DNAME=dag_x -DDIRECTION=X -DDAGGER D103_util_block.m4 >>dxyzt_block.F90 + $(M4) -I../../include $(MYFLAGS) -DNAME=dag_y -DDIRECTION=Y -DDAGGER D103_util_block.m4 >>dxyzt_block.F90 + $(M4) -I../../include $(MYFLAGS) -DNAME=dag_z -DDIRECTION=Z -DDAGGER D103_util_block.m4 >>dxyzt_block.F90 + $(M4) -I../../include $(MYFLAGS) -DNAME=dag_t -DDIRECTION=T -DDAGGER D103_util_block.m4 >>dxyzt_block.F90 + +d100_g.f90: D100_g.F90; $(fpp) D100_g.F90 > $@ +d103_version.f90: DVersion.F90; $(fpp) -DVERSION=103 DVersion.F90 > $@ + +d103.f90: d103.F90; $(fpp) d103.F90 > d103.f90 +dxyzt_block.f90: dxyzt_block.F90; $(fpp) dxyzt_block.F90 > $@ + +d103_r4.f90: d103.F90; $(fpp) -DPRECISION_R4 $< > $@ +dxyzt_block_r4.f90: dxyzt_block.F90; $(fpp) -DPRECISION_R4 $< > $@ + +d100_r16.f90: d100.F90; $(fpp) -DPRECISION_R16 $< > $@ +dxyzt_r16.f90: dxyzt.F90; $(fpp) -DPRECISION_R16 $< > $@ +dxyzt_block_r16.f90: dxyzt_block.F90; $(fpp) -DPRECISION_R16 $< > $@ + +chemicalp.f90: chemicalp.F90; $(fpp) $< > $@ diff --git a/src/fermi/d/libd2.mk b/src/fermi/d/libd2.mk index 93f5a27caab44b4bf236fbcf444fb653de3d2d63..d57e0da91901e4d5b64fbb44e51ff78929dcc0aa 100644 --- a/src/fermi/d/libd2.mk +++ b/src/fermi/d/libd2.mk @@ -56,7 +56,8 @@ OBJS = \ d2_dag_y_block.o \ d2_dag_z_block.o \ d2_dag_t_block.o \ - d2_version.o + d2_version.o \ + chemicalp.o R4_FLAGS = -DPRECISION_R4 -DD_R4_INTERNAL diff --git a/src/fermi/d/libd21.mk b/src/fermi/d/libd21.mk index 2e61d584012c2b509440d287cdd7dd0e2ad60c82..f6d9f0d0db07f0205ef46f2a74e4102db411caba 100644 --- a/src/fermi/d/libd21.mk +++ b/src/fermi/d/libd21.mk @@ -59,7 +59,8 @@ OBJS = \ d21_dag_y_block.o \ d21_dag_z_block.o \ d21_dag_t_block.o \ - d21_version.o + d21_version.o \ + chemicalp.o R4_FLAGS = -DPRECISION_R4 -DD_R4_INTERNAL diff --git a/src/fermi/d/libd25.mk b/src/fermi/d/libd25.mk index 616a6e3e50b56c19aff0c1cde78ce65892641964..b1ed4219666286cdd45ae896f61e35bbe89291af 100644 --- a/src/fermi/d/libd25.mk +++ b/src/fermi/d/libd25.mk @@ -56,7 +56,8 @@ OBJS = \ d2_dag_y_block.o \ d2_dag_z_block.o \ d2_dag_t_block.o \ - d25_version.o + d25_version.o \ + chemicalp.o R4_FLAGS = -DPRECISION_R4 -DD_R4_INTERNAL diff --git a/src/fermi/d/libd3.mk b/src/fermi/d/libd3.mk index 8fd75f9509d033f7ce020ee2df9e89809b1774aa..89037b3a523700a37c8f960fc30973bf824c4edd 100644 --- a/src/fermi/d/libd3.mk +++ b/src/fermi/d/libd3.mk @@ -49,7 +49,8 @@ OBJS = \ d3_version.o \ d_block.o \ d_projection.o \ - d_xbound.o + d_xbound.o \ + chemicalp.o R4_FLAGS = -DPRECISION_R4 -DD_R4_INTERNAL diff --git a/src/fermi/d/libd520.mk b/src/fermi/d/libd520.mk index 61c08591600d56546e94016197f606fd1979deed..a02c4486bdd2532f54b351f5a43d3743fc9c856c 100644 --- a/src/fermi/d/libd520.mk +++ b/src/fermi/d/libd520.mk @@ -42,17 +42,13 @@ OBJS = \ wilson_d520/globals.o \ wilson_d520/adirac.o -# d45_r4.o \ -# d4_bwd_r4.o \ -# d4_fwd_r4.o \ -# d45_dag_r4.o \ -# d4_dag_bwd_r4.o \ -# d4_dag_fwd_r4.o \ -# d4_bwd.o \ -# d4_fwd.o \ -# d4_dag_bwd.o \ -# d4_dag_fwd.o \ -# d4_g_r4.o \ +ifdef quad +OBJS += module_d21_r16.o \ + d100_g.o \ + d100_r16.o \ + dxyzt_r16.o \ + dxyzt_block_r16.o +endif R4_FLAGS = -DPRECISION_R4 -DD_R4_INTERNAL @@ -106,3 +102,31 @@ d520.f90: D520.F90; $(fpp) -DNAME=d -UDAGGER D520.F90 > $@ d520_dag.f90: D520.F90; $(fpp) -DNAME=d_dag -DDAGGER D520.F90 > $@ +d100.F90: D100.m4; $(M4) -I../../include $(MYFLAGS) D100.m4 >d100.F90 +dxyzt.F90: D100_util.m4 + $(M4) -I../../include $(MYFLAGS) -DNAME=xf -DDIRECTION=X D100_util.m4 > dxyzt.F90 + $(M4) -I../../include $(MYFLAGS) -DNAME=yf -DDIRECTION=Y D100_util.m4 >>dxyzt.F90 + $(M4) -I../../include $(MYFLAGS) -DNAME=zf -DDIRECTION=Z D100_util.m4 >>dxyzt.F90 + $(M4) -I../../include $(MYFLAGS) -DNAME=t -DDIRECTION=T D100_util.m4 >>dxyzt.F90 + $(M4) -I../../include $(MYFLAGS) -DNAME=dag_xf -DDIRECTION=X -DDAGGER D100_util.m4 >>dxyzt.F90 + $(M4) -I../../include $(MYFLAGS) -DNAME=dag_yf -DDIRECTION=Y -DDAGGER D100_util.m4 >>dxyzt.F90 + $(M4) -I../../include $(MYFLAGS) -DNAME=dag_zf -DDIRECTION=Z -DDAGGER D100_util.m4 >>dxyzt.F90 + $(M4) -I../../include $(MYFLAGS) -DNAME=dag_t -DDIRECTION=T -DDAGGER D100_util.m4 >>dxyzt.F90 + +dxyzt_block.F90: D100_util_block.m4 + $(M4) -I../../include $(MYFLAGS) -DNAME=x -DDIRECTION=X D100_util_block.m4 > dxyzt_block.F90 + $(M4) -I../../include $(MYFLAGS) -DNAME=y -DDIRECTION=Y D100_util_block.m4 >>dxyzt_block.F90 + $(M4) -I../../include $(MYFLAGS) -DNAME=z -DDIRECTION=Z D100_util_block.m4 >>dxyzt_block.F90 + $(M4) -I../../include $(MYFLAGS) -DNAME=t -DDIRECTION=T D100_util_block.m4 >>dxyzt_block.F90 + $(M4) -I../../include $(MYFLAGS) -DNAME=dag_x -DDIRECTION=X -DDAGGER D100_util_block.m4 >>dxyzt_block.F90 + $(M4) -I../../include $(MYFLAGS) -DNAME=dag_y -DDIRECTION=Y -DDAGGER D100_util_block.m4 >>dxyzt_block.F90 + $(M4) -I../../include $(MYFLAGS) -DNAME=dag_z -DDIRECTION=Z -DDAGGER D100_util_block.m4 >>dxyzt_block.F90 + $(M4) -I../../include $(MYFLAGS) -DNAME=dag_t -DDIRECTION=T -DDAGGER D100_util_block.m4 >>dxyzt_block.F90 + + + +module_d21_r16.f90: module_d21.F90; $(fpp) -DPRECISION_R16 $< > $@ +d100_g.f90: D100_g.F90; $(fpp) -DD520 D100_g.F90 > $@ +d100_r16.f90: d100.F90; $(fpp) -DPRECISION_R16 $< > $@ +dxyzt_r16.f90: dxyzt.F90; $(fpp) -DPRECISION_R16 $< > $@ +dxyzt_block_r16.f90: dxyzt_block.F90; $(fpp) -DPRECISION_R16 $< > $@ diff --git a/src/fermi/dd/dsf_dd.F90 b/src/fermi/dd/dsf_dd.F90 index 0c0319494d6cce818a1ae78bffba558e92c61ea5..3c1e174492658c4e4f0545a7c85b148bf39fa3a8 100644 --- a/src/fermi/dd/dsf_dd.F90 +++ b/src/fermi/dd/dsf_dd.F90 @@ -189,7 +189,7 @@ subroutine dsf_hh2(p, step, calc_sf, sf, id) call hmc_forces_old(p) if (mid2 ==0 ) then - call dsf_mtdagmt_hh(p, step, a, b, mid1,0) + call dsf_mtdagmt_hh(p, step, a, b, mid1) else if (switches%mass_kappa) then call dsf_mtdagmt_hh(p, step, a, b, mid1) diff --git a/src/fermi/dd/init_dd.F90 b/src/fermi/dd/init_dd.F90 index 68a4b4ffb7bac23f216cdfafd6983aa24d90b6e0..5aea1da539ab2c6f25e032438da2aa000da68900 100644 --- a/src/fermi/dd/init_dd.F90 +++ b/src/fermi/dd/init_dd.F90 @@ -142,6 +142,7 @@ subroutine init_dd() end !------------------------------------------------------------------------------- subroutine init_ddeo_count(nn) + use module_function_decl use module_dd implicit none type(type_nn) :: nn @@ -189,6 +190,28 @@ subroutine init_ddeo_count(nn) ! enddo !stop +#ifdef DEBUG2 +if (my_pe()==0) then +write(0,*) nn%count_dd(0,1,FWD)+nn%count_dd(0,1,BWD) +write(0,*) nn%count_dd(0,2,FWD)+nn%count_dd(0,2,BWD) +write(0,*) nn%count_dd(0,3,FWD)+nn%count_dd(0,3,BWD) +write(0,*) nn%count_dd(0,4,FWD)+nn%count_dd(0,4,BWD) +write(0,*) nn%count_dd(1,1,FWD)+nn%count_dd(1,1,BWD) +write(0,*) nn%count_dd(1,2,FWD)+nn%count_dd(1,2,BWD) +write(0,*) nn%count_dd(1,3,FWD)+nn%count_dd(1,3,BWD) +write(0,*) nn%count_dd(1,4,FWD)+nn%count_dd(1,4,BWD) + +write(0,*) nn%count_eo(0,1,FWD)+nn%count_eo(0,1,BWD) +write(0,*) nn%count_eo(0,2,FWD)+nn%count_eo(0,2,BWD) +write(0,*) nn%count_eo(0,3,FWD)+nn%count_eo(0,3,BWD) +write(0,*) nn%count_eo(0,4,FWD)+nn%count_eo(0,4,BWD) +write(0,*) nn%count_eo(1,1,FWD)+nn%count_eo(1,1,BWD) +write(0,*) nn%count_eo(1,2,FWD)+nn%count_eo(1,2,BWD) +write(0,*) nn%count_eo(1,3,FWD)+nn%count_eo(1,3,BWD) +write(0,*) nn%count_eo(1,4,FWD)+nn%count_eo(1,4,BWD) +endif +#endif + do mu=1,DIM if (nn%count_eo(EVEN,mu,FWD)/=nn%count_eo(EVEN,mu,BWD)) call warn("init_ddeo_count: count_ef/=count_eb") if (nn%count_eo(EVEN,mu,FWD)/=nn%count_eo(ODD ,mu,FWD)) call warn("init_ddeo_count: count_ef/=count_of") diff --git a/src/fermi/dd/mult_dd.F90_v2 b/src/fermi/dd/mult_dd.F90_v2 index 0abba49e00a0c8e246fd93364123df3f4231521d..04c0e6047c316cc55b154f718bd7a8b3f5d3cb1b 100644 --- a/src/fermi/dd/mult_dd.F90_v2 +++ b/src/fermi/dd/mult_dd.F90_v2 @@ -402,8 +402,8 @@ end subroutine inv_unprec_mmul_dd_ip(out_e, out_o, in_e, in_o, id, ip, dag) use module_dd use module_action - use module_mre2 - use mre2_get_interface +!! use module_mre2 +!! use mre2_get_interface implicit none COMPLEX, dimension (12*ld%lat%volh) :: out_e, out_o COMPLEX, dimension (12*ld%lat%volh) :: in_e, in_o diff --git a/src/fermi/f_action/dsf.F90 b/src/fermi/f_action/dsf.F90 index cf80ff91a4b2398cc3cd346b9a14c44ad341dd9d..5b8045a4f725523e7d24314f3159cfd1de020c94 100644 --- a/src/fermi/f_action/dsf.F90 +++ b/src/fermi/f_action/dsf.F90 @@ -109,6 +109,11 @@ subroutine dsf_sum(w, w1, w2, step, a, b, id) REAL :: s, s1, s2 integer :: ierr + REAL :: fac1, fac2 + fac1=exp( chemi) + fac2=exp(-chemi) + + TIMING_START(timing_bin_dsf_sum) DEBUG2S("Start: dsf_sum") @@ -141,7 +146,7 @@ subroutine dsf_sum(w, w1, w2, step, a, b, id) s2 = -step * TWO * (action%mtilde(id)%cswkappa / EIGHT) * action%mtilde(id)%kappa**2 #ifdef OMTDTD ! ALLOCATE_SC_FIELD(tmp) - tmp = b + call sc_copy(tmp, b) if (s1 /= ZERO) then call clover_mult_b(clover(action%mtilde(id)%cid)%b(1,1,se), tmp, volh) endif @@ -157,7 +162,11 @@ subroutine dsf_sum(w, w1, w2, step, a, b, id) call scfield_reorder_43_to_34(at) #endif call sc_zero_halo(at) + + if (chemi /=0) call emuu4(gauge(2)%u, fac1, fac2, .false.) call d(se, so, bt, at, gauge(2)%u(1,1,1,0,1)) + if (chemi /=0) call emuu4(gauge(2)%u, ONE, ONE, .false.) + call xbound_sc_field(at) call clover_mult_b(clover(action%mtilde(id)%cid)%b(1,1,se), bt, volh) #ifdef FLIPSC @@ -289,6 +298,7 @@ end !------------------------------------------------------------------------------- subroutine dsf_at_bt(at, bt, a, b, k, ck, h, cid, e) + use module_action use module_field use module_vol implicit none @@ -298,6 +308,9 @@ subroutine dsf_at_bt(at, bt, a, b, k, ck, h, cid, e) integer, intent(in) :: e, cid integer :: o + REAL :: fac1, fac2 + + if (k == ZERO) return TIMING_START(timing_bin_dsf_at_bt) @@ -307,8 +320,17 @@ subroutine dsf_at_bt(at, bt, a, b, k, ck, h, cid, e) call sc_zero_halo(b) o = 1 - e + + fac1=exp( chemi) + fac2=exp(-chemi) + if (chemi /=0) call emuu4(gauge(2)%u, fac1, fac2, .false.) call d( o, e, at, a, gauge(2)%u(1,1,1,0,1)) ! A~ = Doe A + if (chemi /=0) call emuu4(gauge(2)%u, ONE, ONE, .false.) + + if (chemi /=0) call emuu4(gauge(2)%u, fac2, fac1, .false.) call d_dag(o, e, bt, b, gauge(2)%u(1,1,1,0,1)) ! B~ = Deo+ B + if (chemi /=0) call emuu4(gauge(2)%u, ONE, ONE, .false.) + if (ck /= ZERO) then call clover_mult_b(clover(cid)%b(1,1,o), at, volh) ! A~ = inv(Too) A~ call clover_mult_b(clover(cid)%b(1,1,o), bt, volh) ! B~ = inv(Too) B~ @@ -405,7 +427,7 @@ subroutine dsf_xyztfb_w(w_add, u, s, a, b, at, bt, e) #endif call flip_bc(w) - do mu = 1, DIM + do mu = 1, 3 do eo = EVEN, ODD !$omp parallel do do i = 1, volh @@ -414,6 +436,18 @@ subroutine dsf_xyztfb_w(w_add, u, s, a, b, at, bt, e) enddo enddo enddo + !$omp parallel do + do i = 1, volh + call u_scale(w(1, 1, i, e, 4), s*exp(chemi)) + call u_add(w_add(1, 1, i, e, 4), w(1, 1, i, e, 4)) + enddo + !$omp parallel do + do i = 1, volh + call u_scale(w(1, 1, i, o, 4), s*exp(chemi)) + call u_add(w_add(1, 1, i, o, 4), w(1, 1, i, o, 4)) + enddo + + #ifdef GAMMA_NOTATION_CHROMA call dsf_b_dcmp_1_m_gamma1(w(1,1,1,e,1), bt, a, nn(1,e,1,FWD)) @@ -458,14 +492,14 @@ subroutine dsf_xyztfb_w(w_add, u, s, a, b, at, bt, e) !$omp parallel do private(v) do i = 1, volh call uud(v, w(1, 1, i, eo, mu), u(1, 1, i, eo, mu)) - call udu(w(1, 1, i, eo, mu), u(1, 1, i, eo, mu), v) + call udu(w(1, 1, i, eo, mu), u(1, 1, i, eo, mu), v) !! to cancel later enddo enddo enddo call flip_bc(w) - do mu = 1, DIM + do mu = 1, 3 do eo = EVEN, ODD !$omp parallel do do i = 1, volh @@ -474,6 +508,18 @@ subroutine dsf_xyztfb_w(w_add, u, s, a, b, at, bt, e) enddo enddo enddo + !$omp parallel do + do i = 1, volh + call u_scale(w(1, 1, i, o, 4), -s*exp(-chemi)) + call u_add(w_add(1, 1, i, o, 4), w(1, 1, i, o, 4)) + enddo + !$omp parallel do + do i = 1, volh + call u_scale(w(1, 1, i, e, 4), -s*exp(-chemi)) + call u_add(w_add(1, 1, i, e, 4), w(1, 1, i, e, 4)) + enddo + + deallocate(w, STAT = ierr) if (ierr /= 0) then diff --git a/src/fermi/f_action/dsf_mtmp.F90 b/src/fermi/f_action/dsf_mtmp.F90 index 2c8fa94e2c1afc748f554d3a831c6d2079fdbbf6..f2e215f20869e6b995b151e16b03c02428932676 100644 --- a/src/fermi/f_action/dsf_mtmp.F90 +++ b/src/fermi/f_action/dsf_mtmp.F90 @@ -40,9 +40,9 @@ subroutine dsf_mtmp(p, step, calc_sf, sf, fermiid) integer, intent(in) :: fermiid, calc_sf REAL, intent(in) :: step REAL, intent(out) :: sf -!! P_SPINCOL_FIELD, save :: a, b - COMPLEX, allocatable :: a(:,:,:) - COMPLEX, allocatable :: b(:,:,:) + P_SPINCOL_FIELD, save :: a, b +!! COMPLEX, allocatable :: a(:,:,:) +!! COMPLEX, allocatable :: b(:,:,:) REAL, external :: dotprod integer :: ierr @@ -55,18 +55,18 @@ subroutine dsf_mtmp(p, step, calc_sf, sf, fermiid) DEBUG2S("Start: dsf_mtmp") call init_quark(action%fermi(fermiid)%mid1) call init_quark(action%fermi(fermiid)%mid2) -!! ALLOCATE_SC_FIELD(a) -!! ALLOCATE_SC_FIELD(b) - allocate(a(NDIRAC,NCOL,volh_tot), STAT = ierr) - if (ierr /= 0) then - call stderr2_int("allocation failed", 1, ierr) - call die("dsf_mtmp: allocation failed a") - endif - allocate(b(NDIRAC,NCOL,volh_tot), STAT = ierr) - if (ierr /= 0) then - call stderr2_int("allocation failed", 1, ierr) - call die("dsf_mtmp: allocation failed b") - endif + ALLOCATE_SC_FIELD(a) + ALLOCATE_SC_FIELD(b) +!! allocate(a(NDIRAC,NCOL,volh_tot), STAT = ierr) +!! if (ierr /= 0) then +!! call stderr2_int("allocation failed", 1, ierr) +!! call die("dsf_mtmp: allocation failed a") +!! endif +!! allocate(b(NDIRAC,NCOL,volh_tot), STAT = ierr) +!! if (ierr /= 0) then +!! call stderr2_int("allocation failed", 1, ierr) +!! call die("dsf_mtmp: allocation failed b") +!! endif if (action%fermi(fermiid)%mid2 /=0 ) then @@ -115,16 +115,16 @@ subroutine dsf_mtmp(p, step, calc_sf, sf, fermiid) call hmc_forces_new(p, step, action%fermi(fermiid)%fid) TIMING_STOP(timing_bin_dsf) - deallocate(a, STAT = ierr) - if (ierr /= 0) then - call stderr2_int("deallocation failed", 1, ierr) - call die("dsf_mtmp: deallocation failed a") - endif - deallocate(b, STAT = ierr) - if (ierr /= 0) then - call stderr2_int("deallocation failed", 1, ierr) - call die("dsf_mtmp: deallocation failed b") - endif +!! deallocate(a, STAT = ierr) +!! if (ierr /= 0) then +!! call stderr2_int("deallocation failed", 1, ierr) +!! call die("dsf_mtmp: deallocation failed a") +!! endif +!! deallocate(b, STAT = ierr) +!! if (ierr /= 0) then +!! call stderr2_int("deallocation failed", 1, ierr) +!! call die("dsf_mtmp: deallocation failed b") +!! endif DEBUG2S("End: dsf_mtmp") TIMING_STOP(timing_bin_dsf_mtmp) diff --git a/src/fermi/f_action/fermi_action.F90 b/src/fermi/f_action/fermi_action.F90 index aa0244c8c62b9b1c4a5ad331ad32281a49641673..933c108695f5c1c37d8e06991c01bfb8cc557e37 100644 --- a/src/fermi/f_action/fermi_action.F90 +++ b/src/fermi/f_action/fermi_action.F90 @@ -172,6 +172,10 @@ subroutine fermi_action_mtdagmt_dd(fid, inout, sf, init) mid1 = action%fermi(fid)%mid1 mid2 = action%fermi(fid)%mid2 + if (.not. ddable) then + call die("fermi_action_mtdagmt_dd is called, but DD is not able") + endif + if (init) then call random_sc_field_dd(tmp) sf = dotprod(tmp, tmp, SIZE_SC_FIELD) @@ -215,6 +219,10 @@ subroutine fermi_action_mtdagmt_hh(fid, inout, sf, init) mid1 = action%fermi(fid)%mid1 mid2 = action%fermi(fid)%mid2 + if (.not. ddable) then + call die("fermi_action_mtdagmt_dd is called, but DD is not able") + endif + if (init) then call random_sc_field_hh(tmp) sf = dotprod(tmp, tmp, SIZE_SC_FIELD) diff --git a/src/fermi/mult/Makefile b/src/fermi/mult/Makefile index b583c728ae07f571a9a68e879e3d4bf0db29cf2a..4ad2f0ddd5dbfb63d7c88988f3680d8ca488c8d3 100644 --- a/src/fermi/mult/Makefile +++ b/src/fermi/mult/Makefile @@ -4,7 +4,7 @@ # #------------------------------------------------------------------------------- # -# Copyright (C) 2006 Yoshifumi Nakamura +# Copyright (C) 2006, 2010 Yoshifumi Nakamura # # This file is part of BQCD -- Berlin Quantum ChromoDynamics program # @@ -26,7 +26,7 @@ DIR= ../../ include $(DIR)Makefile.in MODULES_DIR = $(DIR)/modules -FAST_MAKE = make -j 1 +FAST_MAKE = $(MAKE) -j 1 ifdef FPP2 fpp = $(FPP2) -I$(DIR)include $(MYFLAGS) @@ -34,19 +34,40 @@ else fpp = $(FPP) -I$(DIR)include $(MYFLAGS) endif +cc = $(CC) -c -I ../../include $(CFLAGS) $(MYFLAGS) + + .SUFFIXES: .SUFFIXES: .a .o .F90 .cc .c .F90.o: - $(fpp) -I../../include $(MYFLAGS) $< > $*.f90 + $(fpp) $< > $*.f90 $(F90) -c $(FFLAGS) $*.f90 .cc.o: $(CCPP) $(CFLAGS) -c -o $@ $< -OBJS = \ +.c.o: + $(cc) -o $@ $< + +OBJS_CLOVER = \ + clover_mult_ao.o \ + clover_mult_ao_r4.o \ clover_mult.o \ - clover_mult_r4.o \ + clover_mult_r4.o + +ifeq ($(libd),103) +OBJS_CLOVER = \ + clover_mult_ao_sse.o \ + clover_mult_ao_sse_r4.o \ + clover_mult_ao_block_sse.o \ + clover_mult_ao_block_sse_r4.o \ + clover_mult.o \ + clover_mult_r4.o +endif + +OBJS = \ + $(OBJS_CLOVER) \ m_tilde.o \ m_tilde_r4.o \ m_tilde_r8.o \ @@ -59,6 +80,16 @@ OBJS = \ w_mult_block.o \ w_mult_block_r4.o +ifdef quad +OBJS += \ + clover_mult_ao_r16.o \ + clover_mult_r16.o \ + m_tilde_r16.o \ + w_mult_r16.o \ + h_mult_r16.o \ + w_mult_block_r16.o +endif + ifdef BAGEL OBJS += bqcd_bagel.o support_bagel.o endif @@ -73,5 +104,54 @@ clobber: rm -f *.[Tiod] *.f90 *.mod rm -f lib_mult.a +clover_mult_r4.o: clover_mult.F90 + $(fpp) -DPRECISION_R4 $< > $*.f90 + $(F90) -c $(FFLAGS32) $*.f90 + +clover_mult_ao_r4.o: clover_mult_ao.F90 + $(fpp) -DPRECISION_R4 $< > $*.f90 + $(F90) -c $(FFLAGS32) $*.f90 + +clover_mult_r16.o: clover_mult.F90 + $(fpp) -DPRECISION_R16 $< > $*.f90 + $(F90) -c $(FFLAGS) $*.f90 + +clover_mult_ao_r16.o: clover_mult_ao.F90 + $(fpp) -DPRECISION_R16 $< > $*.f90 + $(F90) -c $(FFLAGS) $*.f90 + +clover_mult_ao_block_sse.o: clover_mult_ao_sse.c + $(cc) -DBLOCK -o $@ $< + +clover_mult_ao_block_sse_r4.o: clover_mult_ao_sse_r4.c + $(cc) -DBLOCK -o $@ $< + +m_tilde_r8.o: m_tilde.F90 +m_tilde_r4.o: m_tilde.F90 + $(fpp) -DPRECISION_R4 $< > $*.f90 + $(F90) -c $(FFLAGS32) $*.f90 +m_tilde_r16.o: m_tilde.F90 + $(fpp) -DPRECISION_R16 $< > $*.f90 + $(F90) -c $(FFLAGS) $*.f90 + +w_mult_r4.o: w_mult.F90 + $(fpp) -DPRECISION_R4 $< > $*.f90 + $(F90) -c $(FFLAGS32) $*.f90 +w_mult_r16.o: w_mult.F90 + $(fpp) -DPRECISION_R16 $< > $*.f90 + $(F90) -c $(FFLAGS) $*.f90 + +h_mult_r4.o: h_mult.F90 + $(fpp) -DPRECISION_R4 $< > $*.f90 + $(F90) -c $(FFLAGS32) $*.f90 +h_mult_r16.o: h_mult.F90 + $(fpp) -DPRECISION_R16 $< > $*.f90 + $(F90) -c $(FFLAGS) $*.f90 + w_mult_block.o: m_mult_block.h90 m_mult_omtdtd_block.h90 w_mult_block_r4.o: m_mult_block.h90 m_mult_omtdtd_block.h90 w_mult_block.F90 + $(fpp) -DPRECISION_R4 w_mult_block_r4.F90 > $*.f90 + $(F90) -c $(FFLAGS32) $*.f90 +w_mult_block_r16.o: m_mult_block.h90 m_mult_omtdtd_block.h90 w_mult_block.F90 + $(fpp) -DPRECISION_R16 w_mult_block.F90 > $*.f90 + $(F90) -c $(FFLAGS) $*.f90 diff --git a/src/fermi/mult/clover_mult.F90 b/src/fermi/mult/clover_mult.F90 index 0e5467cdfa4101489363a39a2f8db9ed0dfcd0fb..1085eac54c242b59b426b1012e0bc1d81bbc7568 100644 --- a/src/fermi/mult/clover_mult.F90 +++ b/src/fermi/mult/clover_mult.F90 @@ -1,10 +1,10 @@ !=============================================================================== ! -! clover_mult_a.F90 +! clover_mult.F90 ! !------------------------------------------------------------------------------- ! -! Copyright (C) 1998-2001, 2008 Hinnerk Stueben +! Copyright (C) 1998-2011 Hinnerk Stueben ! 2008 Yoshifumi Nakamura ! This file is part of BQCD -- Berlin Quantum ChromoDynamics program ! @@ -250,118 +250,6 @@ subroutine clover_mult_b(b, x, volh) ! x := B x TIMING_STOP(timing_bin_clover_mult_b) end -!------------------------------------------------------------------------------- -subroutine clover_mult_ao(a, x, volh) ! x := A x - - implicit none - - COMPLEX, dimension(18, 2, *) :: a -#ifdef FLIPSC - COMPLEX, dimension(NCOL, NDIRAC, *) :: x -#else - COMPLEX, dimension(NDIRAC, NCOL, *) :: x -#endif - integer :: volh - - integer :: i - COMPLEX :: x1, x2, x3, x4, x5, x6 - COMPLEX :: y1, y2, y3, y4, y5, y6 - - TIMING_START(timing_bin_clover_mult_ao) - -#ifdef IBM - call alignx(16, x(1,1,1)) - call alignx(16, a(1,1,1)) -#endif - !$omp parallel do private(x1, x2, x3, x4, x5, x6, y1, y2, y3, y4, y5, y6) - do i = 1, volh - -#ifdef GAMMAC - x1 = x(SC1, i) - x2 = x(SC2, i) - x3 = x(SC3, i) - x4 = x(SC4, i) - x5 = x(SC5, i) - x6 = x(SC6, i) -#else - x1 = x(SC1, i) + x(SC7, i) - x2 = x(SC2, i) + x(SC8, i) - x3 = x(SC3, i) + x(SC9, i) - x4 = x(SC4, i) + x(SC10, i) - x5 = x(SC5, i) + x(SC11, i) - x6 = x(SC6, i) + x(SC12, i) -#endif - -# undef J -# define J 1 -# include "clover_mult_a.h90" - -#ifdef GAMMAC - x(SC1, i) = y1 - x(SC2, i) = y2 - x(SC3, i) = y3 - x(SC4, i) = y4 - x(SC5, i) = y5 - x(SC6, i) = y6 - x1 = x(SC7, i) - x2 = x(SC8, i) - x3 = x(SC9, i) - x4 = x(SC10, i) - x5 = x(SC11, i) - x6 = x(SC12, i) -#else - x1 = x(SC1, i) - x(SC7, i) - x2 = x(SC2, i) - x(SC8, i) - x3 = x(SC3, i) - x(SC9, i) - x4 = x(SC4, i) - x(SC10, i) - x5 = x(SC5, i) - x(SC11, i) - x6 = x(SC6, i) - x(SC12, i) - - x(SC1, i) = y1 - x(SC2, i) = y2 - x(SC3, i) = y3 - x(SC4, i) = y4 - x(SC5, i) = y5 - x(SC6, i) = y6 - x(SC7, i) = y1 - x(SC8, i) = y2 - x(SC9, i) = y3 - x(SC10, i) = y4 - x(SC11, i) = y5 - x(SC12, i) = y6 -#endif - -# undef J -# define J 2 -# include "clover_mult_a.h90" - -#ifdef GAMMAC - x(SC7, i) = y1 - x(SC8, i) = y2 - x(SC9, i) = y3 - x(SC10, i) = y4 - x(SC11, i) = y5 - x(SC12, i) = y6 -#else - x(SC1, i) = x(SC1, i) + y1 - x(SC2, i) = x(SC2, i) + y2 - x(SC3, i) = x(SC3, i) + y3 - x(SC4, i) = x(SC4, i) + y4 - x(SC5, i) = x(SC5, i) + y5 - x(SC6, i) = x(SC6, i) + y6 - x(SC7, i) = x(SC7, i) - y1 - x(SC8, i) = x(SC8, i) - y2 - x(SC9, i) = x(SC9, i) - y3 - x(SC10, i) = x(SC10, i) - y4 - x(SC11, i) = x(SC11, i) - y5 - x(SC12, i) = x(SC12, i) - y6 -#endif - - enddo - - TIMING_STOP(timing_bin_clover_mult_ao) -end - !------------------------------------------------------------------------------- subroutine clover_mult_a2_block(out, b, a, in, i1, i2) ! out := A in @@ -474,15 +362,15 @@ subroutine clover_mult_a2_block(out, b, a, in, i1, i2) ! out := A in end !------------------------------------------------------------------------------- -subroutine clover_mult_ao_block(a, x, i1, i2) ! x := A x +subroutine clover_mult_ao2_block(out, a, in, i1, i2) ! out := A in implicit none COMPLEX, dimension(18, 2, *) :: a #ifdef FLIPSC - COMPLEX, dimension(NCOL, NDIRAC, *) :: x + COMPLEX, dimension(NCOL, NDIRAC, *) :: out, in #else - COMPLEX, dimension(NDIRAC, NCOL, *) :: x + COMPLEX, dimension(NDIRAC, NCOL, *) :: out, in #endif integer :: i1, i2 @@ -492,25 +380,26 @@ subroutine clover_mult_ao_block(a, x, i1, i2) ! x := A x !!TIMING_START(timing_bin_clover_mult_ao) #ifdef IBM - call alignx(16, x(1,1,1)) + call alignx(16, out(1,1,1)) + call alignx(16, in(1,1,1)) call alignx(16, a(1,1,1)) #endif do i = i1, i2 #ifdef GAMMAC - x1 = x(SC1, i) - x2 = x(SC2, i) - x3 = x(SC3, i) - x4 = x(SC4, i) - x5 = x(SC5, i) - x6 = x(SC6, i) + x1 = in(SC1, i) + x2 = in(SC2, i) + x3 = in(SC3, i) + x4 = in(SC4, i) + x5 = in(SC5, i) + x6 = in(SC6, i) #else - x1 = x(SC1, i) + x(SC7, i) - x2 = x(SC2, i) + x(SC8, i) - x3 = x(SC3, i) + x(SC9, i) - x4 = x(SC4, i) + x(SC10, i) - x5 = x(SC5, i) + x(SC11, i) - x6 = x(SC6, i) + x(SC12, i) + x1 = in(SC1, i) + in(SC7, i) + x2 = in(SC2, i) + in(SC8, i) + x3 = in(SC3, i) + in(SC9, i) + x4 = in(SC4, i) + in(SC10, i) + x5 = in(SC5, i) + in(SC11, i) + x6 = in(SC6, i) + in(SC12, i) #endif # undef J @@ -518,38 +407,38 @@ subroutine clover_mult_ao_block(a, x, i1, i2) ! x := A x # include "clover_mult_a.h90" #ifdef GAMMAC - x(SC1, i) = y1 - x(SC2, i) = y2 - x(SC3, i) = y3 - x(SC4, i) = y4 - x(SC5, i) = y5 - x(SC6, i) = y6 - x1 = x(SC7, i) - x2 = x(SC8, i) - x3 = x(SC9, i) - x4 = x(SC10, i) - x5 = x(SC11, i) - x6 = x(SC12, i) + out(SC1, i) = y1 + out(SC2, i) = y2 + out(SC3, i) = y3 + out(SC4, i) = y4 + out(SC5, i) = y5 + out(SC6, i) = y6 + x1 = in(SC7, i) + x2 = in(SC8, i) + x3 = in(SC9, i) + x4 = in(SC10, i) + x5 = in(SC11, i) + x6 = in(SC12, i) #else - x1 = x(SC1, i) - x(SC7, i) - x2 = x(SC2, i) - x(SC8, i) - x3 = x(SC3, i) - x(SC9, i) - x4 = x(SC4, i) - x(SC10, i) - x5 = x(SC5, i) - x(SC11, i) - x6 = x(SC6, i) - x(SC12, i) - - x(SC1, i) = y1 - x(SC2, i) = y2 - x(SC3, i) = y3 - x(SC4, i) = y4 - x(SC5, i) = y5 - x(SC6, i) = y6 - x(SC7, i) = y1 - x(SC8, i) = y2 - x(SC9, i) = y3 - x(SC10, i) = y4 - x(SC11, i) = y5 - x(SC12, i) = y6 + x1 = in(SC1, i) - in(SC7, i) + x2 = in(SC2, i) - in(SC8, i) + x3 = in(SC3, i) - in(SC9, i) + x4 = in(SC4, i) - in(SC10, i) + x5 = in(SC5, i) - in(SC11, i) + x6 = in(SC6, i) - in(SC12, i) + + out(SC1, i) = y1 + out(SC2, i) = y2 + out(SC3, i) = y3 + out(SC4, i) = y4 + out(SC5, i) = y5 + out(SC6, i) = y6 + out(SC7, i) = y1 + out(SC8, i) = y2 + out(SC9, i) = y3 + out(SC10, i) = y4 + out(SC11, i) = y5 + out(SC12, i) = y6 #endif # undef J @@ -557,25 +446,25 @@ subroutine clover_mult_ao_block(a, x, i1, i2) ! x := A x # include "clover_mult_a.h90" #ifdef GAMMAC - x(SC7, i) = y1 - x(SC8, i) = y2 - x(SC9, i) = y3 - x(SC10, i) = y4 - x(SC11, i) = y5 - x(SC12, i) = y6 + out(SC7, i) = y1 + out(SC8, i) = y2 + out(SC9, i) = y3 + out(SC10, i) = y4 + out(SC11, i) = y5 + out(SC12, i) = y6 #else - x(SC1, i) = x(SC1, i) + y1 - x(SC2, i) = x(SC2, i) + y2 - x(SC3, i) = x(SC3, i) + y3 - x(SC4, i) = x(SC4, i) + y4 - x(SC5, i) = x(SC5, i) + y5 - x(SC6, i) = x(SC6, i) + y6 - x(SC7, i) = x(SC7, i) - y1 - x(SC8, i) = x(SC8, i) - y2 - x(SC9, i) = x(SC9, i) - y3 - x(SC10, i) = x(SC10, i) - y4 - x(SC11, i) = x(SC11, i) - y5 - x(SC12, i) = x(SC12, i) - y6 + out(SC1, i) = out(SC1, i) + y1 + out(SC2, i) = out(SC2, i) + y2 + out(SC3, i) = out(SC3, i) + y3 + out(SC4, i) = out(SC4, i) + y4 + out(SC5, i) = out(SC5, i) + y5 + out(SC6, i) = out(SC6, i) + y6 + out(SC7, i) = out(SC7, i) - y1 + out(SC8, i) = out(SC8, i) - y2 + out(SC9, i) = out(SC9, i) - y3 + out(SC10, i) = out(SC10, i) - y4 + out(SC11, i) = out(SC11, i) - y5 + out(SC12, i) = out(SC12, i) - y6 #endif enddo diff --git a/src/fermi/mult/clover_mult_ao.F90 b/src/fermi/mult/clover_mult_ao.F90 new file mode 100644 index 0000000000000000000000000000000000000000..1637591aa4e0905f8253885f95a6240175306543 --- /dev/null +++ b/src/fermi/mult/clover_mult_ao.F90 @@ -0,0 +1,249 @@ +!=============================================================================== +! +! clover_mult_ao.F90 +! +!------------------------------------------------------------------------------- +! +! Copyright (C) 1998-2011 Hinnerk Stueben +! 2008 Yoshifumi Nakamura +! This file is part of BQCD -- Berlin Quantum ChromoDynamics program +! +! BQCD 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 Foundation, either version 3 of the License, or +! (at your option) any later version. +! +! BQCD is distributed in the hope that it will be useful, +! but WITHOUT ANY WARRANTY; without even the implied warranty of +! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +! GNU General Public License for more details. +! +! You should have received a copy of the GNU General Public License +! along with BQCD. If not, see <http://www.gnu.org/licenses/>. +! +!------------------------------------------------------------------------------- +# define CLOVER_AS_COMPLEX_ARRAY +# include "defs.h" +# include "clover.h" + +!------------------------------------------------------------------------------- +subroutine clover_mult_ao(a, x, volh) ! x := A x + + implicit none + + COMPLEX, dimension(18, 2, *) :: a +#ifdef FLIPSC + COMPLEX, dimension(NCOL, NDIRAC, *) :: x +#else + COMPLEX, dimension(NDIRAC, NCOL, *) :: x +#endif + integer :: volh + + integer :: i + COMPLEX :: x1, x2, x3, x4, x5, x6 + COMPLEX :: y1, y2, y3, y4, y5, y6 + + TIMING_START(timing_bin_clover_mult_ao) + +#ifdef IBM + call alignx(16, x(1,1,1)) + call alignx(16, a(1,1,1)) +#endif + !$omp parallel do private(x1, x2, x3, x4, x5, x6, y1, y2, y3, y4, y5, y6) + do i = 1, volh + +#ifdef GAMMAC + x1 = x(SC1, i) + x2 = x(SC2, i) + x3 = x(SC3, i) + x4 = x(SC4, i) + x5 = x(SC5, i) + x6 = x(SC6, i) +#else + x1 = x(SC1, i) + x(SC7, i) + x2 = x(SC2, i) + x(SC8, i) + x3 = x(SC3, i) + x(SC9, i) + x4 = x(SC4, i) + x(SC10, i) + x5 = x(SC5, i) + x(SC11, i) + x6 = x(SC6, i) + x(SC12, i) +#endif + +# undef J +# define J 1 +# include "clover_mult_a.h90" + +#ifdef GAMMAC + x(SC1, i) = y1 + x(SC2, i) = y2 + x(SC3, i) = y3 + x(SC4, i) = y4 + x(SC5, i) = y5 + x(SC6, i) = y6 + x1 = x(SC7, i) + x2 = x(SC8, i) + x3 = x(SC9, i) + x4 = x(SC10, i) + x5 = x(SC11, i) + x6 = x(SC12, i) +#else + x1 = x(SC1, i) - x(SC7, i) + x2 = x(SC2, i) - x(SC8, i) + x3 = x(SC3, i) - x(SC9, i) + x4 = x(SC4, i) - x(SC10, i) + x5 = x(SC5, i) - x(SC11, i) + x6 = x(SC6, i) - x(SC12, i) + + x(SC1, i) = y1 + x(SC2, i) = y2 + x(SC3, i) = y3 + x(SC4, i) = y4 + x(SC5, i) = y5 + x(SC6, i) = y6 + x(SC7, i) = y1 + x(SC8, i) = y2 + x(SC9, i) = y3 + x(SC10, i) = y4 + x(SC11, i) = y5 + x(SC12, i) = y6 +#endif + +# undef J +# define J 2 +# include "clover_mult_a.h90" + +#ifdef GAMMAC + x(SC7, i) = y1 + x(SC8, i) = y2 + x(SC9, i) = y3 + x(SC10, i) = y4 + x(SC11, i) = y5 + x(SC12, i) = y6 +#else + x(SC1, i) = x(SC1, i) + y1 + x(SC2, i) = x(SC2, i) + y2 + x(SC3, i) = x(SC3, i) + y3 + x(SC4, i) = x(SC4, i) + y4 + x(SC5, i) = x(SC5, i) + y5 + x(SC6, i) = x(SC6, i) + y6 + x(SC7, i) = x(SC7, i) - y1 + x(SC8, i) = x(SC8, i) - y2 + x(SC9, i) = x(SC9, i) - y3 + x(SC10, i) = x(SC10, i) - y4 + x(SC11, i) = x(SC11, i) - y5 + x(SC12, i) = x(SC12, i) - y6 +#endif + + enddo + + TIMING_STOP(timing_bin_clover_mult_ao) +end + +!------------------------------------------------------------------------------- +subroutine clover_mult_ao_block(a, x, i1, i2) ! x := A x + + implicit none + + COMPLEX, dimension(18, 2, *) :: a +#ifdef FLIPSC + COMPLEX, dimension(NCOL, NDIRAC, *) :: x +#else + COMPLEX, dimension(NDIRAC, NCOL, *) :: x +#endif + integer :: i1, i2 + + integer :: i + COMPLEX :: x1, x2, x3, x4, x5, x6 + COMPLEX :: y1, y2, y3, y4, y5, y6 + +#ifdef IBM + call alignx(16, x(1,1,1)) + call alignx(16, a(1,1,1)) +#endif + do i = i1, i2 + +#ifdef GAMMAC + x1 = x(SC1, i) + x2 = x(SC2, i) + x3 = x(SC3, i) + x4 = x(SC4, i) + x5 = x(SC5, i) + x6 = x(SC6, i) +#else + x1 = x(SC1, i) + x(SC7, i) + x2 = x(SC2, i) + x(SC8, i) + x3 = x(SC3, i) + x(SC9, i) + x4 = x(SC4, i) + x(SC10, i) + x5 = x(SC5, i) + x(SC11, i) + x6 = x(SC6, i) + x(SC12, i) +#endif + +# undef J +# define J 1 +# include "clover_mult_a.h90" + +#ifdef GAMMAC + x(SC1, i) = y1 + x(SC2, i) = y2 + x(SC3, i) = y3 + x(SC4, i) = y4 + x(SC5, i) = y5 + x(SC6, i) = y6 + x1 = x(SC7, i) + x2 = x(SC8, i) + x3 = x(SC9, i) + x4 = x(SC10, i) + x5 = x(SC11, i) + x6 = x(SC12, i) +#else + x1 = x(SC1, i) - x(SC7, i) + x2 = x(SC2, i) - x(SC8, i) + x3 = x(SC3, i) - x(SC9, i) + x4 = x(SC4, i) - x(SC10, i) + x5 = x(SC5, i) - x(SC11, i) + x6 = x(SC6, i) - x(SC12, i) + + x(SC1, i) = y1 + x(SC2, i) = y2 + x(SC3, i) = y3 + x(SC4, i) = y4 + x(SC5, i) = y5 + x(SC6, i) = y6 + x(SC7, i) = y1 + x(SC8, i) = y2 + x(SC9, i) = y3 + x(SC10, i) = y4 + x(SC11, i) = y5 + x(SC12, i) = y6 +#endif + +# undef J +# define J 2 +# include "clover_mult_a.h90" + +#ifdef GAMMAC + x(SC7, i) = y1 + x(SC8, i) = y2 + x(SC9, i) = y3 + x(SC10, i) = y4 + x(SC11, i) = y5 + x(SC12, i) = y6 +#else + x(SC1, i) = x(SC1, i) + y1 + x(SC2, i) = x(SC2, i) + y2 + x(SC3, i) = x(SC3, i) + y3 + x(SC4, i) = x(SC4, i) + y4 + x(SC5, i) = x(SC5, i) + y5 + x(SC6, i) = x(SC6, i) + y6 + x(SC7, i) = x(SC7, i) - y1 + x(SC8, i) = x(SC8, i) - y2 + x(SC9, i) = x(SC9, i) - y3 + x(SC10, i) = x(SC10, i) - y4 + x(SC11, i) = x(SC11, i) - y5 + x(SC12, i) = x(SC12, i) - y6 +#endif + + enddo + +end + +!=============================================================================== diff --git a/src/fermi/mult/clover_mult_ao_sse.c b/src/fermi/mult/clover_mult_ao_sse.c new file mode 100644 index 0000000000000000000000000000000000000000..25d09821994fcd458e3cb3a3af28a22e97f26345 --- /dev/null +++ b/src/fermi/mult/clover_mult_ao_sse.c @@ -0,0 +1,237 @@ +/* +!=============================================================================== +! +! clover_mult_ao_sse.c +! +!------------------------------------------------------------------------------- +! +! Copyright (C) 2011 Hinnerk Stueben +! +! This file is part of BQCD -- Berlin Quantum ChromoDynamics program +! +! BQCD 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 Foundation, either version 3 of the License, or +! (at your option) any later version. +! +! BQCD is distributed in the hope that it will be useful, +! but WITHOUT ANY WARRANTY; without even the implied warranty of +! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +! GNU General Public License for more details. +! +! You should have received a copy of the GNU General Public License +! along with BQCD. If not, see <http://www.gnu.org/licenses/>. +! +!------------------------------------------------------------------------------- +*/ +# include <emmintrin.h> +# include <pmmintrin.h> +# include "c_defs.h" + +# define cLoad(b) _mm_load_pd((double*) &(b)) +# define cLoadr(b) _mm_loadr_pd((double*) &(b)) +# define cLoad1(b) _mm_load1_pd((double*) &(b)) +# define cLoads(b) _mm_load_sd((double*) &(b)) +# define cStore(a,b) _mm_store_pd((double*) &(a), b) +# define cAdd(b, c) _mm_add_pd(b, c) +# define cSub(b, c) _mm_sub_pd(b, c) +# define cMul(b, c) _mm_mul_pd(b, c) +# define cAddSub(b, c) _mm_addsub_pd(b, c) + +# define cLoadX(a, b, c) STRCAT(a,rr) = cAdd(cLoad1(Re(b)), cLoad1(Re(c))); \ + STRCAT(a,ii) = cAdd(cLoad1(Im(b)), cLoad1(Im(c))) + +# define cLoadXX(a, b, c) STRCAT(a,rr) = cSub(cLoad1(Re(b)), cLoad1(Re(c))); \ + STRCAT(a,ii) = cSub(cLoad1(Im(b)), cLoad1(Im(c))) + +# define cStoreX(a, b, c) cStore(a, cAdd(b, c)) +# define cStoreXX(a, b, c) cStore(a, cSub(b, c)) + +# define cConjg(a) cMul(conjg, a) +# define cConjgr(a) cMul(conjgr, a) + + +# define cCmplxMul(b, c) cAddSub(cMul(cLoad(b), STRCAT(c,rr)), cMul(cLoadr(b), STRCAT(c,ii))) + +# define cCmplxMulConjg(b, c) cAddSub(cMul(cConjg(cLoad(b)), STRCAT(c,rr)), cMul(cConjgr(cLoadr(b)), STRCAT(c,ii))) + +# define cCmplxMulRe(b, c) _mm_hsub_pd(cMul(cLoads(Re(b)), STRCAT(c,rr)), cMul(cLoads(Re(b)), STRCAT(c,ii))) + +# define cCmplxMulIm(b, c) _mm_hsub_pd(cMul(cLoads(Im(b)), STRCAT(c,rr)), cMul(cLoads(Im(b)), STRCAT(c,ii))) + + +# define cProd(a, b, c) a = cCmplxMul(b, c) + +# define cProdConjg(a, b, c) a = cCmplxMulConjg(b, c) + +# define cProdRe(a, b, c) a = cCmplxMulRe(b, c) + + +# define cAddProd(a, b, c) a = cAdd(a, cCmplxMul(b, c)) + +# define cAddProdConjg(a,b,c) a = cAdd(a, cCmplxMulConjg(b, c)) + +# define cAddProdRe(a, b, c) a = cAdd(a, cCmplxMulRe(b, c)) + +# define cAddProdIm(a, b, c) a = cAdd(a, cCmplxMulIm(b, c)) + + +# define aa(s, c, i) aa_[i][c-1][s-1] +# define x(s, c, i) x_[i][c-1][s-1] + +#ifdef BLOCK +void clover_mult_ao_block_(COMPLEX (*aa_)[2][18], COMPLEX (*x_)[3][4], int *i1, int *i2) +#else +void clover_mult_ao_(COMPLEX (*aa_)[2][18], COMPLEX (*x_)[3][4], int *volh) +#endif +{ + int i; + __m128d x1rr, x2rr, x3rr, x4rr, x5rr, x6rr; + __m128d x1ii, x2ii, x3ii, x4ii, x5ii, x6ii; + __m128d y1, y2, y3, y4, y5, y6; + __m128d xx1rr, xx2rr, xx3rr, xx4rr, xx5rr, xx6rr; + __m128d xx1ii, xx2ii, xx3ii, xx4ii, xx5ii, xx6ii; + __m128d yy1, yy2, yy3, yy4, yy5, yy6; + + const __m128d conjg = _mm_setr_pd(ONE, -ONE); + const __m128d conjgr = _mm_set_pd(ONE, -ONE); + const __m128d sign = _mm_set_pd(-ONE, -ONE); + +#ifndef BLOCK + TIMING_START(timing_bin_clover_mult_ao); +#endif + + aa_--; + x_--; + +#ifdef BLOCK + for (i = *i1; i <= *i2; i++) +#else + # pragma omp parallel for \ + private (x1rr, x2rr, x3rr, x4rr, x5rr, x6rr) \ + private (x1ii, x2ii, x3ii, x4ii, x5ii, x6ii) \ + private (y1, y2, y3, y4, y5, y6) \ + private (xx1rr, xx2rr, xx3rr, xx4rr, xx5rr, xx6rr) \ + private (xx1ii, xx2ii, xx3ii, xx4ii, xx5ii, xx6ii) \ + private (yy1, yy2, yy3, yy4, yy5, yy6) + + for (i = 1; i <= *volh; i++) +#endif + { + cLoadX(x1, x(1, 1, i), x(3, 1, i)); + cLoadX(x2, x(1, 2, i), x(3, 2, i)); + cLoadX(x3, x(1, 3, i), x(3, 3, i)); + cLoadX(x4, x(2, 1, i), x(4, 1, i)); + cLoadX(x5, x(2, 2, i), x(4, 2, i)); + cLoadX(x6, x(2, 3, i), x(4, 3, i)); + + cProdRe(y1, aa(1,1,i), x1); + cAddProd(y1, aa(2,1,i), x2); + cAddProd(y1, aa(3,1,i), x3); + cAddProd(y1, aa(4,1,i), x4); + cAddProd(y1, aa(5,1,i), x5); + cAddProd(y1, aa(6,1,i), x6); + + cProdConjg(y2, aa(2,1,i), x1); + cAddProdIm(y2, aa(1,1,i), x2); + cAddProd(y2, aa(7,1,i), x3); + cAddProd(y2, aa(8,1,i), x4); + cAddProd(y2, aa(9,1,i), x5); + cAddProd(y2, aa(10,1,i), x6); + + cProdConjg(y3, aa(3,1,i), x1); + cAddProdConjg(y3, aa(7,1,i), x2); + cAddProdRe(y3, aa(11,1,i), x3); + cAddProd(y3, aa(12,1,i), x4); + cAddProd(y3, aa(13,1,i), x5); + cAddProd(y3, aa(14,1,i), x6); + + cProdConjg(y4, aa(4,1,i), x1); + cAddProdConjg(y4, aa(8,1,i), x2); + cAddProdConjg(y4, aa(12,1,i), x3); + cAddProdIm(y4, aa(11,1,i), x4); + cAddProd(y4, aa(15,1,i), x5); + cAddProd(y4, aa(16,1,i), x6); + + cProdConjg(y5, aa(5,1,i), x1); + cAddProdConjg(y5, aa(9,1,i), x2); + cAddProdConjg(y5, aa(13,1,i), x3); + cAddProdConjg(y5, aa(15,1,i), x4); + cAddProdRe(y5, aa(17,1,i), x5); + cAddProd(y5, aa(18,1,i), x6); + + cProdConjg(y6, aa(6,1,i), x1); + cAddProdConjg(y6, aa(10,1,i), x2); + cAddProdConjg(y6, aa(14,1,i), x3); + cAddProdConjg(y6, aa(16,1,i), x4); + cAddProdConjg(y6, aa(18,1,i), x5); + cAddProdIm(y6, aa(17,1,i), x6); + + cLoadXX(xx1, x(1, 1, i), x(3, 1, i)); + cLoadXX(xx2, x(1, 2, i), x(3, 2, i)); + cLoadXX(xx3, x(1, 3, i), x(3, 3, i)); + cLoadXX(xx4, x(2, 1, i), x(4, 1, i)); + cLoadXX(xx5, x(2, 2, i), x(4, 2, i)); + cLoadXX(xx6, x(2, 3, i), x(4, 3, i)); + + cProdRe(yy1, aa(1,2,i), xx1); + cAddProd(yy1, aa(2,2,i), xx2); + cAddProd(yy1, aa(3,2,i), xx3); + cAddProd(yy1, aa(4,2,i), xx4); + cAddProd(yy1, aa(5,2,i), xx5); + cAddProd(yy1, aa(6,2,i), xx6); + + cProdConjg(yy2, aa(2,2,i), xx1); + cAddProdIm(yy2, aa(1,2,i), xx2); + cAddProd(yy2, aa(7,2,i), xx3); + cAddProd(yy2, aa(8,2,i), xx4); + cAddProd(yy2, aa(9,2,i), xx5); + cAddProd(yy2, aa(10,2,i), xx6); + + cProdConjg(yy3, aa(3,2,i), xx1); + cAddProdConjg(yy3, aa(7,2,i), xx2); + cAddProdRe(yy3, aa(11,2,i), xx3); + cAddProd(yy3, aa(12,2,i), xx4); + cAddProd(yy3, aa(13,2,i), xx5); + cAddProd(yy3, aa(14,2,i), xx6); + + cProdConjg(yy4, aa(4,2,i), xx1); + cAddProdConjg(yy4, aa(8,2,i), xx2); + cAddProdConjg(yy4, aa(12,2,i), xx3); + cAddProdIm(yy4, aa(11,2,i), xx4); + cAddProd(yy4, aa(15,2,i), xx5); + cAddProd(yy4, aa(16,2,i), xx6); + + cProdConjg(yy5, aa(5,2,i), xx1); + cAddProdConjg(yy5, aa(9,2,i), xx2); + cAddProdConjg(yy5, aa(13,2,i), xx3); + cAddProdConjg(yy5, aa(15,2,i), xx4); + cAddProdRe(yy5, aa(17,2,i), xx5); + cAddProd(yy5, aa(18,2,i), xx6); + + cProdConjg(yy6, aa(6,2,i), xx1); + cAddProdConjg(yy6, aa(10,2,i), xx2); + cAddProdConjg(yy6, aa(14,2,i), xx3); + cAddProdConjg(yy6, aa(16,2,i), xx4); + cAddProdConjg(yy6, aa(18,2,i), xx5); + cAddProdIm(yy6, aa(17,2,i), xx6); + + cStoreX(x(1, 1, i), y1, yy1); + cStoreX(x(1, 2, i), y2, yy2); + cStoreX(x(1, 3, i), y3, yy3); + cStoreX(x(2, 1, i), y4, yy4); + cStoreX(x(2, 2, i), y5, yy5); + cStoreX(x(2, 3, i), y6, yy6); + + cStoreXX(x(3, 1, i), y1, yy1); + cStoreXX(x(3, 2, i), y2, yy2); + cStoreXX(x(3, 3, i), y3, yy3); + cStoreXX(x(4, 1, i), y4, yy4); + cStoreXX(x(4, 2, i), y5, yy5); + cStoreXX(x(4, 3, i), y6, yy6); + } + +#ifndef BLOCK + TIMING_STOP(timing_bin_clover_mult_ao); +#endif +} diff --git a/src/fermi/mult/clover_mult_ao_sse_r4.c b/src/fermi/mult/clover_mult_ao_sse_r4.c new file mode 100644 index 0000000000000000000000000000000000000000..b98fc0d9a27f427bb4609e4631ec654a357c8cb5 --- /dev/null +++ b/src/fermi/mult/clover_mult_ao_sse_r4.c @@ -0,0 +1,206 @@ +/* +!=============================================================================== +! +! clover_mult_ao_sse_r4.c +! +!------------------------------------------------------------------------------- +! +! Copyright (C) 2011 Hinnerk Stueben +! +! This file is part of BQCD -- Berlin Quantum ChromoDynamics program +! +! BQCD 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 Foundation, either version 3 of the License, or +! (at your option) any later version. +! +! BQCD is distributed in the hope that it will be useful, +! but WITHOUT ANY WARRANTY; without even the implied warranty of +! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +! GNU General Public License for more details. +! +! You should have received a copy of the GNU General Public License +! along with BQCD. If not, see <http://www.gnu.org/licenses/>. +! +!------------------------------------------------------------------------------- +*/ +# include <xmmintrin.h> +# include <emmintrin.h> +# include <pmmintrin.h> +# define PRECISION_R4 +# include "c_defs.h" + +# define cLoad(b) _mm_load_ps((float*) &(b)) +# define cLoad1(b) _mm_load1_ps((float*) &(b)) +# define cStore(a,b) _mm_store_ps((float*) &(a), b) +# define cAdd(b, c) _mm_add_ps(b, c) +# define cSub(b, c) _mm_sub_ps(b, c) +# define cMul(b, c) _mm_mul_ps(b, c) +# define cAddSub(b, c) _mm_addsub_ps(b, c) + +# define cConjgRI(a) cMul(conjg, a) +# define cConjgIR(a) cMul(conjgr, a) + +# define cLoadX(a, b, c) STRCAT(a,rr) = cAdd(cLoad1(Re(b)), cLoad1(Re(c))); \ + STRCAT(a,ii) = cAdd(cLoad1(Im(b)), cLoad1(Im(c))) + +# define cLoadXX(a, b, c) STRCAT(a,rr) = cSub(cLoad1(Re(b)), cLoad1(Re(c))); \ + STRCAT(a,ii) = cSub(cLoad1(Im(b)), cLoad1(Im(c))) + +# define cLoadRI(a) cLoad(a) +# define cLoadIR(a) _mm_shuffle_ps(cLoad(a), cLoad(a), _MM_SHUFFLE(2,3,0,1)) + +# define cLoadDiagRI1(a) cMul(cLoadRI(a), conjg1) +# define cLoadDiagIR1(a) cMul(cLoadIR(a), conjg1r) + +# define cLoadDiagRI2(a) cMul(_mm_shuffle_ps(cLoad(a), cLoad(a), _MM_SHUFFLE(0,1,3,2)), c1110) +# define cLoadDiagIR2(a) cMul(_mm_shuffle_ps(cLoad(a), cLoad(a), _MM_SHUFFLE(1,0,2,3)), c1101) + + +# define cDiag1(iaa, y1, y2, ia, x1, x2) \ +y1 = cAddSub(cMul(cLoadDiagRI1(aa(ia,iaa,i)), STRCAT(x1,rr)), cMul(cLoadDiagIR1(aa(ia,iaa,i)), STRCAT(x1,ii))); \ +y1 = cAdd(y1, cAddSub(cMul(cLoadDiagRI2(aa(ia,iaa,i)), STRCAT(x2,rr)), cMul(cLoadDiagIR2(aa(ia,iaa,i)), STRCAT(x2,ii)))) + +# define cDiag2(iaa, y1, y2, ia, x1, x2) \ +y1 = cAdd(y1, cAddSub(cMul(cLoadDiagRI1(aa(ia,iaa,i)), STRCAT(x1,rr)), cMul(cLoadDiagIR1(aa(ia,iaa,i)), STRCAT(x1,ii)))); \ +y1 = cAdd(y1, cAddSub(cMul(cLoadDiagRI2(aa(ia,iaa,i)), STRCAT(x2,rr)), cMul(cLoadDiagIR2(aa(ia,iaa,i)), STRCAT(x2,ii)))) + + + +# define cLoadUpperRI1(a, b) _mm_shuffle_ps(cLoad(a), cLoad(b), _MM_SHUFFLE(1,0,1,0)) +# define cLoadUpperIR1(a, b) _mm_shuffle_ps(cLoad(a), cLoad(b), _MM_SHUFFLE(0,1,0,1)) + +# define cLoadUpperRI2(a, b) _mm_shuffle_ps(cLoad(a), cLoad(b), _MM_SHUFFLE(3,2,3,2)) +# define cLoadUpperIR2(a, b) _mm_shuffle_ps(cLoad(a), cLoad(b), _MM_SHUFFLE(2,3,2,3)) + + +# define cUpper(iaa, y1, y2, ia1, ia2, x1, x2) \ +y1 = cAdd(y1, cAddSub(cMul(cLoadUpperRI1(aa(ia1,iaa,i),aa(ia2,iaa,i)), STRCAT(x1,rr)), cMul(cLoadUpperIR1(aa(ia1,iaa,i),aa(ia2,iaa,i)), STRCAT(x1,ii)))); \ +y1 = cAdd(y1, cAddSub(cMul(cLoadUpperRI2(aa(ia1,iaa,i),aa(ia2,iaa,i)), STRCAT(x2,rr)), cMul(cLoadUpperIR2(aa(ia1,iaa,i),aa(ia2,iaa,i)), STRCAT(x2,ii)))) + + + +# define cCmplxMulConjg(b, c) cAddSub(cMul(cConjgRI(cLoadRI(b)), STRCAT(c,rr)), cMul(cConjgIR(cLoadIR(b)), STRCAT(c,ii))) + +# define cProdConjg(a, b, c) a = cCmplxMulConjg(b, c) + +# define cAddProdConjg(a,b,c) a = cAdd(a, cCmplxMulConjg(b, c)) + +# define cLower1(iaa, y1, y2, ia1, ia2, x1, x2) \ + cProdConjg(y1, aa(ia1,iaa,i), x1); \ + cAddProdConjg(y1, aa(ia2,iaa,i), x2) + +# define cLower2(iaa, y1, y2, ia1, ia2, x1, x2) \ + cAddProdConjg(y1, aa(ia1,iaa,i), x1); \ + cAddProdConjg(y1, aa(ia2,iaa,i), x2) + + +# define cStoreX1(a, b, c) cStore(a, _mm_shuffle_ps(b, c, _MM_SHUFFLE(3,2,1,0))) +# define cStoreX2(a, b, c) cStore(a, _mm_shuffle_ps(b, c, _MM_SHUFFLE(1,0,3,2))) +# define cStoreX3(a, b, c) cStore(a, _mm_shuffle_ps(b, c, _MM_SHUFFLE(3,2,1,0))) + + +# define aa(s, c, i) aa_[i][c-1][s-1] +# define x(s, c, i) x_[i][c-1][s-1] + + +#ifdef BLOCK +void clover_mult_ao_block_r4_(COMPLEX (*aa_)[2][18], COMPLEX (*x_)[3][4], int *i1, int *i2) +#else +void clover_mult_ao_r4_(COMPLEX (*aa_)[2][18], COMPLEX (*x_)[3][4], int *volh) +#endif +{ + int i; + __m128 x1rr, x2rr, x3rr, x4rr, x5rr, x6rr; + __m128 x1ii, x2ii, x3ii, x4ii, x5ii, x6ii; + __m128 y1, y3, y5; + __m128 z1, z3, z5; + __m128 xx1rr, xx2rr, xx3rr, xx4rr, xx5rr, xx6rr; + __m128 xx1ii, xx2ii, xx3ii, xx4ii, xx5ii, xx6ii; + __m128 yy1, yy3, yy5; + __m128 zz1, zz3, zz5; + + const __m128 conjg = _mm_setr_ps(ONE, -ONE, ONE, -ONE); + const __m128 conjgr = _mm_setr_ps(-ONE, ONE, -ONE, ONE); + + const __m128 conjg1 = _mm_setr_ps(ONE, ZERO, ONE, -ONE); + const __m128 conjg1r = _mm_setr_ps(ZERO, ONE, -ONE, ONE); + const __m128 c1101 = _mm_setr_ps(ONE, ONE, ZERO, ONE); + const __m128 c1110 = _mm_setr_ps(ONE, ONE, ONE, ZERO); + + + aa_--; + x_--; + +#ifdef BLOCK + for (i = *i1; i <= *i2; i++) +#else + # pragma omp parallel for \ + private (x1rr, x2rr, x3rr, x4rr, x5rr, x6rr) \ + private (x1ii, x2ii, x3ii, x4ii, x5ii, x6ii) \ + private (y1, y3, y5) \ + private (z1, z3, z5) \ + private (xx1rr, xx2rr, xx3rr, xx4rr, xx5rr, xx6rr) \ + private (xx1ii, xx2ii, xx3ii, xx4ii, xx5ii, xx6ii) \ + private (yy1, yy3, yy5) \ + private (zz1, zz3, zz5) + + for (i = 1; i <= *volh; i++) +#endif + { + cLoadX(x1, x(1, 1, i), x(3, 1, i)); + cLoadX(x2, x(1, 2, i), x(3, 2, i)); + cLoadX(x3, x(1, 3, i), x(3, 3, i)); + cLoadX(x4, x(2, 1, i), x(4, 1, i)); + cLoadX(x5, x(2, 2, i), x(4, 2, i)); + cLoadX(x6, x(2, 3, i), x(4, 3, i)); + + cDiag1(1, y1, y2, 1, x1, x2); + cUpper(1, y1, y2, 3, 7, x3, x4); + cUpper(1, y1, y2, 5, 9, x5, x6); + + cLower1(1, y3, y4, 3, 7, x1, x2); + cDiag2(1, y3, y4, 11, x3, x4); + cUpper(1, y3, y4, 13, 15, x5, x6); + + cLower1(1, y5, y6, 5, 9, x1, x2); + cLower2(1, y5, y6, 13, 15, x3, x4); + cDiag2(1, y5, y6, 17, x5, x6); + + cLoadXX(xx1, x(1, 1, i), x(3, 1, i)); + cLoadXX(xx2, x(1, 2, i), x(3, 2, i)); + cLoadXX(xx3, x(1, 3, i), x(3, 3, i)); + cLoadXX(xx4, x(2, 1, i), x(4, 1, i)); + cLoadXX(xx5, x(2, 2, i), x(4, 2, i)); + cLoadXX(xx6, x(2, 3, i), x(4, 3, i)); + + cDiag1(2, yy1, yy2, 1, xx1, xx2); + cUpper(2, yy1, yy2, 3, 7, xx3, xx4); + cUpper(2, yy1, yy2, 5, 9, xx5, xx6); + + cLower1(2, yy3, yy4, 3, 7, xx1, xx2); + cDiag2(2, yy3, yy4, 11, xx3, xx4); + cUpper(2, yy3, yy4, 13, 15, xx5, xx6); + + cLower1(2, yy5, yy6, 5, 9, xx1, xx2); + cLower2(2, yy5, yy6, 13, 15, xx3, xx4); + cDiag2(2, yy5, yy6, 17, xx5, xx6); + + z1 = cAdd(y1, yy1); + z3 = cAdd(y3, yy3); + z5 = cAdd(y5, yy5); + + zz1 = cSub(y1, yy1); + zz3 = cSub(y3, yy3); + zz5 = cSub(y5, yy5); + + cStoreX1(x(1, 1, i), z1, z3); + cStoreX1(x(3, 1, i), zz1, zz3); + + cStoreX2(x(1, 2, i), z1, z5); + cStoreX2(x(3, 2, i), zz1, zz5); + + cStoreX3(x(1, 3, i), z3, z5); + cStoreX3(x(3, 3, i), zz3, zz5); + } +} diff --git a/src/fermi/mult/m_mult_block.h90 b/src/fermi/mult/m_mult_block.h90 index 82e74fb1c40d4af0790bf413bfb6b43cc9fdb62a..d8fd0c58f4b3b4cb42764a071795eb504f8660ea 100644 --- a/src/fermi/mult/m_mult_block.h90 +++ b/src/fermi/mult/m_mult_block.h90 @@ -37,6 +37,8 @@ d_out => out case (100) ; d_in => tmp1 ; d_out => out case (101) ; d_in => tmp1 ; d_out => out + case (102) ; d_in => tmp1 ; d_out => out + case (103) ; d_in => tmp1 ; d_out => out end select diff --git a/src/fermi/mult/m_mult_omtdtd_block.h90 b/src/fermi/mult/m_mult_omtdtd_block.h90 index 43c362c84199e4a40b550e726b95ed31668e6219..c7db2574ac2d9d61490df507d1ffcd3bfea693f2 100644 --- a/src/fermi/mult/m_mult_omtdtd_block.h90 +++ b/src/fermi/mult/m_mult_omtdtd_block.h90 @@ -12,7 +12,7 @@ SPINCOL_OVERINDEXED, intent(inout), target :: in integer, intent(in) :: id logical, intent(in) :: extra_loops - SPINCOL_FIELD, intent(in) :: p_or_r + SPINCOL_OVERINDEXED, intent(in) :: p_or_r REAL, intent(in) :: bk DOUBLE, intent(out) :: paap @@ -41,18 +41,18 @@ d_out => out end select -#ifdef DAGGER - out = in -#endif - do i1 = 1, volh, input%tuning_cg_block_length i2 = min(volh, i1 + input%tuning_cg_block_length - 1) #ifndef DAGGER if (extra_loops) call sc_xpby_block(in, p_or_r, bk, i1, i2) ! from cg: p = r + bk * p call STRCAT(M_MULT_D, _projection_block)(d_in, in, i1, i2) #else - if (cid/=0)call clover_mult_ao_block(clover(cid)%i(1,1,se), out, i1, i2) - call STRCAT(M_MULT_D, _projection_block)(d_in, out, i1, i2) + if (cid/=0) then + call clover_mult_ao2_block(out, clover(cid)%i(1,1,se), in, i1, i2) + call STRCAT(M_MULT_D, _projection_block)(d_in, out, i1, i2) + else + call STRCAT(M_MULT_D, _projection_block)(d_in, in, i1, i2) + endif #endif enddo diff --git a/src/fermi/mult/m_tilde.F90 b/src/fermi/mult/m_tilde.F90 index b52011a7c53a1f08108afaac7a684a24c89323e6..7ac0fea79c9da21b8fa881cb358b03df55f7a882 100644 --- a/src/fermi/mult/m_tilde.F90 +++ b/src/fermi/mult/m_tilde.F90 @@ -34,9 +34,13 @@ subroutine mtil(out, in, id) SPINCOL_FIELD, intent(in) :: in integer, intent(in) :: id SPINCOL_FIELD :: tmp - REAL :: b + REAL :: b, fac1, fac2 b = action%mtilde(id)%b + fac1=exp( chemi) + fac2=exp(-chemi) + if (chemi /= 0)call emuu4(gauge(2)%u, fac1, fac2, .false.) + if (action%mtilde(id)%kappa /= 0) then #ifdef BAGEL @@ -78,6 +82,8 @@ subroutine mtil(out, in, id) endif #endif + if (chemi /= 0)call emuu4(gauge(2)%u, ONE, ONE, .false.) + end !------------------------------------------------------------------------------- @@ -90,12 +96,16 @@ subroutine mtil_dag(out, in, id) SPINCOL_FIELD, intent(in) :: in integer, intent(in) :: id SPINCOL_FIELD :: tmp - REAL :: b + REAL :: b, fac1, fac2 b = action%mtilde(id)%b + fac1=exp(-chemi) + fac2=exp( chemi) + + if (chemi /= 0)call emuu4(gauge(2)%u, fac1, fac2, .false.) #ifdef OMTDTD - out = in + call sc_copy(out,in) if (action%mtilde(id)%cswkappa /= 0) & call clover_mult_ao(clover(action%mtilde(id)%cid)%i(1,1,se), out, volh) if (action%mtilde(id)%h /= 0) & @@ -149,6 +159,9 @@ subroutine mtil_dag(out, in, id) call h_mult_a(out, -real(action%mtilde(id)%h,kind=RKIND), in, volh) endif #endif + + if (chemi /= 0)call emuu4(gauge(2)%u, ONE, ONE, .false.) + end !=============================================================================== diff --git a/src/fermi/mult/w_mult_block.F90 b/src/fermi/mult/w_mult_block.F90 index c80ab41c09da719cdb969e86edbb20add4f0abae..55281577818134bc158e01a830c513ecc1f826ea 100644 --- a/src/fermi/mult/w_mult_block.F90 +++ b/src/fermi/mult/w_mult_block.F90 @@ -30,24 +30,52 @@ module module_m_mult_block REAL, dimension(:), pointer, save :: tmp1 ! sc2-field REAL, dimension(:), pointer, save :: tmp2 ! sc2-field + interface + subroutine wdagw_block(out, in, id, extra_loops, r, bk, paap) + use module_vol + implicit none + SPINCOL_OVERINDEXED :: out, in, r + integer :: id + logical :: extra_loops + REAL :: bk + DOUBLE :: paap + end subroutine wdagw_block + subroutine wmul_block(out, in, id, extra_loops, p_or_r, bk, paap) + use module_vol + implicit none + SPINCOL_OVERINDEXED, target :: out, in + integer :: id + logical :: extra_loops + SPINCOL_OVERINDEXED :: p_or_r + REAL :: bk + DOUBLE :: paap + end subroutine wmul_block + subroutine wdag_block(out, in, id, extra_loops, p_or_r, bk, paap) + use module_vol + implicit none + SPINCOL_OVERINDEXED, target :: out, in + integer :: id + logical :: extra_loops + SPINCOL_OVERINDEXED :: p_or_r + REAL :: bk + DOUBLE :: paap + end subroutine wdag_block + end interface + end !------------------------------------------------------------------------------- subroutine wdagw_block(out, in, id, extra_loops, r, bk, paap) ! out = (W+ W) in use module_vol - use module_p_interface + use module_m_mult_block implicit none - SPINCOL_FIELD, intent(out) :: out - SPINCOL_FIELD, intent(inout) :: in - P_SPINCOL_FIELD, save :: tmp - integer,intent(in) :: id - logical, intent(in) :: extra_loops - SPINCOL_FIELD, intent(in) :: r - REAL, intent(in) :: bk - DOUBLE, intent(out) :: paap + SPINCOL_OVERINDEXED :: out, in, r, tmp + integer,intent(in) :: id + logical,intent(in) :: extra_loops + REAL, intent(in) :: bk + DOUBLE, intent(out) :: paap TIMING_START(timing_bin_mtdagmt) - ALLOCATE_SC_FIELD(tmp) call wmul_block(tmp, in, id, extra_loops, r, bk, paap) call wdag_block(out, tmp, id, extra_loops, in, bk, paap) TIMING_STOP(timing_bin_mtdagmt) @@ -58,6 +86,7 @@ subroutine wmul_block(out, in, id, extra_loops, p_or_r, bk, paap) # undef DAGGER +# undef d # define M_MULT_D d # define PLUS + # define MINUS - @@ -77,6 +106,7 @@ subroutine wdag_block(out, in, id, extra_loops, p_or_r, bk, paap) # undef PLUS # undef MINUS +# undef d_dag # define M_MULT_D d_dag # define PLUS - # define MINUS + @@ -86,5 +116,6 @@ subroutine wdag_block(out, in, id, extra_loops, p_or_r, bk, paap) #else # include "m_mult_block.h90" #endif + end !=============================================================================== diff --git a/src/fermi/mult/w_mult_block_r4.F90 b/src/fermi/mult/w_mult_block_r4.F90 index e124fab9497f8b026be8a97b4a70a8e0e8825f75..f70501ed3183a37a02963783a4940ad1bc75c7b7 100644 --- a/src/fermi/mult/w_mult_block_r4.F90 +++ b/src/fermi/mult/w_mult_block_r4.F90 @@ -1,5 +1,4 @@ # define PRECISION_R4 -# define WDAGW_R4 #ifdef LIBDI # include "w_mult_block.F90" diff --git a/src/fermi/mult/w_mult_r4.F90 b/src/fermi/mult/w_mult_r4.F90 index 59a7b93a5cb416fccca22710c55aeea54eb8a9cb..b8181e094aef7c1f86c9df79e92515bf7b211583 100644 --- a/src/fermi/mult/w_mult_r4.F90 +++ b/src/fermi/mult/w_mult_r4.F90 @@ -1,4 +1,3 @@ # define PRECISION_R4 -# define WDAGW_R4 # include "w_mult.F90" diff --git a/src/fermi/rhmc/init_rhmc.F90 b/src/fermi/rhmc/init_rhmc.F90 index b7201232db4625f1a854d5e80e3073e8246da704..734d333d8732c85506212c3b7c808abeb8d3de8a 100644 --- a/src/fermi/rhmc/init_rhmc.F90 +++ b/src/fermi/rhmc/init_rhmc.F90 @@ -4,7 +4,7 @@ ! !------------------------------------------------------------------------------- ! -! Copyright (C) 2006-2007 Yoshifumi Nakamura +! Copyright (C) 2006-2011 Yoshifumi Nakamura ! ! This file is part of BQCD -- Berlin Quantum ChromoDynamics program ! @@ -38,6 +38,9 @@ subroutine init_rhmc(para) type(hmc_para), intent(in) :: para integer ::i, j, nth, max_frac, n_rid, iostat FILENAME:: list +!! REAL , allocatable :: relax_tmp(:) + REAL :: dmax + character (len=100) :: key nth=0 if (para%model=="F")then @@ -97,7 +100,6 @@ subroutine init_rhmc(para) enddo n_rid = i - rewind(ULIST) iostat = 0 @@ -107,10 +109,53 @@ subroutine init_rhmc(para) enddo close(ULIST) else - call die("init_rhmc(): list is missing") + call die("init_rhmc(): tuning_approx_range_list is missing") endif endif + list = input%tuning_fraction_tolerance + if (list /= " ") then + open(ULIST, file = list, action = "read", status = "old") + iostat = 0 + i = 0 + do while (iostat == 0) + read(ULIST, *, iostat = iostat) key + i = i + 1 + enddo + i=i-1 + + if (my_pe()==0)write(0,*)"tuning_fraction_tolerance",i,"lines are read" + + rewind(ULIST) + + iostat = 0 + allocate(relax(i)) + do j = 1, i + read(ULIST, *) relax(j) + enddo + + dmax=ZERO + do j = 1, i + dmax=max(relax(j),dmax) + enddo + if (dmax==ZERO) call die("init_rhmc(): max of tuning_fraction_tolerance is zero") + + relax=dmax/relax + if (my_pe()==0) then + write(0,*)"multi shift solver tolerances are relaxed" + write(0,*)"shift factor" + do j = 1, i + write(0,*)j, relax(j) + enddo + endif + +!! deallocate(relax_tmp) + close(ULIST) + endif + + + + ratapp(0)%time_switch=1 !! do i=1,min(ratapp(0)%shift,input%rhmc_fraction_u1) !! ratapp(0)%time_switch(i)=1 @@ -174,8 +219,10 @@ endif if (input%tuning_approx_range/=0)rid = rid + 1 endif if (max_ev/min_ev > ratapp(rid)%max_rhmc/ratapp(rid)%min_rhmc) then - ratapp(rid)%max_rhmc = (max_ev / min_ev) * ratapp(rid)%margin_factor - ratapp(rid)%min_rhmc = 1 +!! ratapp(rid)%max_rhmc = (max_ev / min_ev) * ratapp(rid)%margin_factor +!! ratapp(rid)%min_rhmc = 1 + ratapp(rid)%max_rhmc = max_ev * ratapp(rid)%margin_factor + ratapp(rid)%min_rhmc = min_ev deg(1) = ratapp(rid)%shift deg(2) = ratapp(rid)%shift_exact @@ -185,11 +232,10 @@ endif allocate(dp(1:deg(pm), pm)) #ifdef FMLIB call remez(ratapp(rid)%min_rhmc,ratapp(rid)%max_rhmc, & - 1, num*pm, deg(pm), 60, dr, dp, pm) + 1, num*pm, deg(pm),100, dr, dp, pm) #else call die("remez method needs FMLIB") #endif - call storeremez(rid, deg(pm), pm, num*pm, dr, dp) deallocate(dr) deallocate(dp) @@ -220,6 +266,33 @@ endif !! endif end +!------------------------------------------------------------------------------- +subroutine init_rid() + use module_action + use module_rhmc + use module_input + implicit none + integer :: fid, mid, rid, ftype + logical :: id_done(n_mtilde_id,8) + logical, external :: type_rational + + id_done = .false. + rid = 0 + + do fid = 1, size(action%fermi) + ftype = action%fermi(fid)%type + mid = action%fermi(fid)%mid1 + if ( type_rational(ftype) ) then + if (.not. id_done(mid,ftype)) then + id_done(mid,ftype) = .true. + if (input%tuning_approx_range/=0)rid = rid + 1 + endif + action%fermi(fid)%rid = rid + endif + enddo + +end + !------------------------------------------------------------------------------- subroutine storeremez(rid, deg, pm, num, dr, dp) use module_rhmc @@ -263,4 +336,5 @@ subroutine storeremez(rid, deg, pm, num, dr, dp) endif end + !=============================================================================== diff --git a/src/fermi/rhmc/remez.F90 b/src/fermi/rhmc/remez.F90 index 105fc9852b9dc3961939b9bc62e3809b16324286..6bf87a805529dd52a8fee5918e428e4109c1f793 100644 --- a/src/fermi/rhmc/remez.F90 +++ b/src/fermi/rhmc/remez.F90 @@ -1,10 +1,11 @@ !=============================================================================== ! -! remez.F90 +! remez.F90 with FMLIB version 1.3 +! not optimized, maybe slower then remez.F90_FMLIBv1.2) ! !------------------------------------------------------------------------------- ! -! Copyright (C) 2008 Yoshifumi Nakamura +! Copyright (C) 2008-2011 Yoshifumi Nakamura ! ! This file is part of BQCD -- Berlin Quantum ChromoDynamics program ! @@ -29,6 +30,7 @@ module module_remez type(fm), allocatable, save :: roots(:), poles(:) integer, save :: n, d, neq integer, save :: power_num, power_den + end !------------------------------------------------------------------------------- @@ -176,7 +178,7 @@ integer function remez_root(err_dp) tolerance = 1d-15 - call fmpi(pi) + call fm_pi(pi) spread = to_fm(1d37) iter = 0 apwidt = apend - apstrt @@ -218,22 +220,20 @@ subroutine initialguess() mm(0) = apstrt do i = 1, neq-1 - call fmcos(pi*i/a, cc) -!! r = to_fm(0.5) * (to_fm(1) - cc ) -!! r = (to_fm(1) - cc )/2 - r = ( 1 - cc )/2 - call fmsqrt_r1(r) - mm(i) = apstrt + r * apwidt +!! call fmcos(pi*i/a, cc) +!! cc=cos(pi*i/a) +!! r = ( 1 - cos(pi*i/a) )/2 +!! call fmsqrt_r1(r) + mm(i) = apstrt + sqrt( ( 1 - cos(pi*i/a) )/2 ) * apwidt enddo mm(neq) = apend a = to_fm(2.0 * neq) do i = 0, neq - call fmcos(pi*(2*i+1)/a, cc) - r = (1 - cc )/2 - call fmsqrt_r1(r) -!! r = (exp(to_dp(r))-1)/(exp(1.0)-1) - xx(i) = apstrt + r * apwidt +!! call fmcos(pi*(2*i+1)/a, cc) +!! r = (1 - cc )/2 +!! call fmsqrt_r1(r) + xx(i) = apstrt + sqrt( (1 - cos(pi*(2*i+1)/a) )/2 ) * apwidt enddo end @@ -291,8 +291,9 @@ subroutine target_func(x, y) type(fm), intent(in) :: x type(fm) :: pwr, f, df, dy, tmp1,tmp2 - pwr = to_fm(dble(power_num)/dble(power_den)) - call fmpwr(x,pwr,y) +!! pwr = to_fm(dble(power_num)/dble(power_den)) +!! call fmpwr(x,pwr,y) + call fmrpwr(x, power_num, power_den, y) end @@ -378,7 +379,7 @@ subroutine search(ym) type(fm), allocatable :: yy(:) meq = neq + 1 - allocate( yy(meq) ) + allocate( yy(0:meq) ) eclose = to_fm(1d30) farther = to_fm(0) diff --git a/src/fermi/rhmc/remez.F90_FMLIBv1.2 b/src/fermi/rhmc/remez.F90_FMLIBv1.2 new file mode 100644 index 0000000000000000000000000000000000000000..03a2f89b0bb9d53a60445838831d67fdc77facb4 --- /dev/null +++ b/src/fermi/rhmc/remez.F90_FMLIBv1.2 @@ -0,0 +1,706 @@ +!=============================================================================== +! +! remez.F90 with FMLIB version 1.2 +! +!------------------------------------------------------------------------------- +! +! Copyright (C) 2008-2011 Yoshifumi Nakamura +! +! This file is part of BQCD -- Berlin Quantum ChromoDynamics program +! +! BQCD 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 Foundation, either version 3 of the License, or +! (at your option) any later version. +! +! BQCD is distributed in the hope that it will be useful, +! but WITHOUT ANY WARRANTY; without even the implied warranty of +! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +! GNU General Public License for more details. +! +! You should have received a copy of the GNU General Public License +! along with BQCD. If not, see <http://www.gnu.org/licenses/>. +! +!------------------------------------------------------------------------------- +module module_remez + use fmzm + type(fm), save :: spread, apstrt, apend, apwidt, pi, delta, norm + type(fm), allocatable, save :: mm(:), xx(:), step(:), coef(:) + type(fm), allocatable, save :: roots(:), poles(:) + integer, save :: n, d, neq + integer, save :: power_num, power_den + +end + +!------------------------------------------------------------------------------- +subroutine remez(start, end, power_num, power_den, degree, prec, dr, dp, pm) + use module_function_decl + implicit none + real(8), intent(in) :: start, end + integer, intent(in) :: power_num, power_den, degree, prec, pm + real(8), intent(out):: dr(0:degree,pm), dp(degree,pm) + real(8) :: err + integer :: n,d, i, rrr + integer, external :: remez_root + + if (.not.(pm == 1 .or. pm == 2)) call die("undefined procedure at remez") + + n=degree + d=degree + + call remez_init(power_num,power_den,n,d,start,end,prec) + call remez_allocate() + rrr= remez_root(err) + if (rrr==1) call die("Delta too small, try increasing precision") + if (rrr==2) call die("remez_root : try increasing maxiter") + + if ( pm == 1) then + call getpfe(-1, dr(0,1), dp(1,1)) + if (my_pe()==0) then + write(0,*)"generated new coeffs x^(-",power_num,"/",power_den,")" + write(0,*)"range[", start,",", end,"]" + write(0,*)err + write(0,"(d25.17)")dr(0,1) + do i = 1,n + write(0,"(2d25.17)")dr(i,1),dp(i,1) + enddo + endif + else + call getpfe(-1, dr(0,1), dp(1,1)) + if (my_pe()==0) then + write(0,*)"generated new coeffs x^(-",power_num,"/",power_den,")" + write(0,*)"range[", start,",", end,"]" + write(0,*)err + write(0,"(d25.17)")dr(0,1) + do i = 1,n + write(0,"(2d25.17)")dr(i,1),dp(i,1) + enddo + endif + call getpfe( 1, dr(0,2), dp(1,2)) + if (my_pe()==0) then + write(0,*)"generated new coeffs x^(+",power_num,"/",power_den,")" + write(0,*)"range[", start,",", end,"]" + write(0,*)err + write(0,"(d25.17)")dr(0,2) + do i = 1,n + write(0,"(2d25.17)")dr(i,2),dp(i,2) + enddo + endif + endif + + call remez_deallocate() + +end + +!------------------------------------------------------------------------------- +subroutine remez_test() + implicit none + real(8) :: start, end, err, dr(0:10), dp(10) + integer :: power_num,power_den,n,d, prec, i, rrr + integer, external :: remez_root + + start = 0.003_8 + end = 1 + power_num =1 + power_den =2 + prec=95 + + do i = 41, 80 + n=i;d=n +10 continue + call remez_init(power_num,power_den,n,d,start,end,prec) + call remez_allocate() + rrr= remez_root(err) +!! if (rrr==1) call die("Delta too small, try increasing precision") + if (rrr==1) then + prec = prec + 1 + call remez_deallocate() + go to 10 + endif + if (rrr==2) call die("remez_root : try increasing maxiter") + call remez_deallocate() + write(*,*)" %remez",n, prec + enddo +end + +!------------------------------------------------------------------------------- +subroutine remez_init(pnum,pden,num,den,start,end,prec) + use module_remez + implicit none + real(8) :: start, end + integer :: prec, pnum,pden,num,den + + power_num = pnum + power_den = pden + n = num + d = den + neq = n + d + 1 + call fm_set(prec) + apstrt = to_fm(start) + apend = to_fm(end) + +end +!------------------------------------------------------------------------------- +subroutine remez_allocate() + use module_remez + implicit none + + allocate(step(0:n+d+1)) + allocate( mm(0:n+d+1)) + allocate( xx(0:n+d+2)) + allocate(coef(n+d+1)) + allocate( roots(0:n-1) ) + allocate( poles(0:d-1) ) +end + +!------------------------------------------------------------------------------- +subroutine remez_deallocate() + use module_remez + implicit none + + deallocate(step) + deallocate( mm) + deallocate( xx) + deallocate(coef) + deallocate( roots) + deallocate( poles) +end + +!------------------------------------------------------------------------------- +integer function remez_root(err_dp) + use module_remez + implicit none + real(8), intent(out) :: err_dp + integer :: iter + real(8) :: tolerance + type(fm) :: err + + tolerance = 1d-15 + + call fm_pi(pi) + spread = to_fm(1d37) + iter = 0 + apwidt = apend - apstrt + + call initialguess() + call stpini() + + do while (spread > tolerance) + if (mod(iter, 100) == 0 ) then + write(0,*)iter, to_dp(spread), to_dp(delta) + endif + call equations(neq,n,d, xx(0:neq-1), coef) + if (delta < tolerance) then + remez_root = 1 + return + endif + call search(err) + iter = iter + 1 + if (iter > 999999) then + remez_root = 2 + return + endif + enddo + err_dp = to_dp(err) + write(0,*)"Converged at",iter,"iterations, error =",err_dp + + call root() + remez_root = 0 +end + +!------------------------------------------------------------------------------- +subroutine initialguess() + use module_remez + implicit none + type(fm) :: a, r, cc + integer :: i + + a = to_fm(neq) + + mm(0) = apstrt + do i = 1, neq-1 +!! call fmcos(pi*i/a, cc) +!! cc=cos(pi*i/a) +!! r = ( 1 - cos(pi*i/a) )/2 +!! call fmsqrt_r1(r) + mm(i) = apstrt + sqrt( ( 1 - cos(pi*i/a) )/2 ) * apwidt + enddo + mm(neq) = apend + + a = to_fm(2.0 * neq) + do i = 0, neq +!! call fmcos(pi*(2*i+1)/a, cc) +!! r = (1 - cc )/2 +!! call fmsqrt_r1(r) + xx(i) = apstrt + sqrt( (1 - cos(pi*(2*i+1)/a) )/2 ) * apwidt + enddo + +end + +!------------------------------------------------------------------------------- +subroutine stpini() + use module_remez + implicit none + integer :: i + + xx(neq+1) = apend + delta = to_fm(0.25) + step(0) = xx(0) - apstrt + do i = 1, neq-1 + step(i) = xx(i) - xx(i-1) + enddo + step(neq) = step(neq-1) + +end + +!------------------------------------------------------------------------------- +subroutine equations(nd1,n,d, xt, b) + use fmzm + implicit none + type(fm), intent(out) :: b(nd1) + type(fm), intent(in) :: xt(nd1) + integer, intent(in) :: nd1, n, d + type(fm) :: a(nd1,nd1), yt, z + integer :: i, j + + do i = 1, nd1 + call target_func(xt(i), yt) + z = to_fm(1) + do j = 1, n+1 + a(i,j) = z + z = z * xt(i) + enddo + z = to_fm(1) + do j = 1, d + a(i,n+1+j) = - yt * z + z = z * xt(i) + enddo + b(i) = yt * z + enddo + + call solve_fm(a,b,nd1) + +end + +!------------------------------------------------------------------------------- +subroutine target_func(x, y) + use module_remez + implicit none + type(fm), intent(out) :: y + type(fm), intent(in) :: x + type(fm) :: pwr, f, df, dy, tmp1,tmp2 + +!! pwr = to_fm(dble(power_num)/dble(power_den)) +!! call fmpwr(x,pwr,y) + call fmrpwr(x, power_num, power_den, y) + +end + +!------------------------------------------------------------------------------- +subroutine solve_fm(a, b, n) + use fmzm + implicit none + type(fm), intent(inout) :: a(n,n), b(n) + integer, intent(in) :: n + type(fm) :: big, tmp, dum, pivinv + integer :: i,j,k,l,ll, irow, icol, ipiv(n) + + ipiv = 0 + + do i = 1, n + big = to_fm(0) + do j = 1, n + if (ipiv(j) /= 1) then + do k = 1, n + if (ipiv(k) == 0) then + call fmabs(a(j, k), tmp) + if (tmp >= big) then + big = tmp + irow = j + icol = k + endif + else if (ipiv(k) > 1) then + call die("solve_fm(): singular matrix 1") + endif + enddo + endif + enddo + + ipiv(icol) = ipiv(icol) + 1 + + if (irow /= icol) then + do l = 1, n + dum = a(irow, l) + a(irow, l) = a(icol, l) + a(icol, l) = dum + enddo + dum = b(irow) + b(irow) = b(icol) + b(icol) = dum + endif + + if (a(icol, icol) == 0 ) then + call fm_prnt(a(icol, icol)) + call die("solve_fm(): singular matrix 2") + endif + + pivinv = 1 / a(icol, icol) + !!a(icol, icol) = ONE !! only needed for inv(a) + + do l = 1, n + a(icol, l) = a(icol, l) * pivinv + enddo + + b(icol) = b(icol) * pivinv + + do ll = 1, n + if (ll /= icol) then + dum = a(ll, icol) + a(ll, icol) = to_fm(0) + do l = 1, n + a(ll, l) = a(ll, l) - a(icol, l) * dum + enddo + b(ll) = b(ll) - b(icol) * dum + endif + enddo + + enddo + +end + +!------------------------------------------------------------------------------- +! Search for error maxima and minima +subroutine search(ym) + use module_remez + implicit none + integer :: i, j, meq, emsign, ensign, steps + type(fm) :: a, q, xm, ym, xn, yn, xx0, xx1, eclose, farther + type(fm), allocatable :: yy(:) + + meq = neq + 1 + allocate( yy(0:meq) ) + + eclose = to_fm(1d30) + farther = to_fm(0) + + j = 1 + xx0 = apstrt + + do i=0, meq -1 + steps = 0 + xx1 = xx(i) + if (i==meq-1) xx1 = apend + xm = mm(i) + call geterr(ym,xm,emsign) + q = step(i) + xn = xm + q + if (xn < xx0 .or. xn >= xx1) then + q = -q + xn = xm + yn = ym + ensign = emsign + else + call geterr(yn,xn,ensign) + if (yn < ym) then + q = -q + xn = xm + yn = ym + ensign = emsign + endif + endif + + + do while(yn >= ym) + steps = steps + 1 + if (steps > 10) exit + + ym = yn + xm = xn + emsign = ensign + a = xm + q + if (a == xm .or. a <= xx0 .or. a >= xx1) exit + xn = a + call geterr(yn,xn,ensign) + enddo + + mm(i) = xm !! Position of maximum + yy(i) = ym !! Value of maximum + + if (eclose > ym) eclose = ym + if (farther < ym) farther = ym + + xx0 = xx1 !! Walk to next zero. + enddo !! end of search loop + + q = (farther - eclose) !! Decrease step size if error spread increased + if ( eclose /= to_fm(0) ) q = q / eclose !! Relative error spread + if (q >= spread) delta = delta * to_fm(0.5) !! Spread is increasing; decrease step size + spread = q + + + do i = 0, neq - 1 + q = yy(i+1) + if (q /= 0 ) then + q = yy(i) / q - to_fm(1) + else + q = to_fm(0.0625) + endif + if (q > to_fm(0.25)) q = to_fm(0.25) + q = q * ( mm(i+1) - mm(i) ) + step(i) = q * delta + enddo + + step(neq) = step(neq-1) + + do i = 0, neq - 1 + xm = xx(i) - step(i) + if ( xm <= apstrt ) cycle + if ( xm >= apend ) cycle + if (xm <= mm(i) ) xm = to_fm(0.5) * (mm(i) + xx(i)) + if (xm >= mm(i+1)) xm = to_fm(0.5) * (mm(i+1) + xx(i)) + xx(i) = xm + enddo + + deallocate(yy) + +end + +!------------------------------------------------------------------------------- +subroutine geterr(err,x,nsign) + use fmzm + implicit none + integer :: nsign + type(fm) :: err,x,f,app + + call target_func(x, f) + call approx(x, app) + err = app - f + + if (f /= to_fm(0)) err = err / f + if (err < to_fm(0)) then + nsign = -1 + err = -err + else + nsign = 1 + endif + +end + +!------------------------------------------------------------------------------- +subroutine approx(x,app) + use module_remez + implicit none + type(fm) :: x,app, yn, yd + integer :: i + + yn = coef(n+1) + do i = n, 1, -1 + yn = x * yn + coef(i) + enddo + yd = x + coef(d+n+1) + do i = d+n,n+2,-1 + yd = x * yd + coef(i) + enddo + + app = yn/yd + +end + +!------------------------------------------------------------------------------- +subroutine root() + use module_remez + implicit none + type(fm) :: x,dx,upper,lower,tol + type(fm) :: poly(0:neq) + integer :: i,j + + dx = 0.5 + upper=to_fm(1) ; lower=to_fm(-100000) ; tol = to_fm(1d-20) + + poly(0:neq)=to_fm(0) + + !! First find the numerator roots + do i = 0, n + poly(i) = coef(i+1) + enddo + + do i = n-1, 0, -1 + call rtnewt(roots(i), poly, i+1, lower,upper,tol) + if ( roots(i) == 0 ) write(0,*)i + if ( roots(i) == 0 ) call die("Err: Failure to converge on root of num") + poly(0) = -poly(0) / roots(i) + do j = 1, i + poly(j) = ( poly(j-1) - poly(j) ) / roots(i) + enddo + enddo + + !! Now find the denominator roots + poly(d) = 1 + do i = 0, d-1 + poly(i) = coef(n+2+i) + enddo + do i = d-1, 0, -1 + call rtnewt(poles(i),poly,i+1,lower,upper,tol); + if (poles(i) == 0.0) call die("Err: Failure to converge on rootof den") + poly(0) = -poly(0)/poles(i) + do j = 1, i + poly(j) = ( poly(j-1) - poly(j) ) / poles(i); + enddo + enddo + + norm = coef(n+1) + +#ifdef DEBUG2 + write(0,*)"Normalisation constant is",to_dp(norm) + do i = 0, n-1 + write(0,*)"root(",i,")=",to_dp(roots(i)) + enddo + do i = 0, d-1 + write(0,*)"pole(",i,")=",to_dp(poles(i)) + enddo +#endif + +end + +!------------------------------------------------------------------------------- +subroutine rtnewt(out, poly, i, x1, x2, xacc) + use module_remez + implicit none + type(fm) :: out, poly(0:neq), x1, x2, xacc, df, dx, f + integer :: i, j, jmax, k + +jmax=1000 + out = (x1+x2)/2 + do j=1, jmax + f=poly(i) + do k=i-1,0,-1 + f= f*out + poly(k) + enddo + + df=to_fm(i)*poly(i) + do k=i-1,1,-1 + df = df*out + to_fm(k)*poly(k) + enddo + dx = f/df + out = out - dx + if ((x1-out)*(out-x2) < 0) call die("Jumped out of brackets in rtnewt") + if (abs(dx) < xacc) return + enddo + call warn("Maximum number of iterations exceeded in rtnewt") + out = 0 + +end + +!------------------------------------------------------------------------------- +subroutine getpfe(ss, dr, dp) + use module_remez + implicit none + type(fm) :: r(0:n-1), p(0:d-1), tmp + integer :: i, ss + real(8) :: dr(0:n), dp(d) + + if (n /= d) call die("n should be equal to d ") + if (.not. (ss == 1 .or. ss == -1)) call die("getpfe : unknown sign") + + if (ss == -1) then + do i = 0, n-1 + p(i)=roots(i) + r(i)=poles(i) + enddo + tmp = 1/norm + else + do i = 0, n-1 + r(i)=roots(i) + p(i)=poles(i) + enddo + tmp = norm + endif + + call pfe(n, d, r,p,tmp) + + do i = 1,n + dr(i)= to_dp(r(i-1)) + dp(i)= to_dp(p(i-1)) + enddo + dr(0)=to_dp(tmp) +end + +!------------------------------------------------------------------------------- +subroutine pfe(n, d, res, poles, norm) + use fmzm + implicit none + integer, intent(in) :: n, d + type(fm), intent(inout) :: res(0:n-1), poles(0:d-1), norm + type(fm) :: numerator(0:n-1), denominator(0:d-1), temp + integer :: i, j, small + +! Initialization + do i = 1, n-1 + numerator(i) = to_fm(0) + denominator(i) = to_fm(0) + enddo + numerator(0) = to_fm(1) + denominator(0) = to_fm(1) + + do j = 0, n-1 + do i = n-1, 0, -1 + numerator(i) = - numerator(i) * res(j) + denominator(i) = - denominator(i) * poles(j) + if (i>0) then + numerator(i) = numerator(i) + numerator(i-1) + denominator(i) = denominator(i) + denominator(i-1) + endif + enddo + enddo + +! Convert to proper fraction form. +! Fraction is now in the form 1 + n/d, where O(n)+1=O(d) + + do i = 0, n-1 + numerator(i) = numerator(i) - denominator(i) + enddo + +! Find the residues of the partial fraction expansion and absorb the +! coefficients. + + do i = 0, n-1 + res(i) = to_fm(0) + do j = n-1, 0, -1 + res(i) = poles(i)*res(i)+numerator(j) + enddo + do j = n-1, 0, -1 + if (i/=j) res(i) = res(i) / (poles(i)-poles(j)) + enddo + res(i) = res(i)*norm + enddo + +! res now holds the residues + + j = 0 + do i = 0, n-1 + poles(i) = -poles(i) + enddo + +! Move the ordering of the poles from smallest to largest + do j = 0, n-1 + small = j + do i = j+1, n-1 + if (poles(i) < poles(small)) small = i + enddo + if (small /= j) then + temp = poles(small) + poles(small) = poles(j) + poles(j) = temp + temp = res(small) + res(small) = res(j) + res(j) = temp + + endif +#ifdef DEBUG2 + write(0,*)"pfe : Residue = ", to_dp(res(j)), " Pole = ",to_dp(poles(j)) +#endif + enddo + +end + +!=============================================================================== diff --git a/src/fermi/solver/Makefile b/src/fermi/solver/Makefile index fc41a4834397b5d3032c8403d91600ec853ba577..c82dc33666106e680a895263724e781c9ae1d5d5 100644 --- a/src/fermi/solver/Makefile +++ b/src/fermi/solver/Makefile @@ -4,7 +4,7 @@ # #------------------------------------------------------------------------------- # -# Copyright (C) 2008 Yoshifumi Nakamura +# Copyright (C) 2008, 2010 Yoshifumi Nakamura # # This file is part of BQCD -- Berlin Quantum ChromoDynamics program # @@ -27,25 +27,16 @@ include $(DIR)Makefile.in MODULES_DIR = $(DIR)/modules ifdef FPP2 - fpp = $(FPP2) + fpp = $(FPP2) -I$(DIR)/include $(MYFLAGS) else - fpp = $(FPP) + fpp = $(FPP) -I$(DIR)/include $(MYFLAGS) endif .SUFFIXES: .SUFFIXES: .a .o .F90 - -ifdef ARPACK -MYFLAGS += -DARPACK -endif -ifdef LAPACK -MYFLAGS += -DLAPACK -endif - - .F90.o: - $(fpp) -I$(DIR)/include $(MYFLAGS) $< > $*.f90 + $(fpp) $< > $*.f90 $(F90) -c $(FFLAGS) $*.f90 OBJS = \ @@ -78,7 +69,14 @@ OBJS = \ cg_def.o \ solver.o \ sort.o \ - gcrodr_dd.o + gcrodr_dd.o \ + gcrodr.o + +ifdef quad +OBJS += mre_r16.o \ + cg_r16.o \ + cg_mix_r16.o +endif ifdef ARPACK OBJS += neig.o \ @@ -106,3 +104,14 @@ cg.o:cg.F90 $(fpp) -I$(DIR)/include $(MYFLAGS) cg.F90 > cg.f90 $(F90) -c -O2 -I../../modules -qmaxmem=-1 -qarch=450d -qtune=450 cg.f90 endif + +cg_r4.o: cg.F90 + $(fpp) -DPRECISION_R4 $< > $*.f90 + $(F90) -c $(FFLAGS32) $*.f90 +cg_r16.o: cg.F90 + $(fpp) -DPRECISION_R16 $< > $*.f90 + $(F90) -c $(FFLAGS) $*.f90 + +mre_r16.o: mre.F90 + $(fpp) -DPRECISION_R16 $< > $*.f90 + $(F90) -c $(FFLAGS) $*.f90 diff --git a/src/fermi/solver/blockbicggr.F90 b/src/fermi/solver/blockbicggr.F90 new file mode 100644 index 0000000000000000000000000000000000000000..254eca3d256d233ed07172730be9a943f9182a01 --- /dev/null +++ b/src/fermi/solver/blockbicggr.F90 @@ -0,0 +1,234 @@ +!=============================================================================== +! +! blockbicggr.F90 - solves "matrix_mult * X = B" +! +!------------------------------------------------------------------------------- +! +! Copyright (C) 2010 Yoshifumi Nakamura +! +! This file is part of BQCD -- Berlin Quantum ChromoDynamics program +! +! BQCD 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 Foundation, either version 3 of the License, or +! (at your option) any later version. +! +! BQCD is distributed in the hope that it will be useful, +! but WITHOUT ANY WARRANTY; without even the implied warranty of +! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +! GNU General Public License for more details. +! +! You should have received a copy of the GNU General Public License +! along with BQCD. If not, see <http://www.gnu.org/licenses/>. +! +!------------------------------------------------------------------------------- +# include "defs.h" + +!------------------------------------------------------------------------------- +subroutine bloclbicggr(x, b, id, iter, res, nblock) + use module_function_decl + use module_check_solution + use module_action + use module_cg + use module_vol + use module_counter + implicit none + + real(8), dimension(2*4*3*volh_tot,nblock), intent(inout) :: x + real(8), dimension(2*4*3*volh_tot,nblock), intent(in) :: b + integer, intent(out) :: iter + integer, intent(in) :: id + DOUBLE, intent(in) :: res + + real(8), allocatable ::r0(:,:),r(:,:),p(:,:),aap(:,:) + integer :: i, niter, ierr + character(72) :: msg + integer, save :: nitert=0 + +!------------------------------------------------------------------------------- + + DEBUG2S("Start: cg") + TIMING_START(timing_bin_cg) + + allocate(r(SIZE_COMPLEX*NDIRAC*NCOL*volh_tot), STAT = ierr) + allocate(p(SIZE_COMPLEX*NDIRAC*NCOL*volh_tot), STAT = ierr) + allocate(aap(SIZE_COMPLEX*NDIRAC*NCOL*volh_tot), STAT = ierr) + + niter = 0 + + do ib = 1, nblock + call wdagw(r0(1,ib), x(1,ib), id) + niter = niter +1 + nitert= nitert+1 + + !$omp parallel do reduction(+: rtrold) private(dtmp) + do i = 1, size_sc_field + r0(i,ib) = b(i) - r0(i,ib) + r(i,ib) = r0(i,ib) + p(i,ib) = r0(i,ib) + dtmp = r(i,ib) + rtrold(ib) = rtrold(ib) + dtmp**2 + enddo + enddo + call global_sum_vec(nblock, rtrold) + + +!! if (stop_condition(rtrold, res, bb)) goto 9999 + + do ib = 1, nblock + !! precon F=MR + + !$omp parallel do + do i = 1, size_sc_field + f(i,ib) = r(i,ib) + enddo + + call wdagw(w(1,ib), f(1,ib), id) + niter = niter +1 + nitert= nitert+1 + + !$omp parallel do + do i = 1, size_sc_field + v(i,ib) = w(i,ib) + enddo + enddo + + do niter = 1, cg_para%maxiter + + do ib = 1, nblock + wr=wr+sc_cdotc(w(1,ib),r(1,ib)) + ww=ww+sc_norm2(w(1,ib)) + do jb = 1, nblock + rv(ib,jb)=sc_cdotc(r(1,ib),v(1,jb)) + rr(ib,jb)=sc_cdotc(r(1,ib),r(1,jb)) + enddo + enddo + !! globalsum + xi=1 + alpha=1 + + do ib = 1, nblock + !$omp parallel do + do i = 1, size_sc_field + s(i,ib) = p(i,ib) - zeta * v(i,ib) + enddo + enddo + + do ib = 1, nblock + do i = 1, size_sc_field + tmp=0 + do jb = 1, nblock + tmp = tmp + s(i,jb) * alpha(jb,ib) + enddo + u(i,ib) = tmp + enddo + enddo + + + + + + call wdagw(aap, p, id) ; nitert= nitert+1 + paap = ZERO + !$omp parallel do reduction(+: paap) private(dtmp1, dtmp2) + do i = 1, size_sc_field + dtmp1 = p(i) + dtmp2 = aap(i) + paap = paap + dtmp1 * dtmp2 + enddo + call global_sum_vec(1, paap) + ak = rtrold / paap + + rtr = 0.0_8 + !$omp parallel do reduction(+: rtr) private(dtmp) + do i = 1, size_sc_field + x(i) = x(i) + ak * p(i) + r(i) = r(i) - ak * aap(i) + dtmp = r(i) + rtr = rtr + dtmp**2 + enddo + call global_sum_vec(1, rtr) + + +if(my_pe()==0 .and. mod(niter,100)==0 )write(0,*)"cg res:",nitert, niter, rtr +#ifdef DEBUG2 +if(my_pe()==0 .and. mod(niter,100)==0 )write(0,*)"cg res:",niter, rtr +#endif + + if (stop_condition(rtr, res, bb)) goto 9999 + bk = rtr / rtrold + rtrold = rtr + + call sc_xpby(p, r, bk) ! p = r + bk * p + enddo + + niter = niter - 1 + + if (cg_para%log /= 2) then +if(my_pe()==0) write(0,*)"no conv==============" +if(my_pe()==0) write(0,*)"p(1)=",p(1) + call wdagw_r8(aap, p, id) +if(my_pe()==0) write(0,*)"wdagw_r8 aap(1)=",aap(1) +if(my_pe()==0) write(0,*)"wdagw_r8 aap(2)=",aap(2) +if(my_pe()==0) write(0,*)"wdagw_r8 aap(3)=",aap(3) +if(my_pe()==0) write(0,*)"wdagw_r8 aap(4)=",aap(4) + call wdagw(aap, p, id) +if(my_pe()==0) write(0,*)"wdagw aap(1)=",aap(1) +if(my_pe()==0) write(0,*)"wdagw aap(2)=",aap(2) +if(my_pe()==0) write(0,*)"wdagw aap(3)=",aap(3) +if(my_pe()==0) write(0,*)"wdagw aap(4)=",aap(4) + + + write(msg, *) "cg(): no convergence; rtr = ", rtr + call die(msg) + endif + +9999 continue + + call update_cg_stat(cg_stat, niter, 0) + cg_iterations_total = cg_stat%niter_tot_run + iter = niter + if(my_pe()==0 )write(0,*)"CG done! res:",nitert, niter, rtr + + TIMING_STOP(timing_bin_cg) + + if (cg_para%check /= 0) then ! check solution + + call check_solution(id, x, b, norm) + + if (headline_check_written == 0) then + if (my_pe() == 0) then + write(UREC, fmt_chk_h) & + "T", key_chk, "traj", "rtr", "Rb", "Rx", "iterations" + endif + headline_check_written = 1 + endif + + if (my_pe() == 0) then + write(UREC, fmt_chk_b) & + key_chk, counter%traj, rtr, & + norm(1)/norm(2), norm(1)/norm(3), iter + endif + + endif + + deallocate(r, STAT = ierr) + if (ierr /= 0) then + call stderr2_int("deallocation failed", 1, ierr) + call die("cg: deallocation failed r") + endif + deallocate(p, STAT = ierr) + if (ierr /= 0) then + call stderr2_int("deallocation failed", 1, ierr) + call die("cg: deallocation failed p") + endif + deallocate(aap, STAT = ierr) + if (ierr /= 0) then + call stderr2_int("deallocation failed", 1, ierr) + call die("cg: deallocation failed aap") + endif + + DEBUG2S("End: cg") +end + +!=============================================================================== diff --git a/src/fermi/solver/cg.F90 b/src/fermi/solver/cg.F90 index bd3fb7ccc884fb371117df2afa8631fb82ed1c76..79578e9aaa1493742102a76876e7d54ff9af09ac 100644 --- a/src/fermi/solver/cg.F90 +++ b/src/fermi/solver/cg.F90 @@ -25,6 +25,10 @@ !------------------------------------------------------------------------------- # include "defs.h" +#ifdef PRECISION_R16 +# define stop_condition stop_condition_r16 +#endif + !------------------------------------------------------------------------------- subroutine cg(x, b, id, iter, res) use module_function_decl @@ -47,6 +51,7 @@ subroutine cg(x, b, id, iter, res) DOUBLE :: rtr, rtrold, paap, bb, dtmp, dtmp1, dtmp2 integer :: i, niter, ierr character(72) :: msg + integer, save :: nitert=0 ! ! needed for checking solution @@ -84,7 +89,6 @@ subroutine cg(x, b, id, iter, res) endif - bb = 0.0_8 !$omp parallel do reduction(+: bb) private(dtmp) do i = 1, size_sc_field @@ -100,7 +104,8 @@ subroutine cg(x, b, id, iter, res) DEBUG2S("Start: cg 1") call wdagw(r, x, id) niter = 1 - DEBUG2S("Start: cg 2") + nitert= nitert+1 + rtrold = ZERO !$omp parallel do reduction(+: rtrold) private(dtmp) do i = 1, size_sc_field @@ -109,14 +114,14 @@ subroutine cg(x, b, id, iter, res) dtmp = r(i) rtrold = rtrold + dtmp**2 enddo - DEBUG2S("Start: cg 3") call global_sum_vec(1, rtrold) + + if(my_pe()==0 )write(0,*)"CG start rtr kappa:", rtrold, action%mtilde(id)%kappa if (stop_condition(rtrold, res, bb)) goto 9999 - DEBUG2S("Start: cg 4") bk=ZERO do niter = 1, cg_para%maxiter - call wdagw(aap, p, id) + call wdagw(aap, p, id) ; nitert= nitert+1 paap = ZERO !$omp parallel do reduction(+: paap) private(dtmp1, dtmp2) do i = 1, size_sc_field @@ -138,7 +143,7 @@ subroutine cg(x, b, id, iter, res) call global_sum_vec(1, rtr) #ifdef DEBUG2 -if(my_pe()==0 .and. mod(niter,100)==0 )write(0,*)niter,"rtr",rtr +if(my_pe()==0 .and. mod(niter,100)==0 )write(0,*)"CG rtr iter :",rtr, niter, nitert #endif if (stop_condition(rtr, res, bb)) goto 9999 @@ -164,7 +169,6 @@ if(my_pe()==0) write(0,*)"wdagw aap(2)=",aap(2) if(my_pe()==0) write(0,*)"wdagw aap(3)=",aap(3) if(my_pe()==0) write(0,*)"wdagw aap(4)=",aap(4) - write(msg, *) "cg(): no convergence; rtr = ", rtr call die(msg) endif @@ -174,6 +178,7 @@ if(my_pe()==0) write(0,*)"wdagw aap(4)=",aap(4) call update_cg_stat(cg_stat, niter, 0) cg_iterations_total = cg_stat%niter_tot_run iter = niter + if(my_pe()==0 )write(0,*)"CG done! rtr iter :",rtr, niter, nitert TIMING_STOP(timing_bin_cg) diff --git a/src/fermi/solver/cg_control.F90 b/src/fermi/solver/cg_control.F90 index 118416efd84aef2e74fff2a23694f50ef3c112fd..cea94b04b830f422cd38ababad64f43731229aee 100644 --- a/src/fermi/solver/cg_control.F90 +++ b/src/fermi/solver/cg_control.F90 @@ -71,9 +71,17 @@ subroutine cg_outer(x, b, id, np, calc_sf) endif case("bicgstab"); call bicgstab( x, b, id, iters, res) case("gmres"); call gmres( x, b, id, iters, res) + case("gcrodr") + call init_gcrodr() + call gcrodr( x, b, id, iters, res) case("cg_mix") call cg_mix( x, b, id, iters, iters4, res) call iteration_count_is_f4(iters4, np) +#ifdef QUAD + case("cg_mix_r16") + call cg_mix_r16( x, b, id, iters, iters4, res) + call iteration_count_is_f4(iters4, np) +#endif case("bicgstab_mix") call bicgstab_mix( x, b, id, iters, iters4, res) call iteration_count_is_f4(iters4, np) @@ -350,6 +358,14 @@ subroutine cg_inner(x, b, id, iters, res) DEBUG2S("Start: cg_inner") #ifndef BAGEL +#ifdef IBM + select case(inner_solver) + case("cg"); call cg( x, b, id, iters_tmp, res) + case("bicgstab"); call bicgstab(x, b, id, iters_tmp, res) + case default + call die("cg_inner: unknown solver: " // inner_solver ) + end select +#else allocate(x4(SIZE_COMPLEX*NDIRAC*NCOL*volh_tot), STAT = ierr) if (ierr /= 0) then call stderr2_int("allocation failed", 1, ierr) @@ -388,7 +404,7 @@ subroutine cg_inner(x, b, id, iters, res) call stderr2_int("deallocation failed", 1, ierr) call die("cg_inner: deallocation failed b4") endif - +#endif #else select case(inner_solver) case("cg"); call cg( x, b, id, iters_tmp, res) @@ -458,6 +474,7 @@ subroutine mcg_outer(type, b, id, n, frdo, shift, iter_sh, np, calc_sf) use module_vol use module_dd use module_function_decl + use module_rhmc implicit none integer, intent(in) :: n, calc_sf, id, type, np ! np for iter count @@ -466,25 +483,33 @@ subroutine mcg_outer(type, b, id, n, frdo, shift, iter_sh, np, calc_sf) REAL, intent(in) :: shift(n) COMPLEX, dimension(NDIRAC, NCOL, volh_tot), intent(in) :: b - REAL :: res - integer :: iters, i8, i4 + REAL :: res, res_sh(n) + integer :: i, iters, i8, i4 external :: wdagw_r8, wtdagwt_all_dd, unprec_hdagh call get_cg_res(res, calc_sf) + res_sh=res + + if (calc_sf == CG_MD .and. associated(relax)) then + do i = 1, size(relax) + res_sh(i)=res * relax(i) + enddo + endif + select case(type) case(EO_RATIONAL) - call multi_shift_cg(wdagw_r8, id, n, frdo, shift, b, iters, iter_sh, res) -!! call fom_shift(wdagw_r8, id, n, frdo, shift, b, iters, iter_sh, res) + call multi_shift_cg(wdagw_r8, id, n, frdo, shift, b, iters, iter_sh, res_sh) +!! call fom_shift(wdagw_r8, id, n, frdo, shift, b, iters, iter_sh, res_sh) !! not work -!! call gmres_shift(wdagw_r8, id, n, frdo, shift, b, iters, iter_sh, res) +!! call gmres_shift(wdagw_r8, id, n, frdo, shift, b, iters, iter_sh, res_sh) call iteration_count_is_f(iters, np) case(DD_RATIONAL) - call multi_shift_cg(wtdagwt_all_dd, id, n, frdo, shift, b, iters, iter_sh, res) -!! call fom_shift( wtdagwt_all_dd, id, n, frdo, shift, b, iters, iter_sh, res) + call multi_shift_cg(wtdagwt_all_dd, id, n, frdo, shift, b, iters, iter_sh, res_sh) +!! call fom_shift( wtdagwt_all_dd, id, n, frdo, shift, b, iters, iter_sh, res_sh) call iteration_count_is_d( iters*ld%lat%num_ip,np) case(HH_RATIONAL) call init_cg_stat2(dd_stat) - call multi_shift_cg(unprec_hdagh, id, n, frdo, shift, b, iters, iter_sh, res) + call multi_shift_cg(unprec_hdagh, id, n, frdo, shift, b, iters, iter_sh, res_sh) call get_cg_stat2(dd_stat, i8,i4) call iteration_count_is_d( i8,np) call iteration_count_is_d4(i4,np) diff --git a/src/fermi/solver/cg_mix_r16.F90 b/src/fermi/solver/cg_mix_r16.F90 new file mode 100644 index 0000000000000000000000000000000000000000..1661d2f8f130888d72cf715499df914b222be02f --- /dev/null +++ b/src/fermi/solver/cg_mix_r16.F90 @@ -0,0 +1,168 @@ +!=============================================================================== +! +! cg_mix_r16.F90 - mixed precision cg +! +!------------------------------------------------------------------------------- +! +! Copyright (C) 2010 Yoshifumi Nakamura +! +! This file is part of BQCD -- Berlin Quantum ChromoDynamics program +! +! BQCD 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 Foundation, either version 3 of the License, or +! (at your option) any later version. +! +! BQCD is distributed in the hope that it will be useful, +! but WITHOUT ANY WARRANTY; without even the implied warranty of +! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +! GNU General Public License for more details. +! +! You should have received a copy of the GNU General Public License +! along with BQCD. If not, see <http://www.gnu.org/licenses/>. +! +!------------------------------------------------------------------------------- +# include "defs.h" + +!------------------------------------------------------------------------------- +subroutine cg_mix_r16(x, b, id, iter, iter4, res) + use module_function_decl + use module_check_solution + use module_field + use module_action + use module_mre_r16 + use module_cg + use module_counter + use module_vol + implicit none + + type(type_mre_r16), save :: solutions + + SPINCOL_OVERINDEXED, intent(inout) :: x + SPINCOL_OVERINDEXED, intent(in) :: b + integer, intent(out) :: iter, iter4 + integer, intent(in) :: id + REAL, intent(in) :: res + + real(8), allocatable ::r(:),p(:) + real(16), allocatable ::r16(:),p16(:),x16(:) + real(16) :: rtr, interval, rtr0, bb + integer :: i, niter, ierr + character(72) :: msg + +! +! needed for checking solution +! + REAL :: norm(3) + integer, save :: headline_check_written = 0 + character(*), parameter :: key_chk = "%cgmixChk" + character(*), parameter :: fmt_chk_h = "(1x, 2a, a6, 5a20)" + character(*), parameter :: fmt_chk_b = "(1x, a10, i6, 3e20.10, 2i20)" + +!------------------------------------------------------------------------------- + DEBUG2S("Start: cg_mix_r16") + TIMING_START(timing_bin_cg_mix) + + allocate(r(SIZE_COMPLEX*NDIRAC*NCOL*volh_tot), STAT = ierr) + allocate(p(SIZE_COMPLEX*NDIRAC*NCOL*volh_tot), STAT = ierr) + allocate(r16(SIZE_COMPLEX*NDIRAC*NCOL*volh_tot), STAT = ierr) + allocate(p16(SIZE_COMPLEX*NDIRAC*NCOL*volh_tot), STAT = ierr) + allocate(x16(SIZE_COMPLEX*NDIRAC*NCOL*volh_tot), STAT = ierr) + + iter4 = 0 + + bb = 0 + !$omp parallel do reduction(+: bb) + do i = 1, size_sc_field + bb = bb + (real(b(i),kind=16))**2 + enddo + call global_sum_vec_r16(1, bb) + + x16=x + call wdagw_r16(r16, x16, id) + niter = 1 + + rtr = 0 + !$omp parallel do reduction(+: rtr) + do i = 1, size_sc_field + r16(i) = b(i) - r16(i) + rtr = rtr + r16(i)**2 + enddo + call global_sum_vec_r16(1, rtr) + + if (stop_condition_r16(rtr, real(res,kind=16), bb)) goto 9999 + rtr0=rtr + + do niter = 1, cg_para%maxiter +!! call mre_get2_r16(solutions, p16, r16, id) + p=p16 + r=r16 +!! p=r + call cg_inner(p, r, id, iter4, dble(res_cg_inner(res, dble(rtr0), dble(bb), niter))) + p16=p +!! call mre_put(solutions, p16, 0) + + !$omp parallel do + do i = 1, size_sc_field + x16(i) = x16(i) + p16(i) + enddo + + call wdagw_r16(r16, x16, id) + rtr = 0 + !$omp parallel do reduction(+: rtr) + do i = 1, size_sc_field + r16(i) = b(i) - r16(i) + rtr = rtr + r16(i)**2 + enddo + call global_sum_vec_r16(1, rtr) + + if (stop_condition_r16(rtr, real(res,kind=16), bb)) goto 9999 + enddo + + niter = niter - 1 + + if (cg_para%log /= 2) then + write(msg, *) "cg(): no convergence; rtr = ", rtr + call die(msg) + endif + +9999 continue + call mre_put(solutions, p, 1) + call update_cg_stat(cg_stat, niter, 0) + + x=x16 + iter = niter + + TIMING_STOP(timing_bin_cg_mix) + +!! if (cg_para%check /= 0) then ! check solution +!! +!! call check_solution(id, x, b, norm) +!! +!! if (headline_check_written == 0) then +!! if (my_pe() == 0) then +!! write(UREC, fmt_chk_h) & +!! "T", key_chk, "traj", "rtr", "Rb", "Rx", "iterations", "iter4" +!! endif +!! +!! headline_check_written = 1 +!! endif +!! +!! if (my_pe() == 0) then +!! write(UREC, fmt_chk_b) & +!! key_chk, counter%traj, rtr, norm(1)/norm(2), norm(1)/norm(3), & +!! niter, iter4 +!! endif +!! endif + + deallocate(r, STAT = ierr) + deallocate(p, STAT = ierr) + deallocate(r16, STAT = ierr) + deallocate(p16, STAT = ierr) + deallocate(x16, STAT = ierr) + + DEBUG2S("End: cg_mix_r16") +stop +end + +!=============================================================================== diff --git a/src/fermi/solver/cg_mre_mtmp.F90 b/src/fermi/solver/cg_mre_mtmp.F90 index 7f79f453aa8dadb810819078db20371e00ee2e7f..bb8f2d4c6df2baac21b261c477128f72f5e800ca 100644 --- a/src/fermi/solver/cg_mre_mtmp.F90 +++ b/src/fermi/solver/cg_mre_mtmp.F90 @@ -4,7 +4,7 @@ ! !------------------------------------------------------------------------------- ! -! Copyright (C) 2006-2009 Yoshifumi Nakamura +! Copyright (C) 2006-2010 Yoshifumi Nakamura ! ! This file is part of BQCD -- Berlin Quantum ChromoDynamics program ! @@ -137,6 +137,92 @@ subroutine mre_get2(basis, trial, phi, id) end +!------------------------------------------------------------------------------- +#ifdef QUAD +subroutine mre_get2_r16(basis, trial, phi, id) + + ! get trial solution + + use module_function_decl + use module_mre_r16 + use module_vol + implicit none + + type(type_mre_r16), intent(inout) :: basis + real(16), dimension(SIZE_COMPLEX*NDIRAC*NCOL*volh_tot), intent(out) :: trial + real(16), dimension(SIZE_COMPLEX*NDIRAC*NCOL*volh_tot), intent(in) :: phi + integer , intent(in) :: id + + type(type_mre_r16), save :: mv ! "Matrix * v" + complex(16), target :: g(mre_n_vec_r16, mre_n_vec_r16 + 1) + complex(16), pointer :: b(:) + integer :: size_g + integer :: i + integer :: j + integer :: s + integer :: c + integer :: rest + + + DEBUG2S("Start: mre_get2_r16") + + if (mre_n_vec_r16 == 0 .or. .not. associated(basis%vec) .or. basis%rank == 0) then + call sc_copy_r16(trial, phi) + DEBUG2S("End: mre_get2_r16") + return + endif + + if (basis%rank == 1) then + call sc_copy_r16(trial, basis%vec(1)%sc(1,1,1)) + DEBUG2S("End: mre_get2_r16") + return + endif + + size_g = mre_n_vec_r16 * (mre_n_vec_r16 + 1) * SIZE_COMPLEX + + b => g(:, mre_n_vec_r16 + 1) ! storage arrangement for global sum + ! => one global sum for everything + + call mre_allocate_r16(mv) + call mre_gram_schmidt_r16(basis) + + do i = 1, basis%rank + b(i) = sc_cdotc_r16(basis%vec(i)%sc(1,1,1), phi) + call wmul_r16(mv%vec(i)%sc(1,1,1), basis%vec(i)%sc(1,1,1), id) + enddo + + do i = 1, basis%rank + g(i, i) = sc_norm2_r16(mv%vec(i)%sc(1,1,1)) + do j = i + 1, basis%rank + g(i, j) = sc_cdotc_r16(mv%vec(i)%sc(1,1,1), mv%vec(j)%sc(1,1,1)) + g(j, i) = conjg(g(i, j)) + enddo + enddo + + call global_sum_vec_r16(size_g, g) + + call mre_gauss_jordan_r16(g, b, basis%rank, mre_n_vec_r16) + + ! calculation of "trial" with doubled data re-use: + + call sc_cax2_r16(trial, basis%vec(1)%sc(1,1,1), b(1), basis%vec(2)%sc(1,1,1), b(2)) + + rest = mod(basis%rank, 2) + + do j = 3, basis%rank - rest, 2 + call sc_caxpy2_r16(trial, basis%vec(j)%sc(1,1,1), b(j), & + basis%vec(j+1)%sc(1,1,1), b(j+1)) + enddo + + if (rest == 1) then + j = basis%rank + call sc_caxpy_r16(trial, basis%vec(j)%sc(1,1,1), b(j)) + endif + + DEBUG2S("End: mre_get2_r16") + +end +#endif !=============================================================================== !=============================================================================== !------------------------------------------------------------------------------- diff --git a/src/fermi/solver/cg_ritz.F90 b/src/fermi/solver/cg_ritz.F90 index 33195673e14179011fc7cd2447b662f4aecfb4b4..61b9b373d457551ef3e4a7a67effe13a72fc354d 100644 --- a/src/fermi/solver/cg_ritz.F90 +++ b/src/fermi/solver/cg_ritz.F90 @@ -282,7 +282,6 @@ subroutine cg_ritz_half(ftype, id, iter, mu, x, evecs, n, action) call die("cg_ritz_half can not treat this fermionic type") endif - call orthogonalize_sc_half(n, evecs, z) pap = sc_dot(p, z) ; pap = global_sum(pap) call min_ritz_func(mu, costheta, sintheta, rtr, pap, pp, action) diff --git a/src/fermi/solver/check_solution.F90 b/src/fermi/solver/check_solution.F90 index 542c79721fa6f084c7431edbedf57b1e94116b6b..b284f9366c4867dcf6adeb09f799d1a46cb33984 100644 --- a/src/fermi/solver/check_solution.F90 +++ b/src/fermi/solver/check_solution.F90 @@ -4,7 +4,7 @@ ! !------------------------------------------------------------------------------- ! -! Copyright (C) 2008 Yoshifumi Nakamura +! Copyright (C) 2008, 2010 Yoshifumi Nakamura ! ! This file is part of BQCD -- Berlin Quantum ChromoDynamics program ! @@ -35,6 +35,14 @@ module module_check_solution interface check_solution +#ifdef QUAD + subroutine check_solution_r16(id, x, b, norm) + real(16), dimension(:), intent(in) :: x, b + integer, intent(in) :: id + real(16), intent(out):: norm(3) + end +#endif + subroutine check_solution_r8(id, x, b, norm) real(8), dimension(:), intent(in) :: x, b integer, intent(in) :: id @@ -76,6 +84,34 @@ module module_check_solution #endif end module module_check_solution +!------------------------------------------------------------------------------- +#ifdef QUAD +subroutine check_solution_r16(id, x, b, norm) + use module_vol + use module_p_interface_r16 + implicit none + real(16), dimension(:), intent(in) :: x, b + integer, intent(in) :: id + real(16), intent(out):: norm(3) + real(16), dimension(:), pointer, save :: r + integer :: i + + if (.not. associated(r)) call allocate_sc_overindexed_r16(r) + + call wdagw_r16(r, x, id) + + norm = 0 + !$omp parallel do reduction(+: norm) + do i = 1, size_sc_field + norm(1) = norm(1) + (r(i) - b(i))**2 + norm(2) = norm(2) + b(i)**2 + norm(3) = norm(3) + x(i)**2 + enddo + + call global_sum_vec_r16(3, norm) + +end +#endif !------------------------------------------------------------------------------- subroutine check_solution_r8(id, x, b, norm) use module_vol diff --git a/src/fermi/solver/gcrodr.F90 b/src/fermi/solver/gcrodr.F90 index adce4a7c46de59ea1e9cd4e95bbd176295c37336..69c233b6a913d08b079535939ee10cdba1405ed3 100644 --- a/src/fermi/solver/gcrodr.F90 +++ b/src/fermi/solver/gcrodr.F90 @@ -8,7 +8,7 @@ ! !------------------------------------------------------------------------------- ! -! Copyright (C) 2008 Yoshifumi Nakamura +! Copyright (C) 2008, 2010 Yoshifumi Nakamura ! ! This file is part of BQCD -- Berlin Quantum ChromoDynamics program ! @@ -29,251 +29,474 @@ # include "defs.h" !------------------------------------------------------------------------------- -subroutine gcrodr(x, b, id, iter, res) +module module_gcrodr + + type type_eigenmodes + logical :: initial, fresh + complex(8), pointer :: eval(:) + complex(8), pointer :: x(:,:) + end type type_eigenmodes + + integer, save :: defeig, m + type(type_eigenmodes),dimension(:),pointer,save :: emode + + +end module module_gcrodr + +!------------------------------------------------------------------------------- +subroutine init_gcrodr() + use module_input + use module_gcrodr + use module_vol + use module_action + use module_function_decl + implicit none + integer, save:: count=0 + integer :: i + + if (count==1) return + + DEBUG2S("Start: init_gcrodr") + + allocate(emode(size(action%mtilde))) + m=input%solver_gcrodr_numarstep + defeig=input%solver_gcrodr_numdefvec + do i=1, size(action%mtilde) + emode(i)%initial=.true. + allocate(emode(i)%x(12*volh_tot,defeig)) + allocate(emode(i)%eval(defeig)) + enddo + count=1 + if (my_pe()==0) write(0,*)"GCRODR(", defeig, ",", m, ")" + + DEBUG2S("End: init_gcrodr") +end + +!------------------------------------------------------------------------------- +subroutine gcrodr(x, b, id, iter, res) use module_function_decl use module_check_solution - use module_action use module_cg use module_vol - use module_counter + use module_gcrodr + use module_action implicit none + complex(8),intent(inout):: x(12*volh_tot) + complex(8),intent(in) :: b(12*volh_tot) + integer, intent(in) :: id + integer, intent(out) :: iter + real(8), intent(in) :: res - SPINCOL_OVERINDEXED, intent(inout) :: x - SPINCOL_OVERINDEXED, intent(in) :: b - integer, intent(out) :: iter - integer, intent(in) :: id - DOUBLE, intent(in) :: res + complex(8) :: r(12*volh_tot), v(12*volh_tot,m+1), vtmp(12*volh_tot,defeig+1) + complex(8) :: cc(12*volh_tot,defeig), uu(12*volh_tot,defeig) - SPINCOL_OVERINDEXED :: r, aap - REAL :: ak, bk - DOUBLE :: rtr, paap, bb, dtmp, dtmp1, dtmp2 - integer :: i, niter - character(72) :: msg + integer :: i, j, k, niter, lwork, info + integer, save :: itert=0 + real(8) :: beta, bb, tmp, rtr, rtr_real + complex(8) :: h(m+1,m), g(m+1), yy(m+1),htmp(m+1,m),y(m) + complex(8):: p(m+1,defeig+1), eval(defeig),evec(m,defeig), gg(m,m), ff(m,m) + complex(8):: r_qr(defeig,defeig), qr(m+1,defeig), gtmp(m+1,1), ctmp, ctmp2(defeig) + complex(8)::work(m*2) + lwork=m*2 -! -! needed for checking solution -! - DOUBLE :: norm(3) - integer, save :: headline_check_written = 0 - character(*), parameter :: key_chk = "%cgChk" - character(*), parameter :: fmt_chk_h = "(1x, 2a, a6, 4a20)" - character(*), parameter :: fmt_chk_b = "(1x, a7, i6, 3e20.10, i20)" +#ifdef LAPACK + DEBUG2S("Start: gcrodr") -!------------------------------------------------------------------------------- + if (m<=defeig) call die("GCRODR impossible m<nev") + if (0==defeig) call die("GCRODR inev=0") - TIMING_START(timing_bin_cg) + bb = sc_norm2(b) ; call global_sum_vec(1, bb) + call wdagw(r, x, id) ; iter=1 ; itert=itert+1 + r = b - r + rtr=sc_norm2(r) ; call global_sum_vec(1, rtr) + niter =1 - bb = 0.0_8 - !$omp parallel do reduction(+: bb) private(dtmp) - do i = 1, size_sc_field - dtmp = b(i) - bb = bb + dtmp**2 - enddo - call global_sum_vec(1, bb) - - DEBUG2R("norm(b)= ", sqrt(bb)/2/action%mtilde(id)%kappa) - DEBUG2R("rsd = ", dble(res)**2*bb/(2*action%mtilde(id)%kappa)**2) - - call wdagw(r, x, id) - rtrold = ZERO - !$omp parallel do reduction(+: rtrold) private(dtmp) - do i = 1, size_sc_field - r(i) = b(i) - r(i) - dtmp = r(i) - rtr = rtr + dtmp**2 - enddo - call global_sum_vec(1, rtr) + + if (my_pe()==0 )write(0,*)"GCRODR kappa:", action%mtilde(id)%kappa + if (my_pe()==0 )write(0,*)"GCRODR res:",itert,iter, rtr if (stop_condition(rtr, res, bb)) goto 9999 -!---------------------------------------- - - if (ydefine) then - call wdagw_mult_nsco(id, k, c, u) - call qrdcmp_nsco(k, c, h) ! R => h Q => new - call inv_upper_hessen(k, h) ! h <= h^-1 - call mm_mult_nsco(k, u, h) ! u <= u*h^-1 - call (k, c, x) ! x <= x + U C^+ x - call orthogonalize_sc(k, c, r) ! r <= r - C C^+ r - else - call gmres_m(x, b, r, id, m, rtr) -!! make Pk, line 14 - not yet - call km_mult_nsco(k, m, u, v, p) !tilde{Y}_k = V_m P_k, line 15. - -!! QR dcmp of underbar{H}_m P_k, line 16 - call mm_mult(hp, uh ,p, m+1, k, m) - call qrdcmp(hp, q, invr, m+1, k) - - call mm_mult_nsco(k, m+1, c, v, q)! C_k = V_{m+1} Q, line 17 - call mm_mult_nsco(k, u, invr) !U_k = tilde{Y}_k R^{-1}, line 18 - endif +if (.not. emode(id)%initial) then + ! when rtr /=rtr_real, this does not work + !if (emode(id)%fresh) then + ! do i=1,defeig + ! uu(:,i)=emode(id)%x(:,i) + ! cc(:,i)=emode(id)%ax(:,i) + ! enddo + !else + do i=1,defeig + call wdagw(cc(1,i), emode(id)%x(1,i), id) ; iter=iter+1 ; itert=itert+1 + enddo +!! for check QR +! do i=1,defeig +! call sc_copy(vtmp(1,i), cc(1,i)) +! enddo + + call gram_schmidt2(cc, r_qr, 12*volh_tot, 12*volh, defeig, .true.) + +!! check QR +! do i=1,defeig +! vtmp(1:12*volh,defeig+1)=ZERO +! do j=1,defeig +! if (r_qr(j,i)/=ZERO)then +! vtmp(1:12*volh,defeig+1)=vtmp(1:12*volh,defeig+1)+ cc(1:12*volh,j) * r_qr(j,i) +! endif +! enddo +! vtmp(1:12*volh,defeig+1)=vtmp(1:12*volh,defeig+1) - vtmp(1:12*volh,i) +! rtr=sc_norm2(vtmp(1,defeig+1)); call global_sum_vec(1, rtr) +! if (my_pe()==0)write(0,*)"QR res: ",i,rtr +! enddo + + + + call ZTRTRI( "U", "N", defeig, r_qr, defeig, INFO ) !! R^-1 + + uu=ZERO + do i=1,defeig + do j=1,defeig + if (r_qr(j,i)/=ZERO)then + uu(1:12*volh,i)=uu(1:12*volh,i)+ emode(id)%x(1:12*volh,j) * r_qr(j,i) + endif + enddo + enddo + !endif + + do i=1,defeig + ctmp2(i)=sc_cdotc(cc(1,i), r) + enddo + call global_sum_vec(2*defeig, ctmp2) + + do i=1,defeig + x(1:12*volh)=x(1:12*volh)+uu(1:12*volh,i)*ctmp2(i) + r(1:12*volh)=r(1:12*volh)-cc(1:12*volh,i)*ctmp2(i) + enddo + rtr=sc_norm2(r) ; call global_sum_vec(1, rtr) + +!! do i=1,defeig +!! call sc_copy(emode(id)%x(1,i), uu(1,i)) ! \til{Y} +!! enddo +! call wdagw(vtmp(1,1), x, id) ; iter = iter +1 +! vtmp(:,1)=vtmp(:,1)-b +! rtr_real=sc_norm2(vtmp(1,1)) ; call global_sum_vec(1, rtr_real) +!! if (max(rtr_real, rtr) > 1.01_8* min(rtr_real,rtr) ) then +! write(0,*)rtr,rtr_real +!! stop +!! endif + +else + + v(1:12*volh,1)=r(1:12*volh) + call normalize_sc_half(v(1,1), beta) + h=ZERO - do niter = 1, cg_para%maxiter - if (stop_condition(rtr, res, bb)) goto 9999 - h=ZERO - do i = 1, k - v(i)%sco = u(i)%sco - call normalize_sc(v(i)%sco, dummy) - h(i,i) = ONE/dummy - enddo - v(k+1)%sco = r - call normalize_sc(v(k+1)%sco, dummy) - do j = k+1, m - call wdagw(v(j+1)%sco, v(j)%sco, id) - call orthogonalize_sc(k, c, (v(j+1)%sco) ! v <= (I - C C^+)Av - do i = 1, j - h(i,j) = sc_dot(v(j+1)%sco, v(i)%sco) - h(i,j) = global_sum(h(i,j)) - call sc_axpy(v(j+1)%sco, v(i)%sco, -h(i,j)) - enddo - call normalize_sc(v(j+1)%sco, h(j+1,j)) + do j = 1, m !!!!! gmres(m) + call wdagw(v(1,j+1), v(1,j), id) ; iter = iter +1 ; itert=itert+1 + do i = 1, j + h(i,j) = sc_cdotc(v(1,i), v(1,j+1)) ; call global_sum_vec(2, h(i,j)) + v(1:12*volh,j+1) = v(1:12*volh,j+1) - h(i,j) * v(1:12*volh,i) enddo - do j = k+1, m - call wdagw(aap, v(j)%sco, id) - do i = 1, k - xx=sc_cdotc(c(i)%sco, aap) - call global_sum_vec(2, xx) - h(i,j) = xx - enddo - enddo - - htmp = h - !!!!!!!!!!!!!!!!!!!!!!! koko kara + call normalize_sc_half(v(1,j+1), tmp) + h(j+1,j)=tmp enddo + g=ZERO; g(1)=beta + beta=h(m+1,m) !!! NEW beta + htmp=h; gtmp(:,1)=g + call zgels("N", m+1, m, 1, htmp, m+1, gtmp, m+1, work,lwork, info) + y(1:m)=gtmp(1:m,1) + do j = 1, m + x(1:12*volh) = x(1:12*volh) + v(1:12*volh,j) * y(j) + enddo + gtmp(:,1)=g + call zgemv("N", m+1, m, (dcmplx(-ONE,ZERO)), h, m+1, y, 1, (dcmplx(ONE,ZERO)), gtmp, 1) + yy(:)=gtmp(:,1) - niter = niter - 1 + r(1:12*volh) = v(1:12*volh,1) * yy(1) + do i = 2, m+1 + r(1:12*volh) = r(1:12*volh) + v(1:12*volh,i) * yy(i) + enddo + rtr=sc_norm2(r) ; call global_sum_vec(1, rtr) - if (cg_para%log /= 2) then - write(msg, *) "cg(): no convergence; rtr = ", rtr - call die(msg) - endif +! call wdagw(vtmp(1,1), x, id) +! vtmp(:,1)=vtmp(:,1)-b +! rtr_real=sc_norm2(vtmp(1,1)) ; call global_sum_vec(1, rtr_real) +! write(0,*)rtr,rtr_real -9999 continue + call zhritz(eval, evec, h(1:m,1:m), beta, m, defeig) + p(1:m,1:defeig)=evec(1:m,1:defeig) - call update_cg_stat(gcrodr_stat, niter, 0) - iter = niter + vtmp=ZERO + do i=1,defeig + do j=1,m + vtmp(:,i) = vtmp(:,i) + v(:,j) * p(j,i) + enddo + enddo + do i=1,defeig + call sc_copy(emode(id)%x(1,i),vtmp(1,i)) + enddo - TIMING_STOP(timing_bin_cg) + qr=ZERO + do i=1,m+1 + do j=1,defeig + do k=1, m + qr(i,j)=qr(i,j)+h(i,k)*p(k,j) + enddo + enddo + enddo !!! this is HmPk - if (cg_para%check /= 0) then ! check solution + call zqr(qr,r_qr,m+1,defeig) + call ZTRTRI( "U", "N", defeig, r_qr, defeig, INFO ) !! R^-1 - call check_solution(id, x, b, norm) + cc=ZERO + uu=ZERO + do i=1,defeig + do j=1,m+1 + cc(1:12*volh,i)=cc(1:12*volh,i)+ v(1:12*volh,j) * qr(j,i) + enddo + enddo - if (headline_check_written == 0) then - if (my_pe() == 0) then - write(UREC, fmt_chk_h) & - "T", key_chk, "traj", "rtr", "Rb", "Rx", "iterations" + do i=1,defeig + do j=1,defeig + if (r_qr(j,i)/=ZERO)then + uu(1:12*volh,i)=uu(1:12*volh,i)+ emode(id)%x(1:12*volh,j) * r_qr(j,i) endif - headline_check_written = 1 - endif - - if (my_pe() == 0) then - write(UREC, fmt_chk_b) & - key_chk, counter%traj, rtr, & - norm(1)/norm(2), norm(1)/norm(3), iter - endif + enddo + enddo - endif +! !! check U and C +! do i =1, defeig +! call wdagw(vtmp(1,1), uu(1,i), id) +! vtmp(:,1)=vtmp(:,1)-cc(:,i) +! rtr_real=sc_norm2(vtmp(1,1)) ; call global_sum_vec(1, rtr_real) +! if (my_pe()==0)write(0,*)"|Au-c|",i,rtr_real +! enddo + +endif + +if (my_pe()==0 )write(0,*)"GCRODR res:",itert, iter, rtr +if (stop_condition(rtr, res, bb)) goto 9999 + +do niter = 1, cg_para%maxiter + h=ZERO + do i = 1, defeig + call normalize_sc_half(uu(1,i), tmp) + h(i,i)=ONE/tmp + v(1:12*volh,i)=uu(1:12*volh,i) + enddo + + DEBUG2S("gcrodr 101") + + j=defeig + v(1:12*volh,j+1) = r(1:12*volh) + call normalize_sc_half(v(1,j+1), tmp) + do j = defeig+1, m + call wdagw(vtmp(1,1), v(1,j), id) ; iter = iter +1 ; itert=itert+1 + do i = 1, defeig + h(i,j) = sc_cdotc(cc(1,i), vtmp(1,1)) ; call global_sum_vec(2, h(i,j)) + enddo + call projecton_imvv(v(1,j+1), vtmp(1,1), cc, 12*volh_tot, 12*volh, defeig, .true.) + do i = 1, defeig + ctmp = sc_cdotc(cc(1,i), v(1,j+1)) ; call global_sum_vec(2, ctmp) + v(1:12*volh,j+1) = v(1:12*volh,j+1) - ctmp * cc(1:12*volh,i) + enddo + do i = defeig+1, j + h(i,j) = sc_cdotc(v(1,i), v(1,j+1)) ; call global_sum_vec(2, h(i,j)) + v(1:12*volh,j+1) = v(1:12*volh,j+1) - h(i,j) * v(1:12*volh,i) + enddo + call normalize_sc_half(v(1,j+1), tmp) + h(j+1,j)=tmp + enddo -end + DEBUG2S("gcrodr 102") -!------------------------------------------------------------------------------- -subroutine qrdcmp(input, q, invr, n, k) - implicit none - COMPLEX, intent(in) :: input(n,k) - COMPLEX, intent(out) :: q(n,k), invr(k,k) - integer, intent(in) :: n, k + do i = 1, defeig + g(i)=sc_cdotc(cc(1,i), r) + enddo + do i = defeig+1, m+1 + g(i)=sc_cdotc(v(1,i), r) + enddo + call global_sum_vec(2*(m+1), g) -end + DEBUG2S("gcrodr 103") -!------------------------------------------------------------------------------- -subroutine mv_mult(out, in1, in2, c, r) - implicit none + htmp=h; gtmp(:,1)=g + call zgels("N", m+1, m, 1, htmp, m+1, gtmp, m+1, work,lwork, info) + y(1:m)=gtmp(1:m,1) - COMPLEX, intent(out) :: out(c) - COMPLEX, intent(out) :: in1(c,r), in2(r) - integer, intent(in) :: c, r - integer :: i, j, k + DEBUG2S("gcrodr 104") - !$omp parallel do - do i = 1, c - out(i) = in1(i,1) * in2(1) + do j = 1, m + x(1:12*volh) = x(1:12*volh) + v(1:12*volh,j) * y(j) enddo - do j = 2, r - !$omp parallel do - do i = 1, c - out(i) = out(i) + in1(i,j) * in2(j) + + DEBUG2S("gcrodr 105") + + yy=ZERO + do i = 1, m+1 + do j = 1, m + yy(i) = yy(i) + h(i,j) * y(j) enddo enddo -end + DEBUG2S("gcrodr 106") -!------------------------------------------------------------------------------- -subroutine mm_mult(out, in1, in2, c, r, m) - implicit none + do i = 1, defeig + r(1:12*volh) = r(1:12*volh) - cc(1:12*volh,i) * yy(i) + enddo + do i = defeig+1, m+1 + r(1:12*volh) = r(1:12*volh) - v(1:12*volh,i) * yy(i) + enddo + rtr=sc_norm2(r) ; call global_sum_vec(1, rtr) + + DEBUG2S("gcrodr 107") + + call wdagw(vtmp(1,1), x, id) ; iter = iter +1 ; itert=itert+1 + vtmp(:,1)=vtmp(:,1)-b + rtr_real=sc_norm2(vtmp(1,1)) ; call global_sum_vec(1, rtr_real) + if (max(rtr_real, rtr) > 1.01_8* min(rtr_real,rtr) ) then + if (my_pe()==0)write(0,*)"GCRODR inconsistent res!!!" + if (my_pe()==0)write(0,*)"GCRODR rtr, rtt_real",rtr,rtr_real + if (stop_condition(rtr_real, res, bb)) then + if (my_pe()==0)write(0,*) & + "GCRODR rtt_real satisfies stopping condition, finilize without error" + goto 9999 + endif + stop + endif - COMPLEX, intent(out) :: out(c, r) - COMPLEX, intent(out) :: in1(c,m), in2(m,r) - integer, intent(in) :: c, r, m - integer :: i, j, k + DEBUG2S("gcrodr 108") + +htmp=ZERO +do i=1,defeig + do j=1,m + htmp(i,j)=sc_cdotc(cc(1,i),v(1,j)) + enddo +enddo +do i=defeig+1,m+1 + do j=1,m + htmp(i,j)=sc_cdotc(v(1,i),v(1,j)) + enddo +enddo +call global_sum_vec(2*m*(m+1), htmp) + + DEBUG2S("gcrodr 109") + + +ff=ZERO +do i=1,m +do j=1,m +do k=1,m+1 + ff(i,j)=ff(i,j)+conjg(h(k,i))*htmp(k,j) +enddo +enddo +enddo + + DEBUG2S("gcrodr 110") + + +gg=ZERO +do i=1,m +do j=1,m +do k=1,m+1 + gg(i,j)=gg(i,j)+conjg(h(k,i))*h(k,j) +enddo +enddo +enddo + + DEBUG2S("gcrodr 111") + + call zgeneigen(eval, evec, gg, ff, m, defeig) + p(1:m,1:defeig)=evec(1:m,1:defeig) + + if (my_pe()==0 .and. mod(niter,10)==0) then + do j=1,defeig + write(0,*)"GCRODR eval",itert, iter,j,eval(j) + enddo + endif - do j = 1, r - !$omp parallel do - do i = 1, c - out(i,j) = in1(i,1) * in2(1,j) + do i=1,defeig + call sc_zero(emode(id)%x(1,i)) + do j=1,m + emode(id)%x(1:12*volh,i) = emode(id)%x(1:12*volh,i) + v(1:12*volh,j) * p(j,i) enddo enddo - do k = 2, m - do j = 1, r - !$omp parallel do - do i = 1, c - out(i,j) = out(i,j) + in1(i,k) * in2(k,j) + qr=ZERO + do i=1,m+1 + do j=1,defeig + do k=1, m + qr(i,j)=qr(i,j)+h(i,k)*p(k,j) enddo enddo - enddo + enddo !!! this is HmPk -end + DEBUG2S("gcrodr 114") -!------------------------------------------------------------------------------- -subroutine qrdcmp_nsco(n, v, h) - use typedef - use module_function_decl - implicit none - type(sco_field),intent(inout) :: v(n) - REAL, intent(out) :: h(n,n) - integer, intent(in) :: n - integer :: i, j + call zqr(qr,r_qr,m+1,defeig) + call ZTRTRI( "U", "N", defeig, r_qr, defeig, INFO ) !! R^-1 - h=ZERO - do j = 1, n - do j = 1, j-1 - h(i,j) = sc_dot(v(i)%sco, v(j)%sco) - h(i,j) = global_sum(h(i,j)) - call sc_axpy(v(i)%sco, v(j)%sco, -h(i,j)) + DEBUG2S("gcrodr 115") + + do i=1,defeig + uu(1:12*volh,i)=ZERO + do j=1,defeig + if (r_qr(j,i)/=ZERO)then + uu(1:12*volh,i)=uu(1:12*volh,i)+ emode(id)%x(1:12*volh,j) * r_qr(j,i) + endif enddo - call normalize_sc(v(i)%sco, h(j,j)) enddo -end + DEBUG2S("gcrodr 116") -!------------------------------------------------------------------------------- -subroutine wdagw_mult_nsco(id, n, out, in) - use typedef - implicit none + vtmp=ZERO + do i=1,defeig + do j=1,defeig + vtmp(:,i)=vtmp(:,i) + cc(:,j) * qr(j,i) + enddo + do j=defeig+1,m+1 + vtmp(:,i)=vtmp(:,i) + v(:,j) * qr(j,i) + enddo + enddo + do i=1,defeig + cc(:,i)= vtmp(:,i) + enddo + + DEBUG2S("gcrodr 117") + + if (my_pe()==0 .and. mod(niter,1+ int(50/m) )==0 )write(0,*)"GCRODR res:",itert, iter, rtr + if (stop_condition(rtr, res, bb)) goto 9999 - type(sco_field),intent(out) :: out(n) - type(sco_field),intent(in) :: in(n) - integer, intent(in) :: id, n - integer :: i - do i = 1, n - call wdagw(out(i)%sco, in(i)%sco, id) +enddo + + DEBUG2S("gcrodr 201") + + niter = niter - 1 + if (cg_para%log /= 2) then + write(0, *) "gcrodr(): no convergence; rtr = ", rtr ; stop + endif + 9999 continue + + if (my_pe()==0 )write(0,*)"GCRODR res:",itert, iter, rtr + DEBUG2S("gcrodr 300") + +! must be changed + do i=1,defeig + call sc_copy(emode(id)%x(1,i), uu(1,i)) ! \til{Y} enddo + emode(id)%fresh=.true. + emode(id)%initial=.false. -end -!=============================================================================== + DEBUG2S("gcrodr 301") + + call update_cg_stat(cg_stat, iter, 0) !! must be changed + +#else + call die("gcrodr needs LAPCK") +#endif + + DEBUG2S("End: init_gcrodr") +end diff --git a/src/fermi/solver/gcrodr_dd.F90 b/src/fermi/solver/gcrodr_dd.F90 index dfa5ac27e31d4c3c47b04d470f25f73445a69396..3a281b387e17813dc447bc40d3652fea57a28bcc 100644 --- a/src/fermi/solver/gcrodr_dd.F90 +++ b/src/fermi/solver/gcrodr_dd.F90 @@ -202,7 +202,7 @@ do niter = 1, cg_para%maxiter do i = 1, defeig h(i,j) = ddsc_cdotc(cc(1,i), vtmp(1,1)) enddo - call projecton_imvv(v(1,j+1), vtmp(1,1), cc, 12*ld%lat%volh, defeig) + call projecton_imvv(v(1,j+1), vtmp(1,1), cc, 12*ld%lat%volh, 12*ld%lat%volh, defeig, .false.) do i = 1, defeig ctmp = ddsc_cdotc(cc(1,i), v(1,j+1)) v(:,j+1) = v(:,j+1) - ctmp * cc(:,i) @@ -373,20 +373,22 @@ enddo end !------------------------------------------------------------------------------- -subroutine projecton_imvv(out, in, v, len, k) ! out=(I - V_k V_k^H) in +subroutine projecton_imvv(out, in, v, lenall, len, k, global) ! out=(I - V_k V_k^H) in implicit none - complex(8), dimension(len) :: in, out - complex(8), dimension(len,k):: v - integer :: i, j, k, len + complex(8), dimension(lenall) :: in, out + complex(8), dimension(lenall,k):: v + integer :: i, j, k, len, lenall + logical :: global complex(8) :: fac - out(:) = in(:) + out(1:len) = in(1:len) do i = 1, k fac=ZERO do j = 1, len fac = fac + conjg(v(j,i)) * in(j) enddo - out(:) = out(:) - fac * v(:,i) + if (global) call global_sum_vec(2, fac) + out(1:len) = out(1:len) - fac * v(1:len,i) enddo end @@ -404,7 +406,7 @@ subroutine zhritz(eval, evec, h, beta, m, n) ! return 'SM' harmonic ritz pairs complex(8),allocatable :: work(:) integer :: lwork, info, ilo,ihi, ipiv(m), i,j -#ifdef LAPCK +#ifdef LAPACK scale=ONE @@ -529,7 +531,7 @@ subroutine zqr(q, r, m, n) #ifdef LAPACK -!! write(0,*)"zqr: initial A",q +! write(0,*)"zqr: initial A",q allocate(work(10)) !! dummy allocation lwork=-1 @@ -562,15 +564,18 @@ subroutine zqr(q, r, m, n) if (info/=0)write(0,*)"ZUNGQR failed at zqr err",info if (info/=0)call die("ZUNGQR failed at zqr") -!! qr=ZERO -!! do i=1,m -!! do j=1,n -!! do k=1,n -!! qr(i,j)=qr(i,j)+q(i,k)*r(k,j) -!! enddo -!! enddo -!! enddo -!! write(0,*)"zqr: result qr",qr +!! call gram_schmidt(q, r, m, n, .false.) + +! qr=ZERO +! do i=1,m +! do j=1,n +! do k=1,n +! qr(i,j)=qr(i,j)+q(i,k)*r(k,j) +! enddo +! enddo +! enddo +! write(0,*)"zqr: result qr",qr + deallocate(work) diff --git a/src/fermi/solver/gmres.F90 b/src/fermi/solver/gmres.F90 index c9a4858e73c5acc87e7aa2e06ddb367f1c8cadd0..197b2d0498549c8f3170a858cbacf0736d5aef0b 100644 --- a/src/fermi/solver/gmres.F90 +++ b/src/fermi/solver/gmres.F90 @@ -420,7 +420,7 @@ subroutine gmrespj_dd(matrix, x, b, id, ip, iter, res, m) real(8), external :: ddsc_norm2 integer :: i, j, k, niter, lwork, info, mdm real(8) :: vv, beta, inv, bb, tmp, rtr, ttt(m), rtr_real - complex(8) :: h(m+1,m), g(m+1), yy(m+1), htmp(m+1,m),y(m) + complex(8) :: h(m+1,m), g(m+1), yy(m+1), htmp(m+1,m),y(m), r_dummy(defeig,defeig) complex(8) :: eval(defeig),evec(m,defeig), gtmp(m+1,1), gg(m,m),ff(m,m) complex(8)::work(80) lwork=80 @@ -541,7 +541,7 @@ enddo enddo - call gram_schmidt(vtmp, 12*ld%lat%volh, defeig, .false.) + call gram_schmidt(vtmp, r_dummy, 12*ld%lat%volh, defeig, .false.) do i=1,defeig v(:,i)=vtmp(:,i) enddo @@ -596,7 +596,7 @@ subroutine gmresdr_dd(matrix, x, b, id, ip, iter, res, m) real(8), external :: ddsc_norm2 integer :: i, j, k, niter, lwork,info, mdm real(8) :: beta, inv, bb, tmp, rtr, rtr_real - complex(8) :: h(m+1,m), g(m+1), yy(m+1),htmp(m+1,m),y(m), rr(defeig+1,defeig+1) + complex(8) :: h(m+1,m), g(m+1), yy(m+1),htmp(m+1,m),y(m), rr(defeig+1,defeig+1), r_dummy(defeig,defeig) complex(8) :: p(m+1,defeig+1), eval(defeig),evec(m,defeig), gtmp(m+1,1) complex(8)::work(80) lwork=80 @@ -701,13 +701,10 @@ do niter = 1, cg_para%maxiter p(1:m,1:defeig)=evec(1:m,1:defeig) p(m+1,1:defeig)=dcmplx(ZERO,ZERO) - call gram_schmidt(p, m+1, defeig, .false.) + call gram_schmidt(p, r_dummy, m+1, defeig, .false.) p(:,defeig+1)= yy(:) call gram_schmidt_last(p, m+1, defeig+1, .false.) -!! call zqr(p, rr, m+1, defeig+1) -!! call gram_schmidt(p, m+1, defeig+1, .false.) - ! ! calculation of new H and V @@ -738,7 +735,6 @@ do niter = 1, cg_para%maxiter enddo call gram_schmidt_last(vtmp, 12*ld%lat%volh, defeig+1, .false.) -!! call gram_schmidt(vtmp, 12*ld%lat%volh, defeig+1, .false.) do i=1,defeig+1 v(:,i)=vtmp(:,i) diff --git a/src/fermi/solver/mre.F90 b/src/fermi/solver/mre.F90 index e3cceb5b6b4af310688ba4b8a7978b8d869cec8e..6f7eebce794d0eb8619ae949aae1a308c443446a 100644 --- a/src/fermi/solver/mre.F90 +++ b/src/fermi/solver/mre.F90 @@ -26,6 +26,13 @@ !------------------------------------------------------------------------------- # include "defs.h" +#ifdef PRECISION_R16 +# define vec_norm2_c8 vec_norm2_c16 +# define vec_cdotc_c8 vec_cdotc_c16 +# define vec_dot_c8 vec_dot_c16 +#endif + + !------------------------------------------------------------------------------- subroutine mre_put(basis, sc_field, reset) ! add a solution @@ -66,86 +73,86 @@ subroutine mre_put(basis, sc_field, reset) ! add a solution end !------------------------------------------------------------------------------- -subroutine mre_get(basis, matrix_mult, trial, phi, para, conf) - - ! get trial solution - - use typedef_hmc - use module_function_decl - use module_mre - use module_vol - implicit none - - type(type_mre), intent(inout) :: basis - external :: matrix_mult - SPINCOL_FIELD, intent(out) :: trial - SPINCOL_FIELD, intent(in) :: phi - type(hmc_para), intent(in) :: para - type(hmc_conf), intent(in) :: conf - - type(type_mre), save :: mv ! "Matrix * v" - COMPLEX, target :: g(mre_n_vec, mre_n_vec + 1) - COMPLEX, pointer :: b(:) - integer :: size_g - integer :: i - integer :: j - integer :: s - integer :: c - integer :: rest - - if (mre_n_vec == 0 .or. .not. associated(basis%vec) .or. basis%rank == 0) then - call sc_copy(trial, phi) - return - endif - - if (basis%rank == 1) then - call sc_copy(trial, basis%vec(1)%sc) - return - endif - - size_g = mre_n_vec * (mre_n_vec + 1) * SIZE_COMPLEX - - b => g(:, mre_n_vec + 1) ! storage arrangement for global sum - ! => one global sum for everything - - call mre_allocate(mv) - call mre_gram_schmidt(basis) - - do i = 1, basis%rank - b(i) = sc_cdotc(basis%vec(i)%sc, phi) - call matrix_mult(mv%vec(i)%sc, basis%vec(i)%sc, para, conf) - enddo - - do i = 1, basis%rank - g(i, i) = sc_norm2(mv%vec(i)%sc) - do j = i + 1, basis%rank - g(i, j) = sc_cdotc(mv%vec(i)%sc, mv%vec(j)%sc) - g(j, i) = conjg(g(i, j)) - enddo - enddo - - call global_sum_vec(size_g, g) - - call mre_gauss_jordan(g, b, basis%rank, mre_n_vec) - - ! calculation of "trial" with doubled data re-use: - - call sc_cax2(trial, basis%vec(1)%sc, b(1), basis%vec(2)%sc, b(2)) - - rest = mod(basis%rank, 2) - - do j = 3, basis%rank - rest, 2 - call sc_caxpy2(trial, basis%vec(j)%sc, b(j), & - basis%vec(j+1)%sc, b(j+1)) - enddo - - if (rest == 1) then - j = basis%rank - call sc_caxpy(trial, basis%vec(j)%sc, b(j)) - endif - -end - +!!subroutine mre_get(basis, matrix_mult, trial, phi, para, conf) +!! +!! ! get trial solution +!! +!! use typedef_hmc +!! use module_function_decl +!! use module_mre +!! use module_vol +!! implicit none +!! +!! type(type_mre), intent(inout) :: basis +!! external :: matrix_mult +!! SPINCOL_FIELD, intent(out) :: trial +!! SPINCOL_FIELD, intent(in) :: phi +!! type(hmc_para), intent(in) :: para +!! type(hmc_conf), intent(in) :: conf +!! +!! type(type_mre), save :: mv ! "Matrix * v" +!! COMPLEX, target :: g(mre_n_vec, mre_n_vec + 1) +!! COMPLEX, pointer :: b(:) +!! integer :: size_g +!! integer :: i +!! integer :: j +!! integer :: s +!! integer :: c +!! integer :: rest +!! +!! if (mre_n_vec == 0 .or. .not. associated(basis%vec) .or. basis%rank == 0) then +!! call sc_copy(trial, phi) +!! return +!! endif +!! +!! if (basis%rank == 1) then +!! call sc_copy(trial, basis%vec(1)%sc) +!! return +!! endif +!! +!! size_g = mre_n_vec * (mre_n_vec + 1) * SIZE_COMPLEX +!! +!! b => g(:, mre_n_vec + 1) ! storage arrangement for global sum +!! ! => one global sum for everything +!! +!! call mre_allocate(mv) +!! call mre_gram_schmidt(basis) +!! +!! do i = 1, basis%rank +!! b(i) = sc_cdotc(basis%vec(i)%sc, phi) +!! call matrix_mult(mv%vec(i)%sc, basis%vec(i)%sc, para, conf) +!! enddo +!! +!! do i = 1, basis%rank +!! g(i, i) = sc_norm2(mv%vec(i)%sc) +!! do j = i + 1, basis%rank +!! g(i, j) = sc_cdotc(mv%vec(i)%sc, mv%vec(j)%sc) +!! g(j, i) = conjg(g(i, j)) +!! enddo +!! enddo +!! +!! call global_sum_vec(size_g, g) +!! +!! call mre_gauss_jordan(g, b, basis%rank, mre_n_vec) +!! +!! ! calculation of "trial" with doubled data re-use: +!! +!! call sc_cax2(trial, basis%vec(1)%sc, b(1), basis%vec(2)%sc, b(2)) +!! +!! rest = mod(basis%rank, 2) +!! +!! do j = 3, basis%rank - rest, 2 +!! call sc_caxpy2(trial, basis%vec(j)%sc, b(j), & +!! basis%vec(j+1)%sc, b(j+1)) +!! enddo +!! +!! if (rest == 1) then +!! j = basis%rank +!! call sc_caxpy(trial, basis%vec(j)%sc, b(j)) +!! endif +!! +!!end +!! !------------------------------------------------------------------------------- subroutine mre_allocate(basis) @@ -298,9 +305,9 @@ subroutine mre2_get(matrix, basis, trial, phi, id, ip) implicit none type(type_mre2), intent(inout) :: basis - complex(8), intent(out) :: trial(:) - complex(8),target,intent(in) :: phi(:) - complex(8),pointer :: tmp(:) + COMPLEX, intent(out) :: trial(:) + COMPLEX,target,intent(in) :: phi(:) + COMPLEX,pointer :: tmp(:) integer, intent(in) :: id integer,optional, intent(in) :: ip external :: matrix @@ -367,17 +374,17 @@ subroutine mre2_get(matrix, basis, trial, phi, id, ip) end !------------------------------------------------------------------------------- -! for complex(8) +! for complex(RKIND) !------------------------------------------------------------------------------- subroutine mre2_put(basis, field, reset, vec_size) ! add a solution use module_mre2 implicit none type(type_mre2), intent(inout) :: basis - integer, intent(in) :: reset, vec_size - complex(8), intent(in) :: field(vec_size) - complex(8),pointer :: tmp(:) - integer :: i + integer, intent(in) :: reset, vec_size + COMPLEX, intent(in) :: field(vec_size) + COMPLEX,pointer :: tmp(:) + integer :: i if (mre2_n_vec == 0) return call mre2_allocate(basis, vec_size) diff --git a/src/fermi/solver/multi_shift_cg.F90 b/src/fermi/solver/multi_shift_cg.F90 index 24a0099a2c11e7609a0c5431ccd7d4fa265dd277..6b096c1bcf29d01dc1ef76196f470629866a8911 100644 --- a/src/fermi/solver/multi_shift_cg.F90 +++ b/src/fermi/solver/multi_shift_cg.F90 @@ -36,13 +36,13 @@ subroutine multi_shift_cg(matrix, id, n, shift_switch, betabar, b, iterations, n integer, intent(out) :: iterations, niter_shift(n) integer, intent(in) :: shift_switch(n), n, id REAL, intent(in) :: betabar(n) - REAL, intent(in) :: res + REAL, intent(in) :: res(n) external :: matrix REAL, allocatable ::r(:),p(:),aap(:) REAL :: alpha, alpha_old, beta, beta_new, rtr, rtrold, paap, bb REAL,dimension(n) :: sxi_old,sxi,sxi_new,salpha,salpha_old,sbeta, sbeta_new - integer :: i,j, niter, n_min, n_con(n), niter_sub , ierr + integer :: i,j, niter, n_min, n_con(n), niter_sub , ierr, ncon character(72) :: msg @@ -105,18 +105,24 @@ niter_sub=0 call sc_axpy(sco(1,j)%sco(1), sco(2,j)%sco(1), -salpha(j)) niter_sub = niter_sub + 1 - if (stop_condition(sxi_new(j)*sxi_new(j)*rtr, res, bb)) niter_shift(j)= niter - if (stop_condition(sxi_new(j)*sxi_new(j)*rtr, res, bb)) n_con(j)=1 -!! if ( sxi_new(j)*sxi_new(j)*rtr <= res ) niter_shift(j)= niter -!! if ( sxi_new(j)*sxi_new(j)*rtr <= res ) n_con(j)=1 + if (stop_condition(sxi_new(j)*sxi_new(j)*rtr, res(j), bb)) niter_shift(j)= niter + if (stop_condition(sxi_new(j)*sxi_new(j)*rtr, res(j), bb)) n_con(j)=1 +!! if ( sxi_new(j)*sxi_new(j)*rtr <= res(j) ) niter_shift(j)= niter +!! if ( sxi_new(j)*sxi_new(j)*rtr <= res(j) ) n_con(j)=1 endif enddo #ifdef DEBUG2 if(my_pe()==0 .and. mod(niter,100)==0 )write(0,*)niter,"mcg:rtr",sxi_new(n_min)*sxi_new(n_min)*rtr #endif - if (stop_condition(sxi_new(n_min)*sxi_new(n_min)*rtr, res, bb)) goto 9999 -!! if ( sxi_new(n_min)*sxi_new(n_min)*rtr <= res ) goto 9999 + if (stop_condition(sxi_new(n_min)*sxi_new(n_min)*rtr, res(n_min), bb)) then + ncon=0 + do j = n_min, n + ncon=ncon + n_con(j) + enddo + if (ncon == n - n_min +1) goto 9999 + endif +!! if ( sxi_new(n_min)*sxi_new(n_min)*rtr <= res(n_min) ) goto 9999 beta_new = rtr / rtrold rtrold = rtr @@ -192,7 +198,7 @@ subroutine fom_shift(matrix, id, n, shift_switch, betabar, b, iterations, niter_ integer, intent(out):: iterations, niter_shift(n) integer, intent(in) :: shift_switch(n), n, id REAL, intent(in) :: betabar(n) - REAL, intent(in) :: res + REAL, intent(in) :: res(n) external :: matrix integer,parameter :: m = 3 @@ -200,7 +206,7 @@ subroutine fom_shift(matrix, id, n, shift_switch, betabar, b, iterations, niter_ complex(8) :: h1,h2, g1,g2,cs, w(12*volh_tot,m+1) complex(8) :: h(m+1,m), htmp(m+1,m), c(m+1), ctmp(m+1),s(m+1), stmp(m+1),d(m,n) real(8) :: bb, rtr, rho(n), r2, sn, tmp, inv ,fac - integer :: i,j, niter, n_min, n_con(n), ns, scsize, niter_sub + integer :: i,j, niter, n_min, n_con(n), ncon, ns, scsize, niter_sub character(72) :: msg logical :: nsend(n) @@ -271,14 +277,20 @@ do niter=1, cg_para%maxiter call sc_copy(sco(1, ns)%sco(1),x) niter_shift(ns)=niter*m - nsend(ns)=stop_condition(rho(ns)**2, res, bb) + nsend(ns)=stop_condition(rho(ns)**2, res(ns), bb) niter_sub = niter_sub + 1 endif enddo ! end of ns call sc_copy(r,v(1,m+1)) - if (nsend(n_min)) goto 9999 + if (nsend(n_min)) then + ncon=0 + do i = n_min, n + if (nsend(i)) ncon=ncon + 1 + enddo + if (ncon == n - n_min +1) goto 9999 + endif enddo 9999 iterations = niter @@ -313,7 +325,7 @@ subroutine gmres_shift(matrix, id, n, shift_switch, betabar, b, iterations, nite integer, intent(out) :: iterations, niter_shift(n) integer, intent(in) :: shift_switch(n), n, id REAL, intent(in) :: betabar(n) - REAL, intent(in) :: res + REAL, intent(in) :: res(n) external :: matrix integer,parameter :: m = 5 @@ -347,15 +359,13 @@ do niter=1, cg_para%maxiter s=ZERO h=ZERO rtr = sc_norm2(r) ; rtr=global_sum(rtr) - if (rtr<res)go to 9999 + if (rtr<res(1))go to 9999 inv=ONE/sqrt(rtr) v(1:scsize,1) = r(1:scsize) * inv c(1)=sc_cdotc(v(1,1), r) ; call global_sum_vec(2,c(1)) do j = 1, m -! tmp=sqrt(res) -! call cg_inner(w(1,j), v(1,j), id, iter4, res) call matrix(v(1,j+1), v(1,j), id) @@ -464,7 +474,7 @@ do niter=1, cg_para%maxiter enddo call sc_copy(sco(1, ns)%sco(1),x) niter_shift(ns)=niter - nsend(ns)=(beta(ns)<res) + nsend(ns)=(beta(ns)<res(ns)) enddo do i=1,m+1 diff --git a/src/fermi/solver/solver.F90 b/src/fermi/solver/solver.F90 index 33fc1cba04af5c5b7e06a8555a4913edb1e87f6b..4ec320d00dfff02db64e973b96950d794fe596f4 100644 --- a/src/fermi/solver/solver.F90 +++ b/src/fermi/solver/solver.F90 @@ -166,9 +166,10 @@ subroutine bcgs(matrix, x, b, m) end !------------------------------------------------------------------------------- -subroutine gram_schmidt(inout, len, n, global) +subroutine gram_schmidt(inout, r, len, n, global) ! and QR dcmp implicit none complex(8), dimension(len,n), intent(inout):: inout + complex(8), dimension(n,n), intent(out):: r integer, intent(in) :: len,n real(8), external :: vecnorm2 complex(8),external :: veccdotc @@ -177,30 +178,82 @@ subroutine gram_schmidt(inout, len, n, global) logical :: global integer :: i, j + r = ZERO +! do i=1, n +! xx=vecnorm2(inout(1,i), len) +! if(global) call global_sum_vec(1, xx) +! xx=ONE/sqrt(xx) +! inout(:,i)=inout(:,i)*xx +! do j=i+1,n +! zz = veccdotc(inout(1,i), inout(1,j), len) +! if(global) call global_sum_vec(2, zz) +! inout(:,j) = inout(:,j) -zz * inout(:,i) +! enddo +! enddo + +!! same as above do i=1, n + do j= 1,i-1 + zz = veccdotc(inout(1,j), inout(1,i), len) + if(global) call global_sum_vec(2, zz) + r(j,i)=zz + inout(:,i) = inout(:,i) -zz * inout(:,j) + enddo xx=vecnorm2(inout(1,i), len) if(global) call global_sum_vec(1, xx) - xx=ONE/sqrt(xx) + r(i,i)=sqrt(xx) + xx=ONE/Re(r(i,i)) inout(:,i)=inout(:,i)*xx - do j=i+1,n + enddo + + xx = ZERO + do i = 1, n + do j = 1, n zz = veccdotc(inout(1,i), inout(1,j), len) if(global) call global_sum_vec(2, zz) - inout(:,j) = inout(:,j) -zz * inout(:,i) + if (i==j)then + xx = xx + ( real(zz) - ONE )**2 + xx = xx + (aimag(zz) )**2 + else + xx = xx + ( real(zz) )**2 + xx = xx + (aimag(zz) )**2 + endif enddo enddo +#ifdef DEBUG2 + write(0,*)"orthonormal check: len=",len,"n=",n,"global:",global,"res=",xx +#endif -!! same as above -!! do i=1, n -!! do j= 1,i-1 -!! zz = veccdotc(inout(1,j), inout(1,i), len) -!! if(global) call global_sum_vec(2, zz) -!! inout(:,i) = inout(:,i) -zz * inout(:,j) -!! enddo -!! xx=vecnorm2(inout(1,i), len) -!! if(global) call global_sum_vec(1, xx) -!! xx=ONE/sqrt(xx) -!! inout(:,i)=inout(:,i)*xx -!! enddo +end + +!------------------------------------------------------------------------------- +subroutine gram_schmidt2(inout, r, lenall, len, n, global) ! and QR dcmp + use module_function_decl + implicit none + complex(8), dimension(lenall,n), intent(inout):: inout + complex(8), dimension(n,n), intent(out):: r + integer, intent(in) :: lenall, len,n + real(8), external :: vecnorm2 + complex(8),external :: veccdotc + real(8) :: xx + complex(8):: zz + logical :: global + integer :: i, j + + r = ZERO + do i=1, n + do j= 1,i-1 + zz = veccdotc(inout(1,j), inout(1,i), len) + if(global) call global_sum_vec(2, zz) + r(j,i)=zz + inout(1:len,i) = inout(1:len,i) -zz * inout(1:len,j) + enddo + xx=vecnorm2(inout(1,i), len) + if(global) call global_sum_vec(1, xx) + r(i,i)=sqrt(xx) + xx=ONE/r(i,i) + inout(1:len,i)=inout(1:len,i)*xx + enddo xx = ZERO do i = 1, n @@ -216,6 +269,9 @@ subroutine gram_schmidt(inout, len, n, global) endif enddo enddo + + if (my_pe()==0) write(0,*)"orthonormal check: len=",len,"n=",n,"global:",global,"res=",xx +!! call stderr2_real("gram_schmidt2:res=",1,xx) #ifdef DEBUG2 write(0,*)"orthonormal check: len=",len,"n=",n,"global:",global,"res=",xx #endif diff --git a/src/fermi/solver/sort.F90 b/src/fermi/solver/sort.F90 index e81ecd1797a8783a44a993f7494093a3e327d8e1..942f4712d2046f9a6c4bdeb8c94940963ec36230 100644 --- a/src/fermi/solver/sort.F90 +++ b/src/fermi/solver/sort.F90 @@ -29,11 +29,11 @@ subroutine sortd(a, idx, n) real(8) :: a(n), atmp integer :: i,j -#ifdef DEBUG2 - do i=1,n - write(0,*)"sortd:",i,a(i) - enddo -#endif +!#ifdef DEBUG2 +! do i=1,n +! write(0,*)"sortd:",i,a(i) +! enddo +!#endif idx=1 do j=2, n @@ -48,11 +48,11 @@ subroutine sortd(a, idx, n) idx(i+1)=j end do -#ifdef DEBUG2 - do i=1,n - write(0,*)"sortd:",idx(i),a(i) - enddo -#endif +!#ifdef DEBUG2 +! do i=1,n +! write(0,*)"sortd:",idx(i),a(i) +! enddo +!#endif end diff --git a/src/fmlib/FM.F90 b/src/fmlib/FM.F90 new file mode 100644 index 0000000000000000000000000000000000000000..c720653df2ed4bf9fcfd2181cd7636499fc40357 --- /dev/null +++ b/src/fmlib/FM.F90 @@ -0,0 +1,36895 @@ + + + +! FM 1.2 David M. Smith 8-17-01 + + +! The routines in this package perform multiple precision arithmetic and +! functions on three kinds of numbers. +! FM routines handle floating-point real multiple precision numbers, +! IM routines handle integer multiple precision numbers, and +! ZM routines handle floating-point complex multiple precision numbers. + + +! 1. INITIALIZING THE PACKAGE + +! The variables that contain values to be shared by the different routines are +! located in module FMVALS in file FMSAVE.f90. Variables that are described +! below for controlling various features of the FM package are found in this +! module. They are initialized to default values assuming 32-bit integers and +! 64-bit double precision representation of the arrays holding multiple +! precision numbers. The base and number of digits to be used are initialized +! to give slightly more than 50 decimal digits. Subroutine FMVARS can be used +! to get a list of these variables and their values. + +! The intent of module FMVALS is to hide the FM internal variables from the +! user's program, so that no name conflicts can occur. Subroutine FMSETVAR can +! be used to change the variables listed below to new values. It is not always +! safe to try to change these variables directly by putting USE FMVALS into the +! calling program and then changing them by hand. Some of the saved constants +! depend upon others, so that changing one variable may cause errors if others +! depending on that one are not also changed. FMSETVAR automatically updates +! any others that depend upon the one being changed. + +! Subroutine FMSET also initializes these variables. It tries to compute the +! best value for each, and it checks several of the values set in FMVALS to see +! that they are reasonable for a given machine. FMSET can also be called to +! set or change the current precision level for the multiple precision numbers. + +! Calling FMSET is optional in version 1.2 of the FM package. In previous +! versions one call was required before any other routine in the package could +! be used. + +! The routine ZMSET from version 1.1 is no longer needed, and the complex +! operations are automatically initialized in FMVALS. It has been left in the +! package for compatibility with version 1.1. + + +! 2. REPRESENTATION OF FM NUMBERS + +! MBASE is the base in which the arithmetic is done. MBASE must be +! bigger than one, and less than or equal to the square root of +! the largest representable integer. For best efficiency MBASE +! should be large, but no more than about 1/4 of the square root +! of the largest representable integer. Input and output +! conversions are much faster when MBASE is a power of ten. + +! NDIG is the number of base MBASE digits that are carried in the +! multiple precision numbers. NDIG must be at least two. The +! upper limit for NDIG is defined in FMVALS and is restricted +! only by the amount of memory available. + +! Sometimes it is useful to dynamically vary NDIG during the program. Routine +! FMEQU should be used to round numbers to lower precision or zero-pad them to +! higher precision when changing NDIG. + +! The default value of MBASE is a large power of ten. FMSET also sets MBASE to +! a large power of ten. For an application where another base is used, such as +! simulating a given machine's base two arithmetic, use subroutine FMSETVAR to +! change MBASE, so that the other internal values depending on MBASE will be +! changed accordingly. + +! There are two representations for a floating point multiple precision number. +! The unpacked representation used by the routines while doing the computations +! is base MBASE and is stored in NDIG+3 words. A packed representation is +! available to store the numbers in the user's program in compressed form. In +! this format, the NDIG (base MBASE) digits of the mantissa are packed two per +! word to conserve storage. Thus the external, packed form of a number +! requires (NDIG+1)/2+3 words. + +! This version uses double precision arrays to hold the numbers. Version 1.0 +! of FM used integer arrays, which are faster on some machines. The package +! can be changed to use integer arrays --- see section 11 on EFFICIENCY below. + +! The unpacked format of a floating multiple precision number is as follows. +! A number MA is kept in an array with MA(1) containing the exponent, and +! MA(2) through MA(NDIG+1) each containing one digit of the mantissa, expressed +! in base MBASE. The array is dimensioned to start at MA(-1), with the +! sign of the number (+1 or -1) held in MA(-1), and the approximate number +! of bits of precision stored in MA(0). This precision value is intended to +! be used by FM functions that need to monitor cancellation error in addition +! and subtraction. The cancellation monitor code is usually disabled for user +! calls, and FM functions only check for cancellation when they must. Tracking +! cancellation causes most routines to run slower, with addition and +! subtraction being affected the most. The exponent is a power of MBASE and +! the implied radix point is immediately before the first digit of the +! mantissa. Every nonzero number is normalized so that the second array +! element (the first digit of the mantissa) is nonzero. + +! In both representations the sign of the number is carried on the second array +! element only. Elements 3,4,... are always nonnegative. The exponent is a +! signed integer and may be as large in magnitude as MXEXP. + +! For MBASE = 10,000 and NDIG = 4, if array MA holds the number -pi, it would +! have these representations: +! Word 1 2 3 4 5 + +! Unpacked: 1 3 1415 9265 3590 +! Packed: 1 31415 92653590 + +! In both formats MA(0) would be 42, indicating that the mantissa has about 42 +! bits of precision, and MA(-1) = -1 since the number is negative. + +! Because of normalization in a large base, the equivalent number of base 10 +! significant digits for an FM number may be as small as +! LOG10(MBASE)*(NDIG-1) + 1. + +! The integer routines use the FM format to represent numbers, without the +! number of digits (NDIG) being fixed. Integers in IM format are essentially +! variable precision, using the minimum number of words to represent each +! value. + +! For programs using both FM and IM numbers, FM routines should not be called +! with IM numbers, and IM routines should not be called with FM numbers, since +! the implied value of NDIG used for an IM number may not match the explicit +! NDIG expected by an FM routine. Use the conversion routines IMFM2I and +! IMI2FM to change between the FM and IM formats. + +! The format for complex FM numbers (called ZM numbers below) is very similar +! to that for real FM numbers. Each ZM array holds two FM numbers to represent +! the real and imaginary parts of a complex number. Each ZM array is twice as +! long as a corresponding FM array, with the imaginary part starting at the +! midpoint of the array. As with FM, there are packed and unpacked formats for +! the numbers. + + +! 3. INPUT/OUTPUT ROUTINES + +! All versions of the input routines perform free-format conversion from +! characters to FM numbers. + +! a. Conversion to or from a character array + +! FMINP converts from a character*1 array to an FM number. + +! FMOUT converts an FM number to base 10 and formats it for output as an +! array of type character*1. The output is left justified in the +! array, and the format is defined by two variables in module FMVALS, +! so that a separate format definition does not have to be provided +! for each output call. + +! JFORM1 and JFORM2 define a default output format. + +! JFORM1 = 0 E format ( .314159M+6 ) +! = 1 1PE format ( 3.14159M+5 ) +! = 2 F format ( 314159.000 ) + +! JFORM2 is the number of significant digits to display (if JFORM1 = +! 0 or 1). If JFORM2 = 0 then a default number of digits is chosen. +! The default is roughly the full precision of the number. +! JFORM2 is the number of digits after the decimal point (if JFORM1 = 2). +! See the FMOUT documentation for more details. + +! b. Conversion to or from a character string + +! FMST2M converts from a character string to an FM number. + +! FMFORM converts an FM number to a character string according to a format +! provided in each call. The format description is more like that of +! a Fortran FORMAT statement, and integer or fixed-point output is +! right justified. + +! c. Direct read or write + +! FMPRNT uses FMOUT to print one FM number. + +! FMFPRT uses FMFORM to print one FM number. + +! FMWRIT writes FM numbers for later input using FMREAD. + +! FMREAD reads FM numbers written by FMWRIT. + +! The values given to JFORM1 and JFORM2 can be used to define a default output +! format when FMOUT or FMPRNT are called. The explicit format used in a call +! to FMFORM or FMFPRT overrides the settings of JFORM1 and JFORM2. + +! KW is the unit number to be used for standard output from the package, +! including error and warning messages, and trace output. + +! For multiple precision integers, the corresponding routines IMINP, IMOUT, +! IMST2M, IMFORM, IMPRNT, IMFPRT, IMWRIT, and IMREAD provide similar input and +! output conversions. For output of IM numbers, JFORM1 and JFORM2 are ignored +! and integer format (JFORM1=2, JFORM2=0) is used. + +! For ZM numbers, the corresponding routines ZMINP, ZMOUT, ZMST2M, ZMFORM, +! ZMPRNT, ZMFPRT, ZMWRIT, and ZMREAD provide similar input and output +! conversions. + +! For the output format of ZM numbers, JFORM1 and JFORM2 determine the default +! format for the individual parts of a complex number as with FM numbers. + +! JFORMZ determines the combined output format of the real and +! imaginary parts. + +! JFORMZ = 1 normal setting : 1.23 - 4.56 i +! = 2 use capital I : 1.23 - 4.56 I +! = 3 parenthesis format: ( 1.23 , -4.56 ) + +! JPRNTZ controls whether to print real and imaginary parts +! on one line whenever possible. + +! JPRNTZ = 1 print both parts as a single string : +! 1.23456789M+321 - 9.87654321M-123 i +! = 2 print on separate lines without the 'i' : +! 1.23456789M+321 +! -9.87654321M-123 + +! For further description of these routines, see sections 9 and 10 below. + + +! 4. ARITHMETIC TRACING + +! NTRACE and LVLTRC control trace printout from the package. + +! NTRACE = 0 No output except warnings and errors. (Default) +! = 1 The result of each call to one of the routines +! is printed in base 10, using FMOUT. +! = -1 The result of each call to one of the routines +! is printed in internal base MBASE format. +! = 2 The input arguments and result of each call to one +! of the routines is printed in base 10, using FMOUT. +! = -2 The input arguments and result of each call to one +! of the routines is printed in base MBASE format. + +! LVLTRC defines the call level to which the trace is done. LVLTRC = 1 +! means only FM routines called directly by the user are traced, +! LVLTRC = 2 also prints traces for FM routines called by other +! FM routines called directly by the user, etc. Default is 1. + +! In the above description, internal MBASE format means the number is +! printed as it appears in the array --- an exponent followed by NDIG +! base MBASE digits. + + +! 5. ERROR CONDITIONS + +! KFLAG is a condition value returned by the package after each call to one of +! the routines. Negative values indicate conditions for which a warning +! message will be printed unless KWARN = 0. +! Positive values indicate conditions that may be of interest but are not +! errors. No warning message is printed if KFLAG is nonnegative. + +! Subroutine FMFLAG is provided to give the user access to the current +! condition code. For example, to set the user's local variable LFLAG +! to FM's internal KFLAG value: CALL FMFLAG(LFLAG) + +! KFLAG = 0 Normal operation. + +! = 1 One of the operands in FMADD or FMSUB was insignificant with +! respect to the other, so that the result was equal to +! the argument of larger magnitude. +! = 2 In converting an FM number to a one word integer in FMM2I, +! the FM number was not exactly an integer. The next +! integer toward zero was returned. + +! = -1 NDIG was less than 2 or more than NDIGMX. +! = -2 MBASE was less than 2 or more than MXBASE. +! = -3 An exponent was out of range. +! = -4 Invalid input argument(s) to an FM routine. +! UNKNOWN was returned. +! = -5 + or - OVERFLOW was generated as a result from an +! FM routine. +! = -6 + or - UNDERFLOW was generated as a result from an +! FM routine. +! = -7 The input string (array) to FMINP was not legal. +! = -8 The character array was not large enough in an +! input or output routine. +! = -9 Precision could not be raised enough to provide all +! requested guard digits. Increasing the value +! of NDIGMX in file FMSAVE.f90 may fix this. +! UNKNOWN was returned. +! = -10 An FM input argument was too small in magnitude to +! convert to the machine's single or double +! precision in FMM2SP or FMM2DP. Check that the +! definitions of SPMAX and DPMAX in file FMSAVE.f90 +! are correct for the current machine. +! Zero was returned. +! = -11 Array MBERN is not dimensioned large enough for the +! requested number of Bernoulli numbers. +! = -12 Array MJSUMS is not dimensioned large enough for +! the number of coefficients needed in the +! reflection formula in FMPGAM. + +! When a negative KFLAG condition is encountered, the value of KWARN +! determines the action to be taken. + +! KWARN = 0 Execution continues and no message is printed. +! = 1 A warning message is printed and execution continues. +! = 2 A warning message is printed and execution stops. + +! The default setting is KWARN = 1. + +! When an overflow or underflow is generated for an operation in which an input +! argument was already an overflow or underflow, no additional message is +! printed. When an unknown result is generated and an input argument was +! already unknown, no additional message is printed. In these cases the +! negative KFLAG value is still returned. + +! IM routines handle exceptions like OVERFLOW or UNKNOWN in the same way as FM +! routines. When using IMMPY, the product of two large positive integers will +! return +OVERFLOW. The routines IMMPYM and IMPMOD can be used to obtain a +! modular result without overflow. The largest representable IM integer is +! MBASE**NDIGMX - 1. For example, if MBASE is 10**7 and NDIGMX is set to 256, +! integers less than 10**1792 can be used. + + +! 6. OTHER OPTIONS + +! KRAD = 0 All angles in the trigonometric functions and inverse functions +! are measured in degrees. +! = 1 All angles are measured in radians. (Default) + +! KROUND = -1 All results are rounded toward minus infinity. +! = 0 All results are rounded toward zero (chopped). +! = 1 All results are rounded to the nearest FM number, or to the +! value with an even last digit if the result is halfway +! between two FM numbers. (Default) +! = 2 All results are rounded toward plus infinity. + +! In all cases, while a function is being computed all intermediate +! results are rounded to nearest, with only the final result being +! rounded according to KROUND. + +! KRPERF = 0 A smaller number of guard digits used, to give nearly perfect +! rounding. This number is chosen so that the last intermediate +! result should have error less than 0.001 unit in the last place +! of the final rounded result. (Default) +! = 1 Causes more guard digits to be used, to get perfect rounding in +! the mode set by KROUND. This slows execution speed. + +! If a small base is used for the arithmetic, like MBASE = 2, 10, or 16, +! FM assumes that the arithmetic hardware for some machine is being +! simulated, so perfect rounding is done without regard for the value +! of KRPERF. +! If KROUND = 1, then KRPERF = 1 means returned results are no more than +! 0.500 units in the last place from the exact mathematical result, +! versus 0.501 for KRPERF = 0. +! If KROUND is not 1, then KRPERF = 1 means returned results are no more +! than 1.000 units in the last place from the exact mathematical result, +! versus 1.001 for KRPERF = 0. + +! KSWIDE defines the maximum screen width to be used for all unit KW output. +! Default is 80. + +! KESWCH controls the action taken in FMINP and other input routines for +! strings like 'E7' that have no digits before the exponent field. +! This is sometimes a convenient abbreviation when doing interactive +! keyboard input. +! KESWCH = 1 causes 'E7' to translate like '1.0E+7'. (Default) +! KESWCH = 0 causes 'E7' to translate like '0.0E+7' and give 0. + +! CMCHAR defines the exponent letter to be used for FM variable output. +! Default is 'M', as in 1.2345M+678. +! Change it to 'E' for output to be read by a non-FM program. + +! KDEBUG = 0 No error checking is done to see if input arguments are valid +! and parameters like NDIG and MBASE are correct upon entry to +! each routine. (Default) +! = 1 Some error checking is done. (Slower speed) + +! See module FMVALS in file FMSAVE.f90 for additional description of these and +! other variables defining various FM conditions. + + +! 7. ARRAY DIMENSIONS + +! The dimensions of the arrays in the FM package are defined using parameters +! NDIGMX and NBITS. +! NDIGMX is the maximum value the user may set for NDIG. +! NBITS is the number of bits used to represent integers for a given machine. +! See the EFFICIENCY discussion below. + +! The standard version of FM sets NDIGMX = 55, so on a 32-bit machine using +! MBASE = 10**7 the maximum precision is about 7*54+1 = 379 significant +! digits. Previous versions of FM set NDIGMX = 256. Two reasons for making +! this change are: +! (a) Almost all applications using FM use only 30 to 50 significant digits +! for checking double or quadruple precision results, and the larger +! arrays are wasted space. +! (b) Most FM applications use the derived type interface so that the number +! of changes to existing code is minimized. Many compilers implement the +! FM interface by doing copy in / copy out argument passing of the derived +! types. Copying the entire large array when only a small part of it is +! being used causes the derived type arithmetic to be slow compared to +! making direct calls to the subroutines. Setting NDIGMX to be only +! slightly higher than a program actually uses minimizes any performance +! penalty for the derived type arithmetic. + +! To change dimensions so that 10,000 significant digit calculation can be +! done, NDIGMX needs to be at least 10**4/7 + 5 = 1434. This allows for a +! few user guard digits to be defined when the precision is changed using +! CALL FMSET(10000). Changing 'NDIGMX = 55' to 'NDIGMX = 1434' in FMSAVE.f90 +! will define all the new array sizes. + +! If NDIG much greater than 256 is to be used and elementary functions will +! be needed, they will be faster if array MJSUMS is larger. The parameter +! defining the size of MJSUMS is set in the standard version by +! LJSUMS = 8*(LUNPCK+3) +! The 8 means that up to eight concurrent sums can be used by the elementary +! functions. The approximate number needed for best speed is given by +! 0.051*Log(MBASE)*NDIG**0.333 + 1.85 +! For example, with MBASE=10**7 and NDIG=1434 this gives 11. Changing +! 'LJSUMS = 8*(LUNPCK+3)' to 'LJSUMS = 11*(LUNPCK+3)' in FMSAVE.f90 will give +! slightly better speed. + +! FM numbers in packed format have dimension -1:LPACK, and those in unpacked +! format have dimension -1:LUNPCK. + +! The parameters LPACKZ and LUNPKZ define the size of the packed and unpacked +! ZM arrays. The real part starts at the beginning of the array, and the +! imaginary part starts at word KPTIMP for packed format or at word KPTIMU for +! unpacked format. + + +! 8. PORTABILITY + +! In FMSET several variables are set to machine-dependent values, and many of +! the variables initialized in module FMVALS in file FMSAVE.f90 are checked to +! see that they have reasonable values. FMSET will print warning messages on +! unit KW for any of the FMVALS variables that seem to be poorly initialized. + +! If an FM run fails, call FMVARS to get a list of all the FMVALS variables +! printed on unit KW. Setting KDEBUG = 1 at the start may also identify some +! errors. + +! Some compilers object to a function like FMCOMP with side effects such as +! changing KFLAG or other module variables. Blocks of code in FMCOMP and +! IMCOMP that modify these variables are identified so they may be removed or +! commented out to produce a function without side effects. This disables +! trace printing in FMCOMP and IMCOMP, and error codes are not returned in +! KFLAG. See FMCOMP and IMCOMP for further details. + +! In FMBER2 and FMPGAM several constants are used that require the machine's +! integer word size to be at least 32 bits. + + +! 9. LIST OF ROUTINES + +! These are the FM routines that are designed to be called by the user. +! All are subroutines except logical function FMCOMP. +! MA, MB, MC refer to FM format numbers. + +! In Fortran-90 and later versions of the Fortran standard, it is potentially +! unsafe to use the same array more than once in the calling sequence. The +! operation MA = MA + MB should not be written as +! CALL FMADD(MA,MB,MA) +! since the compiler is allowed to pass the three arguments with a copy in / +! copy out mechanism. This means the third argument, containing the result, +! might not be copied out last, and then a later copy out of the original +! input MA could destroy the computed result. + +! One solution is to use a third array and then put the result back in MA: +! CALL FMADD(MA,MB,MC) +! CALL FMEQ(MC,MA) + +! When the first call is doing one of the "fast" operations like addition, +! the extra call to move the result back to MA can cause a noticeable loss in +! efficiency. To avoid this, separate routines are provided for the basic +! arithmetic operations when the result is to be returned in the same array +! as one of the inputs. + +! A routine name with a suffix of "_R1" returns the result in the first +! input array, and a suffix of "_R2" returns the result in the second input +! array. The example above would then be: +! CALL FMADD_R1(MA,MB) + +! These routines each have one less argument than the original version, since +! the output is re-directed to one of the inputs. The result array should +! not be the same as any input array when the original version of the routine +! is used. + +! The routines that can be used this way are listed below. For others, like +! CALL FMEXP(MA,MA) +! the relative cost of doing an extra copy is small. This one should become +! CALL FMEXP(MA,MB) +! CALL FMEQ(MB,MA) + +! If the derived-type interface is used, as in +! TYPE (FM) A,B +! ... +! A = A + B +! there is no problem putting the result back into A, since the interface +! routine creates a temporary scratch array for the result of A + B, allowing +! copy in / copy out to work. + +! For each of these routines there is also a version available for which the +! argument list is the same but all FM numbers are in packed format. The +! routines using packed numbers have the same names except 'FM' is replaced by +! 'FP' at the start of each name. + + +! FMABS(MA,MB) MB = ABS(MA) + +! FMACOS(MA,MB) MB = ACOS(MA) + +! FMADD(MA,MB,MC) MC = MA + MB + +! FMADD_R1(MA,MB) MA = MA + MB + +! FMADD_R2(MA,MB) MB = MA + MB + +! FMADDI(MA,IVAL) MA = MA + IVAL Increment an FM number by a one word +! integer. Note this call does not have +! an "MB" result like FMDIVI and FMMPYI. + +! FMASIN(MA,MB) MB = ASIN(MA) + +! FMATAN(MA,MB) MB = ATAN(MA) + +! FMATN2(MA,MB,MC) MC = ATAN2(MA,MB) + +! FMBIG(MA) MA = Biggest FM number less than overflow. + +! FMCHSH(MA,MB,MC) MB = COSH(MA), MC = SINH(MA). +! Faster than making two separate calls. + +! FMCOMP(MA,LREL,MB) Logical comparison of MA and MB. +! LREL is a CHARACTER*2 value identifying +! which of the six comparisons is to be made. +! Example: IF (FMCOMP(MA,'GE',MB)) ... +! Also can be: IF (FMCOMP(MA,'>=',MB)) ... +! CHARACTER*1 is ok: IF (FMCOMP(MA,'>',MB)) ... + +! FMCONS Set several saved constants that depend on MBASE, +! the base being used. FMCONS should be called +! immediately after changing MBASE. + +! FMCOS(MA,MB) MB = COS(MA) + +! FMCOSH(MA,MB) MB = COSH(MA) + +! FMCSSN(MA,MB,MC) MB = COS(MA), MC = SIN(MA). +! Faster than making two separate calls. + +! FMDIG(NSTACK,KST) Find a set of precisions to use during Newton +! iteration for finding a simple root starting with +! about double precision accuracy. + +! FMDIM(MA,MB,MC) MC = DIM(MA,MB) + +! FMDIV(MA,MB,MC) MC = MA / MB + +! FMDIV_R1(MA,MB) MA = MA / MB + +! FMDIV_R2(MA,MB) MB = MA / MB + +! FMDIVI(MA,IVAL,MB) MB = MA/IVAL IVAL is a one word integer. + +! FMDIVI_R1(MA,IVAL) MA = MA/IVAL + +! FMDP2M(X,MA) MA = X Convert from double precision to FM. + +! FMDPM(X,MA) MA = X Convert from double precision to FM. +! Faster than FMDP2M, but MA agrees with X only +! to D.P. accuracy. See the comments in the +! two routines. + +! FMEQ(MA,MB) MB = MA Both have precision NDIG. +! This is the version to use for standard +! B = A statements. + +! FMEQU(MA,MB,NA,NB) MB = MA Version for changing precision. +! MA has NA digits (i.e., MA was computed +! using NDIG = NA), and MB will be defined +! having NB digits. +! MB is rounded if NB < NA +! MB is zero-padded if NB > NA + +! FMEXP(MA,MB) MB = EXP(MA) + +! FMFLAG(K) K = KFLAG get the value of the FM condition +! flag -- stored in the internal FM +! variable KFLAG in module FMVALS. + +! FMFORM(FORM,MA,STRING) MA is converted to a character string using format +! FORM and returned in STRING. FORM can represent +! I, F, E, or 1PE formats. Example: +! CALL FMFORM('F60.40',MA,STRING) + +! FMFPRT(FORM,MA) Print MA on unit KW using FORM format. + +! FMI2M(IVAL,MA) MA = IVAL Convert from one word integer to FM. + +! FMINP(LINE,MA,LA,LB) MA = LINE Input conversion. +! Convert LINE(LA) through LINE(LB) +! from characters to FM. + +! FMINT(MA,MB) MB = INT(MA) Integer part of MA. + +! FMIPWR(MA,IVAL,MB) MB = MA**IVAL Raise an FM number to a one word +! integer power. + +! FMLG10(MA,MB) MB = LOG10(MA) + +! FMLN(MA,MB) MB = LOG(MA) + +! FMLNI(IVAL,MA) MA = LOG(IVAL) Natural log of a one word integer. + +! FMM2DP(MA,X) X = MA Convert from FM to double precision. + +! FMM2I(MA,IVAL) IVAL = MA Convert from FM to integer. + +! FMM2SP(MA,X) X = MA Convert from FM to single precision. + +! FMMAX(MA,MB,MC) MC = MAX(MA,MB) + +! FMMIN(MA,MB,MC) MC = MIN(MA,MB) + +! FMMOD(MA,MB,MC) MC = MA mod MB + +! FMMPY(MA,MB,MC) MC = MA * MB + +! FMMPY_R1(MA,MB) MA = MA * MB + +! FMMPY_R2(MA,MB) MB = MA * MB + +! FMMPYI(MA,IVAL,MB) MB = MA*IVAL Multiply by a one word integer. + +! FMMPYI_R1(MA,IVAL) MA = MA*IVAL + +! FMNINT(MA,MB) MB = NINT(MA) Nearest FM integer. + +! FMOUT(MA,LINE,LB) LINE = MA Convert from FM to character. +! LINE is a character array of length LB. + +! FMPI(MA) MA = pi + +! FMPRNT(MA) Print MA on unit KW using current format. + +! FMPWR(MA,MB,MC) MC = MA**MB + +! FM_RANDOM_NUMBER(X) X is returned as a double precision random number, +! uniform on (0,1). High-quality, long-period +! generator. +! Note that X is double precision, unlike the similar +! Fortran intrinsic random number routine, which +! returns a single-precision result. +! See the comments in section 10 below and also those +! in the routine for more details. + +! FMREAD(KREAD,MA) MA is returned after reading one (possibly multi-line) +! FM number on unit KREAD. This routine reads +! numbers written by FMWRIT. + +! FMRPWR(MA,K,J,MB) MB = MA**(K/J) Rational power. +! Faster than FMPWR for functions like the cube root. + +! FMSET(NPREC) Set the internal FM variables so that the precision +! is at least NPREC base 10 digits plus three base 10 +! guard digits. + +! FMSETVAR(STRING) Define a new value for one of the internal FM +! variables in module FMVALS that controls one of the +! FM options. STRING has the form variable = value. +! Example: To change the screen width for FM output: +! CALL FMSETVAR(' KSWIDE = 120 ') +! The variables that can be changed and the options +! they control are listed in sections 2 through 6 +! above. Only one variable can be set per call. +! The variable name in STRING must have no embedded +! blanks. The value part of STRING can be in any +! numerical format, except in the case of variable +! CMCHAR, which is character type. To set CMCHAR to +! 'E', don't use any quotes in STRING: +! CALL FMSETVAR(' CMCHAR = E ') + +! FMSIGN(MA,MB,MC) MC = SIGN(MA,MB) Sign transfer. + +! FMSIN(MA,MB) MB = SIN(MA) + +! FMSINH(MA,MB) MB = SINH(MA) + +! FMSP2M(X,MA) MA = X Convert from single precision to FM. + +! FMSQR(MA,MB) MB = MA * MA Faster than FMMPY. + +! FMSQR_R1(MA) MA = MA * MA + +! FMSQRT(MA,MB) MB = SQRT(MA) + +! FMSQRT_R1(MA) MA = SQRT(MA) + +! FMST2M(STRING,MA) MA = STRING +! Convert from character string to FM. +! STRING may be in any numerical format. +! Often more convenient than FMINP, which converts +! an array of CHARACTER*1 values. Example: +! CALL FMST2M('123.4',MA) + +! FMSUB(MA,MB,MC) MC = MA - MB + +! FMSUB_R1(MA,MB) MA = MA - MB + +! FMSUB_R2(MA,MB) MB = MA - MB + +! FMTAN(MA,MB) MB = TAN(MA) + +! FMTANH(MA,MB) MB = TANH(MA) + +! FMULP(MA,MB) MB = One Unit in the Last Place of MA. + +! FMVARS Write the current values of the internal FM +! variables on unit KW. + +! FMWRIT(KWRITE,MA) Write MA on unit KWRITE. +! Multi-line numbers will have '&' as the last +! nonblank character on all but the last line. These +! numbers can then be read easily using FMREAD. + + + +! These are the Gamma and Related Functions. + +! FMBERN(N,MA,MB) MB = MA*B(N) Multiply by Nth Bernoulli number + +! FMBETA(MA,MB,MC) MC = Beta(MA,MB) + +! FMCOMB(MA,MB,MC) MC = Combination MA choose MB (Binomial coeff.) + +! FMEULR(MA) MA = Euler's constant ( 0.5772156649... ) + +! FMFACT(MA,MB) MB = MA Factorial (Gamma(MA+1)) + +! FMGAM(MA,MB) MB = Gamma(MA) + +! FMIBTA(MX,MA,MB,MC) MC = Incomplete Beta(MX,MA,MB) + +! FMIGM1(MA,MB,MC) MC = Incomplete Gamma(MA,MB). Lower case Gamma(a,x) + +! FMIGM2(MA,MB,MC) MC = Incomplete Gamma(MA,MB). Upper case Gamma(a,x) + +! FMLNGM(MA,MB) MB = Ln(Gamma(MA)) + +! FMPGAM(N,MA,MB) MB = Polygamma(N,MA) (Nth derivative of Psi) + +! FMPOCH(MA,N,MB) MB = MA*(MA+1)*(MA+2)*...*(MA+N-1) (Pochhammer) + +! FMPSI(MA,MB) MB = Psi(MA) (Derivative of Ln(Gamma(MA)) + + + +! These are the integer routines that are designed to be called by the user. +! All are subroutines except logical function IMCOMP. MA, MB, MC refer to IM +! format numbers. In each case the version of the routine to handle packed IM +! numbers has the same name, with 'IM' replaced by 'IP'. + +! IMABS(MA,MB) MB = ABS(MA) + +! IMADD(MA,MB,MC) MC = MA + MB + +! IMBIG(MA) MA = Biggest IM number less than overflow. + +! IMCOMP(MA,LREL,MB) Logical comparison of MA and MB. +! LREL is a CHARACTER*2 value identifying which of +! the six comparisons is to be made. +! Example: IF (IMCOMP(MA,'GE',MB)) ... +! Also can be: IF (IMCOMP(MA,'>=',MB)) +! CHARACTER*1 is ok: IF (IMCOMP(MA,'>',MB)) ... + +! IMDIM(MA,MB,MC) MC = DIM(MA,MB) + +! IMDIV(MA,MB,MC) MC = int(MA/MB) +! Use IMDIVR if the remainder is also needed. + +! IMDIVI(MA,IVAL,MB) MB = int(MA/IVAL) +! IVAL is a one word integer. +! Use IMDVIR to get the remainder also. + +! IMDIVR(MA,MB,MC,MD) MC = int(MA/MB), MD = MA mod MB +! When both the quotient and remainder are needed, +! this routine is twice as fast as calling both +! IMDIV and IMMOD. + +! IMDVIR(MA,IVAL,MB,IREM) MB = int(MA/IVAL), IREM = MA mod IVAL +! IVAL and IREM are one word integers. + +! IMEQ(MA,MB) MB = MA + +! IMFM2I(MAFM,MB) MB = MAFM Convert from real (FM) format to +! integer (IM) format. + +! IMFORM(FORM,MA,STRING) MA is converted to a character string using format +! FORM and returned in STRING. FORM can represent +! I, F, E, or 1PE formats. Example: +! CALL IMFORM('I70',MA,STRING) + +! IMFPRT(FORM,MA) Print MA on unit KW using FORM format. + +! IMGCD(MA,MB,MC) MC = greatest common divisor of MA and MB. + +! IMI2FM(MA,MBFM) MBFM = MA Convert from integer (IM) format to +! real (FM) format. + +! IMI2M(IVAL,MA) MA = IVAL Convert from one word integer to IM. + +! IMINP(LINE,MA,LA,LB) MA = LINE Input conversion. +! Convert LINE(LA) through LINE(LB) +! from characters to IM. + +! IMM2DP(MA,X) X = MA Convert from IM to double precision. + +! IMM2I(MA,IVAL) IVAL = MA Convert from IM to one word integer. + +! IMMAX(MA,MB,MC) MC = MAX(MA,MB) + +! IMMIN(MA,MB,MC) MC = MIN(MA,MB) + +! IMMOD(MA,MB,MC) MC = MA mod MB + +! IMMPY(MA,MB,MC) MC = MA*MB + +! IMMPYI(MA,IVAL,MB) MB = MA*IVAL Multiply by a one word integer. + +! IMMPYM(MA,MB,MC,MD) MD = MA*MB mod MC +! Slightly faster than calling IMMPY and IMMOD +! separately, and it works for cases where IMMPY +! would return OVERFLOW. + +! IMOUT(MA,LINE,LB) LINE = MA Convert from IM to character. +! LINE is a character array of length LB. + +! IMPMOD(MA,MB,MC,MD) MD = MA**MB mod MC + +! IMPRNT(MA) Print MA on unit KW. + +! IMPWR(MA,MB,MC) MC = MA**MB + +! IMREAD(KREAD,MA) MA is returned after reading one (possibly multi-line) +! IM number on unit KREAD. +! This routine reads numbers written by IMWRIT. + +! IMSIGN(MA,MB,MC) MC = SIGN(MA,MB) Sign transfer. + +! IMSQR(MA,MB) MB = MA*MA Faster than IMMPY. + +! IMST2M(STRING,MA) MA = STRING +! Convert from character string to IM. +! Often more convenient than IMINP, which converts an +! array of CHARACTER*1 values. Example: +! CALL IMST2M('12345678901',MA) + +! IMSUB(MA,MB,MC) MC = MA - MB + +! IMWRIT(KWRITE,MA) Write MA on unit KWRITE. +! Multi-line numbers will have '&' as the last +! nonblank character on all but the last line. +! These numbers can then be read easily using IMREAD. + + + +! These are the complex routines that are designed to be called by the user. +! All are subroutines, and in each case the version of the routine to handle +! packed ZM numbers has the same name, with 'ZM' replaced by 'ZP'. + +! MA, MB, MC refer to ZM format complex numbers. +! MAFM, MBFM, MCFM refer to FM format real numbers. +! INTEG is a Fortran INTEGER variable. +! ZVAL is a Fortran COMPLEX variable. + +! ZMABS(MA,MBFM) MBFM = ABS(MA) Result is real. + +! ZMACOS(MA,MB) MB = ACOS(MA) + +! ZMADD(MA,MB,MC) MC = MA + MB + +! ZMADDI(MA,INTEG) MA = MA + INTEG Increment an ZM number by a one word +! integer. Note this call does not have +! an "MB" result like ZMDIVI and ZMMPYI. + +! ZMARG(MA,MBFM) MBFM = Argument(MA) Result is real. + +! ZMASIN(MA,MB) MB = ASIN(MA) + +! ZMATAN(MA,MB) MB = ATAN(MA) + +! ZMCHSH(MA,MB,MC) MB = COSH(MA), MC = SINH(MA). +! Faster than 2 calls. + +! ZMCMPX(MAFM,MBFM,MC) MC = CMPLX(MAFM,MBFM) + +! ZMCONJ(MA,MB) MB = CONJG(MA) + +! ZMCOS(MA,MB) MB = COS(MA) + +! ZMCOSH(MA,MB) MB = COSH(MA) + +! ZMCSSN(MA,MB,MC) MB = COS(MA), MC = SIN(MA). +! Faster than 2 calls. + +! ZMDIV(MA,MB,MC) MC = MA / MB + +! ZMDIVI(MA,INTEG,MB) MB = MA / INTEG + +! ZMEQ(MA,MB) MB = MA + +! ZMEQU(MA,MB,NDA,NDB) MB = MA Version for changing precision. +! (NDA and NDB are as in FMEQU) + +! ZMEXP(MA,MB) MB = EXP(MA) + +! ZMFORM(FORM1,FORM2,MA,STRING) STRING = MA +! MA is converted to a character string using format +! FORM1 for the real part and FORM2 for the imaginary +! part. The result is returned in STRING. FORM1 and +! FORM2 can represent I, F, E, or 1PE formats. Example: +! CALL ZMFORM('F20.10','F15.10',MA,STRING) +! A 1PE in the first format does not carry over to the +! other format descriptor, as it would in an ordinary +! FORMAT statement. + +! ZMFPRT(FORM1,FORM2,MA) Print MA on unit KW using formats FORM1 and FORM2. + +! ZMI2M(INTEG,MA) MA = CMPLX(INTEG,0) + +! ZM2I2M(INTEG1,INTEG2,MA) MA = CMPLX(INTEG1,INTEG2) + +! ZMIMAG(MA,MBFM) MBFM = IMAG(MA) Imaginary part. + +! ZMINP(LINE,MA,LA,LB) MA = LINE Input conversion. +! Convert LINE(LA) through LINE(LB) from +! characters to ZM. LINE is a character array +! of length at least LB. + +! ZMINT(MA,MB) MB = INT(MA) Integer part of both Real +! and Imaginary parts of MA. + +! ZMIPWR(MA,INTEG,MB) MB = MA ** INTEG Integer power function. + +! ZMLG10(MA,MB) MB = LOG10(MA) + +! ZMLN(MA,MB) MB = LOG(MA) + +! ZMM2I(MA,INTEG) INTEG = INT(REAL(MA)) + +! ZMM2Z(MA,ZVAL) ZVAL = MA + +! ZMMPY(MA,MB,MC) MC = MA * MB + +! ZMMPYI(MA,INTEG,MB) MB = MA * INTEG + +! ZMNINT(MA,MB) MB = NINT(MA) Nearest integer of both Real +! and Imaginary. + +! ZMOUT(MA,LINE,LB,LAST1,LAST2) LINE = MA +! Convert from FM to character. +! LINE is the returned character*1 array. +! LB is the dimensioned size of LINE. +! LAST1 is returned as the position in LINE of +! the last character of REAL(MA). +! LAST2 is returned as the position in LINE +! of the last character of AIMAG(MA). + +! ZMPRNT(MA) Print MA on unit KW using current format. + +! ZMPWR(MA,MB,MC) MC = MA ** MB + +! ZMREAD(KREAD,MA) MA is returned after reading one (possibly multi-line) +! ZM number on unit KREAD. +! This routine reads numbers written by ZMWRIT. + +! ZMREAL(MA,MBFM) MBFM = REAL(MA) Real part. + +! ZMRPWR(MA,IVAL,JVAL,MB) MB = MA ** (IVAL/JVAL) + +! ZMSET(NPREC) Set precision to the equivalent of a few more than NPREC +! base 10 digits. This is now the same as FMSET, but is +! retained for compatibility with earlier versions of the +! package. + +! ZMSIN(MA,MB) MB = SIN(MA) + +! ZMSINH(MA,MB) MB = SINH(MA) + +! ZMSQR(MA,MB) MB = MA*MA Faster than ZMMPY. + +! ZMSQRT(MA,MB) MB = SQRT(MA) + +! ZMST2M(STRING,MA) MA = STRING +! Convert from character string to ZM. +! Often more convenient than ZMINP, which +! converts an array of CHARACTER*1 values. +! Example: CALL ZMST2M('123.4+5.67i',MA). + +! ZMSUB(MA,MB,MC) MC = MA - MB + +! ZMTAN(MA,MB) MB = TAN(MA) + +! ZMTANH(MA,MB) MB = TANH(MA) + +! ZMWRIT(KWRITE,MA) Write MA on unit KWRITE. Multi-line numbers are +! formatted for automatic reading with ZMREAD. + +! ZMZ2M(ZVAL,MA) MA = ZVAL + + +! 10. NEW FOR VERSION 1.2 + +! Version 1.2 is written in Fortran-90 free source format. + +! The routines for the Gamma function and related mathematical special +! functions are new in version 1.2. + +! Several new derived-type function interfaces are included in module FMZM in +! file FMZM90.f90, such as integer multiple precision operations GCD, modular +! multiplication, and modular powers. There are also formatting functions and +! function interfaces for the Gamma and related special functions. + +! Two new rounding modes have been added, round toward -infinity and round +! toward +infinity. See the description of KROUND above. +! An option has been added to force more guard digits to be used, so that basic +! arithmetic operations will always round perfectly. See the description of +! KRPERF above. +! These options are included for applications that use FM to check IEEE +! hardware arithmetic. They are not normally useful for most multiple +! precision calculations. + +! The random number routine FM_RANDOM_NUMBER uses 49-digit prime numbers in a +! shuffled multiplicative congruential generator. Historically, some popular +! random number routines tried so hard for maximum speed that they were later +! found to fail some tests for randomness. FM_RANDOM_NUMBER tries to return +! high-quality random values. It is much slower than other generators, but can +! return about 60,000 numbers per second on a 400 MHz single-processor machine. +! This is usually fast enough to be used as a check for suspicious monte carlo +! results from other generators. +! For more details, see the comments in the routine. + +! The arrays for multiple precision numbers were dimensioned starting at 0 in +! version 1.1, and now begin at -1. Array(-1) now holds the sign of the number +! instead of combining the sign with Array(2) as before. The reason for moving +! the sign bit is that many of the original routines, written before Fortran-90 +! existed, simplified the logic by temporarily making input arguments positive, +! working with positive values, then restoring the signs to the input arguments +! upon return. This became illegal under Fortran-90 when used with the derived +! type interface, which demands the inputs to functions for arithmetic operator +! overloading be declared with INTENT(IN). + +! The common blocks of earlier versions have been replaced by module FMVALS. +! This makes it easier to hide the FM internal variable names from the calling +! program, and these variables can be initialized in the module so the +! initializing call to FMSET is no longer mandatory. Several new routines are +! provided to set or return the values for some of these variables. See the +! descriptions for FMSETVAR, FMFLAG, and FMVARS above. + +! Version 1.0 used integer arrays and integer arithmetic internally to perform +! the multiple precision operations. Later versions use double precision +! arithmetic and arrays internally. This is usually faster at higher +! precisions, and on many machines it is also faster at lower precisions. +! Version 1.2 is written so that the arithmetic used can easily be changed from +! double precision to integer, or any other available arithmetic type. This +! permits the user to make the best use of a given machine's arithmetic +! hardware. See the EFFICIENCY discussion below. + + +! 11. EFFICIENCY + +! When the derived type interface is used to access the FM routines, there may +! be a loss of speed if the arrays used to define the multiple precision data +! types are larger than necessary. See comment (b) in the section above on +! array dimensions. + +! To take advantage of hardware architecture on different machines, the package +! has been designed so that the arithmetic used to perform the multiple +! precision operations can easily be changed. All variables that must be +! changed to get a different arithmetic have names beginning with 'M' and are +! declared using REAL (KIND(1.0D0)) ... + +! For example, to change the package to use integer arithmetic internally, make +! these two changes everywhere in the FM.f90 file. +! Change 'REAL (KIND(1.0D0))' to 'INTEGER'. +! Change 'AINT (' to 'INT('. Note the blank between AINT and (. +! On some systems, changing 'AINT (' to '(' may give better speed. + +! In most places in FM, an AINT function is not supposed to be changed. These +! are written 'AINT(', with no embedded blank, so they will not be changed by +! the global change above. + +! The first of these changes must also be made throughout the files FMZM90.f90 +! and FMSAVE.f90. +! Change 'REAL (KIND(1.0D0))' to 'INTEGER'. + +! Many of the variables in FMSAVE.f90 are initialized when they are declared, +! so the initialization values should be changed to integer values. +! Find the lines beginning '! Integer initialization' in file FMSAVE.f90 and +! change the values. The values needed for 32-bit integer arithmetic are next +! to the double precision values, but commented out. In every case, the line +! before the '! Integer initialization' should have '!' inserted in column 1 +! and the line after should have the '!' removed from column 1. If a different +! wordsize is used, the first call to FMSET will check the values defined in +! file FMSAVE.f90 and write messages (on unit KW) if any need to be changed. + +! When changing to a different type of arithmetic, any FM arrays in the user's +! program must be changed to agree. If derived types are used instead of +! direct calls, no changes should be needed in the calling program. + +! For example, in the test program TestFM.f90, change all +! 'REAL (KIND(1.0D0))' to 'INTEGER', as with the other files. + +! This version of FM restricts the base used to be also representable in +! integer variables, so using precision above double usually does not save much +! time unless integers can also be declared at a higher precision. Using IEEE +! Extended would allow a base of around 10**9 to be chosen, but the delayed +! digit-normalization method used for multiplication and division means that a +! slightly smaller base like 10**8 would probably run faster. This would +! usually not be much faster than using the usual base 10**7 with double +! precision. + +! The value of NBITS defined as a parameter in FMVALS refers to the number of +! bits used to represent integers in an M-variable word. Typical values for +! NBITS are: 24 for IEEE single precision, 32 for integer, 53 for IEEE double +! precision. NBITS controls only array size, so setting it too high is ok, but +! then the program will use slightly more memory than necessary. + +! For cases where special compiler directives or minor re-writing of the code +! may improve speed, several of the most important loops in FM are identified +! by comments containing the string '(Inner Loop)'. + +! ------------------------------------------------------------------------------ +! ------------------------------------------------------------------------------ + + + SUBROUTINE FMSET(NPREC) + +! Initialize the global FM variables that must be set before calling +! other FM routines. These variables are initialized to fairly standard +! values in the FMSAVE.f90 file (MODULE FMVALS), so calling FMSET at the +! beginning of a program is now optional. FMSET is a convenient way to set +! or change the precision being used, and it also checks to see that the +! generic values chosen for several machine-dependent variables are valid. + +! Base and precision will be set to give at least NPREC+3 decimal +! digits of precision (giving the user three base ten guard digits). + +! MBASE (base for FM arithmetic) is set to a large power of ten. +! JFORM1 and JFORM2 (default output format controls) are set to 1PE format +! displaying NPREC significant digits. + +! Several FM options were set here in previous versions of the package, +! and are now initialized to their default values in module FMVALS. +! Here are the initial settings: + +! The trace option is set off. +! The mode for angles in trig functions is set to radians. +! The rounding mode is set to symmetric rounding. +! Warning error message level is set to 1. +! Cancellation error monitor is set off. +! Screen width for output is set to 80 columns. +! The exponent character for FM output is set to 'M'. +! Debug error checking is set off. + + USE FMVALS + IMPLICIT NONE + + INTEGER NPREC + + REAL (KIND(1.0D0)) :: MAXINT_CHK,MXEXP2_CHK,MEXPOV_CHK,MEXPUN_CHK, & + MUNKNO_CHK + DOUBLE PRECISION DPEPS_CHK,DPMAX_CHK,SPMAX_CHK,TEMP + INTEGER INTMAX_CHK,K,NPSAVE + + IF (NBITS < DIGITS(MAXINT)) THEN + WRITE (KW,*) ' ' + WRITE (KW,*) ' In routine FMSET it appears that FM internal variable' + WRITE (KW,*) ' NBITS was set to ',NBITS,' in file FMSAVE.f90' + WRITE (KW,*) ' For this machine it should be at least ',DIGITS(MAXINT) + WRITE (KW,*) ' Change the initialization in FMSAVE.f90 to this value.' + WRITE (KW,*) ' ' + WRITE (KW,*) ' NBITS is a parameter that controls array size, so its' + WRITE (KW,*) ' value cannot be changed for this run, and this might' + WRITE (KW,*) ' cause some FM operations to get incorrect results.' + WRITE (KW,*) ' ' + ENDIF + +! MAXINT should be set to a very large integer, possibly +! the largest representable integer for the current +! machine. For most 32-bit machines, MAXINT is set +! to 2**53 - 1 = 9.007D+15 when double precision +! arithmetic is used for M-variables. Using integer +! M-variables usually gives MAXINT = 2**31 - 1 = +! 2147483647. + +! Setting MAXINT to a smaller number is ok, but this +! unnecessarily restricts the permissible range of +! MBASE and MXEXP. + + MAXINT_CHK = RADIX(MAXINT_CHK) + MAXINT_CHK = ((MAXINT_CHK**(DIGITS(MAXINT_CHK)-1)-1)*MAXINT_CHK - 1) + & + MAXINT_CHK + IF (MAXINT > MAXINT_CHK) THEN + WRITE (KW,*) ' ' + WRITE (KW,*) ' In routine FMSET it appears that FM internal variable' + WRITE (KW,*) ' MAXINT was set to ',MAXINT,' in file FMSAVE.f90' + WRITE (KW,*) ' For this machine it should be no more than ',MAXINT_CHK + WRITE (KW,*) ' Change the initialization in FMSAVE.f90 to this value.' + WRITE (KW,*) ' For this run, MAXINT has been changed to ',MAXINT_CHK + WRITE (KW,*) ' ' + MAXINT = MAXINT_CHK + ELSE IF (MAXINT < MAXINT_CHK/2) THEN + WRITE (KW,*) ' ' + WRITE (KW,*) ' In routine FMSET it appears that FM internal variable' + WRITE (KW,*) ' MAXINT was set to ',MAXINT,' in file FMSAVE.f90' + WRITE (KW,*) ' For better performance set it to ',MAXINT_CHK + WRITE (KW,*) ' Change the initialization in FMSAVE.f90 to this value.' + WRITE (KW,*) ' For this run, MAXINT has been changed to ',MAXINT_CHK + WRITE (KW,*) ' ' + MAXINT = MAXINT_CHK + ENDIF + +! INTMAX is a large value close to the overflow threshold +! for integer variables. It is usually 2**31 - 1 +! for machines with 32-bit integer arithmetic. + +! The following code sets INTMAX_CHK to the +! largest representable integer. +! Then INTMAX is checked against this value. + + INTMAX_CHK = HUGE(1) + IF (INTMAX > INTMAX_CHK) THEN + WRITE (KW,*) ' ' + WRITE (KW,*) ' In routine FMSET it appears that FM internal variable' + WRITE (KW,*) ' INTMAX was set to ',INTMAX,' in file FMSAVE.f90' + WRITE (KW,*) ' For this machine it should be no more than ',INTMAX_CHK + WRITE (KW,*) ' Change the initialization in FMSAVE.f90 to this value.' + WRITE (KW,*) ' For this run, INTMAX has been changed to ',INTMAX_CHK + WRITE (KW,*) ' ' + INTMAX = INTMAX_CHK + ELSE IF (INTMAX < INTMAX_CHK/2) THEN + WRITE (KW,*) ' ' + WRITE (KW,*) ' In routine FMSET it appears that FM internal variable' + WRITE (KW,*) ' INTMAX was set to ',INTMAX,' in file FMSAVE.f90' + WRITE (KW,*) ' For better performance set it to ',INTMAX_CHK + WRITE (KW,*) ' Change the initialization in FMSAVE.f90 to this value.' + WRITE (KW,*) ' For this run, INTMAX has been changed to ',INTMAX_CHK + WRITE (KW,*) ' ' + INTMAX = INTMAX_CHK + ENDIF + +! DPMAX should be set to a value near the machine's double +! precision overflow threshold, so that DPMAX and +! 1.0D0/DPMAX are both representable in double +! precision. + + DPMAX_CHK = HUGE(1.0D0)/5 + IF (DPMAX > DPMAX_CHK) THEN + WRITE (KW,*) ' ' + WRITE (KW,*) ' In routine FMSET it appears that FM internal variable' + WRITE (KW,*) ' DPMAX was set to ',DPMAX,' in file FMSAVE.f90' + WRITE (KW,*) ' For this machine it should be no more than ',DPMAX_CHK + WRITE (KW,*) ' Change the initialization in FMSAVE.f90 to this value.' + WRITE (KW,*) ' For this run, DPMAX has been changed to ',DPMAX_CHK + WRITE (KW,*) ' ' + DPMAX = DPMAX_CHK + ELSE IF (DPMAX < DPMAX_CHK/1.0D2) THEN + WRITE (KW,*) ' ' + WRITE (KW,*) ' In routine FMSET it appears that FM internal variable' + WRITE (KW,*) ' DPMAX was set to ',DPMAX,' in file FMSAVE.f90' + WRITE (KW,*) ' For better performance set it to ',DPMAX_CHK + WRITE (KW,*) ' Change the initialization in FMSAVE.f90 to this value.' + WRITE (KW,*) ' For this run, DPMAX has been changed to ',DPMAX_CHK + WRITE (KW,*) ' ' + DPMAX = DPMAX_CHK + ENDIF + +! SPMAX should be set to a value near the machine's single +! precision overflow threshold, so that 1.01*SPMAX +! and 1.0/SPMAX are both representable in single +! precision. + + SPMAX_CHK = HUGE(1.0)/5 + IF (SPMAX > SPMAX_CHK) THEN + WRITE (KW,*) ' ' + WRITE (KW,*) ' In routine FMSET it appears that FM internal variable' + WRITE (KW,*) ' SPMAX was set to ',SPMAX,' in file FMSAVE.f90' + WRITE (KW,*) ' For this machine it should be no more than ',SPMAX_CHK + WRITE (KW,*) ' Change the initialization in FMSAVE.f90 to this value.' + WRITE (KW,*) ' For this run, SPMAX has been changed to ',SPMAX_CHK + WRITE (KW,*) ' ' + SPMAX = SPMAX_CHK + ELSE IF (SPMAX < SPMAX_CHK/1.0D2) THEN + WRITE (KW,*) ' ' + WRITE (KW,*) ' In routine FMSET it appears that FM internal variable' + WRITE (KW,*) ' SPMAX was set to ',SPMAX,' in file FMSAVE.f90' + WRITE (KW,*) ' For better performance set it to ',SPMAX_CHK + WRITE (KW,*) ' Change the initialization in FMSAVE.f90 to this value.' + WRITE (KW,*) ' For this run, SPMAX has been changed to ',SPMAX_CHK + WRITE (KW,*) ' ' + SPMAX = SPMAX_CHK + ENDIF + +! MXBASE is the maximum value for MBASE. + + TEMP = MAXINT + TEMP = INT(MIN(DBLE(INTMAX),SQRT(TEMP))) + IF (MXBASE > TEMP) THEN + WRITE (KW,*) ' ' + WRITE (KW,*) ' In routine FMSET it appears that FM internal variable' + WRITE (KW,*) ' MXBASE was set to ',MXBASE,' in file FMSAVE.f90' + WRITE (KW,*) ' For this machine it should be no more than ',TEMP + WRITE (KW,*) ' Change the initialization in FMSAVE.f90 to this value.' + WRITE (KW,*) ' For this run, MXBASE has been changed to ',TEMP + WRITE (KW,*) ' ' + MXBASE = TEMP + ELSE IF (MXBASE < TEMP/2) THEN + WRITE (KW,*) ' ' + WRITE (KW,*) ' In routine FMSET it appears that FM internal variable' + WRITE (KW,*) ' MXBASE was set to ',MXBASE,' in file FMSAVE.f90' + WRITE (KW,*) ' For better performance set it to ',TEMP + WRITE (KW,*) ' Change the initialization in FMSAVE.f90 to this value.' + WRITE (KW,*) ' For this run, MXBASE has been changed to ',TEMP + WRITE (KW,*) ' ' + MXBASE = TEMP + ENDIF + +! MBASE is the currently used base for arithmetic. + + K = INT(LOG10(DBLE(MXBASE)/4)) + MBASE = 10**K + +! NDIG is the number of digits currently being carried. + + NPSAVE = NPREC + NDIG = 2 + (NPREC+2)/K + IF (NDIG < 2 .OR. NDIG > NDIGMX) THEN + NDIG = MAX(2,NDIG) + NDIG = MIN(NDIGMX,NDIG) + WRITE (KW, & + "(//' Precision out of range when calling FMSET.'," // & + "' NPREC =',I20/' The nearest valid NDIG will be'," // & + "' used instead: NDIG =',I6//)" & + ) NPREC,NDIG + NPSAVE = 0 + ENDIF + +! NCALL is the call stack pointer. + + NCALL = 0 + +! MXEXP is the current maximum exponent. +! MXEXP2 is the internal maximum exponent. This is used to +! define the overflow and underflow thresholds. + +! These values are chosen so that FM routines can raise the +! overflow/underflow limit temporarily while computing +! intermediate results, and so that EXP(INTMAX) is greater +! than MXBASE**(MXEXP2+1). + +! The overflow threshold is MBASE**(MXEXP+1), and the +! underflow threshold is MBASE**(-MXEXP-1). +! This means the valid exponents in the first word of an FM +! number can range from -MXEXP to MXEXP+1 (inclusive). + + MXEXP = INT((DBLE(INTMAX))/(2.0D0*LOG(DBLE(MXBASE))) - 1.0D0) + MXEXP2_CHK = INT(2*MXEXP + MXEXP/100) + IF (MXEXP2 > MXEXP2_CHK*1.01) THEN + WRITE (KW,*) ' ' + WRITE (KW,*) ' In routine FMSET it appears that FM internal variable' + WRITE (KW,*) ' MXEXP2 was set to ',MXEXP2,' in file FMSAVE.f90' + WRITE (KW,*) ' For this machine it should be no more than ',MXEXP2_CHK + WRITE (KW,*) ' Change the initialization in FMSAVE.f90 to this value.' + WRITE (KW,*) ' For this run, MXEXP2 has been changed to ',MXEXP2_CHK + WRITE (KW,*) ' ' + MXEXP2 = MXEXP2_CHK + ELSE IF (MXEXP2 < MXEXP2_CHK*0.99) THEN + WRITE (KW,*) ' ' + WRITE (KW,*) ' In routine FMSET it appears that FM internal variable' + WRITE (KW,*) ' MXEXP2 was set to ',MXEXP2,' in file FMSAVE.f90' + WRITE (KW,*) ' For this machine it should be no less than ',MXEXP2_CHK + WRITE (KW,*) ' Change the initialization in FMSAVE.f90 to this value.' + WRITE (KW,*) ' For this run, MXEXP2 has been changed to ',MXEXP2_CHK + WRITE (KW,*) ' ' + MXEXP2 = MXEXP2_CHK + ENDIF + +! KACCSW is a switch used to enable cancellation error +! monitoring. Routines where cancellation is +! not a problem run faster by skipping the +! cancellation monitor calculations. +! KACCSW = 0 means no error monitoring, +! = 1 means error monitoring is done. + + KACCSW = 0 + +! MEXPUN is the exponent used as a special symbol for +! underflowed results. + + MEXPUN_CHK = -AINT(MXEXP2*1.01D0) + IF (MEXPUN < MEXPUN_CHK*1.01) THEN + WRITE (KW,*) ' ' + WRITE (KW,*) ' In routine FMSET it appears that FM internal variable' + WRITE (KW,*) ' MEXPUN was set to ',MEXPUN,' in file FMSAVE.f90' + WRITE (KW,*) ' For this machine it should be no less than ',MEXPUN_CHK + WRITE (KW,*) ' Change the initialization in FMSAVE.f90 to this value.' + WRITE (KW,*) ' For this run, MEXPUN has been changed to ',MEXPUN_CHK + WRITE (KW,*) ' ' + MEXPUN = MEXPUN_CHK + ELSE IF (MEXPUN > MEXPUN_CHK) THEN + WRITE (KW,*) ' ' + WRITE (KW,*) ' In routine FMSET it appears that FM internal variable' + WRITE (KW,*) ' MEXPUN was set to ',MEXPUN,' in file FMSAVE.f90' + WRITE (KW,*) ' For this machine it should be no more than ',MEXPUN_CHK + WRITE (KW,*) ' Change the initialization in FMSAVE.f90 to this value.' + WRITE (KW,*) ' For this run, MEXPUN has been changed to ',MEXPUN_CHK + WRITE (KW,*) ' ' + MEXPUN = MEXPUN_CHK + ENDIF + +! MEXPOV is the exponent used as a special symbol for +! overflowed results. + + MEXPOV_CHK = -MEXPUN + IF (MEXPOV /= MEXPOV_CHK) THEN + WRITE (KW,*) ' ' + WRITE (KW,*) ' In routine FMSET it appears that FM internal variable' + WRITE (KW,*) ' MEXPOV was set to ',MEXPOV,' in file FMSAVE.f90' + WRITE (KW,*) ' For this machine it should be ',MEXPOV_CHK + WRITE (KW,*) ' Change the initialization in FMSAVE.f90 to this value.' + WRITE (KW,*) ' For this run, MEXPOV has been changed to ',MEXPOV_CHK + WRITE (KW,*) ' ' + MEXPOV = MEXPOV_CHK + ENDIF + +! MUNKNO is the exponent used as a special symbol for +! unknown FM results (1/0, SQRT(-3.0), ...). + + MUNKNO_CHK = AINT(MEXPOV*1.01D0) + IF (MUNKNO > MUNKNO_CHK*1.01) THEN + WRITE (KW,*) ' ' + WRITE (KW,*) ' In routine FMSET it appears that FM internal variable' + WRITE (KW,*) ' MUNKNO was set to ',MUNKNO,' in file FMSAVE.f90' + WRITE (KW,*) ' For this machine it should be no more than ',MUNKNO_CHK + WRITE (KW,*) ' Change the initialization in FMSAVE.f90 to this value.' + WRITE (KW,*) ' For this run, MUNKNO has been changed to ',MUNKNO_CHK + WRITE (KW,*) ' ' + MUNKNO = MUNKNO_CHK + ELSE IF (MUNKNO < MUNKNO_CHK) THEN + WRITE (KW,*) ' ' + WRITE (KW,*) ' In routine FMSET it appears that FM internal variable' + WRITE (KW,*) ' MUNKNO was set to ',MUNKNO,' in file FMSAVE.f90' + WRITE (KW,*) ' For this machine it should be no less than ',MUNKNO_CHK + WRITE (KW,*) ' Change the initialization in FMSAVE.f90 to this value.' + WRITE (KW,*) ' For this run, MUNKNO has been changed to ',MUNKNO_CHK + WRITE (KW,*) ' ' + MUNKNO = MUNKNO_CHK + ENDIF + +! RUNKNO is returned from FM to real or double conversion +! routines when no valid result can be expressed in +! real or double precision. On systems that provide +! a value for undefined results (e.g., Not A Number) +! setting RUNKNO to that value is reasonable. On +! other systems set it to a value that is likely to +! make any subsequent results obviously wrong that +! use it. In either case a KFLAG = -4 condition is +! also returned. + + RUNKNO = -1.01*SPMAX + +! IUNKNO is returned from FM to integer conversion routines +! when no valid result can be expressed as a one word +! integer. KFLAG = -4 is also set. + + IUNKNO = -INT(MXEXP2) + +! DPEPS is the approximate machine precision. + + DPEPS_CHK = EPSILON(1.0D0) + IF (DPEPS > DPEPS_CHK*1.01) THEN + WRITE (KW,*) ' ' + WRITE (KW,*) ' In routine FMSET it appears that FM internal variable' + WRITE (KW,*) ' DPEPS was set to ',DPEPS,' in file FMSAVE.f90' + WRITE (KW,*) ' For this machine it should be no more than ',DPEPS_CHK + WRITE (KW,*) ' Change the initialization in FMSAVE.f90 to this value.' + WRITE (KW,*) ' For this run, DPEPS has been changed to ',DPEPS_CHK + WRITE (KW,*) ' ' + DPEPS = DPEPS_CHK + ELSE IF (DPEPS < DPEPS_CHK*0.99) THEN + WRITE (KW,*) ' ' + WRITE (KW,*) ' In routine FMSET it appears that FM internal variable' + WRITE (KW,*) ' DPEPS was set to ',DPEPS,' in file FMSAVE.f90' + WRITE (KW,*) ' For this machine it should be no less than ',DPEPS_CHK + WRITE (KW,*) ' Change the initialization in FMSAVE.f90 to this value.' + WRITE (KW,*) ' For this run, DPEPS has been changed to ',DPEPS_CHK + WRITE (KW,*) ' ' + DPEPS = DPEPS_CHK + ENDIF + +! JFORM1 indicates the format used by FMOUT. + + JFORM1 = 1 + +! JFORM2 indicates the number of digits used in FMOUT. + + JFORM2 = NPSAVE + +! Set JFORMZ to ' 1.23 + 4.56 i ' format. + + JFORMZ = 1 + +! Set JPRNTZ to print real and imaginary parts on one +! line whenever possible. + + JPRNTZ = 1 + +! Initialize two hash tables that are used for character +! look-up during input conversion. + + CALL FMHTBL + +! FMCONS sets several real and double precision constants. + + CALL FMCONS + + + RETURN + END SUBROUTINE FMSET + + SUBROUTINE FMABS(MA,MB) + +! MB = ABS(MA) + + USE FMVALS + IMPLICIT NONE + + REAL (KIND(1.0D0)) :: MA(-1:LUNPCK),MB(-1:LUNPCK) + + REAL (KIND(1.0D0)) :: MD2B + INTEGER KWRNSV + + NCALL = NCALL + 1 + NAMEST(NCALL) = 'FMABS ' + IF (NTRACE /= 0) CALL FMNTR(2,MA,MA,1,1) + + KFLAG = 0 + KWRNSV = KWARN + KWARN = 0 + CALL FMEQ(MA,MB) + MB(-1) = 1 + KWARN = KWRNSV + + IF (KACCSW == 1) THEN + MD2B = NINT((NDIG-1)*ALOGM2 + LOG(REAL(ABS(MB(2))+1))/0.69315) + MB(0) = MIN(MB(0),MD2B) + ENDIF + IF (NTRACE /= 0) CALL FMNTR(1,MB,MB,1,1) + NCALL = NCALL - 1 + RETURN + END SUBROUTINE FMABS + + SUBROUTINE FMACOS(MA,MB) + +! MB = ACOS(MA) + + USE FMVALS + IMPLICIT NONE + + REAL (KIND(1.0D0)) :: MA(-1:LUNPCK),MB(-1:LUNPCK) + REAL (KIND(1.0D0)) :: MACCA,MACMAX,MAS,MXSAVE + INTEGER J,K,KASAVE,KOVUN,KRESLT,NDSAVE + + IF (MBLOGS /= MBASE) CALL FMCONS + IF (ABS(MA(1)) > MEXPAB .OR. MA(1) > 0 .OR. MA(2) == 0) THEN + CALL FMENTR('FMACOS',MA,MA,1,1,MB,KRESLT,NDSAVE,MXSAVE,KASAVE, & + KOVUN) + IF (KRESLT /= 0) RETURN + ELSE + NCALL = NCALL + 1 + NAMEST(NCALL) = 'FMACOS' + IF (NTRACE /= 0) CALL FMNTR(2,MA,MA,1,1) + KOVUN = 0 + IF (MA(1) == MEXPOV .OR. MA(1) == MEXPUN) KOVUN = 1 + NDSAVE = NDIG + IF (NCALL == 1) THEN + K = MAX(NGRD52-1,2) + NDIG = MAX(NDIG+K,2) + IF (NDIG > NDG2MX) THEN + KFLAG = -9 + CALL FMWARN + NDIG = NDSAVE + KRESLT = 12 + CALL FMRSLT(MA,MA,MB,KRESLT) + IF (NTRACE /= 0) CALL FMNTR(1,MB,MB,1,1) + NCALL = NCALL - 1 + RETURN + ENDIF + ENDIF + KASAVE = KACCSW + KACCSW = 0 + MXSAVE = MXEXP + MXEXP = MXEXP2 + ENDIF + + MAS = MA(-1) + MACCA = MA(0) + CALL FMEQ2(MA,MB,NDSAVE,NDIG) + MB(0) = NINT(NDIG*ALOGM2) + +! Use ACOS(X) = ATAN(SQRT(1-X*X)/X) + + MB(-1) = 1 + CALL FMI2M(1,M05) + CALL FMSUB(M05,MB,M03) + CALL FMADD(M05,MB,M04) + CALL FMMPY_R2(M03,M04) + CALL FMSQRT_R1(M04) + CALL FMDIV_R2(M04,MB) + + CALL FMATAN(MB,M13) + CALL FMEQ(M13,MB) + + IF (MAS < 0) THEN + IF (KRAD == 1) THEN + CALL FMPI(M05) + ELSE + CALL FMI2M(180,M05) + ENDIF + CALL FMSUB_R2(M05,MB) + ENDIF + +! Round the result and return. + + MACMAX = NINT((NDSAVE-1)*ALOGM2 + LOG(REAL(ABS(MB(2))+1))/0.69315) + MB(0) = MIN(MB(0),MACCA,MACMAX) + DO J = -1, NDIG+1 + M01(J) = MB(J) + ENDDO + CALL FMEXIT(M01,MB,NDSAVE,MXSAVE,KASAVE,KOVUN) + RETURN + END SUBROUTINE FMACOS + + SUBROUTINE FMADD(MA,MB,MC) + +! MC = MA + MB + +! This routine performs the trace printing for addition. +! FMADD2 is used to do the arithmetic. + + USE FMVALS + IMPLICIT NONE + + REAL (KIND(1.0D0)) :: MA(-1:LUNPCK),MB(-1:LUNPCK),MC(-1:LUNPCK) + + NCALL = NCALL + 1 + IF (NTRACE /= 0) THEN + NAMEST(NCALL) = 'FMADD ' + CALL FMNTR(2,MA,MB,2,1) + + CALL FMADD2(MA,MB,MC) + + CALL FMNTR(1,MC,MC,1,1) + ELSE + CALL FMADD2(MA,MB,MC) + ENDIF + NCALL = NCALL - 1 + RETURN + END SUBROUTINE FMADD + + SUBROUTINE FMADD2(MA,MB,MC) + +! Internal addition routine. MC = MA + MB + + USE FMVALS + IMPLICIT NONE + + REAL (KIND(1.0D0)) :: MA(-1:LUNPCK),MB(-1:LUNPCK),MC(-1:LUNPCK) + + REAL (KIND(1.0D0)) :: MA0,MA1,MA2,MAS,MB0,MB1,MB2,MB2RD,MBS + INTEGER J,JCOMP,JRSSAV,JSIGN,KRESLT,N1,NGUARD,NMWA + REAL B2RDA,B2RDB + + IF (MBLOGS /= MBASE) CALL FMCONS + JRSSAV = JRSIGN + MA2 = MA(2) + MB2 = MB(2) + IF (ABS(MA(1)) > MEXPAB .OR. ABS(MB(1)) > MEXPAB .OR. & + KDEBUG == 1) THEN + IF (KSUB == 1) THEN + CALL FMARGS('FMSUB ',2,MA,MB,KRESLT) + ELSE + CALL FMARGS('FMADD ',2,MA,MB,KRESLT) + ENDIF + IF (KRESLT /= 0) THEN + IF ((KRESLT /= 1 .AND. KRESLT /= 2) .OR. MA(2) == 0 .OR. & + MB(2) == 0) THEN + NCALL = NCALL + 1 + IF (KSUB == 1) THEN + NAMEST(NCALL) = 'FMSUB ' + ELSE + NAMEST(NCALL) = 'FMADD ' + ENDIF + CALL FMRSLT(MA,MB,MC,KRESLT) + JRSIGN = JRSSAV + NCALL = NCALL - 1 + RETURN + ENDIF + ENDIF + ELSE + IF (MA(2) == 0) THEN + MA0 = MIN(MA(0),MB(0)) + CALL FMEQ(MB,MC) + MC(0) = MA0 + KFLAG = 1 + IF (KSUB == 1) THEN + IF (MC(1) /= MUNKNO .AND. MC(2) /= 0) MC(-1) = -MC(-1) + KFLAG = 0 + ENDIF + JRSIGN = JRSSAV + RETURN + ENDIF + IF (MB(2) == 0) THEN + MA0 = MIN(MA(0),MB(0)) + CALL FMEQ(MA,MC) + MC(0) = MA0 + KFLAG = 1 + JRSIGN = JRSSAV + RETURN + ENDIF + ENDIF + + MA0 = MA(0) + IF (KACCSW == 1) THEN + MB0 = MB(0) + MA1 = MA(1) + MB1 = MB(1) + ENDIF + KFLAG = 0 + N1 = NDIG + 1 + +! NGUARD is the number of guard digits used. + + IF (NCALL > 1) THEN + NGUARD = NGRD21 + IF (NGUARD > NDIG) NGUARD = NDIG + ELSE + NGUARD = NGRD52 + IF (NGUARD > NDIG) NGUARD = NDIG + IF (MBASE < 1000 .OR. KROUND /= 1 .OR. KRPERF == 1) THEN + NGUARD = NDIG + 10 + ENDIF + ENDIF + NMWA = N1 + NGUARD + +! Save the signs of MA and MB and then work with +! positive numbers. +! JSIGN is the sign of the result of MA + MB. + + JSIGN = 1 + MAS = MA(-1) + MBS = MB(-1) + IF (KSUB == 1) MBS = -MBS + +! See which one is larger in absolute value. + + JCOMP = 2 + IF (MA(1) > MB(1)) THEN + JCOMP = 1 + ELSE IF (MB(1) > MA(1)) THEN + JCOMP = 3 + ELSE + DO J = 2, N1 + IF (MA(J) > MB(J)) THEN + JCOMP = 1 + EXIT + ENDIF + IF (MB(J) > MA(J)) THEN + JCOMP = 3 + EXIT + ENDIF + ENDDO + ENDIF + + IF (JCOMP < 3) THEN + IF (MAS < 0) JSIGN = -1 + JRSIGN = JSIGN + IF (MAS*MBS > 0) THEN + CALL FMADDP(MA,MB,NGUARD,NMWA) + ELSE + CALL FMADDN(MA,MB,NGUARD,NMWA) + ENDIF + ELSE + IF (MBS < 0) JSIGN = -1 + JRSIGN = JSIGN + IF (MAS*MBS > 0) THEN + CALL FMADDP(MB,MA,NGUARD,NMWA) + ELSE + CALL FMADDN(MB,MA,NGUARD,NMWA) + ENDIF + ENDIF + +! Transfer to MC and fix the sign of the result. + + CALL FMMOVE(MWA,MC) + MC(-1) = 1 + IF (JSIGN < 0 .AND. MC(2) /= 0) MC(-1) = -1 + + IF (KFLAG < 0) THEN + IF (KSUB == 1) THEN + NAMEST(NCALL) = 'FMSUB ' + ELSE + NAMEST(NCALL) = 'FMADD ' + ENDIF + CALL FMWARN + ENDIF + + IF (KACCSW == 1) THEN + B2RDA = LOG(REAL(ABS(MC(2))+1)/REAL(ABS(MA2)+1))/0.69315 + & + REAL(MC(1)-MA1)*ALOGM2 + REAL(MA0) + B2RDB = LOG(REAL(ABS(MC(2))+1)/REAL(ABS(MB2)+1))/0.69315 + & + REAL(MC(1)-MB1)*ALOGM2 + REAL(MB0) + MB2RD = NINT(MAX(0.0,MIN(B2RDA,B2RDB, & + (NDIG-1)*ALOGM2 + LOG(REAL(ABS(MC(2))+1))/0.69315))) + IF (MC(2) == 0) THEN + MC(0) = 0 + ELSE + MC(0) = MIN(MAX(MA0,MB0),MB2RD) + ENDIF + ELSE + MC(0) = MA0 + ENDIF + + JRSIGN = JRSSAV + RETURN + END SUBROUTINE FMADD2 + + SUBROUTINE FMADD_R1(MA,MB) + +! MA = MA + MB + +! This routine performs the trace printing for addition. +! FMADD2_R1 is used to do the arithmetic. + + USE FMVALS + IMPLICIT NONE + + REAL (KIND(1.0D0)) :: MA(-1:LUNPCK),MB(-1:LUNPCK) + + NCALL = NCALL + 1 + IF (NTRACE /= 0) THEN + NAMEST(NCALL) = 'FMADD ' + CALL FMNTR(2,MA,MB,2,1) + + CALL FMADD2_R1(MA,MB) + + CALL FMNTR(1,MA,MA,1,1) + ELSE + CALL FMADD2_R1(MA,MB) + ENDIF + NCALL = NCALL - 1 + RETURN + END SUBROUTINE FMADD_R1 + + SUBROUTINE FMADD2_R1(MA,MB) + +! Internal addition routine. MA = MA + MB + + USE FMVALS + IMPLICIT NONE + + REAL (KIND(1.0D0)) :: MA(-1:LUNPCK),MB(-1:LUNPCK) + + REAL (KIND(1.0D0)) :: MA0,MA1,MA2,MAS,MB0,MB1,MB2,MB2RD,MBS + INTEGER J,JCOMP,JRSSAV,JSIGN,KRESLT,N1,NGUARD,NMWA + REAL B2RDA,B2RDB + + IF (MBLOGS /= MBASE) CALL FMCONS + JRSSAV = JRSIGN + MA2 = MA(2) + MB2 = MB(2) + IF (ABS(MA(1)) > MEXPAB .OR. ABS(MB(1)) > MEXPAB .OR. & + KDEBUG == 1) THEN + IF (KSUB == 1) THEN + CALL FMARGS('FMSUB ',2,MA,MB,KRESLT) + ELSE + CALL FMARGS('FMADD ',2,MA,MB,KRESLT) + ENDIF + IF (KRESLT /= 0) THEN + IF ((KRESLT /= 1 .AND. KRESLT /= 2) .OR. MA(2) == 0 .OR. & + MB(2) == 0) THEN + NCALL = NCALL + 1 + IF (KSUB == 1) THEN + NAMEST(NCALL) = 'FMSUB ' + ELSE + NAMEST(NCALL) = 'FMADD ' + ENDIF + CALL FMRSLT(MA,MB,M07,KRESLT) + CALL FMEQ(M07,MA) + JRSIGN = JRSSAV + NCALL = NCALL - 1 + RETURN + ENDIF + ENDIF + ELSE + IF (MA(2) == 0) THEN + MA0 = MIN(MA(0),MB(0)) + CALL FMEQ(MB,MA) + MA(0) = MA0 + KFLAG = 1 + IF (KSUB == 1) THEN + IF (MA(1) /= MUNKNO .AND. MA(2) /= 0) MA(-1) = -MA(-1) + KFLAG = 0 + ENDIF + JRSIGN = JRSSAV + RETURN + ENDIF + IF (MB(2) == 0) THEN + MA0 = MIN(MA(0),MB(0)) + MA(0) = MA0 + KFLAG = 1 + JRSIGN = JRSSAV + RETURN + ENDIF + ENDIF + + MA0 = MA(0) + IF (KACCSW == 1) THEN + MB0 = MB(0) + MA1 = MA(1) + MB1 = MB(1) + ENDIF + KFLAG = 0 + N1 = NDIG + 1 + +! NGUARD is the number of guard digits used. + + IF (NCALL > 1) THEN + NGUARD = NGRD21 + IF (NGUARD > NDIG) NGUARD = NDIG + ELSE + NGUARD = NGRD52 + IF (NGUARD > NDIG) NGUARD = NDIG + IF (MBASE < 1000 .OR. KROUND /= 1 .OR. KRPERF == 1) THEN + NGUARD = NDIG + 10 + ENDIF + ENDIF + NMWA = N1 + NGUARD + +! Save the signs of MA and MB and then work with +! positive numbers. +! JSIGN is the sign of the result of MA + MB. + + JSIGN = 1 + MAS = MA(-1) + MBS = MB(-1) + IF (KSUB == 1) MBS = -MBS + +! See which one is larger in absolute value. + + JCOMP = 2 + IF (MA(1) > MB(1)) THEN + JCOMP = 1 + ELSE IF (MB(1) > MA(1)) THEN + JCOMP = 3 + ELSE + DO J = 2, N1 + IF (MA(J) > MB(J)) THEN + JCOMP = 1 + EXIT + ENDIF + IF (MB(J) > MA(J)) THEN + JCOMP = 3 + EXIT + ENDIF + ENDDO + ENDIF + + IF (JCOMP < 3) THEN + IF (MAS < 0) JSIGN = -1 + JRSIGN = JSIGN + IF (MAS*MBS > 0) THEN + CALL FMADDP(MA,MB,NGUARD,NMWA) + ELSE + CALL FMADDN(MA,MB,NGUARD,NMWA) + ENDIF + ELSE + IF (MBS < 0) JSIGN = -1 + JRSIGN = JSIGN + IF (MAS*MBS > 0) THEN + CALL FMADDP(MB,MA,NGUARD,NMWA) + ELSE + CALL FMADDN(MB,MA,NGUARD,NMWA) + ENDIF + ENDIF + +! Transfer to MA and fix the sign of the result. + + CALL FMMOVE(MWA,MA) + MA(-1) = 1 + IF (JSIGN < 0 .AND. MA(2) /= 0) MA(-1) = -1 + + IF (KFLAG < 0) THEN + IF (KSUB == 1) THEN + NAMEST(NCALL) = 'FMSUB ' + ELSE + NAMEST(NCALL) = 'FMADD ' + ENDIF + CALL FMWARN + ENDIF + + IF (KACCSW == 1) THEN + B2RDA = LOG(REAL(ABS(MA(2))+1)/REAL(ABS(MA2)+1))/0.69315 + & + REAL(MA(1)-MA1)*ALOGM2 + REAL(MA0) + B2RDB = LOG(REAL(ABS(MA(2))+1)/REAL(ABS(MB2)+1))/0.69315 + & + REAL(MA(1)-MB1)*ALOGM2 + REAL(MB0) + MB2RD = NINT(MAX(0.0,MIN(B2RDA,B2RDB, & + (NDIG-1)*ALOGM2 + LOG(REAL(ABS(MA(2))+1))/0.69315))) + IF (MA(2) == 0) THEN + MA(0) = 0 + ELSE + MA(0) = MIN(MAX(MA0,MB0),MB2RD) + ENDIF + ELSE + MA(0) = MA0 + ENDIF + + JRSIGN = JRSSAV + RETURN + END SUBROUTINE FMADD2_R1 + + SUBROUTINE FMADD_R2(MA,MB) + +! MB = MA + MB + +! This routine performs the trace printing for addition. +! FMADD2_R2 is used to do the arithmetic. + + USE FMVALS + IMPLICIT NONE + + REAL (KIND(1.0D0)) :: MA(-1:LUNPCK),MB(-1:LUNPCK) + + NCALL = NCALL + 1 + IF (NTRACE /= 0) THEN + NAMEST(NCALL) = 'FMADD ' + CALL FMNTR(2,MA,MB,2,1) + + CALL FMADD2_R2(MA,MB) + + CALL FMNTR(1,MB,MB,1,1) + ELSE + CALL FMADD2_R2(MA,MB) + ENDIF + NCALL = NCALL - 1 + RETURN + END SUBROUTINE FMADD_R2 + + SUBROUTINE FMADD2_R2(MA,MB) + +! Internal addition routine. MB = MA + MB + + USE FMVALS + IMPLICIT NONE + + REAL (KIND(1.0D0)) :: MA(-1:LUNPCK),MB(-1:LUNPCK) + + REAL (KIND(1.0D0)) :: MA0,MA1,MA2,MAS,MB0,MB1,MB2,MB2RD,MBS + INTEGER J,JCOMP,JRSSAV,JSIGN,KRESLT,N1,NGUARD,NMWA + REAL B2RDA,B2RDB + + IF (MBLOGS /= MBASE) CALL FMCONS + JRSSAV = JRSIGN + MA2 = MA(2) + MB2 = MB(2) + IF (ABS(MA(1)) > MEXPAB .OR. ABS(MB(1)) > MEXPAB .OR. & + KDEBUG == 1) THEN + IF (KSUB == 1) THEN + CALL FMARGS('FMSUB ',2,MA,MB,KRESLT) + ELSE + CALL FMARGS('FMADD ',2,MA,MB,KRESLT) + ENDIF + IF (KRESLT /= 0) THEN + IF ((KRESLT /= 1 .AND. KRESLT /= 2) .OR. MA(2) == 0 .OR. & + MB(2) == 0) THEN + NCALL = NCALL + 1 + IF (KSUB == 1) THEN + NAMEST(NCALL) = 'FMSUB ' + ELSE + NAMEST(NCALL) = 'FMADD ' + ENDIF + CALL FMRSLT(MA,MB,M07,KRESLT) + CALL FMEQ(M07,MB) + JRSIGN = JRSSAV + NCALL = NCALL - 1 + RETURN + ENDIF + ENDIF + ELSE + IF (MA(2) == 0) THEN + MA0 = MIN(MA(0),MB(0)) + MB(0) = MA0 + KFLAG = 1 + IF (KSUB == 1) THEN + IF (MB(1) /= MUNKNO .AND. MB(2) /= 0) MB(-1) = -MB(-1) + KFLAG = 0 + ENDIF + JRSIGN = JRSSAV + RETURN + ENDIF + IF (MB(2) == 0) THEN + MA0 = MIN(MA(0),MB(0)) + CALL FMEQ(MA,MB) + MB(0) = MA0 + KFLAG = 1 + JRSIGN = JRSSAV + RETURN + ENDIF + ENDIF + + MA0 = MA(0) + IF (KACCSW == 1) THEN + MB0 = MB(0) + MA1 = MA(1) + MB1 = MB(1) + ENDIF + KFLAG = 0 + N1 = NDIG + 1 + +! NGUARD is the number of guard digits used. + + IF (NCALL > 1) THEN + NGUARD = NGRD21 + IF (NGUARD > NDIG) NGUARD = NDIG + ELSE + NGUARD = NGRD52 + IF (NGUARD > NDIG) NGUARD = NDIG + IF (MBASE < 1000 .OR. KROUND /= 1 .OR. KRPERF == 1) THEN + NGUARD = NDIG + 10 + ENDIF + ENDIF + NMWA = N1 + NGUARD + +! Save the signs of MA and MB and then work with +! positive numbers. +! JSIGN is the sign of the result of MA + MB. + + JSIGN = 1 + MAS = MA(-1) + MBS = MB(-1) + IF (KSUB == 1) MBS = -MBS + +! See which one is larger in absolute value. + + JCOMP = 2 + IF (MA(1) > MB(1)) THEN + JCOMP = 1 + ELSE IF (MB(1) > MA(1)) THEN + JCOMP = 3 + ELSE + DO J = 2, N1 + IF (MA(J) > MB(J)) THEN + JCOMP = 1 + EXIT + ENDIF + IF (MB(J) > MA(J)) THEN + JCOMP = 3 + EXIT + ENDIF + ENDDO + ENDIF + + IF (JCOMP < 3) THEN + IF (MAS < 0) JSIGN = -1 + JRSIGN = JSIGN + IF (MAS*MBS > 0) THEN + CALL FMADDP(MA,MB,NGUARD,NMWA) + ELSE + CALL FMADDN(MA,MB,NGUARD,NMWA) + ENDIF + ELSE + IF (MBS < 0) JSIGN = -1 + JRSIGN = JSIGN + IF (MAS*MBS > 0) THEN + CALL FMADDP(MB,MA,NGUARD,NMWA) + ELSE + CALL FMADDN(MB,MA,NGUARD,NMWA) + ENDIF + ENDIF + +! Transfer to MB and fix the sign of the result. + + CALL FMMOVE(MWA,MB) + MB(-1) = 1 + IF (JSIGN < 0 .AND. MB(2) /= 0) MB(-1) = -1 + + IF (KFLAG < 0) THEN + IF (KSUB == 1) THEN + NAMEST(NCALL) = 'FMSUB ' + ELSE + NAMEST(NCALL) = 'FMADD ' + ENDIF + CALL FMWARN + ENDIF + + IF (KACCSW == 1) THEN + B2RDA = LOG(REAL(ABS(MB(2))+1)/REAL(ABS(MA2)+1))/0.69315 + & + REAL(MB(1)-MA1)*ALOGM2 + REAL(MA0) + B2RDB = LOG(REAL(ABS(MB(2))+1)/REAL(ABS(MB2)+1))/0.69315 + & + REAL(MB(1)-MB1)*ALOGM2 + REAL(MB0) + MB2RD = NINT(MAX(0.0,MIN(B2RDA,B2RDB, & + (NDIG-1)*ALOGM2 + LOG(REAL(ABS(MB(2))+1))/0.69315))) + IF (MB(2) == 0) THEN + MB(0) = 0 + ELSE + MB(0) = MIN(MAX(MA0,MB0),MB2RD) + ENDIF + ELSE + MB(0) = MA0 + ENDIF + + JRSIGN = JRSSAV + RETURN + END SUBROUTINE FMADD2_R2 + + SUBROUTINE FMADDI(MA,IVAL) + +! MA = MA + IVAL + +! Increment MA by one word integer IVAL. + +! This routine is faster than FMADD when IVAL is small enough so +! that it can be added to a single word of MA without often causing +! a carry. Otherwise FMI2M and FMADD are used. + + USE FMVALS + IMPLICIT NONE + + REAL (KIND(1.0D0)) :: MA(-1:LUNPCK) + INTEGER :: IVAL + REAL (KIND(1.0D0)) :: MAEXP,MD2B,MKSUM + INTEGER :: KPTMA + + NCALL = NCALL + 1 + IF (NTRACE /= 0) THEN + NAMEST(NCALL) = 'FMADDI' + CALL FMNTR(2,MA,MA,1,1) + CALL FMNTRI(2,IVAL,0) + ENDIF + KFLAG = 0 + + MAEXP = MA(1) + IF (MAEXP <= 0 .OR. MAEXP > NDIG) GO TO 110 + KPTMA = INT(MAEXP) + 1 + IF (MA(-1) < 0) THEN + MKSUM = MA(KPTMA) - IVAL + ELSE + MKSUM = MA(KPTMA) + IVAL + ENDIF + + IF (MKSUM >= MBASE .OR. MKSUM < 0) GO TO 110 + IF (KPTMA == 2 .AND. MKSUM == 0) GO TO 110 + MA(KPTMA) = MKSUM + GO TO 120 + + 110 CALL FMI2M(IVAL,M01) + CALL FMADD2_R1(MA,M01) + + 120 IF (KACCSW == 1) THEN + MD2B = NINT((NDIG-1)*ALOGM2 + LOG(REAL(ABS(MA(2))+1))/0.69315) + MA(0) = MIN(MA(0),MD2B) + ENDIF + IF (NTRACE /= 0) THEN + CALL FMNTR(1,MA,MA,1,1) + ENDIF + NCALL = NCALL - 1 + RETURN + END SUBROUTINE FMADDI + + SUBROUTINE FMADDN(MA,MB,NGUARD,NMWA) + +! Internal addition routine. MWA = MA - MB +! The arguments are such that MA >= MB >= 0. + +! NGUARD is the number of guard digits being carried. +! NMWA is the number of words in MWA that will be used. + + USE FMVALS + IMPLICIT NONE + + REAL (KIND(1.0D0)) :: MA(-1:LUNPCK),MB(-1:LUNPCK) + INTEGER NGUARD,NMWA + REAL (KIND(1.0D0)) :: MK,MR + INTEGER J,K,KL,KP1,KP2,KPT,KSH,N1,N2,NK,NK1 + + N1 = NDIG + 1 + +! Check for an insignificant operand. + + MK = MA(1) - MB(1) + IF (MK >= NDIG+2) THEN + DO J = 1, N1 + MWA(J) = MA(J) + ENDDO + MWA(N1+1) = 0 + IF (KROUND == 0 .OR. (KROUND == 2 .AND. JRSIGN == -1) .OR. & + (KROUND == -1 .AND. JRSIGN == 1)) THEN + MWA(N1) = MWA(N1) - 1 + GO TO 120 + ENDIF + KFLAG = 1 + RETURN + ENDIF + K = INT(MK) + IF (NGUARD <= 1) NMWA = N1 + 2 + +! Subtract MB from MA. + + KP1 = MIN(N1,K+1) + MWA(K+1) = 0 + DO J = 1, KP1 + MWA(J) = MA(J) + ENDDO + KP2 = K + 2 + +! (Inner Loop) + + DO J = KP2, N1 + MWA(J) = MA(J) - MB(J-K) + ENDDO + + N2 = NDIG + 2 + IF (N2-K <= 1) N2 = 2 + K + NK = MIN(NMWA,N1+K) + DO J = N2, NK + MWA(J) = -MB(J-K) + ENDDO + NK1 = NK + 1 + DO J = NK1, NMWA + MWA(J) = 0 + ENDDO + +! Normalize. Fix the sign of any negative digit. + + IF (K > 0) THEN + DO J = NMWA, KP2, -1 + IF (MWA(J) < 0) THEN + MWA(J) = MWA(J) + MBASE + MWA(J-1) = MWA(J-1) - 1 + ENDIF + ENDDO + + KPT = KP2 - 1 + 110 IF (MWA(KPT) < 0 .AND. KPT >= 3) THEN + MWA(KPT) = MWA(KPT) + MBASE + MWA(KPT-1) = MWA(KPT-1) - 1 + KPT = KPT - 1 + GO TO 110 + ENDIF + GO TO 130 + ENDIF + + 120 DO J = N1, 3, -1 + IF (MWA(J) < 0) THEN + MWA(J) = MWA(J) + MBASE + MWA(J-1) = MWA(J-1) - 1 + ENDIF + ENDDO + +! Shift left if there are any leading zeros in the mantissa. + + 130 DO J = 2, NMWA + IF (MWA(J) > 0) THEN + KSH = J - 2 + GO TO 140 + ENDIF + ENDDO + MWA(1) = 0 + RETURN + + 140 IF (KSH > 0) THEN + KL = NMWA - KSH + DO J = 2, KL + MWA(J) = MWA(J+KSH) + ENDDO + DO J = KL+1, NMWA + MWA(J) = 0 + ENDDO + MWA(1) = MWA(1) - KSH + IF (MK >= NDIG+2) THEN + MWA(N1) = MBASE - 1 + ENDIF + ENDIF + +! Round the result. + + MR = 2*MWA(NDIG+2) + 1 + IF (KROUND == -1 .OR. KROUND == 2) THEN + CALL FMRND(MWA,NDIG,NGUARD,0) + ELSE IF (MR >= MBASE) THEN + IF (MR-1 > MBASE .AND. MWA(N1) < MBASE-1) THEN + IF (KROUND /= 0 .OR. NCALL > 1) THEN + MWA(N1) = MWA(N1) + 1 + MWA(N1+1) = 0 + ENDIF + ELSE + CALL FMRND(MWA,NDIG,NGUARD,0) + ENDIF + ENDIF + +! See if the result is equal to one of the input arguments. + + IF (ABS(MA(1)-MB(1)) < NDIG) GO TO 150 + IF (ABS(MA(1)-MB(1)) > NDIG+1) THEN + KFLAG = 1 + GO TO 150 + ENDIF + + N2 = NDIG + 4 + DO J = 3, N1 + IF (MWA(N2-J) /= MA(N2-J)) GO TO 150 + ENDDO + IF (MWA(1) /= MA(1)) GO TO 150 + IF (MWA(2) /= ABS(MA(2))) GO TO 150 + KFLAG = 1 + + 150 RETURN + END SUBROUTINE FMADDN + + SUBROUTINE FMADDP(MA,MB,NGUARD,NMWA) + +! Internal addition routine. MWA = MA + MB +! The arguments are such that MA >= MB >= 0. + +! NMWA is the number of words in MWA that will be used. + + USE FMVALS + IMPLICIT NONE + + REAL (KIND(1.0D0)) :: MA(-1:LUNPCK),MB(-1:LUNPCK) + INTEGER NGUARD,NMWA + REAL (KIND(1.0D0)) :: MK,MKT,MR + INTEGER J,K,KP,KP2,KPT,KSHIFT,N1,N2,NK + + N1 = NDIG + 1 + +! Check for an insignificant operand. + + MK = MA(1) - MB(1) + IF (MK >= NDIG+1) THEN + MWA(1) = MA(1) + 1 + MWA(2) = 0 + DO J = 2, N1 + MWA(J+1) = MA(J) + ENDDO + MWA(N1+2) = 0 + IF ((KROUND == 2 .AND. JRSIGN == 1) .OR. & + (KROUND == -1 .AND. JRSIGN == -1)) THEN + MWA(N1+2) = 1 + GO TO 120 + ENDIF + KFLAG = 1 + RETURN + ENDIF + K = INT(MK) + +! Add MA and MB. + + MWA(1) = MA(1) + 1 + MWA(2) = 0 + DO J = 2, K+1 + MWA(J+1) = MA(J) + ENDDO + KP2 = K + 2 + +! (Inner Loop) + + DO J = KP2, N1 + MWA(J+1) = MA(J) + MB(J-K) + ENDDO + N2 = NDIG + 2 + NK = MIN(NMWA,N1+K) + DO J = N2, NK + MWA(J+1) = MB(J-K) + ENDDO + DO J = NK+1, NMWA + MWA(J+1) = 0 + ENDDO + +! Normalize. Fix any digit not less than MBASE. + + IF (K == NDIG) GO TO 140 + + IF (K > 0) THEN + DO J = N1+1, KP2, -1 + IF (MWA(J) >= MBASE) THEN + MWA(J) = MWA(J) - MBASE + MWA(J-1) = MWA(J-1) + 1 + ENDIF + ENDDO + + KPT = KP2 - 1 + 110 IF (MWA(KPT) >= MBASE .AND. KPT >= 3) THEN + MWA(KPT) = MWA(KPT) - MBASE + MWA(KPT-1) = MWA(KPT-1) + 1 + KPT = KPT - 1 + GO TO 110 + ENDIF + GO TO 120 + ENDIF + + DO J = N1+1, 3, -1 + IF (MWA(J) >= MBASE) THEN + MWA(J) = MWA(J) - MBASE + MWA(J-1) = MWA(J-1) + 1 + ENDIF + ENDDO + +! Shift right if the leading digit is not less than MBASE. + + 120 IF (MWA(2) >= MBASE) THEN + 130 KP = NMWA + 4 + DO J = 4, NMWA + MWA(KP-J) = MWA(KP-J-1) + ENDDO + MKT = AINT (MWA(2)/MBASE) + MWA(3) = MWA(2) - MKT*MBASE + MWA(2) = MKT + MWA(1) = MWA(1) + 1 + IF (MWA(2) >= MBASE) GO TO 130 + ENDIF + +! Round the result. + + 140 KSHIFT = 0 + IF (MWA(2) == 0) KSHIFT = 1 + MR = 2*MWA(NDIG+2+KSHIFT) + 1 + IF (KROUND == -1 .OR. KROUND == 2) THEN + CALL FMRND(MWA,NDIG,NGUARD,KSHIFT) + ELSE IF (MR >= MBASE) THEN + IF (MR-1 > MBASE .AND. MWA(N1+KSHIFT) < MBASE-1) THEN + IF (KROUND /= 0 .OR. NCALL > 1) THEN + MWA(N1+KSHIFT) = MWA(N1+KSHIFT) + 1 + MWA(N1+1+KSHIFT) = 0 + ENDIF + ELSE + CALL FMRND(MWA,NDIG,NGUARD,KSHIFT) + ENDIF + ENDIF + +! See if the result is equal to one of the input arguments. + + IF (ABS(MA(1)-MB(1)) < NDIG) GO TO 150 + IF (KSHIFT == 0) GO TO 150 + IF (ABS(MA(1)-MB(1)) > NDIG+1) THEN + KFLAG = 1 + GO TO 150 + ENDIF + + N2 = NDIG + 4 + DO J = 3, N1 + IF (MWA(N2-J+1) /= MA(N2-J)) GO TO 150 + ENDDO + IF (MWA(1) /= MA(1)+1) GO TO 150 + IF (MWA(3) /= ABS(MA(2))) GO TO 150 + KFLAG = 1 + + 150 RETURN + END SUBROUTINE FMADDP + + SUBROUTINE FMARGS(KROUTN,NARGS,MA,MB,KRESLT) + +! Check the input arguments to a routine for special cases. + +! KROUTN - Name of the subroutine that was called +! NARGS - The number of input arguments (1 or 2) +! MA - First input argument +! MB - Second input argument (if NARGS is 2) +! KRESLT - Result code returned to the calling routine. + +! Result codes: + +! 0 - Perform the normal operation +! 1 - The result is the first input argument +! 2 - The result is the second input argument +! 3 - The result is -OVERFLOW +! 4 - The result is +OVERFLOW +! 5 - The result is -UNDERFLOW +! 6 - The result is +UNDERFLOW +! 7 - The result is -1.0 +! 8 - The result is +1.0 +! 9 - The result is -pi/2 +! 10 - The result is +pi/2 +! 11 - The result is 0.0 +! 12 - The result is UNKNOWN +! 13 - The result is +pi +! 14 - The result is -pi/4 +! 15 - The result is +pi/4 + + USE FMVALS + IMPLICIT NONE + CHARACTER(6) :: KROUTN + REAL (KIND(1.0D0)) :: MA(-1:LUNPCK),MB(-1:LUNPCK) + INTEGER NARGS,KRESLT + + REAL (KIND(1.0D0)) :: MBS + INTEGER J,KWRNSV,NCATMA,NCATMB,NDS + +! These tables define the result codes to be returned for +! given values of the input argument(s). + +! For example, row 7 column 2 of this array initialization +! KADD(2,7) = 2 means that if the first argument in a call +! to FMADD is in category 7 ( -UNDERFLOW ) and the second +! argument is in category 2 ( near -OVERFLOW but +! representable ) then the result code is 2 ( the value +! of the sum is equal to the second input argument). +! See routine FMCAT for descriptions of the categories. + + INTEGER :: KADD(15,15) = RESHAPE( (/ & + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,12,12, & + 3, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0,12, & + 3, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 4, & + 3, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 4, & + 3, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 4, & + 3, 0, 0, 0, 0, 0,12, 1,12, 0, 0, 0, 0, 0, 4, & + 3, 2, 2, 2, 2,12,12, 5,12,12, 2, 2, 2, 2, 4, & + 3, 2, 2, 2, 2, 2, 5, 2, 6, 2, 2, 2, 2, 2, 4, & + 3, 2, 2, 2, 2,12,12, 6,12,12, 2, 2, 2, 2, 4, & + 3, 0, 0, 0, 0, 0,12, 1,12, 0, 0, 0, 0, 0, 4, & + 3, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 4, & + 3, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 4, & + 3, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 4, & + 12, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 4, & + 12,12, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4 /) & + , (/ 15,15 /) ) + + INTEGER :: KMPY(15,15) = RESHAPE( (/ & + 4, 4, 4, 4,12,12,12,11,12,12,12, 3, 3, 3, 3, & + 4, 0, 0, 0, 0, 0,12,11,12, 0, 0, 1, 0, 0, 3, & + 4, 0, 0, 0, 0, 0,12,11,12, 0, 0, 1, 0, 0, 3, & + 4, 0, 0, 0, 0, 0, 6,11, 5, 0, 0, 1, 0, 0, 3, & + 12, 0, 0, 0, 0, 0, 6,11, 5, 0, 0, 1, 0, 0,12, & + 12, 0, 0, 0, 0, 0, 6,11, 5, 0, 0, 1, 0, 0,12, & + 12,12,12, 6, 6, 6, 6,11, 5, 5, 5, 5,12,12,12, & + 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, & + 12,12,12, 5, 5, 5, 5,11, 6, 6, 6, 6,12,12,12, & + 12, 0, 0, 0, 0, 0, 5,11, 6, 0, 0, 1, 0, 0,12, & + 12, 0, 0, 0, 0, 0, 5,11, 6, 0, 0, 1, 0, 0,12, & + 3, 2, 2, 2, 2, 2, 5,11, 6, 2, 2, 2, 2, 2, 4, & + 3, 0, 0, 0, 0, 0,12,11,12, 0, 0, 1, 0, 0, 4, & + 3, 0, 0, 0, 0, 0,12,11,12, 0, 0, 1, 0, 0, 4, & + 3, 3, 3, 3,12,12,12,11,12,12,12, 4, 4, 4, 4 /) & + , (/ 15,15 /) ) + + INTEGER :: KDIV(15,15) = RESHAPE( (/ & + 12,12,12, 4, 4, 4, 4,12, 3, 3, 3, 3,12,12,12, & + 12, 0, 0, 0, 0, 0, 4,12, 3, 0, 0, 1, 0, 0,12, & + 12, 0, 0, 0, 0, 0, 4,12, 3, 0, 0, 1, 0, 0,12, & + 6, 0, 0, 0, 0, 0, 4,12, 3, 0, 0, 1, 0, 0, 5, & + 6, 0, 0, 0, 0, 0,12,12,12, 0, 0, 1, 0, 0, 5, & + 6, 0, 0, 0, 0, 0,12,12,12, 0, 0, 1, 0, 0, 5, & + 6, 6, 6, 6,12,12,12,12,12,12,12, 5, 5, 5, 5, & + 11,11,11,11,11,11,11,12,11,11,11,11,11,11,11, & + 5, 5, 5, 5,12,12,12,12,12,12,12, 6, 6, 6, 6, & + 5, 0, 0, 0, 0, 0,12,12,12, 0, 0, 1, 0, 0, 6, & + 5, 0, 0, 0, 0, 0,12,12,12, 0, 0, 1, 0, 0, 6, & + 5, 0, 0, 0, 0, 0, 3,12, 4, 0, 0, 1, 0, 0, 6, & + 12, 0, 0, 0, 0, 0, 3,12, 4, 0, 0, 1, 0, 0,12, & + 12, 0, 0, 0, 0, 0, 3,12, 4, 0, 0, 1, 0, 0,12, & + 12,12,12, 3, 3, 3, 3,12, 4, 4, 4, 4,12,12,12 /) & + , (/ 15,15 /) ) + + INTEGER :: KPWR(15,15) = RESHAPE( (/ & + 12,12, 0, 5,12,12,12, 8,12,12,12, 3, 0,12,12, & + 12,12, 0, 0,12,12,12, 8,12,12,12, 1, 0,12,12, & + 12,12, 0, 0,12,12,12, 8,12,12,12, 1, 0,12,12, & + 12,12, 0, 0,12,12,12, 8,12,12,12, 1, 0,12,12, & + 12,12, 0, 0,12,12,12, 8,12,12,12, 1, 0,12,12, & + 12,12, 0, 0,12,12,12, 8,12,12,12, 1, 0,12,12, & + 12,12, 0, 3,12,12,12, 8,12,12,12, 5, 0,12,12, & + 12,12,12,12,12,12,12,12,11,11,11,11,11,11,11, & + 4, 4, 4, 4,12,12,12, 8,12,12,12, 6, 6, 6, 6, & + 4, 4, 0, 0, 0, 8, 8, 8, 8, 0, 0, 1, 0, 6, 6, & + 4, 4, 0, 0, 0, 8, 8, 8, 8, 0, 0, 1, 0, 6, 6, & + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, & + 6, 6, 0, 0, 0, 8, 8, 8, 8, 8, 0, 1, 0, 4, 4, & + 6, 6, 0, 0, 0, 8, 8, 8, 8, 8, 0, 1, 0, 4, 4, & + 6, 6, 6, 6,12,12,12, 8,12,12,12, 4, 4, 4, 4 /) & + , (/ 15,15 /) ) + + INTEGER :: KSQRT(15) = (/ 12,12,12,12,12,12,12,11,12, 0, 0, 8, 0, 0,12 /) + INTEGER :: KEXP(15) = (/ 6, 6, 0, 0, 0, 8, 8, 8, 8, 8, 0, 0, 0, 4, 4 /) + INTEGER :: KLN(15) = (/ 12,12,12,12,12,12,12,12,12, 0, 0,11, 0, 0,12 /) + INTEGER :: KSIN(15) = (/ 12,12, 0, 0, 0, 0, 5,11, 6, 0, 0, 0, 0,12,12 /) + INTEGER :: KCOS(15) = (/ 12,12, 0, 0, 0, 8, 8, 8, 8, 8, 0, 0, 0,12,12 /) + INTEGER :: KTAN(15) = (/ 12,12, 0, 0, 0, 0, 5,11, 6, 0, 0, 0, 0,12,12 /) + INTEGER :: KASIN(15) = (/ 12,12,12, 9, 0, 0, 5,11, 6, 0, 0,10,12,12,12 /) + INTEGER :: KACOS(15) = (/ 12,12,12,13, 0,10,10,10,10,10, 0,11,12,12,12 /) + INTEGER :: KATAN(15) = (/ 9, 9, 0,14, 0, 0, 5,11, 6, 0, 0,15, 0,10,10 /) + INTEGER :: KSINH(15) = (/ 3, 3, 0, 0, 0, 1, 5,11, 6, 1, 0, 0, 0, 4, 4 /) + INTEGER :: KCOSH(15) = (/ 4, 4, 0, 0, 0, 8, 8, 8, 8, 8, 0, 0, 0, 4, 4 /) + INTEGER :: KTANH(15) = (/ 7, 7, 0, 0, 0, 1, 5,11, 6, 1, 0, 0, 0, 8, 8 /) + INTEGER :: KLG10(15) = (/ 12,12,12,12,12,12,12,12,12, 0, 0,11, 0, 0,12 /) + + KRESLT = 12 + KFLAG = -4 + IF (MA(1) == MUNKNO) RETURN + IF (NARGS == 2) THEN + IF (MB(1) == MUNKNO) RETURN + ENDIF + IF (MBLOGS /= MBASE) CALL FMCONS + KFLAG = 0 + NAMEST(NCALL) = KROUTN + +! Check the validity of parameters if this is a user call. + + IF (NCALL > 1 .AND. KDEBUG == 0) GO TO 130 + +! Check NDIG. + + IF (NDIG < 2 .OR. NDIG > NDIGMX) THEN + KFLAG = -1 + CALL FMWARN + NDS = NDIG + IF (NDIG < 2) NDIG = 2 + IF (NDIG > NDIGMX) NDIG = NDIGMX + WRITE (KW, & + "(' NDIG was',I10,'. It has been changed to',I10,'.')" & + ) NDS,NDIG + RETURN + ENDIF + +! Check MBASE. + + IF (MBASE < 2 .OR. MBASE > MXBASE) THEN + KFLAG = -2 + CALL FMWARN + MBS = MBASE + IF (MBASE < 2) MBASE = 2 + IF (MBASE > MXBASE) MBASE = MXBASE + WRITE (KW, & + "(' MBASE was',I10,'. It has been changed to',I10,'.')" & + ) INT(MBS),INT(MBASE) + CALL FMCONS + RETURN + ENDIF + +! Check exponent range. + + IF (MA(1) > MXEXP+1 .OR. MA(1) < -MXEXP) THEN + IF (ABS(MA(1)) /= MEXPOV .OR. ABS(MA(2)) /= 1) THEN + KFLAG = -3 + CALL FMWARN + RETURN + ENDIF + ENDIF + IF (NARGS == 2) THEN + IF (MB(1) > MXEXP+1 .OR. MB(1) < -MXEXP) THEN + IF (ABS(MB(1)) /= MEXPOV .OR. ABS(MB(2)) /= 1) THEN + KFLAG = -3 + CALL FMWARN + RETURN + ENDIF + ENDIF + ENDIF + +! Check for properly normalized digits in the +! input arguments. + + IF (ABS(MA(1)-INT(MA(1))) /= 0) KFLAG = 1 + IF (MA(2) <= (-1) .OR. MA(2) >= MBASE .OR. & + ABS(MA(2)-INT(MA(2))) /= 0) KFLAG = 2 + IF (KDEBUG == 0) GO TO 110 + DO J = 3, NDIG+1 + IF (MA(J) < 0 .OR. MA(J) >= MBASE .OR. & + ABS(MA(J)-INT(MA(J))) /= 0) THEN + KFLAG = J + GO TO 110 + ENDIF + ENDDO + 110 IF (KFLAG /= 0) THEN + J = KFLAG + KFLAG = -4 + KWRNSV = KWARN + IF (KWARN >= 2) KWARN = 1 + CALL FMWARN + KWARN = KWRNSV + IF (KWARN >= 1) THEN + WRITE (KW,*) ' First invalid array element: MA(', & + J,') = ',MA(J) + ENDIF + KFLAG = -4 + IF (KWARN >= 2) THEN + STOP + ENDIF + RETURN + ENDIF + IF (NARGS == 2) THEN + IF (ABS(MB(1)-INT(MB(1))) /= 0) KFLAG = 1 + IF (MB(2) <= (-1) .OR. MB(2) >= MBASE .OR. & + ABS(MB(2)-INT(MB(2))) /= 0) KFLAG = 2 + IF (KDEBUG == 0) GO TO 120 + DO J = 3, NDIG+1 + IF (MB(J) < 0 .OR. MB(J) >= MBASE .OR. & + ABS(MB(J)-INT(MB(J))) /= 0) THEN + KFLAG = J + GO TO 120 + ENDIF + ENDDO + 120 IF (KFLAG /= 0) THEN + J = KFLAG + KFLAG = -4 + KWRNSV = KWARN + IF (KWARN >= 2) KWARN = 1 + CALL FMWARN + KWARN = KWRNSV + IF (KWARN >= 1) THEN + WRITE (KW,*) ' First invalid array element: MB(', & + J,') = ',MB(J) + ENDIF + KFLAG = -4 + IF (KWARN >= 2) THEN + STOP + ENDIF + RETURN + ENDIF + ENDIF + +! Check for special cases. + + 130 CALL FMCAT(MA,NCATMA) + NCATMB = 0 + IF (NARGS == 2) CALL FMCAT(MB,NCATMB) + + IF (KROUTN == 'FMADD ') THEN + KRESLT = KADD(NCATMB,NCATMA) + GO TO 140 + ENDIF + + IF (KROUTN == 'FMSUB ') THEN + IF (NCATMB < 16) NCATMB = 16 - NCATMB + KRESLT = KADD(NCATMB,NCATMA) + GO TO 140 + ENDIF + + IF (KROUTN == 'FMMPY ') THEN + KRESLT = KMPY(NCATMB,NCATMA) + GO TO 140 + ENDIF + + IF (KROUTN == 'FMDIV ') THEN + KRESLT = KDIV(NCATMB,NCATMA) + GO TO 140 + ENDIF + + IF (KROUTN == 'FMPWR ') THEN + KRESLT = KPWR(NCATMB,NCATMA) + GO TO 140 + ENDIF + + IF (KROUTN == 'FMSQRT') THEN + KRESLT = KSQRT(NCATMA) + GO TO 140 + ENDIF + + IF (KROUTN == 'FMEXP ') THEN + KRESLT = KEXP(NCATMA) + GO TO 140 + ENDIF + + IF (KROUTN == 'FMLN ') THEN + KRESLT = KLN(NCATMA) + GO TO 140 + ENDIF + + IF (KROUTN == 'FMSIN ') THEN + KRESLT = KSIN(NCATMA) + GO TO 140 + ENDIF + + IF (KROUTN == 'FMCOS ') THEN + KRESLT = KCOS(NCATMA) + GO TO 140 + ENDIF + + IF (KROUTN == 'FMTAN ') THEN + KRESLT = KTAN(NCATMA) + GO TO 140 + ENDIF + + IF (KROUTN == 'FMASIN') THEN + KRESLT = KASIN(NCATMA) + IF ((NCATMA == 7.OR.NCATMA == 9) .AND. KRAD == 0) KRESLT = 12 + GO TO 140 + ENDIF + + IF (KROUTN == 'FMACOS') THEN + KRESLT = KACOS(NCATMA) + GO TO 140 + ENDIF + + IF (KROUTN == 'FMATAN') THEN + KRESLT = KATAN(NCATMA) + IF ((NCATMA == 7.OR.NCATMA == 9) .AND. KRAD == 0) KRESLT = 12 + GO TO 140 + ENDIF + + IF (KROUTN == 'FMSINH') THEN + KRESLT = KSINH(NCATMA) + GO TO 140 + ENDIF + + IF (KROUTN == 'FMCOSH') THEN + KRESLT = KCOSH(NCATMA) + GO TO 140 + ENDIF + + IF (KROUTN == 'FMTANH') THEN + KRESLT = KTANH(NCATMA) + GO TO 140 + ENDIF + + IF (KROUTN == 'FMLG10') THEN + KRESLT = KLG10(NCATMA) + GO TO 140 + ENDIF + + KRESLT = 0 + RETURN + + 140 IF (KRESLT == 12) THEN + KFLAG = -4 + CALL FMWARN + ENDIF + IF (KRESLT == 3 .OR. KRESLT == 4) THEN + IF (NCATMA == 1 .OR. NCATMA == 7 .OR. NCATMA == 9 .OR. & + NCATMA == 15 .OR. NCATMB == 1 .OR. NCATMB == 7 .OR. & + NCATMB == 9 .OR. NCATMB == 15) THEN + KFLAG = -5 + ELSE + KFLAG = -5 + CALL FMWARN + ENDIF + ENDIF + IF (KRESLT == 5 .OR. KRESLT == 6) THEN + IF (NCATMA == 1 .OR. NCATMA == 7 .OR. NCATMA == 9 .OR. & + NCATMA == 15 .OR. NCATMB == 1 .OR. NCATMB == 7 .OR. & + NCATMB == 9 .OR. NCATMB == 15) THEN + KFLAG = -6 + ELSE + KFLAG = -6 + CALL FMWARN + ENDIF + ENDIF + RETURN + END SUBROUTINE FMARGS + + SUBROUTINE FMASIN(MA,MB) + +! MB = ARCSIN(MA) + + USE FMVALS + IMPLICIT NONE + + REAL (KIND(1.0D0)) :: MA(-1:LUNPCK),MB(-1:LUNPCK) + REAL (KIND(1.0D0)) :: MACCA,MACMAX,MXSAVE + INTEGER J,K,KASAVE,KOVUN,KRESLT,NDSAVE + + IF (MBLOGS /= MBASE) CALL FMCONS + IF (ABS(MA(1)) > MEXPAB .OR. MA(1) > 0 .OR. MA(2) == 0) THEN + CALL FMENTR('FMASIN',MA,MA,1,1,MB,KRESLT,NDSAVE,MXSAVE,KASAVE, & + KOVUN) + IF (KRESLT /= 0) RETURN + ELSE + NCALL = NCALL + 1 + NAMEST(NCALL) = 'FMASIN' + IF (NTRACE /= 0) CALL FMNTR(2,MA,MA,1,1) + KOVUN = 0 + IF (MA(1) == MEXPOV .OR. MA(1) == MEXPUN) KOVUN = 1 + NDSAVE = NDIG + IF (NCALL == 1) THEN + K = MAX(NGRD52-1,2) + NDIG = MAX(NDIG+K,2) + IF (NDIG > NDG2MX) THEN + KFLAG = -9 + CALL FMWARN + NDIG = NDSAVE + KRESLT = 12 + CALL FMRSLT(MA,MA,MB,KRESLT) + IF (NTRACE /= 0) CALL FMNTR(1,MB,MB,1,1) + NCALL = NCALL - 1 + RETURN + ENDIF + ENDIF + KASAVE = KACCSW + KACCSW = 0 + MXSAVE = MXEXP + MXEXP = MXEXP2 + ENDIF + + MACCA = MA(0) + CALL FMEQ2(MA,MB,NDSAVE,NDIG) + MB(0) = NINT(NDIG*ALOGM2) + +! Use ASIN(X) = ATAN(X/SQRT(1-X*X)) + + CALL FMI2M(1,M05) + CALL FMSUB(M05,MB,M03) + CALL FMADD(M05,MB,M04) + CALL FMMPY_R2(M03,M04) + CALL FMSQRT_R1(M04) + CALL FMDIV_R1(MB,M04) + + CALL FMATAN(MB,M13) + CALL FMEQ(M13,MB) + +! Round the result and return. + + MACMAX = NINT((NDSAVE-1)*ALOGM2 + LOG(REAL(ABS(MB(2))+1))/0.69315) + MB(0) = MIN(MB(0),MACCA,MACMAX) + DO J = -1, NDIG+1 + M01(J) = MB(J) + ENDDO + CALL FMEXIT(M01,MB,NDSAVE,MXSAVE,KASAVE,KOVUN) + RETURN + END SUBROUTINE FMASIN + + SUBROUTINE FMATAN(MA,MB) + +! MB = ARCTAN(MA) + + USE FMVALS + IMPLICIT NONE + + DOUBLE PRECISION X,XM + REAL (KIND(1.0D0)) :: MA(-1:LUNPCK),MB(-1:LUNPCK) + INTEGER NSTACK(19) + REAL (KIND(1.0D0)) :: MA1,MACCA,MACMAX,MAS,MXSAVE + INTEGER J,K,KASAVE,KOVUN,KRESLT,KRSAVE,KST,KWRNSV,NDSAV1,NDSAVE, & + NDSV + + IF (MBLOGS /= MBASE) CALL FMCONS + IF (ABS(MA(1)) > MEXPAB .OR. MA(2) == 0) THEN + CALL FMENTR('FMATAN',MA,MA,1,1,MB,KRESLT,NDSAVE,MXSAVE,KASAVE, & + KOVUN) + IF (KRESLT /= 0) RETURN + ELSE + NCALL = NCALL + 1 + NAMEST(NCALL) = 'FMATAN' + IF (NTRACE /= 0) CALL FMNTR(2,MA,MA,1,1) + KOVUN = 0 + IF (MA(1) == MEXPOV .OR. MA(1) == MEXPUN) KOVUN = 1 + NDSAVE = NDIG + IF (NCALL == 1) THEN + K = MAX(NGRD52-1,2) + NDIG = MAX(NDIG+K,2) + IF (NDIG > NDG2MX) THEN + KFLAG = -9 + CALL FMWARN + NDIG = NDSAVE + KRESLT = 12 + CALL FMRSLT(MA,MA,MB,KRESLT) + IF (NTRACE /= 0) CALL FMNTR(1,MB,MB,1,1) + NCALL = NCALL - 1 + RETURN + ENDIF + ENDIF + KASAVE = KACCSW + KACCSW = 0 + MXSAVE = MXEXP + MXEXP = MXEXP2 + ENDIF + + MACCA = MA(0) + CALL FMEQ2(MA,M05,NDSAVE,NDIG) + M05(0) = NINT(NDIG*ALOGM2) + +! If MA >= 1 work with 1/MA. + + MA1 = MA(1) + MAS = MA(-1) + M05(-1) = 1 + IF (MA1 >= 1) THEN + CALL FMI2M(1,MB) + CALL FMDIV_R2(MB,M05) + ENDIF + + KRSAVE = KRAD + KRAD = 1 + KWRNSV = KWARN + + X = M05(1) + XM = MXBASE + +! In case pi has not been computed at the current precision +! and will be needed here, get it to full precision first +! to avoid repeated calls at increasing precision during +! Newton iteration. + + IF (MA1 >= 1 .OR. KRSAVE == 0) THEN + IF (MBSPI /= MBASE .OR. NDIGPI < NDIG) THEN + NDSV = NDIG + NDIG = MIN(NDIG+2,NDG2MX) + NCALL = NCALL + 1 + NAMEST(NCALL) = 'NOEQ ' + CALL FMPI(MPISAV) + NCALL = NCALL - 1 + NDIG = NDSV + ENDIF + ENDIF + +! If the argument is small, use the Taylor series, +! otherwise use Newton iteration. + + IF (X*DLOGMB < -5.0D0*LOG(XM)) THEN + KWARN = 0 + CALL FMEQ(M05,MB) + IF (MB(1) <= -NDIG) GO TO 120 + CALL FMSQR(M05,M06) + J = 3 + NDSAV1 = NDIG + + 110 CALL FMMPY_R1(M05,M06) + IF (M05(1) /= MUNKNO .AND. M05(2) /= 0) M05(-1) = -M05(-1) + CALL FMDIVI(M05,J,M03) + NDIG = NDSAV1 + CALL FMADD_R1(MB,M03) + IF (KFLAG /= 0) THEN + KFLAG = 0 + GO TO 120 + ENDIF + NDIG = NDSAV1 - INT((MB(1)-M03(1))) + IF (NDIG < 2) NDIG = 2 + J = J + 2 + GO TO 110 + ELSE + + CALL FMM2DP(M05,X) + X = ATAN(X) + CALL FMDPM(X,MB) + CALL FMDIG(NSTACK,KST) + +! Newton iteration. + + DO J = 1, KST + NDIG = NSTACK(J) + CALL FMSIN(MB,M06) + CALL FMSQR(M06,M03) + CALL FMI2M(1,M04) + CALL FMSUB_R2(M04,M03) + CALL FMSQRT(M03,M04) + CALL FMDIV_R2(M06,M04) + CALL FMSUB_R1(M04,M05) + CALL FMMPY_R2(M03,M04) + CALL FMSUB_R1(MB,M04) + ENDDO + MB(0) = NINT(NDIG*ALOGM2) + ENDIF + +! If MA >= 1 use pi/2 - ATAN(1/MA) + + 120 IF (MA1 >= 1) THEN + CALL FMDIVI(MPISAV,2,M06) + CALL FMSUB_R2(M06,MB) + ENDIF + +! Convert to degrees if necessary, round and return. + + KRAD = KRSAVE + IF (KRAD == 0) THEN + CALL FMMPYI_R1(MB,180) + CALL FMDIV_R1(MB,MPISAV) + ENDIF + IF (MB(1) /= MUNKNO .AND. MB(2) /= 0 .AND. MAS < 0) MB(-1) = -MB(-1) + + IF (KFLAG == 1) KFLAG = 0 + KWARN = KWRNSV + MACMAX = NINT((NDSAVE-1)*ALOGM2 + LOG(REAL(ABS(MB(2))+1))/0.69315) + MB(0) = MIN(MB(0),MACCA,MACMAX) + DO J = -1, NDIG+1 + M01(J) = MB(J) + ENDDO + CALL FMEXIT(M01,MB,NDSAVE,MXSAVE,KASAVE,KOVUN) + RETURN + END SUBROUTINE FMATAN + + SUBROUTINE FMATN2(MA,MB,MC) + +! MC = ATAN2(MA,MB) + +! MC is returned as the angle between -pi and pi (or -180 and 180 if +! degree mode is selected) for which TAN(MC) = MA/MB. MC is an angle +! for the point (MB,MA) in polar coordinates. + + USE FMVALS + IMPLICIT NONE + + REAL (KIND(1.0D0)) :: MA(-1:LUNPCK),MB(-1:LUNPCK),MC(-1:LUNPCK) + REAL (KIND(1.0D0)) :: MACCA,MACCB,MACMAX,MXEXP1,MXSAVE + INTEGER J,JQUAD,K,KASAVE,KOVUN,KRESLT,KWRNSV,NDSAVE + + IF (MBLOGS /= MBASE) CALL FMCONS + IF (ABS(MA(1)) > MEXPAB .OR. ABS(MB(1)) > MEXPAB) THEN + CALL FMENTR('FMATN2',MA,MB,2,1,MC,KRESLT,NDSAVE,MXSAVE,KASAVE, & + KOVUN) + IF (KRESLT /= 0) RETURN + ELSE + NCALL = NCALL + 1 + NAMEST(NCALL) = 'FMATN2' + IF (NTRACE /= 0) CALL FMNTR(2,MA,MB,2,1) + KOVUN = 0 + IF (MA(1) == MEXPOV .OR. MA(1) == MEXPUN) KOVUN = 1 + NDSAVE = NDIG + IF (NCALL == 1) THEN + K = MAX(NGRD52-1,2) + NDIG = MAX(NDIG+K,2) + IF (NDIG > NDG2MX) THEN + KFLAG = -9 + CALL FMWARN + NDIG = NDSAVE + KRESLT = 12 + CALL FMRSLT(MA,MB,MC,KRESLT) + IF (NTRACE /= 0) CALL FMNTR(1,MC,MC,1,1) + NCALL = NCALL - 1 + RETURN + ENDIF + ENDIF + KASAVE = KACCSW + KACCSW = 0 + MXSAVE = MXEXP + MXEXP = MXEXP2 + ENDIF + + KWRNSV = KWARN + KWARN = 0 + + MACCA = MA(0) + MACCB = MB(0) + CALL FMEQ2(MA,M01,NDSAVE,NDIG) + M01(0) = NINT(NDIG*ALOGM2) + CALL FMEQ2(MB,M02,NDSAVE,NDIG) + M02(0) = NINT(NDIG*ALOGM2) + +! Check for special cases. + + IF (MA(1) == MUNKNO .OR. MB(1) == MUNKNO .OR. & + (MA(2) == 0 .AND. MB(2) == 0)) THEN + CALL FMST2M('UNKNOWN',MC) + KFLAG = -4 + GO TO 110 + ENDIF + + IF (MB(2) == 0 .AND. MA(-1) > 0) THEN + IF (KRAD == 0) THEN + CALL FMI2M(90,MC) + ELSE + CALL FMPI(MC) + CALL FMDIVI_R1(MC,2) + ENDIF + GO TO 110 + ENDIF + + IF (MB(2) == 0 .AND. MA(-1) < 0) THEN + IF (KRAD == 0) THEN + CALL FMI2M(-90,MC) + ELSE + CALL FMPI(MC) + CALL FMDIVI_R1(MC,-2) + ENDIF + GO TO 110 + ENDIF + + MXEXP1 = INT(MXEXP2/2.01D0) + IF (MA(1) == MEXPOV .AND. MB(1) < MXEXP1-NDIG-2) THEN + IF (KRAD == 0) THEN + CALL FMI2M(90,MC) + ELSE + CALL FMPI(MC) + CALL FMDIVI_R1(MC,2) + ENDIF + IF (M01(-1) < 0) MC(-1) = -1 + GO TO 110 + ENDIF + + IF (MA(1) == MEXPUN .AND. (-MB(1)) < MXEXP1-NDIG-2 .AND. & + MB(-1) < 0) THEN + IF (KRAD == 0) THEN + CALL FMI2M(180,MC) + ELSE + CALL FMPI(MC) + ENDIF + IF (M01(-1) < 0) MC(-1) = -1 + GO TO 110 + ENDIF + + IF (MB(1) == MEXPOV .AND. MA(1) < MXEXP1-NDIG-2 .AND. & + MB(-1) < 0) THEN + IF (KRAD == 0) THEN + CALL FMI2M(180,MC) + ELSE + CALL FMPI(MC) + ENDIF + IF (M01(-1) < 0) MC(-1) = -1 + GO TO 110 + ENDIF + + IF (MB(1) == MEXPUN .AND. MA(2) == 0) THEN + IF (MB(-1) < 0) THEN + IF (KRAD == 0) THEN + CALL FMI2M(180,MC) + ELSE + CALL FMPI(MC) + ENDIF + ELSE + CALL FMI2M(0,MC) + ENDIF + GO TO 110 + ENDIF + + IF (MB(1) == MEXPUN .AND. (-MA(1)) < MXEXP1-NDIG-2) THEN + IF (KRAD == 0) THEN + CALL FMI2M(90,MC) + ELSE + CALL FMPI(MC) + CALL FMDIVI_R1(MC,2) + ENDIF + IF (M01(-1) < 0) MC(-1) = -1 + GO TO 110 + ENDIF + +! Determine the quadrant for the result, then use FMATAN. + + IF (MA(-1) >= 0 .AND. MB(-1) > 0) JQUAD = 1 + IF (MA(-1) >= 0 .AND. MB(-1) < 0) JQUAD = 2 + IF (MA(-1) < 0 .AND. MB(-1) < 0) JQUAD = 3 + IF (MA(-1) < 0 .AND. MB(-1) > 0) JQUAD = 4 + + CALL FMDIV(M01,M02,MC) + MC(-1) = 1 + CALL FMATAN(MC,M13) + CALL FMEQ(M13,MC) + + IF (JQUAD == 2 .OR. JQUAD == 3) THEN + IF (KRAD == 0) THEN + CALL FMI2M(180,M05) + CALL FMSUB_R2(M05,MC) + ELSE + CALL FMPI(M05) + CALL FMSUB_R2(M05,MC) + ENDIF + ENDIF + + IF ((JQUAD == 3 .OR. JQUAD == 4) .AND. MC(1) /= MUNKNO .AND. & + MC(2) /= 0) MC(-1) = -MC(-1) + +! Round the result and return. + + 110 IF (KFLAG == 1) KFLAG = 0 + KWARN = KWRNSV + MACMAX = NINT((NDSAVE-1)*ALOGM2 + LOG(REAL(ABS(MC(2))+1))/0.69315) + MC(0) = MIN(MC(0),MACCA,MACCB,MACMAX) + DO J = -1, NDIG+1 + M01(J) = MC(J) + ENDDO + CALL FMEXIT(M01,MC,NDSAVE,MXSAVE,KASAVE,KOVUN) + RETURN + END SUBROUTINE FMATN2 + + SUBROUTINE FMBIG(MA) + +! MA = The biggest representable FM number using the current base +! and precision. +! The smallest positive number is then 1.0/MA. +! Because of rounding, 1.0/(1.0/MA) will then overflow. + + USE FMVALS + IMPLICIT NONE + + REAL (KIND(1.0D0)) :: MA(-1:LUNPCK) + + INTEGER J,N1 + + NCALL = NCALL + 1 + NAMEST(NCALL) = 'FMBIG ' + + IF (MBLOGS /= MBASE) CALL FMCONS + KFLAG = 0 + N1 = NDIG + 1 + DO J = 2, N1 + MA(J) = MBASE - 1 + ENDDO + MA(1) = MXEXP + 1 + MA(0) = NINT(NDIG*ALOGM2) + MA(-1) = 1 + + IF (NTRACE /= 0) CALL FMNTR(1,MA,MA,1,1) + NCALL = NCALL - 1 + RETURN + END SUBROUTINE FMBIG + + SUBROUTINE FMCAT(MA,NCAT) + +! NCAT is returned as the category of MA. This is used by the various +! arithmetic routines to handle special cases such as: +! 'number greater than 1' + 'underflowed result' is the first argument, +! 'overflowed result' / 'overflowed result' is 'unknown'. + +! NCAT range + +! 1. -OV OV stands for overflowed results. +! 2. (-OV , -OVTH) ( MA(1) >= MAXEXP+2 ) +! 3. (-OVTH , -1) +! 4. -1 OVTH stands for a representable +! 5. (-1 , -UNTH) number near the overflow +! 6. (-UNTH , -UN) threshold. +! 7. -UN ( MA(1) >= MAXEXP-NDIG+1 ) +! 8. 0 +! 9. +UN UN stands for underflowed results. +! 10. (+UN , +UNTH) ( MA(1) <= -MAXEXP-1 ) +! 11. (+UNTH , +1) +! 12. +1 UNTH stands for a representable +! 13. (+1 , +OVTH) number near the underflow +! 14. (+OVTH , +OV) threshold. +! 15. +OV ( MA(1) <= -MAXEXP+NDIG-1 ) +! 16. UNKNOWN + + USE FMVALS + IMPLICIT NONE + + REAL (KIND(1.0D0)) :: MA(-1:LUNPCK) + INTEGER NCAT + + REAL (KIND(1.0D0)) :: MA2,MXEXP1 + INTEGER J,NLAST + +! Check for special symbols. + + NCAT = 16 + IF (MA(1) == MUNKNO) RETURN + + IF (MA(1) == MEXPOV) THEN + NCAT = 15 + IF (MA(-1) < 0) NCAT = 1 + RETURN + ENDIF + + IF (MA(1) == MEXPUN) THEN + NCAT = 9 + IF (MA(-1) < 0) NCAT = 7 + RETURN + ENDIF + + IF (MA(2) == 0) THEN + NCAT = 8 + RETURN + ENDIF + +! Check for +1 or -1. + + MA2 = ABS(MA(2)) + IF (MA(1) == 1 .AND. MA2 == 1) THEN + NLAST = NDIG + 1 + IF (NLAST >= 3) THEN + DO J = 3, NLAST + IF (MA(J) /= 0) GO TO 110 + ENDDO + ENDIF + NCAT = 12 + IF (MA(-1) < 0) NCAT = 4 + RETURN + ENDIF + + 110 MXEXP1 = INT(MXEXP) + IF (MA(1) >= MXEXP1-NDIG+2) THEN + NCAT = 14 + IF (MA(-1) < 0) NCAT = 2 + RETURN + ENDIF + + IF (MA(1) >= 1) THEN + NCAT = 13 + IF (MA(-1) < 0) NCAT = 3 + RETURN + ENDIF + + IF (MA(1) >= -MXEXP1+NDIG) THEN + NCAT = 11 + IF (MA(-1) < 0) NCAT = 5 + RETURN + ENDIF + + IF (MA(1) >= -MXEXP1) THEN + NCAT = 10 + IF (MA(-1) < 0) NCAT = 6 + RETURN + ENDIF + + RETURN + END SUBROUTINE FMCAT + + SUBROUTINE FMCHSH(MA,MB,MC) + +! MB = COSH(MA), MC = SINH(MA) + +! If both the hyperbolic sine and cosine are needed, this routine +! is faster than calling both FMCOSH and FMSINH. + +! MB and MC must be distinct arrays. + + USE FMVALS + IMPLICIT NONE + + REAL (KIND(1.0D0)) :: MA(-1:LUNPCK),MB(-1:LUNPCK),MC(-1:LUNPCK) + REAL (KIND(1.0D0)) :: MACCA,MACMAX,MAS,MXSAVE + INTEGER J,K,KASAVE,KOVUN,KRESLT,KWRNSV,NCSAVE,NDSAVE + + IF (MBLOGS /= MBASE) CALL FMCONS + MACCA = MA(0) + MAS = MA(-1) + IF (ABS(MA(1)) > MEXPAB) THEN + NCSAVE = NCALL + CALL FMENTR('FMCHSH',MA,MA,1,1,MB,KRESLT,NDSAVE,MXSAVE,KASAVE, & + KOVUN) + IF (MA(1) == MUNKNO) KOVUN = 2 + NCALL = NCSAVE + 1 + CALL FMEQ2(MA,M04,NDSAVE,NDIG) + M04(0) = NINT(NDIG*ALOGM2) + M04(-1) = 1 + CALL FMCOSH(M04,MB) + CALL FMSINH(M04,MC) + GO TO 110 + ELSE + NCALL = NCALL + 1 + NAMEST(NCALL) = 'FMCHSH' + IF (NTRACE /= 0) CALL FMNTR(2,MA,MA,1,1) + KOVUN = 0 + IF (MA(1) == MEXPOV .OR. MA(1) == MEXPUN) KOVUN = 1 + NDSAVE = NDIG + IF (NCALL == 1) THEN + K = MAX(NGRD52,2) + NDIG = MAX(NDIG+K,2) + IF (NDIG > NDG2MX) THEN + NCALL = NCALL - 1 + NDIG = NDSAVE + CALL FMEQ(MA,M04) + CALL FMCOSH(M04,MB) + CALL FMSINH(M04,MC) + KFLAG = -9 + RETURN + ENDIF + ENDIF + KASAVE = KACCSW + KACCSW = 0 + MXSAVE = MXEXP + MXEXP = MXEXP2 + ENDIF + + CALL FMEQ2(MA,M04,NDSAVE,NDIG) + M04(0) = NINT(NDIG*ALOGM2) + M04(-1) = 1 + + K = 1 + IF (M04(1) == 0 .AND. M04(2) /= 0) THEN + IF (MBASE/M04(2) >= 100) K = 2 + ENDIF + IF (M04(1) >= 0 .AND. M04(2) /= 0 .AND. K == 1) THEN + CALL FMCOSH(M04,MB) + IF (MB(1) > NDIG) THEN + CALL FMEQ(MB,MC) + GO TO 110 + ENDIF + CALL FMSQR(MB,M03) + CALL FMI2M(-1,M02) + CALL FMADD_R1(M03,M02) + CALL FMSQRT(M03,MC) + ELSE + CALL FMSINH(M04,MC) + CALL FMSQR(MC,M03) + CALL FMI2M(1,M02) + CALL FMADD_R1(M03,M02) + CALL FMSQRT(M03,MB) + ENDIF + +! Round and return. + + 110 MACMAX = NINT((NDSAVE-1)*ALOGM2 + LOG(REAL(ABS(MC(2))+1))/0.69315) + MC(0) = MIN(MC(0),MACCA,MACMAX) + IF (MAS < 0 .AND. MC(1) /= MUNKNO .AND. MC(2) /= 0) MC(-1) = -MC(-1) + CALL FMEQ2_R1(MC,NDIG,NDSAVE) + MACMAX = NINT((NDSAVE-1)*ALOGM2 + LOG(REAL(ABS(MB(2))+1))/0.69315) + MB(0) = MIN(MB(0),MACCA,MACMAX) + IF (KOVUN == 2) THEN + KWRNSV = KWARN + KWARN = 0 + ENDIF + DO J = -1, NDIG+1 + M01(J) = MB(J) + ENDDO + CALL FMEXIT(M01,MB,NDSAVE,MXSAVE,KASAVE,KOVUN) + IF (KOVUN == 2) THEN + KWARN = KWRNSV + ENDIF + IF (NTRACE /= 0) THEN + IF (ABS(NTRACE) >= 1 .AND. NCALL+1 <= LVLTRC) THEN + IF (NTRACE < 0) THEN + CALL FMNTRJ(MC,NDIG) + ELSE + CALL FMPRNT(MC) + ENDIF + ENDIF + ENDIF + RETURN + END SUBROUTINE FMCHSH + + FUNCTION FMCOMP(MA,LREL,MB) + +! Logical comparison of FM numbers MA and MB. + +! LREL is a CHARACTER description of the comparison to be done: +! LREL = 'EQ' returns FMCOMP = .TRUE. if MA == MB +! = 'NE', 'GE', 'GT', 'LE', 'LT' also work like a logical IF. +! = '==', '/=', '<', '<=', '>', '>=' may be used. + +! For comparisons involving 'UNKNOWN' or two identical special symbols +! such as +OVERFLOW,'EQ',+OVERFLOW, FMCOMP is returned FALSE and a +! KFLAG = -4 error condition is returned. + +! Some compilers object to functions with side effects such as +! changing KFLAG or other module FMVALS variables. Blocks of +! code that modify these variables are identified by: +! C DELETE START +! ... +! C DELETE STOP +! These may be removed or commented out to produce a function without +! side effects. This disables trace printing in FMCOMP, and error +! codes are not returned in KFLAG. + + USE FMVALS + IMPLICIT NONE + + LOGICAL FMCOMP + CHARACTER(*) :: LREL + CHARACTER(2) :: JREL + REAL (KIND(1.0D0)) :: MA(-1:LUNPCK),MB(-1:LUNPCK) + + INTEGER J,JCOMP,NLAST + +! DELETE START + NCALL = NCALL + 1 + NAMEST(NCALL) = 'FMCOMP' + + IF (NCALL <= LVLTRC .AND. ABS(NTRACE) >= 2) THEN + WRITE (KW,"(' Input to FMCOMP')") + + IF (NTRACE > 0) THEN + CALL FMPRNT(MA) + IF (INDEX('=/<>',LREL(1:1)) > 0) THEN + WRITE (KW,"(8X,A)") LREL + ELSE + WRITE (KW,"(7X,'.',A,'.')") LREL + ENDIF + CALL FMPRNT(MB) + ELSE + CALL FMNTRJ(MA,NDIG) + IF (INDEX('=/<>',LREL(1:1)) > 0) THEN + WRITE (KW,"(8X,A)") LREL + ELSE + WRITE (KW,"(7X,'.',A,'.')") LREL + ENDIF + CALL FMNTRJ(MB,NDIG) + ENDIF + ENDIF +! DELETE STOP + +! JCOMP will be 1 if MA > MB +! 2 if MA == MB +! 3 if MA < MB + +! Check for special cases. + + JREL = LREL + IF (LREL /= 'EQ' .AND. LREL /= 'NE' .AND. LREL /= 'LT' .AND. & + LREL /= 'GT' .AND. LREL /= 'LE' .AND. LREL /= 'GE') THEN + IF (LREL == 'eq' .OR. LREL == '==') THEN + JREL = 'EQ' + ELSE IF (LREL == 'ne' .OR. LREL == '/=') THEN + JREL = 'NE' + ELSE IF (LREL == 'lt' .OR. LREL == '<') THEN + JREL = 'LT' + ELSE IF (LREL == 'gt' .OR. LREL == '>') THEN + JREL = 'GT' + ELSE IF (LREL == 'le' .OR. LREL == '<=') THEN + JREL = 'LE' + ELSE IF (LREL == 'ge' .OR. LREL == '>=') THEN + JREL = 'GE' + ELSE + FMCOMP = .FALSE. +! DELETE START + KFLAG = -4 + IF (NCALL /= 1 .OR. KWARN <= 0) GO TO 120 +! DELETE STOP + IF (KWARN <= 0) GO TO 120 + WRITE (KW, & + "(/' Error of type KFLAG = -4 in FM package in'," // & + "' routine FMCOMP'//1X,A,' is not one of the six'," // & + "' recognized comparisons.'//' .FALSE. has been'," // & + "' returned.'/)" & + ) LREL + IF (KWARN >= 2) THEN + STOP + ENDIF + GO TO 120 + ENDIF + ENDIF + + IF (MA(1) == MUNKNO .OR. MB(1) == MUNKNO) THEN + FMCOMP = .FALSE. +! DELETE START + KFLAG = -4 +! DELETE STOP + GO TO 120 + ENDIF + + IF (ABS(MA(1)) == MEXPOV .AND. MA(1) == MB(1) .AND. & + MA(2) == MB(2) .AND. MA(-1) == MB(-1)) THEN + FMCOMP = .FALSE. +! DELETE START + KFLAG = -4 + IF (NCALL /= 1 .OR. KWARN <= 0) GO TO 120 +! DELETE STOP + IF (KWARN <= 0) GO TO 120 + WRITE (KW, & + "(/' Error of type KFLAG = -4 in FM package in routine'," // & + "' FMCOMP'//' Two numbers in the same overflow or'," // & + "' underflow category cannot be compared.'//" // & + "' .FALSE. has been returned.'/)" & + ) + IF (KWARN >= 2) THEN + STOP + ENDIF + GO TO 120 + ENDIF + +! Check for zero. + +! DELETE START + KFLAG = 0 +! DELETE STOP + IF (MA(2) == 0) THEN + JCOMP = 2 + IF (MB(2) == 0) GO TO 110 + IF (MB(-1) < 0) JCOMP = 1 + IF (MB(-1) > 0) JCOMP = 3 + GO TO 110 + ENDIF + IF (MB(2) == 0) THEN + JCOMP = 1 + IF (MA(-1) < 0) JCOMP = 3 + GO TO 110 + ENDIF +! Check for opposite signs. + + IF (MA(-1) > 0 .AND. MB(-1) < 0) THEN + JCOMP = 1 + GO TO 110 + ENDIF + IF (MB(-1) > 0 .AND. MA(-1) < 0) THEN + JCOMP = 3 + GO TO 110 + ENDIF + +! See which one is larger in absolute value. + + IF (MA(1) > MB(1)) THEN + JCOMP = 1 + GO TO 110 + ENDIF + IF (MB(1) > MA(1)) THEN + JCOMP = 3 + GO TO 110 + ENDIF + NLAST = NDIG + 1 + + DO J = 2, NLAST + IF (ABS(MA(J)) > ABS(MB(J))) THEN + JCOMP = 1 + GO TO 110 + ENDIF + IF (ABS(MB(J)) > ABS(MA(J))) THEN + JCOMP = 3 + GO TO 110 + ENDIF + ENDDO + + JCOMP = 2 + +! Now match the JCOMP value to the requested comparison. + + 110 IF (JCOMP == 1 .AND. MA(-1) < 0) THEN + JCOMP = 3 + ELSE IF (JCOMP == 3 .AND. MB(-1) < 0) THEN + JCOMP = 1 + ENDIF + + FMCOMP = .FALSE. + IF (JCOMP == 1 .AND. (JREL == 'GT' .OR. JREL == 'GE' .OR. & + JREL == 'NE')) FMCOMP = .TRUE. + + IF (JCOMP == 2 .AND. (JREL == 'EQ' .OR. JREL == 'GE' .OR. & + JREL == 'LE')) FMCOMP = .TRUE. + + IF (JCOMP == 3 .AND. (JREL == 'NE' .OR. JREL == 'LT' .OR. & + JREL == 'LE')) FMCOMP = .TRUE. + + 120 CONTINUE +! DELETE START + IF (NTRACE /= 0) THEN + IF (NCALL <= LVLTRC .AND. ABS(NTRACE) >= 1) THEN + IF (KFLAG == 0) THEN + WRITE (KW, & + "(' FMCOMP',15X,'Call level =',I2,5X,'MBASE ='," // & + "I10,5X,'NDIG =',I6)" & + ) NCALL,INT(MBASE),NDIG + ELSE + WRITE (KW, & + "(' FMCOMP',6X,'Call level =',I2,4X,'MBASE ='," // & + "I10,4X,'NDIG =',I6,4X,'KFLAG =',I3)" & + ) NCALL,INT(MBASE),NDIG,KFLAG + ENDIF + IF (FMCOMP) THEN + WRITE (KW,"(7X,'.TRUE.')") + ELSE + WRITE (KW,"(7X,'.FALSE.')") + ENDIF + ENDIF + ENDIF + NCALL = NCALL - 1 +! DELETE STOP + RETURN + END FUNCTION FMCOMP + + SUBROUTINE FMCONS + +! Set several saved machine precision constants. + + USE FMVALS + IMPLICIT NONE + + MBLOGS = MBASE + ALOGMB = LOG(REAL(MBASE)) + ALOGM2 = ALOGMB/LOG(2.0) + ALOGMX = LOG(REAL(MAXINT)) + ALOGMT = ALOGMB/LOG(10.0) + NGRD21 = INT(2.0/ALOGMT + 1.0) + NGRD52 = INT(5.0/ALOGMT + 2.0) + NGRD22 = INT(2.0/ALOGMT + 2.0) + IF (MBASE < 1000 .OR. KRPERF /= 0) THEN + NGRD21 = 2*NGRD21 + NGRD52 = 4*NGRD52 + NGRD22 = 2*NGRD22 + ENDIF + MEXPAB = AINT (MXEXP2/5) + DLOGMB = LOG(DBLE(MBASE)) + DLOGTN = LOG(10.0D0) + DLOGTW = LOG(2.0D0) + DPPI = 4.0D0*ATAN(1.0D0) + DLOGTP = LOG(2.0D0*DPPI) + DLOGPI = LOG(DPPI) + DLOGEB = -LOG(DPEPS)/DLOGMB + + RETURN + END SUBROUTINE FMCONS + + SUBROUTINE FMCOS(MA,MB) + +! MB = COS(MA) + + USE FMVALS + IMPLICIT NONE + + REAL (KIND(1.0D0)) :: MA(-1:LUNPCK),MB(-1:LUNPCK) + REAL (KIND(1.0D0)) :: MACCA,MACMAX,MXSAVE + INTEGER J,JCOS,JSIN,JSWAP,K,KASAVE,KOVUN,KRESLT,KWRNSV,NDSAVE,NDSV + + IF (MBLOGS /= MBASE) CALL FMCONS + IF (ABS(MA(1)) > MEXPAB .OR. MA(2) == 0) THEN + CALL FMENTR('FMCOS ',MA,MA,1,1,MB,KRESLT,NDSAVE,MXSAVE,KASAVE, & + KOVUN) + IF (KRESLT /= 0) RETURN + ELSE + NCALL = NCALL + 1 + NAMEST(NCALL) = 'FMCOS ' + IF (NTRACE /= 0) CALL FMNTR(2,MA,MA,1,1) + KOVUN = 0 + IF (MA(1) == MEXPOV .OR. MA(1) == MEXPUN) KOVUN = 1 + NDSAVE = NDIG + IF (NCALL == 1) THEN + K = MAX(NGRD52,2) + NDIG = MAX(NDIG+K,2) + IF (NDIG > NDG2MX) THEN + KFLAG = -9 + CALL FMWARN + NDIG = NDSAVE + KRESLT = 12 + CALL FMRSLT(MA,MA,MB,KRESLT) + IF (NTRACE /= 0) CALL FMNTR(1,MB,MB,1,1) + NCALL = NCALL - 1 + RETURN + ENDIF + ENDIF + KASAVE = KACCSW + KACCSW = 0 + MXSAVE = MXEXP + MXEXP = MXEXP2 + ENDIF + + MACCA = MA(0) + CALL FMEQ2(MA,MB,NDSAVE,NDIG) + MB(0) = NINT(NDIG*ALOGM2) + MB(-1) = 1 + CALL FMEQ(MB,MWE) + KWRNSV = KWARN + KWARN = 0 + +! Reduce the argument, convert to radians if the input is +! in degrees, and evaluate the function. + + CALL FMRDC(MB,JSIN,JCOS,JSWAP) + KWARN = KWRNSV + IF (MB(1) == MUNKNO) THEN + IF (KRAD /= 1 .OR. JSWAP == 1) THEN + CALL FMEQ(MWE,MB) + CALL FMRDC(MB,JSIN,JCOS,JSWAP) + GO TO 110 + ENDIF + IF (MBSPI /= MBASE .OR. NDIGPI < NDIG) THEN + NDSV = NDIG + NDIG = MIN(NDIG+2,NDG2MX) + NCALL = NCALL + 1 + NAMEST(NCALL) = 'NOEQ ' + CALL FMPI(MPISAV) + NCALL = NCALL - 1 + NDIG = NDSV + ENDIF + CALL FMDIV(MWE,MPISAV,M04) + CALL FMNINT(M04,M03) + CALL FMMPY(M03,MPISAV,M02) + CALL FMSUB_R2(MWE,M02) + IF (M02(2) == 0) CALL FMULP(MWE,M02) + CALL FMI2M(1,M04) + CALL FMSQR_R1(M02) + CALL FMDIVI_R1(M02,2) + CALL FMSUB_R2(M04,M02) + CALL FMSUB_R1(M02,M04) + IF (M02(2) == 0) THEN + CALL FMI2M(JCOS,MB) + ELSE + CALL FMEQ(MWE,MB) + CALL FMRDC(MB,JSIN,JCOS,JSWAP) + ENDIF + GO TO 110 + ENDIF + IF (KRAD == 0) THEN + IF (MBSPI /= MBASE .OR. NDIGPI < NDIG) THEN + NDSV = NDIG + NDIG = MIN(NDIG+2,NDG2MX) + NCALL = NCALL + 1 + NAMEST(NCALL) = 'NOEQ ' + CALL FMPI(MPISAV) + NCALL = NCALL - 1 + NDIG = NDSV + ENDIF + CALL FMMPY_R1(MB,MPISAV) + CALL FMDIVI_R1(MB,180) + ENDIF + IF (MB(1) /= MUNKNO) THEN + IF (JSWAP == 0) THEN + CALL FMCOS2(MB,M09) + CALL FMEQ(M09,MB) + ELSE + IF (MB(1) < 0 .OR. NDIG <= 50) THEN + CALL FMSIN2(MB,M09) + CALL FMEQ(M09,MB) + ELSE + CALL FMCOS2(MB,M09) + CALL FMEQ(M09,MB) + CALL FMI2M(1,M03) + CALL FMSQR_R1(MB) + CALL FMSUB_R2(M03,MB) + CALL FMSQRT_R1(MB) + ENDIF + ENDIF + ENDIF + +! Append the sign, round, and return. + + IF (MB(1) /= MUNKNO .AND. MB(2) /= 0 .AND. JCOS == -1) MB(-1) = -MB(-1) + 110 MACMAX = NINT((NDSAVE-1)*ALOGM2 + LOG(REAL(ABS(MB(2))+1))/0.69315) + MB(0) = MIN(MB(0),MACCA,MACMAX) + DO J = -1, NDIG+1 + M01(J) = MB(J) + ENDDO + CALL FMEXIT(M01,MB,NDSAVE,MXSAVE,KASAVE,KOVUN) + RETURN + END SUBROUTINE FMCOS + + SUBROUTINE FMCOS2(MA,MB) + +! Internal subroutine for MB = COS(MA) where 0 <= MA <= 1. + + USE FMVALS + IMPLICIT NONE + + REAL (KIND(1.0D0)) :: MA(-1:LUNPCK),MB(-1:LUNPCK) +! LJSUMS = 8*(LUNPCK+1) allows for up to eight concurrent +! sums. Increasing this value will begin to improve the +! speed of COS when the base is large and precision exceeds +! about 1,500 decimal digits. + + REAL (KIND(1.0D0)) :: MAXVAL + INTEGER J,J2,K,K2,KPT,KTWO,KWRNSV,L,L2,LARGE,N2,NBOT,NDSAV1, & + NDSAVE,NTERM + REAL ALOG2,ALOGT,B,T,TJ + + IF (MBLOGS /= MBASE) CALL FMCONS + IF (MA(2) == 0) THEN + CALL FMI2M(1,MB) + RETURN + ENDIF + NDSAVE = NDIG + KWRNSV = KWARN + KWARN = 0 + +! Use the direct series +! COS(X) = 1 - X**2/2! + X**4/4! - ... + +! The argument will be divided by 2**K2 before the series +! is summed. The series will be added as J2 concurrent +! series. The approximately optimal values of K2 and J2 +! are now computed to try to minimize the time required. +! N2/2 is the approximate number of terms of the series +! that will be needed, and L2 guard digits will be carried. + +! Since X is small when the series is summed, COS(X) - 1 +! is computed. Then a version of the recovery formula can +! be used that does not suffer from severe cancellation. + + B = REAL(MBASE) + K = NGRD52 + T = MAX(NDIG-K,2) + ALOG2 = LOG(2.0) + ALOGT = LOG(T) + TJ = 0.03*ALOGMB*T**0.3333 + 1.85 + J2 = INT(TJ) + J2 = MAX(1,MIN(J2,LJSUMS/NDG2MX)) + K2 = INT(0.5*SQRT(T*ALOGMB/TJ) + 2.8) + + L = INT(-(REAL(MA(1))*ALOGMB+LOG(REAL(MA(2))/B + & + REAL(MA(3))/(B*B)))/ALOG2 - 0.3) + K2 = K2 - L + IF (L < 0) L = 0 + IF (K2 < 0) THEN + K2 = 0 + J2 = INT(.43*SQRT(T*ALOGMB/(ALOGT+REAL(L)*ALOG2)) + .33) + ENDIF + IF (J2 <= 1) J2 = 1 + + N2 = INT(T*ALOGMB/(ALOGT+REAL(L)*ALOG2)) + L2 = INT(LOG(REAL(N2)+2.0**K2)/ALOGMB) + NDIG = NDIG + L2 + IF (NDIG > NDG2MX) THEN + IF (NCALL == 1) THEN + KFLAG = -9 + CALL FMWARN + NDIG = NDSAVE + CALL FMST2M('UNKNOWN',MB) + KWARN = KWRNSV + RETURN + ELSE + NDIG = NDG2MX + ENDIF + ENDIF + NDSAV1 = NDIG + +! Divide the argument by 2**K2. + + CALL FMEQ2(MA,M02,NDSAVE,NDIG) + KTWO = 1 + MAXVAL = MXBASE/2 + IF (K2 > 0) THEN + DO J = 1, K2 + KTWO = 2*KTWO + IF (KTWO > MAXVAL) THEN + CALL FMDIVI_R1(M02,KTWO) + KTWO = 1 + ENDIF + ENDDO + IF (KTWO > 1) CALL FMDIVI_R1(M02,KTWO) + ENDIF + +! Split into J2 concurrent sums and reduce NDIG while +! computing each term in the sum as the terms get smaller. + + CALL FMSQR_R1(M02) + CALL FMEQ(M02,M03) + IF (M03(1) /= MUNKNO .AND. M03(2) /= 0) M03(-1) = -M03(-1) + NTERM = 2 + DO J = 1, J2 + NBOT = NTERM*(NTERM-1) + CALL FMDIVI_R1(M03,NBOT) + NTERM = NTERM + 2 + KPT = (J-1)*(NDIG+3) + CALL FMEQ(M03,MJSUMS(KPT-1)) + IF (M03(1) /= MUNKNO .AND. M03(2) /= 0) M03(-1) = -M03(-1) + ENDDO + IF (M02(1) < -NDIG) GO TO 120 + CALL FMIPWR(M02,J2,MB) + + 110 CALL FMMPY_R1(M03,MB) + LARGE = INT(INTMAX/NTERM) + DO J = 1, J2 + NBOT = NTERM*(NTERM-1) + IF (NTERM > LARGE .OR. NBOT > MXBASE) THEN + CALL FMDIVI_R1(M03,NTERM) + NBOT = NTERM - 1 + CALL FMDIVI_R1(M03,NBOT) + ELSE + CALL FMDIVI_R1(M03,NBOT) + ENDIF + KPT = (J-1)*(NDSAV1+3) + NDIG = NDSAV1 + CALL FMADD_R1(MJSUMS(KPT-1),M03) + IF (KFLAG /= 0) GO TO 120 + NDIG = NDSAV1 - INT(MJSUMS(KPT+1)-M03(1)) + IF (NDIG < 2) NDIG = 2 + IF (M03(1) /= MUNKNO .AND. M03(2) /= 0) M03(-1) = -M03(-1) + NTERM = NTERM + 2 + ENDDO + GO TO 110 + +! Next put the J2 separate sums back together. + + 120 KFLAG = 0 + KPT = (J2-1)*(NDIG+3) + CALL FMEQ(MJSUMS(KPT-1),MB) + IF (J2 >= 2) THEN + DO J = 2, J2 + CALL FMMPY_R2(M02,MB) + KPT = (J2-J)*(NDIG+3) + CALL FMADD_R1(MB,MJSUMS(KPT-1)) + ENDDO + ENDIF + +! Reverse the effect of reducing the argument to +! compute COS(MA). + + NDIG = NDSAV1 + IF (K2 > 0) THEN + IF (NDSAVE <= 20) THEN + CALL FMI2M(2,M02) + DO J = 1, K2 + CALL FMADD(MB,M02,M03) + CALL FMMPY_R2(MB,M03) + CALL FMADD(M03,M03,MB) + ENDDO + ELSE + DO J = 1, K2 + CALL FMSQR(MB,M03) + CALL FMADD(MB,MB,M02) + CALL FMADD_R1(M03,M02) + CALL FMADD(M03,M03,MB) + ENDDO + ENDIF + ENDIF + CALL FMI2M(1,M03) + CALL FMADD_R2(M03,MB) + + CALL FMEQ2_R1(MB,NDSAV1,NDSAVE) + NDIG = NDSAVE + KWARN = KWRNSV + + RETURN + END SUBROUTINE FMCOS2 + + SUBROUTINE FMCOSH(MA,MB) + +! MB = COSH(MA) + + USE FMVALS + IMPLICIT NONE + + REAL (KIND(1.0D0)) :: MA(-1:LUNPCK),MB(-1:LUNPCK) + REAL (KIND(1.0D0)) :: MACCA,MACMAX,MXSAVE + INTEGER J,K,KASAVE,KOVUN,KRESLT,NDSAVE,NMETHD + + IF (MBLOGS /= MBASE) CALL FMCONS + IF (ABS(MA(1)) > MEXPAB) THEN + CALL FMENTR('FMCOSH',MA,MA,1,1,MB,KRESLT,NDSAVE,MXSAVE,KASAVE, & + KOVUN) + IF (KRESLT /= 0) RETURN + ELSE + NCALL = NCALL + 1 + NAMEST(NCALL) = 'FMCOSH' + IF (NTRACE /= 0) CALL FMNTR(2,MA,MA,1,1) + KOVUN = 0 + IF (MA(1) == MEXPOV .OR. MA(1) == MEXPUN) KOVUN = 1 + NDSAVE = NDIG + IF (NCALL == 1) THEN + K = MAX(NGRD52,2) + NDIG = MAX(NDIG+K,2) + IF (NDIG > NDG2MX) THEN + KFLAG = -9 + CALL FMWARN + NDIG = NDSAVE + KRESLT = 12 + CALL FMRSLT(MA,MA,MB,KRESLT) + IF (NTRACE /= 0) CALL FMNTR(1,MB,MB,1,1) + NCALL = NCALL - 1 + RETURN + ENDIF + ENDIF + KASAVE = KACCSW + KACCSW = 0 + MXSAVE = MXEXP + MXEXP = MXEXP2 + ENDIF + + MACCA = MA(0) + CALL FMEQ2(MA,MB,NDSAVE,NDIG) + MB(0) = NINT(NDIG*ALOGM2) + MB(-1) = 1 + IF (MA(2) == 0) THEN + CALL FMI2M(1,MB) + GO TO 120 + ENDIF + +! Use a series for small arguments, FMEXP for large ones. + + IF (MB(1) == MUNKNO) GO TO 120 + IF (MBASE > 99) THEN + IF (MB(1) <= 0) THEN + NMETHD = 1 + ELSE IF (MB(1) >= 2) THEN + NMETHD = 2 + ELSE IF (ABS(MB(2)) < 10) THEN + NMETHD = 1 + ELSE + NMETHD = 2 + ENDIF + ELSE + IF (MB(1) <= 0) THEN + NMETHD = 1 + ELSE + NMETHD = 2 + ENDIF + ENDIF + + IF (NMETHD == 2) GO TO 110 + CALL FMCSH2(MB,M09) + CALL FMEQ(M09,MB) + GO TO 120 + + 110 CALL FMEXP(MB,M12) + CALL FMEQ(M12,MB) + IF (MB(1) == MEXPOV) THEN + GO TO 120 + ELSE IF (MB(1) == MEXPUN) THEN + MB(1) = MEXPOV + GO TO 120 + ENDIF + IF (INT(MB(1)) <= (NDIG+1)/2) THEN + CALL FMI2M(1,M01) + CALL FMDIV_R1(M01,MB) + CALL FMADD_R1(MB,M01) + ENDIF + CALL FMDIVI_R1(MB,2) + +! Round and return. + + 120 MACMAX = NINT((NDSAVE-1)*ALOGM2 + LOG(REAL(ABS(MB(2))+1))/0.69315) + MB(0) = MIN(MB(0),MACCA,MACMAX) + DO J = -1, NDIG+1 + M01(J) = MB(J) + ENDDO + CALL FMEXIT(M01,MB,NDSAVE,MXSAVE,KASAVE,KOVUN) + RETURN + END SUBROUTINE FMCOSH + + SUBROUTINE FMCSH2(MA,MB) + +! Internal subroutine for MB = COSH(MA). + + USE FMVALS + IMPLICIT NONE + + REAL (KIND(1.0D0)) :: MA(-1:LUNPCK),MB(-1:LUNPCK) +! LJSUMS = 8*(LUNPCK+1) allows for up to eight concurrent +! sums. Increasing this value will begin to improve the +! speed of COSH when the base is large and precision exceeds +! about 1,500 decimal digits. + + REAL (KIND(1.0D0)) :: MAXVAL + INTEGER J,J2,K,K2,KPT,KTWO,KWRNSV,L,L2,LARGE,N2,NBOT,NDSAV1, & + NDSAVE,NTERM + REAL ALOG2,ALOGT,B,T,TJ + + IF (MBLOGS /= MBASE) CALL FMCONS + IF (MA(2) == 0) THEN + CALL FMI2M(1,MB) + RETURN + ENDIF + NDSAVE = NDIG + KWRNSV = KWARN + KWARN = 0 + +! Use the direct series +! COSH(X) = 1 + X**2/2! + X**4/4! - ... + +! The argument will be divided by 2**K2 before the series +! is summed. The series will be added as J2 concurrent +! series. The approximately optimal values of K2 and J2 +! are now computed to try to minimize the time required. +! N2/2 is the approximate number of terms of the series +! that will be needed, and L2 guard digits will be carried. + +! Since X is small when the series is summed, COSH(X) - 1 +! is computed. Then a version of the recovery formula can +! be used that does not suffer from severe cancellation. + + B = REAL(MBASE) + K = NGRD52 + T = MAX(NDIG-K,2) + ALOG2 = LOG(2.0) + ALOGT = LOG(T) + TJ = 0.03*ALOGMB*T**0.3333 + 1.85 + J2 = INT(TJ) + J2 = MAX(1,MIN(J2,LJSUMS/NDG2MX)) + K2 = INT(0.5*SQRT(T*ALOGMB/TJ) + 2.8) + + L = INT(-(REAL(MA(1))*ALOGMB+LOG(REAL(MA(2))/B + & + REAL(MA(3))/(B*B)))/ALOG2 - 0.3) + K2 = K2 - L + IF (L < 0) L = 0 + IF (K2 < 0) THEN + K2 = 0 + J2 = INT(.43*SQRT(T*ALOGMB/(ALOGT+REAL(L)*ALOG2)) + .33) + ENDIF + IF (J2 <= 1) J2 = 1 + + N2 = INT(T*ALOGMB/(ALOGT+REAL(L)*ALOG2)) + L2 = INT(LOG(REAL(N2)+2.0**K2)/ALOGMB) + NDIG = NDIG + L2 + IF (NDIG > NDG2MX) THEN + IF (NCALL == 1) THEN + KFLAG = -9 + CALL FMWARN + NDIG = NDSAVE + CALL FMST2M('UNKNOWN',MB) + KWARN = KWRNSV + RETURN + ELSE + NDIG = NDG2MX + ENDIF + ENDIF + NDSAV1 = NDIG + CALL FMEQ2(MA,M02,NDSAVE,NDIG) + +! Divide the argument by 2**K2. + + KTWO = 1 + MAXVAL = MXBASE/2 + IF (K2 > 0) THEN + DO J = 1, K2 + KTWO = 2*KTWO + IF (KTWO > MAXVAL) THEN + CALL FMDIVI_R1(M02,KTWO) + KTWO = 1 + ENDIF + ENDDO + IF (KTWO > 1) CALL FMDIVI_R1(M02,KTWO) + ENDIF + +! Split into J2 concurrent sums and reduce NDIG while +! computing each term in the sum as the terms get smaller. + + CALL FMSQR_R1(M02) + CALL FMEQ(M02,M03) + NTERM = 2 + DO J = 1, J2 + NBOT = NTERM*(NTERM-1) + CALL FMDIVI_R1(M03,NBOT) + NTERM = NTERM + 2 + KPT = (J-1)*(NDIG+3) + CALL FMEQ(M03,MJSUMS(KPT-1)) + ENDDO + IF (M02(1) < -NDIG) GO TO 120 + CALL FMIPWR(M02,J2,MB) + + 110 CALL FMMPY_R1(M03,MB) + LARGE = INT(INTMAX/NTERM) + DO J = 1, J2 + NBOT = NTERM*(NTERM-1) + IF (NTERM > LARGE .OR. NBOT > MXBASE) THEN + CALL FMDIVI_R1(M03,NTERM) + NBOT = NTERM - 1 + CALL FMDIVI_R1(M03,NBOT) + ELSE + CALL FMDIVI_R1(M03,NBOT) + ENDIF + KPT = (J-1)*(NDSAV1+3) + NDIG = NDSAV1 + CALL FMADD_R1(MJSUMS(KPT-1),M03) + IF (KFLAG /= 0) GO TO 120 + NDIG = NDSAV1 - INT(MJSUMS(KPT+1)-M03(1)) + IF (NDIG < 2) NDIG = 2 + NTERM = NTERM + 2 + ENDDO + GO TO 110 + +! Next put the J2 separate sums back together. + + 120 KFLAG = 0 + KPT = (J2-1)*(NDIG+3) + CALL FMEQ(MJSUMS(KPT-1),MB) + IF (J2 >= 2) THEN + DO J = 2, J2 + CALL FMMPY_R2(M02,MB) + KPT = (J2-J)*(NDIG+3) + CALL FMADD_R1(MB,MJSUMS(KPT-1)) + ENDDO + ENDIF + +! Reverse the effect of reducing the argument to +! compute COSH(MA). + + NDIG = NDSAV1 + IF (K2 > 0) THEN + IF (NDSAVE <= 20) THEN + CALL FMI2M(2,M02) + DO J = 1, K2 + CALL FMADD(MB,M02,M03) + CALL FMMPY_R2(MB,M03) + CALL FMADD(M03,M03,MB) + ENDDO + ELSE + DO J = 1, K2 + CALL FMSQR(MB,M03) + CALL FMADD(MB,MB,M02) + CALL FMADD_R1(M03,M02) + CALL FMADD(M03,M03,MB) + ENDDO + ENDIF + ENDIF + CALL FMI2M(1,M03) + CALL FMADD_R2(M03,MB) + + CALL FMEQ2_R1(MB,NDSAV1,NDSAVE) + NDIG = NDSAVE + KWARN = KWRNSV + + RETURN + END SUBROUTINE FMCSH2 + + SUBROUTINE FMCSSN(MA,MB,MC) + +! MB = COS(MA), MC = SIN(MA) + +! If both the sine and cosine are needed, this routine is faster +! than calling both FMCOS and FMSIN. + +! MB and MC must be distinct arrays. + + USE FMVALS + IMPLICIT NONE + + REAL (KIND(1.0D0)) :: MA(-1:LUNPCK),MB(-1:LUNPCK),MC(-1:LUNPCK) + REAL (KIND(1.0D0)) :: MACCA,MACMAX,MAS,MXSAVE + INTEGER J,JCOS,JSIN,JSWAP,K,KASAVE,KOVUN,KRESLT,KWRNSV,NCSAVE, & + NDSAVE,NDSV + + IF (MBLOGS /= MBASE) CALL FMCONS + MACCA = MA(0) + MAS = MA(-1) + IF (ABS(MA(1)) > MEXPAB .OR. MA(2) == 0) THEN + NCSAVE = NCALL + CALL FMENTR('FMCSSN',MA,MA,1,1,MB,KRESLT,NDSAVE,MXSAVE,KASAVE, & + KOVUN) + IF (MA(1) == MUNKNO) KOVUN = 2 + NCALL = NCSAVE + 1 + CALL FMEQ2(MA,M05,NDSAVE,NDIG) + M05(0) = NINT(NDIG*ALOGM2) + M05(-1) = 1 + CALL FMCOS(M05,MB) + CALL FMSIN(M05,MC) + GO TO 110 + ELSE + NCALL = NCALL + 1 + NAMEST(NCALL) = 'FMCSSN' + IF (NTRACE /= 0) CALL FMNTR(2,MA,MA,1,1) + KOVUN = 0 + IF (MA(1) == MEXPOV .OR. MA(1) == MEXPUN) KOVUN = 1 + NDSAVE = NDIG + IF (NCALL == 1) THEN + K = MAX(NGRD52,2) + NDIG = MAX(NDIG+K,2) + IF (NDIG > NDG2MX) THEN + NCALL = NCALL - 1 + NDIG = NDSAVE + CALL FMEQ(MA,M05) + CALL FMCOS(M05,MB) + CALL FMSIN(M05,MC) + KFLAG = -9 + RETURN + ENDIF + ENDIF + KASAVE = KACCSW + KACCSW = 0 + MXSAVE = MXEXP + MXEXP = MXEXP2 + ENDIF + + IF (MA(2) == 0) THEN + CALL FMI2M(1,MB) + CALL FMI2M(0,MC) + GO TO 110 + ENDIF + + CALL FMEQ2(MA,MB,NDSAVE,NDIG) + MB(0) = NINT(NDIG*ALOGM2) + MB(-1) = 1 + CALL FMEQ(MB,MWE) + +! Reduce the argument, convert to radians if the input is +! in degrees, and evaluate the functions. + + CALL FMRDC(MB,JSIN,JCOS,JSWAP) + IF (MB(1) == MUNKNO) THEN + CALL FMCOS(MWE,MB) + CALL FMSIN(MWE,MC) + GO TO 110 + ENDIF + IF (KRAD == 0) THEN + IF (MBSPI /= MBASE .OR. NDIGPI < NDIG) THEN + NDSV = NDIG + NDIG = MIN(NDIG+2,NDG2MX) + NCALL = NCALL + 1 + NAMEST(NCALL) = 'NOEQ ' + CALL FMPI(MPISAV) + NCALL = NCALL - 1 + NDIG = NDSV + ENDIF + CALL FMMPY_R1(MB,MPISAV) + CALL FMDIVI_R1(MB,180) + ENDIF + IF (MB(1) /= MUNKNO) THEN + IF (JSWAP == 0) THEN + IF (MB(1) < 0) THEN + CALL FMSIN2(MB,MC) + MC(-1) = JSIN*MC(-1) + CALL FMSQR(MC,M03) + CALL FMI2M(1,M02) + CALL FMSUB_R2(M02,M03) + CALL FMSQRT(M03,MB) + MB(-1) = JCOS*MB(-1) + ELSE + CALL FMCOS2(MB,M09) + CALL FMEQ(M09,MB) + MB(-1) = JCOS*MB(-1) + CALL FMSQR(MB,M03) + CALL FMI2M(1,M02) + CALL FMSUB_R2(M02,M03) + CALL FMSQRT(M03,MC) + MC(-1) = JSIN*MC(-1) + ENDIF + ELSE + IF (MB(1) < 0) THEN + CALL FMSIN2(MB,M09) + CALL FMEQ(M09,MB) + MB(-1) = JCOS*MB(-1) + CALL FMSQR(MB,M03) + CALL FMI2M(1,M02) + CALL FMSUB_R2(M02,M03) + CALL FMSQRT(M03,MC) + MC(-1) = JSIN*MC(-1) + ELSE + CALL FMCOS2(MB,MC) + MC(-1) = JSIN*MC(-1) + CALL FMSQR(MC,M03) + CALL FMI2M(1,M02) + CALL FMSUB_R2(M02,M03) + CALL FMSQRT(M03,MB) + MB(-1) = JCOS*MB(-1) + ENDIF + ENDIF + ELSE + CALL FMEQ(MB,MC) + ENDIF + +! Round and return. + + 110 MACMAX = NINT((NDSAVE-1)*ALOGM2 + LOG(REAL(ABS(MC(2))+1))/0.69315) + MC(0) = MIN(MC(0),MACCA,MACMAX) + IF (MAS < 0 .AND. MC(1) /= MUNKNO .AND. MC(2) /= 0) MC(-1) = -MC(-1) + CALL FMEQ2_R1(MC,NDIG,NDSAVE) + MB(0) = MIN(MB(0),MACCA,MACMAX) + IF (KOVUN == 2) THEN + KWRNSV = KWARN + KWARN = 0 + ENDIF + DO J = -1, NDIG+1 + M01(J) = MB(J) + ENDDO + CALL FMEXIT(M01,MB,NDSAVE,MXSAVE,KASAVE,KOVUN) + IF (KOVUN == 2) THEN + KWARN = KWRNSV + ENDIF + IF (NTRACE /= 0) THEN + IF (ABS(NTRACE) >= 1 .AND. NCALL+1 <= LVLTRC) THEN + IF (NTRACE < 0) THEN + CALL FMNTRJ(MC,NDIG) + ELSE + CALL FMPRNT(MC) + ENDIF + ENDIF + ENDIF + RETURN + END SUBROUTINE FMCSSN + + SUBROUTINE FMDBL(A,B,C) + +! C = A + B. All are double precision. This routine tries to +! force the compiler to round C to double precision accuracy. +! Some compilers allow double precision loops like the ones in +! FMSET and FMDM to be done in extended precision, which defeats +! the routine's attempt to determine double precision accuracy. +! This can lead to doing too few Newton steps and failing to +! get sufficient accuracy in several FM routines. + + USE FMVALS + IMPLICIT NONE + DOUBLE PRECISION A,B,C + C = A + B + RETURN + END SUBROUTINE FMDBL + + SUBROUTINE FMDIG(NSTACK,KST) + +! Compute the number of intermediate digits to be used in Newton +! iteration. This assumes that a starting approximation that is +! accurate to double precision is used, and the root is simple. + +! KST is the number of iterations needed for final accuracy NDIG. +! NSTACK(J) holds the value of NDIG to be used for the +! Jth iteration. + + USE FMVALS + IMPLICIT NONE + + INTEGER NSTACK(19),KST + + DOUBLE PRECISION Y + INTEGER J,JT,L,ND,NDT,NE + + IF (MBLOGS /= MBASE) CALL FMCONS + +! NE is the maximum number of base MBASE digits that +! can be used in the first Newton iteration. + + NE = INT(1.9D0*DLOGEB) + +! Fill the intermediate digit stack (backwards). + + KST = 1 + ND = NDIG + NSTACK(1) = ND + IF (ND < NE .OR. ND <= 2) RETURN + + 110 Y = ND + +! The 1.9 accounts for the fact that the number of correct +! digits approximately doubles at each iteration. + + NDT = INT(Y/1.9D0) + IF (2*NDT <= ND) NDT = NDT + 1 + ND = NDT + KST = KST + 1 + NSTACK(KST) = ND + IF (ND > NE .AND. ND > 2) GO TO 110 + +! Reverse the stack. + + L = KST/2 + DO J = 1, L + JT = NSTACK(J) + NSTACK(J) = NSTACK(KST+1-J) + NSTACK(KST+1-J) = JT + ENDDO + + RETURN + END SUBROUTINE FMDIG + + SUBROUTINE FMDIM(MA,MB,MC) + +! MC = DIM(MA,MB) + +! Positive difference. MC = MA - MB if MA >= MB, +! = 0 otherwise. + + USE FMVALS + IMPLICIT NONE + + REAL (KIND(1.0D0)) :: MA(-1:LUNPCK),MB(-1:LUNPCK),MC(-1:LUNPCK) + REAL (KIND(1.0D0)) :: MACCA,MACCB,MACMAX,MXSAVE + INTEGER J,K,KASAVE,KOVUN,KRESLT,KWRNSV,NDSAVE + LOGICAL FMCOMP + + IF (MBLOGS /= MBASE) CALL FMCONS + IF (ABS(MA(1)) > MEXPAB .OR. ABS(MB(1)) > MEXPAB) THEN + CALL FMENTR('FMDIM ',MA,MB,2,1,MC,KRESLT,NDSAVE,MXSAVE,KASAVE, & + KOVUN) + IF (KRESLT /= 0) RETURN + ELSE + NCALL = NCALL + 1 + NAMEST(NCALL) = 'FMDIM ' + IF (NTRACE /= 0) CALL FMNTR(2,MA,MB,2,1) + KOVUN = 0 + IF (MA(1) == MEXPOV .OR. MA(1) == MEXPUN) KOVUN = 1 + IF (MB(1) == MEXPOV .OR. MB(1) == MEXPUN) KOVUN = 1 + NDSAVE = NDIG + IF (NCALL == 1) THEN + K = MAX(NGRD52-1,2) + NDIG = MAX(NDIG+K,2) + IF (NDIG > NDG2MX) THEN + KFLAG = -9 + CALL FMWARN + NDIG = NDSAVE + KRESLT = 12 + CALL FMRSLT(MA,MB,MC,KRESLT) + IF (NTRACE /= 0) CALL FMNTR(1,MC,MC,1,1) + NCALL = NCALL - 1 + RETURN + ENDIF + ENDIF + KASAVE = KACCSW + MXSAVE = MXEXP + MXEXP = MXEXP2 + ENDIF + KWRNSV = KWARN + KWARN = 0 + MXEXP = MXSAVE + + MACCA = MA(0) + MACCB = MB(0) + CALL FMEQ2(MA,M01,NDSAVE,NDIG) + M01(0) = NINT(NDIG*ALOGM2) + CALL FMEQ2(MB,M02,NDSAVE,NDIG) + M02(0) = NINT(NDIG*ALOGM2) + + IF (FMCOMP(M01,'LT',M02)) THEN + CALL FMI2M(0,MC) + ELSE + CALL FMSUB(M01,M02,MC) + ENDIF + + IF (KFLAG == 1) KFLAG = 0 + KWARN = KWRNSV + MACMAX = NINT((NDSAVE-1)*ALOGM2 + LOG(REAL(ABS(MC(2))+1))/0.69315) + MC(0) = MIN(MC(0),MACCA,MACCB,MACMAX) + DO J = -1, NDIG+1 + M01(J) = MC(J) + ENDDO + CALL FMEXIT(M01,MC,NDSAVE,MXSAVE,KASAVE,KOVUN) + RETURN + END SUBROUTINE FMDIM + + SUBROUTINE FMDIV(MA,MB,MC) + +! MC = MA / MB + +! This routine performs the trace printing for division. +! FMDIV2 is used to do the arithmetic. + + USE FMVALS + IMPLICIT NONE + + REAL (KIND(1.0D0)) :: MA(-1:LUNPCK),MB(-1:LUNPCK),MC(-1:LUNPCK) + + NCALL = NCALL + 1 + IF (NTRACE /= 0) THEN + NAMEST(NCALL) = 'FMDIV ' + CALL FMNTR(2,MA,MB,2,1) + + CALL FMDIV2(MA,MB,MC) + + CALL FMNTR(1,MC,MC,1,1) + ELSE + CALL FMDIV2(MA,MB,MC) + ENDIF + NCALL = NCALL - 1 + RETURN + END SUBROUTINE FMDIV + + SUBROUTINE FMDIV2(MA,MB,MC) + +! Internal division routine. MC = MA / MB + + USE FMVALS + IMPLICIT NONE + + REAL (KIND(1.0D0)) :: MA(-1:LUNPCK),MB(-1:LUNPCK),MC(-1:LUNPCK) + + REAL (KIND(1.0D0)) :: MACCA,MACCB,MAS,MBS,MD2B,MLR,MR,MS,MT1,MT2 + INTEGER J,JRSSAV,K,KRESLT,KT,KT1,KT2,KT3,L,N1,NG,NGUARD,NL + + IF (MBLOGS /= MBASE) CALL FMCONS + JRSSAV = JRSIGN + MACCA = MA(0) + MACCB = MB(0) + IF (ABS(MA(1)) > MEXPAB .OR. ABS(MB(1)) > MEXPAB .OR. & + KDEBUG == 1) THEN + CALL FMARGS('FMDIV ',2,MA,MB,KRESLT) + IF (KRESLT /= 0) THEN + NCALL = NCALL + 1 + NAMEST(NCALL) = 'FMDIV ' + CALL FMRSLT(MA,MB,MC,KRESLT) + JRSIGN = JRSSAV + NCALL = NCALL - 1 + RETURN + ENDIF + ELSE + IF (MB(2) == 0) THEN + NAMEST(NCALL) = 'FMDIV ' + CALL FMIM(0,MC) + KFLAG = -4 + CALL FMWARN + MC(1) = MUNKNO + MC(2) = 1 + MC(0) = NINT(NDIG*ALOGM2) + JRSIGN = JRSSAV + RETURN + ENDIF + IF (MA(2) == 0) THEN + CALL FMIM(0,MC) + MC(0) = MIN(MACCA,MACCB) + JRSIGN = JRSSAV + RETURN + ENDIF + ENDIF + KFLAG = 0 + +! NGUARD is the number of guard digits used. + + IF (NCALL > 1) THEN + NGUARD = NGRD21 + IF (NGUARD > NDIG) NGUARD = NDIG + ELSE + NGUARD = NGRD52 - 1 + IF (MBASE < 1000 .OR. KROUND /= 1 .OR. KRPERF == 1) THEN + NGUARD = NDIG + 10 + ENDIF + ENDIF + N1 = NDIG + 1 + NG = NDIG + NGUARD + +! Save the sign of MA and MB and then work only with +! positive numbers. + + MAS = MA(-1) + MBS = MB(-1) + IF ((MAS > 0 .AND. MBS > 0) .OR. (MAS < 0 .AND. MBS < 0)) THEN + JRSIGN = 1 + ELSE + JRSIGN = -1 + ENDIF + MWA(1) = MA(1) - MB(1) + 1 + + IF (MBASE*MBASE <= MXBASE/(4*MBASE)) THEN + IF (NDIGL /= NDIG .OR. MBASEL /= MBASE .OR. NGUARL /= NGUARD) THEN + MBASEL = MBASE + NDIGL = NDIG + NGUARL = NGUARD + DO J = 2, 1000 + MR = MBASE*MBASEL + IF (4*MR > MXBASE) THEN + N21 = J - 1 + NDIG = (NDIGL-1)/N21 + 1 + IF (NDIG < 2) NDIG = 2 + NGRDN = (NDIGL+NGUARD-1)/N21 + 2 - NDIG + IF (NGRDN < 1) NGRDN = 1 + EXIT + ENDIF + MBASE = MR + ENDDO + MBASEN = MBASE + NDIGN = NDIG + ELSE + MBASE = MBASEN + NDIG = NDIGN + ENDIF + MPMA(1) = 0 + MPMB(1) = 0 + L = 2 - N21 + DO J = 2, NDIGL+2-N21, N21 + MT1 = MA(J) + MT2 = MB(J) + DO K = J+1, J+N21-1 + MT1 = MT1*MBASEL + MA(K) + MT2 = MT2*MBASEL + MB(K) + ENDDO + MPMA(2+J/N21) = MT1 + MPMB(2+J/N21) = MT2 + L = J + ENDDO + DO J = 3+L/N21, NDIG+NGRDN+2 + MPMA(J) = 0 + MPMB(J) = 0 + ENDDO + IF (L+N21 <= NDIGL+1) THEN + MT1 = 0 + MT2 = 0 + DO J = L+N21, L+2*N21-1 + IF (J <= NDIGL+1) THEN + MT1 = MT1*MBASEL + MA(J) + MT2 = MT2*MBASEL + MB(J) + ELSE + MT1 = MT1*MBASEL + MT2 = MT2*MBASEL + ENDIF + ENDDO + MPMA(2+(L+N21)/N21) = MT1 + MPMB(2+(L+N21)/N21) = MT2 + ENDIF + NG = NDIG + NGRDN + 1 + IF (MPMA(2) >= MPMB(2)) NG = NG + 1 + +! Copy MA into the working array. + + DO J = 2, NDIG+1 + MWA(J+1) = MPMA(J) + ENDDO + MWA(2) = 0 + DO J = NDIG+3, NG+4 + MWA(J) = 0 + ENDDO + CALL FMDIV3(MPMB,NG) + KT3 = N21 - 1 + IF (MBASEL == 2 .AND. MBASE < INTMAX) THEN + DO J = 2+NDIG+NGRDN, 3, -1 + KT1 = MWA(J) + KT = 2 + (J-2)*N21 + KT2 = N21 + KT - 1 + DO K = KT, MIN(1+(J-1)*N21,NDIGL+NGUARD+2+KT3) + MWA(K-KT3) = IBITS(KT1,KT2-K,1) + ENDDO + ENDDO + ELSE + MS = MBASEL**(N21-1) + DO J = 2+NDIG+NGRDN, 3, -1 + MR = MS + MT1 = MWA(J) + DO K = 2+(J-2)*N21, MIN(1+(J-1)*N21,NDIGL+NGUARD+2+KT3) + MWA(K-KT3) = AINT (MT1/MR) + MT1 = MT1 - MWA(K-KT3)*MR + MR = AINT (MR/MBASEL) + ENDDO + ENDDO + ENDIF + NDIG = NDIGL + MBASE = MBASEL + ELSE + +! Copy MA into the working array. + + DO J = 2, N1 + MWA(J+1) = MA(J) + ENDDO + MWA(2) = 0 + NL = N1 + NGUARD + 3 + DO J = NDIG+3, NL + MWA(J) = 0 + ENDDO + CALL FMDIV3(MB,NG) + ENDIF + +! Round, affix the sign, and return. + + IF (MWA(2) == 0) THEN + MLR = 2*MWA(NDIG+3) + 1 + IF (KROUND == -1 .OR. KROUND == 2) THEN + CALL FMRND(MWA,NDIG,NGUARD,1) + ELSE IF (MLR >= MBASE) THEN + IF (MLR-1 > MBASE .AND. MWA(N1+1) < MBASE-1) THEN + IF (KROUND /= 0 .OR. NCALL > 1) THEN + MWA(N1+1) = MWA(N1+1) + 1 + MWA(N1+2) = 0 + ENDIF + ELSE + CALL FMRND(MWA,NDIG,NGUARD,1) + ENDIF + ENDIF + ELSE + MLR = 2*MWA(NDIG+2) + 1 + IF (KROUND == -1 .OR. KROUND == 2) THEN + CALL FMRND(MWA,NDIG,NGUARD,0) + ELSE IF (MLR >= MBASE) THEN + IF (MLR-1 > MBASE .AND. MWA(N1) < MBASE-1) THEN + IF (KROUND /= 0 .OR. NCALL > 1) THEN + MWA(N1) = MWA(N1) + 1 + MWA(N1+1) = 0 + ENDIF + ELSE + CALL FMRND(MWA,NDIG,NGUARD,0) + ENDIF + ENDIF + ENDIF + CALL FMMOVE(MWA,MC) + + IF (KFLAG < 0) THEN + NAMEST(NCALL) = 'FMDIV ' + CALL FMWARN + ENDIF + + MC(-1) = 1 + IF (MAS*MBS < 0 .AND. MC(1) /= MUNKNO .AND. MC(2) /= 0) MC(-1) = -1 + + IF (KACCSW == 1) THEN + MD2B = NINT((NDIG-1)*ALOGM2 + LOG(REAL(ABS(MC(2))+1))/0.69315) + MC(0) = MIN(MACCA,MACCB,MD2B) + ELSE + MC(0) = MIN(MACCA,MACCB) + ENDIF + JRSIGN = JRSSAV + RETURN + END SUBROUTINE FMDIV2 + + SUBROUTINE FMDIV_R1(MA,MB) + +! MA = MA / MB + +! This routine performs the trace printing for division. +! FMDIV2_R1 is used to do the arithmetic. + + USE FMVALS + IMPLICIT NONE + + REAL (KIND(1.0D0)) :: MA(-1:LUNPCK),MB(-1:LUNPCK) + + NCALL = NCALL + 1 + IF (NTRACE /= 0) THEN + NAMEST(NCALL) = 'FMDIV ' + CALL FMNTR(2,MA,MB,2,1) + + CALL FMDIV2_R1(MA,MB) + + CALL FMNTR(1,MA,MA,1,1) + ELSE + CALL FMDIV2_R1(MA,MB) + ENDIF + NCALL = NCALL - 1 + RETURN + END SUBROUTINE FMDIV_R1 + + SUBROUTINE FMDIV2_R1(MA,MB) + +! Internal division routine. MA = MA / MB + + USE FMVALS + IMPLICIT NONE + + REAL (KIND(1.0D0)) :: MA(-1:LUNPCK),MB(-1:LUNPCK) + + REAL (KIND(1.0D0)) :: MACCA,MACCB,MAS,MBS,MD2B,MLR,MR,MS,MT1,MT2 + INTEGER J,JRSSAV,K,KRESLT,KT,KT1,KT2,KT3,L,N1,NG,NGUARD,NL + + IF (MBLOGS /= MBASE) CALL FMCONS + JRSSAV = JRSIGN + MACCA = MA(0) + MACCB = MB(0) + IF (ABS(MA(1)) > MEXPAB .OR. ABS(MB(1)) > MEXPAB .OR. & + KDEBUG == 1) THEN + CALL FMARGS('FMDIV ',2,MA,MB,KRESLT) + IF (KRESLT /= 0) THEN + NCALL = NCALL + 1 + NAMEST(NCALL) = 'FMDIV ' + CALL FMRSLT(MA,MB,M07,KRESLT) + CALL FMEQ(M07,MA) + JRSIGN = JRSSAV + NCALL = NCALL - 1 + RETURN + ENDIF + ELSE + IF (MB(2) == 0) THEN + NAMEST(NCALL) = 'FMDIV ' + CALL FMIM(0,MA) + KFLAG = -4 + CALL FMWARN + MA(1) = MUNKNO + MA(2) = 1 + MA(0) = NINT(NDIG*ALOGM2) + JRSIGN = JRSSAV + RETURN + ENDIF + IF (MA(2) == 0) THEN + CALL FMIM(0,MA) + MA(0) = MIN(MACCA,MACCB) + JRSIGN = JRSSAV + RETURN + ENDIF + ENDIF + KFLAG = 0 + +! NGUARD is the number of guard digits used. + + IF (NCALL > 1) THEN + NGUARD = NGRD21 + IF (NGUARD > NDIG) NGUARD = NDIG + ELSE + NGUARD = NGRD52 - 1 + IF (MBASE < 1000 .OR. KROUND /= 1 .OR. KRPERF == 1) THEN + NGUARD = NDIG + 10 + ENDIF + ENDIF + N1 = NDIG + 1 + NG = NDIG + NGUARD + +! Save the sign of MA and MB and then work only with +! positive numbers. + + MAS = MA(-1) + MBS = MB(-1) + IF ((MAS > 0 .AND. MBS > 0) .OR. (MAS < 0 .AND. MBS < 0)) THEN + JRSIGN = 1 + ELSE + JRSIGN = -1 + ENDIF + MWA(1) = MA(1) - MB(1) + 1 + + IF (MBASE*MBASE <= MXBASE/(4*MBASE)) THEN + IF (NDIGL /= NDIG .OR. MBASEL /= MBASE .OR. NGUARL /= NGUARD) THEN + MBASEL = MBASE + NDIGL = NDIG + NGUARL = NGUARD + DO J = 2, 1000 + MR = MBASE*MBASEL + IF (4*MR > MXBASE) THEN + N21 = J - 1 + NDIG = (NDIGL-1)/N21 + 1 + IF (NDIG < 2) NDIG = 2 + NGRDN = (NDIGL+NGUARD-1)/N21 + 2 - NDIG + IF (NGRDN < 1) NGRDN = 1 + EXIT + ENDIF + MBASE = MR + ENDDO + MBASEN = MBASE + NDIGN = NDIG + ELSE + MBASE = MBASEN + NDIG = NDIGN + ENDIF + MPMA(1) = 0 + MPMB(1) = 0 + L = 2 - N21 + DO J = 2, NDIGL+2-N21, N21 + MT1 = MA(J) + MT2 = MB(J) + DO K = J+1, J+N21-1 + MT1 = MT1*MBASEL + MA(K) + MT2 = MT2*MBASEL + MB(K) + ENDDO + MPMA(2+J/N21) = MT1 + MPMB(2+J/N21) = MT2 + L = J + ENDDO + DO J = 3+L/N21, NDIG+NGRDN+2 + MPMA(J) = 0 + MPMB(J) = 0 + ENDDO + IF (L+N21 <= NDIGL+1) THEN + MT1 = 0 + MT2 = 0 + DO J = L+N21, L+2*N21-1 + IF (J <= NDIGL+1) THEN + MT1 = MT1*MBASEL + MA(J) + MT2 = MT2*MBASEL + MB(J) + ELSE + MT1 = MT1*MBASEL + MT2 = MT2*MBASEL + ENDIF + ENDDO + MPMA(2+(L+N21)/N21) = MT1 + MPMB(2+(L+N21)/N21) = MT2 + ENDIF + NG = NDIG + NGRDN + 1 + IF (MPMA(2) >= MPMB(2)) NG = NG + 1 + +! Copy MA into the working array. + + DO J = 2, NDIG+1 + MWA(J+1) = MPMA(J) + ENDDO + MWA(2) = 0 + DO J = NDIG+3, NG+4 + MWA(J) = 0 + ENDDO + CALL FMDIV3(MPMB,NG) + KT3 = N21 - 1 + IF (MBASEL == 2 .AND. MBASE < INTMAX) THEN + DO J = 2+NDIG+NGRDN, 3, -1 + KT1 = MWA(J) + KT = 2 + (J-2)*N21 + KT2 = N21 + KT - 1 + DO K = KT, MIN(1+(J-1)*N21,NDIGL+NGUARD+2+KT3) + MWA(K-KT3) = IBITS(KT1,KT2-K,1) + ENDDO + ENDDO + ELSE + MS = MBASEL**(N21-1) + DO J = 2+NDIG+NGRDN, 3, -1 + MR = MS + MT1 = MWA(J) + DO K = 2+(J-2)*N21, MIN(1+(J-1)*N21,NDIGL+NGUARD+2+KT3) + MWA(K-KT3) = AINT (MT1/MR) + MT1 = MT1 - MWA(K-KT3)*MR + MR = AINT (MR/MBASEL) + ENDDO + ENDDO + ENDIF + NDIG = NDIGL + MBASE = MBASEL + ELSE + +! Copy MA into the working array. + + DO J = 2, N1 + MWA(J+1) = MA(J) + ENDDO + MWA(2) = 0 + NL = N1 + NGUARD + 3 + DO J = NDIG+3, NL + MWA(J) = 0 + ENDDO + CALL FMDIV3(MB,NG) + ENDIF + +! Round, affix the sign, and return. + + IF (MWA(2) == 0) THEN + MLR = 2*MWA(NDIG+3) + 1 + IF (KROUND == -1 .OR. KROUND == 2) THEN + CALL FMRND(MWA,NDIG,NGUARD,1) + ELSE IF (MLR >= MBASE) THEN + IF (MLR-1 > MBASE .AND. MWA(N1+1) < MBASE-1) THEN + IF (KROUND /= 0 .OR. NCALL > 1) THEN + MWA(N1+1) = MWA(N1+1) + 1 + MWA(N1+2) = 0 + ENDIF + ELSE + CALL FMRND(MWA,NDIG,NGUARD,1) + ENDIF + ENDIF + ELSE + MLR = 2*MWA(NDIG+2) + 1 + IF (KROUND == -1 .OR. KROUND == 2) THEN + CALL FMRND(MWA,NDIG,NGUARD,0) + ELSE IF (MLR >= MBASE) THEN + IF (MLR-1 > MBASE .AND. MWA(N1) < MBASE-1) THEN + IF (KROUND /= 0 .OR. NCALL > 1) THEN + MWA(N1) = MWA(N1) + 1 + MWA(N1+1) = 0 + ENDIF + ELSE + CALL FMRND(MWA,NDIG,NGUARD,0) + ENDIF + ENDIF + ENDIF + CALL FMMOVE(MWA,MA) + + IF (KFLAG < 0) THEN + NAMEST(NCALL) = 'FMDIV ' + CALL FMWARN + ENDIF + + MA(-1) = 1 + IF (MAS*MBS < 0 .AND. MA(1) /= MUNKNO .AND. MA(2) /= 0) MA(-1) = -1 + + IF (KACCSW == 1) THEN + MD2B = NINT((NDIG-1)*ALOGM2 + LOG(REAL(ABS(MA(2))+1))/0.69315) + MA(0) = MIN(MACCA,MACCB,MD2B) + ELSE + MA(0) = MIN(MACCA,MACCB) + ENDIF + JRSIGN = JRSSAV + RETURN + END SUBROUTINE FMDIV2_R1 + + SUBROUTINE FMDIV_R2(MA,MB) + +! MB = MA / MB + +! This routine performs the trace printing for division. +! FMDIV2_R2 is used to do the arithmetic. + + USE FMVALS + IMPLICIT NONE + + REAL (KIND(1.0D0)) :: MA(-1:LUNPCK),MB(-1:LUNPCK) + + NCALL = NCALL + 1 + IF (NTRACE /= 0) THEN + NAMEST(NCALL) = 'FMDIV ' + CALL FMNTR(2,MA,MB,2,1) + + CALL FMDIV2_R2(MA,MB) + + CALL FMNTR(1,MB,MB,1,1) + ELSE + CALL FMDIV2_R2(MA,MB) + ENDIF + NCALL = NCALL - 1 + RETURN + END SUBROUTINE FMDIV_R2 + + SUBROUTINE FMDIV2_R2(MA,MB) + +! Internal division routine. MB = MA / MB + + USE FMVALS + IMPLICIT NONE + + REAL (KIND(1.0D0)) :: MA(-1:LUNPCK),MB(-1:LUNPCK) + + REAL (KIND(1.0D0)) :: MACCA,MACCB,MAS,MBS,MD2B,MLR,MR,MS,MT1,MT2 + INTEGER J,JRSSAV,K,KRESLT,KT,KT1,KT2,KT3,L,N1,NG,NGUARD,NL + + IF (MBLOGS /= MBASE) CALL FMCONS + JRSSAV = JRSIGN + MACCA = MA(0) + MACCB = MB(0) + IF (ABS(MA(1)) > MEXPAB .OR. ABS(MB(1)) > MEXPAB .OR. & + KDEBUG == 1) THEN + CALL FMARGS('FMDIV ',2,MA,MB,KRESLT) + IF (KRESLT /= 0) THEN + NCALL = NCALL + 1 + NAMEST(NCALL) = 'FMDIV ' + CALL FMRSLT(MA,MB,M07,KRESLT) + CALL FMEQ(M07,MB) + JRSIGN = JRSSAV + NCALL = NCALL - 1 + RETURN + ENDIF + ELSE + IF (MB(2) == 0) THEN + NAMEST(NCALL) = 'FMDIV ' + CALL FMIM(0,MB) + KFLAG = -4 + CALL FMWARN + MB(1) = MUNKNO + MB(2) = 1 + MB(0) = NINT(NDIG*ALOGM2) + JRSIGN = JRSSAV + RETURN + ENDIF + IF (MA(2) == 0) THEN + CALL FMIM(0,MB) + MB(0) = MIN(MACCA,MACCB) + JRSIGN = JRSSAV + RETURN + ENDIF + ENDIF + KFLAG = 0 + +! NGUARD is the number of guard digits used. + + IF (NCALL > 1) THEN + NGUARD = NGRD21 + IF (NGUARD > NDIG) NGUARD = NDIG + ELSE + NGUARD = NGRD52 - 1 + IF (MBASE < 1000 .OR. KROUND /= 1 .OR. KRPERF == 1) THEN + NGUARD = NDIG + 10 + ENDIF + ENDIF + N1 = NDIG + 1 + NG = NDIG + NGUARD + +! Save the sign of MA and MB and then work only with +! positive numbers. + + MAS = MA(-1) + MBS = MB(-1) + IF ((MAS > 0 .AND. MBS > 0) .OR. (MAS < 0 .AND. MBS < 0)) THEN + JRSIGN = 1 + ELSE + JRSIGN = -1 + ENDIF + MWA(1) = MA(1) - MB(1) + 1 + + IF (MBASE*MBASE <= MXBASE/(4*MBASE)) THEN + IF (NDIGL /= NDIG .OR. MBASEL /= MBASE .OR. NGUARL /= NGUARD) THEN + MBASEL = MBASE + NDIGL = NDIG + NGUARL = NGUARD + DO J = 2, 1000 + MR = MBASE*MBASEL + IF (4*MR > MXBASE) THEN + N21 = J - 1 + NDIG = (NDIGL-1)/N21 + 1 + IF (NDIG < 2) NDIG = 2 + NGRDN = (NDIGL+NGUARD-1)/N21 + 2 - NDIG + IF (NGRDN < 1) NGRDN = 1 + EXIT + ENDIF + MBASE = MR + ENDDO + MBASEN = MBASE + NDIGN = NDIG + ELSE + MBASE = MBASEN + NDIG = NDIGN + ENDIF + MPMA(1) = 0 + MPMB(1) = 0 + L = 2 - N21 + DO J = 2, NDIGL+2-N21, N21 + MT1 = MA(J) + MT2 = MB(J) + DO K = J+1, J+N21-1 + MT1 = MT1*MBASEL + MA(K) + MT2 = MT2*MBASEL + MB(K) + ENDDO + MPMA(2+J/N21) = MT1 + MPMB(2+J/N21) = MT2 + L = J + ENDDO + DO J = 3+L/N21, NDIG+NGRDN+2 + MPMA(J) = 0 + MPMB(J) = 0 + ENDDO + IF (L+N21 <= NDIGL+1) THEN + MT1 = 0 + MT2 = 0 + DO J = L+N21, L+2*N21-1 + IF (J <= NDIGL+1) THEN + MT1 = MT1*MBASEL + MA(J) + MT2 = MT2*MBASEL + MB(J) + ELSE + MT1 = MT1*MBASEL + MT2 = MT2*MBASEL + ENDIF + ENDDO + MPMA(2+(L+N21)/N21) = MT1 + MPMB(2+(L+N21)/N21) = MT2 + ENDIF + NG = NDIG + NGRDN + 1 + IF (MPMA(2) >= MPMB(2)) NG = NG + 1 + +! Copy MA into the working array. + + DO J = 2, NDIG+1 + MWA(J+1) = MPMA(J) + ENDDO + MWA(2) = 0 + DO J = NDIG+3, NG+4 + MWA(J) = 0 + ENDDO + CALL FMDIV3(MPMB,NG) + KT3 = N21 - 1 + IF (MBASEL == 2 .AND. MBASE < INTMAX) THEN + DO J = 2+NDIG+NGRDN, 3, -1 + KT1 = MWA(J) + KT = 2 + (J-2)*N21 + KT2 = N21 + KT - 1 + DO K = KT, MIN(1+(J-1)*N21,NDIGL+NGUARD+2+KT3) + MWA(K-KT3) = IBITS(KT1,KT2-K,1) + ENDDO + ENDDO + ELSE + MS = MBASEL**(N21-1) + DO J = 2+NDIG+NGRDN, 3, -1 + MR = MS + MT1 = MWA(J) + DO K = 2+(J-2)*N21, MIN(1+(J-1)*N21,NDIGL+NGUARD+2+KT3) + MWA(K-KT3) = AINT (MT1/MR) + MT1 = MT1 - MWA(K-KT3)*MR + MR = AINT (MR/MBASEL) + ENDDO + ENDDO + ENDIF + NDIG = NDIGL + MBASE = MBASEL + ELSE + +! Copy MA into the working array. + + DO J = 2, N1 + MWA(J+1) = MA(J) + ENDDO + MWA(2) = 0 + NL = N1 + NGUARD + 3 + DO J = NDIG+3, NL + MWA(J) = 0 + ENDDO + CALL FMDIV3(MB,NG) + ENDIF + +! Round, affix the sign, and return. + + IF (MWA(2) == 0) THEN + MLR = 2*MWA(NDIG+3) + 1 + IF (KROUND == -1 .OR. KROUND == 2) THEN + CALL FMRND(MWA,NDIG,NGUARD,1) + ELSE IF (MLR >= MBASE) THEN + IF (MLR-1 > MBASE .AND. MWA(N1+1) < MBASE-1) THEN + IF (KROUND /= 0 .OR. NCALL > 1) THEN + MWA(N1+1) = MWA(N1+1) + 1 + MWA(N1+2) = 0 + ENDIF + ELSE + CALL FMRND(MWA,NDIG,NGUARD,1) + ENDIF + ENDIF + ELSE + MLR = 2*MWA(NDIG+2) + 1 + IF (KROUND == -1 .OR. KROUND == 2) THEN + CALL FMRND(MWA,NDIG,NGUARD,0) + ELSE IF (MLR >= MBASE) THEN + IF (MLR-1 > MBASE .AND. MWA(N1) < MBASE-1) THEN + IF (KROUND /= 0 .OR. NCALL > 1) THEN + MWA(N1) = MWA(N1) + 1 + MWA(N1+1) = 0 + ENDIF + ELSE + CALL FMRND(MWA,NDIG,NGUARD,0) + ENDIF + ENDIF + ENDIF + CALL FMMOVE(MWA,MB) + + IF (KFLAG < 0) THEN + NAMEST(NCALL) = 'FMDIV ' + CALL FMWARN + ENDIF + + MB(-1) = 1 + IF (MAS*MBS < 0 .AND. MB(1) /= MUNKNO .AND. MB(2) /= 0) MB(-1) = -1 + + IF (KACCSW == 1) THEN + MD2B = NINT((NDIG-1)*ALOGM2 + LOG(REAL(ABS(MB(2))+1))/0.69315) + MB(0) = MIN(MACCA,MACCB,MD2B) + ELSE + MB(0) = MIN(MACCA,MACCB) + ENDIF + JRSIGN = JRSSAV + RETURN + END SUBROUTINE FMDIV2_R2 + + SUBROUTINE FMDIV3(MB,NG) + +! Internal division routine. Divide MA/MB and return the +! quotient in MWA. + + USE FMVALS + IMPLICIT NONE + + REAL (KIND(1.0D0)) :: MB(-1:LUNPCK) + + DOUBLE PRECISION XB,XBR,XBASE,XMWA + REAL (KIND(1.0D0)) :: MAXMWA,MBM1,MCARRY,MKT,MLMAX,MQD + INTEGER J,JB,JL,KA,KB,KL,KPTMWA,N1,NG,NL,NMBWDS,NZDMB + N1 = NDIG + 1 + NL = NG + 4 + +! NMBWDS is the number of words of MB used to +! compute the estimated quotient digit MQD. + + NMBWDS = 4 + IF (MBASE < 100) NMBWDS = 7 + +! XB is an approximation of MB used in +! estimating the quotient digits. + + XBASE = DBLE(MBASE) + XB = 0 + JL = NMBWDS + IF (JL <= N1) THEN + DO J = 2, JL + XB = XB*XBASE + DBLE(MB(J)) + ENDDO + ELSE + DO J = 2, JL + IF (J <= N1) THEN + XB = XB*XBASE + DBLE(MB(J)) + ELSE + XB = XB*XBASE + ENDIF + ENDDO + ENDIF + IF (JL+1 <= N1) THEN + XB = XB + DBLE(MB(JL+1))/XBASE + ENDIF + XBR = 1.0D0/XB + +! MLMAX determines when to normalize all of MWA. + + MBM1 = MBASE - 1 + MLMAX = MAXINT/MBM1 + MKT = INTMAX - MBASE + MLMAX = MIN(MLMAX,MKT) + +! Count the trailing zero digits of MB. + + DO J = N1, 2, -1 + IF (MB(J) /= 0) THEN + NZDMB = N1 - J + GO TO 110 + ENDIF + ENDDO + +! MAXMWA is an upper bound on the size of values in MWA +! divided by MBASE-1. It is used to determine whether +! normalization can be postponed. + + 110 MAXMWA = 0 + +! KPTMWA points to the next digit in the quotient. + + KPTMWA = 2 + +! This is the start of the division loop. + +! XMWA is an approximation of the active part of MWA +! used in estimating quotient digits. + + 120 KL = KPTMWA + NMBWDS - 1 + IF (KL <= NL) THEN + XMWA = ((DBLE(MWA(KPTMWA))*XBASE & + + DBLE(MWA(KPTMWA+1)))*XBASE & + + DBLE(MWA(KPTMWA+2)))*XBASE & + + DBLE(MWA(KPTMWA+3)) + DO J = KPTMWA+4, KL + XMWA = XMWA*XBASE + DBLE(MWA(J)) + ENDDO + ELSE + XMWA = DBLE(MWA(KPTMWA)) + DO J = KPTMWA+1, KL + IF (J <= NL) THEN + XMWA = XMWA*XBASE + DBLE(MWA(J)) + ELSE + XMWA = XMWA*XBASE + ENDIF + ENDDO + ENDIF + +! MQD is the estimated quotient digit. + + MQD = AINT(XMWA*XBR) + IF (MQD < 0) MQD = MQD - 1 + + IF (MQD > 0) THEN + MAXMWA = MAXMWA + MQD + ELSE + MAXMWA = MAXMWA - MQD + ENDIF + +! See if MWA must be normalized. + + KA = KPTMWA + 1 + KB = MIN(KA+NDIG-1-NZDMB,NL) + IF (MAXMWA >= MLMAX) THEN + DO J = KB, KA, -1 + IF (MWA(J) < 0) THEN + MCARRY = INT((-MWA(J)-1)/MBASE) + 1 + MWA(J) = MWA(J) + MCARRY*MBASE + MWA(J-1) = MWA(J-1) - MCARRY + ELSE IF (MWA(J) >= MBASE) THEN + MCARRY = -INT(MWA(J)/MBASE) + MWA(J) = MWA(J) + MCARRY*MBASE + MWA(J-1) = MWA(J-1) - MCARRY + ENDIF + ENDDO + XMWA = 0 + IF (KL <= NL) THEN + DO J = KPTMWA, KL + XMWA = XMWA*XBASE + DBLE(MWA(J)) + ENDDO + ELSE + DO J = KPTMWA, KL + IF (J <= NL) THEN + XMWA = XMWA*XBASE + DBLE(MWA(J)) + ELSE + XMWA = XMWA*XBASE + ENDIF + ENDDO + ENDIF + MQD = AINT(XMWA*XBR) + IF (MQD < 0) MQD = MQD - 1 + IF (MQD > 0) THEN + MAXMWA = MQD + ELSE + MAXMWA = -MQD + ENDIF + ENDIF + +! Subtract MQD*MB from MWA. + + JB = KA - 2 + IF (MQD /= 0) THEN + +! Major (Inner Loop) + + DO J = KA, KB + MWA(J) = MWA(J) - MQD*MB(J-JB) + ENDDO + ENDIF + + MWA(KA) = MWA(KA) + MWA(KA-1)*MBASE + MWA(KPTMWA) = MQD + + KPTMWA = KPTMWA + 1 + IF (KPTMWA <= NG) GO TO 120 + IF (MWA(2) == 0 .AND. KPTMWA <= NG+1) GO TO 120 + + KL = KPTMWA + NMBWDS - 1 + IF (KL <= NL) THEN + XMWA = ((DBLE(MWA(KPTMWA))*XBASE & + + DBLE(MWA(KPTMWA+1)))*XBASE & + + DBLE(MWA(KPTMWA+2)))*XBASE & + + DBLE(MWA(KPTMWA+3)) + DO J = KPTMWA+4, KL + XMWA = XMWA*XBASE + DBLE(MWA(J)) + ENDDO + ELSE + XMWA = DBLE(MWA(KPTMWA)) + DO J = KPTMWA+1, KL + IF (J <= NL) THEN + XMWA = XMWA*XBASE + DBLE(MWA(J)) + ELSE + XMWA = XMWA*XBASE + ENDIF + ENDDO + ENDIF + MQD = AINT(XMWA*XBR) + IF (MQD < 0) MQD = MQD - 1 + MWA(KPTMWA) = MQD + MWA(KPTMWA+1) = 0 + MWA(KPTMWA+2) = 0 + +! Final normalization. + + DO J = KPTMWA, 3, -1 + IF (MWA(J) < 0) THEN + MCARRY = INT((-MWA(J)-1)/MBASE) + 1 + MWA(J) = MWA(J) + MCARRY*MBASE + MWA(J-1) = MWA(J-1) - MCARRY + ELSE IF (MWA(J) >= MBASE) THEN + MCARRY = -INT(MWA(J)/MBASE) + MWA(J) = MWA(J) + MCARRY*MBASE + MWA(J-1) = MWA(J-1) - MCARRY + ENDIF + ENDDO + + RETURN + END SUBROUTINE FMDIV3 + + SUBROUTINE FMDIVD(MA,MB,MC,MD,ME) + +! Double division routine. MD = MA / MC, ME = MB / MC + +! It is usually slightly faster to do two divisions that +! have a common denominator with one call. + + USE FMVALS + IMPLICIT NONE + + REAL (KIND(1.0D0)) :: MA(-1:LUNPCK),MB(-1:LUNPCK),MC(-1:LUNPCK), & + MD(-1:LUNPCK),ME(-1:LUNPCK) + + REAL (KIND(1.0D0)) :: MA2P,MACCA,MACCB,MACCC,MAS,MAXMWA,MB2P,MBS, & + MBM1,MC2P,MCARRY,MCS,MD2B,MKT,MLMAX,MLR, & + MQDMWA,MQDMWD,MTEMP + DOUBLE PRECISION XB,XBR,XBASE,XMWA,XMWD + INTEGER J,JB,JL,JRSSAV,KA,KB,KL,KOVUN,KPTMW,N1,NG,NGUARD,NL, & + NMBWDS,NZDMB + + NCALL = NCALL + 1 + JRSSAV = JRSIGN + IF (NTRACE /= 0) THEN + NAMEST(NCALL) = 'FMDIVD' + CALL FMNTR(2,MA,MB,2,1) + IF (ABS(NTRACE) >= 2 .AND. NCALL <= LVLTRC) THEN + IF (NTRACE < 0) THEN + CALL FMNTRJ(MC,NDIG) + ELSE + CALL FMPRNT(MC) + ENDIF + ENDIF + ENDIF + + IF (MBLOGS /= MBASE) CALL FMCONS + MACCA = MA(0) + MACCB = MB(0) + MACCC = MC(0) + IF (ABS(MA(1)) > MEXPAB .OR. ABS(MB(1)) > MEXPAB .OR. & + ABS(MC(1)) > MEXPAB .OR. MBASE*MBASE <= MXBASE/(4*MBASE)) THEN + KOVUN = 0 + IF (MA(1) == MEXPOV .OR. MA(1) == MEXPUN .OR. & + MB(1) == MEXPOV .OR. MB(1) == MEXPUN .OR. & + MC(1) == MEXPOV .OR. MC(1) == MEXPUN) KOVUN = 1 + IF (MA(1) == MUNKNO .OR. MB(1) == MUNKNO .OR. & + MC(1) == MUNKNO) KOVUN = 2 + NCALL = NCALL + 1 + CALL FMDIV2(MA,MC,MWD) + KB = KFLAG + CALL FMDIV2(MB,MC,ME) + NCALL = NCALL - 1 + IF (((KFLAG < 0 .OR. KB < 0) .AND. KOVUN == 0) .OR. & + ((KFLAG == -4 .OR. KB == -4) .AND. KOVUN == 1)) THEN + IF (KFLAG == -4 .OR. KB == -4) THEN + KFLAG = -4 + ELSE IF (KFLAG == -5 .OR. KB == -5) THEN + KFLAG = -5 + ELSE + KFLAG = MIN(KFLAG,KB) + ENDIF + NAMEST(NCALL) = 'FMDIVD' + CALL FMWARN + ENDIF + CALL FMEQ(MWD,MD) + GO TO 130 + ENDIF + IF (MC(2) == 0) THEN + NAMEST(NCALL) = 'FMDIVD' + KFLAG = -4 + CALL FMWARN + CALL FMST2M('UNKNOWN',MD) + CALL FMST2M('UNKNOWN',ME) + GO TO 130 + ENDIF + IF (MA(2) == 0 .OR. MB(2) == 0) THEN + CALL FMDIV2(MA,MC,MWD) + CALL FMDIV2(MB,MC,ME) + CALL FMEQ(MWD,MD) + GO TO 130 + ENDIF + KFLAG = 0 + +! NGUARD is the number of guard digits used. + + IF (NCALL > 1) THEN + NGUARD = NGRD21 + IF (NGUARD > NDIG) NGUARD = NDIG + ELSE + NGUARD = NGRD52 - 1 + IF (MBASE < 1000 .OR. KROUND /= 1 .OR. KRPERF == 1) THEN + NGUARD = NDIG + 10 + ENDIF + ENDIF + MA2P = ABS(MA(2)) + MB2P = ABS(MB(2)) + MC2P = ABS(MC(2)) + IF ((MC2P >= MA2P .OR. MC2P >= MB2P) .AND. NGUARD < 2) NGUARD = 2 + N1 = NDIG + 1 + NG = NDIG + NGUARD + +! Copy MA and MB into the working arrays. + + DO J = 3, N1 + MWA(J+1) = MA(J) + MWD(J+1) = MB(J) + ENDDO + MWA(1) = MA(1) - MC(1) + 1 + MWD(1) = MB(1) - MC(1) + 1 + MWA(2) = 0 + MWD(2) = 0 + NL = N1 + NGUARD + 3 + DO J = NDIG+3, NL + MWA(J) = 0 + MWD(J) = 0 + ENDDO + +! Save the signs and then work only with +! positive numbers. + + MAS = MA(-1) + MBS = MB(-1) + MCS = MC(-1) + MWA(3) = MA(2) + MWD(3) = MB(2) + +! NMBWDS is the number of words used to compute +! the estimated quotient digits. + + NMBWDS = 4 + IF (MBASE < 100) NMBWDS = 7 + +! XB is an approximation of MC used in selecting +! estimated quotients. + + XBASE = DBLE(MBASE) + XB = 0 + JL = NMBWDS + IF (JL <= N1) THEN + DO J = 2, JL + XB = XB*XBASE + DBLE(MC(J)) + ENDDO + ELSE + DO J = 2, JL + IF (J <= N1) THEN + XB = XB*XBASE + DBLE(MC(J)) + ELSE + XB = XB*XBASE + ENDIF + ENDDO + ENDIF + IF (JL+1 <= N1) XB = XB + DBLE(MC(JL+1))/XBASE + XBR = 1.0D0/XB + +! MLMAX determines when to normalize all of MWA. + + MBM1 = MBASE - 1 + MLMAX = MAXINT/MBM1 + MKT = INTMAX - MBASE + MLMAX = MIN(MLMAX,MKT) + +! Count the trailing zero digits of MC. + + DO J = N1, 2, -1 + IF (MC(J) /= 0) THEN + NZDMB = N1 - J + GO TO 110 + ENDIF + ENDDO + +! MAXMWA is an upper bound on the size of values in MWA +! divided by MBASE-1. It is used to determine whether +! normalization can be postponed. + + 110 MAXMWA = 0 + +! KPTMW points to the next digit in the quotient. + + KPTMW = 2 + +! This is the start of the division loop. + +! XMWA is an approximation of the active part of MWA +! used in selecting estimated quotients. + + 120 KL = KPTMW + NMBWDS - 1 + IF (KL <= NL) THEN + XMWA = ((DBLE(MWA(KPTMW))*XBASE & + + DBLE(MWA(KPTMW+1)))*XBASE & + + DBLE(MWA(KPTMW+2)))*XBASE & + + DBLE(MWA(KPTMW+3)) + XMWD = ((DBLE(MWD(KPTMW))*XBASE & + + DBLE(MWD(KPTMW+1)))*XBASE & + + DBLE(MWD(KPTMW+2)))*XBASE & + + DBLE(MWD(KPTMW+3)) + DO J = KPTMW+4, KL + XMWA = XMWA*XBASE + DBLE(MWA(J)) + XMWD = XMWD*XBASE + DBLE(MWD(J)) + ENDDO + ELSE + XMWA = DBLE(MWA(KPTMW)) + XMWD = DBLE(MWD(KPTMW)) + DO J = KPTMW+1, KL + IF (J <= NL) THEN + XMWA = XMWA*XBASE + DBLE(MWA(J)) + XMWD = XMWD*XBASE + DBLE(MWD(J)) + ELSE + XMWA = XMWA*XBASE + XMWD = XMWD*XBASE + ENDIF + ENDDO + ENDIF + +! MQDMWA and MQDMWD are the estimated quotient digits. + + MQDMWA = AINT(XMWA*XBR) + IF (MQDMWA < 0) MQDMWA = MQDMWA - 1 + MQDMWD = AINT(XMWD*XBR) + IF (MQDMWD < 0) MQDMWD = MQDMWD - 1 + + MAXMWA = MAXMWA + MAX(ABS(MQDMWA),ABS(MQDMWD)) + +! See if MWA and MWD must be normalized. + + KA = KPTMW + 1 + KB = MIN(KA+NDIG-1-NZDMB,NL) + IF (MAXMWA >= MLMAX) THEN + DO J = KB, KA, -1 + IF (MWA(J) < 0) THEN + MCARRY = INT((-MWA(J)-1)/MBASE) + 1 + MWA(J) = MWA(J) + MCARRY*MBASE + MWA(J-1) = MWA(J-1) - MCARRY + ELSE IF (MWA(J) >= MBASE) THEN + MCARRY = -INT(MWA(J)/MBASE) + MWA(J) = MWA(J) + MCARRY*MBASE + MWA(J-1) = MWA(J-1) - MCARRY + ENDIF + IF (MWD(J) < 0) THEN + MCARRY = INT((-MWD(J)-1)/MBASE) + 1 + MWD(J) = MWD(J) + MCARRY*MBASE + MWD(J-1) = MWD(J-1) - MCARRY + ELSE IF (MWD(J) >= MBASE) THEN + MCARRY = -INT(MWD(J)/MBASE) + MWD(J) = MWD(J) + MCARRY*MBASE + MWD(J-1) = MWD(J-1) - MCARRY + ENDIF + ENDDO + XMWA = 0 + XMWD = 0 + IF (KL <= NL) THEN + DO J = KPTMW, KL + XMWA = XMWA*XBASE + DBLE(MWA(J)) + XMWD = XMWD*XBASE + DBLE(MWD(J)) + ENDDO + ELSE + DO J = KPTMW, KL + IF (J <= NL) THEN + XMWA = XMWA*XBASE + DBLE(MWA(J)) + XMWD = XMWD*XBASE + DBLE(MWD(J)) + ELSE + XMWA = XMWA*XBASE + XMWD = XMWD*XBASE + ENDIF + ENDDO + ENDIF + MQDMWA = AINT(XMWA*XBR) + IF (MQDMWA < 0) MQDMWA = MQDMWA - 1 + MQDMWD = AINT(XMWD*XBR) + IF (MQDMWD < 0) MQDMWD = MQDMWD - 1 + MAXMWA = MAX(ABS(MQDMWA),ABS(MQDMWD)) + ENDIF + +! Subtract MQDMWA*MC from MWA and MQDMWD*MC from MWD. + + JB = KA - 2 + +! Major (Inner Loop) + + DO J = KA, KB + MTEMP = MC(J-JB) + MWA(J) = MWA(J) - MQDMWA*MTEMP + MWD(J) = MWD(J) - MQDMWD*MTEMP + ENDDO + + MWA(KA) = MWA(KA) + MWA(KA-1)*MBASE + MWD(KA) = MWD(KA) + MWD(KA-1)*MBASE + MWA(KPTMW) = MQDMWA + MWD(KPTMW) = MQDMWD + + KPTMW = KPTMW + 1 + IF (KPTMW <= NG) GO TO 120 + + KL = KPTMW + NMBWDS - 1 + IF (KL <= NL) THEN + XMWA = ((DBLE(MWA(KPTMW))*XBASE & + + DBLE(MWA(KPTMW+1)))*XBASE & + + DBLE(MWA(KPTMW+2)))*XBASE & + + DBLE(MWA(KPTMW+3)) + XMWD = ((DBLE(MWD(KPTMW))*XBASE & + + DBLE(MWD(KPTMW+1)))*XBASE & + + DBLE(MWD(KPTMW+2)))*XBASE & + + DBLE(MWD(KPTMW+3)) + DO J = KPTMW+4, KL + XMWA = XMWA*XBASE + DBLE(MWA(J)) + XMWD = XMWD*XBASE + DBLE(MWD(J)) + ENDDO + ELSE + XMWA = DBLE(MWA(KPTMW)) + XMWD = DBLE(MWD(KPTMW)) + DO J = KPTMW+1, KL + IF (J <= NL) THEN + XMWA = XMWA*XBASE + DBLE(MWA(J)) + XMWD = XMWD*XBASE + DBLE(MWD(J)) + ELSE + XMWA = XMWA*XBASE + XMWD = XMWD*XBASE + ENDIF + ENDDO + ENDIF + MQDMWA = AINT(XMWA*XBR) + IF (MQDMWA < 0) MQDMWA = MQDMWA - 1 + MQDMWD = AINT(XMWD*XBR) + IF (MQDMWD < 0) MQDMWD = MQDMWD - 1 + MWA(KPTMW) = MQDMWA + MWA(KPTMW+1) = 0 + MWA(KPTMW+2) = 0 + MWD(KPTMW) = MQDMWD + MWD(KPTMW+1) = 0 + MWD(KPTMW+2) = 0 + +! Final normalization. + + DO J = KPTMW-1, 3, -1 + IF (MWA(J) < 0) THEN + MCARRY = INT((-MWA(J)-1)/MBASE) + 1 + MWA(J) = MWA(J) + MCARRY*MBASE + MWA(J-1) = MWA(J-1) - MCARRY + ELSE IF (MWA(J) >= MBASE) THEN + MCARRY = -INT(MWA(J)/MBASE) + MWA(J) = MWA(J) + MCARRY*MBASE + MWA(J-1) = MWA(J-1) - MCARRY + ENDIF + IF (MWD(J) < 0) THEN + MCARRY = INT((-MWD(J)-1)/MBASE) + 1 + MWD(J) = MWD(J) + MCARRY*MBASE + MWD(J-1) = MWD(J-1) - MCARRY + ELSE IF (MWD(J) >= MBASE) THEN + MCARRY = -INT(MWD(J)/MBASE) + MWD(J) = MWD(J) + MCARRY*MBASE + MWD(J-1) = MWD(J-1) - MCARRY + ENDIF + ENDDO + +! Round, affix the sign, and return. + + IF ((MAS > 0 .AND. MCS > 0) .OR. (MAS < 0 .AND. MCS < 0)) THEN + JRSIGN = 1 + ELSE + JRSIGN = -1 + ENDIF + IF (MWA(2) == 0) THEN + MLR = 2*MWA(NDIG+3) + 1 + IF (KROUND == -1 .OR. KROUND == 2) THEN + CALL FMRND(MWA,NDIG,NGUARD,1) + ELSE IF (MLR >= MBASE) THEN + IF (MLR-1 > MBASE .AND. MWA(N1+1) < MBASE-1) THEN + IF (KROUND /= 0 .OR. NCALL > 1) THEN + MWA(N1+1) = MWA(N1+1) + 1 + MWA(N1+2) = 0 + ENDIF + ELSE + CALL FMRND(MWA,NDIG,NGUARD,1) + ENDIF + ENDIF + ELSE + MLR = 2*MWA(NDIG+2) + 1 + IF (KROUND == -1 .OR. KROUND == 2) THEN + CALL FMRND(MWA,NDIG,NGUARD,0) + ELSE IF (MLR >= MBASE) THEN + IF (MLR-1 > MBASE .AND. MWA(N1) < MBASE-1) THEN + IF (KROUND /= 0 .OR. NCALL > 1) THEN + MWA(N1) = MWA(N1) + 1 + MWA(N1+1) = 0 + ENDIF + ELSE + CALL FMRND(MWA,NDIG,NGUARD,0) + ENDIF + ENDIF + ENDIF + CALL FMMOVE(MWA,MD) + + IF ((MBS > 0 .AND. MCS > 0) .OR. (MBS < 0 .AND. MCS < 0)) THEN + JRSIGN = 1 + ELSE + JRSIGN = -1 + ENDIF + IF (MWD(2) == 0) THEN + MLR = 2*MWD(NDIG+3) + 1 + IF (KROUND == -1 .OR. KROUND == 2) THEN + CALL FMRND(MWD,NDIG,NGUARD,1) + ELSE IF (MLR >= MBASE) THEN + IF (MLR-1 > MBASE .AND. MWD(N1+1) < MBASE-1) THEN + IF (KROUND /= 0 .OR. NCALL > 1) THEN + MWD(N1+1) = MWD(N1+1) + 1 + MWD(N1+2) = 0 + ENDIF + ELSE + CALL FMRND(MWD,NDIG,NGUARD,1) + ENDIF + ENDIF + ELSE + MLR = 2*MWD(NDIG+2) + 1 + IF (KROUND == -1 .OR. KROUND == 2) THEN + CALL FMRND(MWD,NDIG,NGUARD,0) + ELSE IF (MLR >= MBASE) THEN + IF (MLR-1 > MBASE .AND. MWD(N1) < MBASE-1) THEN + IF (KROUND /= 0 .OR. NCALL > 1) THEN + MWD(N1) = MWD(N1) + 1 + MWD(N1+1) = 0 + ENDIF + ELSE + CALL FMRND(MWD,NDIG,NGUARD,0) + ENDIF + ENDIF + ENDIF + CALL FMMOVE(MWD,ME) + + IF (KFLAG < 0) THEN + NAMEST(NCALL) = 'FMDIVD' + CALL FMWARN + ENDIF + + MD(-1) = 1 + IF (MAS*MCS < 0 .AND. MD(1) /= MUNKNO .AND. MD(2) /= 0) MD(-1) = -1 + ME(-1) = 1 + IF (MBS*MCS < 0 .AND. ME(1) /= MUNKNO .AND. ME(2) /= 0) ME(-1) = -1 + + IF (KACCSW == 1) THEN + MD2B = NINT((NDIG-1)*ALOGM2 + LOG(REAL(ABS(MD(2))+1))/0.69315) + MD(0) = MIN(MACCA,MACCC,MD2B) + MD2B = NINT((NDIG-1)*ALOGM2 + LOG(REAL(ABS(ME(2))+1))/0.69315) + ME(0) = MIN(MACCB,MACCC,MD2B) + ELSE + MD(0) = MIN(MACCA,MACCC) + ME(0) = MIN(MACCB,MACCC) + ENDIF + + 130 IF (NTRACE /= 0) THEN + CALL FMNTR(1,MD,MD,1,1) + IF (ABS(NTRACE) >= 1 .AND. NCALL <= LVLTRC) THEN + IF (NTRACE < 0) THEN + CALL FMNTRJ(ME,NDIG) + ELSE + CALL FMPRNT(ME) + ENDIF + ENDIF + ENDIF + NCALL = NCALL - 1 + JRSIGN = JRSSAV + RETURN + END SUBROUTINE FMDIVD + + SUBROUTINE FMDIVI(MA,IVAL,MB) + +! MB = MA / IVAL + +! Divide FM number MA by one word integer IVAL. + +! This routine is faster than FMDIV when the divisor is less than +! MXBASE (the square root of the largest integer). +! When IVAL is not less than MXBASE, FMDIV2 is used. In this case, +! if IVAL is known to be a product of two integers less than +! MXBASE, it is usually faster to make two calls to FMDIVI with +! half-word factors than one call with their product. + + USE FMVALS + IMPLICIT NONE + + REAL (KIND(1.0D0)) :: MA(-1:LUNPCK),MB(-1:LUNPCK) + INTEGER IVAL + REAL (KIND(1.0D0)) :: MACCA,MD2B + + KFLAG = 0 + MACCA = MA(0) + NCALL = NCALL + 1 + IF (NTRACE /= 0) THEN + NAMEST(NCALL) = 'FMDIVI' + CALL FMNTR(2,MA,MA,1,1) + CALL FMNTRI(2,IVAL,0) + CALL FMDIVN(MA,IVAL,MB) + IF (KACCSW == 1) THEN + MD2B = NINT((NDIG-1)*ALOGM2 + LOG(REAL(ABS(MB(2))+1))/ & + 0.69315) + MB(0) = MIN(MACCA,MD2B) + ELSE + MB(0) = MACCA + ENDIF + CALL FMNTR(1,MB,MB,1,1) + ELSE + CALL FMDIVN(MA,IVAL,MB) + IF (KACCSW == 1) THEN + MD2B = NINT((NDIG-1)*ALOGM2 + LOG(REAL(ABS(MB(2))+1))/ & + 0.69315) + MB(0) = MIN(MACCA,MD2B) + ELSE + MB(0) = MACCA + ENDIF + ENDIF + NCALL = NCALL - 1 + RETURN + END SUBROUTINE FMDIVI + + SUBROUTINE FMDIVN(MA,IVAL,MB) + +! Internal divide by integer routine. MB = MA / IVAL + + USE FMVALS + IMPLICIT NONE + + REAL (KIND(1.0D0)) :: MA(-1:LUNPCK),MB(-1:LUNPCK) + INTEGER IVAL + REAL (KIND(1.0D0)) :: MA1,MAS,MKT,MLR,MODINT,MVALP + INTEGER J,JRSSAV,KA,KB,KL,KPT,KPTWA,N1,NGUARD,NMVAL,NV2 + +! Check for special cases. + + IF (MBLOGS /= MBASE) CALL FMCONS + JRSSAV = JRSIGN + N1 = NDIG + 1 + IF (MA(1) == MUNKNO .OR. IVAL == 0) THEN + MA1 = MA(1) + CALL FMIM(0,MB) + MB(0) = NINT(NDG2MX*ALOGM2) + MB(1) = MUNKNO + MB(2) = 1 + KFLAG = -4 + IF (MA1 /= MUNKNO) THEN + NAMEST(NCALL) = 'FMDIVI' + CALL FMWARN + ENDIF + JRSIGN = JRSSAV + RETURN + ENDIF + + IF (MA(2) == 0) THEN + CALL FMEQ(MA,MB) + JRSIGN = JRSSAV + RETURN + ENDIF + + IF (ABS(MA(1)) < MEXPOV .AND. ABS(IVAL) > 1) GO TO 110 + + IF (ABS(IVAL) == 1) THEN + DO J = 0, N1 + MB(J) = MA(J) + ENDDO + MB(-1) = MA(-1)*IVAL + IF (MA(1) == MEXPOV) KFLAG = -5 + IF (MA(1) == MEXPUN) KFLAG = -6 + JRSIGN = JRSSAV + RETURN + ENDIF + + IF (MA(1) == MEXPUN) THEN + MAS = MA(-1) + CALL FMIM(0,MB) + MB(1) = MEXPUN + MB(2) = 1 + MB(0) = NINT(NDIG*ALOGM2) + IF ((MAS < 0 .AND. IVAL > 0) .OR. & + (MAS > 0 .AND. IVAL < 0)) MB(-1) = -1 + KFLAG = -6 + JRSIGN = JRSSAV + RETURN + ENDIF + + IF (MA(1) == MEXPOV) THEN + NAMEST(NCALL) = 'FMDIVI' + CALL FMIM(0,MB) + MB(1) = MUNKNO + MB(2) = 1 + MB(0) = NINT(NDIG*ALOGM2) + KFLAG = -4 + CALL FMWARN + JRSIGN = JRSSAV + RETURN + ENDIF + +! NGUARD is the number of guard digits used. + + 110 IF (NCALL > 1) THEN + NGUARD = NGRD21 + ELSE + NGUARD = NGRD52 + IF (MBASE < 1000 .OR. KROUND /= 1 .OR. KRPERF == 1) THEN + NGUARD = NDIG + 10 + ENDIF + ENDIF + +! If ABS(IVAL) >= MXBASE use FMDIV. + + MVALP = ABS(IVAL) + NMVAL = INT(MVALP) + NV2 = NMVAL - 1 + IF (ABS(IVAL) > MXBASE .OR. NMVAL /= ABS(IVAL) .OR. & + NV2 /= ABS(IVAL)-1) THEN + CALL FMIM(IVAL,M01) + CALL FMDIV2(MA,M01,MB) + JRSIGN = JRSSAV + RETURN + ENDIF + +! Work with positive numbers. + + MAS = MA(-1) + +! Find the first significant digit of the quotient. + + MKT = MA(2) + IF (MKT >= MVALP) THEN + KPT = 2 + GO TO 130 + ENDIF + DO J = 3, N1 + MKT = MKT*MBASE + MA(J) + IF (MKT >= MVALP) THEN + KPT = J + GO TO 130 + ENDIF + ENDDO + KPT = N1 + + 120 KPT = KPT + 1 + MKT = MKT*MBASE + IF (MKT < MVALP) GO TO 120 + +! Do the rest of the division. + + 130 KA = KPT + 1 + MWA(1) = MA(1) + 2 - KPT + MWA(2) = INT (MKT/MVALP) + MODINT = MKT - MWA(2)*MVALP + KPTWA = 2 + IF (KA <= N1) THEN + KL = 3 - KA + +! (Inner Loop) + + DO J = KA, N1 + MKT = MODINT*MBASE + MA(J) + MWA(KL+J) = INT (MKT/MVALP) + MODINT = MKT - MWA(KL+J)*MVALP + ENDDO + KPTWA = KL + N1 + ENDIF + + KA = KPTWA + 1 + KB = N1 + NGUARD + DO J = KA, KB + MKT = MODINT*MBASE + MWA(J) = INT (MKT/MVALP) + MODINT = MKT - MWA(J)*MVALP + ENDDO + +! Round the result, put the sign on MB and return. + + MLR = 2*MWA(NDIG+2) + 1 + IF ((MAS > 0 .AND. IVAL > 0) .OR. (MAS < 0 .AND. IVAL < 0)) THEN + JRSIGN = 1 + ELSE + JRSIGN = -1 + ENDIF + IF (KROUND == -1 .OR. KROUND == 2) THEN + CALL FMRND(MWA,NDIG,NGUARD,0) + ELSE IF (MLR >= MBASE) THEN + IF (MLR-1 > MBASE .AND. MWA(N1) < MBASE-1) THEN + IF (KROUND /= 0 .OR. NCALL > 1) THEN + MWA(N1) = MWA(N1) + 1 + MWA(N1+1) = 0 + ENDIF + ELSE + CALL FMRND(MWA,NDIG,NGUARD,0) + ENDIF + ENDIF + CALL FMMOVE(MWA,MB) + + IF (KFLAG < 0) THEN + NAMEST(NCALL) = 'FMDIVI' + CALL FMWARN + ENDIF + MB(-1) = JRSIGN + JRSIGN = JRSSAV + RETURN + END SUBROUTINE FMDIVN + + SUBROUTINE FMDIVI_R1(MA,IVAL) + +! MA = MA / IVAL + +! Divide FM number MA by one word integer IVAL. + +! This routine is faster than FMDIV when the divisor is less than +! MXBASE (the square root of the largest integer). +! When IVAL is not less than MXBASE, FMDIV2 is used. In this case, +! if IVAL is known to be a product of two integers less than +! MXBASE, it is usually faster to make two calls to FMDIVI with +! half-word factors than one call with their product. + + USE FMVALS + IMPLICIT NONE + + REAL (KIND(1.0D0)) :: MA(-1:LUNPCK) + INTEGER IVAL + REAL (KIND(1.0D0)) :: MACCA,MD2B + + KFLAG = 0 + MACCA = MA(0) + NCALL = NCALL + 1 + IF (NTRACE /= 0) THEN + NAMEST(NCALL) = 'FMDIVI' + CALL FMNTR(2,MA,MA,1,1) + CALL FMNTRI(2,IVAL,0) + CALL FMDIVN_R1(MA,IVAL) + IF (KACCSW == 1) THEN + MD2B = NINT((NDIG-1)*ALOGM2 + LOG(REAL(ABS(MA(2))+1))/ & + 0.69315) + MA(0) = MIN(MACCA,MD2B) + ELSE + MA(0) = MACCA + ENDIF + CALL FMNTR(1,MA,MA,1,1) + ELSE + CALL FMDIVN_R1(MA,IVAL) + IF (KACCSW == 1) THEN + MD2B = NINT((NDIG-1)*ALOGM2 + LOG(REAL(ABS(MA(2))+1))/ & + 0.69315) + MA(0) = MIN(MACCA,MD2B) + ELSE + MA(0) = MACCA + ENDIF + ENDIF + NCALL = NCALL - 1 + RETURN + END SUBROUTINE FMDIVI_R1 + + SUBROUTINE FMDIVN_R1(MA,IVAL) + +! Internal divide by integer routine. MA = MA / IVAL + + USE FMVALS + IMPLICIT NONE + + REAL (KIND(1.0D0)) :: MA(-1:LUNPCK) + INTEGER IVAL + REAL (KIND(1.0D0)) :: MA1,MAS,MKT,MLR,MODINT,MVALP + INTEGER J,JRSSAV,KA,KB,KL,KPT,KPTWA,N1,NGUARD,NMVAL,NV2 + +! Check for special cases. + + IF (MBLOGS /= MBASE) CALL FMCONS + JRSSAV = JRSIGN + N1 = NDIG + 1 + IF (MA(1) == MUNKNO .OR. IVAL == 0) THEN + MA1 = MA(1) + CALL FMIM(0,MA) + MA(0) = NINT(NDG2MX*ALOGM2) + MA(1) = MUNKNO + MA(2) = 1 + KFLAG = -4 + IF (MA1 /= MUNKNO) THEN + NAMEST(NCALL) = 'FMDIVI' + CALL FMWARN + ENDIF + JRSIGN = JRSSAV + RETURN + ENDIF + + IF (MA(2) == 0) THEN + JRSIGN = JRSSAV + RETURN + ENDIF + + IF (ABS(MA(1)) < MEXPOV .AND. ABS(IVAL) > 1) GO TO 110 + + IF (ABS(IVAL) == 1) THEN + MA(-1) = MA(-1)*IVAL + IF (MA(1) == MEXPOV) KFLAG = -5 + IF (MA(1) == MEXPUN) KFLAG = -6 + JRSIGN = JRSSAV + RETURN + ENDIF + + IF (MA(1) == MEXPUN) THEN + MAS = MA(-1) + CALL FMIM(0,MA) + MA(1) = MEXPUN + MA(2) = 1 + MA(0) = NINT(NDIG*ALOGM2) + IF ((MAS < 0 .AND. IVAL > 0) .OR. & + (MAS > 0 .AND. IVAL < 0)) MA(-1) = -1 + KFLAG = -6 + JRSIGN = JRSSAV + RETURN + ENDIF + + IF (MA(1) == MEXPOV) THEN + NAMEST(NCALL) = 'FMDIVI' + CALL FMIM(0,MA) + MA(1) = MUNKNO + MA(2) = 1 + MA(0) = NINT(NDIG*ALOGM2) + KFLAG = -4 + CALL FMWARN + JRSIGN = JRSSAV + RETURN + ENDIF + +! NGUARD is the number of guard digits used. + + 110 IF (NCALL > 1) THEN + NGUARD = NGRD21 + ELSE + NGUARD = NGRD52 + IF (MBASE < 1000 .OR. KROUND /= 1 .OR. KRPERF == 1) THEN + NGUARD = NDIG + 10 + ENDIF + ENDIF + +! If ABS(IVAL) >= MXBASE use FMDIV. + + MVALP = ABS(IVAL) + NMVAL = INT(MVALP) + NV2 = NMVAL - 1 + IF (ABS(IVAL) > MXBASE .OR. NMVAL /= ABS(IVAL) .OR. & + NV2 /= ABS(IVAL)-1) THEN + CALL FMIM(IVAL,M01) + CALL FMDIV2_R1(MA,M01) + JRSIGN = JRSSAV + RETURN + ENDIF + +! Work with positive numbers. + + MAS = MA(-1) + +! Find the first significant digit of the quotient. + + MKT = MA(2) + IF (MKT >= MVALP) THEN + KPT = 2 + GO TO 130 + ENDIF + DO J = 3, N1 + MKT = MKT*MBASE + MA(J) + IF (MKT >= MVALP) THEN + KPT = J + GO TO 130 + ENDIF + ENDDO + KPT = N1 + + 120 KPT = KPT + 1 + MKT = MKT*MBASE + IF (MKT < MVALP) GO TO 120 + +! Do the rest of the division. + + 130 KA = KPT + 1 + MWA(1) = MA(1) + 2 - KPT + MWA(2) = INT (MKT/MVALP) + MODINT = MKT - MWA(2)*MVALP + KPTWA = 2 + IF (KA <= N1) THEN + KL = 3 - KA + +! (Inner Loop) + + DO J = KA, N1 + MKT = MODINT*MBASE + MA(J) + MWA(KL+J) = INT (MKT/MVALP) + MODINT = MKT - MWA(KL+J)*MVALP + ENDDO + KPTWA = KL + N1 + ENDIF + + KA = KPTWA + 1 + KB = N1 + NGUARD + DO J = KA, KB + MKT = MODINT*MBASE + MWA(J) = INT (MKT/MVALP) + MODINT = MKT - MWA(J)*MVALP + ENDDO + +! Round the result, put the sign on MA and return. + + MLR = 2*MWA(NDIG+2) + 1 + IF ((MAS > 0 .AND. IVAL > 0) .OR. (MAS < 0 .AND. IVAL < 0)) THEN + JRSIGN = 1 + ELSE + JRSIGN = -1 + ENDIF + IF (KROUND == -1 .OR. KROUND == 2) THEN + CALL FMRND(MWA,NDIG,NGUARD,0) + ELSE IF (MLR >= MBASE) THEN + IF (MLR-1 > MBASE .AND. MWA(N1) < MBASE-1) THEN + IF (KROUND /= 0 .OR. NCALL > 1) THEN + MWA(N1) = MWA(N1) + 1 + MWA(N1+1) = 0 + ENDIF + ELSE + CALL FMRND(MWA,NDIG,NGUARD,0) + ENDIF + ENDIF + CALL FMMOVE(MWA,MA) + + IF (KFLAG < 0) THEN + NAMEST(NCALL) = 'FMDIVI' + CALL FMWARN + ENDIF + MA(-1) = JRSIGN + JRSIGN = JRSSAV + RETURN + END SUBROUTINE FMDIVN_R1 + + SUBROUTINE FMDM(X,MA) + +! Internal routine for converting double precision to multiple +! precision. Called by FMDPM. + + USE FMVALS + IMPLICIT NONE + + DOUBLE PRECISION X + REAL (KIND(1.0D0)) :: MA(-1:LUNPCK) + + DOUBLE PRECISION ONE,XBASE,Y,Y2,YT + REAL (KIND(1.0D0)) :: MK,MN + INTEGER J,K,N1,NE + + IF (MBLOGS /= MBASE) CALL FMCONS + KFLAG = 0 + N1 = NDIG + 1 + + ONE = 1.0D0 + XBASE = MBASE + K = 0 + +! NE-1 is the number of words at the current precision and +! base roughly equal to machine precision. + + NE = INT(DLOGEB) + 3 + Y = X + IF (X < 0.0) Y = -X + + IF (X == 0.0) THEN + DO J = 1, N1 + MA(J) = 0 + ENDDO + GO TO 160 + ENDIF + +! Get the exponent. + + IF (Y > ONE) THEN + IF (Y/XBASE < Y) THEN + 110 K = K + 1 + Y = Y/XBASE + IF (Y > ONE) GO TO 110 + IF (Y < ONE) THEN + MA(1) = K + GO TO 140 + ENDIF + GO TO 130 + ELSE + KFLAG = -4 + CALL FMWARN + DO J = 1, N1 + MA(J) = 0 + ENDDO + MA(1) = MUNKNO + MA(2) = 1 + MA(-1) = 1 + MA(0) = NINT(NDIG*ALOGM2) + RETURN + ENDIF + ENDIF + + IF (Y < ONE) THEN + IF (Y*XBASE > Y) THEN + 120 K = K - 1 + Y = Y*XBASE + IF (Y < ONE) GO TO 120 + IF (Y > ONE) THEN + K = K + 1 + Y = Y/XBASE + MA(1) = K + GO TO 140 + ENDIF + ELSE + KFLAG = -4 + CALL FMWARN + DO J = 1, N1 + MA(J) = 0 + ENDDO + MA(1) = MUNKNO + MA(2) = 1 + MA(-1) = 1 + MA(0) = NINT(NDIG*ALOGM2) + RETURN + ENDIF + ENDIF + + 130 MA(1) = K + 1 + MA(2) = 1 + DO J = 3, N1 + MA(J) = 0 + ENDDO + GO TO 160 + +! Build the rest of the number. + + 140 DO J = 2, NE + Y = Y*XBASE + MK = AINT(Y) + YT = -MK + CALL FMDBL(Y,YT,Y2) + Y = Y2 + MA(J) = MK + IF (J >= N1) GO TO 150 + ENDDO + K = NE + 1 + DO J = K, N1 + MA(J) = 0 + ENDDO + +! Normalize. + + 150 IF (ABS(MA(2)) >= MBASE) THEN + K = N1 + 1 + DO J = 3, N1 + K = K - 1 + MA(K) = MA(K-1) + ENDDO + MN = AINT (MA(2)/MBASE) + MA(3) = MA(2) - MN*MBASE + MA(2) = MN + MA(1) = MA(1) + 1 + GO TO 160 + ENDIF + + IF (MA(2) == 0) THEN + DO J = 2, NDIG + MA(J) = MA(J+1) + ENDDO + MA(1) = MA(1) - 1 + MA(N1) = 0 + ENDIF + + 160 MA(-1) = 1 + IF (X < 0.0 .AND. MA(1) /= MUNKNO .AND. MA(2) /= 0) MA(-1) = -1 + MA(0) = MIN(NINT((NE-1)*ALOGM2),NINT(NDIG*ALOGM2)) + RETURN + END SUBROUTINE FMDM + + SUBROUTINE FMDM2(X,MA) + +! Internal routine for converting double precision to multiple +! precision. Called by FMDP2M. + + USE FMVALS + IMPLICIT NONE + + DOUBLE PRECISION X + REAL (KIND(1.0D0)) :: MA(-1:LUNPCK) + DOUBLE PRECISION Y,TWO20 + INTEGER J,JEXP,K,KEXP,KRESLT,N1,NDSAVE + +! Increase the working precision. + + NDSAVE = NDIG + IF (NCALL == 1) THEN + K = MAX(NGRD21,1) + NDIG = MAX(NDIG+K,2) + IF (NDIG > NDG2MX) THEN + KFLAG = -9 + CALL FMWARN + NDIG = NDSAVE + KRESLT = 12 + CALL FMRSLT(MA,MA,M07,KRESLT) + CALL FMEQ(M07,MA) + IF (NTRACE /= 0) CALL FMNTR(1,MA,MA,1,1) + NCALL = NCALL - 1 + RETURN + ENDIF + ENDIF + + IF (MBLOGS /= MBASE) CALL FMCONS + KFLAG = 0 + N1 = NDIG + 1 + + IF (X == 0.0D0) THEN + DO J = 1, N1 + MA(J) = 0 + ENDDO + GO TO 140 + ENDIF + + Y = ABS(X) + TWO20 = 1048576.0D0 + +! If this power of two is not representable at the current +! base and precision, use a smaller one. + + IF (INT(NDIG*ALOGM2) < 20) THEN + K = INT(NDIG*ALOGM2) + TWO20 = 1.0D0 + DO J = 1, K + TWO20 = TWO20*2.0D0 + ENDDO + ENDIF + + KEXP = 0 + IF (Y > TWO20) THEN + 110 Y = Y/TWO20 + KEXP = KEXP + 1 + IF (Y > TWO20) GO TO 110 + ELSE IF (Y < 1.0D0) THEN + 120 Y = Y*TWO20 + KEXP = KEXP - 1 + IF (Y < 1.0D0) GO TO 120 + ENDIF + + K = INT(TWO20) + CALL FMI2M(K,M04) + K = INT(Y) + CALL FMI2M(K,M02) + Y = (Y-DBLE(K))*TWO20 + JEXP = 0 + + 130 K = INT(Y) + CALL FMI2M(K,M03) + CALL FMMPY_R1(M02,M04) + JEXP = JEXP + 1 + CALL FMADD_R1(M02,M03) + Y = (Y-DBLE(K))*TWO20 + IF (JEXP <= 1000 .AND. Y /= 0.0D0) GO TO 130 + + K = KEXP - JEXP + CALL FMIPWR(M04,K,M03) + CALL FMMPY(M02,M03,MA) + + 140 MA(-1) = 1 + IF (X < 0.0 .AND. MA(1) /= MUNKNO .AND. MA(2) /= 0) MA(-1) = -1 + MA(0) = NINT((NDSAVE-1)*ALOGM2 + LOG(REAL(ABS(MA(2))+1))/0.69315) + NDIG = NDSAVE + RETURN + END SUBROUTINE FMDM2 + + SUBROUTINE FMDP2M(X,MA) + +! MA = X + +! Convert a double precision floating point number to FM format. + +! This version tries to convert the REAL (KIND(1.0D0)) :: Machine +! number to FM with accuracy of nearly full FM precision. +! If conversion to FM with approximately double precision accuracy +! is good enough, FMDPM is faster and uses less scratch space. + +! This routine assumes the machine's base for double precision is +! a power of two. + + USE FMVALS + IMPLICIT NONE + + DOUBLE PRECISION X + REAL (KIND(1.0D0)) :: MA(-1:LUNPCK) + NCALL = NCALL + 1 + NAMEST(NCALL) = 'FMDP2M' + IF (NTRACE /= 0) CALL FMNTRR(2,X,1) + + CALL FMDM2(X,MA) + + IF (NTRACE /= 0) CALL FMNTR(1,MA,MA,1,1) + NCALL = NCALL - 1 + RETURN + END SUBROUTINE FMDP2M + + SUBROUTINE FMDPM(X,MA) + +! MA = X + +! Convert a double precision floating point number to FM format. + +! In general, the relative accuracy of the FM number returned is only +! the relative accuracy of a machine precision number. This may be +! true even if X can be represented exactly in the machine floating +! point number system. + +! This version is faster than FMDP2M, but often less accurate. +! No scratch arrays are used. + + USE FMVALS + IMPLICIT NONE + + DOUBLE PRECISION X + REAL (KIND(1.0D0)) :: MA(-1:LUNPCK) + + DOUBLE PRECISION Y,YT + INTEGER K + + NCALL = NCALL + 1 + NAMEST(NCALL) = 'FMDPM ' + IF (NTRACE /= 0) CALL FMNTRR(2,X,1) + +! Check to see if X is exactly a small integer. If so, +! converting as an integer is better. +! Also see if X is exactly a small integer divided by +! a small power of two. + + Y = 1048576.0D0 + IF (ABS(X) < Y) THEN + K = INT(X) + Y = K + IF (Y == X) THEN + CALL FMIM(K,MA) + GO TO 110 + ENDIF + ENDIF + IF (ABS(X) < 1.0D0) THEN + Y = 4096.0D0*X + K = INT(Y) + YT = K + IF (Y == YT) THEN + CALL FMIM(K,MA) + CALL FMDIVI_R1(MA,4096) + GO TO 110 + ENDIF + ENDIF + + CALL FMDM(X,MA) + + 110 IF (NTRACE /= 0) CALL FMNTR(1,MA,MA,1,1) + NCALL = NCALL - 1 + RETURN + END SUBROUTINE FMDPM + + SUBROUTINE FMENTR(NROUTN,MA,MB,NARGS,KNAM,MC,KRESLT,NDSAVE,MXSAVE, & + KASAVE,KOVUN) + +! Do the argument checking and increasing of precision and overflow +! threshold upon entry to an FM routine. + +! NROUTN - routine name of calling routine +! MA - first input argument +! MB - second input argument (optional) +! NARGS - number of input arguments +! KNAM - positive if the routine name is to be printed. +! MC - result argument +! KRESLT - returned nonzero if the input arguments give the result +! immediately (e.g., MA*0 or OVERFLOW*MB) +! NDSAVE - saves the value of NDIG after NDIG is increased +! MXSAVE - saves the value of MXEXP +! KASAVE - saves the value of KACCSW +! KOVUN - returned nonzero if an input argument is (+ or -) overflow +! or underflow. + + USE FMVALS + IMPLICIT NONE + + CHARACTER(6) :: NROUTN + REAL (KIND(1.0D0)) :: MA(-1:LUNPCK),MB(-1:LUNPCK),MC(-1:LUNPCK),MXSAVE + INTEGER KNAM,NARGS,KRESLT,NDSAVE,KASAVE,KOVUN + + REAL (KIND(1.0D0)) :: MACCAB + INTEGER K + + NCALL = NCALL + 1 + NAMEST(NCALL) = NROUTN + IF (NTRACE /= 0) CALL FMNTR(2,MA,MB,NARGS,KNAM) + CALL FMARGS(NROUTN,NARGS,MA,MB,KRESLT) + + IF (MBLOGS /= MBASE) CALL FMCONS + KOVUN = 0 + IF (MA(1) == MEXPOV .OR. MA(1) == MEXPUN) KOVUN = 1 + IF (NARGS == 2) THEN + IF (MB(1) == MEXPOV .OR. MB(1) == MEXPUN) KOVUN = 1 + ENDIF + +! Increase the working precision. + + NDSAVE = NDIG + IF (NCALL == 1) THEN + K = MAX(NGRD52-1,2) + NDIG = MAX(NDIG+K,2) + IF (NDIG > NDG2MX) THEN + KFLAG = -9 + CALL FMWARN + KRESLT = 12 + NDIG = NDSAVE + ENDIF + ENDIF + + IF (KRESLT /= 0) THEN + MACCAB = MA(0) + IF (NARGS == 2) MACCAB = MIN(MACCAB,MB(0)) + IF (KRESLT == 9 .OR. KRESLT == 10 .OR. KRESLT >= 13) THEN + IF (KRAD == 1) THEN + CALL FMPI(MC) + ELSE + CALL FMI2M(180,MC) + ENDIF + IF (KRESLT <= 10) CALL FMDIVI_R1(MC,2) + IF (KRESLT >= 14) CALL FMDIVI_R1(MC,4) + CALL FMEQ2_R1(MC,NDIG,NDSAVE) + NDIG = NDSAVE + IF ((KRESLT == 9 .OR. KRESLT == 14) .AND. & + MC(1) /= MUNKNO .AND. MC(2) /= 0) & + MC(-1) = -MC(-1) + MC(0) = MACCAB + IF (NTRACE /= 0) CALL FMNTR(1,MC,MC,1,1) + KASAVE = KACCSW + MXSAVE = MXEXP + NCALL = NCALL - 1 + RETURN + ENDIF + + NDIG = NDSAVE + CALL FMRSLT(MA,MB,MC,KRESLT) + IF (NTRACE /= 0) CALL FMNTR(1,MC,MC,1,1) + KASAVE = KACCSW + MXSAVE = MXEXP + NCALL = NCALL - 1 + RETURN + ENDIF + + KASAVE = KACCSW + KACCSW = 0 + +! Extend the overflow/underflow threshold. + + MXSAVE = MXEXP + MXEXP = MXEXP2 + RETURN + END SUBROUTINE FMENTR + + SUBROUTINE FMEQ(MA,MB) + +! MB = MA + +! This is the standard form of equality, where MA and MB both +! have precision NDIG. Use FMEQU for assignments that also +! change precision. + + USE FMVALS + IMPLICIT NONE + + REAL (KIND(1.0D0)) :: MA(-1:LUNPCK),MB(-1:LUNPCK) + + INTEGER J + + DO J = -1, NDIG+1 + MB(J) = MA(J) + ENDDO + +! Check for overflow or underflow. + + IF (ABS(MB(1)) > MXEXP) THEN + IF (MB(1) /= MUNKNO .OR. MB(2) /= 1) THEN + NCALL = NCALL + 1 + CALL FMTRAP(MB) + NCALL = NCALL - 1 + ENDIF + IF (MB(1) == MUNKNO) KFLAG = -4 + ENDIF + + RETURN + END SUBROUTINE FMEQ + + SUBROUTINE FMEQ2(MA,MB,NDA,NDB) + +! Set MB (having NDB digits) equal to MA (having NDA digits). + +! If MB has less precision than MA the result is rounded to NDB digits. + +! If MB has more precision the result has zero digits padded on the +! right. + + USE FMVALS + IMPLICIT NONE + + REAL (KIND(1.0D0)) :: MA(-1:LUNPCK),MB(-1:LUNPCK) + INTEGER NDA,NDB + + REAL (KIND(1.0D0)) :: M2,MACCA,MBS,MKT + INTEGER J,JT,K,KB,L,N1 + + IF (MBLOGS /= MBASE) CALL FMCONS + MACCA = MA(0) + +! Check for precision in range. + + IF (NDA < 1 .OR. NDA > NDG2MX .OR. NDB < 1 .OR. & + NDB > NDG2MX) THEN + NCALL = NCALL + 1 + NAMEST(NCALL) = 'FMEQU ' + KFLAG = -1 + CALL FMWARN + WRITE (KW, & + "(/' The two precisions in FMEQU were NDA =',I10," // & + "' NDB =',I10/)" & + ) NDA,NDB + CALL FMIM(0,MB) + KFLAG = -1 + MB(1) = MUNKNO + MB(2) = 1 + MB(0) = NINT(NDIG*ALOGM2) + NCALL = NCALL - 1 + RETURN + ENDIF + MBS = MA(-1) + MB(-1) = MBS + +! Check for special symbols. + + KFLAG = 0 + IF (ABS(MA(1)) >= MEXPOV) THEN + DO J = 2, NDB + MB(J+1) = 0 + ENDDO + MB(1) = MA(1) + MB(2) = MA(2) + GO TO 150 + ENDIF + + IF (NDB == NDA) GO TO 130 + + IF (NDB > NDA) GO TO 140 + +! Round to NDB digits. + + N1 = NDB + 1 + DO J = 1, N1 + MB(J) = MA(J) + ENDDO + IF (KROUND == -1 .AND. NCALL <= 1) THEN + IF (MA(-1) > 0) GO TO 150 + DO J = NDB+2, NDA+1 + IF (MA(J) > 0) GO TO 110 + ENDDO + GO TO 150 + ENDIF + IF (KROUND == 2 .AND. NCALL <= 1) THEN + IF (MA(-1) < 0) GO TO 150 + DO J = NDB+2, NDA+1 + IF (MA(J) > 0) GO TO 110 + ENDDO + GO TO 150 + ENDIF + IF (KROUND == 0 .AND. NCALL <= 1) GO TO 150 + + L = NDB + 2 + IF (2*(MA(L)+1) < MBASE) GO TO 150 + M2 = 2 + IF (INT(MBASE-AINT (MBASE/M2)*M2) == 0) THEN + IF (2*MA(L) < MBASE) GO TO 150 + IF (2*MA(L) == MBASE) THEN + IF (L <= NDA) THEN + DO J = L, NDA + IF (MA(J+1) > 0) GO TO 110 + ENDDO + ENDIF + +! Round to even. + + IF (INT(MB(N1)-AINT (MB(N1)/M2)*M2) == 0) GO TO 150 + ENDIF + ELSE + IF (2*MA(L)+1 == MBASE) THEN + IF (L <= NDA) THEN + DO J = L, NDA + IF (2*(MA(J+1)+1) < MBASE) GO TO 150 + IF (2*MA(J+1) > MBASE) GO TO 110 + ENDDO + GO TO 150 + ENDIF + ENDIF + ENDIF + + 110 MB(NDB+1) = MB(NDB+1) + 1 + MB(NDB+2) = 0 + +! Check whether there was a carry in the rounded digit. + + KB = NDB + 1 + IF (KB >= 3) THEN + K = KB + 1 + DO J = 3, KB + K = K - 1 + IF (MB(K) < MBASE) GO TO 120 + MKT = AINT (MB(K)/MBASE) + MB(K-1) = MB(K-1) + MKT + MB(K) = MB(K) - MKT*MBASE + ENDDO + ENDIF + +! If there is a carry in the first digit then the exponent +! must be adjusted and the number shifted right. + + IF (MB(2) < MBASE) GO TO 120 + IF (KB >= 4) THEN + K = KB + 1 + DO J = 4, KB + K = K - 1 + MB(K) = MB(K-1) + ENDDO + ENDIF + + MKT = AINT (MB(2)/MBASE) + IF (KB >= 3) MB(3) = MB(2) - MKT*MBASE + MB(2) = MKT + MB(1) = MB(1) + 1 + + 120 IF (MBS < 0 .AND. MB(1) /= MUNKNO .AND. MB(2) /= 0) MB(-1) = -1 + GO TO 150 + +! MA and MB have the same precision. + + 130 DO J = 1, NDA+1 + MB(J) = MA(J) + ENDDO + GO TO 150 + +! Extend to NDB digits by padding with zeros. + + 140 DO J = 1, NDA+1 + MB(J) = MA(J) + ENDDO + DO J = NDA+2, NDB+1 + MB(J) = 0 + ENDDO + +! Check for overflow or underflow. + + 150 IF (ABS(MB(1)) > MXEXP) THEN + IF (MB(1) /= MUNKNO .OR. MB(2) /= 1) THEN + NCALL = NCALL + 1 + CALL FMTRAP(MB) + NCALL = NCALL - 1 + ENDIF + IF (MB(1) == MUNKNO) KFLAG = -4 + ENDIF + + IF (KACCSW == 1) THEN + JT = NINT(LOG(REAL(ABS(MB(2))+1))/0.69315) + IF (NDB > NDA) THEN + MB(0) = NINT((NDB-1)*ALOGM2 + JT) + ELSE + MB(0) = MIN(NINT((NDB-1)*ALOGM2+JT),INT(MACCA)) + ENDIF + ELSE + MB(0) = MA(0) + ENDIF + RETURN + END SUBROUTINE FMEQ2 + + SUBROUTINE FMEQ2_R1(MA,NDA,NDB) + +! Change precision of MA from NDA digits on input to NDB digits on output. + +! If NDB is less than NDA the result is rounded to NDB digits. + +! If NDB is greater than NDA the result has zero digits padded on the +! right. + + USE FMVALS + IMPLICIT NONE + + REAL (KIND(1.0D0)) :: MA(-1:LUNPCK) + INTEGER NDA,NDB + + REAL (KIND(1.0D0)) :: M2,MACCA,MBS,MKT + INTEGER J,JT,K,KB,L,N1 + + IF (MBLOGS /= MBASE) CALL FMCONS + MACCA = MA(0) + +! Check for precision in range. + + IF (NDA < 1 .OR. NDA > NDG2MX .OR. NDB < 1 .OR. & + NDB > NDG2MX) THEN + NCALL = NCALL + 1 + NAMEST(NCALL) = 'FMEQU ' + KFLAG = -1 + CALL FMWARN + WRITE (KW, & + "(/' The two precisions in FMEQU were NDA =',I10," // & + "' NDB =',I10/)" & + ) NDA,NDB + CALL FMIM(0,MA) + KFLAG = -1 + MA(1) = MUNKNO + MA(2) = 1 + MA(0) = NINT(NDIG*ALOGM2) + NCALL = NCALL - 1 + RETURN + ENDIF + MBS = MA(-1) + +! Check for special symbols. + + KFLAG = 0 + IF (ABS(MA(1)) >= MEXPOV) THEN + DO J = 2, NDB + MA(J+1) = 0 + ENDDO + GO TO 140 + ENDIF + + IF (NDB == NDA) GO TO 140 + + IF (NDB > NDA) GO TO 130 + +! Round to NDB digits. + + N1 = NDB + 1 + IF (KROUND == -1 .AND. NCALL <= 1) THEN + IF (MA(-1) > 0) GO TO 140 + DO J = NDB+2, NDA+1 + IF (MA(J) > 0) GO TO 110 + ENDDO + GO TO 140 + ENDIF + IF (KROUND == 2 .AND. NCALL <= 1) THEN + IF (MA(-1) < 0) GO TO 140 + DO J = NDB+2, NDA+1 + IF (MA(J) > 0) GO TO 110 + ENDDO + GO TO 140 + ENDIF + IF (KROUND == 0 .AND. NCALL <= 1) GO TO 140 + + L = NDB + 2 + IF (2*(MA(L)+1) < MBASE) GO TO 140 + M2 = 2 + IF (INT(MBASE-AINT (MBASE/M2)*M2) == 0) THEN + IF (2*MA(L) < MBASE) GO TO 140 + IF (2*MA(L) == MBASE) THEN + IF (L <= NDA) THEN + DO J = L, NDA + IF (MA(J+1) > 0) GO TO 110 + ENDDO + ENDIF + +! Round to even. + + IF (INT(MA(N1)-AINT (MA(N1)/M2)*M2) == 0) GO TO 140 + ENDIF + ELSE + IF (2*MA(L)+1 == MBASE) THEN + IF (L <= NDA) THEN + DO J = L, NDA + IF (2*(MA(J+1)+1) < MBASE) GO TO 140 + IF (2*MA(J+1) > MBASE) GO TO 110 + ENDDO + GO TO 140 + ENDIF + ENDIF + ENDIF + + 110 MA(NDB+1) = MA(NDB+1) + 1 + MA(NDB+2) = 0 + +! Check whether there was a carry in the rounded digit. + + KB = NDB + 1 + IF (KB >= 3) THEN + K = KB + 1 + DO J = 3, KB + K = K - 1 + IF (MA(K) < MBASE) GO TO 120 + MKT = AINT (MA(K)/MBASE) + MA(K-1) = MA(K-1) + MKT + MA(K) = MA(K) - MKT*MBASE + ENDDO + ENDIF + +! If there is a carry in the first digit then the exponent +! must be adjusted and the number shifted right. + + IF (MA(2) < MBASE) GO TO 120 + IF (KB >= 4) THEN + K = KB + 1 + DO J = 4, KB + K = K - 1 + MA(K) = MA(K-1) + ENDDO + ENDIF + + MKT = AINT (MA(2)/MBASE) + IF (KB >= 3) MA(3) = MA(2) - MKT*MBASE + MA(2) = MKT + MA(1) = MA(1) + 1 + + 120 IF (MBS < 0 .AND. MA(1) /= MUNKNO .AND. MA(2) /= 0) MA(-1) = -1 + GO TO 140 + +! Extend to NDB digits by padding with zeros. + + 130 DO J = NDA+2, NDB+1 + MA(J) = 0 + ENDDO + +! Check for overflow or underflow. + + 140 IF (ABS(MA(1)) > MXEXP) THEN + IF (MA(1) /= MUNKNO .OR. MA(2) /= 1) THEN + NCALL = NCALL + 1 + CALL FMTRAP(MA) + NCALL = NCALL - 1 + ENDIF + IF (MA(1) == MUNKNO) KFLAG = -4 + ENDIF + + IF (KACCSW == 1) THEN + JT = NINT(LOG(REAL(ABS(MA(2))+1))/0.69315) + IF (NDB > NDA) THEN + MA(0) = NINT((NDB-1)*ALOGM2 + JT) + ELSE + MA(0) = MIN(NINT((NDB-1)*ALOGM2+JT),INT(MACCA)) + ENDIF + ENDIF + RETURN + END SUBROUTINE FMEQ2_R1 + + SUBROUTINE FMEQU(MA,MB,NDA,NDB) + +! Set MB (having NDB digits) equal to MA (having NDA digits). + +! If MB has less precision than MA, the result is rounded to +! NDB digits. + +! If MB has more precision, the result has its precision extended +! by padding with zero digits on the right. + + USE FMVALS + IMPLICIT NONE + + REAL (KIND(1.0D0)) :: MA(-1:LUNPCK),MB(-1:LUNPCK) + INTEGER NDA,NDB + + CALL FMEQ2(MA,MB,NDA,NDB) + + RETURN + END SUBROUTINE FMEQU + + SUBROUTINE FMEXIT(MT,MC,NDSAVE,MXSAVE,KASAVE,KOVUN) + +! Upon exit from an FM routine the result MT (having precision NDIG) +! is rounded and returned in MC (having precision NDSAVE). +! The values of NDIG, MXEXP, and KACCSW are restored. +! KOVUN is nonzero if one of the routine's input arguments was overflow +! or underflow. + + USE FMVALS + IMPLICIT NONE + + REAL (KIND(1.0D0)) :: MT(-1:LUNPCK),MC(-1:LUNPCK),MXSAVE + INTEGER NDSAVE,KASAVE,KOVUN + + INTEGER KFSAVE,KWRNSV + + KWRNSV = KWARN + KWARN = 0 + MXEXP = MXSAVE + KFSAVE = KFLAG + CALL FMEQ2(MT,MC,NDIG,NDSAVE) + IF (KFLAG /= -5 .AND. KFLAG /= -6) KFLAG = KFSAVE + NDIG = NDSAVE + KWARN = KWRNSV + IF (KFLAG == 1) KFLAG = 0 + IF ((MC(1) == MUNKNO .AND. KFLAG /= -9) & + .OR. (MC(1) == MEXPUN .AND. KOVUN == 0) & + .OR. (MC(1) == MEXPOV .AND. KOVUN == 0)) CALL FMWARN + IF (NTRACE /= 0) CALL FMNTR(1,MC,MC,1,1) + NCALL = NCALL - 1 + KACCSW = KASAVE + RETURN + END SUBROUTINE FMEXIT + + SUBROUTINE FMEXP(MA,MB) + +! MB = EXP(MA) + + USE FMVALS + IMPLICIT NONE + + REAL (KIND(1.0D0)) :: MA(-1:LUNPCK),MB(-1:LUNPCK) + CHARACTER(155) :: STRING + REAL (KIND(1.0D0)) :: M1,MA1,MA2,MACCA,MACMAX,MAS,MXSAVE + INTEGER IEXTRA,J,K,KASAVE,KOVUN,KRESLT,KT,KWRNSV,NDMB, & + NDSAVE,NDSV,NMETHD + REAL XMA,XOV + + IF (MBLOGS /= MBASE) CALL FMCONS + IF (ABS(MA(1)) > MEXPAB .OR. MA(2) == 0) THEN + CALL FMENTR('FMEXP ',MA,MA,1,1,MB,KRESLT,NDSAVE,MXSAVE,KASAVE, & + KOVUN) + IF (KRESLT /= 0) RETURN + ELSE + NCALL = NCALL + 1 + NAMEST(NCALL) = 'FMEXP ' + IF (NTRACE /= 0) CALL FMNTR(2,MA,MA,1,1) + KOVUN = 0 + IF (MA(1) == MEXPOV .OR. MA(1) == MEXPUN) KOVUN = 1 + NDSAVE = NDIG + IF (NCALL == 1) THEN + K = MAX(NGRD52-1,2) + NDIG = MAX(NDIG+K,2) + IF (NDIG > NDG2MX) THEN + KFLAG = -9 + CALL FMWARN + NDIG = NDSAVE + KRESLT = 12 + CALL FMRSLT(MA,MA,MB,KRESLT) + IF (NTRACE /= 0) CALL FMNTR(1,MB,MB,1,1) + NCALL = NCALL - 1 + RETURN + ENDIF + ENDIF + KASAVE = KACCSW + KACCSW = 0 + MXSAVE = MXEXP + MXEXP = MXEXP2 + ENDIF + + MA1 = MA(1) + MA2 = MA(2) + MAS = MA(-1) + + MACCA = MA(0) + CALL FMEQ2(MA,MB,NDSAVE,NDIG) + MB(0) = NINT(NDIG*ALOGM2) + +! Check for obvious underflow or overflow. +! XOV is LN(LN(slightly above overflow)) +! XMA is LN(LN(EXP(MA))) approximately. + + XOV = LOG(1.01*REAL(MXEXP)) + LOG(ALOGMB) + M1 = 1 + XMA = LOG(REAL(MAX(ABS(MA2),M1))) - ALOGMB + & + REAL(MA1)*ALOGMB + + 110 IF (XMA >= XOV) THEN + CALL FMIM(0,MB) + IF (MAS > 0) THEN + KFLAG = -5 + CALL FMST2M('OVERFLOW',MB) + ELSE + KFLAG = -6 + CALL FMST2M('UNDERFLOW',MB) + ENDIF + NDIG = NDSAVE + MXEXP = MXSAVE + KACCSW = KASAVE + CALL FMWARN + IF (NTRACE /= 0) CALL FMNTR(1,MB,MB,1,1) + NCALL = NCALL - 1 + RETURN + ENDIF + +! Split MA into integer and fraction parts. +! Work with a positive argument. +! M02 = integer part of ABS(MA) +! MB = fraction part of ABS(MA) + + MB(-1) = 1 + CALL FMINT(MB,M02) + CALL FMSUB_R1(MB,M02) + +! If the integer part is not zero, use FMIPWR to compute +! E**(M02). If M02 is too large to represent as a one word +! integer, the definition of MXEXP insures that E**(M02) +! overflows or underflows. + + KWRNSV = KWARN + KWARN = 0 + CALL FMM2I(M02,KT) + KWARN = KWRNSV + IF (KFLAG /= 0) THEN + XMA = XOV + GO TO 110 + ENDIF + IF (KT > 0) THEN + +! Compute IEXTRA, the number of extra digits required +! to get EXP(KT) correct to the current precision. + + IEXTRA = INT(LOG(REAL(KT))/ALOGMB + 0.5) + IF (IEXTRA > 0 .AND. NDIG+IEXTRA <= NDG2MX) THEN + CALL FMEQ2_R1(MB,NDIG,NDIG+IEXTRA) + ENDIF + NDIG = NDIG + IEXTRA + IF (NDIG > NDG2MX) THEN + IF (NCALL == 1) THEN + KFLAG = -9 + CALL FMWARN + NDIG = NDIG - IEXTRA + CALL FMST2M('UNKNOWN',MB) + DO J = -1, NDIG+1 + M01(J) = MB(J) + ENDDO + CALL FMEXIT(M01,MB,NDSAVE,MXSAVE,KASAVE,KOVUN) + RETURN + ELSE + CALL FMEQ2_R1(MB,NDIG-IEXTRA,NDG2MX) + NDIG = NDG2MX + ENDIF + ENDIF + +! Check whether the current precision of e is large +! enough. + + IF (MBSE /= MBASE .OR. NDIG > NDIGE) THEN + NDMB = INT(150.0*2.302585/ALOGMB) + IF (NDMB >= NDIG) THEN + NDSV = NDIG + NDIG = MIN(NDMB,NDG2MX) + STRING = '2.718281828459045235360287471352662497757247'// & + '09369995957496696762772407663035354759457138217852516'// & + '6427427466391932003059921817413596629043572900334295261' + CALL FMST2M(STRING,MESAV) + MESAV(0) = NINT(NDIG*ALOGM2) + MBSE = MBASE + NDIGE = NDIG + IF (ABS(MESAV(1)) > 10) NDIGE = 0 + NDIG = NDSV + ELSE + NDSV = NDIG + NDIG = MIN(NDIG+2,NDG2MX) + CALL FMI2M(1,MESAV) + CALL FMEXP2(MESAV,M09) + CALL FMEQ(M09,MESAV) + MESAV(0) = NINT(NDIG*ALOGM2) + MBSE = MBASE + NDIGE = NDIG + IF (ABS(MESAV(1)) > 10) NDIGE = 0 + NDIG = NDSV + ENDIF + ENDIF + + ENDIF + +! Now do the fraction part of MA and combine the results. + + KWRNSV = KWARN + KWARN = 0 + NMETHD = 1 + IF (NDIG > 50) NMETHD = 2 + IF (MB(2) /= 0 .AND. KT > 0 .AND. NMETHD == 1) THEN + CALL FMEXP2(MB,M09) + CALL FMEQ(M09,MB) + CALL FMIPWR(MESAV,KT,M03) + CALL FMMPY_R1(MB,M03) + ELSE IF (MB(2) /= 0 .AND. KT == 0 .AND. NMETHD == 1) THEN + CALL FMEXP2(MB,M09) + CALL FMEQ(M09,MB) + ELSE IF (MB(2) /= 0 .AND. KT > 0 .AND. NMETHD == 2) THEN + NDSV = NDIG + NDIG = MIN(NDIG+NGRD21,NDG2MX) + CALL FMEQ2_R1(MB,NDSV,NDIG) + IF (MB(1) >= 0) THEN + CALL FMCSH2(MB,M09) + CALL FMEQ(M09,MB) + CALL FMSQR(MB,M03) + CALL FMI2M(-1,M02) + CALL FMADD_R1(M03,M02) + CALL FMSQRT_R1(M03) + CALL FMADD_R1(MB,M03) + ELSE + CALL FMSNH2(MB,M09) + CALL FMEQ(M09,MB) + CALL FMSQR(MB,M03) + CALL FMI2M(1,M02) + CALL FMADD_R1(M03,M02) + CALL FMSQRT_R1(M03) + CALL FMADD_R1(MB,M03) + ENDIF + NDIG = NDSV + CALL FMIPWR(MESAV,KT,M03) + CALL FMMPY_R1(MB,M03) + ELSE IF (MB(2) /= 0 .AND. KT == 0 .AND. NMETHD == 2) THEN + NDSV = NDIG + NDIG = MIN(NDIG+NGRD21,NDG2MX) + CALL FMEQ2_R1(MB,NDSV,NDIG) + IF (MB(1) >= 0) THEN + CALL FMCSH2(MB,M09) + CALL FMEQ(M09,MB) + CALL FMSQR(MB,M03) + CALL FMI2M(-1,M02) + CALL FMADD_R1(M03,M02) + CALL FMSQRT_R1(M03) + CALL FMADD_R1(MB,M03) + ELSE + CALL FMSNH2(MB,M09) + CALL FMEQ(M09,MB) + CALL FMSQR(MB,M03) + CALL FMI2M(1,M02) + CALL FMADD_R1(M03,M02) + CALL FMSQRT_R1(M03) + CALL FMADD_R1(MB,M03) + ENDIF + NDIG = NDSV + ELSE IF (MB(2) == 0 .AND. KT > 0) THEN + CALL FMIPWR(MESAV,KT,MB) + ELSE + CALL FMI2M(1,MB) + ENDIF + +! Invert if MA was negative. + + IF (MAS < 0) THEN + CALL FMI2M(1,M02) + CALL FMDIV_R2(M02,MB) + ENDIF + KWARN = KWRNSV + +! Round the result and return. + + MACMAX = NINT((NDSAVE-1)*ALOGM2 + LOG(REAL(ABS(MB(2))+1))/0.69315) + MB(0) = MIN(MB(0),MACCA,MACMAX) + DO J = -1, NDIG+1 + M01(J) = MB(J) + ENDDO + CALL FMEXIT(M01,MB,NDSAVE,MXSAVE,KASAVE,KOVUN) + RETURN + END SUBROUTINE FMEXP + + SUBROUTINE FMEXP2(MA,MB) + +! MB = EXP(MA) + +! Internal exponential routine (called with 0 < MA <= 1). + + USE FMVALS + IMPLICIT NONE + + REAL (KIND(1.0D0)) :: MA(-1:LUNPCK),MB(-1:LUNPCK) +! LJSUMS = 8*(LUNPCK+1) allows for up to eight concurrent +! sums. Increasing this value will begin to improve the +! speed of EXP when the base is large and precision exceeds +! about 1,500 decimal digits. + + REAL (KIND(1.0D0)) :: MAXVAL + INTEGER J,J2,K,K2,KPT,KTWO,L,L2,N2,NBIG,NBOT,NDSAV1,NDSAVE, & + NTERM,NTOP + REAL ALOG2,ALOGT,B,T,TJ,XN + + IF (MBLOGS /= MBASE) CALL FMCONS + NDSAVE = NDIG + IF (MA(1) == 1) THEN + +! Here the special case EXP(1.0) is computed. +! Use the direct series e = 1/0! + 1/1! + 1/2! + ... +! Do as much of the work as possible using small integers +! to minimize the number of FM calls. +! Reduce NDIG while computing each term in the +! sum as the terms get smaller. + + T = NDIG + XN = T*ALOGMB/LOG(T) + K = INT(LOG(XN)/ALOGMB) + NDIG = MAX(NDIG+K,2) + IF (NDIG > NDG2MX) THEN + IF (NCALL == 1) THEN + KFLAG = -9 + CALL FMWARN + NDIG = NDSAVE + CALL FMST2M('UNKNOWN',MB) + RETURN + ELSE + NDIG = NDG2MX + ENDIF + ENDIF + NDSAV1 = NDIG + + CALL FMI2M(2,MB) + CALL FMI2M(1,M02) + J = 2 + NBIG = INT(MXBASE) + + 110 NTOP = 1 + NBOT = J + 120 IF (NBOT > NBIG/(J+1)) GO TO 130 + J = J + 1 + NTOP = J*NTOP + 1 + NBOT = J*NBOT + GO TO 120 + + 130 CALL FMDIVI_R1(M02,NBOT) + IF (NTOP > 1) THEN + CALL FMMPYI(M02,NTOP,M03) + NDIG = NDSAV1 + CALL FMADD_R1(MB,M03) + NDIG = NDSAV1 - INT(MB(1)-M03(1)) + ELSE + NDIG = NDSAV1 + CALL FMADD_R1(MB,M02) + NDIG = NDSAV1 - INT(MB(1)-M02(1)) + ENDIF + IF (NDIG < 2) NDIG = 2 + IF (KFLAG /= 1) THEN + J = J + 1 + GO TO 110 + ENDIF + NDIG = NDSAVE + CALL FMI2M(-1,M02) + CALL FMADD(MB,M02,M03) + KFLAG = 0 + RETURN + ENDIF + +! Here is the general case. Compute EXP(MA) where +! 0 < MA < 1. + +! Use the direct series +! EXP(X) = 1 + X + X**2/2! + X**3/3! + ... + +! The argument will be halved K2 times before the series +! is summed. The series will be added as J2 concurrent +! series. The approximately optimal values of K2 and J2 +! are now computed to try to minimize the time required. +! N2 is the approximate number of terms of the series that +! will be needed, and L2 guard digits will be carried. + + B = REAL(MBASE) + K = NGRD52 + T = MAX(NDIG-K,2) + ALOG2 = REAL(DLOGTW) + ALOGT = LOG(T) + TJ = 0.051*ALOGMB*T**0.3333 + 1.85 + J2 = INT(TJ) + J2 = MAX(1,MIN(J2,LJSUMS/NDG2MX)) + K2 = INT(1.13*SQRT(T*ALOGMB/TJ) - 0.5*ALOGT + 4.5) + + L = INT(-(REAL(MA(1))*ALOGMB+LOG(REAL(MA(2))/B + & + REAL(MA(3))/(B*B)))/ALOG2 - 0.3) + K2 = K2 - L + IF (L < 0) L = 0 + IF (K2 < 0) THEN + K2 = 0 + J2 = INT(.43*SQRT(T*ALOGMB/(ALOGT+REAL(L)*ALOG2)) + .33) + ENDIF + IF (J2 <= 1) J2 = 1 + + N2 = INT(T*ALOGMB/(ALOGT+REAL(L)*ALOG2)) + L2 = INT(LOG(REAL(N2)+2.0**K2)/ALOGMB) + NDIG = NDIG + L2 + IF (NDIG > NDG2MX) THEN + IF (NCALL == 1) THEN + KFLAG = -9 + CALL FMWARN + NDIG = NDSAVE + CALL FMST2M('UNKNOWN',MB) + RETURN + ELSE + NDIG = NDG2MX + ENDIF + ENDIF + NDSAV1 = NDIG + +! Halve the argument K2 times. + + CALL FMEQ2(MA,M02,NDSAVE,NDIG) + KTWO = 1 + MAXVAL = MXBASE/2 + IF (K2 > 0) THEN + DO J = 1, K2 + KTWO = 2*KTWO + IF (KTWO > MAXVAL) THEN + CALL FMDIVI_R1(M02,KTWO) + KTWO = 1 + ENDIF + ENDDO + IF (KTWO > 1) CALL FMDIVI_R1(M02,KTWO) + ENDIF + +! Sum the series X + X**2/2! + X**3/3! + .... +! Split into J2 concurrent sums and reduce NDIG while +! computing each term in the sum as the terms get smaller. + + CALL FMEQ(M02,MB) + NTERM = 1 + DO J = 1, J2 + CALL FMDIVI_R1(MB,NTERM) + NTERM = NTERM + 1 + KPT = (J-1)*(NDIG+3) + CALL FMEQ(MB,MJSUMS(KPT-1)) + ENDDO + IF (M02(1) < -NDIG) GO TO 150 + CALL FMIPWR(M02,J2,M03) + + 140 CALL FMMPY_R1(MB,M03) + DO J = 1, J2 + CALL FMDIVI_R1(MB,NTERM) + KPT = (J-1)*(NDSAV1+3) + NDIG = NDSAV1 + CALL FMADD_R1(MJSUMS(KPT-1),MB) + IF (KFLAG /= 0) GO TO 150 + NDIG = NDSAV1 - INT(MJSUMS(KPT+1)-MB(1)) + IF (NDIG < 2) NDIG = 2 + NTERM = NTERM + 1 + ENDDO + GO TO 140 + +! Put the J2 separate sums back together. + + 150 KFLAG = 0 + KPT = (J2-1)*(NDIG+3) + CALL FMEQ(MJSUMS(KPT-1),M03) + IF (J2 >= 2) THEN + DO J = 2, J2 + CALL FMMPY_R2(M02,M03) + KPT = (J2-J)*(NDIG+3) + CALL FMADD_R1(M03,MJSUMS(KPT-1)) + ENDDO + ENDIF + +! Reverse the effect of halving the argument to +! compute EXP(MA). + + NDIG = NDSAV1 + IF (K2 > 0) THEN + IF (NDSAVE <= 20) THEN + CALL FMI2M(2,M02) + DO J = 1, K2 + CALL FMADD(M03,M02,MB) + CALL FMMPY_R2(MB,M03) + ENDDO + ELSE + DO J = 1, K2 + CALL FMSQR(M03,MB) + CALL FMADD(M03,M03,M02) + CALL FMADD(MB,M02,M03) + ENDDO + ENDIF + ENDIF + CALL FMI2M(1,M02) + CALL FMADD(M02,M03,MB) + + CALL FMEQ2_R1(MB,NDSAV1,NDSAVE) + NDIG = NDSAVE + + RETURN + END SUBROUTINE FMEXP2 + + SUBROUTINE FMFLAG(K) + +! Return the internal condition variable KFLAG to the user. + + USE FMVALS + IMPLICIT NONE + INTEGER K + K = KFLAG + RETURN + END SUBROUTINE FMFLAG + + SUBROUTINE FMFORM(FORM,MA,STRING) + +! Convert an FM number (MA) to a character string base 10 (STRING) +! using character string FORM format. + +! FORM can be one of these types: Iw, Fw.d, Ew.d, 1PEw.d +! for positive integers w,d. + +! If Iw format is used and MA is not exactly an integer, then the +! nearest integer to MA is printed. + + USE FMVALS + IMPLICIT NONE + + CHARACTER(*) :: FORM,STRING + REAL (KIND(1.0D0)) :: MA(-1:LUNPCK) + CHARACTER(20) :: FORMB + INTEGER J,JF1SAV,JF2SAV,JPT,K1,K2,K3,KD,KSAVE,KWD,KWI,LAST, & + LB,LENGFM,LENGST,LFIRST,ND,NEXP + + NCALL = NCALL + 1 + NAMEST(NCALL) = 'FMFORM' + + KSAVE = KFLAG + JF1SAV = JFORM1 + JF2SAV = JFORM2 + STRING = ' ' + LENGFM = LEN(FORM) + LENGST = LEN(STRING) + KWI = 75 + KWD = 40 + + IF (INDEX(FORM,'I') > 0 .OR. INDEX(FORM,'i') > 0) THEN + K1 = MAX(INDEX(FORM,'I'),INDEX(FORM,'i')) + 1 + K2 = LENGFM + WRITE (FORMB,"('(I',I5,')')") K2-K1+1 + IF (K2 >= K1) THEN + READ (FORM(K1:K2),FORMB) KWI + ELSE + KWI = LENGST + ENDIF + KWI = MAX(1,MIN(KWI,LENGST)) + JFORM1 = 2 + JFORM2 = 0 + KWD = KWI + 21 + IF (KWD > LMBUFF) GO TO 120 + CALL FMNINT(MA,M02) + IF (M02(2) /= 0) THEN + CALL FMOUT(M02,CMBUFF,KWD) + ELSE + DO J = 1, KWD + CMBUFF(J) = ' ' + ENDDO + CMBUFF(2) = '0' + ENDIF + LFIRST = 1 + LAST = 1 + DO J = 1, KWD + IF (CMBUFF(KWD+1-J) /= ' ') LFIRST = KWD+1-J + IF (CMBUFF(J) /= ' ') LAST = J + ENDDO + JPT = 1 + IF (LAST-LFIRST+1 > KWI) GO TO 120 + IF (LAST <= KWI) THEN + DO J = LAST, LFIRST, -1 + JPT = KWI - LAST + J + STRING(JPT:JPT) = CMBUFF(J) + ENDDO + DO J = 1, JPT-1 + STRING(J:J) = ' ' + ENDDO + ELSE + DO J = LFIRST, LAST + JPT = KWI - LAST + J + STRING(JPT:JPT) = CMBUFF(J) + ENDDO + ENDIF + ELSE IF (INDEX(FORM,'F') > 0 .OR. INDEX(FORM,'f') > 0) THEN + K1 = MAX(INDEX(FORM,'F'),INDEX(FORM,'f')) + 1 + K2 = INDEX(FORM,'.') + K3 = LENGFM + IF (K2 > K1) THEN + WRITE (FORMB,"('(I',I5,')')") K2-K1 + READ (FORM(K1:K2-1),FORMB) KWI + ELSE + KWI = 50 + ENDIF + IF (K3 > K2) THEN + WRITE (FORMB,"('(I',I5,')')") K3-K2 + READ (FORM(K2+1:K3),FORMB) KD + ELSE + KD = 0 + ENDIF + KWI = MAX(1,MIN(KWI,LENGST)) + KD = MAX(0,MIN(KD,KWI-2)) + JFORM1 = 2 + JFORM2 = KD + ND = INT(REAL(NDIG)*LOG10(REAL(MBASE))) + 1 + IF (ND < 2) ND = 2 + NEXP = INT(2.0*LOG10(REAL(MXBASE))) + 6 + LB = MAX(JFORM2+NEXP,ND+NEXP) + LB = MIN(LB,LMBUFF) + KWD = LB + CALL FMOUT(MA,CMBUFF,KWD) + LFIRST = 1 + LAST = 1 + DO J = 1, KWD + IF (CMBUFF(KWD+1-J) /= ' ') LFIRST = KWD+1-J + IF (CMBUFF(J) /= ' ') LAST = J + ENDDO + IF (LAST-LFIRST+1 > KWI) THEN + +! Not enough room for this F format, or FMOUT converted +! it to E format to avoid showing no significant digits. +! See if a shortened form will fit in E format. + + NEXP = INT(LOG10((ABS(REAL(MA(1)))+1)*LOG10(REAL(MBASE))+1)+1) + ND = KWI - NEXP - 5 + IF (ND < 1) THEN + GO TO 120 + ELSE + JFORM1 = 0 + JFORM2 = ND + CALL FMOUT(MA,CMBUFF,KWI) + LFIRST = 1 + LAST = 1 + DO J = 1, KWI + IF (CMBUFF(KWI+1-J) /= ' ') LFIRST = KWI+1-J + IF (CMBUFF(J) /= ' ') LAST = J + ENDDO + ENDIF + ENDIF + JPT = 1 + IF (LAST <= KWI) THEN + DO J = LAST, LFIRST, -1 + JPT = KWI - LAST + J + STRING(JPT:JPT) = CMBUFF(J) + ENDDO + DO J = 1, JPT-1 + STRING(J:J) = ' ' + ENDDO + ELSE + DO J = LFIRST, LAST + JPT = KWI - LAST + J + STRING(JPT:JPT) = CMBUFF(J) + ENDDO + ENDIF + ELSE IF (INDEX(FORM,'1PE') > 0 .OR. INDEX(FORM,'1pe') > 0) THEN + K1 = MAX(INDEX(FORM,'E'),INDEX(FORM,'e')) + 1 + K2 = INDEX(FORM,'.') + K3 = LENGFM + IF (K2 > K1) THEN + WRITE (FORMB,"('(I',I5,')')") K2-K1 + READ (FORM(K1:K2-1),FORMB) KWI + ELSE + KWI = 50 + ENDIF + IF (K3 > K2) THEN + WRITE (FORMB,"('(I',I5,')')") K3-K2 + READ (FORM(K2+1:K3),FORMB) KD + ELSE + KD = 0 + ENDIF + KWI = MAX(1,MIN(KWI,LENGST)) + KD = MAX(0,MIN(KD,KWI-2)) + JFORM1 = 1 + JFORM2 = KD + IF (KWI > LMBUFF) GO TO 120 + CALL FMOUT(MA,CMBUFF,KWI) + DO J = KWI, 1, -1 + IF (J > LENGST) THEN + IF (CMBUFF(J) /= ' ') GO TO 120 + ELSE + STRING(J:J) = CMBUFF(J) + ENDIF + ENDDO + ELSE IF (INDEX(FORM,'E') > 0 .OR. INDEX(FORM,'e') > 0) THEN + K1 = MAX(INDEX(FORM,'E'),INDEX(FORM,'e')) + 1 + K2 = INDEX(FORM,'.') + K3 = LENGFM + IF (K2 > K1) THEN + WRITE (FORMB,"('(I',I5,')')") K2-K1 + READ (FORM(K1:K2-1),FORMB) KWI + ELSE + KWI = 50 + ENDIF + IF (K3 > K2) THEN + WRITE (FORMB,"('(I',I5,')')") K3-K2 + READ (FORM(K2+1:K3),FORMB) KD + ELSE + KD = 0 + ENDIF + KWI = MAX(1,MIN(KWI,LENGST)) + KD = MAX(0,MIN(KD,KWI-2)) + JFORM1 = 0 + JFORM2 = KD + IF (KWI > LMBUFF) GO TO 120 + CALL FMOUT(MA,CMBUFF,KWI) + DO J = KWI, 1, -1 + IF (J > LENGST) THEN + IF (CMBUFF(J) /= ' ') GO TO 120 + ELSE + STRING(J:J) = CMBUFF(J) + ENDIF + ENDDO + ELSE + GO TO 120 + ENDIF + + 110 KFLAG = KSAVE + JFORM1 = JF1SAV + JFORM2 = JF2SAV + NCALL = NCALL - 1 + RETURN + +! Error condition. + + 120 KFLAG = -8 + DO J = 1, LENGST + STRING(J:J) = '*' + ENDDO + GO TO 110 + END SUBROUTINE FMFORM + + SUBROUTINE FMFPRT(FORM,MA) + +! Print an FM number (MA) on unit KW using character +! string FORM format. + +! FORM can be one of these types: Iw, Fw.d, Ew.d, 1PEw.d +! for positive integers w,d. + +! If Iw format is used and MA is not exactly an integer, then the +! nearest integer to MA is printed. + + USE FMVALS + IMPLICIT NONE + + CHARACTER(*) :: FORM + REAL (KIND(1.0D0)) :: MA(-1:LUNPCK) + CHARACTER(20) :: FORM2,FORMB + INTEGER J,JF1SAV,JF2SAV,JPT,K,K1,K2,K3,KD,KSAVE,KWD,KWI, & + LAST,LB,LENGFM,LFIRST,ND,NEXP + + NCALL = NCALL + 1 + NAMEST(NCALL) = 'FMFPRT' + + KSAVE = KFLAG + JF1SAV = JFORM1 + JF2SAV = JFORM2 + LENGFM = LEN(FORM) + KWI = 75 + KWD = 40 + + IF (INDEX(FORM,'I') > 0 .OR. INDEX(FORM,'i') > 0) THEN + K1 = MAX(INDEX(FORM,'I'),INDEX(FORM,'i')) + 1 + K2 = LENGFM + WRITE (FORMB,"('(I',I5,')')") K2-K1+1 + IF (K2 >= K1) THEN + READ (FORM(K1:K2),FORMB) KWI + ELSE + KWI = 50 + ENDIF + KWI = MAX(1,MIN(KWI,LMBUFF-11)) + JFORM1 = 2 + JFORM2 = 0 + KWD = KWI + 21 + CALL FMNINT(MA,M02) + IF (M02(2) /= 0) THEN + CALL FMOUT(M02,CMBUFF,KWD) + ELSE + DO J = 1, KWD + CMBUFF(J) = ' ' + ENDDO + CMBUFF(2) = '0' + ENDIF + LFIRST = 1 + LAST = 1 + DO J = 1, KWD + IF (CMBUFF(KWD+1-J) /= ' ') LFIRST = KWD+1-J + IF (CMBUFF(J) /= ' ') LAST = J + ENDDO + JPT = 1 + IF (LAST-LFIRST+1 > KWI) GO TO 120 + IF (LAST <= KWI) THEN + DO J = LAST, LFIRST, -1 + JPT = KWI - LAST + J + IF (JPT /= J) CMBUFF(JPT) = CMBUFF(J) + ENDDO + DO J = 1, JPT-1 + CMBUFF(J) = ' ' + ENDDO + ELSE + DO J = LFIRST, LAST + JPT = KWI - LAST + J + IF (JPT /= J) CMBUFF(JPT) = CMBUFF(J) + ENDDO + ENDIF + ELSE IF (INDEX(FORM,'F') > 0 .OR. INDEX(FORM,'f') > 0) THEN + K1 = MAX(INDEX(FORM,'F'),INDEX(FORM,'f')) + 1 + K2 = INDEX(FORM(1:LENGFM),'.') + K3 = LENGFM + IF (K2 > K1) THEN + WRITE (FORMB,"('(I',I5,')')") K2-K1 + READ (FORM(K1:K2-1),FORMB) KWI + ELSE + KWI = 50 + ENDIF + IF (K3 > K2) THEN + WRITE (FORMB,"('(I',I5,')')") K3-K2 + READ (FORM(K2+1:K3),FORMB) KD + ELSE + KD = 0 + ENDIF + KWI = MAX(1,MIN(KWI,LMBUFF)) + KD = MAX(0,MIN(KD,KWI-2)) + JFORM1 = 2 + JFORM2 = KD + ND = INT(REAL(NDIG)*LOG10(REAL(MBASE))) + 1 + IF (ND < 2) ND = 2 + NEXP = INT(2.0*LOG10(REAL(MXBASE))) + 6 + LB = MAX(JFORM2+NEXP,ND+NEXP) + LB = MIN(LB,LMBUFF) + KWD = LB + CALL FMOUT(MA,CMBUFF,KWD) + LFIRST = 1 + LAST = 1 + DO J = 1, KWD + IF (CMBUFF(KWD+1-J) /= ' ') LFIRST = KWD+1-J + IF (CMBUFF(J) /= ' ') LAST = J + ENDDO + IF (LAST-LFIRST+1 > KWI) THEN + +! Not enough room for this F format, or FMOUT converted +! it to E format to avoid showing no significant digits. +! See if a shortened form will fit in E format. + + NEXP = INT(LOG10((ABS(REAL(MA(1)))+1)*LOG10(REAL(MBASE))+1)+1) + ND = KWI - NEXP - 5 + IF (ND < 1) THEN + GO TO 120 + ELSE + JFORM1 = 0 + JFORM2 = ND + CALL FMOUT(MA,CMBUFF,KWI) + LFIRST = 1 + LAST = 1 + DO J = 1, KWI + IF (CMBUFF(KWI+1-J) /= ' ') LFIRST = KWI+1-J + IF (CMBUFF(J) /= ' ') LAST = J + ENDDO + ENDIF + ENDIF + JPT = 1 + IF (LAST <= KWI) THEN + DO J = LAST, LFIRST, -1 + JPT = KWI - LAST + J + IF (JPT /= J) CMBUFF(JPT) = CMBUFF(J) + ENDDO + DO J = 1, JPT-1 + CMBUFF(J) = ' ' + ENDDO + ELSE + DO J = LFIRST, LAST + JPT = KWI - LAST + J + IF (JPT /= J) CMBUFF(JPT) = CMBUFF(J) + ENDDO + ENDIF + ELSE IF (INDEX(FORM,'1PE') > 0 .OR. INDEX(FORM,'1pe') > 0) THEN + K1 = MAX(INDEX(FORM,'E'),INDEX(FORM,'e')) + 1 + K2 = INDEX(FORM(1:LENGFM),'.') + K3 = LENGFM + IF (K2 > K1) THEN + WRITE (FORMB,"('(I',I5,')')") K2-K1 + READ (FORM(K1:K2-1),FORMB) KWI + ELSE + KWI = 50 + ENDIF + IF (K3 > K2) THEN + WRITE (FORMB,"('(I',I5,')')") K3-K2 + READ (FORM(K2+1:K3),FORMB) KD + ELSE + KD = 0 + ENDIF + KWI = MAX(1,MIN(KWI,LMBUFF)) + KD = MAX(0,MIN(KD,KWI-2)) + JFORM1 = 1 + JFORM2 = KD + CALL FMOUT(MA,CMBUFF,KWI) + ELSE IF (INDEX(FORM,'E') > 0 .OR. INDEX(FORM,'e') > 0) THEN + K1 = MAX(INDEX(FORM,'E'),INDEX(FORM,'e')) + 1 + K2 = INDEX(FORM(1:LENGFM),'.') + K3 = LENGFM + IF (K2 > K1) THEN + WRITE (FORMB,"('(I',I5,')')") K2-K1 + READ (FORM(K1:K2-1),FORMB) KWI + ELSE + KWI = 50 + ENDIF + IF (K3 > K2) THEN + WRITE (FORMB,"('(I',I5,')')") K3-K2 + READ (FORM(K2+1:K3),FORMB) KD + ELSE + KD = 0 + ENDIF + KWI = MAX(1,MIN(KWI,LMBUFF)) + KD = MAX(0,MIN(KD,KWI-2)) + JFORM1 = 0 + JFORM2 = KD + CALL FMOUT(MA,CMBUFF,KWI) + ELSE + GO TO 120 + ENDIF + + 110 LAST = KWI + 1 + WRITE (FORM2,"(' (6X,',I3,'A1) ')") KSWIDE-7 + IF (KFLAG /= -8) KFLAG = KSAVE + JFORM1 = JF1SAV + JFORM2 = JF2SAV + DO J = KWI, 1, -1 + IF (CMBUFF(J) /= ' ' .OR. J == 1) THEN + WRITE (KW,FORM2) (CMBUFF(K),K=1,J) + NCALL = NCALL - 1 + RETURN + ENDIF + ENDDO + NCALL = NCALL - 1 + RETURN + +! Error condition. + + 120 KFLAG = -8 + DO J = 1, KWI + CMBUFF(J) = '*' + ENDDO + GO TO 110 + END SUBROUTINE FMFPRT + + SUBROUTINE FMGCDI(N1,N2) + +! Find the Greatest Common Divisor of N1 and N2, and return both +! having been divided by their GCD. Both must be positive. + + USE FMVALS + IMPLICIT NONE + INTEGER K1,K2,K3,N1,N2 + + K1 = MAX(N1,N2) + K2 = MIN(N1,N2) + 110 K3 = MOD(K1,K2) + IF (K3 == 0) THEN + N1 = N1/K2 + N2 = N2/K2 + RETURN + ELSE + K1 = K2 + K2 = K3 + GO TO 110 + ENDIF + END SUBROUTINE FMGCDI + + SUBROUTINE FMHTBL + +! Initialize two hash tables that are used for character +! look-up during input conversion. + + USE FMVALS + IMPLICIT NONE + + INTEGER J,KPT + + CHARACTER :: LCHARS(21) = (/ & + '+','-','0','1','2','3','4','5','6','7','8','9', & + '.','E','D','Q','M','e','d','q','m' /) + INTEGER :: LTYPES(21) = (/ 1,1,2,2,2,2,2,2,2,2,2,2,3,4,4,4,4,4,4,4,4 /) + INTEGER :: LVALS(21) = (/ 1,-1,0,1,2,3,4,5,6,7,8,9,0,0,0,0,0,0,0,0,0 /) + + DO J = LHASH1, LHASH2 + KHASHT(J) = 5 + KHASHV(J) = 0 + ENDDO + DO J = 1, 21 + KPT = ICHAR(LCHARS(J)) + IF (KPT < LHASH1 .OR. KPT > LHASH2) THEN + WRITE (KW, & + "(/' Error in input conversion.'/" // & + "' ICHAR function was out of range for the current'," // & + "' dimensions.'/' ICHAR(''',A,''') gave the value '," // & + "I12,', which is outside the currently'/' dimensioned'," // & + "' bounds of (',I5,':',I5,') for variables KHASHT '," // & + "'and KHASHV.'/' Re-define the two parameters '," // & + "'LHASH1 and LHASH2 so the dimensions will'/' contain'," // & + "' all possible output values from ICHAR.'//)" & + ) LCHARS(J),KPT,LHASH1,LHASH2 + ELSE + KHASHT(KPT) = LTYPES(J) + KHASHV(KPT) = LVALS(J) + ENDIF + ENDDO + LHASH = 1 + END SUBROUTINE FMHTBL + + SUBROUTINE FMI2M(IVAL,MA) + +! MA = IVAL + +! Convert an integer to FM format. + +! The conversion is exact if IVAL is less than MBASE**NDIG, +! otherwise the result is an approximation. + +! This routine performs the trace printing for the conversion. +! FMIM is used to do the arithmetic. + + USE FMVALS + IMPLICIT NONE + + REAL (KIND(1.0D0)) :: MA(-1:LUNPCK) + INTEGER IVAL + + NCALL = NCALL + 1 + IF (NTRACE /= 0) THEN + NAMEST(NCALL) = 'FMI2M ' + CALL FMNTRI(2,IVAL,1) + + CALL FMIM(IVAL,MA) + + CALL FMNTR(1,MA,MA,1,1) + ELSE + CALL FMIM(IVAL,MA) + ENDIF + NCALL = NCALL - 1 + RETURN + END SUBROUTINE FMI2M + + SUBROUTINE FMIM(IVAL,MA) + +! MA = IVAL. Internal integer conversion routine. + +! The conversion is exact if IVAL is less than MBASE**NDIG. +! Otherwise FMDM is used to get an approximation. + + USE FMVALS + IMPLICIT NONE + + REAL (KIND(1.0D0)) :: MA(-1:LUNPCK) + INTEGER IVAL + + DOUBLE PRECISION X + REAL (KIND(1.0D0)) :: MK,ML,MVAL + INTEGER J,JM2,KB,KB1,N1,NMVAL,NV2 + + IF (MBLOGS /= MBASE) CALL FMCONS + KFLAG = 0 + N1 = NDIG + 1 + + MVAL = ABS(IVAL) + NMVAL = INT(MVAL) + NV2 = NMVAL - 1 + IF (ABS(IVAL) > MXBASE .OR. NMVAL /= ABS(IVAL) .OR. & + NV2 /= ABS(IVAL)-1) THEN + CALL FMIMS(IVAL,MA) + GO TO 120 + ENDIF + +! Check for small IVAL. + + IF (MVAL < MBASE) THEN + DO J = 3, N1 + MA(J) = 0 + ENDDO + IF (IVAL >= 0) THEN + MA(2) = IVAL + MA(-1) = 1 + ELSE + MA(2) = -IVAL + MA(-1) = -1 + ENDIF + IF (IVAL == 0) THEN + MA(1) = 0 + ELSE + MA(1) = 1 + ENDIF + GO TO 120 + ENDIF + +! Compute and store the digits, right to left. + + MA(1) = 0 + J = NDIG + 1 + + 110 MK = AINT (MVAL/MBASE) + ML = MVAL - MK*MBASE + MA(1) = MA(1) + 1 + MA(J) = ML + IF (MK > 0) THEN + MVAL = MK + J = J - 1 + IF (J >= 2) GO TO 110 + +! Here IVAL cannot be expressed exactly. + + X = IVAL + CALL FMDM(X,MA) + RETURN + ENDIF + +! Normalize MA. + + KB = N1 - J + 2 + JM2 = J - 2 + DO J = 2, KB + MA(J) = MA(J+JM2) + ENDDO + KB1 = KB + 1 + IF (KB1 <= N1) THEN + DO J = KB1, N1 + MA(J) = 0 + ENDDO + ENDIF + + MA(-1) = 1 + IF (IVAL < 0 .AND. MA(1) /= MUNKNO .AND. MA(2) /= 0) MA(-1) = -1 + + 120 MA(0) = NINT(NDIG*ALOGM2) + RETURN + END SUBROUTINE FMIM + + SUBROUTINE FMIMS(IVAL,MA) + +! MA = IVAL. Internal integer conversion routine. + +! This routine is called when M-variable precision is less than +! Integer precision. This often happens when single precision +! is chosen for M-variables. + + USE FMVALS + IMPLICIT NONE + + REAL (KIND(1.0D0)) :: MA(-1:LUNPCK) + INTEGER IVAL + + DOUBLE PRECISION X + REAL (KIND(1.0D0)) :: ML + INTEGER J,JM2,KB,KB1,KBASE,KMK,KVAL,N1 + + IF (MBLOGS /= MBASE) CALL FMCONS + KFLAG = 0 + N1 = NDIG + 1 + +! Check for small IVAL. + + KVAL = ABS(IVAL) + KBASE = INT(MBASE) + IF (KVAL < KBASE) THEN + DO J = 3, N1 + MA(J) = 0 + ENDDO + IF (IVAL >= 0) THEN + MA(2) = IVAL + MA(-1) = 1 + ELSE + MA(2) = -IVAL + MA(-1) = -1 + ENDIF + IF (IVAL == 0) THEN + MA(1) = 0 + ELSE + MA(1) = 1 + ENDIF + GO TO 120 + ENDIF + +! Compute and store the digits, right to left. + + MA(1) = 0 + J = NDIG + 1 + + 110 KMK = (KVAL/KBASE) + ML = KVAL - KMK*KBASE + MA(1) = MA(1) + 1 + MA(J) = ML + IF (KMK > 0) THEN + KVAL = KMK + J = J - 1 + IF (J >= 2) GO TO 110 + +! Here IVAL cannot be expressed exactly. + + X = IVAL + CALL FMDM(X,MA) + RETURN + ENDIF + +! Normalize MA. + + KB = N1 - J + 2 + JM2 = J - 2 + DO J = 2, KB + MA(J) = MA(J+JM2) + ENDDO + KB1 = KB + 1 + IF (KB1 <= N1) THEN + DO J = KB1, N1 + MA(J) = 0 + ENDDO + ENDIF + + MA(-1) = 1 + IF (IVAL < 0 .AND. MA(1) /= MUNKNO .AND. MA(2) /= 0) MA(-1) = -1 + + 120 MA(0) = NINT(NDIG*ALOGM2) + RETURN + END SUBROUTINE FMIMS + + SUBROUTINE FMINP(LINE,MA,LA,LB) + +! Convert an array of characters to floating point multiple precision +! format. + +! LINE is an A1 character array of length LB to be converted +! to FM format and returned in MA. +! LA is a pointer telling the routine where in the array to begin +! the conversion. This allows more than one number to be stored +! in an array and converted in place. +! LB is a pointer to the last character of the field for that number. + +! The input number may be in integer or any real format. + +! KESWCH = 1 causes input to FMINP with no digits before the exponent +! letter to be treated as if there were a leading '1'. +! This is sometimes better for interactive input: +! 'E7' converts to 10.0**7. +! = 0 causes a leading zero to be assumed. This gives +! compatibility with Fortran: +! 'E7' converts to 0.0. + +! In exponential format the 'E' may also be 'D', 'Q', or 'M'. + +! So that FMINP will convert any output from FMOUT, LINE is tested +! to see if the input is one of the special symbols +OVERFLOW, +! -OVERFLOW, +UNDERFLOW, -UNDERFLOW, or UNKNOWN. +! For user input the abbreviations OVFL, UNFL, UNKN may be used. + + USE FMVALS + IMPLICIT NONE + + INTEGER LA,LB + CHARACTER LINE(LB) + REAL (KIND(1.0D0)) :: MA(-1:LUNPCK) + + REAL (KIND(1.0D0)) :: M2,MNDSV1,MXSAV1,MXSAV2 + INTEGER J,JSTATE,K,K10PWR,KASAVE,KDFLAG,KEXP,KF1,KF2,KMN,KOF,KPOWER, & + KPT,KRSAVE,KSIGN,KSIGNX,KSTART,KSTOP,KTENEX,KTENF1,KTENF2, & + KTYPE,KUF,KUK,KVAL,KWRNSV,LARGE,N2,NDSAV1,NDSAVE + +! Simulate a finite-state automaton to scan the input line +! and build the number. States of the machine: + +! 1. Initial entry to the subroutine +! 2. Sign of the number +! 3. Scanning digits before a decimal point +! 4. Decimal point +! 5. Scanning digits after a decimal point +! 6. E, D, Q, or M -- precision indicator before the exponent +! 7. Sign of the exponent +! 8. Scanning exponent +! 9. Syntax error + +! Character types recognized by the machine: + +! 1. Sign (+,-) +! 2. Numeral (0,1,...,9) +! 3. Decimal point (.) +! 4. Precision indicator (E,D,Q,M) +! 5. Illegal character for number + +! All blanks are ignored. The analysis of the number proceeds as +! follows: If the simulated machine is in state JSTATE and a character +! of type JTYPE is encountered the new state of the machine is given by +! JTRANS(JSTATE,JTYPE). + +! In this initialization note the array is loaded by columns. + +! State 1 2 3 4 5 6 7 8 + + INTEGER :: JTRANS(8,4) = RESHAPE( (/ & + 2, 9, 9, 9, 9, 7, 9, 9, & + 3, 3, 3, 5, 5, 8, 8, 8, & + 4, 4, 4, 9, 9, 9, 9, 9, & + 6, 6, 6, 6, 6, 9, 9, 9 /) & + , (/ 8,4 /) ) + + CHARACTER :: KOVFL(4) = (/ 'O','V','F','L' /) + CHARACTER :: KUNFL(4) = (/ 'U','N','F','L' /) + CHARACTER :: KUNKN(4) = (/ 'U','N','K','N' /) + CHARACTER :: LOVFL(4) = (/ 'o','v','f','l' /) + CHARACTER :: LUNFL(4) = (/ 'u','n','f','l' /) + CHARACTER :: LUNKN(4) = (/ 'u','n','k','n' /) + +! To avoid recursion, FMINP calls only internal arithmetic +! routines (FMADD2, FMMPY2, ...), so no trace printout is +! done during a call to FMINP. + + IF (MBLOGS /= MBASE) CALL FMCONS + NCALL = NCALL + 1 + NAMEST(NCALL) = 'FMINP ' + +! Raise the call stack again, since the internal +! routines don't. + + NCALL = NCALL + 1 + NAMEST(NCALL) = 'FMINP ' + NDSAVE = NDIG + KASAVE = KACCSW + KACCSW = 0 + KRSAVE = KROUND + KROUND = 1 + KFLAG = 0 + MXSAV1 = MXEXP + MXSAV2 = MXEXP2 + IF (MXEXP < 100000) THEN + MXEXP = 100000 + MXEXP2 = 201000 + ENDIF + +! Initialize two hash tables that are used for character +! look-up during input conversion. + + IF (LHASH == 0) CALL FMHTBL + +! Check for special symbols. + + KMN = 1 + KOF = 1 + KUF = 1 + KUK = 1 + DO J = LA, LB + KPT = ICHAR(LINE(J)) + IF (KPT >= LHASH1 .AND. KPT <= LHASH2) THEN + KTYPE = KHASHT(KPT) + IF (KTYPE == 2) GO TO 110 + ENDIF + IF (LINE(J) == '-') KMN = -1 + IF (LINE(J) == KOVFL(KOF) .OR. LINE(J) == LOVFL(KOF)) THEN + KOF = KOF + 1 + IF (KOF == 5) THEN + CALL FMIM(0,MA) + MA(1) = MEXPOV + MA(2) = 1 + MA(-1) = KMN + MA(0) = NINT(NDIG*ALOGM2) + GO TO 150 + ENDIF + ENDIF + IF (LINE(J) == KUNFL(KUF) .OR. LINE(J) == LUNFL(KOF)) THEN + KUF = KUF + 1 + IF (KUF == 5) THEN + CALL FMIM(0,MA) + MA(1) = MEXPUN + MA(2) = 1 + MA(-1) = KMN + MA(0) = NINT(NDIG*ALOGM2) + GO TO 150 + ENDIF + ENDIF + IF (LINE(J) == KUNKN(KUK) .OR. LINE(J) == LUNKN(KOF)) THEN + KUK = KUK + 1 + IF (KUK == 5) THEN + CALL FMIM(0,MA) + MA(1) = MUNKNO + MA(2) = 1 + MA(0) = NINT(NDIG*ALOGM2) + GO TO 150 + ENDIF + ENDIF + ENDDO + +! Increase the working precision. + + 110 K = NGRD52 + NDIG = MAX(NDIG+K,2) + IF (NDIG > NDG2MX) NDIG = NDG2MX + NDSAV1 = NDIG + M2 = 2 + MNDSV1 = NDSAV1 + KSTART = LA + KSTOP = LB + JSTATE = 1 + KSIGN = 1 + CALL FMIM(0,MLV2) + CALL FMIM(0,MLV3) + CALL FMIM(0,MLV4) + CALL FMIM(0,MLV5) + +! If MBASE is a power of ten then call FMINP2 for +! faster input conversion. + + KPOWER = INT(LOG10(DBLE(MBASE)) + 0.5D0) + IF (MBASE == 10**KPOWER) THEN + CALL FMINP2(MA,LINE,KSTART,KSTOP,JTRANS,KPOWER) + GO TO 140 + ENDIF + + N2 = 0 + KSIGNX = 1 + KF1 = 0 + KF2 = 0 + KEXP = 0 + KTENF1 = 1 + KTENF2 = 1 + KTENEX = 1 + K10PWR = 0 + +! LARGE is a threshold used in order to do as much of the +! conversion as possible in one-word integer arithmetic. + + LARGE = INT((INTMAX - 10)/10) + +! KDFLAG will be 1 if any digits are found before 'E'. + + KDFLAG = 0 + +! Scan the number. + + DO J = KSTART, KSTOP + IF (LINE(J) == ' ') CYCLE + KPT = ICHAR(LINE(J)) + IF (KPT < LHASH1 .OR. KPT > LHASH2) THEN + WRITE (KW, & + "(/' Error in input conversion.'/" // & + "' ICHAR function was out of range for the current'," // & + "' dimensions.'/' ICHAR(''',A,''') gave the value '," // & + "I12,', which is outside the currently'/' dimensioned'," // & + "' bounds of (',I5,':',I5,') for variables KHASHT '," // & + "'and KHASHV.'/' Re-define the two parameters '," // & + "'LHASH1 and LHASH2 so the dimensions will'/' contain'," // & + "' all possible output values from ICHAR.'//)" & + ) LINE(J),KPT,LHASH1,LHASH2 + KTYPE = 5 + KVAL = 0 + ELSE + KTYPE = KHASHT(KPT) + KVAL = KHASHV(KPT) + ENDIF + + IF (KTYPE >= 5) GO TO 160 + + JSTATE = JTRANS(JSTATE,KTYPE) + + SELECT CASE (JSTATE) + +! State 2. Sign of the number. + + CASE (2) + KSIGN = KVAL + +! State 3. Digits before a decimal point. + + CASE (3) + KDFLAG = 1 + KF1 = 10*KF1 + KVAL + KTENF1 = 10*KTENF1 + IF (KTENF1 > LARGE) THEN + IF (KTENF1 /= K10PWR .AND. MLV3(2) /= 0) THEN + CALL FMIM(KTENF1,MA) + K10PWR = KTENF1 + ENDIF + IF (MLV3(2) == 0) THEN + CALL FMIM(KF1,MLV3) + ELSE + NDIG = INT(MAX(M2,MIN(MLV3(1)+MA(1),MNDSV1))) + CALL FMMPY2_R1(MLV3,MA) + NDIG = NDSAV1 + CALL FMIM(KF1,MLV2) + NDIG = INT(MAX(M2,MIN(MAX(MLV3(1),MLV2(1))+1,MNDSV1))) + IF (KF1 /= 0) CALL FMADD2_R1(MLV3,MLV2) + NDIG = NDSAV1 + ENDIF + KF1 = 0 + KTENF1 = 1 + ENDIF + +! State 4. Decimal point + + CASE (4) + CYCLE + +! State 5. Digits after a decimal point. + + CASE (5) + KDFLAG = 1 + N2 = N2 + 1 + KF2 = 10*KF2 + KVAL + KTENF2 = 10*KTENF2 + IF (KTENF2 > LARGE) THEN + IF (KTENF2 /= K10PWR .AND. MLV4(2) /= 0) THEN + CALL FMIM(KTENF2,MA) + K10PWR = KTENF2 + ENDIF + IF (MLV4(2) == 0) THEN + CALL FMIM(KF2,MLV4) + ELSE + NDIG = INT(MAX(M2,MIN(MLV4(1)+MA(1),MNDSV1))) + CALL FMMPY2_R1(MLV4,MA) + NDIG = NDSAV1 + CALL FMIM(KF2,MLV2) + NDIG = INT(MAX(M2,MIN(MAX(MLV4(1),MLV2(1))+1,MNDSV1))) + IF (KF2 /= 0) CALL FMADD2_R1(MLV4,MLV2) + NDIG = NDSAV1 + ENDIF + KF2 = 0 + KTENF2 = 1 + ENDIF + +! State 6. Precision indicator. + + CASE (6) + IF (KDFLAG == 0 .AND. KESWCH == 1) CALL FMIM(1,MLV3) + +! State 7. Sign of the exponent. + + CASE (7) + KSIGNX = KVAL + +! State 8. Digits of the exponent. + + CASE (8) + KEXP = 10*KEXP + KVAL + KTENEX = 10*KTENEX + IF (KTENEX > LARGE) THEN + IF (KTENEX /= K10PWR .AND. MLV5(2) /= 0) THEN + CALL FMIM(KTENEX,MA) + K10PWR = KTENEX + ENDIF + IF (MLV5(2) == 0) THEN + CALL FMIM(KEXP,MLV5) + ELSE + NDIG = INT(MAX(M2,MIN(MLV5(1)+MA(1),MNDSV1))) + CALL FMMPY2_R1(MLV5,MA) + NDIG = NDSAV1 + CALL FMIM(KEXP,MLV2) + NDIG = INT(MAX(M2,MIN(MAX(MLV5(1),MLV2(1))+1,MNDSV1))) + IF (KEXP /= 0) CALL FMADD2_R1(MLV5,MLV2) + NDIG = NDSAV1 + ENDIF + KEXP = 0 + KTENEX = 1 + ENDIF + + CASE DEFAULT + GO TO 160 + + END SELECT + + ENDDO + +! Form the number and return. +! MA = KSIGN*(MLV3 + MLV4/10.0**N2)*10.0**MLV5 + + IF (KTENF1 > 1) THEN + IF (KTENF1 /= K10PWR .AND. MLV3(2) /= 0) THEN + CALL FMIM(KTENF1,MA) + K10PWR = KTENF1 + ENDIF + IF (MLV3(2) == 0) THEN + CALL FMIM(KF1,MLV3) + ELSE + NDIG = INT(MAX(M2,MIN(MLV3(1)+MA(1),MNDSV1))) + CALL FMMPY2_R1(MLV3,MA) + NDIG = NDSAV1 + CALL FMIM(KF1,MLV2) + NDIG = INT(MAX(M2,MIN(MAX(MLV3(1),MLV2(1))+1,MNDSV1))) + IF (KF1 /= 0) CALL FMADD2_R1(MLV3,MLV2) + NDIG = NDSAV1 + ENDIF + ENDIF + IF (KTENF2 > 1) THEN + IF (KTENF2 /= K10PWR .AND. MLV4(2) /= 0) THEN + CALL FMIM(KTENF2,MA) + K10PWR = KTENF2 + ENDIF + IF (MLV4(2) == 0) THEN + CALL FMIM(KF2,MLV4) + ELSE + NDIG = INT(MAX(M2,MIN(MLV4(1)+MA(1),MNDSV1))) + CALL FMMPY2_R1(MLV4,MA) + NDIG = NDSAV1 + CALL FMIM(KF2,MLV2) + NDIG = INT(MAX(M2,MIN(MAX(MLV4(1),MLV2(1))+1,MNDSV1))) + IF (KF2 /= 0) CALL FMADD2_R1(MLV4,MLV2) + NDIG = NDSAV1 + ENDIF + ENDIF + IF (KTENEX > 1) THEN + IF (KTENEX /= K10PWR .AND. MLV5(2) /= 0) THEN + CALL FMIM(KTENEX,MA) + K10PWR = KTENEX + ENDIF + IF (MLV5(2) == 0) THEN + CALL FMIM(KEXP,MLV5) + ELSE + NDIG = INT(MAX(M2,MIN(MLV5(1)+MA(1),MNDSV1))) + CALL FMMPY2_R1(MLV5,MA) + NDIG = NDSAV1 + CALL FMIM(KEXP,MLV2) + NDIG = INT(MAX(M2,MIN(MAX(MLV5(1),MLV2(1))+1,MNDSV1))) + IF (KEXP /= 0) CALL FMADD2_R1(MLV5,MLV2) + NDIG = NDSAV1 + ENDIF + ENDIF + + IF (KSIGNX == -1 .AND. MLV5(1) /= MUNKNO .AND. MLV5(2) /= 0) & + MLV5(-1) = -MLV5(-1) + IF (MLV4(2) /= 0) THEN + CALL FMIM(10,MLV2) + K = N2 + IF (MOD(K,2) == 0) THEN + CALL FMIM(1,MA) + ELSE + CALL FMEQ(MLV2,MA) + ENDIF + + 120 K = K/2 + NDIG = INT(MAX(M2,MIN(2*MLV2(1),MNDSV1))) + CALL FMSQR2_R1(MLV2) + IF (MOD(K,2) == 1) THEN + NDIG = INT(MAX(M2,MIN(MLV2(1)+MA(1),MNDSV1))) + CALL FMMPY2_R2(MLV2,MA) + ENDIF + IF (K > 1) GO TO 120 + NDIG = NDSAV1 + CALL FMDIV2_R1(MLV4,MA) + ENDIF + IF (MLV5(2) /= 0) THEN + CALL FMIM(10,MLV2) + KWRNSV = KWARN + KWARN = 0 + CALL FMMI(MLV5,KEXP) + KWARN = KWRNSV + IF (KFLAG /= 0) GO TO 160 + K = ABS(KEXP) + IF (MOD(K,2) == 0) THEN + CALL FMIM(1,MLV5) + ELSE + CALL FMEQ(MLV2,MLV5) + ENDIF + + 130 K = K/2 + NDIG = INT(MAX(M2,MIN(2*MLV2(1),MNDSV1))) + CALL FMSQR2_R1(MLV2) + IF (MOD(K,2) == 1) THEN + NDIG = INT(MAX(M2,MIN(MLV2(1)+MLV5(1),MNDSV1))) + CALL FMMPY2_R2(MLV2,MLV5) + ENDIF + IF (K > 1) GO TO 130 + NDIG = NDSAV1 + IF (KEXP < 0) THEN + CALL FMIM(1,MLV2) + CALL FMDIV2_R2(MLV2,MLV5) + ENDIF + ENDIF + CALL FMADD2(MLV3,MLV4,MA) + IF (MLV5(2) /= 0) CALL FMMPY2_R1(MA,MLV5) + IF (KSIGN == -1 .AND. MA(1) /= MUNKNO .AND. MA(2) /= 0) MA(-1) = -MA(-1) + 140 CALL FMEQ2_R1(MA,NDIG,NDSAVE) + IF (MA(1) == MUNKNO) GO TO 160 + + 150 NDIG = NDSAVE + KACCSW = KASAVE + KROUND = KRSAVE + MXEXP = MXSAV1 + MXEXP2 = MXSAV2 + IF (KFLAG == 1) KFLAG = 0 + MA(0) = NINT(NDIG*ALOGM2) + IF (MA(2) == 0) MA(-1) = 1 + NCALL = NCALL - 2 + RETURN + +! Error in converting the number. + + 160 CALL FMIM(0,MA) + MA(1) = MUNKNO + MA(2) = 1 + MA(0) = NINT(NDIG*ALOGM2) + KFLAG = -7 + NCALL = NCALL - 1 + CALL FMWARN + NCALL = NCALL + 1 + GO TO 150 + END SUBROUTINE FMINP + + SUBROUTINE FMINP2(MA,LINE,KSTART,KSTOP,JTRANS,KPOWER) + +! Internal routine for input conversion for a power of ten MBASE. + + USE FMVALS + IMPLICIT NONE + + INTEGER KSTART,KSTOP,KPOWER,JTRANS(8,4) + CHARACTER LINE(KSTOP) + REAL (KIND(1.0D0)) :: MA(-1:LUNPCK) + + INTEGER J,JSTATE,KDFLAG,KEXP,KF1,KF1DIG,KF2,KF2DIG,KF2PT,KNZDIG, & + KPT,KSHIFT,KSIGN,KSIGNX,KTYPE,KVAL,LARGE + + JSTATE = 1 + KDFLAG = 0 + KSIGN = 1 + KSIGNX = 1 + KF1 = 0 + KNZDIG = 0 + KF1DIG = 0 + KF2 = 0 + KF2DIG = 0 + KF2PT = 2 + KEXP = 0 + LARGE = INT(INTMAX/10) + +! Scan the number. + + DO J = KSTART, KSTOP + IF (LINE(J) == ' ') CYCLE + KPT = ICHAR(LINE(J)) + IF (KPT < LHASH1 .OR. KPT > LHASH2) THEN + WRITE (KW, & + "(/' Error in input conversion.'/" // & + "' ICHAR function was out of range for the current'," // & + "' dimensions.'/' ICHAR(''',A,''') gave the value '," // & + "I12,', which is outside the currently'/' dimensioned'," // & + "' bounds of (',I5,':',I5,') for variables KHASHT '," // & + "'and KHASHV.'/' Re-define the two parameters '," // & + "'LHASH1 and LHASH2 so the dimensions will'/' contain'," // & + "' all possible output values from ICHAR.'//)" & + ) LINE(J),KPT,LHASH1,LHASH2 + KTYPE = 5 + KVAL = 0 + ELSE + KTYPE = KHASHT(KPT) + KVAL = KHASHV(KPT) + ENDIF + + IF (KTYPE >= 5) GO TO 110 + + JSTATE = JTRANS(JSTATE,KTYPE) + + SELECT CASE (JSTATE) + +! State 2. Sign of the number. + + CASE (2) + KSIGN = KVAL + +! State 3. Digits before a decimal point. + + CASE (3) + KDFLAG = 1 + KF1 = 10*KF1 + KVAL + IF (KVAL > 0 .OR. KNZDIG /= 0) THEN + KNZDIG = 1 + KF1DIG = KF1DIG + 1 + ENDIF + IF (KF1DIG == KPOWER) THEN + MLV3(1) = MLV3(1) + 1 + IF (MLV3(1) < NDIG) MLV3(INT(MLV3(1))+1) = KF1 + KF1 = 0 + KF1DIG = 0 + ENDIF + +! State 4. Decimal point + + CASE (4) + CYCLE + +! State 5. Digits after a decimal point. + + CASE (5) + KDFLAG = 1 + IF (KF2PT > NDIG+1) CYCLE + KF2 = 10*KF2 + KVAL + KF2DIG = KF2DIG + 1 + IF (KF2DIG == KPOWER) THEN + MLV4(KF2PT) = KF2 + IF (KF2 == 0 .AND. KF2PT == 2) THEN + MLV4(1) = MLV4(1) - 1 + ELSE + KF2PT = KF2PT + 1 + ENDIF + KF2 = 0 + KF2DIG = 0 + ENDIF + +! State 6. Precision indicator. + + CASE (6) + IF (KDFLAG == 0 .AND. KESWCH == 1) CALL FMIM(1,MLV3) + +! State 7. Sign of the exponent. + + CASE (7) + KSIGNX = KVAL + +! State 8. Digits of the exponent. + + CASE (8) + IF (KEXP >= LARGE) THEN + IF (MLV3(2) == 0 .AND. MLV4(2) == 0) THEN + CALL FMIM(0,MA) + RETURN + ENDIF + CALL FMIM(0,MA) + IF (KSIGNX == 1) THEN + MA(1) = MEXPOV + KFLAG = -4 + ELSE + MA(1) = MEXPUN + KFLAG = -4 + ENDIF + MA(2) = 1 + MA(-1) = KSIGN + MA(0) = NINT(NDIG*ALOGM2) + NCALL = NCALL - 1 + CALL FMWARN + NCALL = NCALL + 1 + RETURN + ENDIF + KEXP = 10*KEXP + KVAL + + CASE DEFAULT + GO TO 110 + + END SELECT + + ENDDO + +! Form the number and return. +! MA = KSIGN*(MLV3 + MLV4)*10.0**(KSIGNX*KEXP) + + IF (KF1DIG /= 0) THEN + MLV3(1) = MLV3(1) + 1 + KSHIFT = 10**(KPOWER-KF1DIG) + IF (MLV3(1) < NDIG) MLV3(INT(MLV3(1))+1) = KF1*KSHIFT + IF (KSHIFT > 1) THEN + CALL FMDIVN_R1(MLV3,KSHIFT) + ENDIF + ENDIF + + IF (KF2DIG /= 0) THEN + KSHIFT = 10**(KPOWER-KF2DIG) + MLV4(KF2PT) = KF2*KSHIFT + ENDIF + IF (MLV4(2) == 0) MLV4(1) = 0 + + IF (KEXP /= 0) THEN + IF (KSIGNX == 1) THEN + MLV5(1) = INT(KEXP/KPOWER) + 1 + MLV5(2) = 10**(MOD(KEXP,KPOWER)) + ELSE + MLV5(1) = -INT((KEXP-1)/KPOWER) + KSHIFT = 10**(MOD(KEXP,KPOWER)) + IF (KSHIFT > 1) THEN + MLV5(2) = MBASE/KSHIFT + ELSE + MLV5(2) = 1 + ENDIF + ENDIF + ENDIF + + CALL FMADD2(MLV3,MLV4,MA) + IF (KEXP > 0) CALL FMMPY2_R1(MA,MLV5) + MA(-1) = KSIGN + + RETURN + +! Error in converting the number. + + 110 CALL FMIM(0,MA) + MA(1) = MUNKNO + MA(2) = 1 + MA(-1) = 1 + MA(0) = NINT(NDIG*ALOGM2) + RETURN + END SUBROUTINE FMINP2 + + SUBROUTINE FMINT(MA,MB) + +! MB = INT(MA) + +! The integer part of MA is computed and returned in MB as a multiple +! precision floating point number. + + USE FMVALS + IMPLICIT NONE + + REAL (KIND(1.0D0)) :: MA(-1:LUNPCK),MB(-1:LUNPCK) + + REAL (KIND(1.0D0)) :: MACCA,MACMAX + INTEGER J,KA,KB,KRESLT,N1 + + IF (MBLOGS /= MBASE) CALL FMCONS + MACCA = MA(0) + KFLAG = 0 + NCALL = NCALL + 1 + NAMEST(NCALL) = 'FMINT ' + IF (NTRACE /= 0) CALL FMNTR(2,MA,MA,1,1) + IF (ABS(MA(1)) > MEXPAB) THEN + CALL FMARGS('FMINT ',1,MA,MB,KRESLT) + IF (KRESLT /= 0) THEN + CALL FMRSLT(MA,MA,MB,KRESLT) + IF (NTRACE /= 0) CALL FMNTR(1,MB,MB,1,1) + NCALL = NCALL - 1 + RETURN + ENDIF + ENDIF + + N1 = NDIG + 1 + +! If MA is less than one in magnitude, return zero. + + IF (MA(1) <= 0) THEN + DO J = 1, N1 + MB(J) = 0 + ENDDO + GO TO 110 + ENDIF + +! If the radix point is off the right end of MA then MA is +! already an integer. Return MA. + + IF (MA(1) >= NDIG) THEN + DO J = 1, N1 + MB(J) = MA(J) + ENDDO + GO TO 110 + ENDIF + +! Here MA has both integer and fraction parts. Replace +! the digits right of the radix point by zeros. + + KA = INT(MA(1)) + 2 + KB = KA - 1 + DO J = 1, KB + MB(J) = MA(J) + ENDDO + + DO J = KA, N1 + MB(J) = 0 + ENDDO + + 110 IF (KACCSW == 1) THEN + MACMAX = NINT((NDIG-1)*ALOGM2 + & + LOG(REAL(ABS(MB(2))+1))/0.69315) + MB(0) = MIN(MACCA,MACMAX) + ELSE + MB(0) = MACCA + ENDIF + MB(-1) = MA(-1) + IF (MB(2) == 0) MB(-1) = 1 + IF (NTRACE /= 0) CALL FMNTR(1,MB,MB,1,1) + NCALL = NCALL - 1 + RETURN + END SUBROUTINE FMINT + + SUBROUTINE FMIPWR(MA,IVAL,MB) + +! MB = MA ** IVAL + +! Raise an FM number to an integer power. +! The binary multiplication method used requires an average of +! 1.5 * LOG2(IVAL) multiplications. MA may be negative. + + USE FMVALS + IMPLICIT NONE + + REAL (KIND(1.0D0)) :: MA(-1:LUNPCK),MB(-1:LUNPCK) + INTEGER IVAL + REAL (KIND(1.0D0)) :: MACCA,MACMAX + INTEGER JSIGN,K,KWRNSV,NDSAVE + REAL XVAL + + IF (MBLOGS /= MBASE) CALL FMCONS + KFLAG = 0 + NCALL = NCALL + 1 + NAMEST(NCALL) = 'FMIPWR' + IF (NTRACE /= 0) THEN + CALL FMNTR(2,MA,MA,1,1) + CALL FMNTRI(2,IVAL,0) + ENDIF + +! Check for special cases. + + IF (MA(1) == MUNKNO .OR. (IVAL <= 0 .AND. MA(2) == 0)) THEN + KFLAG = -4 + IF (IVAL <= 0 .AND. MA(2) == 0) CALL FMWARN + CALL FMST2M('UNKNOWN',MB) + IF (NTRACE /= 0) CALL FMNTR(1,MB,MB,1,1) + NCALL = NCALL - 1 + RETURN + ENDIF + + IF (IVAL == 0) THEN + CALL FMIM(1,MB) + IF (NTRACE /= 0) CALL FMNTR(1,MB,MB,1,1) + NCALL = NCALL - 1 + RETURN + ENDIF + + IF (ABS(IVAL) == 1) THEN + KWRNSV = KWARN + KWARN = 0 + IF (IVAL == 1) THEN + CALL FMEQ(MA,MB) + ELSE + CALL FMIM(1,M01) + CALL FMDIV(M01,MA,MB) + ENDIF + IF (NTRACE /= 0) CALL FMNTR(1,MB,MB,1,1) + NCALL = NCALL - 1 + KWARN = KWRNSV + RETURN + ENDIF + + IF (MA(2) == 0) THEN + CALL FMEQ(MA,MB) + IF (NTRACE /= 0) CALL FMNTR(1,MB,MB,1,1) + NCALL = NCALL - 1 + RETURN + ENDIF + + IF (MA(1) == MEXPOV) THEN + JSIGN = 1 + IF (MA(-1) < 0) JSIGN = -1 + CALL FMIM(0,MB) + IF (IVAL > 0) THEN + CALL FMST2M('OVERFLOW',MB) + MB(-1) = JSIGN**MOD(IVAL,2) + KFLAG = -5 + ELSE + CALL FMST2M('UNDERFLOW',MB) + MB(-1) = JSIGN**MOD(IVAL,2) + KFLAG = -6 + ENDIF + IF (NTRACE /= 0) CALL FMNTR(1,MB,MB,1,1) + NCALL = NCALL - 1 + RETURN + ENDIF + + IF (MA(1) == MEXPUN) THEN + JSIGN = 1 + IF (MA(-1) < 0) JSIGN = -1 + CALL FMIM(0,MB) + IF (IVAL > 0) THEN + CALL FMST2M('UNDERFLOW',MB) + MB(-1) = JSIGN**MOD(IVAL,2) + KFLAG = -6 + ELSE + CALL FMST2M('OVERFLOW',MB) + MB(-1) = JSIGN**MOD(IVAL,2) + KFLAG = -5 + ENDIF + IF (NTRACE /= 0) CALL FMNTR(1,MB,MB,1,1) + NCALL = NCALL - 1 + RETURN + ENDIF + +! Increase the working precision. + + NDSAVE = NDIG + IF (NCALL == 1) THEN + XVAL = ABS(IVAL) + K = INT((5.0*REAL(DLOGTN) + LOG(XVAL))/ALOGMB + 2.0) + NDIG = MAX(NDIG+K,2) + IF (MBASE < 1000 .OR. KROUND /= 1 .OR. KRPERF == 1) THEN + NDIG = MIN(NDG2MX,MAX(NDIG,2*NDSAVE+10)) + ENDIF + ELSE + XVAL = ABS(IVAL) + IF (XVAL > 10.0 .OR. REAL(MBASE) <= 999.0) THEN + K = INT(LOG(XVAL)/ALOGMB + 1.0) + NDIG = NDIG + K + ENDIF + ENDIF + IF (NDIG > NDG2MX) THEN + IF (NCALL == 1) THEN + KFLAG = -9 + CALL FMWARN + NDIG = NDSAVE + CALL FMST2M('UNKNOWN',MB) + IF (NTRACE /= 0) CALL FMNTR(1,MB,MB,1,1) + NCALL = NCALL - 1 + RETURN + ELSE + NDIG = NDG2MX + ENDIF + ENDIF + +! Initialize. + + K = ABS(IVAL) + KWRNSV = KWARN + KWARN = 0 + MACCA = MA(0) + CALL FMEQ2(MA,M01,NDSAVE,NDIG) + M01(0) = NINT(NDIG*ALOGM2) + +! Handle small exponents by hand. + + IF (K == 2) THEN + CALL FMSQR(M01,MB) + GO TO 120 + ENDIF + IF (K == 3) THEN + CALL FMSQR(M01,MB) + CALL FMMPY_R1(MB,M01) + GO TO 120 + ENDIF + IF (K == 4) THEN + CALL FMSQR(M01,MB) + CALL FMSQR_R1(MB) + GO TO 120 + ENDIF + IF (K == 5) THEN + CALL FMSQR(M01,MB) + CALL FMSQR_R1(MB) + CALL FMMPY_R1(MB,M01) + GO TO 120 + ENDIF + + IF (MOD(K,2) == 0) THEN + CALL FMI2M(1,MB) + ELSE + CALL FMEQ(M01,MB) + ENDIF + +! This is the multiplication loop. + + 110 K = K/2 + CALL FMSQR_R1(M01) + IF (MOD(K,2) == 1) CALL FMMPY_R2(M01,MB) + IF (K > 1) GO TO 110 + +! Invert if the exponent is negative. + + 120 IF (IVAL < 0) THEN + CALL FMI2M(1,M01) + CALL FMDIV_R2(M01,MB) + ENDIF + KWARN = KWRNSV + +! Round the result and return. + + CALL FMEQ2_R1(MB,NDIG,NDSAVE) + NDIG = NDSAVE + IF (KACCSW == 1) THEN + MACMAX = NINT((NDSAVE-1)*ALOGM2 + & + LOG(REAL(ABS(MB(2))+1))/0.69315) + MB(0) = MIN(MB(0),MACCA,MACMAX) + ELSE + MB(0) = MACCA + ENDIF + IF (KFLAG < 0) CALL FMWARN + IF (NTRACE /= 0) CALL FMNTR(1,MB,MB,1,1) + NCALL = NCALL - 1 + RETURN + END SUBROUTINE FMIPWR + + SUBROUTINE FMLG10(MA,MB) + +! MB = LOG10(MA) + + USE FMVALS + IMPLICIT NONE + + REAL (KIND(1.0D0)) :: MA(-1:LUNPCK),MB(-1:LUNPCK) + REAL (KIND(1.0D0)) :: MACCA,MACMAX,MXSAVE + INTEGER J,K,KASAVE,KOVUN,KRESLT,NDSAVE + + IF (MBLOGS /= MBASE) CALL FMCONS + IF (ABS(MA(1)) > MEXPAB .OR. MA(2) == 0 .OR. MA(-1) < 0) THEN + CALL FMENTR('FMLG10',MA,MA,1,1,MB,KRESLT,NDSAVE,MXSAVE,KASAVE, & + KOVUN) + IF (KRESLT /= 0) RETURN + ELSE + NCALL = NCALL + 1 + NAMEST(NCALL) = 'FMLG10' + IF (NTRACE /= 0) CALL FMNTR(2,MA,MA,1,1) + KOVUN = 0 + IF (MA(1) == MEXPOV .OR. MA(1) == MEXPUN) KOVUN = 1 + NDSAVE = NDIG + IF (NCALL == 1) THEN + K = MAX(NGRD52-1,2) + NDIG = MAX(NDIG+K,2) + IF (NDIG > NDG2MX) THEN + KFLAG = -9 + CALL FMWARN + NDIG = NDSAVE + KRESLT = 12 + CALL FMRSLT(MA,MA,MB,KRESLT) + IF (NTRACE /= 0) CALL FMNTR(1,MB,MB,1,1) + NCALL = NCALL - 1 + RETURN + ENDIF + ENDIF + KASAVE = KACCSW + KACCSW = 0 + MXSAVE = MXEXP + MXEXP = MXEXP2 + ENDIF + + MACCA = MA(0) + CALL FMEQ2(MA,MB,NDSAVE,NDIG) + MB(0) = NINT(NDIG*ALOGM2) + + CALL FMLN(MB,M13) + CALL FMEQ(M13,MB) + IF (MBASE /= MBSLI .OR. NDIG > NDIGLI) THEN + CALL FMLNI(10,M03) + ELSE + CALL FMADD(MLN1,MLN3,M03) + ENDIF + CALL FMDIV_R1(MB,M03) + +! Round the result and return. + + MACMAX = NINT((NDSAVE-1)*ALOGM2 + LOG(REAL(ABS(MB(2))+1))/0.69315) + MB(0) = MIN(MB(0),MACCA,MACMAX) + DO J = -1, NDIG+1 + M01(J) = MB(J) + ENDDO + CALL FMEXIT(M01,MB,NDSAVE,MXSAVE,KASAVE,KOVUN) + RETURN + END SUBROUTINE FMLG10 + + SUBROUTINE FMLN(MA,MB) + +! MB = LOG(MA) (Natural logarithm) + + USE FMVALS + IMPLICIT NONE + + DOUBLE PRECISION Y + REAL (KIND(1.0D0)) :: MA(-1:LUNPCK),MB(-1:LUNPCK) + INTEGER NSTACK(19) + REAL (KIND(1.0D0)) :: MA1,MACCA,MACMAX,MXSAVE + INTEGER IEXTRA,IVAL,J,K,K2,K2EXP,KASAVE,KBOT,KM1,KOVUN,KRESLT, & + KSCALE,KST,KWRNSV,LAST,N1,N3,NDSAV1,NDSAVE,NDSV + REAL X + + IF (MBLOGS /= MBASE) CALL FMCONS + IF (ABS(MA(1)) > MEXPAB .OR. MA(2) == 0 .OR. MA(-1) < 0) THEN + CALL FMENTR('FMLN ',MA,MA,1,1,MB,KRESLT,NDSAVE,MXSAVE,KASAVE, & + KOVUN) + IF (KRESLT /= 0) RETURN + ELSE + NCALL = NCALL + 1 + NAMEST(NCALL) = 'FMLN ' + IF (NTRACE /= 0) CALL FMNTR(2,MA,MA,1,1) + KOVUN = 0 + IF (MA(1) == MEXPOV .OR. MA(1) == MEXPUN) KOVUN = 1 + NDSAVE = NDIG + IF (NCALL == 1) THEN + K = MAX(NGRD52-1,2) + NDIG = MAX(NDIG+K,2) + IF (NDIG > NDG2MX) THEN + KFLAG = -9 + CALL FMWARN + NDIG = NDSAVE + KRESLT = 12 + CALL FMRSLT(MA,MA,MB,KRESLT) + IF (NTRACE /= 0) CALL FMNTR(1,MB,MB,1,1) + NCALL = NCALL - 1 + RETURN + ENDIF + ENDIF + KASAVE = KACCSW + KACCSW = 0 + MXSAVE = MXEXP + MXEXP = MXEXP2 + ENDIF + +! If MA is close to 1, use the Taylor series: +! LN(1+X) = X - X**2/2 + X**3/3 - ... +! This is faster for small X and avoids cancellation error. + +! This method is faster for moderate sized NDIG, but is +! asymptotically slower by a factor of NDIG**(2/3) than +! using Newton and FMEXP. For MBASE=10,000 the Taylor +! series is faster for NDIG less than about 150 (and is +! used only when MA is between .9999 and 1.0001). + + IF (MA(1) == 0 .OR. MA(1) == 1) THEN + X = REAL(MBASE) + X = X**(INT(MA(1))-1)*(REAL(MA(2))+REAL(MA(3))/X) + ELSE + X = 2.0 + ENDIF + IF (X > 0.9999 .AND. X <= 1.0001) THEN + MACCA = MA(0) + CALL FMEQ2(MA,M03,NDSAVE,NDIG) + M03(0) = NINT(NDIG*ALOGM2) + + CALL FMI2M(-1,M01) + CALL FMADD_R1(M03,M01) + +! The sum will be done as two concurrent series. + + NDSAV1 = NDIG + CALL FMEQ(M03,M04) + CALL FMDIVI(M03,2,M05) + CALL FMSQR(M03,MB) + CALL FMEQ(M03,M02) + KBOT = 2 + + 110 KBOT = KBOT + 1 + CALL FMMPY_R1(M02,MB) + CALL FMDIVI(M02,KBOT,M01) + NDIG = NDSAV1 + CALL FMADD_R1(M04,M01) + NDIG = MAX(2,NDSAV1 - INT(M04(1)-M01(1))) + KBOT = KBOT + 1 + CALL FMDIVI(M02,KBOT,M01) + NDIG = NDSAV1 + CALL FMADD_R1(M05,M01) + NDIG = MAX(2,NDSAV1 - INT(M04(1)-M01(1))) + IF (KFLAG /= 1) GO TO 110 + + NDIG = NDSAV1 + CALL FMMPY_R1(M05,M03) + CALL FMSUB(M04,M05,MB) + GO TO 140 + ENDIF + + MA1 = MA(1) + MACCA = MA(0) + CALL FMEQ2(MA,M05,NDSAVE,NDIG) + M05(0) = NINT(NDIG*ALOGM2) + +! Compute IEXTRA, the number of extra digits required. + + CALL FMI2M(1,M04) + CALL FMSUB_R1(M04,M05) + IEXTRA = MAX(0-INT(M04(1)),0) + IF (IEXTRA > 0 .AND. NDIG+IEXTRA <= NDG2MX) THEN + CALL FMEQ2_R1(M05,NDIG,NDIG+IEXTRA) + ENDIF + NDIG = NDIG + IEXTRA + IF (NDIG > NDG2MX) THEN + IF (NCALL == 1) THEN + KFLAG = -9 + CALL FMWARN + NDIG = NDSAVE + CALL FMST2M('UNKNOWN',MB) + DO J = -1, NDIG+1 + M01(J) = MB(J) + ENDDO + CALL FMEXIT(M01,MB,NDSAVE,MXSAVE,KASAVE,KOVUN) + RETURN + ELSE + CALL FMEQ2_R1(M05,NDIG-IEXTRA,NDG2MX) + NDIG = NDG2MX + ENDIF + ENDIF + +! Check to see if the argument is a small integer. +! If so use FMLNI. + + KM1 = 0 + + KWRNSV = KWARN + KWARN = 0 + CALL FMM2I(M05,IVAL) + KWARN = KWRNSV + IF (KFLAG == 0 .AND. IVAL < MXBASE) THEN + CALL FMLNI(IVAL,MB) + GO TO 140 + ENDIF + +! See if the argument can be scaled to a small integer. + + N3 = NDIG + 3 + N1 = NDIG + 1 + DO J = 2, N1 + IF (M05(N3-J) /= 0) THEN + LAST = N3 - J - 1 + GO TO 120 + ENDIF + ENDDO + + 120 KSCALE = INT(MA1) - LAST + M05(1) = LAST + KWRNSV = KWARN + KWARN = 0 + CALL FMM2I(M05,IVAL) + KWARN = KWRNSV + IF (KFLAG == 0 .AND. IVAL < MXBASE) THEN + CALL FMLNI(IVAL,M04) + IF (IVAL == 1) KM1 = 1 + K2EXP = 0 + GO TO 130 + ENDIF + +! For the non-integer case, scale the argument to lie +! between e/2 and e to speed up the calls to FMEXP. + + M05(1) = 1 + KSCALE = INT(MA1) - 1 + CALL FMM2DP(M05,Y) + K2EXP = INT(LOG(2.0*REAL(Y)/2.71828)/0.693147) + IF (Y < 1.359141) THEN + K2EXP = -1 + CALL FMMPYI_R1(M05,2) + Y = 2.0D0*Y + ELSE + K2 = 2**K2EXP + CALL FMDIVI_R1(M05,K2) + Y = Y/K2 + ENDIF + +! Generate the initial approximation. + + Y = LOG(Y) + CALL FMDPM(Y,M04) + CALL FMDIG(NSTACK,KST) + +! Newton iteration. + + DO J = 1, KST + NDIG = NSTACK(J) + CALL FMEXP(M04,MB) + CALL FMSUB(M05,MB,M02) + CALL FMDIV_R2(M02,MB) + CALL FMADD_R1(M04,MB) + ENDDO + M04(0) = NINT(NDIG*ALOGM2) + +! Compute LN(MBASE**KSCALE). + + 130 IF ((MBSLB /= MBASE .OR. NDIGLB < NDIG) .AND. KSCALE /= 0) THEN + NDSV = NDIG + NDIG = MIN(NDIG+2,NDG2MX) + CALL FMLNI(INT(MBASE),MLBSAV) + MBSLB = MBASE + NDIGLB = NDIG + IF (ABS(MLBSAV(1)) > 10) NDIGLB = 0 + NDIG = NDSV + ENDIF + + IF (KSCALE /= 0 .AND. KM1 == 0) THEN + CALL FMMPYI(MLBSAV,KSCALE,MB) + CALL FMADD_R2(M04,MB) + ELSE IF (KSCALE /= 0 .AND. KM1 == 1) THEN + CALL FMMPYI(MLBSAV,KSCALE,MB) + ELSE IF (KSCALE == 0 .AND. KM1 == 0) THEN + CALL FMEQ(M04,MB) + ELSE IF (KSCALE == 0 .AND. KM1 == 1) THEN + CALL FMI2M(0,MB) + ENDIF + + IF (K2EXP /= 0) THEN + IF (MBASE /= MBSLI .OR. NDIG > NDIGLI) THEN + CALL FMLNI(2,M04) + ENDIF + CALL FMMPYI(MLN1,K2EXP,M04) + CALL FMADD_R1(MB,M04) + ENDIF + +! Round the result and return. + + 140 MACMAX = NINT((NDSAVE-1)*ALOGM2 + LOG(REAL(ABS(MB(2))+1))/0.69315) + MB(0) = MIN(MB(0),MACCA,MACMAX) + DO J = -1, NDIG+1 + M01(J) = MB(J) + ENDDO + CALL FMEXIT(M01,MB,NDSAVE,MXSAVE,KASAVE,KOVUN) + RETURN + END SUBROUTINE FMLN + + SUBROUTINE FMLNI(IVAL,MA) + +! MA = LOG(IVAL) + +! Compute the natural logarithm of an integer IVAL. + +! If IVAL has only powers of 2, 3, 5, and 7 in its factorization then +! FMLNI is faster than FMLN. Otherwise, if IVAL >= MXBASE (i.e., IVAL +! does not fit in 1/2 word) then FMLN is usually faster. + +! Use FMLN instead of FMLNI if 10*IVAL would cause integer overflow. + + USE FMVALS + IMPLICIT NONE + + REAL (KIND(1.0D0)) :: MA(-1:LUNPCK) + INTEGER IVAL + CHARACTER(155) :: STRING + INTEGER INT2,J2,J3,J5,J7,JTEMP2,JTEMP3,JTEMP5,JTEMP7,K,K2,K3, & + K5,K7,KASAVE,KDELTA,LAST,ND,NDMB,NDSAVE,NDSV,NT + REAL XVAL + + IF (MBLOGS /= MBASE) CALL FMCONS + KFLAG = 0 + NCALL = NCALL + 1 + NAMEST(NCALL) = 'FMLNI ' + IF (NTRACE /= 0) CALL FMNTRI(2,IVAL,1) + +! Check for special cases. + + IF (IVAL <= 0) THEN + KFLAG = -4 + CALL FMWARN + CALL FMST2M('UNKNOWN',MA) + IF (NTRACE /= 0) CALL FMNTR(1,MA,MA,1,1) + NCALL = NCALL - 1 + RETURN + ENDIF + + IF (IVAL == 1) THEN + CALL FMI2M(0,MA) + IF (NTRACE /= 0) CALL FMNTR(1,MA,MA,1,1) + NCALL = NCALL - 1 + RETURN + ENDIF + +! Increase the working precision. + + NDSAVE = NDIG + IF (NCALL == 1) THEN + K = NGRD52 + NDIG = MAX(NDIG+K,2) + IF (NDIG > NDG2MX) THEN + KFLAG = -9 + CALL FMWARN + NDIG = NDSAVE + CALL FMST2M('UNKNOWN',MA) + IF (NTRACE /= 0) CALL FMNTR(1,MA,MA,1,1) + NCALL = NCALL - 1 + RETURN + ENDIF + ENDIF + KASAVE = KACCSW + KACCSW = 0 + +! Find integers K2, K3, K5, and K7 such that +! NT = 2**K2 * 3**K3 * 5**K5 * 7**K7 +! is a good approximation of IVAL. +! KDELTA = ABS(IVAL - NT). + + INT2 = IVAL + IF (IVAL > INTMAX/100) INT2 = IVAL/100 + KDELTA = INT2 + NT = 0 + K2 = 0 + K3 = 0 + K5 = 0 + K7 = 0 + +! Start the search loop. + + XVAL = INT2 + LAST = INT(LOG(DBLE(XVAL))/DLOGTW + 2.0D0) + + JTEMP7 = 1 + DO J7 = 1, LAST + IF (JTEMP7 > INT2 .AND. & + ABS(JTEMP7-INT2) > KDELTA) GO TO 140 + + JTEMP5 = JTEMP7 + DO J5 = 1, LAST + IF (JTEMP5 > INT2 .AND. & + ABS(JTEMP5-INT2) > KDELTA) GO TO 130 + + JTEMP3 = JTEMP5 + DO J3 = 1, LAST + IF (JTEMP3 > INT2 .AND. & + ABS(JTEMP3-INT2) > KDELTA) GO TO 120 + + JTEMP2 = JTEMP3 + DO J2 = 1, LAST + IF (ABS(JTEMP2-INT2) <= KDELTA) THEN + IF (ABS(JTEMP2-INT2) == KDELTA .AND. & + JTEMP2 < INT2) GO TO 110 + KDELTA = ABS(JTEMP2-INT2) + NT = JTEMP2 + K2 = J2 - 1 + K3 = J3 - 1 + K5 = J5 - 1 + K7 = J7 - 1 + IF (KDELTA == 0) GO TO 140 + ENDIF + IF (JTEMP2 > INT2) GO TO 110 + + JTEMP2 = 2*JTEMP2 + ENDDO + + 110 JTEMP3 = 3*JTEMP3 + ENDDO + + 120 JTEMP5 = 5*JTEMP5 + ENDDO + + 130 JTEMP7 = 7*JTEMP7 + ENDDO + +! If IVAL was too close to the integer overflow limit, +! restore NT to an approximation of IVAL. + + 140 IF (INT2 /= IVAL) THEN + IF (NT <= INT2) THEN + NT = NT*100 + K2 = K2 + 2 + K5 = K5 + 2 + ELSE IF (NT <= IVAL/98) THEN + NT = NT*98 + K2 = K2 + 1 + K7 = K7 + 2 + ELSE + NT = NT*70 + K2 = K2 + 1 + K5 = K5 + 1 + K7 = K7 + 1 + ENDIF + ENDIF + +! End of the search. Now compute LN(NT) as a linear +! combination of LN(2), LN(3), LN(5), and LN(7). + + IF (MBASE /= MBSLI .OR. NDIG > NDIGLI) THEN + NDMB = INT(150.0*2.302585/ALOGMB) + IF (NDMB >= NDIG) THEN + NDSV = NDIG + NDIG = MIN(NDMB,NDG2MX) + STRING = '0.693147180559945309417232121458176568075500'// & + '13436025525412068000949339362196969471560586332699641'// & + '8687542001481020570685733685520235758130557032670751635' + CALL FMST2M(STRING,MLN1) + STRING = '1.098612288668109691395245236922525704647490'// & + '55782274945173469433363749429321860896687361575481373'// & + '2088787970029065957865742368004225930519821052801870767' + CALL FMST2M(STRING,MLN2) + STRING = '1.609437912434100374600759333226187639525601'// & + '35426851772191264789147417898770765776463013387809317'// & + '9610799966303021715562899724005229324676199633616617464' + CALL FMST2M(STRING,MLN3) + STRING = '1.945910149055313305105352743443179729637084'// & + '72958186118845939014993757986275206926778765849858787'// & + '1526993061694205851140911723752257677786843148958095164' + CALL FMST2M(STRING,MLN4) + MBSLI = MBASE + NDIGLI = NDIG + IF (ABS(MLN1(1)) > 10 .OR. ABS(MLN2(1)) > 10 .OR. & + ABS(MLN3(1)) > 10 .OR. ABS(MLN4(1)) > 10) NDIGLI = 0 + ELSE + NDSV = NDIG + NDIG = MIN(NDIG+2,NDG2MX) + MBSLI = MBASE + NDIGLI = NDIG + + CALL FMLNI2(1,126,MLN1) + CALL FMLNI2(1,225,MLN2) + CALL FMLNI2(1,2401,MLN3) + CALL FMLNI2(1,4375,MLN4) + +! Get Ln(2). + + CALL FMMPYI_R1(MLN1,-72) + CALL FMMPYI(MLN2,-27,MA) + CALL FMADD_R1(MLN1,MA) + CALL FMMPYI(MLN3,19,MA) + CALL FMADD_R1(MLN1,MA) + CALL FMMPYI(MLN4,-31,MA) + CALL FMADD_R1(MLN1,MA) + +! Get Ln(3). + + CALL FMMPYI_R1(MLN2,-3) + CALL FMMPYI(MLN1,19,MA) + CALL FMADD_R1(MLN2,MA) + CALL FMSUB_R1(MLN2,MLN3) + CALL FMADD_R1(MLN2,MLN4) + CALL FMDIVI_R1(MLN2,12) + +! Get Ln(5). + + CALL FMSUB_R1(MLN3,MLN1) + CALL FMMPYI(MLN2,27,MA) + CALL FMADD_R1(MLN3,MA) + CALL FMMPYI(MLN4,-4,MA) + CALL FMADD_R1(MLN3,MA) + CALL FMDIVI_R1(MLN3,18) + +! Get Ln(7). + + CALL FMSUB_R2(MLN1,MLN4) + CALL FMMPYI(MLN2,7,MA) + CALL FMADD_R1(MLN4,MA) + CALL FMMPYI(MLN3,-4,MA) + CALL FMADD_R1(MLN4,MA) + ENDIF + MLN1(0) = NINT(NDIG*ALOGM2) + MLN2(0) = MLN1(0) + MLN3(0) = MLN1(0) + MLN4(0) = MLN1(0) + IF (ABS(MLN1(1)) > 10 .OR. ABS(MLN2(1)) > 10 .OR. & + ABS(MLN3(1)) > 10 .OR. ABS(MLN4(1)) > 10) NDIGLI = 0 + NDIG = NDSV + ENDIF + +! If NT /= IVAL then the final step is to compute +! LN(IVAL/NT) and then use LN(IVAL) = LN(IVAL/NT) + LN(NT). + + IF (NT /= IVAL) THEN + ND = NT - IVAL + CALL FMLNI2(ND,NT,MA) + ENDIF + + CALL FMMPYI(MLN1,K2,M02) + CALL FMMPYI(MLN2,K3,M01) + CALL FMADD_R1(M02,M01) + CALL FMMPYI(MLN3,K5,M01) + CALL FMADD_R1(M02,M01) + CALL FMMPYI(MLN4,K7,M01) + IF (NT /= IVAL) CALL FMADD_R1(M02,MA) + CALL FMADD(M02,M01,MA) + +! Round and move the result to MA. + + KACCSW = KASAVE + CALL FMEQ2_R1(MA,NDIG,NDSAVE) + NDIG = NDSAVE + IF (NTRACE /= 0) CALL FMNTR(1,MA,MA,1,1) + NCALL = NCALL - 1 + RETURN + END SUBROUTINE FMLNI + + SUBROUTINE FMLNI2(INT1,INT2,MA) + +! MA = LN(1 - INT1/INT2) + +! Taylor series for computing the logarithm of a rational number +! near 1. + + USE FMVALS + IMPLICIT NONE + + INTEGER INT1,INT2 + REAL (KIND(1.0D0)) :: MA(-1:LUNPCK) + INTEGER J,NDSAVE + + CALL FMI2M(INT1,M02) + CALL FMDIVI_R1(M02,INT2) + CALL FMEQ(M02,MA) + NDSAVE = NDIG + J = 1 + + 110 J = J + 1 + IF (INT1 /= 1) CALL FMMPYI_R1(M02,INT1) + CALL FMDIVI_R1(M02,INT2) + CALL FMDIVI(M02,J,M01) + NDIG = NDSAVE + CALL FMADD_R1(MA,M01) + NDIG = NDSAVE - INT(MA(1)-M01(1)) + IF (NDIG < 2) NDIG = 2 + IF (KFLAG /= 1) GO TO 110 + + NDIG = NDSAVE + MA(0) = NINT(NDIG*ALOGM2) + IF (MA(1) /= MUNKNO .AND. MA(2) /= 0) MA(-1) = -MA(-1) + RETURN + END SUBROUTINE FMLNI2 + + SUBROUTINE FMM2DP(MA,X) + +! X = MA + +! Convert an FM number to double precision. + +! If KFLAG = -4 is returned for a value of MA that is in the range +! of the machine's double precision number system, change the +! definition of DPMAX in routine FMSET to reflect the current machine's +! range. + + USE FMVALS + IMPLICIT NONE + + REAL (KIND(1.0D0)) :: MA(-1:LUNPCK) + DOUBLE PRECISION X + + INTEGER KRESLT + + NCALL = NCALL + 1 + NAMEST(NCALL) = 'FMM2DP' + KRESLT = 0 + IF (ABS(MA(1)) > MEXPAB) THEN + CALL FMARGS('FMM2DP',1,MA,MA,KRESLT) + ENDIF + IF (NTRACE /= 0) CALL FMNTR(2,MA,MA,1,1) + IF (KRESLT /= 0) THEN + +! Here no valid result can be returned. Set X to some +! value that the user is likely to recognize as wrong. + + X = DBLE(RUNKNO) + KFLAG = -4 + IF (MA(1) /= MUNKNO) CALL FMWARN + IF (NTRACE /= 0) CALL FMNTRR(1,X,1) + NCALL = NCALL - 1 + RETURN + ENDIF + + CALL FMMD(MA,X) + + IF (NTRACE /= 0) CALL FMNTRR(1,X,1) + NCALL = NCALL - 1 + RETURN + END SUBROUTINE FMM2DP + + SUBROUTINE FMM2I(MA,IVAL) + +! IVAL = MA + +! Convert an FM number to integer. + +! KFLAG = 0 is returned if the conversion is exact. +! = -4 is returned if MA is larger than INTMAX in magnitude. +! IVAL = IUNKNO is returned as an indication that IVAL +! could not be computed without integer overflow. +! = 2 is returned if MA is smaller than INTMAX in magnitude +! but MA is not an integer. The next integer toward zero +! is returned in IVAL. +! It is sometimes convenient to call FMM2I to see if an FM number +! can be represented as a one-word integer, by checking KFLAG upon +! return. To avoid an unwanted error message being printed in the +! KFLAG=-4 case, set KWARN=0 before the call to FMM2I and reset it +! after the call. + +! This routine performs the trace printing for the conversion. +! FMMI is used to do the arithmetic. + + USE FMVALS + IMPLICIT NONE + + REAL (KIND(1.0D0)) :: MA(-1:LUNPCK) + INTEGER IVAL + + NCALL = NCALL + 1 + NAMEST(NCALL) = 'FMM2I ' + IF (NTRACE /= 0) CALL FMNTR(2,MA,MA,1,1) + + CALL FMMI(MA,IVAL) + + IF (NTRACE /= 0) CALL FMNTRI(1,IVAL,1) + NCALL = NCALL - 1 + RETURN + END SUBROUTINE FMM2I + + SUBROUTINE FMM2SP(MA,X) + +! X = MA + +! Convert an FM number to single precision. + +! MA is converted and the result is returned in X. + +! If KFLAG = -4 is returned for a value of MA that is in the range +! of the machine's single precision number system, change the +! definition of SPMAX in routine FMSET to reflect the current machine's +! range. + + USE FMVALS + IMPLICIT NONE + + REAL (KIND(1.0D0)) :: MA(-1:LUNPCK) + REAL X + + DOUBLE PRECISION Y + INTEGER KRESLT + + NCALL = NCALL + 1 + NAMEST(NCALL) = 'FMM2SP' + KRESLT = 0 + IF (ABS(MA(1)) > MEXPAB) THEN + CALL FMARGS('FMM2SP',1,MA,MA,KRESLT) + ENDIF + IF (NTRACE /= 0) CALL FMNTR(2,MA,MA,1,1) + IF (KRESLT /= 0) THEN + +! Here no valid result can be returned. Set X to some +! value that the user is likely to recognize as wrong. + + X = RUNKNO + KFLAG = -4 + IF (MA(1) /= MUNKNO) CALL FMWARN + Y = DBLE(X) + IF (NTRACE /= 0) CALL FMNTRR(1,Y,1) + NCALL = NCALL - 1 + RETURN + ENDIF + + CALL FMMD(MA,Y) + X = REAL(Y) + + IF (NTRACE /= 0) THEN + Y = DBLE(X) + CALL FMNTRR(1,Y,1) + ENDIF + NCALL = NCALL - 1 + RETURN + END SUBROUTINE FMM2SP + + SUBROUTINE FMMAX(MA,MB,MC) + +! MC = MAX(MA,MB) + + USE FMVALS + IMPLICIT NONE + + REAL (KIND(1.0D0)) :: MA(-1:LUNPCK),MB(-1:LUNPCK),MC(-1:LUNPCK) + + INTEGER KWRNSV + LOGICAL FMCOMP + + KFLAG = 0 + NCALL = NCALL + 1 + NAMEST(NCALL) = 'FMMAX ' + IF (NTRACE /= 0) CALL FMNTR(2,MA,MB,2,1) + + KWRNSV = KWARN + KWARN = 0 + IF (MA(1) == MUNKNO .OR. MB(1) == MUNKNO) THEN + CALL FMST2M('UNKNOWN',MC) + KFLAG = -4 + ELSE IF (FMCOMP(MA,'LT',MB)) THEN + CALL FMEQ(MB,MC) + ELSE + CALL FMEQ(MA,MC) + ENDIF + + KWARN = KWRNSV + IF (NTRACE /= 0) CALL FMNTR(1,MC,MC,1,1) + NCALL = NCALL - 1 + RETURN + END SUBROUTINE FMMAX + + SUBROUTINE FMMD(MA,X) + +! X = MA + +! Internal routine for conversion to double precision. + + USE FMVALS + IMPLICIT NONE + + REAL (KIND(1.0D0)) :: MA(-1:LUNPCK) + DOUBLE PRECISION X + + DOUBLE PRECISION Y,YT,XBASE,RZERO,ONE,PMAX,DLOGDP + REAL (KIND(1.0D0)) :: MA1,MAS + INTEGER J,KWRNSV,N1,NCASE + +! Check to see if MA is in range for single or double +! precision. + + IF (MBLOGS /= MBASE) CALL FMCONS + PMAX = DPMAX + IF (NCALL > 0) THEN + IF (NAMEST(NCALL) == 'FMM2SP') PMAX = DBLE(SPMAX) + ENDIF + DLOGDP = LOG(PMAX) + MA1 = MA(1) + NCASE = 0 + IF (DBLE(MA(1)-1)*DLOGMB > DLOGDP) THEN + KFLAG = -4 + X = DBLE(RUNKNO) + CALL FMWARN + RETURN + ELSE IF (DBLE(MA(1)+1)*DLOGMB > DLOGDP) THEN + MA1 = MA1 - 2 + NCASE = 1 + ELSE IF (DBLE(MA(1)+1)*DLOGMB < -DLOGDP) THEN + KFLAG = -10 + X = 0.0D0 + CALL FMWARN + RETURN + ELSE IF (DBLE(MA(1)-1)*DLOGMB < -DLOGDP) THEN + MA1 = MA1 + 2 + NCASE = 2 + ENDIF + +! Try FMMI first so that small integers will be +! converted exactly. + + KWRNSV = KWARN + KWARN = 0 + CALL FMMI(MA,J) + KWARN = KWRNSV + IF (KFLAG == 0) THEN + X = J + RETURN + ENDIF + KFLAG = 0 + + MAS = MA(-1) + RZERO = 0.0D0 + ONE = 1.0D0 + N1 = NDIG + 1 + XBASE = MBASE + X = RZERO + Y = ONE + DO J = 2, N1 + Y = Y/XBASE + YT = MA(J) + X = X + Y*YT + YT = ONE + Y*XBASE + IF (YT <= ONE) GO TO 110 + ENDDO + + 110 X = X*XBASE**MA1 + IF (MAS < 0) X = -X + +! Check the result if it is near overflow or underflow. + + IF (NCASE == 1) THEN + IF (X <= PMAX/(XBASE*XBASE)) THEN + X = X*XBASE*XBASE + ELSE + KFLAG = -4 + X = DBLE(RUNKNO) + CALL FMWARN + ENDIF + ELSE IF (NCASE == 2) THEN + IF (X >= (1.0D0/PMAX)*XBASE*XBASE) THEN + X = X/(XBASE*XBASE) + ELSE + KFLAG = -10 + X = 0.0D0 + CALL FMWARN + ENDIF + ENDIF + RETURN + END SUBROUTINE FMMD + + SUBROUTINE FMMI(MA,IVAL) + +! IVAL = MA. Internal FM to integer conversion routine. + + USE FMVALS + IMPLICIT NONE + + REAL (KIND(1.0D0)) :: MA(-1:LUNPCK) + INTEGER IVAL + + INTEGER J,KA,KB,LARGE,N1 + + KFLAG = 0 + N1 = NDIG + 1 + LARGE = INT(INTMAX/MBASE) + IVAL = 0 + IF (MA(1) <= 0) THEN + IF (MA(2) /= 0) KFLAG = 2 + RETURN + ENDIF + + KB = INT(MA(1)) + 1 + IVAL = INT(ABS(MA(2))) + IF (KB >= 3) THEN + DO J = 3, KB + IF (IVAL > LARGE) THEN + KFLAG = -4 + IF (MA(1) /= MUNKNO) CALL FMWARN + IVAL = IUNKNO + RETURN + ENDIF + IF (J <= N1) THEN + IVAL = IVAL*INT(MBASE) + IF (IVAL > INTMAX-MA(J)) THEN + KFLAG = -4 + IF (MA(1) /= MUNKNO) CALL FMWARN + IVAL = IUNKNO + RETURN + ELSE + IVAL = IVAL + INT(MA(J)) + ENDIF + ELSE + IVAL = IVAL*INT(MBASE) + ENDIF + ENDDO + ENDIF + + IF (MA(-1) < 0) IVAL = -IVAL + +! Check to see if MA is an integer. + + KA = KB + 1 + IF (KA <= N1) THEN + DO J = KA, N1 + IF (MA(J) /= 0) THEN + KFLAG = 2 + RETURN + ENDIF + ENDDO + ENDIF + + RETURN + END SUBROUTINE FMMI + + SUBROUTINE FMMIN(MA,MB,MC) + +! MC = MIN(MA,MB) + + USE FMVALS + IMPLICIT NONE + + REAL (KIND(1.0D0)) :: MA(-1:LUNPCK),MB(-1:LUNPCK),MC(-1:LUNPCK) + + INTEGER KWRNSV + LOGICAL FMCOMP + + KFLAG = 0 + NCALL = NCALL + 1 + NAMEST(NCALL) = 'FMMIN ' + IF (NTRACE /= 0) CALL FMNTR(2,MA,MB,2,1) + + KWRNSV = KWARN + KWARN = 0 + IF (MA(1) == MUNKNO .OR. MB(1) == MUNKNO) THEN + CALL FMST2M('UNKNOWN',MC) + KFLAG = -4 + ELSE IF (FMCOMP(MA,'GT',MB)) THEN + CALL FMEQ(MB,MC) + ELSE + CALL FMEQ(MA,MC) + ENDIF + + KWARN = KWRNSV + IF (NTRACE /= 0) CALL FMNTR(1,MC,MC,1,1) + NCALL = NCALL - 1 + RETURN + END SUBROUTINE FMMIN + + SUBROUTINE FMMOD(MA,MB,MC) + +! MC = MA(MOD MB). + + USE FMVALS + IMPLICIT NONE + + REAL (KIND(1.0D0)) :: MA(-1:LUNPCK),MB(-1:LUNPCK),MC(-1:LUNPCK) + REAL (KIND(1.0D0)) :: MACCA,MACCB,MACMAX,MVB,MVC,MVY,MVZ,MXSAVE + INTEGER J,K,KASAVE,KB,KE,KN,KOVUN,KRESLT,KWRNSV,NDSAVE,NTRSAV + LOGICAL FMCOMP + + IF (MBLOGS /= MBASE) CALL FMCONS + IF (ABS(MA(1)) > MEXPAB .OR. ABS(MB(1)) > MEXPAB) THEN + CALL FMENTR('FMMOD ',MA,MB,2,1,MC,KRESLT,NDSAVE,MXSAVE,KASAVE, & + KOVUN) + IF (KRESLT /= 0) RETURN + ELSE + NCALL = NCALL + 1 + NAMEST(NCALL) = 'FMMOD ' + IF (NTRACE /= 0) CALL FMNTR(2,MA,MB,2,1) + KOVUN = 0 + IF (MA(1) == MEXPOV .OR. MA(1) == MEXPUN) KOVUN = 1 + IF (MB(1) == MEXPOV .OR. MB(1) == MEXPUN) KOVUN = 1 + NDSAVE = NDIG + IF (NCALL == 1) THEN + K = MAX(NGRD52-1,2) + NDIG = MAX(NDIG+K,2) + IF (NDIG > NDG2MX) THEN + KFLAG = -9 + CALL FMWARN + NDIG = NDSAVE + KRESLT = 12 + CALL FMRSLT(MA,MB,MC,KRESLT) + IF (NTRACE /= 0) CALL FMNTR(1,MC,MC,1,1) + NCALL = NCALL - 1 + RETURN + ENDIF + ENDIF + KASAVE = KACCSW + MXSAVE = MXEXP + MXEXP = MXEXP2 + ENDIF + KWRNSV = KWARN + KWARN = 0 + MACCA = MA(0) + MACCB = MB(0) + + IF (MB(1) > MA(1) .AND. MB(2) /= 0) THEN + CALL FMEQ2(MA,M01,NDSAVE,NDIG) + M01(0) = NINT(NDIG*ALOGM2) + ELSE + +! Special cases when MB is a small integer. + + CALL FMEQ2(MA,M02,NDSAVE,NDIG) + M02(0) = NINT(NDIG*ALOGM2) + CALL FMEQ2(MB,M03,NDSAVE,NDIG) + M03(0) = NINT(NDIG*ALOGM2) + M02(-1) = 1 + M03(-1) = 1 + + CALL FMM2I(M03,KB) + IF (KFLAG == 0 .AND. KB < MXBASE) THEN + IF (KB == 1 .OR. KB == -1) THEN + IF (M02(1) >= NDIG) THEN + CALL FMI2M(0,M01) + GO TO 130 + ELSE + CALL FMINT(M02,M03) + CALL FMSUB(M02,M03,M01) + IF (MA(-1) < 0 .AND. M01(1) /= MUNKNO .AND. & + M01(2) /= 0) M01(-1) = -M01(-1) + GO TO 130 + ENDIF + ELSE IF (M02(1) == MEXPOV .OR. KB == 0) THEN + KFLAG = -4 + KWARN = KWRNSV + KACCSW = KASAVE + MXEXP = MXSAVE + CALL FMWARN + NDIG = NDSAVE + CALL FMST2M('UNKNOWN',MC) + IF (NTRACE /= 0) CALL FMNTR(1,MC,MC,1,1) + NCALL = NCALL - 1 + RETURN + ELSE IF (M02(1) > NDIG.AND.MOD(INT(MBASE),KB) == 0) THEN + CALL FMI2M(0,M01) + GO TO 130 + ENDIF + IF (M02(1) < NDIG) THEN + DO J = INT(M02(1))+1, NDIG+1 + IF (M02(J) /= 0) GO TO 120 + ENDDO + ENDIF + KE = MIN(INT(M02(1)),NDIG) + MVB = KB + MVC = MOD(M02(2),MVB) + DO J = 3, KE+1 + MVC = MOD(MVC*MBASE+M02(J),MVB) + ENDDO + IF (MVC == 0) THEN + CALL FMI2M(0,M01) + GO TO 130 + ENDIF + KN = INT(M02(1)) - KE + MVY = MOD(MBASE,MVB) + MVZ = 1 + IF (MOD(KN,2) == 1) MVZ = MVY + + IF (MVY /= 1) THEN + 110 KN = KN/2 + MVY = MOD(MVY*MVY,MVB) + IF (MOD(KN,2) == 1) MVZ = MOD(MVZ*MVY,MVB) + IF (KN > 1) GO TO 110 + ENDIF + MVZ = MOD(MVZ*MVC,MVB) + KE = INT(MVZ) + CALL FMI2M(KE,M01) + IF (MA(-1) < 0 .AND. M01(1) /= MUNKNO .AND. & + M01(2) /= 0) M01(-1) = -M01(-1) + GO TO 130 + ENDIF + +! General case. + + 120 IF (MA(2) /= 0) THEN + NDIG = NDIG + INT(MA(1)-MB(1)) + ENDIF + IF (NDIG > NDG2MX .OR. MB(2) == 0) THEN + KFLAG = -9 + IF (MA(1) == MEXPOV .OR. MB(1) == MEXPUN .OR. MB(2) == 0) & + KFLAG = -4 + KWARN = KWRNSV + KACCSW = KASAVE + MXEXP = MXSAVE + CALL FMWARN + NDIG = NDSAVE + CALL FMST2M('UNKNOWN',MC) + IF (NTRACE /= 0) CALL FMNTR(1,MC,MC,1,1) + NCALL = NCALL - 1 + RETURN + ENDIF + + CALL FMEQ2(MA,M02,NDSAVE,NDIG) + M02(0) = NINT(NDIG*ALOGM2) + CALL FMEQ2(MB,M03,NDSAVE,NDIG) + M03(0) = NINT(NDIG*ALOGM2) + + M02(-1) = 1 + M03(-1) = 1 + CALL FMDIV(M02,M03,M01) + CALL FMINT(M01,M08) + CALL FMEQ(M08,M01) + CALL FMMPY_R1(M01,M03) + CALL FMSUB_R2(M02,M01) + +! Due to rounding, M01 may not be between 0 and MB here. + + NTRSAV = NTRACE + NTRACE = 0 + IF (FMCOMP(M01,'GE',M03)) THEN + NTRACE = NTRSAV + CALL FMSUB_R1(M01,M03) + ENDIF + NTRACE = NTRSAV + IF (M01(-1) < 0) CALL FMADD_R1(M01,M03) + IF (MA(-1) < 0 .AND. M01(1) /= MUNKNO .AND. M01(2) /= 0) & + M01(-1) = -M01(-1) + ENDIF + + 130 IF (KFLAG == 1) KFLAG = 0 + KWARN = KWRNSV + MACMAX = NINT((NDSAVE-1)*ALOGM2+LOG(REAL(ABS(M01(2))+1))/0.69315) + M01(0) = MIN(M01(0),MACCA,MACCB,MACMAX) + CALL FMEXIT(M01,MC,NDSAVE,MXSAVE,KASAVE,KOVUN) + RETURN + END SUBROUTINE FMMOD + + SUBROUTINE FMMOVE(MW,MA) + +! Move a result from a work area (MW) to MA. + +! If the result has MW(2)=0, then it is shifted and the exponent +! adjusted when it is moved to MA. + + USE FMVALS + IMPLICIT NONE + + REAL (KIND(1.0D0)) :: MA(-1:LUNPCK),MW(LMWA) + + INTEGER J,N1,N2 + + IF (MW(2) /= 0) THEN + N1 = NDIG + 1 + +! Major (Inner Loop) + + DO J = 1, N1 + MA(J) = MW(J) + ENDDO + ELSE + N2 = NDIG + 2 + DO J = 3, N2 + MA(J-1) = MW(J) + ENDDO + IF (MA(2) /= 0) THEN + MA(1) = MW(1) - 1 + ELSE + MA(1) = 0 + ENDIF + ENDIF + + MA(-1) = 1 + IF (ABS(MA(1)) > MXEXP) CALL FMTRAP(MA) + + RETURN + END SUBROUTINE FMMOVE + + SUBROUTINE FMMPY(MA,MB,MC) + +! MC = MA * MB + +! When one of the numbers MA, MB is known to have more zero digits +! (base MBASE) than the other, it is faster if MB is the one with +! more zero digits. + +! This routine performs the trace printing for multiplication. +! FMMPY2 is used to do the arithmetic. + + USE FMVALS + IMPLICIT NONE + + REAL (KIND(1.0D0)) :: MA(-1:LUNPCK),MB(-1:LUNPCK),MC(-1:LUNPCK) + + NCALL = NCALL + 1 + IF (NTRACE /= 0) THEN + NAMEST(NCALL) = 'FMMPY ' + CALL FMNTR(2,MA,MB,2,1) + + CALL FMMPY2(MA,MB,MC) + + CALL FMNTR(1,MC,MC,1,1) + ELSE + CALL FMMPY2(MA,MB,MC) + ENDIF + NCALL = NCALL - 1 + RETURN + END SUBROUTINE FMMPY + + SUBROUTINE FMMPY2(MA,MB,MC) + +! Internal multiplication routine. MC = MA * MB + + USE FMVALS + IMPLICIT NONE + + REAL (KIND(1.0D0)) :: MA(-1:LUNPCK),MB(-1:LUNPCK),MC(-1:LUNPCK) + + REAL (KIND(1.0D0)) :: MACCA,MACCB,MAS,MBS,MD2B,MR,MS,MT1,MT2 + INTEGER J,JRSSAV,K,KRESLT,KT,KT1,KT2,KSHIFT,L,N1,NGUARD + + IF (MBLOGS /= MBASE) CALL FMCONS + JRSSAV = JRSIGN + MACCA = MA(0) + MACCB = MB(0) + IF (ABS(MA(1)) > MEXPAB .OR. ABS(MB(1)) > MEXPAB .OR. & + KDEBUG == 1) THEN + CALL FMARGS('FMMPY ',2,MA,MB,KRESLT) + IF (KRESLT /= 0) THEN + NCALL = NCALL + 1 + NAMEST(NCALL) = 'FMMPY ' + CALL FMRSLT(MA,MB,MC,KRESLT) + JRSIGN = JRSSAV + NCALL = NCALL - 1 + RETURN + ENDIF + ELSE IF (MA(2) == 0 .OR. MB(2) == 0) THEN + CALL FMIM(0,MC) + MC(0) = MIN(MACCA,MACCB) + JRSIGN = JRSSAV + RETURN + ENDIF + KFLAG = 0 + +! Save the sign of MA and MB and then work only with +! positive numbers. + + MAS = MA(-1) + MBS = MB(-1) + +! NGUARD is the number of guard digits used. + + IF (NCALL > 1) THEN + NGUARD = NGRD22 + IF (NGUARD > NDIG) NGUARD = NDIG + ELSE + NGUARD = NGRD52 + IF (NGUARD > NDIG) NGUARD = NDIG + IF (MBASE < 1000 .OR. KROUND /= 1 .OR. KRPERF == 1) THEN + NGUARD = NDIG + 2 + ENDIF + ENDIF + IF (MA(2)*MB(2) < MBASE .AND. NGUARD < 3) NGUARD = 3 + + N1 = NDIG + 1 + +! If MBASE is small, pack the input numbers and use a larger +! base to speed up the calculation. + + IF (MBASE*MBASE <= MXBASE/(4*MBASE)) THEN + IF (NDIGL /= NDIG .OR. MBASEL /= MBASE .OR. NGUARL /= NGUARD) THEN + MBASEL = MBASE + NDIGL = NDIG + NGUARL = NGUARD + DO J = 2, 1000 + MR = MBASE*MBASEL + IF (4*MR > MXBASE) THEN + N21 = J - 1 + NDIG = (NDIGL-1)/N21 + 1 + IF (NDIG < 2) NDIG = 2 + NGRDN = (NDIGL+NGUARD-1)/N21 + 2 - NDIG + IF (NGRDN < 1) NGRDN = 1 + EXIT + ENDIF + MBASE = MR + ENDDO + MBASEN = MBASE + NDIGN = NDIG + ELSE + MBASE = MBASEN + NDIG = NDIGN + ENDIF + MPMA(1) = 0 + MPMB(1) = 0 + L = 2 - N21 + DO J = 2, NDIGL+2-N21, N21 + MT1 = MA(J) + MT2 = MB(J) + DO K = J+1, J+N21-1 + MT1 = MT1*MBASEL + MA(K) + MT2 = MT2*MBASEL + MB(K) + ENDDO + MPMA(2+J/N21) = MT1 + MPMB(2+J/N21) = MT2 + L = J + ENDDO + DO J = 3+L/N21, NDIG+NGRDN+1 + MPMA(J) = 0 + MPMB(J) = 0 + ENDDO + IF (L+N21 <= NDIGL+1) THEN + MT1 = 0 + MT2 = 0 + DO J = L+N21, L+2*N21-1 + IF (J <= NDIGL+1) THEN + MT1 = MT1*MBASEL + MA(J) + MT2 = MT2*MBASEL + MB(J) + ELSE + MT1 = MT1*MBASEL + MT2 = MT2*MBASEL + ENDIF + ENDDO + MPMA(2+(L+N21)/N21) = MT1 + MPMB(2+(L+N21)/N21) = MT2 + ENDIF + CALL FMMPY3(MPMA,MPMB,NGRDN,KSHIFT) + IF (MBASEL == 2 .AND. MBASE < INTMAX) THEN + DO J = 1+NDIG+NGRDN, 2, -1 + KT1 = MWA(J) + KT = 2 + (J-2)*N21 + KT2 = N21 + KT - 1 + DO K = KT, MIN(1+(J-1)*N21,NDIGL+NGUARD+2) + MWA(K) = IBITS(KT1,KT2-K,1) + ENDDO + ENDDO + ELSE + MS = MBASEL**(N21-1) + DO J = 1+NDIG+NGRDN, 2, -1 + MR = MS + MT1 = MWA(J) + DO K = 2+(J-2)*N21, MIN(1+(J-1)*N21,NDIGL+NGUARD+2) + MWA(K) = AINT (MT1/MR) + MT1 = MT1 - MWA(K)*MR + MR = AINT (MR/MBASEL) + ENDDO + ENDDO + ENDIF + KSHIFT = 0 + IF (MWA(2) == 0) KSHIFT = 1 + MWA(1) = MA(1) + MB(1) + NDIG = NDIGL + MBASE = MBASEL + ELSE + CALL FMMPY3(MA,MB,NGUARD,KSHIFT) + ENDIF + +! The multiplication is complete. Round the result, +! move it to MC, and append the correct sign. + + IF ((MAS > 0 .AND. MBS > 0) .OR. (MAS < 0 .AND. MBS < 0)) THEN + JRSIGN = 1 + ELSE + JRSIGN = -1 + ENDIF + MR = 2*MWA(NDIG+2+KSHIFT) + 1 + IF (KROUND == -1 .OR. KROUND == 2) THEN + CALL FMRND(MWA,NDIG,NGUARD,KSHIFT) + ELSE IF (MR >= MBASE) THEN + IF (MR-1 > MBASE .AND. MWA(N1+KSHIFT) < MBASE-1) THEN + IF (KROUND /= 0 .OR. NCALL > 1) THEN + MWA(N1+KSHIFT) = MWA(N1+KSHIFT) + 1 + MWA(N1+1+KSHIFT) = 0 + ENDIF + ELSE + CALL FMRND(MWA,NDIG,NGUARD,KSHIFT) + ENDIF + ENDIF + CALL FMMOVE(MWA,MC) + + IF (KFLAG < 0) THEN + NAMEST(NCALL) = 'FMMPY ' + CALL FMWARN + ENDIF + + MC(-1) = 1 + IF (MAS*MBS < 0 .AND. MC(1) /= MUNKNO .AND. MC(2) /= 0) MC(-1) = -1 + + IF (KACCSW == 1) THEN + MD2B = NINT((NDIG-1)*ALOGM2 + LOG(REAL(ABS(MC(2))+1))/0.69315) + MC(0) = MIN(MACCA,MACCB,MD2B) + ELSE + MC(0) = MIN(MACCA,MACCB) + ENDIF + JRSIGN = JRSSAV + RETURN + END SUBROUTINE FMMPY2 + + SUBROUTINE FMMPY_R1(MA,MB) + +! MA = MA * MB + +! When one of the numbers MA, MB is known to have more zero digits +! (base MBASE) than the other, it is faster if MB is the one with +! more zero digits. + +! This routine performs the trace printing for multiplication. +! FMMPY2_R1 is used to do the arithmetic. + + USE FMVALS + IMPLICIT NONE + + REAL (KIND(1.0D0)) :: MA(-1:LUNPCK),MB(-1:LUNPCK) + + NCALL = NCALL + 1 + IF (NTRACE /= 0) THEN + NAMEST(NCALL) = 'FMMPY ' + CALL FMNTR(2,MA,MB,2,1) + + CALL FMMPY2_R1(MA,MB) + + CALL FMNTR(1,MA,MA,1,1) + ELSE + CALL FMMPY2_R1(MA,MB) + ENDIF + NCALL = NCALL - 1 + RETURN + END SUBROUTINE FMMPY_R1 + + SUBROUTINE FMMPY2_R1(MA,MB) + +! Internal multiplication routine. MA = MA * MB + + USE FMVALS + IMPLICIT NONE + + REAL (KIND(1.0D0)) :: MA(-1:LUNPCK),MB(-1:LUNPCK) + + REAL (KIND(1.0D0)) :: MACCA,MACCB,MAS,MBS,MD2B,MR,MS,MT1,MT2 + INTEGER J,JRSSAV,K,KRESLT,KT,KT1,KT2,KSHIFT,L,N1,NGUARD + + IF (MBLOGS /= MBASE) CALL FMCONS + JRSSAV = JRSIGN + MACCA = MA(0) + MACCB = MB(0) + IF (ABS(MA(1)) > MEXPAB .OR. ABS(MB(1)) > MEXPAB .OR. & + KDEBUG == 1) THEN + CALL FMARGS('FMMPY ',2,MA,MB,KRESLT) + IF (KRESLT /= 0) THEN + NCALL = NCALL + 1 + NAMEST(NCALL) = 'FMMPY ' + CALL FMRSLT(MA,MB,M07,KRESLT) + CALL FMEQ(M07,MA) + JRSIGN = JRSSAV + NCALL = NCALL - 1 + RETURN + ENDIF + ELSE IF (MA(2) == 0 .OR. MB(2) == 0) THEN + CALL FMIM(0,MA) + MA(0) = MIN(MACCA,MACCB) + JRSIGN = JRSSAV + RETURN + ENDIF + KFLAG = 0 + +! Save the sign of MA and MB and then work only with +! positive numbers. + + MAS = MA(-1) + MBS = MB(-1) + +! NGUARD is the number of guard digits used. + + IF (NCALL > 1) THEN + NGUARD = NGRD22 + IF (NGUARD > NDIG) NGUARD = NDIG + ELSE + NGUARD = NGRD52 + IF (NGUARD > NDIG) NGUARD = NDIG + IF (MBASE < 1000 .OR. KROUND /= 1 .OR. KRPERF == 1) THEN + NGUARD = NDIG + 2 + ENDIF + ENDIF + IF (MA(2)*MB(2) < MBASE .AND. NGUARD < 3) NGUARD = 3 + + N1 = NDIG + 1 + +! If MBASE is small, pack the input numbers and use a larger +! base to speed up the calculation. + + IF (MBASE*MBASE <= MXBASE/(4*MBASE)) THEN + IF (NDIGL /= NDIG .OR. MBASEL /= MBASE .OR. NGUARL /= NGUARD) THEN + MBASEL = MBASE + NDIGL = NDIG + NGUARL = NGUARD + DO J = 2, 1000 + MR = MBASE*MBASEL + IF (4*MR > MXBASE) THEN + N21 = J - 1 + NDIG = (NDIGL-1)/N21 + 1 + IF (NDIG < 2) NDIG = 2 + NGRDN = (NDIGL+NGUARD-1)/N21 + 2 - NDIG + IF (NGRDN < 1) NGRDN = 1 + EXIT + ENDIF + MBASE = MR + ENDDO + MBASEN = MBASE + NDIGN = NDIG + ELSE + MBASE = MBASEN + NDIG = NDIGN + ENDIF + MPMA(1) = 0 + MPMB(1) = 0 + L = 2 - N21 + DO J = 2, NDIGL+2-N21, N21 + MT1 = MA(J) + MT2 = MB(J) + DO K = J+1, J+N21-1 + MT1 = MT1*MBASEL + MA(K) + MT2 = MT2*MBASEL + MB(K) + ENDDO + MPMA(2+J/N21) = MT1 + MPMB(2+J/N21) = MT2 + L = J + ENDDO + DO J = 3+L/N21, NDIG+NGRDN+1 + MPMA(J) = 0 + MPMB(J) = 0 + ENDDO + IF (L+N21 <= NDIGL+1) THEN + MT1 = 0 + MT2 = 0 + DO J = L+N21, L+2*N21-1 + IF (J <= NDIGL+1) THEN + MT1 = MT1*MBASEL + MA(J) + MT2 = MT2*MBASEL + MB(J) + ELSE + MT1 = MT1*MBASEL + MT2 = MT2*MBASEL + ENDIF + ENDDO + MPMA(2+(L+N21)/N21) = MT1 + MPMB(2+(L+N21)/N21) = MT2 + ENDIF + CALL FMMPY3(MPMA,MPMB,NGRDN,KSHIFT) + IF (MBASEL == 2 .AND. MBASE < INTMAX) THEN + DO J = 1+NDIG+NGRDN, 2, -1 + KT1 = MWA(J) + KT = 2 + (J-2)*N21 + KT2 = N21 + KT - 1 + DO K = KT, MIN(1+(J-1)*N21,NDIGL+NGUARD+2) + MWA(K) = IBITS(KT1,KT2-K,1) + ENDDO + ENDDO + ELSE + MS = MBASEL**(N21-1) + DO J = 1+NDIG+NGRDN, 2, -1 + MR = MS + MT1 = MWA(J) + DO K = 2+(J-2)*N21, MIN(1+(J-1)*N21,NDIGL+NGUARD+2) + MWA(K) = AINT (MT1/MR) + MT1 = MT1 - MWA(K)*MR + MR = AINT (MR/MBASEL) + ENDDO + ENDDO + ENDIF + KSHIFT = 0 + IF (MWA(2) == 0) KSHIFT = 1 + MWA(1) = MA(1) + MB(1) + NDIG = NDIGL + MBASE = MBASEL + ELSE + CALL FMMPY3(MA,MB,NGUARD,KSHIFT) + ENDIF + +! The multiplication is complete. Round the result, +! move it to MA, and append the correct sign. + + IF ((MAS > 0 .AND. MBS > 0) .OR. (MAS < 0 .AND. MBS < 0)) THEN + JRSIGN = 1 + ELSE + JRSIGN = -1 + ENDIF + MR = 2*MWA(NDIG+2+KSHIFT) + 1 + IF (KROUND == -1 .OR. KROUND == 2) THEN + CALL FMRND(MWA,NDIG,NGUARD,KSHIFT) + ELSE IF (MR >= MBASE) THEN + IF (MR-1 > MBASE .AND. MWA(N1+KSHIFT) < MBASE-1) THEN + IF (KROUND /= 0 .OR. NCALL > 1) THEN + MWA(N1+KSHIFT) = MWA(N1+KSHIFT) + 1 + MWA(N1+1+KSHIFT) = 0 + ENDIF + ELSE + CALL FMRND(MWA,NDIG,NGUARD,KSHIFT) + ENDIF + ENDIF + CALL FMMOVE(MWA,MA) + + IF (KFLAG < 0) THEN + NAMEST(NCALL) = 'FMMPY ' + CALL FMWARN + ENDIF + + MA(-1) = 1 + IF (MAS*MBS < 0 .AND. MA(1) /= MUNKNO .AND. MA(2) /= 0) MA(-1) = -1 + + IF (KACCSW == 1) THEN + MD2B = NINT((NDIG-1)*ALOGM2 + LOG(REAL(ABS(MA(2))+1))/0.69315) + MA(0) = MIN(MACCA,MACCB,MD2B) + ELSE + MA(0) = MIN(MACCA,MACCB) + ENDIF + JRSIGN = JRSSAV + RETURN + END SUBROUTINE FMMPY2_R1 + + SUBROUTINE FMMPY_R2(MA,MB) + +! MB = MA * MB + +! When one of the numbers MA, MB is known to have more zero digits +! (base MBASE) than the other, it is faster if MB is the one with +! more zero digits. + +! This routine performs the trace printing for multiplication. +! FMMPY2_R2 is used to do the arithmetic. + + USE FMVALS + IMPLICIT NONE + + REAL (KIND(1.0D0)) :: MA(-1:LUNPCK),MB(-1:LUNPCK) + + NCALL = NCALL + 1 + IF (NTRACE /= 0) THEN + NAMEST(NCALL) = 'FMMPY ' + CALL FMNTR(2,MA,MB,2,1) + + CALL FMMPY2_R2(MA,MB) + + CALL FMNTR(1,MB,MB,1,1) + ELSE + CALL FMMPY2_R2(MA,MB) + ENDIF + NCALL = NCALL - 1 + RETURN + END SUBROUTINE FMMPY_R2 + + SUBROUTINE FMMPY2_R2(MA,MB) + +! Internal multiplication routine. MB = MA * MB + + USE FMVALS + IMPLICIT NONE + + REAL (KIND(1.0D0)) :: MA(-1:LUNPCK),MB(-1:LUNPCK) + + REAL (KIND(1.0D0)) :: MACCA,MACCB,MAS,MBS,MD2B,MR,MS,MT1,MT2 + INTEGER J,JRSSAV,K,KRESLT,KT,KT1,KT2,KSHIFT,L,N1,NGUARD + + IF (MBLOGS /= MBASE) CALL FMCONS + JRSSAV = JRSIGN + MACCA = MA(0) + MACCB = MB(0) + IF (ABS(MA(1)) > MEXPAB .OR. ABS(MB(1)) > MEXPAB .OR. & + KDEBUG == 1) THEN + CALL FMARGS('FMMPY ',2,MA,MB,KRESLT) + IF (KRESLT /= 0) THEN + NCALL = NCALL + 1 + NAMEST(NCALL) = 'FMMPY ' + CALL FMRSLT(MA,MB,M07,KRESLT) + CALL FMEQ(M07,MB) + JRSIGN = JRSSAV + NCALL = NCALL - 1 + RETURN + ENDIF + ELSE IF (MA(2) == 0 .OR. MB(2) == 0) THEN + CALL FMIM(0,MB) + MB(0) = MIN(MACCA,MACCB) + JRSIGN = JRSSAV + RETURN + ENDIF + KFLAG = 0 + +! Save the sign of MA and MB and then work only with +! positive numbers. + + MAS = MA(-1) + MBS = MB(-1) + +! NGUARD is the number of guard digits used. + + IF (NCALL > 1) THEN + NGUARD = NGRD22 + IF (NGUARD > NDIG) NGUARD = NDIG + ELSE + NGUARD = NGRD52 + IF (NGUARD > NDIG) NGUARD = NDIG + IF (MBASE < 1000 .OR. KROUND /= 1 .OR. KRPERF == 1) THEN + NGUARD = NDIG + 2 + ENDIF + ENDIF + IF (MA(2)*MB(2) < MBASE .AND. NGUARD < 3) NGUARD = 3 + + N1 = NDIG + 1 + +! If MBASE is small, pack the input numbers and use a larger +! base to speed up the calculation. + + IF (MBASE*MBASE <= MXBASE/(4*MBASE)) THEN + IF (NDIGL /= NDIG .OR. MBASEL /= MBASE .OR. NGUARL /= NGUARD) THEN + MBASEL = MBASE + NDIGL = NDIG + NGUARL = NGUARD + DO J = 2, 1000 + MR = MBASE*MBASEL + IF (4*MR > MXBASE) THEN + N21 = J - 1 + NDIG = (NDIGL-1)/N21 + 1 + IF (NDIG < 2) NDIG = 2 + NGRDN = (NDIGL+NGUARD-1)/N21 + 2 - NDIG + IF (NGRDN < 1) NGRDN = 1 + EXIT + ENDIF + MBASE = MR + ENDDO + MBASEN = MBASE + NDIGN = NDIG + ELSE + MBASE = MBASEN + NDIG = NDIGN + ENDIF + MPMA(1) = 0 + MPMB(1) = 0 + L = 2 - N21 + DO J = 2, NDIGL+2-N21, N21 + MT1 = MA(J) + MT2 = MB(J) + DO K = J+1, J+N21-1 + MT1 = MT1*MBASEL + MA(K) + MT2 = MT2*MBASEL + MB(K) + ENDDO + MPMA(2+J/N21) = MT1 + MPMB(2+J/N21) = MT2 + L = J + ENDDO + DO J = 3+L/N21, NDIG+NGRDN+1 + MPMA(J) = 0 + MPMB(J) = 0 + ENDDO + IF (L+N21 <= NDIGL+1) THEN + MT1 = 0 + MT2 = 0 + DO J = L+N21, L+2*N21-1 + IF (J <= NDIGL+1) THEN + MT1 = MT1*MBASEL + MA(J) + MT2 = MT2*MBASEL + MB(J) + ELSE + MT1 = MT1*MBASEL + MT2 = MT2*MBASEL + ENDIF + ENDDO + MPMA(2+(L+N21)/N21) = MT1 + MPMB(2+(L+N21)/N21) = MT2 + ENDIF + CALL FMMPY3(MPMA,MPMB,NGRDN,KSHIFT) + IF (MBASEL == 2 .AND. MBASE < INTMAX) THEN + DO J = 1+NDIG+NGRDN, 2, -1 + KT1 = MWA(J) + KT = 2 + (J-2)*N21 + KT2 = N21 + KT - 1 + DO K = KT, MIN(1+(J-1)*N21,NDIGL+NGUARD+2) + MWA(K) = IBITS(KT1,KT2-K,1) + ENDDO + ENDDO + ELSE + MS = MBASEL**(N21-1) + DO J = 1+NDIG+NGRDN, 2, -1 + MR = MS + MT1 = MWA(J) + DO K = 2+(J-2)*N21, MIN(1+(J-1)*N21,NDIGL+NGUARD+2) + MWA(K) = AINT (MT1/MR) + MT1 = MT1 - MWA(K)*MR + MR = AINT (MR/MBASEL) + ENDDO + ENDDO + ENDIF + KSHIFT = 0 + IF (MWA(2) == 0) KSHIFT = 1 + MWA(1) = MA(1) + MB(1) + NDIG = NDIGL + MBASE = MBASEL + ELSE + CALL FMMPY3(MA,MB,NGUARD,KSHIFT) + ENDIF + +! The multiplication is complete. Round the result, +! move it to MB, and append the correct sign. + + IF ((MAS > 0 .AND. MBS > 0) .OR. (MAS < 0 .AND. MBS < 0)) THEN + JRSIGN = 1 + ELSE + JRSIGN = -1 + ENDIF + MR = 2*MWA(NDIG+2+KSHIFT) + 1 + IF (KROUND == -1 .OR. KROUND == 2) THEN + CALL FMRND(MWA,NDIG,NGUARD,KSHIFT) + ELSE IF (MR >= MBASE) THEN + IF (MR-1 > MBASE .AND. MWA(N1+KSHIFT) < MBASE-1) THEN + IF (KROUND /= 0 .OR. NCALL > 1) THEN + MWA(N1+KSHIFT) = MWA(N1+KSHIFT) + 1 + MWA(N1+1+KSHIFT) = 0 + ENDIF + ELSE + CALL FMRND(MWA,NDIG,NGUARD,KSHIFT) + ENDIF + ENDIF + CALL FMMOVE(MWA,MB) + + IF (KFLAG < 0) THEN + NAMEST(NCALL) = 'FMMPY ' + CALL FMWARN + ENDIF + + MB(-1) = 1 + IF (MAS*MBS < 0 .AND. MB(1) /= MUNKNO .AND. MB(2) /= 0) MB(-1) = -1 + + IF (KACCSW == 1) THEN + MD2B = NINT((NDIG-1)*ALOGM2 + LOG(REAL(ABS(MB(2))+1))/0.69315) + MB(0) = MIN(MACCA,MACCB,MD2B) + ELSE + MB(0) = MIN(MACCA,MACCB) + ENDIF + JRSIGN = JRSSAV + RETURN + END SUBROUTINE FMMPY2_R2 + + SUBROUTINE FMMPY3(MA,MB,NGUARD,KSHIFT) + +! Internal multiplication of MA*MB. The result is returned in MWA. +! Both MA and MB are positive. + +! NGUARD is the number of guard digits that will be used. +! KSHIFT = 1 is returned if a left shift is pending (i.e., MWA(2)=0). +! The shift will be done in FMMOVE. KSHIFT = 0 is returned +! if no shift is pending. + + USE FMVALS + IMPLICIT NONE + + REAL (KIND(1.0D0)) :: MA(-1:LUNPCK),MB(-1:LUNPCK) + INTEGER NGUARD,KSHIFT + + REAL (KIND(1.0D0)) :: MAXMWA,MBJ,MBKJ,MBM1,MBNORM,MK,MKT,MMAX,MT + INTEGER J,JM1,K,KB,KI,KJ,KL,KNZ,KWA,L,N1 + + N1 = NDIG + 1 + MWA(1) = MA(1) + MB(1) + L = N1 + NGUARD + MWA(L+1) = 0 + +! The multiplication loop begins here. + +! MBNORM is the minimum number of digits that can be +! multiplied before normalization is required. +! MAXMWA is an upper bound on the size of values in MWA +! divided by (MBASE-1). It is used to determine +! whether to normalize before the next digit is +! multiplied. + + MBM1 = MBASE - 1 + MBNORM = AINT (MAXINT/(MBM1*MBM1)) + MMAX = INTMAX - MBASE + MMAX = MIN(AINT (MAXINT/MBM1 - MBM1),MMAX) + IF (MBNORM > 1) THEN + MBJ = MB(2) + +! Count the trailing zeros in MA. + + IF (MA(N1) /= 0) THEN + KNZ = N1 + ELSE + DO J = NDIG, 2, -1 + IF (MA(J) /= 0) THEN + KNZ = J + GO TO 110 + ENDIF + ENDDO + ENDIF + + 110 MWA(2) = 0 + DO K = NDIG+2, L + MWA(K) = 0 + ENDDO + +! (Inner Loop) + + DO K = 2, N1 + MWA(K+1) = MA(K)*MBJ + ENDDO + MAXMWA = MBJ + DO J = 3, N1 + MBJ = MB(J) + IF (MBJ /= 0) THEN + MAXMWA = MAXMWA + MBJ + JM1 = J - 1 + KL = MIN(KNZ,L-JM1) + +! Major (Inner Loop) + + DO K = J+1, J+KL-1 + MWA(K) = MWA(K) + MA(K-JM1)*MBJ + ENDDO + ENDIF + + IF (MAXMWA > MMAX) THEN + MAXMWA = 0 + +! Here normalization is only required for the +! range of digits currently changing in MWA. + + DO KB = JM1+KL, JM1+2, -1 + MKT = INT (MWA(KB)/MBASE) + MWA(KB-1) = MWA(KB-1) + MKT + MWA(KB) = MWA(KB) - MKT*MBASE + ENDDO + ENDIF + ENDDO + +! Perform the final normalization. (Inner Loop) + + DO KB = L, 3, -1 + MKT = INT (MWA(KB)/MBASE) + MWA(KB-1) = MWA(KB-1) + MKT + MWA(KB) = MWA(KB) - MKT*MBASE + ENDDO + + ELSE + +! If normalization must be done for each digit, combine +! the two loops and normalize as the digits are multiplied. + + DO J = 2, L + MWA(J) = 0 + ENDDO + KJ = NDIG + 2 + DO J = 2, N1 + KJ = KJ - 1 + MBKJ = MB(KJ) + IF (MBKJ == 0) CYCLE + KL = L - KJ + 1 + IF (KL > N1) KL = N1 + KI = KL + 2 + KWA = KL+ KJ + 1 + MK = 0 + DO K = 2, KL + MT = MA(KI-K)*MBKJ + MWA(KWA-K) + MK + MK = INT (MT/MBASE) + MWA(KWA-K) = MT - MBASE*MK + ENDDO + MWA(KWA-KL-1) = MK + ENDDO + + ENDIF + +! Set KSHIFT = 1 if a shift left is necessary. + + IF (MWA(2) == 0) THEN + KSHIFT = 1 + RETURN + ELSE + KSHIFT = 0 + RETURN + ENDIF + + END SUBROUTINE FMMPY3 + + SUBROUTINE FMMPYD(MA,MB,MC,MD,ME) + +! Double multiplication routine. MD = MA * MB, ME = MA * MC + +! It is usually slightly faster to do two multiplications that +! have a common factor with one call. + + USE FMVALS + IMPLICIT NONE + + REAL (KIND(1.0D0)) :: MA(-1:LUNPCK),MB(-1:LUNPCK),MC(-1:LUNPCK), & + MD(-1:LUNPCK),ME(-1:LUNPCK) + + REAL (KIND(1.0D0)) :: MACCA,MACCB,MACCC,MAS,MAXMWA,MBS,MBJ,MBKJ, & + MBM1,MBNORM,MCJ,MCKJ,MCS,MD2B,MKB,MKC,MKT, & + MMAX,MR,MT,MTEMP + INTEGER J,JM1,JRSSAV,K,KB,KI,KJ,KL,KNZ,KOVUN,KSHIFT,KWA,L,N1,NGUARD + + NCALL = NCALL + 1 + JRSSAV = JRSIGN + IF (NTRACE /= 0) THEN + NAMEST(NCALL) = 'FMMPYD' + CALL FMNTR(2,MA,MB,2,1) + IF (ABS(NTRACE) >= 2 .AND. NCALL <= LVLTRC) THEN + IF (NTRACE < 0) THEN + CALL FMNTRJ(MC,NDIG) + ELSE + CALL FMPRNT(MC) + ENDIF + ENDIF + ENDIF + + IF (MBLOGS /= MBASE) CALL FMCONS + MACCA = MA(0) + MACCB = MB(0) + MACCC = MC(0) + IF (ABS(MA(1)) > MEXPAB .OR. ABS(MB(1)) > MEXPAB .OR. & + ABS(MC(1)) > MEXPAB .OR. MBASE*MBASE <= MXBASE/(4*MBASE)) THEN + KOVUN = 0 + IF (MA(1) == MEXPOV .OR. MA(1) == MEXPUN .OR. & + MB(1) == MEXPOV .OR. MB(1) == MEXPUN .OR. & + MC(1) == MEXPOV .OR. MC(1) == MEXPUN) KOVUN = 1 + IF (MA(1) == MUNKNO .OR. MB(1) == MUNKNO .OR. & + MC(1) == MUNKNO) KOVUN = 2 + NCALL = NCALL + 1 + CALL FMMPY2(MA,MB,MWD) + KB = KFLAG + CALL FMMPY2(MA,MC,ME) + NCALL = NCALL - 1 + IF (((KFLAG < 0 .OR. KB < 0) .AND. KOVUN == 0) .OR. & + ((KFLAG == -4 .OR. KB == -4) .AND. KOVUN == 1)) THEN + IF (KFLAG == -4 .OR. KB == -4) THEN + KFLAG = -4 + ELSE IF (KFLAG == -5 .OR. KB == -5) THEN + KFLAG = -5 + ELSE + KFLAG = MIN(KFLAG,KB) + ENDIF + NAMEST(NCALL) = 'FMMPYD' + CALL FMWARN + ENDIF + CALL FMEQ(MWD,MD) + GO TO 120 + ENDIF + IF (MA(2) == 0) THEN + CALL FMIM(0,MD) + MD(0) = MIN(MACCA,MACCB) + CALL FMIM(0,ME) + ME(0) = MIN(MACCA,MACCC) + GO TO 120 + ENDIF + IF (MB(2) == 0) THEN + CALL FMMPY2(MA,MC,ME) + CALL FMIM(0,MD) + MD(0) = MIN(MACCA,MACCB) + GO TO 120 + ENDIF + IF (MC(2) == 0) THEN + CALL FMMPY2(MA,MB,MD) + CALL FMIM(0,ME) + ME(0) = MIN(MACCA,MACCC) + GO TO 120 + ENDIF + KFLAG = 0 + +! NGUARD is the number of guard digits used. + + IF (NCALL > 1) THEN + NGUARD = NGRD22 + IF (NGUARD > NDIG) NGUARD = NDIG + ELSE + NGUARD = NGRD52 + IF (NGUARD > NDIG) NGUARD = NDIG + IF (MBASE < 1000 .OR. KROUND /= 1 .OR. KRPERF == 1) THEN + NGUARD = NDIG + 10 + ENDIF + ENDIF + IF ((MA(2)*MB(2) < MBASE .OR. MA(2)*MC(2) < MBASE) & + .AND. NGUARD < 3) NGUARD = 3 + +! Save the sign of MA, MB, and MC and then +! work only with positive numbers. + + MAS = MA(-1) + MBS = MB(-1) + MCS = MC(-1) + + N1 = NDIG + 1 + MWA(1) = MA(1) + MB(1) + MWD(1) = MA(1) + MC(1) + L = NDIG + 1 + NGUARD + MWA(L+1) = 0 + MWD(L+1) = 0 + +! The multiplication loop begins here. + +! MBNORM is the minimum number of digits that can be +! multiplied before normalization is required. +! MAXMWA is an upper bound on the size of values in MWA +! divided by (MBASE-1). It is used to determine +! whether to normalize before the next digit is +! multiplied. + + MBM1 = MBASE - 1 + MBNORM = AINT (MAXINT/(MBM1*MBM1)) + MMAX = INTMAX - MBASE + MMAX = MIN(AINT (MAXINT/MBM1 - MBM1),MMAX) + IF (MBNORM > 1) THEN + MBJ = MB(2) + MCJ = MC(2) + +! Count the trailing zeros in MA. + + IF (MA(N1) /= 0) THEN + KNZ = N1 + ELSE + DO J = NDIG, 2, -1 + IF (MA(J) /= 0) THEN + KNZ = J + GO TO 110 + ENDIF + ENDDO + ENDIF + + 110 MWA(2) = 0 + MWD(2) = 0 + DO K = NDIG+2, L + MWA(K) = 0 + MWD(K) = 0 + ENDDO + +! (Inner Loop) + + DO K = 2, N1 + MTEMP = MA(K) + MWA(K+1) = MTEMP*MBJ + MWD(K+1) = MTEMP*MCJ + ENDDO + IF (MBJ > MCJ) THEN + MAXMWA = MBJ + ELSE + MAXMWA = MCJ + ENDIF + DO J = 3, N1 + MBJ = MB(J) + MCJ = MC(J) + IF (MBJ > MCJ) THEN + MAXMWA = MAXMWA + MBJ + ELSE + MAXMWA = MAXMWA + MCJ + ENDIF + JM1 = J - 1 + KL = MIN(KNZ,L-JM1) + +! Major (Inner Loop) + + DO K = J+1, J+KL-1 + MTEMP = MA(K-JM1) + MWA(K) = MWA(K) + MTEMP*MBJ + MWD(K) = MWD(K) + MTEMP*MCJ + ENDDO + + IF (MAXMWA > MMAX) THEN + MAXMWA = 0 + +! Here normalization is only required for the +! range of digits currently changing in MWA. + + DO KB = JM1+KL, JM1+2, -1 + MKT = INT (MWA(KB)/MBASE) + MWA(KB-1) = MWA(KB-1) + MKT + MWA(KB) = MWA(KB) - MKT*MBASE + MKT = INT (MWD(KB)/MBASE) + MWD(KB-1) = MWD(KB-1) + MKT + MWD(KB) = MWD(KB) - MKT*MBASE + ENDDO + ENDIF + ENDDO + +! Perform the final normalization. (Inner Loop) + + DO KB = L, 3, -1 + MKT = INT (MWA(KB)/MBASE) + MWA(KB-1) = MWA(KB-1) + MKT + MWA(KB) = MWA(KB) - MKT*MBASE + MKT = INT (MWD(KB)/MBASE) + MWD(KB-1) = MWD(KB-1) + MKT + MWD(KB) = MWD(KB) - MKT*MBASE + ENDDO + + ELSE + +! If normalization must be done for each digit, combine +! the two loops and normalize as the digits are multiplied. + + DO J = 2, L + MWA(J) = 0 + MWD(J) = 0 + ENDDO + KJ = NDIG + 2 + DO J = 2, N1 + KJ = KJ - 1 + MBKJ = MB(KJ) + MCKJ = MC(KJ) + KL = L - KJ + 1 + IF (KL > N1) KL = N1 + KI = KL + 2 + KWA = KL+ KJ + 1 + MKB = 0 + MKC = 0 + DO K = 2, KL + MT = MA(KI-K)*MBKJ + MWA(KWA-K) + MKB + MKB = INT (MT/MBASE) + MWA(KWA-K) = MT - MBASE*MKB + MT = MA(KI-K)*MCKJ + MWD(KWA-K) + MKC + MKC = INT (MT/MBASE) + MWD(KWA-K) = MT - MBASE*MKC + ENDDO + MWA(KWA-KL-1) = MKB + MWD(KWA-KL-1) = MKC + ENDDO + + ENDIF + +! Set KSHIFT = 1 if a shift left is necessary. + + IF (MWA(2) == 0) THEN + KSHIFT = 1 + ELSE + KSHIFT = 0 + ENDIF + +! The multiplications are complete. + + IF ((MAS > 0 .AND. MBS > 0) .OR. (MAS < 0 .AND. MBS < 0)) THEN + JRSIGN = 1 + ELSE + JRSIGN = -1 + ENDIF + MR = 2*MWA(NDIG+2+KSHIFT) + 1 + IF (KROUND == -1 .OR. KROUND == 2) THEN + CALL FMRND(MWA,NDIG,NGUARD,KSHIFT) + ELSE IF (MR >= MBASE) THEN + IF (MR-1 > MBASE .AND. MWA(N1+KSHIFT) < MBASE-1) THEN + IF (KROUND /= 0 .OR. NCALL > 1) THEN + MWA(N1+KSHIFT) = MWA(N1+KSHIFT) + 1 + MWA(N1+1+KSHIFT) = 0 + ENDIF + ELSE + CALL FMRND(MWA,NDIG,NGUARD,KSHIFT) + ENDIF + ENDIF + CALL FMMOVE(MWA,MD) + + IF ((MAS > 0 .AND. MCS > 0) .OR. (MAS < 0 .AND. MCS < 0)) THEN + JRSIGN = 1 + ELSE + JRSIGN = -1 + ENDIF + IF (MWD(2) == 0) THEN + KSHIFT = 1 + ELSE + KSHIFT = 0 + ENDIF + MR = 2*MWD(NDIG+2+KSHIFT) + 1 + IF (KROUND == -1 .OR. KROUND == 2) THEN + CALL FMRND(MWD,NDIG,NGUARD,KSHIFT) + ELSE IF (MR >= MBASE) THEN + IF (MR-1 > MBASE .AND. MWD(N1+KSHIFT) < MBASE-1) THEN + IF (KROUND /= 0 .OR. NCALL > 1) THEN + MWD(N1+KSHIFT) = MWD(N1+KSHIFT) + 1 + MWD(N1+1+KSHIFT) = 0 + ENDIF + ELSE + CALL FMRND(MWD,NDIG,NGUARD,KSHIFT) + ENDIF + ENDIF + CALL FMMOVE(MWD,ME) + + IF (KFLAG < 0) THEN + NAMEST(NCALL) = 'FMMPYD' + CALL FMWARN + ENDIF + + MD(-1) = 1 + IF (MAS*MBS < 0 .AND. MD(1) /= MUNKNO .AND. MD(2) /= 0) MD(-1) = -1 + ME(-1) = 1 + IF (MAS*MCS < 0 .AND. ME(1) /= MUNKNO .AND. ME(2) /= 0) ME(-1) = -1 + + IF (KACCSW == 1) THEN + MD2B = NINT((NDIG-1)*ALOGM2 + LOG(REAL(ABS(MD(2))+1))/0.69315) + MD(0) = MIN(MACCA,MACCB,MD2B) + MD2B = NINT((NDIG-1)*ALOGM2 + LOG(REAL(ABS(ME(2))+1))/0.69315) + ME(0) = MIN(MACCA,MACCC,MD2B) + ELSE + MD(0) = MIN(MACCA,MACCB) + ME(0) = MIN(MACCA,MACCC) + ENDIF + + 120 IF (NTRACE /= 0) THEN + CALL FMNTR(1,MD,MD,1,1) + IF (ABS(NTRACE) >= 1 .AND. NCALL <= LVLTRC) THEN + IF (NTRACE < 0) THEN + CALL FMNTRJ(ME,NDIG) + ELSE + CALL FMPRNT(ME) + ENDIF + ENDIF + ENDIF + NCALL = NCALL - 1 + JRSIGN = JRSSAV + RETURN + END SUBROUTINE FMMPYD + + SUBROUTINE FMMPYE(MA,MB,MC,MD,ME,MF,MG) + +! Triple multiplication routine. + +! ME = MA * MB, MF = MA * MC, MG = MA * MD + +! It is usually slightly faster to do three multiplications that +! have a common factor with one call. + + USE FMVALS + IMPLICIT NONE + + REAL (KIND(1.0D0)) :: MA(-1:LUNPCK),MB(-1:LUNPCK),MC(-1:LUNPCK), & + MD(-1:LUNPCK),ME(-1:LUNPCK),MF(-1:LUNPCK), & + MG(-1:LUNPCK) + + REAL (KIND(1.0D0)) :: MACCA,MACCB,MACCC,MACCD,MAS,MAXJ,MAXMWA,MBS,MBJ, & + MBKJ,MBM1,MBNORM,MCJ,MCKJ,MCS,MD2B,MDJ,MDKJ,MDS, & + MKB,MKC,MKD,MKT,MMAX,MR,MT,MTEMP + INTEGER J,JM1,JRSSAV,K,KB,KI,KJ,KL,KNZ,KOVUN,KSHIFT,KWA,L,N1,NGUARD + + NCALL = NCALL + 1 + JRSSAV = JRSIGN + IF (NTRACE /= 0) THEN + NAMEST(NCALL) = 'FMMPYE' + CALL FMNTR(2,MA,MB,2,1) + IF (ABS(NTRACE) >= 2 .AND. NCALL <= LVLTRC) THEN + IF (NTRACE < 0) THEN + CALL FMNTRJ(MC,NDIG) + CALL FMNTRJ(MD,NDIG) + ELSE + CALL FMPRNT(MC) + CALL FMPRNT(MD) + ENDIF + ENDIF + ENDIF + + IF (MBLOGS /= MBASE) CALL FMCONS + MACCA = MA(0) + MACCB = MB(0) + MACCC = MC(0) + MACCD = MD(0) + IF (ABS(MA(1)) > MEXPAB .OR. ABS(MB(1)) > MEXPAB .OR. & + ABS(MC(1)) > MEXPAB .OR. ABS(MD(1)) > MEXPAB .OR. & + MBASE*MBASE <= MXBASE/(4*MBASE)) THEN + KOVUN = 0 + IF (MA(1) == MEXPOV .OR. MA(1) == MEXPUN .OR. & + MB(1) == MEXPOV .OR. MB(1) == MEXPUN .OR. & + MC(1) == MEXPOV .OR. MC(1) == MEXPUN .OR. & + MD(1) == MEXPOV .OR. MD(1) == MEXPUN) KOVUN = 1 + IF (MA(1) == MUNKNO .OR. MB(1) == MUNKNO .OR. & + MC(1) == MUNKNO .OR. MD(1) == MUNKNO) KOVUN = 2 + NCALL = NCALL + 1 + CALL FMMPY2(MA,MB,MWD) + KB = KFLAG + CALL FMMPY2(MA,MC,MWE) + KJ = KFLAG + CALL FMMPY2(MA,MD,MG) + NCALL = NCALL - 1 + IF (((KFLAG < 0 .OR. KB < 0 .OR. KJ < 0) .AND. KOVUN == 0) & + .OR. ((KFLAG == -4 .OR. KB == -4 .OR. KJ == -4) .AND. & + KOVUN == 1)) THEN + IF (KFLAG == -4 .OR. KB == -4 .OR. KJ == -4) THEN + KFLAG = -4 + ELSE IF (KFLAG == -5 .OR. KB == -5 .OR. KJ == -5) THEN + KFLAG = -5 + ELSE + KFLAG = MIN(KFLAG,KB,KJ) + ENDIF + NAMEST(NCALL) = 'FMMPYE' + CALL FMWARN + ENDIF + CALL FMEQ(MWD,ME) + CALL FMEQ(MWE,MF) + GO TO 120 + ENDIF + IF (MA(2) == 0) THEN + CALL FMIM(0,ME) + ME(0) = MIN(MACCA,MACCB) + CALL FMIM(0,MF) + MF(0) = MIN(MACCA,MACCC) + CALL FMIM(0,MG) + MG(0) = MIN(MACCA,MACCD) + GO TO 120 + ENDIF + IF (MB(2) == 0 .OR. MC(2) == 0 .OR. MD(2) == 0) THEN + CALL FMMPY2(MA,MB,MWD) + CALL FMMPY2(MA,MC,MWE) + CALL FMMPY2(MA,MD,MG) + CALL FMEQ(MWD,ME) + CALL FMEQ(MWE,MF) + GO TO 120 + ENDIF + KFLAG = 0 + +! NGUARD is the number of guard digits used. + + IF (NCALL > 1) THEN + NGUARD = NGRD22 + IF (NGUARD > NDIG) NGUARD = NDIG + ELSE + NGUARD = NGRD52 + IF (NGUARD > NDIG) NGUARD = NDIG + IF (MBASE < 1000 .OR. KROUND /= 1 .OR. KRPERF == 1) THEN + NGUARD = NDIG + 10 + ENDIF + ENDIF + IF ((MA(2)*MB(2) < MBASE .OR. MA(2)*MC(2) < MBASE .OR. & + MA(2)*MD(2) < MBASE) .AND. NGUARD < 3) NGUARD = 3 + +! Save the signs and then work only with positive numbers. + + MAS = MA(-1) + MBS = MB(-1) + MCS = MC(-1) + MDS = MD(-1) + + N1 = NDIG + 1 + MWA(1) = MA(1) + MB(1) + MWD(1) = MA(1) + MC(1) + MWE(1) = MA(1) + MD(1) + L = NDIG + 1 + NGUARD + MWA(L+1) = 0 + MWD(L+1) = 0 + MWE(L+1) = 0 + +! The multiplication loop begins here. + +! MBNORM is the minimum number of digits that can be +! multiplied before normalization is required. +! MAXMWA is an upper bound on the size of values in MWA +! divided by (MBASE-1). It is used to determine +! whether to normalize before the next digit is +! multiplied. + + MBM1 = MBASE - 1 + MBNORM = AINT (MAXINT/(MBM1*MBM1)) + MMAX = INTMAX - MBASE + MMAX = MIN(AINT (MAXINT/MBM1 - MBM1),MMAX) + IF (MBNORM > 1) THEN + MBJ = MB(2) + MCJ = MC(2) + MDJ = MD(2) + +! Count the trailing zeros in MA. + + IF (MA(N1) /= 0) THEN + KNZ = N1 + ELSE + DO J = NDIG, 2, -1 + IF (MA(J) /= 0) THEN + KNZ = J + GO TO 110 + ENDIF + ENDDO + ENDIF + + 110 MWA(2) = 0 + MWD(2) = 0 + MWE(2) = 0 + DO K = NDIG+2, L + MWA(K) = 0 + MWD(K) = 0 + MWE(K) = 0 + ENDDO + +! (Inner Loop) + + DO K = 2, N1 + MTEMP = MA(K) + MWA(K+1) = MTEMP*MBJ + MWD(K+1) = MTEMP*MCJ + MWE(K+1) = MTEMP*MDJ + ENDDO + MAXMWA = MBJ + IF (MCJ > MAXMWA) MAXMWA = MCJ + IF (MDJ > MAXMWA) MAXMWA = MDJ + DO J = 3, N1 + MBJ = MB(J) + MCJ = MC(J) + MDJ = MD(J) + MAXJ = MBJ + IF (MCJ > MAXJ) MAXJ = MCJ + IF (MDJ > MAXJ) MAXJ = MDJ + MAXMWA = MAXMWA + MAXJ + JM1 = J - 1 + KL = MIN(KNZ,L-JM1) + +! Major (Inner Loop) + + DO K = J+1, J+KL-1 + MTEMP = MA(K-JM1) + MWA(K) = MWA(K) + MTEMP*MBJ + MWD(K) = MWD(K) + MTEMP*MCJ + MWE(K) = MWE(K) + MTEMP*MDJ + ENDDO + + IF (MAXMWA > MMAX) THEN + MAXMWA = 0 + +! Here normalization is only required for the +! range of digits currently changing in MWA. + + DO KB = JM1+KL, JM1+2, -1 + MKT = INT (MWA(KB)/MBASE) + MWA(KB-1) = MWA(KB-1) + MKT + MWA(KB) = MWA(KB) - MKT*MBASE + MKT = INT (MWD(KB)/MBASE) + MWD(KB-1) = MWD(KB-1) + MKT + MWD(KB) = MWD(KB) - MKT*MBASE + MKT = INT (MWE(KB)/MBASE) + MWE(KB-1) = MWE(KB-1) + MKT + MWE(KB) = MWE(KB) - MKT*MBASE + ENDDO + ENDIF + ENDDO + +! Perform the final normalization. (Inner Loop) + + DO KB = L, 3, -1 + MKT = INT (MWA(KB)/MBASE) + MWA(KB-1) = MWA(KB-1) + MKT + MWA(KB) = MWA(KB) - MKT*MBASE + MKT = INT (MWD(KB)/MBASE) + MWD(KB-1) = MWD(KB-1) + MKT + MWD(KB) = MWD(KB) - MKT*MBASE + MKT = INT (MWE(KB)/MBASE) + MWE(KB-1) = MWE(KB-1) + MKT + MWE(KB) = MWE(KB) - MKT*MBASE + ENDDO + + ELSE + +! If normalization must be done for each digit, combine +! the two loops and normalize as the digits are multiplied. + + DO J = 2, L + MWA(J) = 0 + MWD(J) = 0 + MWE(J) = 0 + ENDDO + KJ = NDIG + 2 + DO J = 2, N1 + KJ = KJ - 1 + MBKJ = MB(KJ) + MCKJ = MC(KJ) + MDKJ = MD(KJ) + KL = L - KJ + 1 + IF (KL > N1) KL = N1 + KI = KL + 2 + KWA = KL+ KJ + 1 + MKB = 0 + MKC = 0 + MKD = 0 + DO K = 2, KL + MT = MA(KI-K)*MBKJ + MWA(KWA-K) + MKB + MKB = INT (MT/MBASE) + MWA(KWA-K) = MT - MBASE*MKB + MT = MA(KI-K)*MCKJ + MWD(KWA-K) + MKC + MKC = INT (MT/MBASE) + MWD(KWA-K) = MT - MBASE*MKC + MT = MA(KI-K)*MDKJ + MWE(KWA-K) + MKD + MKD = INT (MT/MBASE) + MWE(KWA-K) = MT - MBASE*MKD + ENDDO + MWA(KWA-KL-1) = MKB + MWD(KWA-KL-1) = MKC + MWE(KWA-KL-1) = MKD + ENDDO + + ENDIF + +! Set KSHIFT = 1 if a shift left is necessary. + + IF (MWA(2) == 0) THEN + KSHIFT = 1 + ELSE + KSHIFT = 0 + ENDIF + +! The multiplications are complete. + + IF ((MAS > 0 .AND. MBS > 0) .OR. (MAS < 0 .AND. MBS < 0)) THEN + JRSIGN = 1 + ELSE + JRSIGN = -1 + ENDIF + MR = 2*MWA(NDIG+2+KSHIFT) + 1 + IF (KROUND == -1 .OR. KROUND == 2) THEN + CALL FMRND(MWA,NDIG,NGUARD,KSHIFT) + ELSE IF (MR >= MBASE) THEN + IF (MR-1 > MBASE .AND. MWA(N1+KSHIFT) < MBASE-1) THEN + IF (KROUND /= 0 .OR. NCALL > 1) THEN + MWA(N1+KSHIFT) = MWA(N1+KSHIFT) + 1 + MWA(N1+1+KSHIFT) = 0 + ENDIF + ELSE + CALL FMRND(MWA,NDIG,NGUARD,KSHIFT) + ENDIF + ENDIF + CALL FMMOVE(MWA,ME) + + IF ((MAS > 0 .AND. MCS > 0) .OR. (MAS < 0 .AND. MCS < 0)) THEN + JRSIGN = 1 + ELSE + JRSIGN = -1 + ENDIF + IF (MWD(2) == 0) THEN + KSHIFT = 1 + ELSE + KSHIFT = 0 + ENDIF + MR = 2*MWD(NDIG+2+KSHIFT) + 1 + IF (KROUND == -1 .OR. KROUND == 2) THEN + CALL FMRND(MWD,NDIG,NGUARD,KSHIFT) + ELSE IF (MR >= MBASE) THEN + IF (MR-1 > MBASE .AND. MWD(N1+KSHIFT) < MBASE-1) THEN + IF (KROUND /= 0 .OR. NCALL > 1) THEN + MWD(N1+KSHIFT) = MWD(N1+KSHIFT) + 1 + MWD(N1+1+KSHIFT) = 0 + ENDIF + ELSE + CALL FMRND(MWD,NDIG,NGUARD,KSHIFT) + ENDIF + ENDIF + CALL FMMOVE(MWD,MF) + + IF ((MAS > 0 .AND. MDS > 0) .OR. (MAS < 0 .AND. MDS < 0)) THEN + JRSIGN = 1 + ELSE + JRSIGN = -1 + ENDIF + IF (MWE(2) == 0) THEN + KSHIFT = 1 + ELSE + KSHIFT = 0 + ENDIF + MR = 2*MWE(NDIG+2+KSHIFT) + 1 + IF (KROUND == -1 .OR. KROUND == 2) THEN + CALL FMRND(MWE,NDIG,NGUARD,KSHIFT) + ELSE IF (MR >= MBASE) THEN + IF (MR-1 > MBASE .AND. MWE(N1+KSHIFT) < MBASE-1) THEN + IF (KROUND /= 0 .OR. NCALL > 1) THEN + MWE(N1+KSHIFT) = MWE(N1+KSHIFT) + 1 + MWE(N1+1+KSHIFT) = 0 + ENDIF + ELSE + CALL FMRND(MWE,NDIG,NGUARD,KSHIFT) + ENDIF + ENDIF + CALL FMMOVE(MWE,MG) + + IF (KFLAG < 0) THEN + NAMEST(NCALL) = 'FMMPYE' + CALL FMWARN + ENDIF + + ME(-1) = 1 + IF (MAS*MBS < 0 .AND. ME(1) /= MUNKNO .AND. ME(2) /= 0) ME(-1) = -1 + MF(-1) = 1 + IF (MAS*MCS < 0 .AND. MF(1) /= MUNKNO .AND. MF(2) /= 0) MF(-1) = -1 + MG(-1) = 1 + IF (MAS*MDS < 0 .AND. MG(1) /= MUNKNO .AND. MG(2) /= 0) MG(-1) = -1 + + IF (KACCSW == 1) THEN + MD2B = NINT((NDIG-1)*ALOGM2 + LOG(REAL(ABS(ME(2))+1))/0.69315) + ME(0) = MIN(MACCA,MACCB,MD2B) + MD2B = NINT((NDIG-1)*ALOGM2 + LOG(REAL(ABS(MF(2))+1))/0.69315) + MF(0) = MIN(MACCA,MACCC,MD2B) + MD2B = NINT((NDIG-1)*ALOGM2 + LOG(REAL(ABS(MG(2))+1))/0.69315) + MG(0) = MIN(MACCA,MACCD,MD2B) + ELSE + ME(0) = MIN(MACCA,MACCB) + MF(0) = MIN(MACCA,MACCC) + MG(0) = MIN(MACCA,MACCD) + ENDIF + + 120 IF (NTRACE /= 0) THEN + CALL FMNTR(1,ME,ME,1,1) + IF (ABS(NTRACE) >= 1 .AND. NCALL <= LVLTRC) THEN + IF (NTRACE < 0) THEN + CALL FMNTRJ(MF,NDIG) + CALL FMNTRJ(MG,NDIG) + ELSE + CALL FMPRNT(MF) + CALL FMPRNT(MG) + ENDIF + ENDIF + ENDIF + NCALL = NCALL - 1 + JRSIGN = JRSSAV + RETURN + END SUBROUTINE FMMPYE + + SUBROUTINE FMMPYI(MA,IVAL,MB) + +! MB = MA * IVAL + +! Multiply FM number MA by one word integer IVAL. + +! This routine is faster than FMMPY when IVAL*MBASE is a +! one word integer. + + USE FMVALS + IMPLICIT NONE + + REAL (KIND(1.0D0)) :: MA(-1:LUNPCK),MB(-1:LUNPCK) + INTEGER IVAL + REAL (KIND(1.0D0)) :: MACCA,MAS,MCARRY,MD2B,MKT,MLR,MVAL + INTEGER J,JRSSAV,KA,KB,KC,KSHIFT,N1,NGUARD,NMVAL,NV2 + + IF (MBLOGS /= MBASE) CALL FMCONS + JRSSAV = JRSIGN + MACCA = MA(0) + NCALL = NCALL + 1 + IF (NTRACE /= 0) THEN + NAMEST(NCALL) = 'FMMPYI' + CALL FMNTR(2,MA,MA,1,1) + CALL FMNTRI(2,IVAL,0) + ENDIF + KFLAG = 0 + N1 = NDIG + 1 + +! Check for special cases. + + IF (MA(2) == 0) THEN + CALL FMEQ(MA,MB) + IF (NTRACE /= 0) THEN + CALL FMNTR(1,MB,MB,1,1) + ENDIF + NCALL = NCALL - 1 + JRSIGN = JRSSAV + RETURN + ENDIF + + IF (ABS(MA(1)) < MEXPOV .AND. ABS(IVAL) > 1) GO TO 110 + + IF (MA(1) == MUNKNO) THEN + CALL FMST2M('UNKNOWN',MB) + KFLAG = -4 + IF (NTRACE /= 0) THEN + CALL FMNTR(1,MB,MB,1,1) + ENDIF + NCALL = NCALL - 1 + JRSIGN = JRSSAV + RETURN + ENDIF + + IF (IVAL == 0) THEN + CALL FMIM(0,MB) + IF (NTRACE /= 0) THEN + CALL FMNTR(1,MB,MB,1,1) + ENDIF + NCALL = NCALL - 1 + JRSIGN = JRSSAV + RETURN + ENDIF + + IF (ABS(IVAL) == 1) THEN + DO J = -1, N1 + MB(J) = MA(J) + ENDDO + IF (MA(1) == MEXPOV) KFLAG = -5 + IF (MA(1) == MEXPUN) KFLAG = -6 + MB(-1) = MA(-1)*IVAL + IF (NTRACE /= 0) THEN + CALL FMNTR(1,MB,MB,1,1) + ENDIF + NCALL = NCALL - 1 + JRSIGN = JRSSAV + RETURN + ENDIF + + IF (MA(1) == MEXPOV) THEN + MAS = MA(-1) + KFLAG = -5 + CALL FMST2M('OVERFLOW',MB) + IF ((MAS < 0 .AND. IVAL > 0) .OR. & + (MAS > 0 .AND. IVAL < 0)) MB(-1) = -1 + IF (NTRACE /= 0) THEN + CALL FMNTR(1,MB,MB,1,1) + ENDIF + NCALL = NCALL - 1 + JRSIGN = JRSSAV + RETURN + ENDIF + + IF (MA(1) == MEXPUN) THEN + NAMEST(NCALL) = 'FMMPYI' + KFLAG = -4 + CALL FMWARN + CALL FMST2M('UNKNOWN',MB) + IF (NTRACE /= 0) THEN + CALL FMNTR(1,MB,MB,1,1) + ENDIF + NCALL = NCALL - 1 + JRSIGN = JRSSAV + RETURN + ENDIF + +! Work with positive numbers. + + 110 MAS = MA(-1) + MVAL = ABS(IVAL) + NMVAL = INT(MVAL) + NV2 = NMVAL - 1 + +! To leave room for the normalization, shift the product +! to the right KSHIFT places in MWA. + + KSHIFT = INT((LOG(DBLE(MA(2)+1)*DBLE(MVAL)))/DLOGMB) + +! If IVAL is too big use FMMPY. + + IF (KSHIFT > NDIG .OR. MVAL > MAXINT/MBASE .OR. & + NMVAL /= ABS(IVAL) .OR. NV2 /= ABS(IVAL)-1) THEN + CALL FMIM(IVAL,M01) + CALL FMMPY2(MA,M01,MB) + IF (NTRACE /= 0) THEN + CALL FMNTR(1,MB,MB,1,1) + ENDIF + NCALL = NCALL - 1 + JRSIGN = JRSSAV + RETURN + ENDIF + + MWA(1) = MA(1) + KSHIFT + KA = 2 + KSHIFT + KB = N1 + KSHIFT + KC = NDIG + 5 + DO J = KB, KC + MWA(J) = 0 + ENDDO + + MCARRY = 0 + +! This is the main multiplication loop. + + DO J = KB, KA, -1 + MKT = MA(J-KSHIFT)*MVAL + MCARRY + MCARRY = INT (MKT/MBASE) + MWA(J) = MKT - MCARRY*MBASE + ENDDO + +! Resolve the final carry. + + DO J = KA-1, 2, -1 + MKT = INT (MCARRY/MBASE) + MWA(J) = MCARRY - MKT*MBASE + MCARRY = MKT + ENDDO + +! Now the first significant digit in the product is in +! MWA(2) or MWA(3). Round the result and move it to MB. + + IF ((MAS > 0 .AND. IVAL > 0) .OR. (MAS < 0 .AND. IVAL < 0)) THEN + JRSIGN = 1 + ELSE + JRSIGN = -1 + ENDIF + IF (MWA(2) == 0) THEN + MLR = 2*MWA(NDIG+3) + 1 + IF (KROUND == -1 .OR. KROUND == 2) THEN + NGUARD = KSHIFT - 1 + CALL FMRND(MWA,NDIG,NGUARD,1) + ELSE IF (MLR >= MBASE) THEN + IF (MLR-1 > MBASE .AND. MWA(N1+1) < MBASE-1) THEN + IF (KROUND /= 0 .OR. NCALL > 1) THEN + MWA(N1+1) = MWA(N1+1) + 1 + MWA(N1+2) = 0 + ENDIF + ELSE + NGUARD = KSHIFT - 1 + CALL FMRND(MWA,NDIG,NGUARD,1) + ENDIF + ENDIF + ELSE + MLR = 2*MWA(NDIG+2) + 1 + IF (KROUND == -1 .OR. KROUND == 2) THEN + CALL FMRND(MWA,NDIG,KSHIFT,0) + ELSE IF (MLR >= MBASE) THEN + IF (MLR-1 > MBASE .AND. MWA(N1) < MBASE-1) THEN + IF (KROUND /= 0 .OR. NCALL > 1) THEN + MWA(N1) = MWA(N1) + 1 + MWA(N1+1) = 0 + ENDIF + ELSE + CALL FMRND(MWA,NDIG,KSHIFT,0) + ENDIF + ENDIF + ENDIF + CALL FMMOVE(MWA,MB) + + IF (KFLAG < 0) THEN + NAMEST(NCALL) = 'FMMPYI' + CALL FMWARN + ENDIF + +! Put the sign on the result. + + MB(-1) = JRSIGN + IF (KACCSW == 1) THEN + MD2B = NINT((NDIG-1)*ALOGM2 + LOG(REAL(ABS(MB(2))+1))/0.69315) + MB(0) = MIN(MACCA,MD2B) + ELSE + MB(0) = MACCA + ENDIF + + IF (NTRACE /= 0) THEN + CALL FMNTR(1,MB,MB,1,1) + ENDIF + NCALL = NCALL - 1 + JRSIGN = JRSSAV + RETURN + END SUBROUTINE FMMPYI + + SUBROUTINE FMMPYI_R1(MA,IVAL) + +! MA = MA * IVAL + +! Multiply FM number MA by one word integer IVAL. + +! This routine is faster than FMMPY when IVAL*MBASE is a +! one word integer. + + USE FMVALS + IMPLICIT NONE + + REAL (KIND(1.0D0)) :: MA(-1:LUNPCK) + INTEGER IVAL + REAL (KIND(1.0D0)) :: MACCA,MAS,MCARRY,MD2B,MKT,MLR,MVAL + INTEGER J,JRSSAV,KA,KB,KC,KSHIFT,N1,NGUARD,NMVAL,NV2 + + IF (MBLOGS /= MBASE) CALL FMCONS + JRSSAV = JRSIGN + MACCA = MA(0) + NCALL = NCALL + 1 + IF (NTRACE /= 0) THEN + NAMEST(NCALL) = 'FMMPYI' + CALL FMNTR(2,MA,MA,1,1) + CALL FMNTRI(2,IVAL,0) + ENDIF + KFLAG = 0 + N1 = NDIG + 1 + +! Check for special cases. + + IF (MA(2) == 0) THEN + IF (NTRACE /= 0) THEN + CALL FMNTR(1,MA,MA,1,1) + ENDIF + NCALL = NCALL - 1 + JRSIGN = JRSSAV + RETURN + ENDIF + + IF (ABS(MA(1)) < MEXPOV .AND. ABS(IVAL) > 1) GO TO 110 + + IF (MA(1) == MUNKNO) THEN + CALL FMST2M('UNKNOWN',MA) + KFLAG = -4 + IF (NTRACE /= 0) THEN + CALL FMNTR(1,MA,MA,1,1) + ENDIF + NCALL = NCALL - 1 + JRSIGN = JRSSAV + RETURN + ENDIF + + IF (IVAL == 0) THEN + CALL FMIM(0,MA) + IF (NTRACE /= 0) THEN + CALL FMNTR(1,MA,MA,1,1) + ENDIF + NCALL = NCALL - 1 + JRSIGN = JRSSAV + RETURN + ENDIF + + IF (ABS(IVAL) == 1) THEN + IF (MA(1) == MEXPOV) KFLAG = -5 + IF (MA(1) == MEXPUN) KFLAG = -6 + MA(-1) = MA(-1)*IVAL + IF (NTRACE /= 0) THEN + CALL FMNTR(1,MA,MA,1,1) + ENDIF + NCALL = NCALL - 1 + JRSIGN = JRSSAV + RETURN + ENDIF + + IF (MA(1) == MEXPOV) THEN + MAS = MA(-1) + KFLAG = -5 + CALL FMST2M('OVERFLOW',MA) + IF ((MAS < 0 .AND. IVAL > 0) .OR. & + (MAS > 0 .AND. IVAL < 0)) MA(-1) = -1 + IF (NTRACE /= 0) THEN + CALL FMNTR(1,MA,MA,1,1) + ENDIF + NCALL = NCALL - 1 + JRSIGN = JRSSAV + RETURN + ENDIF + + IF (MA(1) == MEXPUN) THEN + NAMEST(NCALL) = 'FMMPYI' + KFLAG = -4 + CALL FMWARN + CALL FMST2M('UNKNOWN',MA) + IF (NTRACE /= 0) THEN + CALL FMNTR(1,MA,MA,1,1) + ENDIF + NCALL = NCALL - 1 + JRSIGN = JRSSAV + RETURN + ENDIF + +! Work with positive numbers. + + 110 MAS = MA(-1) + MVAL = ABS(IVAL) + NMVAL = INT(MVAL) + NV2 = NMVAL - 1 + +! To leave room for the normalization, shift the product +! to the right KSHIFT places in MWA. + + KSHIFT = INT((LOG(DBLE(MA(2)+1)*DBLE(MVAL)))/DLOGMB) + +! If IVAL is too big use FMMPY. + + IF (KSHIFT > NDIG .OR. MVAL > MAXINT/MBASE .OR. & + NMVAL /= ABS(IVAL) .OR. NV2 /= ABS(IVAL)-1) THEN + CALL FMIM(IVAL,M01) + CALL FMMPY2_R1(MA,M01) + IF (NTRACE /= 0) THEN + CALL FMNTR(1,MA,MA,1,1) + ENDIF + NCALL = NCALL - 1 + JRSIGN = JRSSAV + RETURN + ENDIF + + MWA(1) = MA(1) + KSHIFT + KA = 2 + KSHIFT + KB = N1 + KSHIFT + KC = NDIG + 5 + DO J = KB, KC + MWA(J) = 0 + ENDDO + + MCARRY = 0 + +! This is the main multiplication loop. + + DO J = KB, KA, -1 + MKT = MA(J-KSHIFT)*MVAL + MCARRY + MCARRY = INT (MKT/MBASE) + MWA(J) = MKT - MCARRY*MBASE + ENDDO + +! Resolve the final carry. + + DO J = KA-1, 2, -1 + MKT = INT (MCARRY/MBASE) + MWA(J) = MCARRY - MKT*MBASE + MCARRY = MKT + ENDDO + +! Now the first significant digit in the product is in +! MWA(2) or MWA(3). Round the result and move it to MA. + + IF ((MAS > 0 .AND. IVAL > 0) .OR. (MAS < 0 .AND. IVAL < 0)) THEN + JRSIGN = 1 + ELSE + JRSIGN = -1 + ENDIF + IF (MWA(2) == 0) THEN + MLR = 2*MWA(NDIG+3) + 1 + IF (KROUND == -1 .OR. KROUND == 2) THEN + NGUARD = KSHIFT - 1 + CALL FMRND(MWA,NDIG,NGUARD,1) + ELSE IF (MLR >= MBASE) THEN + IF (MLR-1 > MBASE .AND. MWA(N1+1) < MBASE-1) THEN + IF (KROUND /= 0 .OR. NCALL > 1) THEN + MWA(N1+1) = MWA(N1+1) + 1 + MWA(N1+2) = 0 + ENDIF + ELSE + NGUARD = KSHIFT - 1 + CALL FMRND(MWA,NDIG,NGUARD,1) + ENDIF + ENDIF + ELSE + MLR = 2*MWA(NDIG+2) + 1 + IF (KROUND == -1 .OR. KROUND == 2) THEN + CALL FMRND(MWA,NDIG,KSHIFT,0) + ELSE IF (MLR >= MBASE) THEN + IF (MLR-1 > MBASE .AND. MWA(N1) < MBASE-1) THEN + IF (KROUND /= 0 .OR. NCALL > 1) THEN + MWA(N1) = MWA(N1) + 1 + MWA(N1+1) = 0 + ENDIF + ELSE + CALL FMRND(MWA,NDIG,KSHIFT,0) + ENDIF + ENDIF + ENDIF + CALL FMMOVE(MWA,MA) + + IF (KFLAG < 0) THEN + NAMEST(NCALL) = 'FMMPYI' + CALL FMWARN + ENDIF + +! Put the sign on the result. + + MA(-1) = JRSIGN + IF (KACCSW == 1) THEN + MD2B = NINT((NDIG-1)*ALOGM2 + LOG(REAL(ABS(MA(2))+1))/0.69315) + MA(0) = MIN(MACCA,MD2B) + ELSE + MA(0) = MACCA + ENDIF + + IF (NTRACE /= 0) THEN + CALL FMNTR(1,MA,MA,1,1) + ENDIF + NCALL = NCALL - 1 + JRSIGN = JRSSAV + RETURN + END SUBROUTINE FMMPYI_R1 + + SUBROUTINE FMNINT(MA,MB) + +! MB = NINT(MA) -- MB is returned as the nearest integer to MA. + + USE FMVALS + IMPLICIT NONE + + REAL (KIND(1.0D0)) :: MA(-1:LUNPCK),MB(-1:LUNPCK) + REAL (KIND(1.0D0)) :: MA2,MXSAVE + INTEGER J,K,KASAVE,KOVUN,KRESLT,KWRNSV,NDSAVE + + IF (MBLOGS /= MBASE) CALL FMCONS + IF (ABS(MA(1)) > MEXPAB) THEN + CALL FMENTR('FMNINT',MA,MA,1,1,MB,KRESLT,NDSAVE,MXSAVE,KASAVE, & + KOVUN) + IF (KRESLT /= 0) RETURN + ELSE + NCALL = NCALL + 1 + NAMEST(NCALL) = 'FMNINT' + IF (NTRACE /= 0) CALL FMNTR(2,MA,MA,1,1) + KOVUN = 0 + IF (MA(1) == MEXPOV .OR. MA(1) == MEXPUN) KOVUN = 1 + NDSAVE = NDIG + IF (NCALL == 1) THEN + K = MAX(NGRD52-1,2) + NDIG = MAX(NDIG+K,2) + IF (NDIG > NDG2MX) THEN + KFLAG = -9 + CALL FMWARN + NDIG = NDSAVE + KRESLT = 12 + CALL FMRSLT(MA,MA,MB,KRESLT) + IF (NTRACE /= 0) CALL FMNTR(1,MB,MB,1,1) + NCALL = NCALL - 1 + RETURN + ENDIF + ENDIF + KASAVE = KACCSW + KACCSW = 0 + MXSAVE = MXEXP + MXEXP = MXEXP2 + ENDIF + + KWRNSV = KWARN + KWARN = 0 + CALL FMEQ2(MA,MB,NDSAVE,NDIG) + IF (NDSAVE > INT(MA(1))) THEN + MA2 = MA(-1) + MB(-1) = 1 + CALL FMI2M(1,M01) + CALL FMDIVI_R1(M01,2) + CALL FMADD_R1(MB,M01) + CALL FMINT(MB,M08) + CALL FMEQ(M08,MB) + IF (MA2 < 0 .AND. MB(1) /= MUNKNO .AND. MB(2) /= 0) MB(-1) = -MB(-1) + ENDIF + KWARN = KWRNSV + +! Round the result and return. + + DO J = -1, NDIG+1 + M01(J) = MB(J) + ENDDO + CALL FMEXIT(M01,MB,NDSAVE,MXSAVE,KASAVE,KOVUN) + RETURN + END SUBROUTINE FMNINT + + SUBROUTINE FMNTR(NTR,MA,MB,NARG,KNAM) + +! Print FM numbers in base 10 format using FMOUT for conversion. +! This is used for trace output from the FM routines. + +! NTR = 1 if a result of an FM call is to be printed. +! = 2 to print input argument(s) to an FM call. + +! MA - the FM number to be printed. + +! MB - an optional second FM number to be printed. + +! NARG - the number of arguments. NARG = 1 if only MA is to be +! printed, and NARG = 2 if both MA and MB are to be printed. + +! KNAM - positive if the routine name is to be printed. + + +! NTRACE and LVLTRC (in module FMVALS) control trace printout. + +! NTRACE = 0 No printout except warnings and errors. + +! NTRACE = 1 The result of each call to one of the routines +! is printed in base 10, using FMOUT. + +! NTRACE = -1 The result of each call to one of the routines +! is printed in internal base MBASE format. + +! NTRACE = 2 The input arguments and result of each call to one +! of the routines is printed in base 10, using FMOUT. + +! NTRACE = -2 The input arguments and result of each call to one +! of the routines is printed in base MBASE format. + +! LVLTRC defines the call level to which the trace is done. LVLTRC = 1 +! means only FM routines called directly by the user are traced, +! LVLTRC = K prints traces for FM routines with call levels up +! to and including level K. + + USE FMVALS + IMPLICIT NONE + + REAL (KIND(1.0D0)) :: MA(-1:LUNPCK),MB(-1:LUNPCK) + INTEGER KNAM,NTR,NARG + + CHARACTER(6) :: NAME + + IF (NTRACE == 0) RETURN + IF (NCALL > LVLTRC) RETURN + IF (NTR == 2 .AND. ABS(NTRACE) == 1) RETURN + + IF (NTR == 2) THEN + IF (KNAM > 0) THEN + NAME = NAMEST(NCALL) + WRITE (KW,"(' Input to ',A6)") NAME + ENDIF + ELSE + NAME = NAMEST(NCALL) + IF (KFLAG == 0) THEN + WRITE (KW, & + "(' ',A6,15X,'Call level =',I2,5X,'MBASE ='," // & + "I10,5X,'NDIG =',I6)" & + ) NAME,NCALL,INT(MBASE),NDIG + ELSE + WRITE (KW, & + "(' ',A6,6X,'Call level =',I2,4X,'MBASE ='," // & + "I10,4X,'NDIG =',I6,4X,'KFLAG =',I3)" & + ) NAME,NCALL,INT(MBASE),NDIG,KFLAG + ENDIF + ENDIF + +! Check for base MBASE internal format trace. + + IF (NTRACE < 0) THEN + CALL FMNTRJ(MA,NDIG) + IF (NARG == 2) CALL FMNTRJ(MB,NDIG) + ENDIF + +! Check for base 10 trace using FMOUT. + + IF (NTRACE > 0) THEN + CALL FMPRNT(MA) + + IF (NARG == 2) THEN + CALL FMPRNT(MB) + ENDIF + ENDIF + + RETURN + END SUBROUTINE FMNTR + + SUBROUTINE FMNTRI(NTR,N,KNAM) + +! Internal routine for trace output of integer variables. + +! NTR = 1 for output values +! 2 for input values + +! N Integer to be printed. + +! KNAM is positive if the routine name is to be printed. + + USE FMVALS + IMPLICIT NONE + + INTEGER NTR,N,KNAM + + CHARACTER(6) :: NAME + + IF (NTRACE == 0) RETURN + IF (NCALL > LVLTRC) RETURN + IF (NTR == 2 .AND. ABS(NTRACE) == 1) RETURN + + IF (NTR == 2 .AND. KNAM > 0) THEN + NAME = NAMEST(NCALL) + WRITE (KW,"(' Input to ',A6)") NAME + ENDIF + IF (NTR == 1 .AND. KNAM > 0) THEN + NAME = NAMEST(NCALL) + IF (KFLAG == 0) THEN + WRITE (KW, & + "(' ',A6,15X,'Call level =',I2,5X,'MBASE ='," // & + "I10,5X,'NDIG =',I6)" & + ) NAME,NCALL,INT(MBASE),NDIG + ELSE + WRITE (KW, & + "(' ',A6,6X,'Call level =',I2,4X,'MBASE ='," // & + "I10,4X,'NDIG =',I6,4X,'KFLAG =',I3)" & + ) NAME,NCALL,INT(MBASE),NDIG,KFLAG + ENDIF + ENDIF + + WRITE (KW,"(1X,I18)") N + + RETURN + END SUBROUTINE FMNTRI + + SUBROUTINE FMNTRJ(MA,ND) + +! Print trace output in internal base MBASE format. The number to +! be printed is in MA. + +! ND is the number of base MBASE digits to be printed. + + USE FMVALS + IMPLICIT NONE + + REAL (KIND(1.0D0)) :: MA(-1:LUNPCK) + INTEGER ND + + CHARACTER(50) :: FORM + INTEGER J,L,N,N1 + + N1 = ND + 1 + + L = INT(LOG10(DBLE(MBASE-1))) + 2 + N = (KSWIDE-23)/L + IF (N > 10) N = 5*(N/5) + IF (ND <= N) THEN + WRITE (FORM,"(' (1X,I19,I',I2,',',I3,'I',I2,') ')") L+2, N-1, L + ELSE + WRITE (FORM, & + "(' (1X,I19,I',I2,',',I3,'I',I2,'/" // & + "(22X,',I3,'I',I2,')) ')" & + ) L+2, N-1, L, N, L + ENDIF + WRITE (KW,FORM) INT(MA(1)),INT(MA(-1)*MA(2)),(INT(MA(J)),J=3,N1) + + RETURN + END SUBROUTINE FMNTRJ + + SUBROUTINE FMNTRR(NTR,X,KNAM) + +! Internal routine for trace output of real variables. + +! NTR - 1 for output values +! 2 for input values + +! X - Double precision value to be printed if NX == 1 + +! KNAM - Positive if the routine name is to be printed. + + USE FMVALS + IMPLICIT NONE + + INTEGER NTR,KNAM + DOUBLE PRECISION X + + CHARACTER(6) :: NAME + + IF (NTRACE == 0) RETURN + IF (NCALL > LVLTRC) RETURN + IF (NTR == 2 .AND. ABS(NTRACE) == 1) RETURN + + IF (NTR == 2 .AND. KNAM > 0) THEN + NAME = NAMEST(NCALL) + WRITE (KW,"(' Input to ',A6)") NAME + ENDIF + IF (NTR == 1 .AND. KNAM > 0) THEN + NAME = NAMEST(NCALL) + IF (KFLAG == 0) THEN + WRITE (KW, & + "(' ',A6,15X,'Call level =',I2,5X,'MBASE ='," // & + "I10,5X,'NDIG =',I6)" & + ) NAME,NCALL,INT(MBASE),NDIG + ELSE + WRITE (KW, & + "(' ',A6,6X,'Call level =',I2,4X,'MBASE ='," // & + "I10,4X,'NDIG =',I6,4X,'KFLAG =',I3)" & + ) NAME,NCALL,INT(MBASE),NDIG,KFLAG + ENDIF + ENDIF + + WRITE (KW,"(1X,D30.20)") X + + RETURN + END SUBROUTINE FMNTRR + + SUBROUTINE FMOUT(MA,LINE,LB) + +! Convert a floating multiple precision number to a character array +! for output. + +! MA is an FM number to be converted to an A1 character +! array in base 10 format +! LINE is the CHARACTER*1 array in which the result is returned. +! LB is the length of LINE. + +! JFORM1 and JFORM2 (in module FMVALS) determine the format of LINE. + +! JFORM1 = 0 normal setting ( .314159M+6 ) +! = 1 1PE format ( 3.14159M+5 ) +! = 2 F format ( 314159.000 ) + +! JFORM2 = number of significant digits to display (if JFORM1 = 0, 1) +! = number of digits after the decimal point (if JFORM1 = 2) + +! If JFORM2 == 0 and JFORM1 /= 2 then a default number of +! digits is chosen. The default is roughly the full precision +! of MA. + +! If JFORM2 == 0 and JFORM1 == 2 then the number is returned in +! integer format with no decimal point. Rounding is done as +! with other settings, so the value displayed is the nearest +! integer to MA. + +! If JFORM1 == 2 and MA is too large or too small to display in the +! requested format, it is converted using JFORM1=0, JFORM2=0. + +! LINE should be dimensioned at least LOG10(MBASE)*NDIG + 15 on a +! 32-bit machine to allow for up to 10 digit exponents. Replace +! 15 by 20 if 48-bit integers are used, 25 for 64-bit integers, .... + + USE FMVALS + IMPLICIT NONE + + REAL (KIND(1.0D0)) :: MA(-1:LUNPCK) + INTEGER LB + CHARACTER LINE(LB) + + CHARACTER KCHAR + REAL (KIND(1.0D0)) :: M2,MBSAVE,MEXP,MEXP10,MKT,MNDGMS,MS1,MS2, & + MSD2,MT10,MXSAVE + INTEGER J,JDPT,JF1SAV,JF2SAV,K,K1,K2,KA,KASAVE,KB,KC,KDIGIT, & + KEXP,KEXPSH,KMS2SD,KMT,KPT,KRSAVE,L,ND,NDE,NDE2,NDIGMS, & + NDS2,NDSAVE,NPOWER,NSD1,NSD2,NVAL,NWORD,NWORD1,NWORD2 + REAL X + + CHARACTER :: NUMB(10) = (/ '0','1','2','3','4','5','6','7','8','9' /) + CHARACTER :: NUNKNO(12) = (/ & + ' ',' ',' ','U','N','K','N','O','W','N',' ',' ' /) + CHARACTER :: NEXPOV(12) = (/ & + ' ',' ',' ','O','V','E','R','F','L','O','W',' ' /) + CHARACTER :: NEXPUN(12) = (/ & + ' ',' ',' ','U','N','D','E','R','F','L','O','W' /) + +! To avoid recursion, FMOUT calls only internal arithmetic +! routines (FMADD2, FMMPY2, ...), so no trace printout is +! done during a call to FMOUT. + + KFLAG = 0 + NCALL = NCALL + 1 + NAMEST(NCALL) = 'FMOUT ' + +! Raise the call stack again, since the internal +! routines don't. + + NCALL = NCALL + 1 + NAMEST(NCALL) = 'FMOUT ' + DO J = 1, LB + LINE(J) = ' ' + ENDDO + +! Check for special cases. + + IF (MA(1) == MUNKNO) THEN + DO J = 1, 12 + LINE(J) = NUNKNO(J) + ENDDO + NCALL = NCALL - 2 + RETURN + ENDIF + IF (MA(1) == MEXPOV) THEN + DO J = 1, 12 + LINE(J) = NEXPOV(J) + ENDDO + LINE(2) = '+' + IF (MA(-1) < 0) LINE(2) = '-' + NCALL = NCALL - 2 + RETURN + ENDIF + IF (MA(1) == MEXPUN) THEN + DO J = 1, 12 + LINE(J) = NEXPUN(J) + ENDDO + LINE(2) = '+' + IF (MA(-1) < 0) LINE(2) = '-' + NCALL = NCALL - 2 + RETURN + ENDIF + IF (MA(2) == 0 .AND. JFORM1 == 2 .AND. JFORM2 == 0) THEN + LINE(2) = '0' + NCALL = NCALL - 2 + RETURN + ENDIF + + KASAVE = KACCSW + KACCSW = 0 + KRSAVE = KROUND + KROUND = 1 + JF1SAV = JFORM1 + JF2SAV = JFORM2 + MBSAVE = MBASE + NDSAVE = NDIG + MXSAVE = MXEXP + +! ND is the number of base 10 digits required. + + 110 ND = JFORM2 + IF (JFORM1 == 2 .AND. MA(1) > 0) ND = JFORM2 + & + INT(REAL(MA(1))*LOG10(REAL(MBASE))) + 1 + IF (ND <= 1) THEN + K = INT(REAL(NDIG)*LOG10(REAL(MBASE))) + ND = MAX(K,JFORM2) + ENDIF + IF (JFORM2 <= 0 .AND. JFORM1 <= 1) ND = & + INT(1.1 + REAL(NDIG-1)*LOG10(REAL(MBASE))) + IF (ND < 2) ND = 2 + + IF (LB < ND+6) THEN + IF (JFORM1 == 2) THEN + JFORM1 = 0 + JFORM2 = 0 + GO TO 110 + ENDIF + GO TO 170 + ENDIF + +! Convert to the base that is the largest power of 10 +! less than MXBASE and build the output number. + + NPOWER = INT(LOG10(REAL(MXBASE)/4)) + MXEXP = MXEXP2 + MBASE = 10**NPOWER + IF (MBLOGS /= MBASE) CALL FMCONS + NDIG = ND/NPOWER + 3 + IF (NDIG < 2) NDIG = 2 + IF (NDIG > NDG2MX) THEN + KFLAG = -9 + NCALL = NCALL - 1 + CALL FMWARN + NCALL = NCALL + 1 + GO TO 170 + ENDIF + + IF (MA(2) == 0) THEN + CALL FMIM(0,MLV4) + GO TO 130 + ENDIF + +! Check to see if MA is already in a base that is a +! power of ten. If so, the conversion can be skipped. + + K = NPOWER + DO J = 1, K + MBASE = 10**J + IF (MBASE == MBSAVE) THEN + IF (MBLOGS /= MBASE) CALL FMCONS + NPOWER = J + NDIG = ND/NPOWER + 2 + IF (NDIG < 2) NDIG = 2 + IF (NDIG > NDG2MX) THEN + KFLAG = -9 + NCALL = NCALL - 1 + CALL FMWARN + NCALL = NCALL + 1 + GO TO 170 + ENDIF + CALL FMEQ2(MA,MLV4,NDSAVE,NDIG) + MLV4(-1) = 1 + GO TO 130 + ENDIF + ENDDO + + IF (MBLOGS /= MBASE) CALL FMCONS + CALL FMIM(INT(MBSAVE),MLV2) + NDS2 = NDSAVE + 1 + CALL FMIM(1,MLV3) + KMT = 1 + +! Convert the fraction part of MA to the new base. + + KPT = NDS2 + 1 + DO J = 3, NDS2 + KPT = KPT - 1 + IF (MA(KPT) /= 0) EXIT + ENDDO + + KEXPSH = KPT - 1 + KDIGIT = INT(ABS(MA(2))) + CALL FMIM(KDIGIT,MLV4) + NDIGMS = NDIG + + DO J = 3, KPT + KDIGIT = INT(MA(J)) + NDIG = MIN(NDIGMS,MAX(2,INT(MLV4(1)+MLV2(1)))) + CALL FMMPY2_R1(MLV4,MLV2) + + IF (KDIGIT > 0) THEN + IF (KMT /= KDIGIT) THEN + NDIG = MIN(NDIGMS,MAX(2,INT(MLV2(1)))) + CALL FMIM(KDIGIT,MLV3) + KMT = KDIGIT + ENDIF + NDIG = MIN(NDIGMS,MAX(2,INT(MAX(MLV4(1),MLV3(1)))+1)) + CALL FMADD2_R1(MLV4,MLV3) + ENDIF + ENDDO + +! Convert the exponent. + + NDIG = NDIGMS + CALL FMIM(1,MLV3) + K = ABS(INT(MA(1))-KEXPSH) + IF (MOD(K,2) == 1) THEN + CALL FMEQ(MLV2,MLV3) + ELSE + CALL FMIM(1,MLV3) + ENDIF + + 120 K = K/2 + M2 = 2 + MNDGMS = NDIGMS + NDIG = INT(MIN(MNDGMS,MAX(M2,MLV2(1)*M2))) + IF (K > 0) CALL FMSQR2_R1(MLV2) + IF (MOD(K,2) == 1) THEN + NDIG = INT(MIN(MNDGMS,MAX(M2,MLV3(1)+MLV2(1)))) + CALL FMMPY2_R1(MLV3,MLV2) + ENDIF + IF (K > 1) GO TO 120 + + NDIG = NDIGMS + IF (MA(1)-KEXPSH < 0) THEN + CALL FMDIV2_R1(MLV4,MLV3) + ELSE + CALL FMMPY2_R1(MLV4,MLV3) + ENDIF + +! Now MLV4 is the value of MA converted to a +! power of ten base. + +! Convert it to a character string base 10 for output. + +! MEXP10 is the base 10 exponent. +! KMS2SD is the number of base 10 significant digits +! in MLV4(2). + + 130 MS1 = MLV4(1) + 140 MEXP10 = NPOWER*MLV4(1) + KMS2SD = NPOWER + K = INT(MBASE) + DO J = 1, NPOWER + K = K/10 + IF (MLV4(2) < K .AND. MLV4(2) /= 0) THEN + MEXP10 = MEXP10 - 1 + KMS2SD = KMS2SD - 1 + ENDIF + ENDDO + +! For printing using JFORM1 = 1, reduce the exponent to +! account for the fact that the decimal point and first +! significant digit will later be swapped. + + IF (JFORM1 == 1 .AND. MLV4(2) /= 0) MEXP10 = MEXP10 - 1 + +! Find the position in the unpacked number for rounding. +! NWORD is the word in which rounding is done, or zero if +! no rounding is necessary. +! NWORD is set to -1 if JFORM1 is 2 (F format) but no +! significant digits would be printed. This case +! defaults to JFORM1 = 0. +! NVAL gives the position within that word where rounding +! occurs. +! NSD1 is the maximum number of base 10 S.D.'s in NWORD +! digits of base 10**NPOWER. +! NSD2 is the number of base 10 S.D.'s needed to get ND +! base 10 digits after the decimal. + + NSD2 = ND + IF (JFORM1 == 2) THEN + MSD2 = JFORM2 + MEXP10 + IF (MSD2 > ND) THEN + NSD2 = ND + ELSE + NSD2 = INT(MSD2) + ENDIF + NWORD = (NSD2-KMS2SD-1+NPOWER)/NPOWER + 2 + IF (NWORD < 2) NWORD = -1 + IF (NWORD > NDIG) NWORD = 0 + IF (NWORD >= 2 .AND. NSD2 <= 0) NWORD = -1 + ELSE + NWORD = (ND-KMS2SD-1+NPOWER)/NPOWER + 2 + ENDIF + NSD1 = KMS2SD + NPOWER*(NWORD-2) + IF (NWORD < 2) THEN + NVAL = 0 + ELSE + NVAL = 10**(NSD1-NSD2) + ENDIF + +! Now do the base 10 rounding. + + IF (NWORD >= 2) THEN + X = 0.0 + IF (NVAL > 1) X = MOD(INT(MLV4(NWORD)),NVAL) + IF (NWORD < NDIG+1) THEN + X = REAL(DBLE(X) + DBLE(MLV4(NWORD+1))/DBLE(MBASE)) + ENDIF + X = X/NVAL + IF (X < 0.5) GO TO 150 + MS2 = MLV4(2) + MLV4(NWORD) = INT(MLV4(NWORD)/NVAL)*NVAL + MLV4(NWORD+1) = 0 + MLV4(NWORD+2) = 0 + MLV4(NWORD) = MLV4(NWORD) + NVAL + IF (MLV4(NWORD) >= MBASE) THEN + NWORD1 = NWORD - 1 + NWORD2 = NWORD - 2 + IF (NWORD > 2) THEN + CALL FMEQ2_R1(MLV4,NWORD1,NWORD2) + ELSE + MLV4(1) = MLV4(1) + 1 + MLV4(2) = INT(MLV4(2)/MBASE) + MLV4(3) = 0 + ENDIF + ENDIF + IF (MLV4(1) /= MS1 .OR. MLV4(2) /= MS2) GO TO 140 + ENDIF + +! Build the base 10 character string. + + 150 IF (MA(-1) < 0) LINE(1) = '-' + LINE(2) = '.' + K = 10**KMS2SD + L = 2 + IF (NWORD == -1) NSD2 = ND + DO J = 1, NSD2 + K = K/10 + IF (K == 0) THEN + K = INT(MBASE)/10 + L = L + 1 + ENDIF + KDIGIT = INT(MLV4(L))/K + MLV4(L) = MOD(INT(MLV4(L)),K) + LINE(J+2) = NUMB(KDIGIT+1) + ENDDO + + KA = NSD2 + 3 + KB = ND + 2 + IF (KB >= KA) THEN + DO J = KA, KB + LINE(J) = NUMB(1) + ENDDO + ENDIF + + LINE(ND+3) = CMCHAR + LINE(ND+4) = '+' + IF (MEXP10 < 0) LINE(ND+4) = '-' + IF (MA(2) == 0) LINE(ND+4) = ' ' + +! Build the digits of the base 10 exponent backwards, +! then reverse them. + + NDE = 1 + MEXP = ABS(MEXP10) + MT10 = 10 + DO J = 1, LB + MKT = AINT (MEXP/MT10) + KDIGIT = INT(MEXP-MKT*MT10) + LINE(ND+4+J) = NUMB(KDIGIT+1) + MEXP = MKT + IF (MEXP == 0) EXIT + + IF (ND+5+J > LB) THEN + DO K = 1, LB + LINE(K) = '*' + ENDDO + GO TO 160 + ENDIF + + NDE = NDE + 1 + ENDDO + + NDE2 = NDE/2 + IF (NDE2 < 1) GO TO 160 + K1 = ND + 4 + K2 = ND + 5 + NDE + DO J = 1, NDE2 + K1 = K1 + 1 + K2 = K2 - 1 + KCHAR = LINE(K1) + LINE(K1) = LINE(K2) + LINE(K2) = KCHAR + ENDDO + +! If JFORM1 is 1 put the first digit left of the decimal. + + 160 IF (JFORM1 == 1) THEN + KCHAR = LINE(2) + LINE(2) = LINE(3) + LINE(3) = KCHAR + ENDIF + +! If JFORM1 is 2 put the number into fixed format. + + IF (JFORM1 == 2 .AND. JFORM2 >= 0) THEN + IF (MEXP10 <= -JFORM2 .OR. MEXP10+2 > LB) THEN + JFORM1 = 0 + JFORM2 = 0 + MBASE = MBSAVE + IF (MBLOGS /= MBASE) CALL FMCONS + NDIG = NDSAVE + MXEXP = MXSAVE + DO J = 1, LB + LINE(J) = ' ' + ENDDO + GO TO 110 + ENDIF + KA = ND + 3 + DO J = KA, LB + LINE(J) = NUMB(1) + ENDDO + + KEXP = INT(MEXP10) + IF (MEXP10 > 0) THEN + DO J = 1, KEXP + LINE(J+1) = LINE(J+2) + ENDDO + LINE(KEXP+2) = '.' + ENDIF + + IF (MEXP10 < 0) THEN + KEXP = -INT(MEXP10) + KA = 3 + KEXP + KB = LB + 1 + KC = KB - KEXP + DO J = KA, LB + KB = KB - 1 + KC = KC - 1 + LINE(KB) = LINE(KC) + LINE(KC) = NUMB(1) + ENDDO + ENDIF + + JDPT = 0 + DO J = 1, LB + IF (LINE(J) == '.') JDPT = J + IF (JDPT > 0 .AND. J > JDPT+JFORM2) LINE(J) = ' ' + ENDDO + IF (JFORM2 == 0 .AND. JDPT > 0) LINE(KEXP+2) = ' ' + + ENDIF + +! Restore values and return + + GO TO 180 + +! LINE is not big enough to hold the number +! of digits specified. + + 170 KFLAG = -8 + DO J = 1, LB + LINE(J) = '*' + ENDDO + NCALL = NCALL - 1 + CALL FMWARN + NCALL = NCALL + 1 + + 180 MBASE = MBSAVE + IF (MBLOGS /= MBASE) CALL FMCONS + NDIG = NDSAVE + MXEXP = MXSAVE + NCALL = NCALL - 2 + KACCSW = KASAVE + KROUND = KRSAVE + JFORM1 = JF1SAV + JFORM2 = JF2SAV + RETURN + END SUBROUTINE FMOUT + + SUBROUTINE FMPACK(MA,MP) + +! MA is packed two base NDIG digits per word and returned in MP. + + USE FMVALS + IMPLICIT NONE + + REAL (KIND(1.0D0)) :: MA(-1:LUNPCK),MP(-1:LPACK) + + INTEGER J,KP + + KP = 2 + MP(-1) = MA(-1) + MP(0) = MA(0) + MP(1) = MA(1) + MP(2) = ABS(MA(2))*MBASE + MA(3) + IF (NDIG >= 4) THEN + DO J = 4, NDIG, 2 + KP = KP + 1 + MP(KP) = MA(J)*MBASE + MA(J+1) + ENDDO + ENDIF + IF (MOD(NDIG,2) == 1) MP(KP+1) = MA(NDIG+1)*MBASE + RETURN + END SUBROUTINE FMPACK + + SUBROUTINE FMPI(MA) + +! MA = pi + + USE FMVALS + IMPLICIT NONE + + REAL (KIND(1.0D0)) :: MA(-1:LUNPCK) + CHARACTER(155) :: STRING + INTEGER K,KASAVE,NDMB,NDSAVE,NDSV + + IF (MBLOGS /= MBASE) CALL FMCONS + KFLAG = 0 + NCALL = NCALL + 1 + NAMEST(NCALL) = 'FMPI ' + IF (ABS(NTRACE) >= 2 .AND. NCALL <= LVLTRC) THEN + WRITE (KW,"(' Input to FMPI')") + ENDIF + KASAVE = KACCSW + KACCSW = 0 + +! Increase the working precision. + + NDSAVE = NDIG + IF (NCALL == 1) THEN + K = NGRD52 + NDIG = MAX(NDIG+K,2) + IF (NDIG > NDG2MX) THEN + KFLAG = -9 + CALL FMWARN + NDIG = NDSAVE + CALL FMST2M('UNKNOWN',MA) + GO TO 110 + ENDIF + ENDIF + +! Check to see if pi has previously been computed +! in base MBASE with sufficient precision. + + IF (MBSPI == MBASE .AND. NDIGPI >= NDIG) THEN + IF (NAMEST(NCALL-1) /= 'NOEQ ') THEN + KACCSW = KASAVE + CALL FMEQ2(MPISAV,MA,NDIGPI,NDSAVE) + ENDIF + ELSE + NDMB = INT(150.0*2.302585/ALOGMB) + IF (NDMB >= NDIG) THEN + NDSV = NDIG + NDIG = MIN(NDMB,NDG2MX) + STRING = '3.141592653589793238462643383279502884197169'// & + '39937510582097494459230781640628620899862803482534211'// & + '7067982148086513282306647093844609550582231725359408128' + CALL FMST2M(STRING,MPISAV) + MPISAV(0) = NINT(NDIG*ALOGM2) + MBSPI = MBASE + NDIGPI = NDIG + IF (ABS(MPISAV(1)) > 10) NDIGPI = 0 + ELSE + NDSV = NDIG + NDIG = MIN(NDIG+2,NDG2MX) + CALL FMPI2(MPISAV) + MPISAV(0) = NINT(NDIG*ALOGM2) + MBSPI = MBASE + NDIGPI = NDIG + IF (ABS(MPISAV(1)) > 10) NDIGPI = 0 + ENDIF + IF (NAMEST(NCALL-1) /= 'NOEQ ') THEN + KACCSW = KASAVE + CALL FMEQ2(MPISAV,MA,NDIG,NDSAVE) + ENDIF + NDIG = NDSV + ENDIF + + 110 NDIG = NDSAVE + KACCSW = KASAVE + IF (NTRACE /= 0) CALL FMNTR(1,MA,MA,1,1) + NCALL = NCALL - 1 + RETURN + END SUBROUTINE FMPI + + SUBROUTINE FMPI2(MPI) + +! Internal routine to compute pi. +! The formula used is due to S. Ramanujan: +! (4n)!(1103+26390n) +! 1/pi = (sqrt(8)/9801) * sum(n=0 to infinity) -------------------- +! ((n!)**4)(396**(4n)) +! The result is returned in MPI. + + USE FMVALS + IMPLICIT NONE + + REAL (KIND(1.0D0)) :: MPI(-1:LUNPCK) + DOUBLE PRECISION X + REAL (KIND(1.0D0)) :: MX + INTEGER NSTACK(19),J,K,KST,LARGE,N,NDIGRD,NDSAVE + + IF (MBLOGS /= MBASE) CALL FMCONS + NDSAVE = NDIG + N = -1 + CALL FMI2M(1103,MPI) + CALL FMI2M(1,M02) + CALL FMI2M(26390,M03) + CALL FMI2M(1103,M04) + MX = MXBASE**2/MBASE + IF (MX > MXEXP2) MX = MXEXP2 + + 110 N = N + 1 + LARGE = INT(MX)/(4*N + 3) + J = 4*N + 1 + IF (J > LARGE) THEN + CALL FMMPYI_R1(M02,J) + J = J + 1 + CALL FMMPYI_R1(M02,J) + J = J + 1 + CALL FMMPYI_R1(M02,J) + ELSE IF (J*(J+1) > LARGE) THEN + K = J*(J+1) + CALL FMMPYI_R1(M02,K) + J = J + 2 + CALL FMMPYI_R1(M02,J) + ELSE + K = J*(J+1)*(J+2) + CALL FMMPYI_R1(M02,K) + ENDIF + + J = N + 1 + LARGE = INT(MXBASE)/J + IF (J > LARGE) THEN + CALL FMDIVI_R1(M02,J) + CALL FMDIVI_R1(M02,J) + CALL FMDIVI_R1(M02,J) + ELSE IF (J*J > LARGE) THEN + K = J*J + CALL FMDIVI_R1(M02,K) + CALL FMDIVI_R1(M02,J) + ELSE + K = J*J*J + CALL FMDIVI_R1(M02,K) + ENDIF + +! Break 4/396**4 into 1/(2178*2178*1296). + + J = 2178 + LARGE = INT(MXBASE)/J + IF (J > LARGE) THEN + CALL FMDIVI_R1(M02,J) + CALL FMDIVI_R1(M02,J) + CALL FMDIVI_R1(M02,1296) + ELSE + K = J*J + CALL FMDIVI_R1(M02,K) + CALL FMDIVI_R1(M02,1296) + ENDIF + + NDIGRD = NDIG + NDIG = NDSAVE + CALL FMADD_R2(M03,M04) + NDIG = NDIGRD + CALL FMMPY(M02,M04,M01) + + NDIG = NDSAVE + CALL FMADD_R1(MPI,M01) + NDIG = MAX(2,NDSAVE - INT(MPI(1) - M01(1))) + IF (KFLAG /= 1) GO TO 110 + NDIG = NDSAVE + + CALL FMI2M(8,M02) + X = 8 + X = SQRT(X) + CALL FMDPM(X,M04) + CALL FMDIG(NSTACK,KST) + DO J = 1, KST + NDIG = NSTACK(J) + CALL FMDIV(M02,M04,M01) + CALL FMADD_R1(M04,M01) + CALL FMDIVI_R1(M04,2) + ENDDO + M04(0) = NINT(NDIG*ALOGM2) + CALL FMI2M(9801,M03) + CALL FMMPY_R1(MPI,M04) + CALL FMDIV_R2(M03,MPI) + + RETURN + END SUBROUTINE FMPI2 + + SUBROUTINE FMPRNT(MA) + +! Print MA in base 10 format. + +! FMPRNT can be called directly by the user for easy output +! in M format. MA is converted using FMOUT and printed. + + USE FMVALS + IMPLICIT NONE + + REAL (KIND(1.0D0)) :: MA(-1:LUNPCK) + + CHARACTER(20) :: FORM + INTEGER J,K,KSAVE,L,LAST,LB,ND,NEXP + + NCALL = NCALL + 1 + NAMEST(NCALL) = 'FMPRNT' + KSAVE = KFLAG + ND = INT(REAL(NDIG)*LOG10(REAL(MBASE))) + 1 + IF (ND < 2) ND = 2 + NEXP = INT(2.0*LOG10(REAL(MXBASE))) + 6 + LB = MAX(JFORM2+NEXP,ND+NEXP) + LB = MIN(LB,LMBUFF) + CALL FMOUT(MA,CMBUFF,LB) + KFLAG = KSAVE + LAST = LB + 1 + WRITE (FORM,"(' (6X,',I3,'A1) ')") KSWIDE-7 + DO J = 1, LB + IF (CMBUFF(LAST-J) /= ' ' .OR. J == LB) THEN + L = LAST - J + WRITE (KW,FORM) (CMBUFF(K),K=1,L) + NCALL = NCALL - 1 + RETURN + ENDIF + ENDDO + NCALL = NCALL - 1 + RETURN + END SUBROUTINE FMPRNT + + SUBROUTINE FMPWR(MA,MB,MC) + +! MC = MA ** MB + +! If MB can be expressed exactly as a one word integer, then FMIPWR is +! used. This is much faster when MB is small, and using FMIPWR allows +! MA to be negative. + + USE FMVALS + IMPLICIT NONE + + REAL (KIND(1.0D0)) :: MA(-1:LUNPCK),MB(-1:LUNPCK),MC(-1:LUNPCK) + REAL (KIND(1.0D0)) :: MACCA,MACCB,MACMAX,MXSAVE + INTEGER IEXTRA,INTMB,J,K,KASAVE,KFL,KOVUN,KRESLT,KWRNSV,NDSAVE + +! Convert MB to an integer before changing NDIG. + + KWRNSV = KWARN + KWARN = 0 + CALL FMMI(MB,INTMB) + KWARN = KWRNSV + KFL = KFLAG + + IF (MBLOGS /= MBASE) CALL FMCONS + IF (ABS(MA(1)) > MEXPAB .OR. ABS(MB(1)) > MEXPAB .OR. & + MA(2) == 0 .OR. MA(-1) < 0) THEN + CALL FMENTR('FMPWR ',MA,MB,2,1,MC,KRESLT,NDSAVE,MXSAVE,KASAVE, & + KOVUN) + IF (KRESLT /= 0) RETURN + ELSE + NCALL = NCALL + 1 + NAMEST(NCALL) = 'FMPWR ' + IF (NTRACE /= 0) CALL FMNTR(2,MA,MB,2,1) + KOVUN = 0 + IF (MA(1) == MEXPOV .OR. MA(1) == MEXPUN) KOVUN = 1 + IF (MB(1) == MEXPOV .OR. MB(1) == MEXPUN) KOVUN = 1 + NDSAVE = NDIG + IF (NCALL == 1) THEN + K = MAX(NGRD52-1,2) + NDIG = MAX(NDIG+K,2) + IF (NDIG > NDG2MX) THEN + KFLAG = -9 + CALL FMWARN + NDIG = NDSAVE + KRESLT = 12 + CALL FMRSLT(MA,MB,MC,KRESLT) + IF (NTRACE /= 0) CALL FMNTR(1,MC,MC,1,1) + NCALL = NCALL - 1 + RETURN + ENDIF + ENDIF + KASAVE = KACCSW + KACCSW = 0 + MXSAVE = MXEXP + MXEXP = MXEXP2 + ENDIF + +! If the exponent is large or the base is very large, +! raise the precision. + + IF (MA(1) /= 0) THEN + IEXTRA = MAX(0,INT(MB(1)))+INT(LOG(ABS(REAL(MA(1))))/ALOGMB) + ELSE + IEXTRA = MAX(0,INT(MB(1))) + ENDIF + IF (MB(1)-NDIG > LOG(ALOGMB*REAL(MXEXP2))) THEN + IEXTRA = 0 + ENDIF + + NDIG = NDIG + IEXTRA + IF (NDIG > NDG2MX) THEN + IF (NCALL == 1) THEN + KFLAG = -9 + CALL FMWARN + NDIG = NDSAVE + CALL FMST2M('UNKNOWN',MC) + DO J = -1, NDIG+1 + M01(J) = MC(J) + ENDDO + CALL FMEXIT(M01,MC,NDSAVE,MXSAVE,KASAVE,KOVUN) + RETURN + ELSE + NDIG = NDG2MX + ENDIF + ENDIF + IF (MBASE < 1000 .OR. KROUND /= 1 .OR. KRPERF == 1) THEN + IF (NCALL == 1) NDIG = MIN(NDG2MX,MAX(NDIG,2*NDSAVE+10)) + ENDIF + +! If the exponent is a small integer, call FMIPWR. + + KWRNSV = KWARN + KWARN = 0 + + MACCA = MA(0) + MACCB = NINT(NDIG*ALOGM2) + CALL FMEQ2(MA,M06,NDSAVE,NDIG) + M06(0) = NINT(NDIG*ALOGM2) + + IF (KFL == 0) THEN + CALL FMIPWR(M06,INTMB,MC) + ELSE IF (M06(2) == 0 .OR. M06(-1) < 0) THEN + CALL FMST2M('UNKNOWN',MC) + KFLAG = -4 + ELSE + CALL FMLN(M06,M13) + CALL FMEQ(M13,M06) + MACCB = MB(0) + CALL FMEQ2(MB,M02,NDSAVE,NDIG) + M02(0) = NINT(NDIG*ALOGM2) + CALL FMMPY_R1(M06,M02) + CALL FMEXP(M06,MC) + ENDIF + KWARN = KWRNSV + +! Round the result and return. + + MACMAX = NINT((NDSAVE-1)*ALOGM2 + LOG(REAL(ABS(MC(2))+1))/0.69315) + MC(0) = MIN(MC(0),MACCA,MACCB,MACMAX) + DO J = -1, NDIG+1 + M01(J) = MC(J) + ENDDO + CALL FMEXIT(M01,MC,NDSAVE,MXSAVE,KASAVE,KOVUN) + RETURN + END SUBROUTINE FMPWR + + SUBROUTINE FM_RANDOM_NUMBER(VALUE) + +! FM_RANDOM_NUMBER generates pseudo-random numbers uniform on (0,1). +! VALUE is returned as the next random (double precision) number. +! Neither zero nor one will be returned in VALUE. + +! This version uses the FM package to implement a multiplicative congruential +! generator. Both the modulus and the multiplier are 49-digit primes, and +! the period is over 1.0E+49. This generator passes the spectral test, with +! mu(2), ..., mu(6) = 3.40, 4.35, 3.98, 3.19, 3.20. + +! Then the numbers are shuffled before returning them to the calling program. +! See the discussion of Bays and Durham shuffling in Knuth, V. 2. + +! Both the basic multiplicative congruential generator and the shuffled +! version have passed Marsaglia's DieHard test suite for generators. + +! The typical usage is to call FM_RANDOM_SEED once with PUT defined as an +! integer array of length 7 containing seven seed values used to initialize +! the generator. This initializes the table used by the mixed congruential +! generator. Then each call to FM_RANDOM_NUMBER gets the next random value. + +! The calling program must USE FMZM to call FM_RANDOM_SEED. FM_RANDOM_NUMBER +! can be used with a default seed without any calls to FM_RANDOM_SEED. + +! This example seeds the generator and then fills the array R with random +! values between 0 and 1. + +! SEED = (/ 314159,265358,979323,846264,338327,950288,419716 /) +! CALL FM_RANDOM_SEED(PUT=SEED) +! DO J = 1, N +! CALL FM_RANDOM_NUMBER(R(J)) +! ENDDO + +! In a GET= call, the seed array is returned that would later restart the +! multiplicative congruential generator in FM_RANDOM_NUMBER at the same place +! in the sequence, but since the table used to shuffle the output values is +! not saved in a GET= call, the sequence may not repeat exactly. + +! SEED = (/ 314159,265358,979323,846264,338327,950288,419716 /) +! CALL FM_RANDOM_SEED(PUT=SEED) +! DO J = 1, 100 +! CALL FM_RANDOM_NUMBER(R(J)) +! ENDDO + +! CALL FM_RANDOM_SEED(GET=SEED) +! DO J = 101, 200 +! CALL FM_RANDOM_NUMBER(R(J)) +! ENDDO + +! CALL FM_RANDOM_SEED(PUT=SEED) +! DO J = 201, 300 +! CALL FM_RANDOM_NUMBER(R(J)) +! ENDDO + +! CALL FM_RANDOM_SEED(PUT=SEED) +! DO J = 301, 400 +! CALL FM_RANDOM_NUMBER(R(J)) +! ENDDO + +! Here the seed is saved after 100 calls. The seed is used to re-set the +! generator after 200 calls to the same state it had after 100 calls, but +! R(201), ..., R(300) is not the same sequence as R(101), ..., R(200) +! because the shuffling is different. + +! However, re-setting again after 300 calls will reinitialize the shuffling +! the same way as after 200 calls, so R(301), ..., R(400) is exactly the +! same sequence as R(201), ..., R(300). + + USE FMVALS + USE FMZM + + IMPLICIT NONE + + DOUBLE PRECISION VALUE,DPM,DPX,Y + SAVE DPM,Y + INTEGER POS_OF_LAST_DIGIT,J,JBASE,LAST_DIGIT_OF_X,LAST_DIGIT_OF_M_M1 + INTEGER :: SEED(7) = (/314159,265358,979323,846264,338327,950288,419716/) + SAVE JBASE,LAST_DIGIT_OF_M_M1,SEED + DOUBLE PRECISION :: MSAVE + LOGICAL IMCOMP + +! Keep a table of recently generated numbers and shuffle the +! order before returning them. + + INTEGER, PARAMETER :: TABLE_SIZE = 100 + DOUBLE PRECISION, SAVE :: TABLE(0:TABLE_SIZE-1) + + MSAVE = MBASE + MBASE = MBRAND + +! START_RANDOM_SEQUENCE = 0 for normal operation. +! Get the next random value. +! = 1 for an initializing call after +! the user has called FM_RANDOM_SEED. +! Use that value in MRNX to initialize. +! = -1 for the first user call if there +! was no initializing call to +! FM_RANDOM_SEED. Use a default +! seed to initialize MRNX. + + IF (START_RANDOM_SEQUENCE /= 0) THEN + IF (START_RANDOM_SEQUENCE == -1) THEN + CALL FM_RANDOM_SEED(PUT=SEED) + ENDIF + START_RANDOM_SEQUENCE = 0 + CALL IMST2M('1424133622579837639401183671018194926834820238197',MRNA) + CALL IMST2M('2070613773952029032014000773560846464373793273739',MRNM) + LAST_DIGIT_OF_M_M1 = INT(MRNM(INT(MRNM(1))+1)) - 1 + JBASE = INT(MBASE) - 1 + CALL IMI2M(1,MRNC) + CALL IMM2DP(MRNM,DPM) + DPM = 1.0D0/DPM + DO J = 0, TABLE_SIZE-1 + 110 CALL IMMPYM(MRNA,MRNX,MRNM,M13) + CALL IMADD(M13,MRNC,M10) + CALL IMMOD(M10,MRNM,MRNX) + CALL IMM2DP(MRNX,DPX) + VALUE = DPX*DPM + IF (VALUE >= 1.0D0 .OR. VALUE <= 0.0D0) GO TO 110 + TABLE(J) = VALUE + ENDDO + CALL IMMPYM(MRNA,MRNX,MRNM,M13) + CALL IMADD(M13,MRNC,M10) + CALL IMMOD(M10,MRNM,MRNX) + CALL IMM2DP(MRNX,DPX) + Y = DPX*DPM + ENDIF + +! Get the next number in the sequence. + + 120 CALL IMMPYM(MRNA,MRNX,MRNM,M13) + POS_OF_LAST_DIGIT = INT(MRNX(1)) + 1 + DO J = -1, POS_OF_LAST_DIGIT + MRNX(J) = M13(J) + ENDDO + LAST_DIGIT_OF_X = INT(MRNX(POS_OF_LAST_DIGIT)) + IF (LAST_DIGIT_OF_X == LAST_DIGIT_OF_M_M1) THEN + CALL IMADD(MRNX,MRNC,M10) + CALL IMEQ(M10,MRNX) + IF (IMCOMP(MRNX,'GE',MRNM)) THEN + CALL IMSUB(MRNX,MRNM,M10) + CALL IMEQ(M10,MRNX) + ENDIF + ELSE IF (LAST_DIGIT_OF_X < JBASE) THEN + MRNX(POS_OF_LAST_DIGIT) = MRNX(POS_OF_LAST_DIGIT) + 1 + ELSE + CALL IMADD(MRNX,MRNC,M10) + CALL IMEQ(M10,MRNX) + ENDIF + +! Convert to double precision. + + DPX = MRNX(2) + DO J = 3, POS_OF_LAST_DIGIT + DPX = MBASE*DPX + MRNX(J) + ENDDO + + DPX = DPX*DPM + IF (DPX >= 1.0D0 .OR. DPX <= 0.0D0) GO TO 120 + +! Shuffling. + + J = Y*TABLE_SIZE + Y = TABLE(J) + VALUE = Y + TABLE(J) = DPX + + MBASE = MSAVE + RETURN + END SUBROUTINE FM_RANDOM_NUMBER + + SUBROUTINE FMRDC(MA,JSIN,JCOS,JSWAP) + +! Reduce MA using various trigonometric identities to an equivalent +! angle between 0 and 45 degrees. The reduction is done in radians +! if KRAD (in module FMVALS) is 1, in degrees if KRAD is 0. +! JSIN and JCOS are returned +1 or -1 and JSWAP is returned to indicate +! that the sin and cos functions have been interchanged as follows: + +! JSWAP = 0 means SIN(MA) = JSIN*SIN(returned value of MA) +! COS(MA) = JCOS*COS(returned value of MA) + +! JSWAP = 1 means SIN(MA) = JSIN*COS(returned value of MA) +! COS(MA) = JCOS*SIN(returned value of MA) + + USE FMVALS + IMPLICIT NONE + + REAL (KIND(1.0D0)) :: MA(-1:LUNPCK) + INTEGER JSIN,JCOS,JSWAP + REAL (KIND(1.0D0)) :: MA0 + DOUBLE PRECISION X + INTEGER J,KASAVE,NDSAVE,NDSV + LOGICAL FMCOMP + + IF (MBLOGS /= MBASE) CALL FMCONS + JSIN = 1 + JCOS = 1 + JSWAP = 0 + NDSAVE = NDIG + NDIG = NDIG + MAX(0,INT(MA(1))) + +! If the argument is too big, return UNKNOWN. + + IF (NDIG > NDG2MX) THEN + KFLAG = -9 + CALL FMWARN + NDIG = NDSAVE + CALL FMST2M('UNKNOWN',MA) + RETURN + ENDIF + MA0 = MA(0) + NINT(ALOGM2*REAL(MAX(0,INT(MA(1))))) + +! If MA is less than 1/MBASE, no reduction is needed. + + IF (MA(1) < 0) THEN + NDIG = NDSAVE + IF (MA(-1) < 0) THEN + MA(-1) = 1 + JSIN = -1 + ENDIF + RETURN + ENDIF + + J = 1 + IF (KRAD == 1) THEN + 110 IF (MBSPI /= MBASE .OR. NDIGPI < NDIG) THEN + NDSV = NDIG + NDIG = MIN(NDIG+2,NDG2MX) + KASAVE = KACCSW + KACCSW = 0 + NCALL = NCALL + 1 + NAMEST(NCALL) = 'NOEQ ' + CALL FMPI(MPISAV) + NCALL = NCALL - 1 + KACCSW = KASAVE + NDIG = NDSV + ENDIF + CALL FMEQ2(MA,M04,NDSAVE,NDIG) + M04(0) = MA0 + IF (MA(-1) < 0) JSIN = -1 + M04(-1) = 1 + IF (M04(1) == 0) THEN + CALL FMM2DP(M04,X) + IF (X <= 0.75) THEN + NDIG = NDSAVE + CALL FMEQ(M04,MA) + RETURN + ENDIF + ENDIF + CALL FMADD(MPISAV,MPISAV,M02) + IF (FMCOMP(M04,'GE',M02)) THEN + CALL FMDIV(M04,M02,M01) + CALL FMINT(M01,M08) + CALL FMEQ(M08,M01) + CALL FMMPY_R1(M01,M02) + CALL FMSUB_R1(M04,M01) + ENDIF + CALL FMEQ(MPISAV,M03) + IF (FMCOMP(M04,'GE',M03)) THEN + JSIN = -JSIN + CALL FMSUB_R2(M02,M04) + ENDIF + CALL FMDIVI_R1(M02,4) + IF (FMCOMP(M04,'GE',M02)) THEN + JCOS = -JCOS + CALL FMSUB_R2(M03,M04) + ENDIF + CALL FMDIVI_R1(M03,4) + IF (FMCOMP(M04,'GE',M03)) THEN + JSWAP = 1 + CALL FMSUB_R2(M02,M04) + ENDIF + +! If the reduced argument is close to zero, then +! cancellation has produced an inaccurate value. +! Raise NDIG and do the reduction again. + + IF (J == 1 .AND. (M04(1) < 0 .OR. M04(2) == 0)) THEN + J = 2 + IF (M04(2) == 0) THEN + NDIG = MIN(2*NDIG,NDG2MX) + ELSE + NDIG = NDIG - INT(M04(1)) + ENDIF + IF (NDIG > NDG2MX) THEN + KFLAG = -9 + CALL FMWARN + NDIG = NDSAVE + CALL FMST2M('UNKNOWN',MA) + RETURN + ENDIF + JSIN = 1 + JCOS = 1 + JSWAP = 0 + MA0 = MA(0) + NINT(ALOGM2*REAL(-M04(1))) + GO TO 110 + ENDIF + + ELSE + + CALL FMEQ2(MA,M04,NDSAVE,NDIG) + M04(0) = MA0 + IF (MA(-1) < 0) JSIN = -1 + M04(-1) = 1 + IF (M04(1) == 0) THEN + CALL FMM2DP(M04,X) + IF (X <= 44.0) THEN + NDIG = NDSAVE + CALL FMEQ(M04,MA) + RETURN + ENDIF + ENDIF + CALL FMI2M(360,M02) + IF (FMCOMP(M04,'GE',M02)) THEN + CALL FMDIV(M04,M02,M01) + CALL FMINT(M01,M08) + CALL FMEQ(M08,M01) + CALL FMMPY_R1(M01,M02) + CALL FMSUB_R1(M04,M01) + ENDIF + CALL FMI2M(180,M03) + IF (FMCOMP(M04,'GE',M03)) THEN + JSIN = -JSIN + CALL FMSUB_R2(M02,M04) + ENDIF + CALL FMI2M(90,M02) + IF (FMCOMP(M04,'GE',M02)) THEN + JCOS = -JCOS + CALL FMSUB_R2(M03,M04) + ENDIF + CALL FMI2M(45,M03) + IF (FMCOMP(M04,'GE',M03)) THEN + JSWAP = 1 + CALL FMSUB_R2(M02,M04) + ENDIF + + ENDIF + +! Round the result and return. + + CALL FMEQ2(M04,MA,NDIG,NDSAVE) + NDIG = NDSAVE + RETURN + END SUBROUTINE FMRDC + + SUBROUTINE FMREAD(KREAD,MA) + +! Read MA on unit KREAD. Multi-line numbers will have '&' as the +! last nonblank character on all but the last line. Only one +! number is allowed on the line(s). + + USE FMVALS + IMPLICIT NONE + + REAL (KIND(1.0D0)) :: MA(-1:LUNPCK) + INTEGER KREAD + + CHARACTER LINE(80) + INTEGER J,LB,NDSAVE + + IF (MBLOGS /= MBASE) CALL FMCONS + NCALL = NCALL + 1 + NAMEST(NCALL) = 'FMREAD' + NDSAVE = NDIG + NDIG = MIN(NDG2MX,MAX(NDIG+NGRD52,2)) + LB = 0 + + 110 READ (KREAD,"(80A1)",ERR=120,END=120) LINE + +! Scan the line and look for '&' + + DO J = 1, 80 + IF (LINE(J) == '&') GO TO 110 + IF (LINE(J) /= ' ') THEN + LB = LB + 1 + IF (LB > LMBUFF) THEN + KFLAG = -8 + GO TO 130 + ENDIF + CMBUFF(LB) = LINE(J) + ENDIF + ENDDO + + CALL FMINP(CMBUFF,M01,1,LB) + + CALL FMEQ2(M01,MA,NDIG,NDSAVE) + NDIG = NDSAVE + NCALL = NCALL - 1 + RETURN + +! If there is an error, return UNKNOWN. + + 120 KFLAG = -4 + 130 CALL FMWARN + NDIG = NDSAVE + CALL FMST2M('UNKNOWN',MA) + NCALL = NCALL - 1 + RETURN + END SUBROUTINE FMREAD + + SUBROUTINE FMRND(MW,ND,NGUARD,KSHIFT) + +! Round MW to ND digits (base MBASE). + +! MW is non-negative and has ND+NGUARD+KSHIFT digits. + +! NGUARD is the number of guard digits carried. +! KSHIFT is 1 if a left shift is pending when MW(2)=0. + +! Round to position MW(ND+1+KSHIFT) using the guard digits +! MW(ND+2+KSHIFT), ..., MW(ND+1+NGUARD+KSHIFT). + +! This routine is designed to be called only from within the FM +! package. The user should call FMEQU to round numbers. + + USE FMVALS + IMPLICIT NONE + + REAL (KIND(1.0D0)) :: MW(LMWA) + INTEGER ND,NGUARD,KSHIFT + + REAL (KIND(1.0D0)) :: M2,MFACTR,MKT + INTEGER J,K,KB,L + + IF (KROUND == -1 .AND. NCALL <= 1) THEN + IF (JRSIGN == 1) RETURN + DO J = ND+2+KSHIFT, ND+1+NGUARD+KSHIFT + IF (MW(J) > 0) THEN + MW(ND+1+KSHIFT) = MW(ND+1+KSHIFT) + 1 + MW(ND+2+KSHIFT) = 0 + IF (MW(ND+1+KSHIFT) < MBASE) RETURN + L = ND + 2 + KSHIFT + GO TO 120 + ENDIF + ENDDO + RETURN + ENDIF + + IF (KROUND == 2 .AND. NCALL <= 1) THEN + IF (JRSIGN == -1) RETURN + DO J = ND+2+KSHIFT, ND+1+NGUARD+KSHIFT + IF (MW(J) > 0) THEN + MW(ND+1+KSHIFT) = MW(ND+1+KSHIFT) + 1 + MW(ND+2+KSHIFT) = 0 + IF (MW(ND+1+KSHIFT) < MBASE) RETURN + L = ND + 2 + KSHIFT + GO TO 120 + ENDIF + ENDDO + RETURN + ENDIF + + IF (KROUND == 0 .AND. NCALL <= 1) RETURN + L = ND + 2 + KSHIFT + IF (2*(MW(L)+1) < MBASE) RETURN + IF (2*MW(L) > MBASE) THEN + MW(L-1) = MW(L-1) + 1 + MW(L) = 0 + IF (MW(L-1) < MBASE) RETURN + GO TO 120 + ENDIF + +! If the first guard digit gives a value close to 1/2 then +! further guard digits must be examined. + + M2 = 2 + IF (INT(MBASE-AINT (MBASE/M2)*M2) == 0) THEN + IF (2*MW(L) < MBASE) RETURN + IF (2*MW(L) == MBASE) THEN + IF (NGUARD >= 2) THEN + IF (MBASE >= 1000) THEN + IF (MBASE < 1000000) THEN + MFACTR = INT(0.5D0+0.6883D0*MBASE) + ELSE + MFACTR = INT(0.5D0+0.687783D0*MBASE) + ENDIF + IF (MW(L+1) == MFACTR) RETURN + ENDIF + DO J = 2, NGUARD + IF (MW(L+J-1) > 0) GO TO 110 + ENDDO + ENDIF + +! Round to even. + + IF (INT(MW(L-1)-AINT (MW(L-1)/M2)*M2) == 0) RETURN + ENDIF + ELSE + IF (2*MW(L)+1 == MBASE) THEN + IF (NGUARD >= 2) THEN + DO J = 2, NGUARD + IF (2*(MW(L+J-1)+1) < MBASE) RETURN + IF (2*MW(L+J-1) > MBASE) GO TO 110 + ENDDO + IF (NGUARD <= NDIG) RETURN + M2 = 2 + IF (INT(MW(L-1)-AINT (MW(L-1)/M2)*M2) == 0) THEN + RETURN + ELSE + GO TO 110 + ENDIF + ENDIF + ENDIF + ENDIF + + 110 MW(L-1) = MW(L-1) + 1 + MW(L) = 0 + +! Check whether there was a carry in the rounded digit. + + 120 KB = L - 1 + IF (KB >= 3) THEN + K = KB + 1 + DO J = 3, KB + K = K - 1 + IF (MW(K) < MBASE) RETURN + MKT = AINT (MW(K)/MBASE) + MW(K-1) = MW(K-1) + MKT + MW(K) = MW(K) - MKT*MBASE + ENDDO + ENDIF + +! If there is a carry in the first digit then the exponent +! must be adjusted and the number shifted right. + + IF (MW(2) >= MBASE) THEN + IF (KB >= 4) THEN + K = KB + 1 + DO J = 4, KB + K = K - 1 + MW(K) = MW(K-1) + ENDDO + ENDIF + + MKT = AINT (MW(2)/MBASE) + IF (KB >= 3) MW(3) = MW(2) - MKT*MBASE + MW(2) = MKT + MW(1) = MW(1) + 1 + ENDIF + + RETURN + END SUBROUTINE FMRND + + SUBROUTINE FMRPWR(MA,IVAL,JVAL,MB) + +! MB = MA ** (IVAL/JVAL) rational exponentiation. + +! This routine is faster than FMPWR when IVAL and JVAL are +! small integers. + + USE FMVALS + IMPLICIT NONE + + REAL (KIND(1.0D0)) :: MA(-1:LUNPCK),MB(-1:LUNPCK) + INTEGER IVAL,JVAL + DOUBLE PRECISION X,F + REAL (KIND(1.0D0)) :: MA1,MA2,MAS,MACCA,MACMAX,MXSAVE + INTEGER NSTACK(19),IJSIGN,INVERT,IVAL2,J,JVAL2,K,KASAVE,KOVUN, & + KRESLT,KST,KWRNSV,L,LVAL,NDSAVE + REAL XVAL + + IF (MBLOGS /= MBASE) CALL FMCONS + NCALL = NCALL + 1 + NAMEST(NCALL) = 'FMRPWR' + IF (NTRACE /= 0) THEN + CALL FMNTR(2,MA,MA,1,1) + CALL FMNTRI(2,IVAL,0) + CALL FMNTRI(2,JVAL,0) + ENDIF + KOVUN = 0 + IF (MA(1) == MEXPOV .OR. MA(1) == MEXPUN) KOVUN = 1 + NDSAVE = NDIG + IF (NCALL == 1) THEN + XVAL = MAX(ABS(IVAL),ABS(JVAL)) + IF (XVAL == 0.0) XVAL = 1.0 + K = INT((5.0*REAL(DLOGTN) + 2.0*LOG(XVAL))/ALOGMB + 2.0) + NDIG = MAX(NDIG+K,2) + IF (MBASE < 1000 .OR. KROUND /= 1 .OR. KRPERF == 1) THEN + NDIG = MIN(NDG2MX,MAX(NDIG,2*NDSAVE+10)) + ENDIF + ELSE + XVAL = MAX(ABS(IVAL),ABS(JVAL)) + IF (XVAL == 0.0) XVAL = 1.0 + K = INT(LOG(XVAL)/ALOGMB + 1.0) + NDIG = NDIG + K + ENDIF + IF (NDIG > NDG2MX) THEN + KFLAG = -9 + CALL FMWARN + NDIG = NDSAVE + KRESLT = 12 + CALL FMRSLT(MA,MA,MB,KRESLT) + IF (NTRACE /= 0) CALL FMNTR(1,MB,MB,1,1) + NCALL = NCALL - 1 + RETURN + ENDIF + KASAVE = KACCSW + KACCSW = 0 + MXSAVE = MXEXP + MXEXP = MXEXP2 + + MAS = MA(-1) + MA1 = MA(1) + MA2 = MA(2) + MACCA = MA(0) + CALL FMEQ2(MA,M02,NDSAVE,NDIG) + M02(0) = NINT(NDIG*ALOGM2) + +! Use GCD-reduced positive exponents. + + IJSIGN = 1 + IVAL2 = ABS(IVAL) + JVAL2 = ABS(JVAL) + IF (IVAL > 0 .AND. JVAL < 0) IJSIGN = -1 + IF (IVAL < 0 .AND. JVAL > 0) IJSIGN = -1 + IF (IVAL2 > 0 .AND. JVAL2 > 0) CALL FMGCDI(IVAL2,JVAL2) + +! Check for special cases. + + 110 IF (MA1 == MUNKNO .OR. JVAL2 == 0 .OR. & + (IJSIGN <= 0 .AND. MA2 == 0)) THEN + CALL FMST2M('UNKNOWN',MB) + KFLAG = -4 + GO TO 120 + ENDIF + + IF (IVAL2 == 0) THEN + CALL FMIM(1,MB) + GO TO 120 + ENDIF + + IF (JVAL2 == 1) THEN + CALL FMIPWR(M02,IJSIGN*IVAL2,MB) + GO TO 120 + ENDIF + + IF (MA2 == 0) THEN + CALL FMEQ(MA,MB) + GO TO 120 + ENDIF + + IF (MAS < 0) THEN + IF (MOD(JVAL2,2) == 0) THEN + JVAL2 = 0 + GO TO 110 + ENDIF + ENDIF + + IF (MA1 == MEXPOV) THEN + IF (IVAL2 < JVAL2) THEN + JVAL2 = 0 + GO TO 110 + ENDIF + CALL FMIM(0,MB) + IF (IJSIGN == 1 .AND. MAS > 0) THEN + CALL FMST2M('OVERFLOW',MB) + KFLAG = -5 + ELSE IF (IJSIGN == -1 .AND. MAS > 0) THEN + CALL FMST2M('UNDERFLOW',MB) + KFLAG = -6 + ELSE IF (IJSIGN == 1 .AND. MAS < 0) THEN + IF (MOD(IVAL2,2) == 0) THEN + CALL FMST2M('OVERFLOW',MB) + KFLAG = -5 + ELSE + CALL FMST2M('-OVERFLOW',MB) + KFLAG = -5 + ENDIF + ELSE IF (IJSIGN == -1 .AND. MAS < 0) THEN + IF (MOD(IVAL2,2) == 0) THEN + CALL FMST2M('UNDERFLOW',MB) + KFLAG = -6 + ELSE + CALL FMST2M('-UNDERFLOW',MB) + KFLAG = -6 + ENDIF + ENDIF + GO TO 120 + ENDIF + + IF (MA1 == MEXPUN) THEN + IF (IVAL2 < JVAL2) THEN + JVAL2 = 0 + GO TO 110 + ENDIF + CALL FMIM(0,MB) + IF (IJSIGN == 1 .AND. MAS > 0) THEN + CALL FMST2M('UNDERFLOW',MB) + KFLAG = -6 + ELSE IF (IJSIGN == -1 .AND. MAS > 0) THEN + CALL FMST2M('OVERFLOW',MB) + KFLAG = -5 + ELSE IF (IJSIGN == 1 .AND. MAS < 0) THEN + IF (MOD(IVAL2,2) == 0) THEN + CALL FMST2M('UNDERFLOW',MB) + KFLAG = -6 + ELSE + CALL FMST2M('-UNDERFLOW',MB) + KFLAG = -6 + ENDIF + ELSE IF (IJSIGN == -1 .AND. MAS < 0) THEN + IF (MOD(IVAL2,2) == 0) THEN + CALL FMST2M('OVERFLOW',MB) + KFLAG = -5 + ELSE + CALL FMST2M('-OVERFLOW',MB) + KFLAG = -5 + ENDIF + ENDIF + GO TO 120 + ENDIF + +! Invert MA if MA > 1 and IVAL or JVAL is large. + + INVERT = 0 + IF (MA(1) > 0) THEN + IF (IVAL > 5 .OR. JVAL > 5) THEN + INVERT = 1 + CALL FMI2M(1,M01) + CALL FMDIV_R2(M01,M02) + ENDIF + ENDIF + +! Generate the first approximation to ABS(MA)**(1/JVAL2). + + MA1 = M02(1) + M02(1) = 0 + M02(-1) = 1 + CALL FMM2DP(M02,X) + L = INT(MA1/JVAL2) + F = MA1/DBLE(JVAL2) - L + X = X**(1.0D0/JVAL2) * DBLE(MBASE)**F + CALL FMDPM(X,MB) + MB(1) = MB(1) + L + M02(1) = MA1 + +! Initialize. + + CALL FMDIG(NSTACK,KST) + +! Newton iteration. + + DO J = 1, KST + NDIG = NSTACK(J) + IF (J < KST) NDIG = NDIG + 1 + LVAL = JVAL2 - 1 + CALL FMIPWR(MB,LVAL,M03) + CALL FMDIV_R2(M02,M03) + CALL FMMPYI_R1(MB,LVAL) + CALL FMADD_R1(MB,M03) + CALL FMDIVI_R1(MB,JVAL2) + ENDDO + + IF (MB(1) /= MUNKNO .AND. MB(2) /= 0 .AND. MAS < 0) MB(-1) = -MB(-1) + CALL FMIPWR(MB,IJSIGN*IVAL2,M03) + CALL FMEQ(M03,MB) + IF (INVERT == 1) THEN + CALL FMI2M(1,M01) + CALL FMDIV_R2(M01,MB) + ENDIF + +! Round the result and return. + + 120 MACMAX = NINT((NDSAVE-1)*ALOGM2 + LOG(REAL(ABS(MB(2))+1))/0.69315) + MB(0) = MIN(MACCA,MACMAX) + KWRNSV = KWARN + IF (MA1 == MUNKNO) KWARN = 0 + DO J = -1, NDIG+1 + M01(J) = MB(J) + ENDDO + CALL FMEXIT(M01,MB,NDSAVE,MXSAVE,KASAVE,KOVUN) + KWARN = KWRNSV + RETURN + END SUBROUTINE FMRPWR + + SUBROUTINE FMRSLT(MA,MB,MC,KRESLT) + +! Handle results that are special cases, such as overflow, +! underflow, and unknown. + +! MA and MB are the input arguments to an FM subroutine. + +! MC is the result that is returned. + +! KRESLT is the result code from FMARGS. Result codes handled here: + +! 0 - Perform the normal operation +! 1 - The result is the first input argument +! 2 - The result is the second input argument +! 3 - The result is -OVERFLOW +! 4 - The result is +OVERFLOW +! 5 - The result is -UNDERFLOW +! 6 - The result is +UNDERFLOW +! 7 - The result is -1.0 +! 8 - The result is +1.0 +! 11 - The result is 0.0 +! 12 - The result is UNKNOWN + + USE FMVALS + IMPLICIT NONE + + REAL (KIND(1.0D0)) :: MA(-1:LUNPCK),MB(-1:LUNPCK),MC(-1:LUNPCK) + INTEGER KRESLT + + REAL (KIND(1.0D0)) :: MACCAB,MACCSV + INTEGER KFSAVE + + KFSAVE = KFLAG + MACCAB = MIN(MA(0),MB(0)) + IF (KRESLT == 1) THEN + MACCSV = MA(0) + CALL FMEQ(MA,MC) + MC(0) = MACCAB + IF (NAMEST(NCALL) == 'FMADD ' .OR. & + NAMEST(NCALL) == 'FMSUB ') THEN + KFLAG = 1 + MC(0) = MACCSV + ELSE + KFLAG = KFSAVE + ENDIF + RETURN + ENDIF + + IF (KRESLT == 2) THEN + MACCSV = MB(0) + CALL FMEQ(MB,MC) + MC(0) = MACCAB + IF (NAMEST(NCALL) == 'FMADD ') THEN + KFLAG = 1 + MC(0) = MACCSV + ELSE + KFLAG = KFSAVE + ENDIF + IF (NAMEST(NCALL) == 'FMSUB ') THEN + IF (MC(1) /= MUNKNO .AND. MC(2) /= 0) MC(-1) = -MC(-1) + KFLAG = KFSAVE + MC(0) = MACCSV + ENDIF + RETURN + ENDIF + + IF (KRESLT == 3 .OR. KRESLT == 4) THEN + CALL FMIM(0,MC) + MC(1) = MEXPOV + MC(2) = 1 + MC(0) = NINT(NDIG*ALOGM2) + IF (KRESLT == 3) MC(-1) = -1 + MC(0) = MACCAB + KFLAG = KFSAVE + RETURN + ENDIF + + IF (KRESLT == 5 .OR. KRESLT == 6) THEN + CALL FMIM(0,MC) + MC(1) = MEXPUN + MC(2) = 1 + MC(0) = NINT(NDIG*ALOGM2) + IF (KRESLT == 5) MC(-1) = -1 + MC(0) = MACCAB + KFLAG = KFSAVE + RETURN + ENDIF + + IF (KRESLT == 7) THEN + CALL FMIM(-1,MC) + MC(0) = MACCAB + KFLAG = KFSAVE + RETURN + ENDIF + + IF (KRESLT == 8) THEN + CALL FMIM(1,MC) + MC(0) = MACCAB + KFLAG = KFSAVE + RETURN + ENDIF + + IF (KRESLT == 11) THEN + CALL FMIM(0,MC) + MC(0) = MACCAB + KFLAG = KFSAVE + RETURN + ENDIF + + IF (KRESLT == 12 .OR. KRESLT < 0 .OR. KRESLT > 15) THEN + CALL FMIM(0,MC) + MC(1) = MUNKNO + MC(2) = 1 + MC(0) = NINT(NDIG*ALOGM2) + MC(0) = MACCAB + KFLAG = KFSAVE + RETURN + ENDIF + + RETURN + END SUBROUTINE FMRSLT + + SUBROUTINE FMSETVAR(STRING) + +! Change the value of one of the internal FM variables. +! STRING must have the format ' variablename = value ', with no +! embedded blanks in variablename. + + USE FMVALS + IMPLICIT NONE + CHARACTER(*) :: STRING + CHARACTER(6) :: VARNAME + INTEGER IVAL,J,KPTEQ,KPT1,KPT2 + DOUBLE PRECISION DVAL + REAL (KIND(1.0D0)) :: MVAL + + CHARACTER(52) :: LETTERS = & + 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz' + +! Find the equal sign. + + KPTEQ = INDEX(STRING,'=') + IF (KPTEQ <= 0) THEN + WRITE (KW,*) ' ' + WRITE (KW,*) ' Cannot find the equal sign in FMSETVAR.' + WRITE (KW,*) ' Input string: ',STRING + RETURN + ENDIF + +! Find the variable name. + + KPT1 = 0 + KPT2 = 0 + DO J = 1, KPTEQ-1 + IF (KPT1 == 0 .AND. STRING(J:J) /= ' ') KPT1 = J + ENDDO + DO J = KPTEQ-1, 1, -1 + IF (KPT2 == 0 .AND. STRING(J:J) /= ' ') KPT2 = J + ENDDO + IF (KPT1 == 0) THEN + WRITE (KW,*) ' ' + WRITE (KW,*) ' Cannot find the variable name in FMSETVAR.' + WRITE (KW,*) ' Input string: ',STRING + RETURN + ENDIF + VARNAME = ' ' + DO J = KPT1, KPT2 + IVAL = INDEX(LETTERS,STRING(J:J)) + IF (IVAL > 26 .AND. IVAL <= 52) THEN + VARNAME(J-KPT1+1:J-KPT1+1) = LETTERS(IVAL-26:IVAL-26) + ELSE + VARNAME(J-KPT1+1:J-KPT1+1) = STRING(J:J) + ENDIF + ENDDO + +! CMCHAR is a special case, since the value is a character. + + IF (VARNAME == 'CMCHAR') THEN + KPT1 = 0 + KPT2 = 0 + DO J = KPTEQ+1, LEN(STRING) + IF (KPT1 == 0 .AND. STRING(J:J) /= ' ') KPT1 = J + ENDDO + DO J = LEN(STRING), KPTEQ+1, -1 + IF (KPT2 == 0 .AND. STRING(J:J) /= ' ') KPT2 = J + ENDDO + IF (KPT1 == KPT2 .AND. INDEX(LETTERS,STRING(KPT1:KPT2)) > 0) THEN + CMCHAR = STRING(KPT1:KPT2) + ELSE + WRITE (KW,*) ' ' + WRITE (KW,*) ' Only a single letter is allowed after the', & + ' equal sign in FMSETVAR.' + WRITE (KW,*) ' Input string: ',STRING + RETURN + ENDIF + ENDIF + +! Convert the value after the equal sign. + + IF (KPTEQ+1 <= LEN(STRING)) THEN + IF (INDEX(STRING(KPTEQ+1:LEN(STRING)),'=') /= 0) THEN + WRITE (KW,*) ' ' + WRITE (KW,*) ' Only a single equal sign is allowed in FMSETVAR.' + WRITE (KW,*) ' Input string: ',STRING + RETURN + ENDIF + CALL FMST2D(STRING(KPTEQ+1:LEN(STRING)),DVAL) + IF (KFLAG /= 0) THEN + WRITE (KW,*) ' ' + WRITE (KW,*) ' Invalid value after the equal sign in', & + ' FMSETVAR.' + WRITE (KW,*) ' Input string: ',STRING + RETURN + ENDIF + ELSE + WRITE (KW,*) ' ' + WRITE (KW,*) ' Cannot find a value after the equal sign in', & + ' FMSETVAR.' + WRITE (KW,*) ' Input string: ',STRING + RETURN + ENDIF + +! Check the list of variable names. + + IF (VARNAME == 'JFORM1') THEN + JFORM1 = NINT(DVAL) + IF (JFORM1 < 0 .OR. JFORM1 > 2) THEN + WRITE (KW,*) ' ' + WRITE (KW,*) ' FMSETVAR: Input string: ',STRING + WRITE (KW,*) ' ',JFORM1, & + ' is an invalid value for JFORM1' + JFORM1 = 1 + WRITE (KW,*) ' Valid values are 0,1,2.', & + ' JFORM1 was set to ',JFORM1 + ENDIF + ELSE IF (VARNAME == 'JFORM2') THEN + JFORM2 = NINT(DVAL) + IF (JFORM2 < 0) THEN + WRITE (KW,*) ' ' + WRITE (KW,*) ' FMSETVAR: Input string: ',STRING + WRITE (KW,*) ' ',JFORM2, & + ' is an invalid value for JFORM2' + JFORM2 = 1 + WRITE (KW,*) ' It should be nonegative.', & + ' JFORM2 was set to ',JFORM2 + ENDIF + ELSE IF (VARNAME == 'JFORMZ') THEN + JFORMZ = NINT(DVAL) + IF (JFORMZ < 1 .OR. JFORMZ > 3) THEN + WRITE (KW,*) ' ' + WRITE (KW,*) ' FMSETVAR: Input string: ',STRING + WRITE (KW,*) ' ',JFORMZ, & + ' is an invalid value for JFORMZ' + JFORMZ = 1 + WRITE (KW,*) ' Valid values are 1,2,3.', & + ' JFORMZ was set to ',JFORMZ + ENDIF + ELSE IF (VARNAME == 'JPRNTZ') THEN + JPRNTZ = NINT(DVAL) + IF (JPRNTZ < 1 .OR. JPRNTZ > 2) THEN + WRITE (KW,*) ' ' + WRITE (KW,*) ' FMSETVAR: Input string: ',STRING + WRITE (KW,*) ' ',JPRNTZ, & + ' is an invalid value for JPRNTZ' + JPRNTZ = 1 + WRITE (KW,*) ' Valid values are 1,2.', & + ' JPRNTZ was set to ',JPRNTZ + ENDIF + ELSE IF (VARNAME == 'KACCSW') THEN + KACCSW = NINT(DVAL) + IF (KACCSW < 0 .OR. KACCSW > 1) THEN + WRITE (KW,*) ' ' + WRITE (KW,*) ' FMSETVAR: Input string: ',STRING + WRITE (KW,*) ' ',KACCSW, & + ' is an invalid value for KACCSW' + KACCSW = 0 + WRITE (KW,*) ' Valid values are 0,1.', & + ' KACCSW was set to ',KACCSW + ENDIF + ELSE IF (VARNAME == 'KDEBUG') THEN + KDEBUG = NINT(DVAL) + IF (KDEBUG < 0 .OR. KDEBUG > 1) THEN + WRITE (KW,*) ' ' + WRITE (KW,*) ' FMSETVAR: Input string: ',STRING + WRITE (KW,*) ' ',KDEBUG, & + ' is an invalid value for KDEBUG' + KDEBUG = 1 + WRITE (KW,*) ' Valid values are 0,1.', & + ' KDEBUG was set to ',KDEBUG + ENDIF + ELSE IF (VARNAME == 'KESWCH') THEN + KESWCH = NINT(DVAL) + IF (KESWCH < 0 .OR. KESWCH > 1) THEN + WRITE (KW,*) ' ' + WRITE (KW,*) ' FMSETVAR: Input string: ',STRING + WRITE (KW,*) ' ',KESWCH, & + ' is an invalid value for KESWCH' + KESWCH = 1 + WRITE (KW,*) ' Valid values are 0,1.', & + ' KESWCH was set to ',KESWCH + ENDIF + ELSE IF (VARNAME == 'KRAD ') THEN + KRAD = NINT(DVAL) + IF (KRAD < 0 .OR. KRAD > 1) THEN + WRITE (KW,*) ' ' + WRITE (KW,*) ' FMSETVAR: Input string: ',STRING + WRITE (KW,*) ' ',KRAD, & + ' is an invalid value for KRAD' + KRAD = 1 + WRITE (KW,*) ' Valid values are 0,1.', & + ' KRAD was set to ',KRAD + ENDIF + ELSE IF (VARNAME == 'KROUND') THEN + KROUND = NINT(DVAL) + IF (KROUND < -1 .OR. KROUND > 2) THEN + WRITE (KW,*) ' ' + WRITE (KW,*) ' FMSETVAR: Input string: ',STRING + WRITE (KW,*) ' ',KROUND, & + ' is an invalid value for KROUND' + KROUND = 1 + WRITE (KW,*) ' Valid values are -1,0,1,2.', & + ' KROUND was set to ',KROUND + ENDIF + ELSE IF (VARNAME == 'KRPERF') THEN + KRPERF = NINT(DVAL) + IF (KRPERF < 0 .OR. KRPERF > 1) THEN + WRITE (KW,*) ' ' + WRITE (KW,*) ' FMSETVAR: Input string: ',STRING + WRITE (KW,*) ' ',KRPERF, & + ' is an invalid value for KRPERF' + KRPERF = 0 + WRITE (KW,*) ' Valid values are 0,1.', & + ' KRPERF was set to ',KRPERF + ENDIF + ELSE IF (VARNAME == 'KSWIDE') THEN + KSWIDE = NINT(DVAL) + IF (KSWIDE < 10) THEN + WRITE (KW,*) ' ' + WRITE (KW,*) ' FMSETVAR: Input string: ',STRING + WRITE (KW,*) ' ',KSWIDE, & + ' is an invalid value for KSWIDE' + KSWIDE = 80 + WRITE (KW,*) ' It should be 10 or more.', & + ' KSWIDE was set to ',KSWIDE + ENDIF + ELSE IF (VARNAME == 'KW ') THEN + KW = NINT(DVAL) + ELSE IF (VARNAME == 'KWARN ') THEN + KWARN = NINT(DVAL) + IF (KWARN < 0 .OR. KWARN > 2) THEN + WRITE (KW,*) ' ' + WRITE (KW,*) ' FMSETVAR: Input string: ',STRING + WRITE (KW,*) ' ',KWARN, & + ' is an invalid value for KWARN' + KWARN = 1 + WRITE (KW,*) ' Valid values are 0,1,2.', & + ' KWARN was set to ',KWARN + ENDIF + ELSE IF (VARNAME == 'LVLTRC') THEN + LVLTRC = NINT(DVAL) + IF (LVLTRC < 0) THEN + WRITE (KW,*) ' ' + WRITE (KW,*) ' FMSETVAR: Input string: ',STRING + WRITE (KW,*) ' ',LVLTRC, & + ' is an invalid value for LVLTRC' + LVLTRC = 1 + WRITE (KW,*) ' It should be nonegative.', & + ' LVLTRC was set to ',LVLTRC + ENDIF + ELSE IF (VARNAME == 'NDIG ') THEN + IVAL = NDIG + NDIG = NINT(DVAL) + IF (NDIG < 2) THEN + WRITE (KW,*) ' ' + WRITE (KW,*) ' FMSETVAR: Input string: ',STRING + WRITE (KW,*) ' ',NDIG, & + ' is an invalid value for NDIG' + NDIG = IVAL + WRITE (KW,*) ' It should be > 1.', & + ' NDIG was not changed from ',NDIG + ENDIF + IF (NDIG > NDIGMX) THEN + WRITE (KW,*) ' ' + WRITE (KW,*) ' FMSETVAR: Input string: ',STRING + WRITE (KW,*) ' ',NDIG, & + ' is an invalid value for NDIG' + NDIG = NDIGMX + WRITE (KW,*) ' It should be <=',NDIGMX, & + '. NDIG was set to ',NDIG + ENDIF + ELSE IF (VARNAME == 'NTRACE') THEN + NTRACE = NINT(DVAL) + IF (NTRACE < -2 .OR. NTRACE > 2) THEN + WRITE (KW,*) ' ' + WRITE (KW,*) ' FMSETVAR: Input string: ',STRING + WRITE (KW,*) ' ',NTRACE, & + ' is an invalid value for NTRACE' + NTRACE = 0 + WRITE (KW,*) ' Valid values are -2,-1,0,1,2.', & + ' NTRACE was set to ',NTRACE + ENDIF + ELSE IF (VARNAME == 'MBASE ') THEN + MVAL = MBASE + MBASE = ANINT (DVAL) + IF (MBASE < 2) THEN + WRITE (KW,*) ' ' + WRITE (KW,*) ' FMSETVAR: Input string: ',STRING + WRITE (KW,*) ' ',MBASE, & + ' is an invalid value for MBASE' + MBASE = MVAL + WRITE (KW,*) ' It should be > 1.', & + ' MBASE was not changed from ',MBASE + ENDIF + ELSE IF (VARNAME == 'MXEXP ') THEN + MXEXP = AINT (DVAL) + IF (MXEXP < 10 .OR. MXEXP > MXEXP2/2.01D0) THEN + WRITE (KW,*) ' ' + WRITE (KW,*) ' FMSETVAR: Input string: ',STRING + WRITE (KW,*) ' ',MXEXP, & + ' is an invalid value for MXEXP' + MXEXP = INT(MXEXP2/2.01D0) + WRITE (KW,*) ' Valid values are 10 to ', & + INT(MXEXP2/2.01D0),' MXEXP was set to ',MXEXP + ENDIF + ELSE + WRITE (KW,*) ' Variable name not recognized in FMSETVAR.' + WRITE (KW,*) ' Input string: ',STRING + RETURN + ENDIF + + CALL FMCONS + RETURN + END SUBROUTINE FMSETVAR + + SUBROUTINE FMSIGN(MA,MB,MC) + +! MC = SIGN(MA,MB) + +! MC is set to ABS(MA) if MB is positive or zero, +! or -ABS(MA) if MB is negative. + + USE FMVALS + IMPLICIT NONE + + REAL (KIND(1.0D0)) :: MA(-1:LUNPCK),MB(-1:LUNPCK),MC(-1:LUNPCK) + + INTEGER KWRNSV + + KFLAG = 0 + NCALL = NCALL + 1 + NAMEST(NCALL) = 'FMSIGN' + IF (NTRACE /= 0) CALL FMNTR(2,MA,MB,2,1) + + KWRNSV = KWARN + KWARN = 0 + IF (MA(1) == MUNKNO .OR. MB(1) == MUNKNO) THEN + CALL FMST2M('UNKNOWN',MC) + KFLAG = -4 + ELSE IF (MB(-1) >= 0) THEN + CALL FMEQ(MA,MC) + MC(-1) = 1 + ELSE + CALL FMEQ(MA,MC) + IF (MC(1) /= MUNKNO .AND. MC(2) /= 0) MC(-1) = -1 + ENDIF + + KWARN = KWRNSV + IF (NTRACE /= 0) CALL FMNTR(1,MC,MC,1,1) + NCALL = NCALL - 1 + RETURN + END SUBROUTINE FMSIGN + + SUBROUTINE FMSIN(MA,MB) + +! MB = SIN(MA) + + USE FMVALS + IMPLICIT NONE + + REAL (KIND(1.0D0)) :: MA(-1:LUNPCK),MB(-1:LUNPCK) + REAL (KIND(1.0D0)) :: MACCA,MACMAX,MAS,MXSAVE + INTEGER J,JCOS,JSIN,JSWAP,K,KASAVE,KOVUN,KRESLT,KWRNSV,NDSAVE,NDSV + + IF (MBLOGS /= MBASE) CALL FMCONS + IF (ABS(MA(1)) > MEXPAB .OR. MA(2) == 0) THEN + CALL FMENTR('FMSIN ',MA,MA,1,1,MB,KRESLT,NDSAVE,MXSAVE,KASAVE, & + KOVUN) + IF (KRESLT /= 0) RETURN + ELSE + NCALL = NCALL + 1 + NAMEST(NCALL) = 'FMSIN ' + IF (NTRACE /= 0) CALL FMNTR(2,MA,MA,1,1) + KOVUN = 0 + IF (MA(1) == MEXPOV .OR. MA(1) == MEXPUN) KOVUN = 1 + NDSAVE = NDIG + IF (NCALL == 1) THEN + K = MAX(NGRD52,2) + NDIG = MAX(NDIG+K,2) + IF (NDIG > NDG2MX) THEN + KFLAG = -9 + CALL FMWARN + NDIG = NDSAVE + KRESLT = 12 + CALL FMRSLT(MA,MA,MB,KRESLT) + IF (NTRACE /= 0) CALL FMNTR(1,MB,MB,1,1) + NCALL = NCALL - 1 + RETURN + ENDIF + ENDIF + KASAVE = KACCSW + KACCSW = 0 + MXSAVE = MXEXP + MXEXP = MXEXP2 + ENDIF + + MACCA = MA(0) + MAS = MA(-1) + CALL FMEQ2(MA,MB,NDSAVE,NDIG) + MB(0) = NINT(NDIG*ALOGM2) + MB(-1) = 1 + CALL FMEQ(MB,MWE) + KWRNSV = KWARN + KWARN = 0 + +! Reduce the argument, convert to radians if the input is +! in degrees, and evaluate the function. + + CALL FMRDC(MB,JSIN,JCOS,JSWAP) + KWARN = KWRNSV + IF (MB(1) == MUNKNO) THEN + IF (KRAD /= 1 .OR. JSWAP == 0) THEN + CALL FMEQ(MWE,MB) + CALL FMRDC(MB,JSIN,JCOS,JSWAP) + GO TO 110 + ENDIF + IF (MBSPI /= MBASE .OR. NDIGPI < NDIG) THEN + NDSV = NDIG + NDIG = MIN(NDIG+2,NDG2MX) + NCALL = NCALL + 1 + NAMEST(NCALL) = 'NOEQ ' + CALL FMPI(MPISAV) + NCALL = NCALL - 1 + NDIG = NDSV + ENDIF + CALL FMDIV(MWE,MPISAV,M04) + CALL FMMPYI_R1(M04,2) + CALL FMNINT(M04,M03) + CALL FMMPY(M03,MPISAV,M02) + CALL FMDIVI_R1(M02,2) + CALL FMSUB_R2(MWE,M02) + IF (M02(2) == 0) CALL FMULP(MWE,M02) + CALL FMI2M(1,M04) + CALL FMSQR_R1(M02) + CALL FMDIVI_R1(M02,2) + CALL FMSUB_R2(M04,M02) + CALL FMSUB_R1(M02,M04) + IF (M02(2) == 0) THEN + CALL FMI2M(JSIN,MB) + ELSE + CALL FMEQ(MWE,MB) + CALL FMRDC(MB,JSIN,JCOS,JSWAP) + ENDIF + GO TO 110 + ENDIF + IF (KRAD == 0) THEN + IF (MBSPI /= MBASE .OR. NDIGPI < NDIG) THEN + NDSV = NDIG + NDIG = MIN(NDIG+2,NDG2MX) + NCALL = NCALL + 1 + NAMEST(NCALL) = 'NOEQ ' + CALL FMPI(MPISAV) + NCALL = NCALL - 1 + NDIG = NDSV + ENDIF + CALL FMMPY_R1(MB,MPISAV) + CALL FMDIVI_R1(MB,180) + ENDIF + IF (MB(1) /= MUNKNO) THEN + IF (JSWAP == 0) THEN + IF (MB(1) < 0 .OR. NDIG <= 50) THEN + CALL FMSIN2(MB,M09) + CALL FMEQ(M09,MB) + ELSE + CALL FMCOS2(MB,M09) + CALL FMEQ(M09,MB) + CALL FMI2M(1,M03) + CALL FMSQR_R1(MB) + CALL FMSUB_R2(M03,MB) + CALL FMSQRT_R1(MB) + ENDIF + ELSE + CALL FMCOS2(MB,M09) + CALL FMEQ(M09,MB) + ENDIF + ENDIF + +! Append the sign, round, and return. + + IF (JSIN == -1 .AND. MB(1) /= MUNKNO .AND. MB(2) /= 0) MB(-1) = -MB(-1) + 110 MACMAX = NINT((NDSAVE-1)*ALOGM2 + LOG(REAL(ABS(MB(2))+1))/0.69315) + MB(0) = MIN(MB(0),MACCA,MACMAX) + IF (MAS < 0 .AND. MB(1) /= MUNKNO .AND. MB(2) /= 0) MB(-1) = -MB(-1) + DO J = -1, NDIG+1 + M01(J) = MB(J) + ENDDO + CALL FMEXIT(M01,MB,NDSAVE,MXSAVE,KASAVE,KOVUN) + RETURN + END SUBROUTINE FMSIN + + SUBROUTINE FMSIN2(MA,MB) + +! Internal subroutine for MB = SIN(MA) where 0 <= MA <= 1. + + USE FMVALS + IMPLICIT NONE + + REAL (KIND(1.0D0)) :: MA(-1:LUNPCK),MB(-1:LUNPCK) +! LJSUMS = 8*(LUNPCK+1) allows for up to eight concurrent +! sums. Increasing this value will begin to improve the +! speed of SIN when the base is large and precision exceeds +! about 1,500 decimal digits. + + REAL (KIND(1.0D0)) :: MAXVAL + INTEGER J,J2,K,K2,KPT,KTHREE,KWRNSV,L,L2,LARGE,N2,NBOT,NDSAV1, & + NDSAVE,NTERM + REAL ALOG3,ALOGT,B,T,TJ + + IF (MBLOGS /= MBASE) CALL FMCONS + IF (MA(2) == 0) THEN + CALL FMEQ(MA,MB) + RETURN + ENDIF + NDSAVE = NDIG + KWRNSV = KWARN + KWARN = 0 + +! Use the direct series +! SIN(X) = X - X**3/3! + X**5/5! - ... + +! The argument will be divided by 3**K2 before the series +! is summed. The series will be added as J2 concurrent +! series. The approximately optimal values of K2 and J2 +! are now computed to try to minimize the time required. +! N2/2 is the approximate number of terms of the series +! that will be needed, and L2 guard digits will be carried. + + B = REAL(MBASE) + K = NGRD52 + T = MAX(NDIG-K,2) + ALOG3 = LOG(3.0) + ALOGT = LOG(T) + TJ = 0.05*ALOGMB*T**0.3333 + 1.85 + J2 = INT(TJ) + J2 = MAX(1,MIN(J2,LJSUMS/NDG2MX)) + K2 = INT(0.1*SQRT(T*ALOGMB/TJ) - 0.05*ALOGT + 2.5) + + L = INT(-(REAL(MA(1))*ALOGMB+LOG(REAL(MA(2))/B + & + REAL(MA(3))/(B*B)))/ALOG3 - 0.3) + K2 = K2 - L + IF (L < 0) L = 0 + IF (K2 < 0) THEN + K2 = 0 + J2 = INT(.43*SQRT(T*ALOGMB/(ALOGT+REAL(L)*ALOG3)) + .33) + ENDIF + IF (J2 <= 1) J2 = 1 + + N2 = INT(T*ALOGMB/(ALOGT+REAL(L)*ALOG3)) + L2 = INT(LOG(REAL(N2)+3.0**K2)/ALOGMB) + NDIG = NDIG + L2 + IF (NDIG > NDG2MX) THEN + IF (NCALL == 1) THEN + KFLAG = -9 + CALL FMWARN + NDIG = NDSAVE + CALL FMST2M('UNKNOWN',MB) + KWARN = KWRNSV + RETURN + ELSE + NDIG = NDG2MX + ENDIF + ENDIF + NDSAV1 = NDIG + +! Divide the argument by 3**K2. + + CALL FMEQ2(MA,M02,NDSAVE,NDIG) + KTHREE = 1 + MAXVAL = MXBASE/3 + IF (K2 > 0) THEN + DO J = 1, K2 + KTHREE = 3*KTHREE + IF (KTHREE > MAXVAL) THEN + CALL FMDIVI_R1(M02,KTHREE) + KTHREE = 1 + ENDIF + ENDDO + IF (KTHREE > 1) CALL FMDIVI_R1(M02,KTHREE) + ENDIF + +! Split into J2 concurrent sums and reduce NDIG while +! computing each term in the sum as the terms get smaller. + + CALL FMEQ(M02,M03) + NTERM = 1 + DO J = 1, J2 + NBOT = NTERM*(NTERM-1) + IF (NBOT > 1) CALL FMDIVI_R1(M03,NBOT) + NTERM = NTERM + 2 + KPT = (J-1)*(NDIG+3) + CALL FMEQ(M03,MJSUMS(KPT-1)) + IF (M03(1) /= MUNKNO .AND. M03(2) /= 0) M03(-1) = -M03(-1) + ENDDO + CALL FMSQR_R1(M02) + IF (M02(1) < -NDIG) GO TO 120 + CALL FMIPWR(M02,J2,MB) + + 110 CALL FMMPY_R1(M03,MB) + LARGE = INT(INTMAX/NTERM) + DO J = 1, J2 + NBOT = NTERM*(NTERM-1) + IF (NTERM > LARGE .OR. NBOT > MXBASE) THEN + CALL FMDIVI_R1(M03,NTERM) + NBOT = NTERM - 1 + CALL FMDIVI_R1(M03,NBOT) + ELSE + CALL FMDIVI_R1(M03,NBOT) + ENDIF + KPT = (J-1)*(NDSAV1+3) + NDIG = NDSAV1 + CALL FMADD_R1(MJSUMS(KPT-1),M03) + IF (KFLAG /= 0) GO TO 120 + NDIG = NDSAV1 - INT(MJSUMS(KPT+1)-M03(1)) + IF (NDIG < 2) NDIG = 2 + IF (M03(1) /= MUNKNO .AND. M03(2) /= 0) M03(-1) = -M03(-1) + NTERM = NTERM + 2 + ENDDO + GO TO 110 + +! Next put the J2 separate sums back together. + + 120 KFLAG = 0 + KPT = (J2-1)*(NDIG+3) + CALL FMEQ(MJSUMS(KPT-1),MB) + IF (J2 >= 2) THEN + DO J = 2, J2 + CALL FMMPY_R2(M02,MB) + KPT = (J2-J)*(NDIG+3) + CALL FMADD_R1(MB,MJSUMS(KPT-1)) + ENDDO + ENDIF + +! Reverse the effect of reducing the argument to +! compute SIN(MA). + + NDIG = NDSAV1 + IF (K2 > 0) THEN + CALL FMI2M(3,M02) + DO J = 1, K2 + CALL FMSQR(MB,M03) + CALL FMMPYI_R1(M03,-4) + CALL FMADD_R2(M02,M03) + CALL FMMPY_R2(M03,MB) + ENDDO + ENDIF + + CALL FMEQ2_R1(MB,NDSAV1,NDSAVE) + NDIG = NDSAVE + KWARN = KWRNSV + + RETURN + END SUBROUTINE FMSIN2 + + SUBROUTINE FMSINH(MA,MB) + +! MB = SINH(MA) + + USE FMVALS + IMPLICIT NONE + + REAL (KIND(1.0D0)) :: MA(-1:LUNPCK),MB(-1:LUNPCK) + REAL (KIND(1.0D0)) :: MACCA,MACMAX,MAS,MXSAVE + INTEGER J,K,KASAVE,KOVUN,KRESLT,NDSAVE,NMETHD + + IF (MBLOGS /= MBASE) CALL FMCONS + IF (ABS(MA(1)) > MEXPAB) THEN + CALL FMENTR('FMSINH',MA,MA,1,1,MB,KRESLT,NDSAVE,MXSAVE,KASAVE, & + KOVUN) + IF (KRESLT /= 0) RETURN + ELSE + NCALL = NCALL + 1 + NAMEST(NCALL) = 'FMSINH' + IF (NTRACE /= 0) CALL FMNTR(2,MA,MA,1,1) + KOVUN = 0 + IF (MA(1) == MEXPOV .OR. MA(1) == MEXPUN) KOVUN = 1 + NDSAVE = NDIG + IF (NCALL == 1) THEN + K = MAX(NGRD52,2) + NDIG = MAX(NDIG+K,2) + IF (NDIG > NDG2MX) THEN + KFLAG = -9 + CALL FMWARN + NDIG = NDSAVE + KRESLT = 12 + CALL FMRSLT(MA,MA,MB,KRESLT) + IF (NTRACE /= 0) CALL FMNTR(1,MB,MB,1,1) + NCALL = NCALL - 1 + RETURN + ENDIF + ENDIF + KASAVE = KACCSW + KACCSW = 0 + MXSAVE = MXEXP + MXEXP = MXEXP2 + ENDIF + + MACCA = MA(0) + MAS = MA(-1) + CALL FMEQ2(MA,MB,NDSAVE,NDIG) + IF (MA(2) == 0) THEN + GO TO 120 + ENDIF + MB(0) = NINT(NDIG*ALOGM2) + MB(-1) = 1 + +! Use a series for small arguments, FMEXP for large ones. + + IF (MB(1) == MUNKNO) GO TO 120 + IF (MBASE > 99) THEN + IF (MB(1) <= 0) THEN + NMETHD = 1 + ELSE IF (MB(1) >= 2) THEN + NMETHD = 2 + ELSE IF (ABS(MB(2)) < 10) THEN + NMETHD = 1 + ELSE + NMETHD = 2 + ENDIF + ELSE + IF (MB(1) <= 0) THEN + NMETHD = 1 + ELSE + NMETHD = 2 + ENDIF + ENDIF + + IF (NMETHD == 2) GO TO 110 + IF (MB(1) < 0 .OR. NDIG <= 50) THEN + CALL FMSNH2(MB,M09) + CALL FMEQ(M09,MB) + ELSE + CALL FMCSH2(MB,M09) + CALL FMEQ(M09,MB) + CALL FMI2M(1,M03) + CALL FMSQR_R1(MB) + CALL FMSUB_R1(MB,M03) + CALL FMSQRT_R1(MB) + ENDIF + GO TO 120 + + 110 CALL FMEXP(MB,M12) + CALL FMEQ(M12,MB) + IF (MB(1) == MEXPOV) THEN + GO TO 120 + ELSE IF (MB(1) == MEXPUN) THEN + MB(1) = MEXPOV + GO TO 120 + ENDIF + IF (INT(MB(1)) <= (NDIG+1)/2) THEN + CALL FMI2M(1,M01) + CALL FMDIV_R1(M01,MB) + CALL FMSUB_R1(MB,M01) + ENDIF + CALL FMDIVI_R1(MB,2) + +! Round and return. + + 120 MACMAX = NINT((NDSAVE-1)*ALOGM2 + LOG(REAL(ABS(MB(2))+1))/0.69315) + MB(0) = MIN(MB(0),MACCA,MACMAX) + IF (MAS < 0 .AND. MB(1) /= MUNKNO .AND. MB(2) /= 0) MB(-1) = -MB(-1) + DO J = -1, NDIG+1 + M01(J) = MB(J) + ENDDO + CALL FMEXIT(M01,MB,NDSAVE,MXSAVE,KASAVE,KOVUN) + RETURN + END SUBROUTINE FMSINH + + SUBROUTINE FMSNH2(MA,MB) + +! Internal subroutine for MB = SINH(MA). + + USE FMVALS + IMPLICIT NONE + + REAL (KIND(1.0D0)) :: MA(-1:LUNPCK),MB(-1:LUNPCK) +! LJSUMS = 8*(LUNPCK+1) allows for up to eight concurrent +! sums. Increasing this value will begin to improve the +! speed of SINH when the base is large and precision exceeds +! about 1,500 decimal digits. + + REAL (KIND(1.0D0)) :: MAXVAL + INTEGER J,J2,K,K2,KPT,KTHREE,KWRNSV,L,L2,LARGE,N2,NBOT,NDSAV1, & + NDSAVE,NTERM + REAL ALOG3,ALOGT,B,T,TJ + + IF (MBLOGS /= MBASE) CALL FMCONS + IF (MA(2) == 0) THEN + CALL FMEQ(MA,MB) + RETURN + ENDIF + NDSAVE = NDIG + KWRNSV = KWARN + KWARN = 0 + +! Use the direct series +! SINH(X) = X + X**3/3! + X**5/5! - ... + +! The argument will be divided by 3**K2 before the series +! is summed. The series will be added as J2 concurrent +! series. The approximately optimal values of K2 and J2 +! are now computed to try to minimize the time required. +! N2/2 is the approximate number of terms of the series +! that will be needed, and L2 guard digits will be carried. + + B = REAL(MBASE) + K = NGRD52 + T = MAX(NDIG-K,2) + ALOG3 = LOG(3.0) + ALOGT = LOG(T) + TJ = 0.05*ALOGMB*T**0.3333 + 1.85 + J2 = INT(TJ) + J2 = MAX(1,MIN(J2,LJSUMS/NDG2MX)) + K2 = INT(0.1*SQRT(T*ALOGMB/TJ) - 0.05*ALOGT + 2.5) + + L = INT(-(REAL(MA(1))*ALOGMB+LOG(REAL(MA(2))/B + & + REAL(MA(3))/(B*B)))/ALOG3 - 0.3) + K2 = K2 - L + IF (L < 0) L = 0 + IF (K2 < 0) THEN + K2 = 0 + J2 = INT(.43*SQRT(T*ALOGMB/(ALOGT+REAL(L)*ALOG3)) + .33) + ENDIF + IF (J2 <= 1) J2 = 1 + + N2 = INT(T*ALOGMB/(ALOGT+REAL(L)*ALOG3)) + L2 = INT(LOG(REAL(N2)+3.0**K2)/ALOGMB) + NDIG = NDIG + L2 + IF (NDIG > NDG2MX) THEN + IF (NCALL == 1) THEN + KFLAG = -9 + CALL FMWARN + NDIG = NDSAVE + CALL FMST2M('UNKNOWN',MB) + KWARN = KWRNSV + RETURN + ELSE + NDIG = NDG2MX + ENDIF + ENDIF + NDSAV1 = NDIG + +! Divide the argument by 3**K2. + + CALL FMEQ2(MA,M02,NDSAVE,NDIG) + KTHREE = 1 + MAXVAL = MXBASE/3 + IF (K2 > 0) THEN + DO J = 1, K2 + KTHREE = 3*KTHREE + IF (KTHREE > MAXVAL) THEN + CALL FMDIVI_R1(M02,KTHREE) + KTHREE = 1 + ENDIF + ENDDO + IF (KTHREE > 1) CALL FMDIVI_R1(M02,KTHREE) + ENDIF + +! Split into J2 concurrent sums and reduce NDIG while +! computing each term in the sum as the terms get smaller. + + CALL FMEQ(M02,M03) + NTERM = 1 + DO J = 1, J2 + NBOT = NTERM*(NTERM-1) + IF (NBOT > 1) CALL FMDIVI_R1(M03,NBOT) + NTERM = NTERM + 2 + KPT = (J-1)*(NDIG+3) + CALL FMEQ(M03,MJSUMS(KPT-1)) + ENDDO + CALL FMSQR_R1(M02) + IF (M02(1) < -NDIG) GO TO 120 + CALL FMIPWR(M02,J2,MB) + + 110 CALL FMMPY_R1(M03,MB) + LARGE = INT(INTMAX/NTERM) + DO J = 1, J2 + NBOT = NTERM*(NTERM-1) + IF (NTERM > LARGE .OR. NBOT > MXBASE) THEN + CALL FMDIVI_R1(M03,NTERM) + NBOT = NTERM - 1 + CALL FMDIVI_R1(M03,NBOT) + ELSE + CALL FMDIVI_R1(M03,NBOT) + ENDIF + KPT = (J-1)*(NDSAV1+3) + NDIG = NDSAV1 + CALL FMADD_R1(MJSUMS(KPT-1),M03) + IF (KFLAG /= 0) GO TO 120 + NDIG = NDSAV1 - INT(MJSUMS(KPT+1)-M03(1)) + IF (NDIG < 2) NDIG = 2 + NTERM = NTERM + 2 + ENDDO + GO TO 110 + +! Next put the J2 separate sums back together. + + 120 KFLAG = 0 + KPT = (J2-1)*(NDIG+3) + CALL FMEQ(MJSUMS(KPT-1),MB) + IF (J2 >= 2) THEN + DO J = 2, J2 + CALL FMMPY_R2(M02,MB) + KPT = (J2-J)*(NDIG+3) + CALL FMADD_R1(MB,MJSUMS(KPT-1)) + ENDDO + ENDIF + +! Reverse the effect of reducing the argument to +! compute SINH(MA). + + NDIG = NDSAV1 + IF (K2 > 0) THEN + CALL FMI2M(3,M02) + DO J = 1, K2 + CALL FMSQR(MB,M03) + CALL FMMPYI_R1(M03,4) + CALL FMADD_R2(M02,M03) + CALL FMMPY_R2(M03,MB) + ENDDO + ENDIF + + CALL FMEQ2_R1(MB,NDSAV1,NDSAVE) + NDIG = NDSAVE + KWARN = KWRNSV + + RETURN + END SUBROUTINE FMSNH2 + + SUBROUTINE FMSP2M(X,MA) + +! MA = X + +! Convert a single precision number to FM format. + +! This version tries to convert the single precision machine +! number to FM with accuracy of nearly full FM precision. +! If conversion to FM with approximately double precision accuracy +! is good enough, it is faster to CALL FMDPM(DBLE(X),MA) + + USE FMVALS + IMPLICIT NONE + + REAL X + REAL (KIND(1.0D0)) :: MA(-1:LUNPCK) + + DOUBLE PRECISION XDP,Y,YT + INTEGER K + + NCALL = NCALL + 1 + NAMEST(NCALL) = 'FMSP2M' + XDP = DBLE(X) + IF (NTRACE /= 0) CALL FMNTRR(2,XDP,1) + +! Check to see if X is exactly a small integer. If so, +! converting as an integer is better. +! Also see if X is exactly a small integer divided by +! a small power of two. + + Y = MXEXP2 + IF (ABS(XDP) < Y) THEN + K = INT(XDP) + Y = K + IF (Y == XDP) THEN + CALL FMIM(K,MA) + GO TO 110 + ENDIF + ENDIF + IF (ABS(XDP) < 1.0D0) THEN + Y = 4096.0D0 * XDP + K = INT(Y) + YT = K + IF (Y == YT) THEN + CALL FMIM(K,MA) + CALL FMDIVI_R1(MA,4096) + GO TO 110 + ENDIF + ENDIF + + CALL FMDM2(XDP,MA) + + 110 IF (NTRACE /= 0) CALL FMNTR(1,MA,MA,1,1) + NCALL = NCALL - 1 + RETURN + END SUBROUTINE FMSP2M + + SUBROUTINE FMSQR(MA,MB) + +! MB = MA*MA Faster than using FMMPY. + + USE FMVALS + IMPLICIT NONE + + REAL (KIND(1.0D0)) :: MA(-1:LUNPCK),MB(-1:LUNPCK) + + NCALL = NCALL + 1 + IF (NTRACE /= 0) THEN + NAMEST(NCALL) = 'FMSQR ' + CALL FMNTR(2,MA,MA,1,1) + + CALL FMSQR2(MA,MB) + + CALL FMNTR(1,MB,MB,1,1) + ELSE + CALL FMSQR2(MA,MB) + ENDIF + NCALL = NCALL - 1 + RETURN + END SUBROUTINE FMSQR + + SUBROUTINE FMSQR2(MA,MB) + +! MB = MA*MA. + + USE FMVALS + IMPLICIT NONE + + REAL (KIND(1.0D0)) :: MA(-1:LUNPCK),MB(-1:LUNPCK) + + REAL (KIND(1.0D0)) :: MACCA,MAXMAX,MAXMWA,MBJ,MBKJ,MBM1, & + MBNORM,MD2B,MK,MKA,MKT,MMAX,MR,MT + INTEGER J,JM1,JRSSAV,K,KB,KI,KJ,KL,KNZ,KOVUN,KSHIFT,KWA, & + L,N1,NGUARD + + IF (MBLOGS /= MBASE) CALL FMCONS + JRSSAV = JRSIGN + IF (ABS(MA(1)) > MEXPAB .OR. KDEBUG == 1 .OR. & + MBASE*MBASE <= MXBASE/(4*MBASE)) THEN + KOVUN = 0 + IF (MA(1) == MEXPOV .OR. MA(1) == MEXPUN) KOVUN = 1 + IF (MA(1) == MUNKNO) KOVUN = 2 + NCALL = NCALL + 1 + CALL FMMPY2(MA,MA,MB) + NCALL = NCALL - 1 + IF ((KFLAG < 0 .AND. KOVUN == 0) .OR. & + (KFLAG == -4 .AND. KOVUN == 1)) THEN + NAMEST(NCALL) = 'FMSQR ' + CALL FMWARN + ENDIF + GO TO 120 + ELSE IF (MA(2) == 0) THEN + CALL FMEQ(MA,MB) + GO TO 120 + ENDIF + KFLAG = 0 + MAXMAX = 0 + + MACCA = MA(0) + N1 = NDIG + 1 + MWA(1) = MA(1) + MA(1) + +! NGUARD is the number of guard digits used. + + IF (NCALL > 1) THEN + NGUARD = NGRD22 + IF (NGUARD > NDIG) NGUARD = NDIG + ELSE + NGUARD = NGRD52 + IF (NGUARD > NDIG) NGUARD = NDIG + IF (MBASE < 1000 .OR. KROUND /= 1 .OR. KRPERF == 1) THEN + NGUARD = NDIG + 10 + ENDIF + ENDIF + IF (MA(2)*MA(2) < MBASE .AND. NGUARD < 3) NGUARD = 3 + + L = N1 + NGUARD + MWA(L+1) = 0 + +! The multiplication loop begins here. + +! MBNORM is the minimum number of digits that can be +! multiplied before normalization is required. +! MAXMWA is an upper bound on the size of values in MWA +! divided by (MBASE-1). It is used to determine +! whether to normalize before the next digit is +! multiplied. + + MBM1 = MBASE - 1 + MBNORM = AINT (MAXINT/(MBM1*MBM1)) + MMAX = INTMAX - MBASE + MMAX = MIN(AINT (MAXINT/MBM1 - MBM1),MMAX) + IF (MBNORM > 1) THEN + MBJ = MA(2) + +! Count the trailing zeros in MA. + + IF (MA(N1) /= 0) THEN + KNZ = N1 + ELSE + DO J = NDIG, 2, -1 + IF (MA(J) /= 0) THEN + KNZ = J + GO TO 110 + ENDIF + ENDDO + ENDIF + + 110 MWA(2) = 0 + MWA(3) = 0 + DO K = NDIG+2, L + MWA(K) = 0 + ENDDO + +! (Inner Loop) + + DO K = 3, N1 + MWA(K+1) = MA(K)*MBJ + ENDDO + MAXMWA = MBJ + DO J = 3, MIN(L/2,N1) + MBJ = MA(J) + IF (MBJ /= 0) THEN + MAXMWA = MAXMWA + MBJ + JM1 = J - 1 + KL = MIN(KNZ,L-JM1) + +! Major (Inner Loop) + + DO K = 2*J, JM1+KL + MWA(K) = MWA(K) + MA(K-JM1)*MBJ + ENDDO + ENDIF + + IF (MAXMWA > MMAX) THEN + MAXMAX = MAX(MAXMAX,MAXMWA) + MAXMWA = 0 + +! Normalization is only required for the +! range of digits currently changing in MWA. + + DO KB = JM1+KL, 2*J, -1 + MKT = INT (MWA(KB)/MBASE) + MWA(KB-1) = MWA(KB-1) + MKT + MWA(KB) = MWA(KB) - MKT*MBASE + ENDDO + ENDIF + ENDDO + +! Double MWA, add the square terms, and perform +! the final normalization. (Inner Loop) + + IF (2*MAX(MAXMAX,MAXMWA)+MBASE > MMAX) THEN + DO KB = L, 4, -1 + MKT = INT (MWA(KB)/MBASE) + MWA(KB-1) = MWA(KB-1) + MKT + MWA(KB) = MWA(KB) - MKT*MBASE + ENDDO + ENDIF + + DO J = 3, L-1, 2 + IF ((J+1)/2 <= N1) THEN + MKA = MA((J+1)/2) + MWA(J) = 2*MWA(J) + MKA*MKA + MWA(J+1) = 2*MWA(J+1) + ELSE + MWA(J) = 2*MWA(J) + MWA(J+1) = 2*MWA(J+1) + ENDIF + ENDDO + IF (MOD(L,2) == 1) THEN + IF ((L+1)/2 <= N1) THEN + MKA = MA((L+1)/2) + MWA(L) = 2*MWA(L) + MKA*MKA + ELSE + MWA(L) = 2*MWA(L) + ENDIF + ENDIF + + DO KB = L, 3, -1 + MKT = INT (MWA(KB)/MBASE) + MWA(KB-1) = MWA(KB-1) + MKT + MWA(KB) = MWA(KB) - MKT*MBASE + ENDDO + + ELSE + +! If normalization must be done for each digit, combine +! the two loops and normalize as the digits are multiplied. + + DO J = 2, L + MWA(J) = 0 + ENDDO + KJ = NDIG + 2 + DO J = 2, N1 + KJ = KJ - 1 + MBKJ = MA(KJ) + IF (MBKJ == 0) CYCLE + KL = L - KJ + 1 + IF (KL > N1) KL = N1 + KI = KL + 2 + KWA = KL+ KJ + 1 + MK = 0 + DO K = 2, KL + MT = MA(KI-K)*MBKJ + MWA(KWA-K) + MK + MK = INT (MT/MBASE) + MWA(KWA-K) = MT - MBASE*MK + ENDDO + MWA(KWA-KL-1) = MK + ENDDO + + ENDIF + +! Set KSHIFT = 1 if a shift left is necessary. + + IF (MWA(2) == 0) THEN + KSHIFT = 1 + ELSE + KSHIFT = 0 + ENDIF + +! The multiplication is complete. +! Round the result and move it to MB. + + JRSIGN = 1 + MR = 2*MWA(NDIG+2+KSHIFT) + 1 + IF (KROUND == -1 .OR. KROUND == 2) THEN + CALL FMRND(MWA,NDIG,NGUARD,KSHIFT) + ELSE IF (MR >= MBASE) THEN + IF (MR-1 > MBASE .AND. MWA(N1+KSHIFT) < MBASE-1) THEN + IF (KROUND /= 0 .OR. NCALL > 1) THEN + MWA(N1+KSHIFT) = MWA(N1+KSHIFT) + 1 + MWA(N1+1+KSHIFT) = 0 + ENDIF + ELSE + CALL FMRND(MWA,NDIG,NGUARD,KSHIFT) + ENDIF + ENDIF + CALL FMMOVE(MWA,MB) + + IF (KFLAG < 0) THEN + NAMEST(NCALL) = 'FMSQR ' + CALL FMWARN + ENDIF + + IF (KACCSW == 1) THEN + MD2B = NINT((NDIG-1)*ALOGM2 + LOG(REAL(ABS(MB(2))+1))/0.69315) + MB(0) = MIN(MACCA,MD2B) + ELSE + MB(0) = MACCA + ENDIF + 120 MB(-1) = 1 + JRSIGN = JRSSAV + RETURN + END SUBROUTINE FMSQR2 + + SUBROUTINE FMSQR_R1(MA) + +! MA = MA*MA Faster than using FMMPY. + + USE FMVALS + IMPLICIT NONE + + REAL (KIND(1.0D0)) :: MA(-1:LUNPCK) + + NCALL = NCALL + 1 + IF (NTRACE /= 0) THEN + NAMEST(NCALL) = 'FMSQR ' + CALL FMNTR(2,MA,MA,1,1) + + CALL FMSQR2_R1(MA) + + CALL FMNTR(1,MA,MA,1,1) + ELSE + CALL FMSQR2_R1(MA) + ENDIF + NCALL = NCALL - 1 + RETURN + END SUBROUTINE FMSQR_R1 + + SUBROUTINE FMSQR2_R1(MA) + +! MA = MA*MA. + + USE FMVALS + IMPLICIT NONE + + REAL (KIND(1.0D0)) :: MA(-1:LUNPCK) + + REAL (KIND(1.0D0)) :: MACCA,MAXMAX,MAXMWA,MBJ,MBKJ,MBM1, & + MBNORM,MD2B,MK,MKA,MKT,MMAX,MR,MT + INTEGER J,JM1,JRSSAV,K,KB,KI,KJ,KL,KNZ,KOVUN,KSHIFT,KWA, & + L,N1,NGUARD + + IF (MBLOGS /= MBASE) CALL FMCONS + JRSSAV = JRSIGN + IF (ABS(MA(1)) > MEXPAB .OR. KDEBUG == 1 .OR. & + MBASE*MBASE <= MXBASE/(4*MBASE)) THEN + KOVUN = 0 + IF (MA(1) == MEXPOV .OR. MA(1) == MEXPUN) KOVUN = 1 + IF (MA(1) == MUNKNO) KOVUN = 2 + NCALL = NCALL + 1 + CALL FMMPY2(MA,MA,M07) + CALL FMEQ(M07,MA) + NCALL = NCALL - 1 + IF ((KFLAG < 0 .AND. KOVUN == 0) .OR. & + (KFLAG == -4 .AND. KOVUN == 1)) THEN + NAMEST(NCALL) = 'FMSQR ' + CALL FMWARN + ENDIF + GO TO 120 + ELSE IF (MA(2) == 0) THEN + GO TO 120 + ENDIF + KFLAG = 0 + MAXMAX = 0 + + MACCA = MA(0) + N1 = NDIG + 1 + MWA(1) = MA(1) + MA(1) + +! NGUARD is the number of guard digits used. + + IF (NCALL > 1) THEN + NGUARD = NGRD22 + IF (NGUARD > NDIG) NGUARD = NDIG + ELSE + NGUARD = NGRD52 + IF (NGUARD > NDIG) NGUARD = NDIG + IF (MBASE < 1000 .OR. KROUND /= 1 .OR. KRPERF == 1) THEN + NGUARD = NDIG + 10 + ENDIF + ENDIF + IF (MA(2)*MA(2) < MBASE .AND. NGUARD < 3) NGUARD = 3 + + L = N1 + NGUARD + MWA(L+1) = 0 + +! The multiplication loop begins here. + +! MBNORM is the minimum number of digits that can be +! multiplied before normalization is required. +! MAXMWA is an upper bound on the size of values in MWA +! divided by (MBASE-1). It is used to determine +! whether to normalize before the next digit is +! multiplied. + + MBM1 = MBASE - 1 + MBNORM = AINT (MAXINT/(MBM1*MBM1)) + MMAX = INTMAX - MBASE + MMAX = MIN(AINT (MAXINT/MBM1 - MBM1),MMAX) + IF (MBNORM > 1) THEN + MBJ = MA(2) + +! Count the trailing zeros in MA. + + IF (MA(N1) /= 0) THEN + KNZ = N1 + ELSE + DO J = NDIG, 2, -1 + IF (MA(J) /= 0) THEN + KNZ = J + GO TO 110 + ENDIF + ENDDO + ENDIF + + 110 MWA(2) = 0 + MWA(3) = 0 + DO K = NDIG+2, L + MWA(K) = 0 + ENDDO + +! (Inner Loop) + + DO K = 3, N1 + MWA(K+1) = MA(K)*MBJ + ENDDO + MAXMWA = MBJ + DO J = 3, MIN(L/2,N1) + MBJ = MA(J) + IF (MBJ /= 0) THEN + MAXMWA = MAXMWA + MBJ + JM1 = J - 1 + KL = MIN(KNZ,L-JM1) + +! Major (Inner Loop) + + DO K = 2*J, JM1+KL + MWA(K) = MWA(K) + MA(K-JM1)*MBJ + ENDDO + ENDIF + + IF (MAXMWA > MMAX) THEN + MAXMAX = MAX(MAXMAX,MAXMWA) + MAXMWA = 0 + +! Normalization is only required for the +! range of digits currently changing in MWA. + + DO KB = JM1+KL, 2*J, -1 + MKT = INT (MWA(KB)/MBASE) + MWA(KB-1) = MWA(KB-1) + MKT + MWA(KB) = MWA(KB) - MKT*MBASE + ENDDO + ENDIF + ENDDO + +! Double MWA, add the square terms, and perform +! the final normalization. (Inner Loop) + + IF (2*MAX(MAXMAX,MAXMWA)+MBASE > MMAX) THEN + DO KB = L, 4, -1 + MKT = INT (MWA(KB)/MBASE) + MWA(KB-1) = MWA(KB-1) + MKT + MWA(KB) = MWA(KB) - MKT*MBASE + ENDDO + ENDIF + + DO J = 3, L-1, 2 + IF ((J+1)/2 <= N1) THEN + MKA = MA((J+1)/2) + MWA(J) = 2*MWA(J) + MKA*MKA + MWA(J+1) = 2*MWA(J+1) + ELSE + MWA(J) = 2*MWA(J) + MWA(J+1) = 2*MWA(J+1) + ENDIF + ENDDO + IF (MOD(L,2) == 1) THEN + IF ((L+1)/2 <= N1) THEN + MKA = MA((L+1)/2) + MWA(L) = 2*MWA(L) + MKA*MKA + ELSE + MWA(L) = 2*MWA(L) + ENDIF + ENDIF + + DO KB = L, 3, -1 + MKT = INT (MWA(KB)/MBASE) + MWA(KB-1) = MWA(KB-1) + MKT + MWA(KB) = MWA(KB) - MKT*MBASE + ENDDO + + ELSE + +! If normalization must be done for each digit, combine +! the two loops and normalize as the digits are multiplied. + + DO J = 2, L + MWA(J) = 0 + ENDDO + KJ = NDIG + 2 + DO J = 2, N1 + KJ = KJ - 1 + MBKJ = MA(KJ) + IF (MBKJ == 0) CYCLE + KL = L - KJ + 1 + IF (KL > N1) KL = N1 + KI = KL + 2 + KWA = KL+ KJ + 1 + MK = 0 + DO K = 2, KL + MT = MA(KI-K)*MBKJ + MWA(KWA-K) + MK + MK = INT (MT/MBASE) + MWA(KWA-K) = MT - MBASE*MK + ENDDO + MWA(KWA-KL-1) = MK + ENDDO + + ENDIF + +! Set KSHIFT = 1 if a shift left is necessary. + + IF (MWA(2) == 0) THEN + KSHIFT = 1 + ELSE + KSHIFT = 0 + ENDIF + +! The multiplication is complete. +! Round the result and move it to MA. + + JRSIGN = 1 + MR = 2*MWA(NDIG+2+KSHIFT) + 1 + IF (KROUND == -1 .OR. KROUND == 2) THEN + CALL FMRND(MWA,NDIG,NGUARD,KSHIFT) + ELSE IF (MR >= MBASE) THEN + IF (MR-1 > MBASE .AND. MWA(N1+KSHIFT) < MBASE-1) THEN + IF (KROUND /= 0 .OR. NCALL > 1) THEN + MWA(N1+KSHIFT) = MWA(N1+KSHIFT) + 1 + MWA(N1+1+KSHIFT) = 0 + ENDIF + ELSE + CALL FMRND(MWA,NDIG,NGUARD,KSHIFT) + ENDIF + ENDIF + CALL FMMOVE(MWA,MA) + + IF (KFLAG < 0) THEN + NAMEST(NCALL) = 'FMSQR ' + CALL FMWARN + ENDIF + + IF (KACCSW == 1) THEN + MD2B = NINT((NDIG-1)*ALOGM2 + LOG(REAL(ABS(MA(2))+1))/0.69315) + MA(0) = MIN(MACCA,MD2B) + ELSE + MA(0) = MACCA + ENDIF + 120 MA(-1) = 1 + JRSIGN = JRSSAV + RETURN + END SUBROUTINE FMSQR2_R1 + + SUBROUTINE FMSQRT(MA,MB) + +! MB = SQRT(MA) + + USE FMVALS + IMPLICIT NONE + + REAL (KIND(1.0D0)) :: MA(-1:LUNPCK),MB(-1:LUNPCK) + DOUBLE PRECISION X,XB + REAL (KIND(1.0D0)) :: MA1,MACCA,MD2B,MKE,MXSAVE + INTEGER NSTACK(19),J,K,KASAVE,KMA1,KOVUN,KRESLT,KST,NDSAVE + + IF (MBLOGS /= MBASE) CALL FMCONS + IF (ABS(MA(1)) > MEXPAB .OR. MA(2) == 0 .OR. MA(-1) < 0) THEN + CALL FMENTR('FMSQRT',MA,MA,1,1,MB,KRESLT,NDSAVE,MXSAVE,KASAVE, & + KOVUN) + IF (KRESLT /= 0) RETURN + ELSE + NCALL = NCALL + 1 + IF (NTRACE /= 0) THEN + NAMEST(NCALL) = 'FMSQRT' + CALL FMNTR(2,MA,MA,1,1) + ENDIF + NDSAVE = NDIG + IF (NCALL == 1) THEN + K = MAX(NGRD52-1,2) + NDIG = MAX(NDIG+K,2) + IF (NDIG > NDG2MX) THEN + NAMEST(NCALL) = 'FMSQRT' + KFLAG = -9 + CALL FMWARN + NDIG = NDSAVE + KRESLT = 12 + CALL FMRSLT(MA,MA,MB,KRESLT) + IF (NTRACE /= 0) CALL FMNTR(1,MB,MB,1,1) + NCALL = NCALL - 1 + RETURN + ENDIF + ENDIF + KASAVE = KACCSW + KACCSW = 0 + MXSAVE = MXEXP + MXEXP = MXEXP2 + ENDIF + IF (MBASE < 1000 .OR. KROUND /= 1 .OR. KRPERF == 1) THEN + IF (NCALL == 1) NDIG = MIN(NDG2MX,MAX(NDIG,2*NDSAVE+10)) + ENDIF + + MA1 = MA(1) + + MACCA = MA(0) + CALL FMEQ2(MA,M02,NDSAVE,NDIG) + M02(0) = NINT(NDIG*ALOGM2) + +! Generate the first approximation. + + M02(1) = 0 + CALL FMM2DP(M02,X) + X = SQRT(X) + MKE = MA1/2 + KMA1 = INT(ABS(MA1)) + IF (MOD(KMA1,2) == 1) THEN + XB = MBASE + X = X*SQRT(XB) + MKE = (MA1-1)/2 + ENDIF + CALL FMDPM(X,MB) + MB(1) = MB(1) + MKE + +! Initialize. + + M02(1) = MA1 + CALL FMDIG(NSTACK,KST) + +! Newton iteration. + + DO J = 1, KST + NDIG = NSTACK(J) + CALL FMDIV(M02,MB,M01) + CALL FMADD_R1(MB,M01) + CALL FMDIVI_R1(MB,2) + ENDDO + +! Round the result and return. + + IF (KASAVE == 1) THEN + MD2B = NINT((NDSAVE-1)*ALOGM2+LOG(REAL(ABS(MB(2))+1))/0.69315) + MB(0) = MIN(MACCA,MD2B) + ELSE + MB(0) = MACCA + ENDIF + MB(-1) = 1 + DO J = -1, NDIG+1 + M01(J) = MB(J) + ENDDO + CALL FMEXIT(M01,MB,NDSAVE,MXSAVE,KASAVE,0) + RETURN + END SUBROUTINE FMSQRT + + SUBROUTINE FMSQRT_R1(MA) + +! MA = SQRT(MA) + + USE FMVALS + IMPLICIT NONE + + REAL (KIND(1.0D0)) :: MA(-1:LUNPCK) + DOUBLE PRECISION X,XB + REAL (KIND(1.0D0)) :: MA1,MACCA,MD2B,MKE,MXSAVE + INTEGER NSTACK(19),J,K,KASAVE,KMA1,KOVUN,KRESLT,KST,NDSAVE + + IF (MBLOGS /= MBASE) CALL FMCONS + IF (ABS(MA(1)) > MEXPAB .OR. MA(2) == 0 .OR. MA(-1) < 0) THEN + CALL FMENTR('FMSQRT',MA,MA,1,1,M07,KRESLT,NDSAVE,MXSAVE,KASAVE, & + KOVUN) + IF (KRESLT /= 0) THEN + CALL FMEQ(M07,MA) + RETURN + ENDIF + ELSE + NCALL = NCALL + 1 + IF (NTRACE /= 0) THEN + NAMEST(NCALL) = 'FMSQRT' + CALL FMNTR(2,MA,MA,1,1) + ENDIF + NDSAVE = NDIG + IF (NCALL == 1) THEN + K = MAX(NGRD52-1,2) + NDIG = MAX(NDIG+K,2) + IF (NDIG > NDG2MX) THEN + NAMEST(NCALL) = 'FMSQRT' + KFLAG = -9 + CALL FMWARN + NDIG = NDSAVE + KRESLT = 12 + CALL FMRSLT(MA,MA,M07,KRESLT) + CALL FMEQ(M07,MA) + IF (NTRACE /= 0) CALL FMNTR(1,MA,MA,1,1) + NCALL = NCALL - 1 + RETURN + ENDIF + ENDIF + KASAVE = KACCSW + KACCSW = 0 + MXSAVE = MXEXP + MXEXP = MXEXP2 + ENDIF + IF (MBASE < 1000 .OR. KROUND /= 1 .OR. KRPERF == 1) THEN + IF (NCALL == 1) NDIG = MIN(NDG2MX,MAX(NDIG,2*NDSAVE+10)) + ENDIF + + MA1 = MA(1) + + MACCA = MA(0) + CALL FMEQ2(MA,M02,NDSAVE,NDIG) + M02(0) = NINT(NDIG*ALOGM2) + +! Generate the first approximation. + + M02(1) = 0 + CALL FMM2DP(M02,X) + X = SQRT(X) + MKE = MA1/2 + KMA1 = INT(ABS(MA1)) + IF (MOD(KMA1,2) == 1) THEN + XB = MBASE + X = X*SQRT(XB) + MKE = (MA1-1)/2 + ENDIF + CALL FMDPM(X,MA) + MA(1) = MA(1) + MKE + +! Initialize. + + M02(1) = MA1 + CALL FMDIG(NSTACK,KST) + +! Newton iteration. + + DO J = 1, KST + NDIG = NSTACK(J) + CALL FMDIV(M02,MA,M01) + CALL FMADD_R1(MA,M01) + CALL FMDIVI_R1(MA,2) + ENDDO + +! Round the result and return. + + IF (KASAVE == 1) THEN + MD2B = NINT((NDSAVE-1)*ALOGM2+LOG(REAL(ABS(MA(2))+1))/0.69315) + MA(0) = MIN(MACCA,MD2B) + ELSE + MA(0) = MACCA + ENDIF + MA(-1) = 1 + DO J = -1, NDIG+1 + M01(J) = MA(J) + ENDDO + CALL FMEXIT(M01,MA,NDSAVE,MXSAVE,KASAVE,0) + RETURN + END SUBROUTINE FMSQRT_R1 + + SUBROUTINE FMST2D(STRING,X) + +! STRING contains a free-format number that is converted to double +! precision and returned in X. + +! The input number may be in integer or any real format. +! The convention is made that if no digits appear before 'E' then 1.0 +! is assumed. For example 'E6' is converted as '1.0E+6'. + + USE FMVALS + IMPLICIT NONE + + CHARACTER(*) :: STRING + INTEGER J,JSTATE,KDIGFL,KEXP,KPT,KSIGN,KSIGNX,KSTART,KSTOP, & + KTYPE,KVAL,N2 + DOUBLE PRECISION X,F1,F2 + + INTEGER :: JTRANS(8,4) = RESHAPE( (/ & + 2, 9, 9, 9, 9, 7, 9, 9, & + 3, 3, 3, 5, 5, 8, 8, 8, & + 4, 4, 4, 9, 9, 9, 9, 9, & + 6, 6, 6, 6, 6, 9, 9, 9 /) & + , (/ 8,4 /) ) + + CHARACTER :: KBLANK = ' ' + + JSTATE = 1 + KSIGN = 1 + F1 = 0.0D0 + F2 = 0.0D0 + N2 = 0 + KSIGNX = 1 + KEXP = 0 + KSTART = 1 + KSTOP = LEN(STRING) + KFLAG = 0 + +! KDIGFL will be 1 if any digits are found before 'E'. + + KDIGFL = 0 + +! Initialize two hash tables that are used for character +! look-up during input conversion. + + IF (LHASH == 0) CALL FMHTBL + +! Scan the number. + + DO J = KSTART, KSTOP + IF (STRING(J:J) == KBLANK) CYCLE + KPT = ICHAR(STRING(J:J)) + IF (KPT < LHASH1 .OR. KPT > LHASH2) THEN + WRITE (KW, & + "(/' Error in input conversion.'/" // & + "' ICHAR function was out of range for the current'," // & + "' dimensions.'/' ICHAR(''',A,''') gave the value '," // & + "I12,', which is outside the currently'/' dimensioned'," // & + "' bounds of (',I5,':',I5,') for variables KHASHT '," // & + "'and KHASHV.'/' Re-define the two parameters '," // & + "'LHASH1 and LHASH2 so the dimensions will'/' contain'," // & + "' all possible output values from ICHAR.'//)" & + ) STRING(J:J),KPT,LHASH1,LHASH2 + KTYPE = 5 + KVAL = 0 + ELSE + KTYPE = KHASHT(KPT) + KVAL = KHASHV(KPT) + ENDIF + IF (KTYPE >= 5) GO TO 110 + + JSTATE = JTRANS(JSTATE,KTYPE) + + SELECT CASE (JSTATE) + +! State 2. Sign of the number. + + CASE (2) + KSIGN = KVAL + +! State 3. Digits before a decimal point. + + CASE (3) + KDIGFL = 1 + F1 = 10.0D0*F1 + KVAL + +! State 4. Decimal point + + CASE (4) + CYCLE + +! State 5. Digits after a decimal point. + + CASE (5) + KDIGFL = 1 + F2 = 10.0D0*F2 + KVAL + N2 = N2 + 1 + +! State 6. Precision indicator. + + CASE (6) + IF (KDIGFL == 0) F1 = 1.0D0 + +! State 7. Sign of the exponent. + + CASE (7) + KSIGNX = KVAL + +! State 8. Digits of the exponent. + + CASE (8) + KEXP = 10*KEXP + KVAL + + CASE DEFAULT + GO TO 110 + + END SELECT + + ENDDO + +! Form the number and return. + + KEXP = KSIGNX*KEXP + X = KSIGN*(F1 + F2/10.0D0**N2)*10.0D0**KEXP + + RETURN + +! Error in converting the number. + + 110 X = -1.0D+31 + KFLAG = -4 + RETURN + END SUBROUTINE FMST2D + + SUBROUTINE FMST2M(STRING,MA) + +! MA = STRING + +! Convert a character string to FM format. +! This is often more convenient than using FMINP, which converts an +! array of CHARACTER*1 values. + + USE FMVALS + IMPLICIT NONE + + CHARACTER(*) :: STRING + REAL (KIND(1.0D0)) :: MA(-1:LUNPCK) + + INTEGER J,LB,KFSAVE + + IF (MBLOGS /= MBASE) CALL FMCONS + NCALL = NCALL + 1 + NAMEST(NCALL) = 'FMST2M' + LB = MIN(LEN(STRING),LMBUFF) + KFSAVE = KFLAG + + DO J = 1, LB + CMBUFF(J) = STRING(J:J) + ENDDO + CALL FMINP(CMBUFF,MA,1,LB) + + IF (KFSAVE /= 0) KFLAG = KFSAVE + NCALL = NCALL - 1 + RETURN + END SUBROUTINE FMST2M + + SUBROUTINE FMSUB(MA,MB,MC) + +! MC = MA - MB + + USE FMVALS + IMPLICIT NONE + + REAL (KIND(1.0D0)) :: MA(-1:LUNPCK),MB(-1:LUNPCK),MC(-1:LUNPCK) + + INTEGER KFLG1 + + NCALL = NCALL + 1 + IF (NTRACE /= 0) THEN + NAMEST(NCALL) = 'FMSUB ' + IF (NTRACE /= 0) CALL FMNTR(2,MA,MB,2,1) + + KFLG1 = 0 + IF (MB(1) > MA(1) .OR. MA(2) == 0) KFLG1 = 1 + IF (MB(2) == 0) KFLG1 = 0 + +! FMADD2 will negate MB and add. + + KSUB = 1 + CALL FMADD2(MA,MB,MC) + KSUB = 0 + +! If MA was smaller than MB, then KFLAG = 1 returned from +! FMADD means the result from FMSUB is the opposite of the +! input argument of larger magnitude, so reset KFLAG. + + IF (KFLAG == 1 .AND. KFLG1 == 1) KFLAG = 0 + + IF (NTRACE /= 0) CALL FMNTR(1,MC,MC,1,1) + ELSE + KFLG1 = 0 + IF (MB(1) > MA(1) .OR. MA(2) == 0) KFLG1 = 1 + IF (MB(2) == 0) KFLG1 = 0 + KSUB = 1 + CALL FMADD2(MA,MB,MC) + KSUB = 0 + IF (KFLAG == 1 .AND. KFLG1 == 1) KFLAG = 0 + ENDIF + NCALL = NCALL - 1 + RETURN + END SUBROUTINE FMSUB + + SUBROUTINE FMSUB_R1(MA,MB) + +! MA = MA - MB + + USE FMVALS + IMPLICIT NONE + + REAL (KIND(1.0D0)) :: MA(-1:LUNPCK),MB(-1:LUNPCK) + + INTEGER KFLG1 + + NCALL = NCALL + 1 + IF (NTRACE /= 0) THEN + NAMEST(NCALL) = 'FMSUB ' + IF (NTRACE /= 0) CALL FMNTR(2,MA,MB,2,1) + + KFLG1 = 0 + IF (MB(1) > MA(1) .OR. MA(2) == 0) KFLG1 = 1 + IF (MB(2) == 0) KFLG1 = 0 + +! FMADD2 will negate MB and add. + + KSUB = 1 + CALL FMADD2_R1(MA,MB) + KSUB = 0 + +! If MA was smaller than MB, then KFLAG = 1 returned from +! FMADD means the result from FMSUB is the opposite of the +! input argument of larger magnitude, so reset KFLAG. + + IF (KFLAG == 1 .AND. KFLG1 == 1) KFLAG = 0 + + IF (NTRACE /= 0) CALL FMNTR(1,MA,MA,1,1) + ELSE + KFLG1 = 0 + IF (MB(1) > MA(1) .OR. MA(2) == 0) KFLG1 = 1 + IF (MB(2) == 0) KFLG1 = 0 + KSUB = 1 + CALL FMADD2_R1(MA,MB) + KSUB = 0 + IF (KFLAG == 1 .AND. KFLG1 == 1) KFLAG = 0 + ENDIF + NCALL = NCALL - 1 + RETURN + END SUBROUTINE FMSUB_R1 + + SUBROUTINE FMSUB_R2(MA,MB) + +! MB = MA - MB + + USE FMVALS + IMPLICIT NONE + + REAL (KIND(1.0D0)) :: MA(-1:LUNPCK),MB(-1:LUNPCK) + + INTEGER KFLG1 + + NCALL = NCALL + 1 + IF (NTRACE /= 0) THEN + NAMEST(NCALL) = 'FMSUB ' + IF (NTRACE /= 0) CALL FMNTR(2,MA,MB,2,1) + + KFLG1 = 0 + IF (MB(1) > MA(1) .OR. MA(2) == 0) KFLG1 = 1 + IF (MB(2) == 0) KFLG1 = 0 + +! FMADD2 will negate MB and add. + + KSUB = 1 + CALL FMADD2_R2(MA,MB) + KSUB = 0 + +! If MA was smaller than MB, then KFLAG = 1 returned from +! FMADD means the result from FMSUB is the opposite of the +! input argument of larger magnitude, so reset KFLAG. + + IF (KFLAG == 1 .AND. KFLG1 == 1) KFLAG = 0 + + IF (NTRACE /= 0) CALL FMNTR(1,MB,MB,1,1) + ELSE + KFLG1 = 0 + IF (MB(1) > MA(1) .OR. MA(2) == 0) KFLG1 = 1 + IF (MB(2) == 0) KFLG1 = 0 + KSUB = 1 + CALL FMADD2_R2(MA,MB) + KSUB = 0 + IF (KFLAG == 1 .AND. KFLG1 == 1) KFLAG = 0 + ENDIF + NCALL = NCALL - 1 + RETURN + END SUBROUTINE FMSUB_R2 + + SUBROUTINE FMTAN(MA,MB) + +! MB = TAN(MA) + + USE FMVALS + IMPLICIT NONE + + REAL (KIND(1.0D0)) :: MA(-1:LUNPCK),MB(-1:LUNPCK) + REAL (KIND(1.0D0)) :: MACCA,MACMAX,MAS,MXSAVE + INTEGER J,JCOS,JSIN,JSWAP,K,KASAVE,KOVUN,KRESLT,NDSAVE,NDSV + + IF (MBLOGS /= MBASE) CALL FMCONS + IF (ABS(MA(1)) > MEXPAB .OR. MA(2) == 0) THEN + CALL FMENTR('FMTAN ',MA,MA,1,1,MB,KRESLT,NDSAVE,MXSAVE,KASAVE, & + KOVUN) + IF (KRESLT /= 0) RETURN + ELSE + NCALL = NCALL + 1 + NAMEST(NCALL) = 'FMTAN ' + IF (NTRACE /= 0) CALL FMNTR(2,MA,MA,1,1) + KOVUN = 0 + IF (MA(1) == MEXPOV .OR. MA(1) == MEXPUN) KOVUN = 1 + NDSAVE = NDIG + IF (NCALL == 1) THEN + K = MAX(NGRD52-1,2) + NDIG = MAX(NDIG+K,2) + IF (NDIG > NDG2MX) THEN + KFLAG = -9 + CALL FMWARN + NDIG = NDSAVE + KRESLT = 12 + CALL FMRSLT(MA,MA,MB,KRESLT) + IF (NTRACE /= 0) CALL FMNTR(1,MB,MB,1,1) + NCALL = NCALL - 1 + RETURN + ENDIF + ENDIF + KASAVE = KACCSW + KACCSW = 0 + MXSAVE = MXEXP + MXEXP = MXEXP2 + ENDIF + + MACCA = MA(0) + MAS = MA(-1) + CALL FMEQ2(MA,MB,NDSAVE,NDIG) + MB(0) = NINT(NDIG*ALOGM2) + MB(-1) = 1 + +! Reduce the argument, convert to radians if the input is +! in degrees, and evaluate the function. + + CALL FMRDC(MB,JSIN,JCOS,JSWAP) + IF (MB(1) == MUNKNO) GO TO 110 + IF (MB(2) == 0) THEN + IF (JSWAP == 1) THEN + KFLAG = -4 + CALL FMWARN + CALL FMST2M('UNKNOWN',MB) + ENDIF + GO TO 110 + ENDIF + IF (KRAD == 0) THEN + IF (MBSPI /= MBASE .OR. NDIGPI < NDIG) THEN + NDSV = NDIG + NDIG = MIN(NDIG+2,NDG2MX) + NCALL = NCALL + 1 + NAMEST(NCALL) = 'NOEQ ' + CALL FMPI(MPISAV) + NCALL = NCALL - 1 + NDIG = NDSV + ENDIF + CALL FMMPY_R1(MB,MPISAV) + CALL FMDIVI_R1(MB,180) + ENDIF + IF (MB(1) /= MUNKNO) THEN + IF (JSWAP == 0) THEN + IF (MB(1) < 0) THEN + CALL FMSIN2(MB,M09) + CALL FMEQ(M09,MB) + MB(-1) = JSIN*MB(-1) + CALL FMSQR(MB,M03) + CALL FMI2M(1,M02) + CALL FMSUB_R2(M02,M03) + CALL FMSQRT(M03,M04) + M04(-1) = JCOS*M04(-1) + CALL FMDIV_R1(MB,M04) + ELSE + CALL FMCOS2(MB,M09) + CALL FMEQ(M09,MB) + MB(-1) = JCOS*MB(-1) + CALL FMSQR(MB,M03) + CALL FMI2M(1,M02) + CALL FMSUB_R2(M02,M03) + CALL FMSQRT(M03,M04) + M04(-1) = JSIN*M04(-1) + CALL FMDIV_R2(M04,MB) + ENDIF + ELSE + IF (MB(1) < 0) THEN + CALL FMSIN2(MB,M09) + CALL FMEQ(M09,MB) + MB(-1) = JCOS*MB(-1) + CALL FMSQR(MB,M03) + CALL FMI2M(1,M02) + CALL FMSUB_R2(M02,M03) + CALL FMSQRT(M03,M04) + M04(-1) = JSIN*M04(-1) + CALL FMDIV_R2(M04,MB) + ELSE + CALL FMCOS2(MB,M09) + CALL FMEQ(M09,MB) + MB(-1) = JSIN*MB(-1) + CALL FMSQR(MB,M03) + CALL FMI2M(1,M02) + CALL FMSUB_R2(M02,M03) + CALL FMSQRT(M03,M04) + M04(-1) = JCOS*M04(-1) + CALL FMDIV_R1(MB,M04) + ENDIF + ENDIF + ENDIF + +! Round and return. + + 110 MACMAX = NINT((NDSAVE-1)*ALOGM2 + LOG(REAL(ABS(MB(2))+1))/0.69315) + MB(0) = MIN(MB(0),MACCA,MACMAX) + IF (MAS < 0 .AND. MB(1) /= MUNKNO .AND. MB(2) /= 0) MB(-1) = -MB(-1) + DO J = -1, NDIG+1 + M01(J) = MB(J) + ENDDO + CALL FMEXIT(M01,MB,NDSAVE,MXSAVE,KASAVE,KOVUN) + RETURN + END SUBROUTINE FMTAN + + SUBROUTINE FMTANH(MA,MB) + +! MB = TANH(MA) + + USE FMVALS + IMPLICIT NONE + + REAL (KIND(1.0D0)) :: MA(-1:LUNPCK),MB(-1:LUNPCK) + REAL (KIND(1.0D0)) :: MACCA,MACMAX,MAS,MXSAVE + INTEGER J,K,KASAVE,KOVUN,KRESLT,KWRNSV,NDSAVE + REAL X,XT + + IF (MBLOGS /= MBASE) CALL FMCONS + IF (ABS(MA(1)) > MEXPAB) THEN + CALL FMENTR('FMTANH',MA,MA,1,1,MB,KRESLT,NDSAVE,MXSAVE,KASAVE, & + KOVUN) + IF (KRESLT /= 0) RETURN + ELSE + NCALL = NCALL + 1 + NAMEST(NCALL) = 'FMTANH' + IF (NTRACE /= 0) CALL FMNTR(2,MA,MA,1,1) + KOVUN = 0 + IF (MA(1) == MEXPOV .OR. MA(1) == MEXPUN) KOVUN = 1 + NDSAVE = NDIG + IF (NCALL == 1) THEN + K = MAX(NGRD52-1,2) + NDIG = MAX(NDIG+K,2) + IF (NDIG > NDG2MX) THEN + KFLAG = -9 + CALL FMWARN + NDIG = NDSAVE + KRESLT = 12 + CALL FMRSLT(MA,MA,MB,KRESLT) + IF (NTRACE /= 0) CALL FMNTR(1,MB,MB,1,1) + NCALL = NCALL - 1 + RETURN + ENDIF + ENDIF + KASAVE = KACCSW + KACCSW = 0 + MXSAVE = MXEXP + MXEXP = MXEXP2 + ENDIF + + KWRNSV = KWARN + KWARN = 0 + MAS = MA(-1) + + MACCA = MA(0) + CALL FMEQ2(MA,MB,NDSAVE,NDIG) + IF (MA(2) == 0) THEN + GO TO 110 + ENDIF + MB(0) = NINT(NDIG*ALOGM2) + MB(-1) = 1 + + IF (MA(1) >= 1) THEN + XT = REAL((NDIG+1)/2)*ALOGMB + K = INT(LOG(XT)/ALOGMB) + IF (MA(1) > K+1) THEN + CALL FMI2M(1,MB) + GO TO 110 + ELSE + X = REAL(MB(2)*MBASE+MB(3)+1)*REAL(MBASE)**INT(MB(1)-2) + IF (X > XT+5.0) THEN + CALL FMI2M(1,MB) + GO TO 110 + ENDIF + ENDIF + ENDIF + IF (MB(1) == 0 .AND. NDIG < 50) THEN + CALL FMEXP2(MB,M09) + CALL FMEQ(M09,MB) + CALL FMSQR_R1(MB) + CALL FMI2M(1,M02) + CALL FMSUB(MB,M02,M03) + CALL FMADD_R2(MB,M02) + CALL FMDIV(M03,M02,MB) + GO TO 110 + ENDIF + IF (MB(1) >= 0 .AND. MB(2) /= 0) THEN + CALL FMCOSH(MB,M13) + CALL FMEQ(M13,MB) + IF (MB(1) > NDIG) THEN + IF (MAS > 0) THEN + CALL FMI2M(1,MB) + GO TO 110 + ELSE + CALL FMI2M(-1,MB) + GO TO 110 + ENDIF + ENDIF + CALL FMSQR(MB,M03) + CALL FMI2M(-1,M02) + CALL FMADD_R1(M03,M02) + CALL FMSQRT_R1(M03) + CALL FMDIV_R2(M03,MB) + ELSE + CALL FMSINH(MB,M13) + CALL FMEQ(M13,MB) + CALL FMSQR(MB,M03) + CALL FMI2M(1,M02) + CALL FMADD_R1(M03,M02) + CALL FMSQRT_R1(M03) + CALL FMDIV_R1(MB,M03) + ENDIF + +! Round and return. + + 110 KWARN = KWRNSV + MACMAX = NINT((NDSAVE-1)*ALOGM2 + LOG(REAL(ABS(MB(2))+1))/0.69315) + MB(0) = MIN(MB(0),MACCA,MACMAX) + IF (MAS < 0 .AND. MB(1) /= MUNKNO .AND. MB(2) /= 0) MB(-1) = -MB(-1) + DO J = -1, NDIG+1 + M01(J) = MB(J) + ENDDO + CALL FMEXIT(M01,MB,NDSAVE,MXSAVE,KASAVE,KOVUN) + RETURN + END SUBROUTINE FMTANH + + SUBROUTINE FMTRAP(MA) + +! If MA has overflowed or underflowed, replace it by the appropriate +! symbol. + + USE FMVALS + IMPLICIT NONE + + REAL (KIND(1.0D0)) :: MA(-1:LUNPCK) + + IF (NCALL <= 0) RETURN + IF (MA(1) > MXEXP+1) THEN + IF (MA(-1) > 0) THEN + CALL FMIM(0,MA) + MA(1) = MEXPOV + MA(2) = 1 + MA(0) = NINT(NDIG*ALOGM2) + ELSE + CALL FMIM(0,MA) + MA(1) = MEXPOV + MA(2) = 1 + MA(-1) = -1 + MA(0) = NINT(NDIG*ALOGM2) + ENDIF + KFLAG = -5 + ENDIF + IF (MA(1) < -MXEXP) THEN + IF (MA(-1) > 0) THEN + CALL FMIM(0,MA) + MA(1) = MEXPUN + MA(2) = 1 + MA(0) = NINT(NDIG*ALOGM2) + ELSE + CALL FMIM(0,MA) + MA(1) = MEXPUN + MA(2) = 1 + MA(-1) = -1 + MA(0) = NINT(NDIG*ALOGM2) + ENDIF + KFLAG = -6 + ENDIF + + RETURN + END SUBROUTINE FMTRAP + + SUBROUTINE FMULP(MA,MB) + +! MB = The value of one Unit in the Last Place of MA at the current +! base and precision. + + USE FMVALS + IMPLICIT NONE + + REAL (KIND(1.0D0)) :: MA(-1:LUNPCK),MB(-1:LUNPCK) + + REAL (KIND(1.0D0)) :: MA1 + INTEGER J,KWRNSV,N1 + + IF (MBLOGS /= MBASE) CALL FMCONS + KFLAG = 0 + NCALL = NCALL + 1 + NAMEST(NCALL) = 'FMULP ' + IF (NTRACE /= 0) CALL FMNTR(2,MA,MA,1,1) + + MA1 = MA(1) + N1 = NDIG + 1 + DO J = 3, N1 + MWA(J) = 0 + ENDDO + MWA(2) = 1 + MWA(1) = MA(1) - NDIG + 1 + IF (MA(2) == 0 .OR. MA(1) >= MEXPOV) THEN + KFLAG = -4 + IF (MA1 /= MUNKNO) CALL FMWARN + CALL FMST2M('UNKNOWN',MB) + ELSE + KWRNSV = KWARN + IF (MA1 == MEXPUN) KWARN = 0 + IF (MA(-1) < 0) THEN + CALL FMMOVE(MWA,MB) + MB(-1) = 1 + IF (MB(1) /= MUNKNO .AND. MB(2) /= 0) MB(-1) = -1 + ELSE + CALL FMMOVE(MWA,MB) + MB(-1) = 1 + ENDIF + IF (KFLAG < 0) THEN + NAMEST(NCALL) = 'FMULP ' + CALL FMWARN + ENDIF + KWARN = KWRNSV + ENDIF + MB(0) = NINT(NDIG*ALOGM2) + + IF (NTRACE /= 0) CALL FMNTR(1,MB,MB,1,1) + NCALL = NCALL - 1 + RETURN + END SUBROUTINE FMULP + + SUBROUTINE FMUNPK(MP,MA) + +! MP is unpacked and the value returned in MA. + + USE FMVALS + IMPLICIT NONE + + REAL (KIND(1.0D0)) :: MA(-1:LUNPCK),MP(-1:LPACK) + + INTEGER J,KP + + KP = 2 + MA(-1) = MP(-1) + MA(0) = MP(0) + MA(1) = MP(1) + MA(2) = AINT (ABS(MP(2))/MBASE) + MA(3) = ABS(MP(2)) - MA(2)*MBASE + IF (NDIG >= 4) THEN + DO J = 4, NDIG, 2 + KP = KP + 1 + MA(J) = AINT (MP(KP)/MBASE) + MA(J+1) = MP(KP) - MA(J)*MBASE + ENDDO + ENDIF + IF (MOD(NDIG,2) == 1) THEN + MA(NDIG+1) = AINT (MP(KP+1)/MBASE) + ENDIF + RETURN + END SUBROUTINE FMUNPK + + SUBROUTINE FMVARS + +! Write the values of the FM global variables in module FMVALS. + + USE FMVALS + IMPLICIT NONE + + WRITE (KW,*) ' ' + WRITE (KW,*) ' Current values of the FM global variables.' + WRITE (KW,*) ' ' + WRITE (KW,*) ' ALOGM2 = ',ALOGM2 + WRITE (KW,*) ' ALOGMB = ',ALOGMB + WRITE (KW,*) ' ALOGMT = ',ALOGMT + WRITE (KW,*) ' ALOGMX = ',ALOGMX + WRITE (KW,*) ' CMCHAR = ',CMCHAR + WRITE (KW,*) ' DLOGEB = ',DLOGEB + WRITE (KW,*) ' DLOGMB = ',DLOGMB + WRITE (KW,*) ' DLOGPI = ',DLOGPI + WRITE (KW,*) ' DLOGTN = ',DLOGTN + WRITE (KW,*) ' DLOGTP = ',DLOGTP + WRITE (KW,*) ' DLOGTW = ',DLOGTW + WRITE (KW,*) ' DPEPS = ',DPEPS + WRITE (KW,*) ' DPMAX = ',DPMAX + WRITE (KW,*) ' DPPI = ',DPPI + WRITE (KW,*) ' INTMAX = ',INTMAX + WRITE (KW,*) ' IUNKNO = ',IUNKNO + WRITE (KW,*) ' JFORM1 = ',JFORM1 + WRITE (KW,*) ' JFORM2 = ',JFORM2 + WRITE (KW,*) ' JFORMZ = ',JFORMZ + WRITE (KW,*) ' JPRNTZ = ',JPRNTZ + WRITE (KW,*) ' KACCSW = ',KACCSW + WRITE (KW,*) ' KDEBUG = ',KDEBUG + WRITE (KW,*) ' KESWCH = ',KESWCH + WRITE (KW,*) ' KFLAG = ',KFLAG + WRITE (KW,*) ' KPTIMP = ',KPTIMP + WRITE (KW,*) ' KPTIMU = ',KPTIMU + WRITE (KW,*) ' KRAD = ',KRAD + WRITE (KW,*) ' KROUND = ',KROUND + WRITE (KW,*) ' KRPERF = ',KRPERF + WRITE (KW,*) ' KSUB = ',KSUB + WRITE (KW,*) ' KSWIDE = ',KSWIDE + WRITE (KW,*) ' KW = ',KW + WRITE (KW,*) ' KWARN = ',KWARN + WRITE (KW,*) ' LHASH = ',LHASH + WRITE (KW,*) ' LHASH1 = ',LHASH1 + WRITE (KW,*) ' LHASH2 = ',LHASH2 + WRITE (KW,*) ' LJSUMS = ',LJSUMS + WRITE (KW,*) ' LMBERN = ',LMBERN + WRITE (KW,*) ' LMBUFF = ',LMBUFF + WRITE (KW,*) ' LMBUFZ = ',LMBUFZ + WRITE (KW,*) ' LMWA = ',LMWA + WRITE (KW,*) ' LPACK = ',LPACK + WRITE (KW,*) ' LPACKZ = ',LPACKZ + WRITE (KW,*) ' LUNPCK = ',LUNPCK + WRITE (KW,*) ' LUNPKZ = ',LUNPKZ + WRITE (KW,*) ' LVLTRC = ',LVLTRC + WRITE (KW,*) ' MAXINT = ',MAXINT + WRITE (KW,*) ' MBASE = ',MBASE + WRITE (KW,*) ' MBLOGS = ',MBLOGS + WRITE (KW,*) ' MBS2PI = ',MBS2PI + WRITE (KW,*) ' MBSBRN = ',MBSBRN + WRITE (KW,*) ' MBSE = ',MBSE + WRITE (KW,*) ' MBSEUL = ',MBSEUL + WRITE (KW,*) ' MBSGAM = ',MBSGAM + WRITE (KW,*) ' MBSLB = ',MBSLB + WRITE (KW,*) ' MBSLI = ',MBSLI + WRITE (KW,*) ' MBSPI = ',MBSPI + WRITE (KW,*) ' MEXPAB = ',MEXPAB + WRITE (KW,*) ' MEXPOV = ',MEXPOV + WRITE (KW,*) ' MEXPUN = ',MEXPUN + WRITE (KW,*) ' MUNKNO = ',MUNKNO + WRITE (KW,*) ' MXBASE = ',MXBASE + WRITE (KW,*) ' MXEXP = ',MXEXP + WRITE (KW,*) ' MXEXP2 = ',MXEXP2 + WRITE (KW,*) ' NBITS = ',NBITS + WRITE (KW,*) ' NCALL = ',NCALL + WRITE (KW,*) ' NDG2MX = ',NDG2MX + WRITE (KW,*) ' NDG2PI = ',NDG2PI + WRITE (KW,*) ' NDGEUL = ',NDGEUL + WRITE (KW,*) ' NDGGAM = ',NDGGAM + WRITE (KW,*) ' NDIG = ',NDIG + WRITE (KW,*) ' NDIGE = ',NDIGE + WRITE (KW,*) ' NDIGLB = ',NDIGLB + WRITE (KW,*) ' NDIGLI = ',NDIGLI + WRITE (KW,*) ' NDIGMX = ',NDIGMX + WRITE (KW,*) ' NDIGPI = ',NDIGPI + WRITE (KW,*) ' NGRD21 = ',NGRD21 + WRITE (KW,*) ' NGRD22 = ',NGRD22 + WRITE (KW,*) ' NGRD52 = ',NGRD52 + WRITE (KW,*) ' NTRACE = ',NTRACE + WRITE (KW,*) ' NUMBRN = ',NUMBRN + WRITE (KW,*) ' NWDBRN = ',NWDBRN + WRITE (KW,*) ' RUNKNO = ',RUNKNO + WRITE (KW,*) ' SPMAX = ',SPMAX + WRITE (KW,*) ' ' + + RETURN + END SUBROUTINE FMVARS + + SUBROUTINE FMWARN + +! Called by one of the FM routines to print a warning message +! if any error condition arises in that routine. + + USE FMVALS + IMPLICIT NONE + + CHARACTER(6) :: NAME + INTEGER NCS + + IF (KFLAG >= 0 .OR. NCALL /= 1 .OR. KWARN <= 0) RETURN + NCS = NCALL + NAME = NAMEST(NCALL) + WRITE (KW, & + "(/' Error of type KFLAG =',I3," // & + "' in FM package in routine ',A6/)" & + ) KFLAG,NAME + + 110 NCALL = NCALL - 1 + IF (NCALL > 0) THEN + NAME = NAMEST(NCALL) + WRITE (KW,"( ' called from ',A6)") NAME + GO TO 110 + ENDIF + + IF (KFLAG == -1) THEN + WRITE (KW,"(' NDIG must be between 2 and',I10/)") NDIGMX + ELSE IF (KFLAG == -2) THEN + WRITE (KW,"(' MBASE must be between 2 and',I10/)") INT(MXBASE) + ELSE IF (KFLAG == -3) THEN + WRITE (KW, & + "(' An input argument is not a valid FM number.'," // & + "' Its exponent is out of range.'/)" & + ) + WRITE (KW,"(' UNKNOWN has been returned.'/)") + ELSE IF (KFLAG == -4 .OR. KFLAG == -7) THEN + WRITE (KW,"(' Invalid input argument for this routine.'/)") + WRITE (KW,"(' UNKNOWN has been returned.'/)") + ELSE IF (KFLAG == -5) THEN + WRITE (KW,"(' The result has overflowed.'/)") + ELSE IF (KFLAG == -6) THEN + WRITE (KW,"(' The result has underflowed.'/)") + ELSE IF (KFLAG == -8 .AND. NAME == 'FMOUT ') THEN + WRITE (KW, & + "(' The result array is not big enough to hold the'," // & + "' output character string'/' in the current format.'/" // & + "' The result ''***...***'' has been returned.'/)" & + ) + ELSE IF (KFLAG == -8 .AND. NAME == 'FMREAD') THEN + WRITE (KW, & + "(' The CMBUFF array is not big enough to hold the'," // & + "' input character string'/" // & + "' UNKNOWN has been returned.'/)" & + ) + ELSE IF (KFLAG == -9) THEN + WRITE (KW, & + "(' Precision could not be raised enough to'" // & + ",' provide all requested guard digits.'/)" & + ) + WRITE (KW, & + "(I23,' digits were requested (NDIG).'/" // & + "' Maximum number of digits currently available'," // & + "' (NDG2MX) is',I7,'.'/)" & + ) NDIG,NDG2MX + WRITE (KW,"(' UNKNOWN has been returned.'/)") + ELSE IF (KFLAG == -10) THEN + IF (NAMEST(NCS) == 'FMM2SP') THEN + WRITE (KW, & + "(' An FM number was too small in magnitude to '," // & + "'convert to single precision.'/)" & + ) + ELSE + WRITE (KW, & + "(' An FM number was too small in magnitude to '," // & + "'convert to double precision.'/)" & + ) + ENDIF + WRITE (KW,"(' Zero has been returned.'/)") + ENDIF + + NCALL = NCS + IF (KWARN >= 2) THEN + STOP + ENDIF + RETURN + END SUBROUTINE FMWARN + + SUBROUTINE FMWRIT(KWRITE,MA) + +! Write MA on unit KWRITE. Multi-line numbers will have '&' as the +! last nonblank character on all but the last line. These numbers can +! then be read easily using FMREAD. + + USE FMVALS + IMPLICIT NONE + + INTEGER KWRITE + REAL (KIND(1.0D0)) :: MA(-1:LUNPCK) + + INTEGER J,JF1SAV,JF2SAV,K,KSAVE,L,LAST,LB,ND,NDSAVE,NEXP + + NCALL = NCALL + 1 + NAMEST(NCALL) = 'FMWRIT' + NDSAVE = NDIG + NDIG = MIN(NDG2MX,MAX(NDIG+NGRD52,2)) + + CALL FMEQ2(MA,M01,NDSAVE,NDIG) + KSAVE = KFLAG + ND = INT(REAL(NDIG)*LOG10(REAL(MBASE))) + 1 + IF (ND < 2) ND = 2 + NEXP = INT(2.0*LOG10(REAL(MXBASE))) + 6 + LB = MIN(ND+NEXP,LMBUFF) + + JF1SAV = JFORM1 + JF2SAV = JFORM2 + JFORM1 = 1 + JFORM2 = ND + 6 + + CALL FMOUT(M01,CMBUFF,LB) + + KFLAG = KSAVE + NDIG = NDSAVE + JFORM1 = JF1SAV + JFORM2 = JF2SAV + LAST = LB + 1 + DO J = 1, LB + IF (CMBUFF(LAST-J) /= ' ' .OR. J == LB) THEN + L = LAST - J + IF (MOD(L,73) /= 0) THEN + WRITE (KWRITE,"(4X,73A1,' &')") (CMBUFF(K),K=1,L) + ELSE + IF (L > 73) WRITE (KWRITE,"(4X,73A1,' &')") & + (CMBUFF(K),K=1,L-73) + WRITE (KWRITE,"(4X,73A1)") (CMBUFF(K),K=L-72,L) + ENDIF + NCALL = NCALL - 1 + RETURN + ENDIF + ENDDO + NCALL = NCALL - 1 + RETURN + END SUBROUTINE FMWRIT + +! Here are the routines that work with packed FM numbers. All names +! are the same as unpacked versions with 'FM' replaced by 'FP'. + +! To convert a program using the FM package from unpacked calls to +! packed calls make these changes to the program: +! '(-1:LUNPCK)' to '(-1:LPACK)' in dimensions. +! 'CALL FM' to 'CALL FP' +! 'FMCOMP' to 'FPCOMP'. + +! This packed format is not available when using the FM, IM, or ZM +! derived types. + + + SUBROUTINE FPABS(MA,MB) + USE FMVALS + IMPLICIT NONE + REAL (KIND(1.0D0)) :: MA(-1:LPACK),MB(-1:LPACK) + CALL FMUNPK(MA,MPA) + CALL FMABS(MPA,MPB) + CALL FMPACK(MPB,MB) + RETURN + END SUBROUTINE FPABS + + SUBROUTINE FPACOS(MA,MB) + USE FMVALS + IMPLICIT NONE + REAL (KIND(1.0D0)) :: MA(-1:LPACK),MB(-1:LPACK) + CALL FMUNPK(MA,MPA) + CALL FMACOS(MPA,MPB) + CALL FMPACK(MPB,MB) + RETURN + END SUBROUTINE FPACOS + + SUBROUTINE FPADD(MA,MB,MC) + USE FMVALS + IMPLICIT NONE + REAL (KIND(1.0D0)) :: MA(-1:LPACK),MB(-1:LPACK),MC(-1:LPACK) + CALL FMUNPK(MA,MPA) + CALL FMUNPK(MB,MPB) + CALL FMADD(MPA,MPB,MPC) + CALL FMPACK(MPC,MC) + RETURN + END SUBROUTINE FPADD + + SUBROUTINE FPADD_R1(MA,MB) + USE FMVALS + IMPLICIT NONE + REAL (KIND(1.0D0)) :: MA(-1:LPACK),MB(-1:LPACK) + CALL FMUNPK(MA,MPA) + CALL FMUNPK(MB,MPB) + CALL FMADD(MPA,MPB,MPC) + CALL FMPACK(MPC,MA) + RETURN + END SUBROUTINE FPADD_R1 + + SUBROUTINE FPADD_R2(MA,MB) + USE FMVALS + IMPLICIT NONE + REAL (KIND(1.0D0)) :: MA(-1:LPACK),MB(-1:LPACK) + CALL FMUNPK(MA,MPA) + CALL FMUNPK(MB,MPB) + CALL FMADD(MPA,MPB,MPC) + CALL FMPACK(MPC,MB) + RETURN + END SUBROUTINE FPADD_R2 + + SUBROUTINE FPADDI(MA,L) + USE FMVALS + IMPLICIT NONE + REAL (KIND(1.0D0)) :: MA(-1:LPACK) + INTEGER L + CALL FMUNPK(MA,MPA) + CALL FMADDI(MPA,L) + CALL FMPACK(MPA,MA) + RETURN + END SUBROUTINE FPADDI + + SUBROUTINE FPASIN(MA,MB) + USE FMVALS + IMPLICIT NONE + REAL (KIND(1.0D0)) :: MA(-1:LPACK),MB(-1:LPACK) + CALL FMUNPK(MA,MPA) + CALL FMASIN(MPA,MPB) + CALL FMPACK(MPB,MB) + RETURN + END SUBROUTINE FPASIN + + SUBROUTINE FPATAN(MA,MB) + USE FMVALS + IMPLICIT NONE + REAL (KIND(1.0D0)) :: MA(-1:LPACK),MB(-1:LPACK) + CALL FMUNPK(MA,MPA) + CALL FMATAN(MPA,MPB) + CALL FMPACK(MPB,MB) + RETURN + END SUBROUTINE FPATAN + + SUBROUTINE FPATN2(MA,MB,MC) + USE FMVALS + IMPLICIT NONE + REAL (KIND(1.0D0)) :: MA(-1:LPACK),MB(-1:LPACK),MC(-1:LPACK) + CALL FMUNPK(MA,MPA) + CALL FMUNPK(MB,MPB) + CALL FMATN2(MPA,MPB,MPC) + CALL FMPACK(MPC,MC) + RETURN + END SUBROUTINE FPATN2 + + SUBROUTINE FPBIG(MA) + USE FMVALS + IMPLICIT NONE + REAL (KIND(1.0D0)) :: MA(-1:LPACK) + CALL FMBIG(MPA) + CALL FMPACK(MPA,MA) + RETURN + END SUBROUTINE FPBIG + + SUBROUTINE FPCHSH(MA,MB,MC) + USE FMVALS + IMPLICIT NONE + REAL (KIND(1.0D0)) :: MA(-1:LPACK),MB(-1:LPACK),MC(-1:LPACK) + CALL FMUNPK(MA,MPA) + CALL FMCHSH(MPA,MPB,MPC) + CALL FMPACK(MPB,MB) + CALL FMPACK(MPC,MC) + RETURN + END SUBROUTINE FPCHSH + + FUNCTION FPCOMP(MA,LREL,MB) + USE FMVALS + IMPLICIT NONE + LOGICAL FPCOMP,FMCOMP + CHARACTER(*) :: LREL + REAL (KIND(1.0D0)) :: MA(-1:LPACK),MB(-1:LPACK) + CALL FMUNPK(MA,MPA) + CALL FMUNPK(MB,MPB) + FPCOMP = FMCOMP(MPA,LREL,MPB) + RETURN + END FUNCTION FPCOMP + + SUBROUTINE FPCOS(MA,MB) + USE FMVALS + IMPLICIT NONE + REAL (KIND(1.0D0)) :: MA(-1:LPACK),MB(-1:LPACK) + CALL FMUNPK(MA,MPA) + CALL FMCOS(MPA,MPB) + CALL FMPACK(MPB,MB) + RETURN + END SUBROUTINE FPCOS + + SUBROUTINE FPCOSH(MA,MB) + USE FMVALS + IMPLICIT NONE + REAL (KIND(1.0D0)) :: MA(-1:LPACK),MB(-1:LPACK) + CALL FMUNPK(MA,MPA) + CALL FMCOSH(MPA,MPB) + CALL FMPACK(MPB,MB) + RETURN + END SUBROUTINE FPCOSH + + SUBROUTINE FPCSSN(MA,MB,MC) + USE FMVALS + IMPLICIT NONE + REAL (KIND(1.0D0)) :: MA(-1:LPACK),MB(-1:LPACK),MC(-1:LPACK) + CALL FMUNPK(MA,MPA) + CALL FMCSSN(MPA,MPB,MPC) + CALL FMPACK(MPB,MB) + CALL FMPACK(MPC,MC) + RETURN + END SUBROUTINE FPCSSN + + SUBROUTINE FPDIG(NSTACK,KST) + USE FMVALS + IMPLICIT NONE + INTEGER NSTACK(19),KST + CALL FMDIG(NSTACK,KST) + RETURN + END SUBROUTINE FPDIG + + SUBROUTINE FPDIM(MA,MB,MC) + USE FMVALS + IMPLICIT NONE + REAL (KIND(1.0D0)) :: MA(-1:LPACK),MB(-1:LPACK),MC(-1:LPACK) + CALL FMUNPK(MA,MPA) + CALL FMUNPK(MB,MPB) + CALL FMDIM(MPA,MPB,MPC) + CALL FMPACK(MPC,MC) + RETURN + END SUBROUTINE FPDIM + + SUBROUTINE FPDIV(MA,MB,MC) + USE FMVALS + IMPLICIT NONE + REAL (KIND(1.0D0)) :: MA(-1:LPACK),MB(-1:LPACK),MC(-1:LPACK) + CALL FMUNPK(MA,MPA) + CALL FMUNPK(MB,MPB) + CALL FMDIV(MPA,MPB,MPC) + CALL FMPACK(MPC,MC) + RETURN + END SUBROUTINE FPDIV + + SUBROUTINE FPDIV_R1(MA,MB) + USE FMVALS + IMPLICIT NONE + REAL (KIND(1.0D0)) :: MA(-1:LPACK),MB(-1:LPACK) + CALL FMUNPK(MA,MPA) + CALL FMUNPK(MB,MPB) + CALL FMDIV(MPA,MPB,MPC) + CALL FMPACK(MPC,MA) + RETURN + END SUBROUTINE FPDIV_R1 + + SUBROUTINE FPDIV_R2(MA,MB) + USE FMVALS + IMPLICIT NONE + REAL (KIND(1.0D0)) :: MA(-1:LPACK),MB(-1:LPACK) + CALL FMUNPK(MA,MPA) + CALL FMUNPK(MB,MPB) + CALL FMDIV(MPA,MPB,MPC) + CALL FMPACK(MPC,MB) + RETURN + END SUBROUTINE FPDIV_R2 + + SUBROUTINE FPDIVI(MA,IVAL,MB) + USE FMVALS + IMPLICIT NONE + REAL (KIND(1.0D0)) :: MA(-1:LPACK),MB(-1:LPACK) + INTEGER IVAL + CALL FMUNPK(MA,MPA) + CALL FMDIVI(MPA,IVAL,MPB) + CALL FMPACK(MPB,MB) + RETURN + END SUBROUTINE FPDIVI + + SUBROUTINE FPDIVI_R1(MA,IVAL) + USE FMVALS + IMPLICIT NONE + REAL (KIND(1.0D0)) :: MA(-1:LPACK) + INTEGER IVAL + CALL FMUNPK(MA,MPA) + CALL FMDIVI(MPA,IVAL,MPB) + CALL FMPACK(MPB,MA) + RETURN + END SUBROUTINE FPDIVI_R1 + + SUBROUTINE FPDP2M(X,MA) + USE FMVALS + IMPLICIT NONE + DOUBLE PRECISION X + REAL (KIND(1.0D0)) :: MA(-1:LPACK) + CALL FMDP2M(X,MPA) + CALL FMPACK(MPA,MA) + RETURN + END SUBROUTINE FPDP2M + + SUBROUTINE FPDPM(X,MA) + USE FMVALS + IMPLICIT NONE + DOUBLE PRECISION X + REAL (KIND(1.0D0)) :: MA(-1:LPACK) + CALL FMDPM(X,MPA) + CALL FMPACK(MPA,MA) + RETURN + END SUBROUTINE FPDPM + + SUBROUTINE FPEQ(MA,MB) + USE FMVALS + IMPLICIT NONE + REAL (KIND(1.0D0)) :: MA(-1:LPACK),MB(-1:LPACK) + CALL FMUNPK(MA,MPA) + CALL FMEQ(MPA,MPB) + CALL FMPACK(MPB,MB) + RETURN + END SUBROUTINE FPEQ + + SUBROUTINE FPEQ2_R1(MA,NDA,NDB) + USE FMVALS + IMPLICIT NONE + REAL (KIND(1.0D0)) :: MA(-1:LPACK) + INTEGER NDA,NDB + INTEGER NDASAV,NDBSAV,NDGSAV + NDASAV = NDA + NDBSAV = NDB + NDGSAV = NDIG + NDIG = NDASAV + CALL FMUNPK(MA,MPA) + CALL FMEQ2_R1(MPA,NDASAV,NDBSAV) + NDIG = NDBSAV + CALL FMPACK(MPA,MA) + NDA = NDASAV + NDB = NDBSAV + NDIG = NDGSAV + RETURN + END SUBROUTINE FPEQ2_R1 + + SUBROUTINE FPEQU(MA,MB,NDA,NDB) + USE FMVALS + IMPLICIT NONE + REAL (KIND(1.0D0)) :: MA(-1:LPACK),MB(-1:LPACK) + INTEGER NDA,NDB + INTEGER NDASAV,NDBSAV,NDGSAV + NDASAV = NDA + NDBSAV = NDB + NDGSAV = NDIG + NDIG = NDASAV + CALL FMUNPK(MA,MPA) + CALL FMEQ2_R1(MPA,NDASAV,NDBSAV) + NDIG = NDBSAV + CALL FMPACK(MPA,MB) + NDA = NDASAV + NDB = NDBSAV + NDIG = NDGSAV + RETURN + END SUBROUTINE FPEQU + + SUBROUTINE FPEXP(MA,MB) + USE FMVALS + IMPLICIT NONE + REAL (KIND(1.0D0)) :: MA(-1:LPACK),MB(-1:LPACK) + CALL FMUNPK(MA,MPA) + CALL FMEXP(MPA,MPB) + CALL FMPACK(MPB,MB) + RETURN + END SUBROUTINE FPEXP + + SUBROUTINE FPFLAG(K) + USE FMVALS + IMPLICIT NONE + INTEGER K + K = KFLAG + RETURN + END SUBROUTINE FPFLAG + + SUBROUTINE FPFORM(FORM,MA,STRING) + USE FMVALS + IMPLICIT NONE + CHARACTER(*) :: FORM,STRING + REAL (KIND(1.0D0)) :: MA(-1:LPACK) + CALL FMUNPK(MA,MPA) + CALL FMFORM(FORM,MPA,STRING) + RETURN + END SUBROUTINE FPFORM + + SUBROUTINE FPFPRT(FORM,MA) + USE FMVALS + IMPLICIT NONE + CHARACTER(*) :: FORM + REAL (KIND(1.0D0)) :: MA(-1:LPACK) + CALL FMUNPK(MA,MPA) + CALL FMFPRT(FORM,MPA) + RETURN + END SUBROUTINE FPFPRT + + SUBROUTINE FPI2M(IVAL,MA) + USE FMVALS + IMPLICIT NONE + INTEGER IVAL + REAL (KIND(1.0D0)) :: MA(-1:LPACK) + CALL FMI2M(IVAL,MPA) + CALL FMPACK(MPA,MA) + RETURN + END SUBROUTINE FPI2M + + SUBROUTINE FPINP(LINE,MA,LA,LB) + USE FMVALS + IMPLICIT NONE + INTEGER LA,LB + CHARACTER LINE(LB) + REAL (KIND(1.0D0)) :: MA(-1:LPACK) + CALL FMINP(LINE,MPA,LA,LB) + CALL FMPACK(MPA,MA) + RETURN + END SUBROUTINE FPINP + + SUBROUTINE FPINT(MA,MB) + USE FMVALS + IMPLICIT NONE + REAL (KIND(1.0D0)) :: MA(-1:LPACK),MB(-1:LPACK) + CALL FMUNPK(MA,MPA) + CALL FMINT(MPA,MPB) + CALL FMPACK(MPB,MB) + RETURN + END SUBROUTINE FPINT + + SUBROUTINE FPIPWR(MA,IVAL,MB) + USE FMVALS + IMPLICIT NONE + REAL (KIND(1.0D0)) :: MA(-1:LPACK),MB(-1:LPACK) + INTEGER IVAL + CALL FMUNPK(MA,MPA) + CALL FMIPWR(MPA,IVAL,MPB) + CALL FMPACK(MPB,MB) + RETURN + END SUBROUTINE FPIPWR + + SUBROUTINE FPLG10(MA,MB) + USE FMVALS + IMPLICIT NONE + REAL (KIND(1.0D0)) :: MA(-1:LPACK),MB(-1:LPACK) + CALL FMUNPK(MA,MPA) + CALL FMLG10(MPA,MPB) + CALL FMPACK(MPB,MB) + RETURN + END SUBROUTINE FPLG10 + + SUBROUTINE FPLN(MA,MB) + USE FMVALS + IMPLICIT NONE + REAL (KIND(1.0D0)) :: MA(-1:LPACK),MB(-1:LPACK) + CALL FMUNPK(MA,MPA) + CALL FMLN(MPA,MPB) + CALL FMPACK(MPB,MB) + RETURN + END SUBROUTINE FPLN + + SUBROUTINE FPLNI(IVAL,MA) + USE FMVALS + IMPLICIT NONE + INTEGER IVAL + REAL (KIND(1.0D0)) :: MA(-1:LPACK) + CALL FMLNI(IVAL,MPA) + CALL FMPACK(MPA,MA) + RETURN + END SUBROUTINE FPLNI + + SUBROUTINE FPM2DP(MA,X) + USE FMVALS + IMPLICIT NONE + REAL (KIND(1.0D0)) :: MA(-1:LPACK) + DOUBLE PRECISION X + CALL FMUNPK(MA,MPA) + CALL FMM2DP(MPA,X) + RETURN + END SUBROUTINE FPM2DP + + SUBROUTINE FPM2I(MA,IVAL) + USE FMVALS + IMPLICIT NONE + REAL (KIND(1.0D0)) :: MA(-1:LPACK) + INTEGER IVAL + CALL FMUNPK(MA,MPA) + CALL FMM2I(MPA,IVAL) + RETURN + END SUBROUTINE FPM2I + + SUBROUTINE FPM2SP(MA,X) + USE FMVALS + IMPLICIT NONE + REAL (KIND(1.0D0)) :: MA(-1:LPACK) + REAL X + CALL FMUNPK(MA,MPA) + CALL FMM2SP(MPA,X) + RETURN + END SUBROUTINE FPM2SP + + SUBROUTINE FPMAX(MA,MB,MC) + USE FMVALS + IMPLICIT NONE + REAL (KIND(1.0D0)) :: MA(-1:LPACK),MB(-1:LPACK),MC(-1:LPACK) + CALL FMUNPK(MA,MPA) + CALL FMUNPK(MB,MPB) + CALL FMMAX(MPA,MPB,MPC) + CALL FMPACK(MPC,MC) + RETURN + END SUBROUTINE FPMAX + + SUBROUTINE FPMIN(MA,MB,MC) + USE FMVALS + IMPLICIT NONE + REAL (KIND(1.0D0)) :: MA(-1:LPACK),MB(-1:LPACK),MC(-1:LPACK) + CALL FMUNPK(MA,MPA) + CALL FMUNPK(MB,MPB) + CALL FMMIN(MPA,MPB,MPC) + CALL FMPACK(MPC,MC) + RETURN + END SUBROUTINE FPMIN + + SUBROUTINE FPMOD(MA,MB,MC) + USE FMVALS + IMPLICIT NONE + REAL (KIND(1.0D0)) :: MA(-1:LPACK),MB(-1:LPACK),MC(-1:LPACK) + CALL FMUNPK(MA,MPA) + CALL FMUNPK(MB,MPB) + CALL FMMOD(MPA,MPB,MPC) + CALL FMPACK(MPC,MC) + RETURN + END SUBROUTINE FPMOD + + SUBROUTINE FPMPY(MA,MB,MC) + USE FMVALS + IMPLICIT NONE + REAL (KIND(1.0D0)) :: MA(-1:LPACK),MB(-1:LPACK),MC(-1:LPACK) + CALL FMUNPK(MA,MPA) + CALL FMUNPK(MB,MPB) + CALL FMMPY(MPA,MPB,MPC) + CALL FMPACK(MPC,MC) + RETURN + END SUBROUTINE FPMPY + + SUBROUTINE FPMPY_R1(MA,MB) + USE FMVALS + IMPLICIT NONE + REAL (KIND(1.0D0)) :: MA(-1:LPACK),MB(-1:LPACK) + CALL FMUNPK(MA,MPA) + CALL FMUNPK(MB,MPB) + CALL FMMPY(MPA,MPB,MPC) + CALL FMPACK(MPC,MA) + RETURN + END SUBROUTINE FPMPY_R1 + + SUBROUTINE FPMPY_R2(MA,MB) + USE FMVALS + IMPLICIT NONE + REAL (KIND(1.0D0)) :: MA(-1:LPACK),MB(-1:LPACK) + CALL FMUNPK(MA,MPA) + CALL FMUNPK(MB,MPB) + CALL FMMPY(MPA,MPB,MPC) + CALL FMPACK(MPC,MB) + RETURN + END SUBROUTINE FPMPY_R2 + + SUBROUTINE FPMPYI(MA,IVAL,MB) + USE FMVALS + IMPLICIT NONE + REAL (KIND(1.0D0)) :: MA(-1:LPACK),MB(-1:LPACK) + INTEGER IVAL + CALL FMUNPK(MA,MPA) + CALL FMMPYI(MPA,IVAL,MPB) + CALL FMPACK(MPB,MB) + RETURN + END SUBROUTINE FPMPYI + + SUBROUTINE FPMPYI_R1(MA,IVAL) + USE FMVALS + IMPLICIT NONE + REAL (KIND(1.0D0)) :: MA(-1:LPACK) + INTEGER IVAL + CALL FMUNPK(MA,MPA) + CALL FMMPYI(MPA,IVAL,MPB) + CALL FMPACK(MPB,MA) + RETURN + END SUBROUTINE FPMPYI_R1 + + SUBROUTINE FPNINT(MA,MB) + USE FMVALS + IMPLICIT NONE + REAL (KIND(1.0D0)) :: MA(-1:LPACK),MB(-1:LPACK) + CALL FMUNPK(MA,MPA) + CALL FMNINT(MPA,MPB) + CALL FMPACK(MPB,MB) + RETURN + END SUBROUTINE FPNINT + + SUBROUTINE FPOUT(MA,LINE,LB) + USE FMVALS + IMPLICIT NONE + REAL (KIND(1.0D0)) :: MA(-1:LPACK) + INTEGER LB + CHARACTER LINE(LB) + CALL FMUNPK(MA,MPA) + CALL FMOUT(MPA,LINE,LB) + RETURN + END SUBROUTINE FPOUT + + SUBROUTINE FPPI(MA) + USE FMVALS + IMPLICIT NONE + REAL (KIND(1.0D0)) :: MA(-1:LPACK) + CALL FMPI(MPA) + CALL FMPACK(MPA,MA) + RETURN + END SUBROUTINE FPPI + + SUBROUTINE FPPRNT(MA) + USE FMVALS + IMPLICIT NONE + REAL (KIND(1.0D0)) :: MA(-1:LPACK) + CALL FMUNPK(MA,MPA) + CALL FMPRNT(MPA) + RETURN + END SUBROUTINE FPPRNT + + SUBROUTINE FPPWR(MA,MB,MC) + USE FMVALS + IMPLICIT NONE + REAL (KIND(1.0D0)) :: MA(-1:LPACK),MB(-1:LPACK),MC(-1:LPACK) + CALL FMUNPK(MA,MPA) + CALL FMUNPK(MB,MPB) + CALL FMPWR(MPA,MPB,MPC) + CALL FMPACK(MPC,MC) + RETURN + END SUBROUTINE FPPWR + + SUBROUTINE FPREAD(KREAD,MA) + USE FMVALS + IMPLICIT NONE + INTEGER KREAD + REAL (KIND(1.0D0)) :: MA(-1:LPACK) + CALL FMREAD(KREAD,MPA) + CALL FMPACK(MPA,MA) + RETURN + END SUBROUTINE FPREAD + + SUBROUTINE FPRPWR(MA,KVAL,JVAL,MB) + USE FMVALS + IMPLICIT NONE + REAL (KIND(1.0D0)) :: MA(-1:LPACK),MB(-1:LPACK) + INTEGER KVAL,JVAL + CALL FMUNPK(MA,MPA) + CALL FMRPWR(MPA,KVAL,JVAL,MPB) + CALL FMPACK(MPB,MB) + RETURN + END SUBROUTINE FPRPWR + + SUBROUTINE FPSET(NPREC) + USE FMVALS + IMPLICIT NONE + INTEGER NPREC + CALL FMSET(NPREC) + RETURN + END SUBROUTINE FPSET + + SUBROUTINE FPSETVAR(STRING) + USE FMVALS + IMPLICIT NONE + CHARACTER(*) :: STRING + CALL FMSETVAR(STRING) + RETURN + END SUBROUTINE FPSETVAR + + SUBROUTINE FPSIGN(MA,MB,MC) + USE FMVALS + IMPLICIT NONE + REAL (KIND(1.0D0)) :: MA(-1:LPACK),MB(-1:LPACK),MC(-1:LPACK) + CALL FMUNPK(MA,MPA) + CALL FMUNPK(MB,MPB) + CALL FMSIGN(MPA,MPB,MPC) + CALL FMPACK(MPC,MC) + RETURN + END SUBROUTINE FPSIGN + + SUBROUTINE FPSIN(MA,MB) + USE FMVALS + IMPLICIT NONE + REAL (KIND(1.0D0)) :: MA(-1:LPACK),MB(-1:LPACK) + CALL FMUNPK(MA,MPA) + CALL FMSIN(MPA,MPB) + CALL FMPACK(MPB,MB) + RETURN + END SUBROUTINE FPSIN + + SUBROUTINE FPSINH(MA,MB) + USE FMVALS + IMPLICIT NONE + REAL (KIND(1.0D0)) :: MA(-1:LPACK),MB(-1:LPACK) + CALL FMUNPK(MA,MPA) + CALL FMSINH(MPA,MPB) + CALL FMPACK(MPB,MB) + RETURN + END SUBROUTINE FPSINH + + SUBROUTINE FPSP2M(X,MA) + USE FMVALS + IMPLICIT NONE + REAL X + REAL (KIND(1.0D0)) :: MA(-1:LPACK) + CALL FMSP2M(X,MPA) + CALL FMPACK(MPA,MA) + RETURN + END SUBROUTINE FPSP2M + + SUBROUTINE FPSQR(MA,MB) + USE FMVALS + IMPLICIT NONE + REAL (KIND(1.0D0)) :: MA(-1:LPACK),MB(-1:LPACK) + CALL FMUNPK(MA,MPA) + CALL FMSQR(MPA,MPB) + CALL FMPACK(MPB,MB) + RETURN + END SUBROUTINE FPSQR + + SUBROUTINE FPSQR_R1(MA) + USE FMVALS + IMPLICIT NONE + REAL (KIND(1.0D0)) :: MA(-1:LPACK) + CALL FMUNPK(MA,MPA) + CALL FMSQR(MPA,MPB) + CALL FMPACK(MPB,MA) + RETURN + END SUBROUTINE FPSQR_R1 + + SUBROUTINE FPSQRT(MA,MB) + USE FMVALS + IMPLICIT NONE + REAL (KIND(1.0D0)) :: MA(-1:LPACK),MB(-1:LPACK) + CALL FMUNPK(MA,MPA) + CALL FMSQRT(MPA,MPB) + CALL FMPACK(MPB,MB) + RETURN + END SUBROUTINE FPSQRT + + SUBROUTINE FPSQRT_R1(MA) + USE FMVALS + IMPLICIT NONE + REAL (KIND(1.0D0)) :: MA(-1:LPACK) + CALL FMUNPK(MA,MPA) + CALL FMSQRT(MPA,MPB) + CALL FMPACK(MPB,MA) + RETURN + END SUBROUTINE FPSQRT_R1 + + SUBROUTINE FPST2M(STRING,MA) + USE FMVALS + IMPLICIT NONE + CHARACTER(*) :: STRING + REAL (KIND(1.0D0)) :: MA(-1:LPACK) + CALL FMST2M(STRING,MPA) + CALL FMPACK(MPA,MA) + RETURN + END SUBROUTINE FPST2M + + SUBROUTINE FPSUB(MA,MB,MC) + USE FMVALS + IMPLICIT NONE + REAL (KIND(1.0D0)) :: MA(-1:LPACK),MB(-1:LPACK),MC(-1:LPACK) + CALL FMUNPK(MA,MPA) + CALL FMUNPK(MB,MPB) + CALL FMSUB(MPA,MPB,MPC) + CALL FMPACK(MPC,MC) + RETURN + END SUBROUTINE FPSUB + + SUBROUTINE FPSUB_R1(MA,MB) + USE FMVALS + IMPLICIT NONE + REAL (KIND(1.0D0)) :: MA(-1:LPACK),MB(-1:LPACK) + CALL FMUNPK(MA,MPA) + CALL FMUNPK(MB,MPB) + CALL FMSUB(MPA,MPB,MPC) + CALL FMPACK(MPC,MA) + RETURN + END SUBROUTINE FPSUB_R1 + + SUBROUTINE FPSUB_R2(MA,MB) + USE FMVALS + IMPLICIT NONE + REAL (KIND(1.0D0)) :: MA(-1:LPACK),MB(-1:LPACK) + CALL FMUNPK(MA,MPA) + CALL FMUNPK(MB,MPB) + CALL FMSUB(MPA,MPB,MPC) + CALL FMPACK(MPC,MB) + RETURN + END SUBROUTINE FPSUB_R2 + + SUBROUTINE FPTAN(MA,MB) + USE FMVALS + IMPLICIT NONE + REAL (KIND(1.0D0)) :: MA(-1:LPACK),MB(-1:LPACK) + CALL FMUNPK(MA,MPA) + CALL FMTAN(MPA,MPB) + CALL FMPACK(MPB,MB) + RETURN + END SUBROUTINE FPTAN + + SUBROUTINE FPTANH(MA,MB) + USE FMVALS + IMPLICIT NONE + REAL (KIND(1.0D0)) :: MA(-1:LPACK),MB(-1:LPACK) + CALL FMUNPK(MA,MPA) + CALL FMTANH(MPA,MPB) + CALL FMPACK(MPB,MB) + RETURN + END SUBROUTINE FPTANH + + SUBROUTINE FPULP(MA,MB) + USE FMVALS + IMPLICIT NONE + REAL (KIND(1.0D0)) :: MA(-1:LPACK),MB(-1:LPACK) + CALL FMUNPK(MA,MPA) + CALL FMULP(MPA,MPB) + CALL FMPACK(MPB,MB) + RETURN + END SUBROUTINE FPULP + + SUBROUTINE FPVARS + CALL FMVARS + RETURN + END SUBROUTINE FPVARS + + SUBROUTINE FPWRIT(KWRITE,MA) + USE FMVALS + IMPLICIT NONE + INTEGER KWRITE + REAL (KIND(1.0D0)) :: MA(-1:LPACK) + CALL FMUNPK(MA,MPA) + CALL FMWRIT(KWRITE,MPA) + RETURN + END SUBROUTINE FPWRIT + +! The IM routines perform integer multiple-precision arithmetic. + + + SUBROUTINE IMABS(MA,MB) + +! MB = ABS(MA) + + USE FMVALS + IMPLICIT NONE + + REAL (KIND(1.0D0)) :: MA(-1:LUNPCK),MB(-1:LUNPCK) + + INTEGER KWRNSV,NDSAVE + + NCALL = NCALL + 1 + IF (KDEBUG == 1) CALL IMARGS('IMABS ',1,MA,MA) + NDSAVE = NDIG + IF (NTRACE /= 0) THEN + NAMEST(NCALL) = 'IMABS ' + CALL IMNTR(2,MA,MA,1) + ENDIF + + KFLAG = 0 + KWRNSV = KWARN + KWARN = 0 + CALL IMEQ(MA,MB) + MB(-1) = 1 + KWARN = KWRNSV + + IF (NTRACE /= 0) CALL IMNTR(1,MB,MB,1) + NCALL = NCALL - 1 + NDIG = NDSAVE + RETURN + END SUBROUTINE IMABS + + SUBROUTINE IMADD(MA,MB,MC) + +! MC = MA + MB + + USE FMVALS + IMPLICIT NONE + + REAL (KIND(1.0D0)) :: MA(-1:LUNPCK),MB(-1:LUNPCK),MC(-1:LUNPCK) + + REAL (KIND(1.0D0)) :: MDA,MDAB,MDB + INTEGER NDSAVE + + NCALL = NCALL + 1 + IF (KDEBUG == 1) CALL IMARGS('IMADD ',2,MA,MB) + NDSAVE = NDIG + IF (NTRACE /= 0) THEN + NAMEST(NCALL) = 'IMADD ' + CALL IMNTR(2,MA,MB,2) + ENDIF + KFLAG = 0 + + IF (MA(1) <= 2) THEN + IF (MB(1) > 2 .OR. MA(1) < 0 .OR. MB(1) < 0) GO TO 110 + IF (MA(1) <= 1) THEN + MDA = MA(-1) * MA(2) + ELSE + MDA = MA(-1) * (MA(2)*MBASE + MA(3)) + ENDIF + IF (MB(1) <= 1) THEN + MDB = MB(-1) * MB(2) + ELSE + MDB = MB(-1) * (MB(2)*MBASE + MB(3)) + ENDIF + MDAB = MDA + MDB + IF (ABS(MDAB) < MBASE) THEN + MC(0) = MIN(MA(0),MB(0)) + MC(1) = 1 + IF (MDAB == 0) MC(1) = 0 + IF (MDAB < 0) THEN + MC(2) = -MDAB + MC(-1) = -1 + ELSE + MC(2) = MDAB + MC(-1) = 1 + ENDIF + MC(3) = 0 + IF (MDA == 0 .OR. MDB == 0) KFLAG = 1 + GO TO 120 + ELSE IF (ABS(MDAB) < MBASE*MBASE) THEN + MC(0) = MIN(MA(0),MB(0)) + MC(1) = 2 + IF (MDAB < 0) THEN + MC(2) = AINT (-MDAB/MBASE) + MC(3) = ABS(-MDAB - MBASE*MC(2)) + MC(-1) = -1 + ELSE + MC(2) = AINT (MDAB/MBASE) + MC(3) = ABS(MDAB - MBASE*MC(2)) + MC(-1) = 1 + ENDIF + IF (MDA == 0 .OR. MDB == 0) KFLAG = 1 + GO TO 120 + ENDIF + ENDIF + +! Check for special cases. + + 110 IF (MA(1) > NDG2MX .OR. MB(1) > NDG2MX .OR. & + MA(1) < 0 .OR. MB(1) < 0) THEN + IF (MA(1) == MUNKNO .OR. MB(1) == MUNKNO) THEN + CALL IMST2M('UNKNOWN',MC) + KFLAG = -4 + GO TO 130 + ENDIF + IF (MA(1) == MEXPOV) THEN + IF (MA(-1) == MB(-1) .OR. MB(2) == 0) THEN + MC(-1) = MA(-1) + MC(0) = MA(0) + MC(1) = MA(1) + MC(2) = MA(2) + MC(3) = MA(3) + KFLAG = -5 + GO TO 130 + ELSE + KFLAG = -4 + NAMEST(NCALL) = 'IMADD ' + CALL FMWARN + CALL IMST2M('UNKNOWN',MC) + GO TO 130 + ENDIF + ENDIF + IF (MB(1) == MEXPOV) THEN + IF (MB(-1) == MA(-1) .OR. MA(2) == 0) THEN + MC(-1) = MB(-1) + MC(0) = MB(0) + MC(1) = MB(1) + MC(2) = MB(2) + MC(3) = MB(3) + KFLAG = -5 + GO TO 130 + ELSE + KFLAG = -4 + NAMEST(NCALL) = 'IMADD ' + CALL FMWARN + CALL IMST2M('UNKNOWN',MC) + GO TO 130 + ENDIF + ENDIF + KFLAG = -4 + NAMEST(NCALL) = 'IMADD ' + CALL FMWARN + CALL IMST2M('UNKNOWN',MC) + GO TO 130 + ENDIF + + CALL IMADD2(MA,MB,MC) + + 120 IF (MC(1) > NDIGMX) THEN + IF (NCALL == 1 .OR. MC(1) > NDG2MX) THEN + IF (MC(-1) > 0) THEN + CALL IMST2M('OVERFLOW',MC) + ELSE + CALL IMST2M('-OVERFLOW',MC) + ENDIF + KFLAG = -5 + NAMEST(NCALL) = 'IMADD ' + CALL FMWARN + ENDIF + ENDIF + + 130 IF (MC(1) <= 1) MC(3) = 0 + IF (NTRACE /= 0) CALL IMNTR(1,MC,MC,1) + NCALL = NCALL - 1 + NDIG = NDSAVE + RETURN + END SUBROUTINE IMADD + + SUBROUTINE IMADD2(MA,MB,MC) + +! Internal addition routine. MC = MA + MB + + USE FMVALS + IMPLICIT NONE + + REAL (KIND(1.0D0)) :: MA(-1:LUNPCK),MB(-1:LUNPCK),MC(-1:LUNPCK) + + REAL (KIND(1.0D0)) :: MAS,MBS + INTEGER J,JCOMP,JSIGN,N1 + IF (MBLOGS /= MBASE) CALL FMCONS + IF (MA(2) == 0) THEN + CALL IMEQ(MB,MC) + KFLAG = 1 + IF (KSUB == 1) THEN + IF (MC(1) /= MUNKNO .AND. MC(2) /= 0) MC(-1) = -MC(-1) + KFLAG = 0 + ENDIF + RETURN + ENDIF + IF (MB(2) == 0) THEN + CALL IMEQ(MA,MC) + KFLAG = 1 + RETURN + ENDIF + + KFLAG = 0 + N1 = MAX(MA(1),MB(1)) + 1 + +! JSIGN is the sign of the result of MA + MB. + + JSIGN = 1 + MAS = MA(-1) + MBS = MB(-1) + IF (KSUB == 1) MBS = -MBS + +! See which one is larger in absolute value. + + JCOMP = 2 + IF (MA(1) > MB(1)) THEN + JCOMP = 1 + ELSE IF (MB(1) > MA(1)) THEN + JCOMP = 3 + ELSE + DO J = 2, N1 + IF (MA(J) > MB(J)) THEN + JCOMP = 1 + EXIT + ENDIF + IF (MB(J) > MA(J)) THEN + JCOMP = 3 + EXIT + ENDIF + ENDDO + ENDIF + + IF (JCOMP < 3) THEN + IF (MAS < 0) JSIGN = -1 + IF (MAS*MBS > 0) THEN + CALL IMADDP(MA,MB) + ELSE + CALL IMADDN(MA,MB) + ENDIF + ELSE + IF (MBS < 0) JSIGN = -1 + IF (MAS*MBS > 0) THEN + CALL IMADDP(MB,MA) + ELSE + CALL IMADDN(MB,MA) + ENDIF + ENDIF + +! Transfer to MC and fix the sign of the result. + + NDIG = MWA(1) + IF (NDIG < 2) NDIG = 2 + IF (NDIG > NDG2MX) NDIG = NDG2MX + CALL FMMOVE(MWA,MC) + MC(0) = NINT(NDIGMX*ALOGM2) + MC(-1) = 1 + IF (JSIGN < 0 .AND. MC(2) /= 0) MC(-1) = -1 + + IF (KFLAG < 0) THEN + IF (KSUB == 1) THEN + NAMEST(NCALL) = 'IMSUB ' + ELSE + NAMEST(NCALL) = 'IMADD ' + ENDIF + CALL FMWARN + ENDIF + + RETURN + END SUBROUTINE IMADD2 + + SUBROUTINE IMADDN(MA,MB) + +! Internal addition routine. MWA = MA - MB +! The arguments are such that MA >= MB >= 0. + + USE FMVALS + IMPLICIT NONE + + REAL (KIND(1.0D0)) :: MA(-1:LUNPCK),MB(-1:LUNPCK) + REAL (KIND(1.0D0)) :: MK + INTEGER J,K,KL,KP1,KP2,KPT,KSH,N1 + + IF (MA(1) == MEXPOV .OR. MB(1) == MEXPOV) THEN + KFLAG = -4 + MWA(1) = MUNKNO + MWA(2) = 1 + MWA(3) = 0 + RETURN + ENDIF + + N1 = MA(1) + 1 + MK = MA(1) - MB(1) + K = INT(MK) + +! Subtract MB from MA. + + KP1 = MIN(N1,K+1) + DO J = 1, KP1 + MWA(J) = MA(J) + ENDDO + KP2 = K + 2 + +! (Inner Loop) + + DO J = KP2, N1 + MWA(J) = MA(J) - MB(J-K) + ENDDO + +! Normalize. Fix the sign of any negative digit. + + IF (K > 0) THEN + DO J = N1, KP2, -1 + IF (MWA(J) < 0) THEN + MWA(J) = MWA(J) + MBASE + MWA(J-1) = MWA(J-1) - 1 + ENDIF + ENDDO + KPT = KP2 - 1 + 110 IF (MWA(KPT) < 0 .AND. KPT >= 3) THEN + MWA(KPT) = MWA(KPT) + MBASE + MWA(KPT-1) = MWA(KPT-1) - 1 + KPT = KPT - 1 + GO TO 110 + ENDIF + ELSE + DO J = N1, 3, -1 + IF (MWA(J) < 0) THEN + MWA(J) = MWA(J) + MBASE + MWA(J-1) = MWA(J-1) - 1 + ENDIF + ENDDO + ENDIF + +! Shift left if there are any leading zeros in the mantissa. + + DO J = 2, N1 + IF (MWA(J) > 0) THEN + KSH = J - 2 + GO TO 120 + ENDIF + ENDDO + MWA(1) = 0 + MWA(3) = 0 + RETURN + + 120 IF (KSH > 0) THEN + KL = N1 - KSH + DO J = 2, KL + MWA(J) = MWA(J+KSH) + ENDDO + DO J = KL+1, N1 + MWA(J) = 0 + ENDDO + MWA(1) = MWA(1) - KSH + ENDIF + + RETURN + END SUBROUTINE IMADDN + + SUBROUTINE IMADDP(MA,MB) + +! Internal addition routine. MWA = MA + MB +! The arguments are such that MA >= MB >= 0. + + USE FMVALS + IMPLICIT NONE + + REAL (KIND(1.0D0)) :: MA(-1:LUNPCK),MB(-1:LUNPCK) + REAL (KIND(1.0D0)) :: MK + INTEGER J,K,KP2,KPT,N1 + + N1 = MA(1) + 1 + MK = MA(1) - MB(1) + K = INT(MK) + +! Add MA and MB. + + MWA(1) = MA(1) + 1 + MWA(2) = 0 + DO J = 2, K+1 + MWA(J+1) = MA(J) + ENDDO + KP2 = K + 2 + +! (Inner Loop) + + DO J = KP2, N1 + MWA(J+1) = MA(J) + MB(J-K) + ENDDO + +! Normalize. Fix any digit not less than MBASE. + + IF (K > 0) THEN + DO J = N1+1, KP2, -1 + IF (MWA(J) >= MBASE) THEN + MWA(J) = MWA(J) - MBASE + MWA(J-1) = MWA(J-1) + 1 + ENDIF + ENDDO + KPT = KP2 - 1 + 110 IF (MWA(KPT) >= MBASE .AND. KPT >= 3) THEN + MWA(KPT) = MWA(KPT) - MBASE + MWA(KPT-1) = MWA(KPT-1) + 1 + KPT = KPT - 1 + GO TO 110 + ENDIF + ELSE + DO J = N1+1, 3, -1 + IF (MWA(J) >= MBASE) THEN + MWA(J) = MWA(J) - MBASE + MWA(J-1) = MWA(J-1) + 1 + ENDIF + ENDDO + ENDIF + + RETURN + END SUBROUTINE IMADDP + + SUBROUTINE IMARGS(KROUTN,NARGS,MA,MB) + +! Check the input arguments to a routine for special cases. + +! KROUTN - Name of the subroutine that was called +! NARGS - The number of input arguments (1 or 2) +! MA - First input argument +! MB - Second input argument (if NARGS is 2) + + USE FMVALS + IMPLICIT NONE + + CHARACTER(6) :: KROUTN + REAL (KIND(1.0D0)) :: MA(-1:LUNPCK),MB(-1:LUNPCK) + INTEGER NARGS + + REAL (KIND(1.0D0)) :: MBS + INTEGER J,KWRNSV,LAST + + KFLAG = -4 + IF (MA(1) == MUNKNO) RETURN + IF (NARGS == 2) THEN + IF (MB(1) == MUNKNO) RETURN + ENDIF + IF (MBLOGS /= MBASE) CALL FMCONS + KFLAG = 0 + +! Check the validity of parameters. + + IF (NCALL > 1 .AND. KDEBUG == 0) RETURN + NAMEST(NCALL) = KROUTN + +! Check MBASE. + + IF (MBASE < 2 .OR. MBASE > MXBASE) THEN + KFLAG = -2 + CALL FMWARN + MBS = MBASE + IF (MBASE < 2) MBASE = 2 + IF (MBASE > MXBASE) MBASE = MXBASE + WRITE (KW, & + "(' MBASE was',I10,'. It has been changed to',I10,'.')" & + ) INT(MBS),INT(MBASE) + CALL FMCONS + RETURN + ENDIF + +! Check exponent range. + + IF (MA(1) > LUNPCK .OR. MA(1) < 0) THEN + IF (ABS(MA(1)) /= MEXPOV .OR. ABS(MA(2)) /= 1) THEN + KFLAG = -3 + CALL FMWARN + CALL IMST2M('UNKNOWN',MA) + RETURN + ENDIF + ENDIF + IF (NARGS == 2) THEN + IF (MB(1) > LUNPCK .OR. MB(1) < 0) THEN + IF (ABS(MB(1)) /= MEXPOV .OR. ABS(MB(2)) /= 1) THEN + KFLAG = -3 + CALL FMWARN + CALL IMST2M('UNKNOWN',MB) + RETURN + ENDIF + ENDIF + ENDIF + +! Check for properly normalized digits in the +! input arguments. + + IF (ABS(MA(1)-INT(MA(1))) /= 0) KFLAG = 1 + IF (MA(2) <= (-1) .OR. MA(2) >= MBASE .OR. & + ABS(MA(2)-INT(MA(2))) /= 0) KFLAG = 2 + IF (KDEBUG == 0) GO TO 110 + LAST = INT(MA(1)) + 1 + IF (MA(1) > LUNPCK) LAST = 3 + DO J = 3, LAST + IF (MA(J) < 0 .OR. MA(J) >= MBASE .OR. & + ABS(MA(J)-INT(MA(J))) /= 0) THEN + KFLAG = J + GO TO 110 + ENDIF + ENDDO + 110 IF (KFLAG /= 0) THEN + J = KFLAG + KFLAG = -4 + KWRNSV = KWARN + IF (KWARN >= 2) KWARN = 1 + CALL FMWARN + KWARN = KWRNSV + IF (KWARN >= 1) THEN + WRITE (KW,*) ' First invalid array element: MA(', & + J,') = ',MA(J) + ENDIF + CALL IMST2M('UNKNOWN',MA) + IF (KWARN >= 2) THEN + STOP + ENDIF + RETURN + ENDIF + IF (NARGS == 2) THEN + IF (ABS(MB(1)-INT(MB(1))) /= 0) KFLAG = 1 + IF (MB(2) <= (-1) .OR. MB(2) >= MBASE .OR. & + ABS(MB(2)-INT(MB(2))) /= 0) KFLAG = 2 + IF (KDEBUG == 0) GO TO 120 + LAST = INT(MB(1)) + 1 + IF (MB(1) > LUNPCK) LAST = 3 + DO J = 3, LAST + IF (MB(J) < 0 .OR. MB(J) >= MBASE .OR. & + ABS(MB(J)-INT(MB(J))) /= 0) THEN + KFLAG = J + GO TO 120 + ENDIF + ENDDO + 120 IF (KFLAG /= 0) THEN + J = KFLAG + KFLAG = -4 + KWRNSV = KWARN + IF (KWARN >= 2) KWARN = 1 + CALL FMWARN + KWARN = KWRNSV + IF (KWARN >= 1) THEN + WRITE (KW,*) ' First invalid array element: MB(', & + J,') = ',MB(J) + ENDIF + CALL IMST2M('UNKNOWN',MB) + IF (KWARN >= 2) THEN + STOP + ENDIF + RETURN + ENDIF + ENDIF + RETURN + END SUBROUTINE IMARGS + + SUBROUTINE IMBIG(MA) + +! MA = The biggest representable IM integer. + + USE FMVALS + IMPLICIT NONE + + REAL (KIND(1.0D0)) :: MA(-1:LUNPCK) + + INTEGER J + + NCALL = NCALL + 1 + NAMEST(NCALL) = 'IMBIG ' + + IF (MBLOGS /= MBASE) CALL FMCONS + KFLAG = 0 + DO J = 2, NDIGMX+1 + MA(J) = MBASE - 1 + ENDDO + MA(1) = NDIGMX + MA(0) = NINT(NDIGMX*ALOGM2) + MA(-1) = 1 + + IF (NTRACE /= 0) CALL IMNTR(1,MA,MA,1) + NCALL = NCALL - 1 + RETURN + END SUBROUTINE IMBIG + + FUNCTION IMCOMP(MA,LREL,MB) + +! Logical comparison of FM numbers MA and MB. + +! LREL is a CHARACTER description of the comparison to be done: +! LREL = 'EQ' returns IMCOMP = .TRUE. if MA == MB +! = 'NE', 'GE', 'GT', 'LE', 'LT' also work like a logical IF. +! = '==', '/=', '<', '<=', '>', '>=' may be used. + +! Some compilers object to functions with side effects such as +! changing KFLAG or other module FMVALS variables. Blocks of +! code that modify these variables are identified by: +! C DELETE START +! ... +! C DELETE STOP +! These may be removed or commented out to produce a function without +! side effects. This disables trace printing in IMCOMP, and error +! codes are not returned in KFLAG. + + USE FMVALS + IMPLICIT NONE + + LOGICAL IMCOMP + CHARACTER(*) :: LREL + CHARACTER(2) :: JREL + REAL (KIND(1.0D0)) :: MA(-1:LUNPCK),MB(-1:LUNPCK) + + INTEGER J,JCOMP,NDSAVE,NLAST,NTRSAV + +! DELETE START + NCALL = NCALL + 1 + IF (KDEBUG == 1) CALL IMARGS('IMCOMP',2,MA,MB) + NAMEST(NCALL) = 'IMCOMP' + + IF (NCALL <= LVLTRC .AND. ABS(NTRACE) >= 2) THEN + WRITE (KW,"(' Input to IMCOMP')") + NDSAVE = NDIG + IF (NTRACE > 0) THEN + CALL IMPRNT(MA) + IF (INDEX('=/<>',LREL(1:1)) > 0) THEN + WRITE (KW,"(8X,A)") LREL + ELSE + WRITE (KW,"(7X,'.',A,'.')") LREL + ENDIF + CALL IMPRNT(MB) + ELSE + NDIG = MAX(2,INT(MA(1))) + IF (NDIG > NDG2MX) NDIG = 2 + NTRSAV = NTRACE + IF (NTRACE < -2) NTRACE = -2 + CALL IMNTRJ(MA,NDIG) + IF (INDEX('=/<>',LREL(1:1)) > 0) THEN + WRITE (KW,"(8X,A)") LREL + ELSE + WRITE (KW,"(7X,'.',A,'.')") LREL + ENDIF + NDIG = MAX(2,INT(MB(1))) + IF (NDIG > NDG2MX) NDIG = 2 + CALL IMNTRJ(MB,NDIG) + NTRACE = NTRSAV + ENDIF + NDIG = NDSAVE + ENDIF +! DELETE STOP + +! JCOMP will be 1 if MA > MB +! 2 if MA == MB +! 3 if MA < MB + +! Check for special cases. + + JREL = LREL + IF (LREL /= 'EQ' .AND. LREL /= 'NE' .AND. LREL /= 'LT' .AND. & + LREL /= 'GT' .AND. LREL /= 'LE' .AND. LREL /= 'GE') THEN + IF (LREL == 'eq' .OR. LREL == '==') THEN + JREL = 'EQ' + ELSE IF (LREL == 'ne' .OR. LREL == '/=') THEN + JREL = 'NE' + ELSE IF (LREL == 'lt' .OR. LREL == '<') THEN + JREL = 'LT' + ELSE IF (LREL == 'gt' .OR. LREL == '>') THEN + JREL = 'GT' + ELSE IF (LREL == 'le' .OR. LREL == '<=') THEN + JREL = 'LE' + ELSE IF (LREL == 'ge' .OR. LREL == '>=') THEN + JREL = 'GE' + ELSE + IMCOMP = .FALSE. +! DELETE START + KFLAG = -4 + IF (NCALL /= 1 .OR. KWARN <= 0) GO TO 120 +! DELETE STOP + IF (KWARN <= 0) GO TO 120 + WRITE (KW, & + "(/' Error of type KFLAG = -4 in FM package in'," // & + "' routine IMCOMP'//1X,A,' is not one of the six'," // & + "' recognized comparisons.'//' .FALSE. has been'," // & + "' returned.'/)" & + ) LREL + IF (KWARN >= 2) THEN + STOP + ENDIF + GO TO 120 + ENDIF + ENDIF + + IF (MA(1) == MUNKNO .OR. MB(1) == MUNKNO) THEN + IMCOMP = .FALSE. +! DELETE START + KFLAG = -4 +! DELETE STOP + GO TO 120 + ENDIF + + IF (ABS(MA(1)) == MEXPOV .AND. MA(1) == MB(1) .AND. & + MA(2) == MB(2) .AND. MA(-1) == MB(-1)) THEN + IMCOMP = .FALSE. +! DELETE START + KFLAG = -4 + IF (NCALL /= 1 .OR. KWARN <= 0) GO TO 120 +! DELETE STOP + IF (KWARN <= 0) GO TO 120 + WRITE (KW, & + "(/' Error of type KFLAG = -4 in FM package in '," // & + "'routine IMCOMP'//' Two numbers in the same '," // & + "'overflow category cannot be compared.'//" // & + "' .FALSE. has been returned.'/)" & + ) + IF (KWARN >= 2) THEN + STOP + ENDIF + GO TO 120 + ENDIF + +! Check for zero. + +! DELETE START + KFLAG = 0 +! DELETE STOP + IF (MA(2) == 0) THEN + JCOMP = 2 + IF (MB(2) == 0) GO TO 110 + IF (MB(-1) < 0) JCOMP = 1 + IF (MB(-1) > 0) JCOMP = 3 + GO TO 110 + ENDIF + IF (MB(2) == 0) THEN + JCOMP = 1 + IF (MA(-1) < 0) JCOMP = 3 + GO TO 110 + ENDIF +! Check for opposite signs. + + IF (MA(-1) > 0 .AND. MB(-1) < 0) THEN + JCOMP = 1 + GO TO 110 + ENDIF + IF (MB(-1) > 0 .AND. MA(-1) < 0) THEN + JCOMP = 3 + GO TO 110 + ENDIF + +! See which one is larger in absolute value. + + IF (MA(1) > MB(1)) THEN + JCOMP = 1 + GO TO 110 + ENDIF + IF (MB(1) > MA(1)) THEN + JCOMP = 3 + GO TO 110 + ENDIF + NLAST = INT(MA(1)) + 1 + IF (NLAST > NDG2MX+1) NLAST = 2 + + DO J = 2, NLAST + IF (ABS(MA(J)) > ABS(MB(J))) THEN + JCOMP = 1 + GO TO 110 + ENDIF + IF (ABS(MB(J)) > ABS(MA(J))) THEN + JCOMP = 3 + GO TO 110 + ENDIF + ENDDO + + JCOMP = 2 + +! Now match the JCOMP value to the requested comparison. + + 110 IF (JCOMP == 1 .AND. MA(-1) < 0) THEN + JCOMP = 3 + ELSE IF (JCOMP == 3 .AND. MB(-1) < 0) THEN + JCOMP = 1 + ENDIF + + IMCOMP = .FALSE. + IF (JCOMP == 1 .AND. (JREL == 'GT' .OR. JREL == 'GE' .OR. & + JREL == 'NE')) IMCOMP = .TRUE. + + IF (JCOMP == 2 .AND. (JREL == 'EQ' .OR. JREL == 'GE' .OR. & + JREL == 'LE')) IMCOMP = .TRUE. + + IF (JCOMP == 3 .AND. (JREL == 'NE' .OR. JREL == 'LT' .OR. & + JREL == 'LE')) IMCOMP = .TRUE. + + 120 CONTINUE +! DELETE START + IF (NTRACE /= 0) THEN + IF (NCALL <= LVLTRC .AND. ABS(NTRACE) >= 1) THEN + IF (KFLAG == 0) THEN + WRITE (KW, & + "(' IMCOMP',15X,'Call level =',I2,5X," // & + "'MBASE =',I10)" & + ) NCALL,INT(MBASE) + ELSE + WRITE (KW, & + "(' IMCOMP',6X,'Call level =',I2,4X," // & + "'MBASE =',I10,4X,'KFLAG =',I3)" & + ) NCALL,INT(MBASE),KFLAG + ENDIF + IF (IMCOMP) THEN + WRITE (KW,"(7X,'.TRUE.')") + ELSE + WRITE (KW,"(7X,'.FALSE.')") + ENDIF + ENDIF + ENDIF + NCALL = NCALL - 1 +! DELETE STOP + RETURN + END FUNCTION IMCOMP + + SUBROUTINE IMDIM(MA,MB,MC) + +! MC = DIM(MA,MB) + +! Positive difference. MC = MA - MB if MA >= MB, +! = 0 otherwise. + + USE FMVALS + IMPLICIT NONE + + REAL (KIND(1.0D0)) :: MA(-1:LUNPCK),MB(-1:LUNPCK),MC(-1:LUNPCK) + + INTEGER KOVFL + LOGICAL IMCOMP + + KFLAG = 0 + NCALL = NCALL + 1 + IF (KDEBUG == 1) CALL IMARGS('IMDIM ',2,MA,MB) + IF (NTRACE /= 0) THEN + NAMEST(NCALL) = 'IMDIM ' + CALL IMNTR(2,MA,MB,2) + ENDIF + + IF (MA(1) == MUNKNO .OR. MB(1) == MUNKNO) THEN + CALL IMST2M('UNKNOWN',MC) + KFLAG = -4 + GO TO 110 + ENDIF + IF (MA(1) < 0 .OR. MB(1) < 0) THEN + KFLAG = -4 + NAMEST(NCALL) = 'IMDIM ' + CALL FMWARN + CALL IMST2M('UNKNOWN',MC) + GO TO 110 + ENDIF + KOVFL = 0 + IF (MA(1) == MEXPOV .OR. MB(1) == MEXPOV) THEN + KOVFL = 1 + IF (MA(1) == MEXPOV .AND. MB(1) == MEXPOV .AND. & + MA(2) == MB(2) .AND. MA(-1) == MB(-1)) THEN + KFLAG = -4 + NAMEST(NCALL) = 'IMDIM ' + CALL FMWARN + CALL IMST2M('UNKNOWN',MC) + GO TO 110 + ENDIF + ENDIF + + IF (IMCOMP(MA,'GE',MB)) THEN + CALL IMSUB(MA,MB,MC) + IF (KFLAG == 1) KFLAG = 0 + ELSE + MC(1) = 0 + MC(2) = 0 + MC(3) = 0 + MC(-1) = 1 + MC(0) = NINT(NDG2MX*ALOGM2) + ENDIF + + IF (MC(1) > NDIGMX) THEN + IF (MC(1) == MUNKNO) THEN + KFLAG = -4 + NAMEST(NCALL) = 'IMDIM ' + CALL FMWARN + ELSE IF (NCALL == 1 .OR. MC(1) > NDG2MX) THEN + IF (MC(-1) > 0) THEN + CALL IMST2M('OVERFLOW',MC) + ELSE + CALL IMST2M('-OVERFLOW',MC) + ENDIF + KFLAG = -5 + NAMEST(NCALL) = 'IMDIM ' + IF (KOVFL /= 1) CALL FMWARN + ENDIF + ENDIF + + 110 IF (MC(1) <= 1) MC(3) = 0 + IF (NTRACE /= 0) CALL IMNTR(1,MC,MC,1) + NCALL = NCALL - 1 + RETURN + END SUBROUTINE IMDIM + + SUBROUTINE IMDIV(MA,MB,MC) + +! MC = INT(MA/MB) + +! Use IMDIVR if both INT(MA/MB) and MOD(MA,MB) are needed. + + USE FMVALS + IMPLICIT NONE + + REAL (KIND(1.0D0)) :: MA(-1:LUNPCK),MB(-1:LUNPCK),MC(-1:LUNPCK) + INTEGER NDSAVE + + NCALL = NCALL + 1 + IF (KDEBUG == 1) CALL IMARGS('IMDIV ',2,MA,MB) + KFLAG = 0 + NDSAVE = NDIG + IF (NTRACE /= 0) THEN + NAMEST(NCALL) = 'IMDIV ' + CALL IMNTR(2,MA,MB,2) + ENDIF + + IF (MA(1) == MUNKNO .OR. MB(1) == MUNKNO) THEN + CALL IMST2M('UNKNOWN',MC) + KFLAG = -4 + GO TO 110 + ENDIF + + CALL IMDIVR(MA,MB,MC,M03) + + IF (MC(1) == MUNKNO) THEN + KFLAG = -4 + NAMEST(NCALL) = 'IMDIV ' + CALL FMWARN + ENDIF + + 110 IF (MC(1) <= 1) MC(3) = 0 + IF (NTRACE /= 0) CALL IMNTR(1,MC,MC,1) + NCALL = NCALL - 1 + NDIG = NDSAVE + RETURN + END SUBROUTINE IMDIV + + SUBROUTINE IMDIVI(MA,IDIV,MB) + +! MB = INT(MA/IDIV) + +! Use IMDVIR if both INT(MA/IDIV) and MOD(MA,IDIV) are needed. + + USE FMVALS + IMPLICIT NONE + + REAL (KIND(1.0D0)) :: MA(-1:LUNPCK),MB(-1:LUNPCK) + INTEGER IDIV,IREM,NDSAVE + + NCALL = NCALL + 1 + IF (KDEBUG == 1) CALL IMARGS('IMDIVI',1,MA,MA) + KFLAG = 0 + NDSAVE = NDIG + IF (NTRACE /= 0) THEN + NAMEST(NCALL) = 'IMDIVI' + CALL IMNTR(2,MA,MA,1) + CALL IMNTRI(2,IDIV,0) + ENDIF + + IF (MA(1) == MUNKNO) THEN + CALL IMST2M('UNKNOWN',MB) + KFLAG = -4 + GO TO 110 + ENDIF + + CALL IMDVIR(MA,IDIV,MB,IREM) + + IF (MB(1) == MUNKNO) THEN + KFLAG = -4 + NAMEST(NCALL) = 'IMDIVI' + CALL FMWARN + ENDIF + + 110 IF (MB(1) <= 1) MB(3) = 0 + IF (NTRACE /= 0) CALL IMNTR(1,MB,MB,1) + NCALL = NCALL - 1 + NDIG = NDSAVE + RETURN + END SUBROUTINE IMDIVI + + SUBROUTINE IMDIVR(MA,MB,MC,MD) + +! MC = INT(MA / MB), MD = Remainder from the division. + + USE FMVALS + IMPLICIT NONE + + REAL (KIND(1.0D0)) :: MA(-1:LUNPCK),MB(-1:LUNPCK),MC(-1:LUNPCK), & + MD(-1:LUNPCK) + REAL (KIND(1.0D0)) :: MDA,MDAB,MDB,MDR + DOUBLE PRECISION XB,XBR,XBASE,XMWA + REAL (KIND(1.0D0)) :: MACCA,MACCB,MAS,MAXMWA,MB1, & + MBM1,MBS,MCARRY,MKT,MLMAX,MQD + INTEGER J,JB,JL,K,KA,KB,KL,KLTFLG,KPTMWA,LCRRCT,NA1,NB1, & + NDSAVE,NGUARD,NL,NMBWDS,NTRSAV + LOGICAL IMCOMP + + NCALL = NCALL + 1 + IF (KDEBUG == 1) CALL IMARGS('IMDIVR',2,MA,MB) + NDSAVE = NDIG + IF (NTRACE /= 0) THEN + NAMEST(NCALL) = 'IMDIVR' + CALL IMNTR(2,MA,MB,2) + ENDIF + KFLAG = 0 + NTRSAV = NTRACE + NTRACE = 0 + IF (MBLOGS /= MBASE) CALL FMCONS + +! Check for special cases. + + IF (MB(1) == 1 .AND. MA(1) /= MUNKNO) THEN + IF (MB(-1)*MB(2) == 1) THEN + CALL IMEQ(MA,MC) + MD(1) = 0 + MD(2) = 0 + MD(3) = 0 + MD(-1) = 1 + MD(0) = NINT(NDG2MX*ALOGM2) + GO TO 170 + ELSE IF (MB(-1)*MB(2) == -1) THEN + CALL IMEQ(MA,MC) + IF (MC(1) /= MUNKNO .AND. MC(2) /= 0) MC(-1) = -MC(-1) + MD(1) = 0 + MD(2) = 0 + MD(3) = 0 + MD(-1) = 1 + MD(0) = NINT(NDG2MX*ALOGM2) + GO TO 170 + ENDIF + ENDIF + IF (MA(1) < MB(1) .AND. MB(1) /= MUNKNO) GO TO 110 + IF (MA(1) > NDG2MX .OR. MB(1) > NDG2MX .OR. & + MA(1) < 0 .OR. MB(1) < 0 .OR. MB(2) == 0) THEN + KFLAG = -4 + IF (MA(1) /= MUNKNO .AND. MB(1) /= MUNKNO) THEN + NAMEST(NCALL) = 'IMDIVR' + CALL FMWARN + ENDIF + CALL IMST2M('UNKNOWN',MC) + CALL IMST2M('UNKNOWN',MD) + GO TO 170 + ENDIF + IF (MA(1) <= 2) THEN + IF (MB(1) > 2) GO TO 110 + IF (MB(2) == 0) GO TO 110 + IF (MA(1) <= 1) THEN + MDA = MA(-1) * MA(2) + ELSE + MDA = MA(-1) * (MA(2)*MBASE + MA(3)) + ENDIF + IF (MB(1) <= 1) THEN + MDB = MB(-1) * MB(2) + ELSE + MDB = MB(-1) * (MB(2)*MBASE + MB(3)) + ENDIF + MDAB = AINT (MDA / MDB) + MDR = MDA - MDAB*MDB + IF (ABS(MDAB) < MBASE) THEN + MC(0) = NINT(NDG2MX*ALOGM2) + MC(1) = 1 + IF (MDAB == 0) MC(1) = 0 + IF (MDAB >= 0) THEN + MC(2) = MDAB + MC(-1) = 1 + ELSE + MC(2) = -MDAB + MC(-1) = -1 + ENDIF + MC(3) = 0 + ELSE IF (ABS(MDAB) < MBASE*MBASE) THEN + MC(0) = NINT(NDG2MX*ALOGM2) + MC(1) = 2 + IF (MDAB >= 0) THEN + MC(2) = AINT (MDAB/MBASE) + MC(3) = ABS(MDAB - MBASE*MC(2)) + MC(-1) = 1 + ELSE + MC(2) = AINT (-MDAB/MBASE) + MC(3) = ABS(-MDAB - MBASE*MC(2)) + MC(-1) = -1 + ENDIF + ELSE + GO TO 110 + ENDIF + IF (ABS(MDR) < MBASE) THEN + MD(0) = MC(0) + MD(1) = 1 + IF (MDR == 0) MD(1) = 0 + IF (MDR >= 0) THEN + MD(2) = MDR + MD(-1) = 1 + ELSE + MD(2) = -MDR + MD(-1) = -1 + ENDIF + MD(3) = 0 + GO TO 170 + ELSE IF (ABS(MDR) < MBASE*MBASE) THEN + MD(0) = MC(0) + MD(1) = 2 + IF (MDR >= 0) THEN + MD(2) = AINT (MDR/MBASE) + MD(3) = ABS(MDR - MBASE*MD(2)) + MD(-1) = 1 + ELSE + MD(2) = AINT (-MDR/MBASE) + MD(3) = ABS(-MDR - MBASE*MD(2)) + MD(-1) = -1 + ENDIF + GO TO 170 + ENDIF + ENDIF + + 110 KLTFLG = 0 + MAS = MA(-1) + MBS = MB(-1) + KL = INT(MB(1)) + IF (KL > NDG2MX) KL = 2 + DO J = 0, KL+1 + M01(J) = MB(J) + ENDDO + M01(-1) = 1 + IF (KL == 1) M01(3) = 0 + IF (MA(1) == M01(1) .AND. ABS(MA(2)) <= M01(2)) THEN + DO J = 2, KL+1 + IF (MA(J) /= M01(J)) GO TO 120 + ENDDO + KLTFLG = 2 + 120 IF (KLTFLG == 0) THEN + DO J = 2, KL+1 + IF (MA(J) < M01(J)) THEN + KLTFLG = 1 + EXIT + ELSE IF (MA(J) > M01(J)) THEN + EXIT + ENDIF + ENDDO + ENDIF + ENDIF + IF (MA(1) < MB(1) .OR. KLTFLG >= 1) THEN + IF (KLTFLG /= 2) THEN + CALL IMEQ(MA,MD) + MD(-1) = ABS(MD(-1)) + CALL IMI2M(0,MC) + ELSE + CALL IMI2M(1,MC) + CALL IMI2M(0,MD) + ENDIF + GO TO 160 + ENDIF + + NDIG = INT(MA(1)) + IF (NDIG < 2) NDIG = 2 + + MACCA = MA(0) + MACCB = MB(0) + +! NGUARD is the number of guard digits used. + + NGUARD = 1 + NA1 = INT(MA(1)) + 1 + NB1 = INT(MB(1)) + 1 + +! Copy MA into the working array. + + DO J = 3, NA1 + MWA(J+1) = MA(J) + ENDDO + MWA(1) = MA(1) - MB(1) + 1 + MWA(2) = 0 + NL = NA1 + NGUARD + 3 + DO J = NA1+2, NL + MWA(J) = 0 + ENDDO + +! Save the sign of MA and MB and then work only with +! positive numbers. + + MAS = MA(-1) + MB1 = MB(1) + MBS = MB(-1) + MWA(3) = MA(2) + +! NMBWDS is the number of words of MB used to +! compute the estimated quotient digit MQD. + + NMBWDS = 4 + IF (MBASE < 100) NMBWDS = 7 + +! XB is an approximation of MB used in +! estimating the quotient digits. + + XBASE = DBLE(MBASE) + XB = 0 + JL = NMBWDS + IF (JL <= NB1) THEN + DO J = 2, JL + XB = XB*XBASE + DBLE(MB(J)) + ENDDO + ELSE + DO J = 2, JL + IF (J <= NB1) THEN + XB = XB*XBASE + DBLE(MB(J)) + ELSE + XB = XB*XBASE + ENDIF + ENDDO + ENDIF + IF (JL+1 <= NB1) XB = XB + DBLE(MB(JL+1))/XBASE + XBR = 1.0D0/XB + +! MLMAX determines when to normalize all of MWA. + + MBM1 = MBASE - 1 + MLMAX = MAXINT/MBM1 + MKT = INTMAX - MBASE + MLMAX = MIN(MLMAX,MKT) + +! MAXMWA is an upper bound on the size of values in MWA +! divided by MBASE-1. It is used to determine whether +! normalization can be postponed. + + MAXMWA = 0 + +! KPTMWA points to the next digit in the quotient. + + KPTMWA = 2 + +! This is the start of the division loop. + +! XMWA is an approximation of the active part of MWA +! used in estimating quotient digits. + + 130 KL = KPTMWA + NMBWDS - 1 + IF (KL <= NL) THEN + XMWA = ((DBLE(MWA(KPTMWA))*XBASE & + + DBLE(MWA(KPTMWA+1)))*XBASE & + + DBLE(MWA(KPTMWA+2)))*XBASE & + + DBLE(MWA(KPTMWA+3)) + DO J = KPTMWA+4, KL + XMWA = XMWA*XBASE + DBLE(MWA(J)) + ENDDO + ELSE + XMWA = DBLE(MWA(KPTMWA)) + DO J = KPTMWA+1, KL + IF (J <= NL) THEN + XMWA = XMWA*XBASE + DBLE(MWA(J)) + ELSE + XMWA = XMWA*XBASE + ENDIF + ENDDO + ENDIF + +! MQD is the estimated quotient digit. + + MQD = AINT(XMWA*XBR) + IF (MQD < 0) MQD = MQD - 1 + + IF (MQD > 0) THEN + MAXMWA = MAXMWA + MQD + ELSE + MAXMWA = MAXMWA - MQD + ENDIF + +! See if MWA must be normalized. + + KA = KPTMWA + 1 + KB = KA + INT(MB1) - 1 + IF (MAXMWA >= MLMAX) THEN + DO J = KB, KA, -1 + IF (MWA(J) < 0) THEN + MCARRY = INT((-MWA(J)-1)/MBASE) + 1 + MWA(J) = MWA(J) + MCARRY*MBASE + MWA(J-1) = MWA(J-1) - MCARRY + ELSE IF (MWA(J) >= MBASE) THEN + MCARRY = -INT(MWA(J)/MBASE) + MWA(J) = MWA(J) + MCARRY*MBASE + MWA(J-1) = MWA(J-1) - MCARRY + ENDIF + ENDDO + XMWA = 0 + IF (KL <= NL) THEN + DO J = KPTMWA, KL + XMWA = XMWA*XBASE + DBLE(MWA(J)) + ENDDO + ELSE + DO J = KPTMWA, KL + IF (J <= NL) THEN + XMWA = XMWA*XBASE + DBLE(MWA(J)) + ELSE + XMWA = XMWA*XBASE + ENDIF + ENDDO + ENDIF + MQD = AINT(XMWA*XBR) + IF (MQD < 0) MQD = MQD - 1 + IF (MQD > 0) THEN + MAXMWA = MQD + ELSE + MAXMWA = -MQD + ENDIF + ENDIF + +! Subtract MQD*MB from MWA. + + JB = KA - 2 + IF (MQD /= 0) THEN + +! Major (Inner Loop) + + DO J = KA, KB + MWA(J) = MWA(J) - MQD*MB(J-JB) + ENDDO + ENDIF + + MWA(KA) = MWA(KA) + MWA(KA-1)*MBASE + MWA(KPTMWA) = MQD + + KPTMWA = KPTMWA + 1 + IF (KPTMWA-2 < MWA(1)) GO TO 130 + +! Final normalization. + + KPTMWA = KPTMWA - 1 + DO J = KPTMWA, 3, -1 + IF (MWA(J) < 0) THEN + MCARRY = INT((-MWA(J)-1)/MBASE) + 1 + MWA(J) = MWA(J) + MCARRY*MBASE + MWA(J-1) = MWA(J-1) - MCARRY + ELSE IF (MWA(J) >= MBASE) THEN + MCARRY = -INT(MWA(J)/MBASE) + MWA(J) = MWA(J) + MCARRY*MBASE + MWA(J-1) = MWA(J-1) - MCARRY + ENDIF + ENDDO + + LCRRCT = 0 + 140 DO J = KPTMWA+INT(MB1), KPTMWA+2, -1 + IF (MWA(J) < 0) THEN + MCARRY = INT((-MWA(J)-1)/MBASE) + 1 + MWA(J) = MWA(J) + MCARRY*MBASE + MWA(J-1) = MWA(J-1) - MCARRY + ELSE IF (MWA(J) >= MBASE) THEN + MCARRY = -INT(MWA(J)/MBASE) + MWA(J) = MWA(J) + MCARRY*MBASE + MWA(J-1) = MWA(J-1) - MCARRY + ENDIF + ENDDO + +! Due to rounding, the remainder may not be between +! 0 and ABS(MB) here. Correct if necessary. + + IF (MWA(KA) < 0) THEN + LCRRCT = LCRRCT - 1 + DO J = KA, KB + MWA(J) = MWA(J) + MB(J-JB) + ENDDO + GO TO 140 + ELSE IF (MWA(KA) >= MBASE) THEN + LCRRCT = LCRRCT + 1 + DO J = KA, KB + MWA(J) = MWA(J) - MB(J-JB) + ENDDO + GO TO 140 + ENDIF + IF (MWA(2) /= 0 .OR. KPTMWA == 2) THEN + DO J = 1, INT(MWA(1))+1 + MC(J) = MWA(J) + ENDDO + ELSE + DO J = 3, INT(MWA(1))+1 + MC(J-1) = MWA(J) + ENDDO + IF (MC(2) /= 0) THEN + MC(1) = MWA(1) - 1 + ELSE + MC(1) = 0 + ENDIF + ENDIF + IF (MC(1) <= 1) MC(3) = 0 + MC(0) = MIN(MACCA,MACCB) + MC(-1) = 1 + + IF (MWA(KPTMWA+1) /= 0) THEN + DO J = 1, INT(MB1) + MD(J+1) = MWA(KPTMWA+J) + ENDDO + MD(1) = MB1 + ELSE + DO J = 1, INT(MB1) + IF (MWA(KPTMWA+J) /= 0) THEN + DO K = J, INT(MB1) + MD(K-J+2) = MWA(KPTMWA+K) + ENDDO + MD(1) = MB1 + 1 - J + GO TO 150 + ENDIF + ENDDO + MD(1) = 0 + MD(2) = 0 + ENDIF + 150 IF (MD(1) <= 1) MD(3) = 0 + MD(0) = MIN(MACCA,MACCB) + MD(-1) = 1 + +! If the remainder had to be corrected, make the +! corresponding adjustment in the quotient. + + IF (MD(1) > M01(1) .OR. & + (MD(1) == M01(1) .AND. ABS(MD(2)) >= M01(2))) THEN + IF (IMCOMP(MD,'GE',M01)) THEN + CALL IMSUB(MD,M01,M10) + CALL IMEQ(M10,MD) + LCRRCT = LCRRCT + 1 + ENDIF + ENDIF + IF (LCRRCT /= 0) THEN + CALL IMI2M(LCRRCT,M02) + CALL IMADD(M02,MC,M10) + CALL IMEQ(M10,MC) + ENDIF + + 160 MC(-1) = 1 + MD(-1) = 1 + IF (MAS < 0 .AND. MBS > 0) THEN + IF (MC(1) /= MUNKNO .AND. MC(2) /= 0) MC(-1) = -1 + IF (MD(1) /= MUNKNO .AND. MD(2) /= 0) MD(-1) = -1 + ELSE IF (MAS > 0 .AND. MBS < 0) THEN + IF (MC(1) /= MUNKNO .AND. MC(2) /= 0) MC(-1) = -1 + ELSE IF (MAS < 0 .AND. MBS < 0) THEN + IF (MD(1) /= MUNKNO .AND. MD(2) /= 0) MD(-1) = -1 + ENDIF + + 170 IF (MC(1) <= 1) MC(3) = 0 + IF (MD(1) <= 1) MD(3) = 0 + NTRACE = NTRSAV + IF (NTRACE /= 0) THEN + CALL IMNTR(1,MC,MC,1) + IF (ABS(NTRACE) >= 1 .AND. NCALL <= LVLTRC) THEN + IF (NTRACE < 0) THEN + NDIG = MAX(2,INT(MD(1))) + IF (NDIG > NDG2MX) NDIG = 2 + NTRSAV = NTRACE + IF (NTRACE < -2) NTRACE = -2 + CALL IMNTRJ(MD,NDIG) + NTRACE = NTRSAV + ELSE + CALL IMPRNT(MD) + ENDIF + ENDIF + ENDIF + NCALL = NCALL - 1 + NDIG = NDSAVE + RETURN + END SUBROUTINE IMDIVR + + SUBROUTINE IMDVIR(MA,IDIV,MB,IREM) + +! MB = INT(MA / IDIV), IREM = Remainder from the division. + +! Division by a one word integer. The remainder is also a +! one word integer. + + USE FMVALS + IMPLICIT NONE + + REAL (KIND(1.0D0)) :: MA(-1:LUNPCK),MB(-1:LUNPCK) + REAL (KIND(1.0D0)) :: MAS,MDA,MDAB,MDB,MDR,MKT,MODINT,MVALP + INTEGER IDIV,IREM,J,JDIV,KA,KL,KLTFLG,KPT,N1,NDSAVE, & + NMVAL,NTRSAV,NV2 + + NCALL = NCALL + 1 + IF (KDEBUG == 1) CALL IMARGS('IMDVIR',1,MA,MA) + KFLAG = 0 + NDSAVE = NDIG + KLTFLG = 0 + NTRSAV = NTRACE + NTRACE = 0 + MKT = ABS(IDIV) + IF (MKT < MBASE) THEN + M01(0) = MA(0) + M01(1) = 1 + M01(2) = ABS(IDIV) + M01(-1) = 1 + IF (IDIV < 0) M01(-1) = -1 + M01(3) = 0 + ELSE IF (MKT < MBASE*MBASE) THEN + M01(0) = MA(0) + M01(1) = 2 + M01(2) = INT(MKT/MBASE) + M01(3) = MKT - M01(2)*MBASE + M01(-1) = 1 + IF (IDIV < 0) M01(-1) = -1 + ELSE + CALL IMI2M(IDIV,M01) + ENDIF + NTRACE = NTRSAV + IF (NTRACE /= 0) THEN + NAMEST(NCALL) = 'IMDVIR' + CALL IMNTR(2,MA,MA,1) + CALL IMNTRI(2,IDIV,0) + ENDIF + JDIV = ABS(IDIV) + +! Check for special cases. + + IF (MA(1) < 0) THEN + IREM = IUNKNO + KFLAG = -4 + NAMEST(NCALL) = 'IMDVIR' + CALL FMWARN + CALL IMST2M('UNKNOWN',MB) + GO TO 150 + ENDIF + IF (JDIV == 1 .AND. MA(1) /= MUNKNO) THEN + IF (IDIV == 1) THEN + CALL IMEQ(MA,MB) + IREM = 0 + GO TO 150 + ELSE + CALL IMEQ(MA,MB) + IF (MB(1) /= MUNKNO .AND. MB(2) /= 0) MB(-1) = -MB(-1) + IREM = 0 + GO TO 150 + ENDIF + ENDIF + IF (MA(1) > NDG2MX .OR. IDIV == 0) THEN + KFLAG = -4 + IF (MA(1) /= MUNKNO) THEN + NAMEST(NCALL) = 'IMDVIR' + CALL FMWARN + ENDIF + CALL IMST2M('UNKNOWN',MB) + IREM = IUNKNO + GO TO 150 + ENDIF + IF (MA(1) <= 2) THEN + IF (MA(1) <= 1) THEN + MDA = MA(-1) * MA(2) + ELSE + MDA = MA(-1) * (MA(2)*MBASE + MA(3)) + ENDIF + MDB = IDIV + MDAB = AINT (MDA/MDB) + MDR = MDA - MDAB*MDB + IF (ABS(MDAB) < MBASE) THEN + MB(0) = MA(0) + MB(1) = 1 + IF (MDAB == 0) MB(1) = 0 + IF (MDAB < 0) THEN + MB(2) = -MDAB + MB(-1) = -1 + ELSE + MB(2) = MDAB + MB(-1) = 1 + ENDIF + MB(3) = 0 + ELSE IF (ABS(MDAB) < MBASE*MBASE) THEN + MB(0) = MA(0) + MB(1) = 2 + IF (MDAB < 0) THEN + MB(2) = AINT (-MDAB/MBASE) + MB(3) = ABS(-MDAB - MBASE*MB(2)) + MB(-1) = -1 + ELSE + MB(2) = AINT (MDAB/MBASE) + MB(3) = ABS(MDAB - MBASE*MB(2)) + MB(-1) = 1 + ENDIF + ELSE + GO TO 110 + ENDIF + IREM = INT(MDR) + GO TO 150 + ENDIF + + 110 MAS = MA(-1) + M01(-1) = 1 + KL = M01(1) + IF (MA(1) <= M01(1)) THEN + IF (MA(1) == M01(1) .AND. ABS(MA(2)) <= M01(2)) THEN + DO J = 2, KL+1 + IF (MA(J) /= M01(J)) THEN + IF (MA(J) < M01(J)) KLTFLG = 1 + GO TO 120 + ENDIF + ENDDO + KLTFLG = 2 + ENDIF + 120 IF (MA(1) < M01(1) .OR. KLTFLG >= 1) THEN + IF (KLTFLG /= 2) THEN + CALL IMM2I(MA,IREM) + IREM = ABS(IREM) + CALL IMI2M(0,MB) + ELSE + CALL IMI2M(1,MB) + IREM = 0 + ENDIF + GO TO 140 + ENDIF + ENDIF + NDIG = INT(MA(1)) + IF (NDIG < 2) NDIG = 2 + N1 = INT(MA(1)) + 1 + +! If ABS(IDIV) >= MXBASE use IMDIVR. + + MVALP = ABS(IDIV) + NMVAL = INT(MVALP) + NV2 = NMVAL - 1 + IF (ABS(IDIV) > MXBASE .OR. NMVAL /= ABS(IDIV) .OR. & + NV2 /= ABS(IDIV)-1) THEN + CALL IMI2M(IDIV,M03) + CALL IMDIVR(MA,M03,MB,M11) + CALL IMEQ(M11,M03) + CALL IMM2I(M03,IREM) + GO TO 150 + ENDIF + +! Find the first significant digit of the quotient. + + MKT = MA(2) + IF (MKT >= MVALP) THEN + KPT = 2 + GO TO 130 + ENDIF + DO J = 3, N1 + MKT = MKT*MBASE + MA(J) + IF (MKT >= MVALP) THEN + KPT = J + GO TO 130 + ENDIF + ENDDO + + CALL IMM2I(MA,IREM) + CALL IMI2M(0,MB) + GO TO 150 + +! Do the rest of the division. + + 130 KA = KPT + 1 + MWA(1) = MA(1) + 2 - KPT + MWA(2) = INT (MKT/MVALP) + MODINT = MKT - MWA(2)*MVALP + IF (KA <= N1) THEN + KL = 3 - KA + +! (Inner Loop) + + DO J = KA, N1 + MKT = MODINT*MBASE + MA(J) + MWA(KL+J) = INT (MKT/MVALP) + MODINT = MKT - MWA(KL+J)*MVALP + ENDDO + ENDIF + + MB(0) = MA(0) + DO J = 1, INT(MWA(1))+1 + MB(J) = MWA(J) + ENDDO + IREM = INT(MODINT) + + 140 MB(-1) = 1 + IF (MAS < 0 .AND. IDIV > 0) THEN + IF (MB(1) /= MUNKNO .AND. MB(2) /= 0) MB(-1) = -1 + IREM = -IREM + ELSE IF (MAS > 0 .AND. IDIV < 0) THEN + IF (MB(1) /= MUNKNO .AND. MB(2) /= 0) MB(-1) = -1 + ELSE IF (MAS < 0 .AND. IDIV < 0) THEN + IREM = -IREM + ENDIF + + 150 IF (MB(1) <= 1) MB(3) = 0 + IF (NTRACE /= 0 .AND. NCALL <= LVLTRC) THEN + CALL IMNTR(1,MB,MB,1) + CALL IMNTRI(1,IREM,0) + ENDIF + + NCALL = NCALL - 1 + NDIG = NDSAVE + RETURN + END SUBROUTINE IMDVIR + + SUBROUTINE IMEQ(MA,MB) + +! MB = MA + + USE FMVALS + IMPLICIT NONE + + REAL (KIND(1.0D0)) :: MA(-1:LUNPCK),MB(-1:LUNPCK) + + INTEGER J,KDG + + KDG = MAX(2,INT(MA(1))) + 1 + IF (KDG > LUNPCK) KDG = 3 + DO J = -1, KDG + MB(J) = MA(J) + ENDDO + RETURN + END SUBROUTINE IMEQ + + SUBROUTINE IMFM2I(MA,MB) + +! MB = INT(MA) + +! Convert from real (FM) format to integer (IM) format. + + USE FMVALS + IMPLICIT NONE + + REAL (KIND(1.0D0)) :: MA(-1:LUNPCK),MB(-1:LUNPCK) + + INTEGER J,NTRSAV + + NCALL = NCALL + 1 + KFLAG = 0 + NTRSAV = NTRACE + NTRACE = 0 + CALL FMEQ(MA,MB) + CALL FMINT(MB,M08) + CALL FMEQ(M08,MB) + IF (MB(1) > NDIGMX) THEN + IF (MB(1) <= NDG2MX .OR. NCALL <= 1) THEN + KFLAG = -4 + NAMEST(NCALL) = 'IMFM2I' + CALL FMWARN + CALL IMST2M('UNKNOWN',MB) + ENDIF + ELSE + DO J = NDIG+2, INT(MA(1))+1 + MB(J) = 0 + ENDDO + ENDIF + IF (MB(1) <= 1) MB(3) = 0 + NTRACE = NTRSAV + NCALL = NCALL - 1 + + RETURN + END SUBROUTINE IMFM2I + + SUBROUTINE IMFORM(FORM,MA,STRING) + +! Convert an IM number (MA) to a character string base 10 (STRING) +! using character string FORM format. + +! FORM can be one of these types: Iw, Fw.d, Ew.d, 1PEw.d +! for positive integers w,d. + + USE FMVALS + IMPLICIT NONE + + CHARACTER(*) :: FORM,STRING + REAL (KIND(1.0D0)) :: MA(-1:LUNPCK) + INTEGER NDSAVE + + NCALL = NCALL + 1 + IF (KDEBUG == 1) CALL IMARGS('IMFORM',1,MA,MA) + KFLAG = 0 + NAMEST(NCALL) = 'IMFORM' + NDSAVE = NDIG + NDIG = INT(MA(1)) + IF (NDIG < 2 .OR. NDIG > NDG2MX) NDIG = 2 + + CALL FMFORM(FORM,MA,STRING) + + NCALL = NCALL - 1 + NDIG = NDSAVE + RETURN + END SUBROUTINE IMFORM + + SUBROUTINE IMFPRT(FORM,MA) + +! Print an IM number (MA) on unit KW using character +! string FORM format. + +! FORM can be one of these types: Iw, Fw.d, Ew.d, 1PEw.d +! for positive integers w,d. + + USE FMVALS + IMPLICIT NONE + + CHARACTER(*) :: FORM + REAL (KIND(1.0D0)) :: MA(-1:LUNPCK) + INTEGER NDSAVE + + NCALL = NCALL + 1 + IF (KDEBUG == 1) CALL IMARGS('IMFPRT',1,MA,MA) + KFLAG = 0 + NAMEST(NCALL) = 'IMFPRT' + NDSAVE = NDIG + NDIG = INT(MA(1)) + IF (NDIG < 2 .OR. NDIG > NDG2MX) NDIG = 2 + + CALL FMFPRT(FORM,MA) + + NCALL = NCALL - 1 + NDIG = NDSAVE + RETURN + END SUBROUTINE IMFPRT + + SUBROUTINE IMGCD(MA,MB,MC) + +! MC is returned as the greatest common divisor of MA and MB. + + USE FMVALS + IMPLICIT NONE + + REAL (KIND(1.0D0)) :: MA(-1:LUNPCK),MB(-1:LUNPCK),MC(-1:LUNPCK) + INTEGER NDSAVE + + NCALL = NCALL + 1 + IF (KDEBUG == 1) CALL IMARGS('IMGCD ',2,MA,MB) + KFLAG = 0 + NDSAVE = NDIG + IF (NTRACE /= 0) THEN + NAMEST(NCALL) = 'IMGCD ' + CALL IMNTR(2,MA,MB,2) + ENDIF + +! Check for special cases. + + IF (MA(1) == MUNKNO .OR. MB(1) == MUNKNO) THEN + CALL IMST2M('UNKNOWN',MC) + KFLAG = -4 + GO TO 120 + ELSE IF (MB(2) == 0) THEN + CALL IMABS(MA,MC) + GO TO 120 + ELSE IF (MA(2) == 0) THEN + CALL IMABS(MB,MC) + GO TO 120 + ELSE IF (MB(1) == 1 .AND. ABS(MB(2)) == 1) THEN + CALL IMI2M(1,MC) + GO TO 120 + ELSE IF (MA(1) == 1 .AND. ABS(MA(2)) == 1) THEN + CALL IMI2M(1,MC) + GO TO 120 + ELSE IF (MA(1) >= NDG2MX .OR. MB(1) >= NDG2MX .OR. & + MA(1) < 0 .OR. MB(1) < 0) THEN + KFLAG = -4 + NAMEST(NCALL) = 'IMGCD ' + CALL FMWARN + CALL IMST2M('UNKNOWN',MC) + GO TO 120 + ENDIF + + CALL IMABS(MA,M05) + CALL IMABS(MB,M04) + CALL IMMAX(M05,M04,M03) + CALL IMMIN(M05,M04,M11) + CALL IMEQ(M11,M04) + 110 CALL IMDIVR(M03,M04,MC,M05) + IF (M05(2) /= 0) THEN + CALL IMEQ(M04,M03) + CALL IMEQ(M05,M04) + GO TO 110 + ENDIF + CALL IMEQ(M04,MC) + + IF (MC(1) == MUNKNO) THEN + KFLAG = -4 + NAMEST(NCALL) = 'IMGCD ' + CALL FMWARN + ENDIF + + 120 IF (MC(1) <= 1) MC(3) = 0 + IF (NTRACE /= 0) CALL IMNTR(1,MC,MC,1) + NCALL = NCALL - 1 + NDIG = NDSAVE + RETURN + END SUBROUTINE IMGCD + + SUBROUTINE IMI2FM(MA,MB) + +! MB = MA + +! Convert from integer (IM) format to real (FM) format. + + USE FMVALS + IMPLICIT NONE + + REAL (KIND(1.0D0)) :: MA(-1:LUNPCK),MB(-1:LUNPCK) + + INTEGER KDG + + NCALL = NCALL + 1 + IF (KDEBUG == 1) CALL IMARGS('IMI2FM',1,MA,MA) + KFLAG = 0 + KDG = MAX(2,INT(MA(1))) + IF (KDG > NDG2MX) KDG = 2 + CALL FMEQU(MA,MB,KDG,NDIG) + MB(0) = NINT(NDG2MX*ALOGM2) + NCALL = NCALL - 1 + + RETURN + END SUBROUTINE IMI2FM + + SUBROUTINE IMI2M(IVAL,MA) + +! MA = IVAL + +! Convert a one word integer to IM format. + + USE FMVALS + IMPLICIT NONE + + REAL (KIND(1.0D0)) :: MA(-1:LUNPCK) + INTEGER IVAL + + INTEGER NDSAVE + + NCALL = NCALL + 1 + KFLAG = 0 + NDSAVE = NDIG + IF (NTRACE /= 0) THEN + NAMEST(NCALL) = 'IMI2M ' + CALL IMNTRI(2,IVAL,1) + + NDIG = 4 + CALL FMIM(IVAL,MA) + IF (MA(1) > 4) THEN + NDIG = NDIGMX + CALL FMIM(IVAL,MA) + ENDIF + + CALL IMNTR(1,MA,MA,1) + ELSE + NDIG = 4 + CALL FMIM(IVAL,MA) + IF (MA(1) > 4) THEN + NDIG = NDIGMX + CALL FMIM(IVAL,MA) + ENDIF + ENDIF + IF (MA(1) <= 1) MA(3) = 0 + NDIG = NDSAVE + NCALL = NCALL - 1 + RETURN + END SUBROUTINE IMI2M + + SUBROUTINE IMINP(LINE,MA,LA,LB) + +! Convert an array of characters to multiple precision integer format. + +! LINE is an A1 character array of length LB to be converted +! to IM format and returned in MA. +! LA is a pointer telling the routine where in the array to begin +! the conversion. +! LB is a pointer to the last character of the field for that number. + + USE FMVALS + IMPLICIT NONE + + INTEGER KFSAVE,NDSAVE,LA,LB + CHARACTER LINE(LB) + REAL (KIND(1.0D0)) :: MA(-1:LUNPCK) + + NCALL = NCALL + 1 + KFLAG = 0 + NDSAVE = NDIG + NAMEST(NCALL) = 'IMINP ' + + NDIG = NDIGMX + CALL FMINP(LINE,MA,LA,LB) + KFSAVE = KFLAG + CALL FMINT(MA,M08) + CALL FMEQ(M08,MA) + KFLAG = KFSAVE + + IF (MA(1) > NDG2MX .AND. MA(1) < MEXPOV) THEN + KFLAG = -9 + NDIG = INT(MA(1)) + CALL FMWARN + MA(-1) = 1 + MA(0) = NINT(NDG2MX*ALOGM2) + MA(1) = MUNKNO + MA(2) = 1 + MA(3) = 0 + ENDIF + + IF (MA(1) <= 1) MA(3) = 0 + NDIG = NDSAVE + IF (NTRACE /= 0) CALL IMNTR(1,MA,MA,1) + NCALL = NCALL - 1 + RETURN + END SUBROUTINE IMINP + + SUBROUTINE IMM2DP(MA,X) + +! X = MA + +! Convert an IM number to double precision. + +! If KFLAG = -4 is returned for a value of MA that is in the range +! of the machine's double precision number system, change the +! definition of DPMAX in routine FMSET to reflect the current machine's +! range. + + USE FMVALS + IMPLICIT NONE + + REAL (KIND(1.0D0)) :: MA(-1:LUNPCK) + DOUBLE PRECISION X + + INTEGER KRESLT,NDSAVE + + NCALL = NCALL + 1 + KFLAG = 0 + NAMEST(NCALL) = 'IMM2DP' + KRESLT = 0 + IF (ABS(MA(1)) > MEXPAB) THEN + CALL FMARGS('IMM2DP',1,MA,MA,KRESLT) + ENDIF + IF (NTRACE /= 0) CALL IMNTR(2,MA,MA,1) + IF (KRESLT /= 0) THEN + +! Here no valid result can be returned. Set X to some +! value that the user is likely to recognize as wrong. + + X = DBLE(RUNKNO) + KFLAG = -4 + IF (MA(1) /= MUNKNO) CALL FMWARN + IF (NTRACE /= 0) CALL IMNTRR(1,X,1) + NCALL = NCALL - 1 + RETURN + ENDIF + + NDSAVE = NDIG + NDIG = MAX(2,INT(MA(1))) + IF (NDIG > NDG2MX) NDIG = 2 + CALL FMMD(MA,X) + + IF (NTRACE /= 0) CALL IMNTRR(1,X,1) + NDIG = NDSAVE + NCALL = NCALL - 1 + RETURN + END SUBROUTINE IMM2DP + + SUBROUTINE IMM2I(MA,IVAL) + +! IVAL = MA + +! Convert an IM number to a one word integer. + +! KFLAG = 0 is returned if the conversion is exact. +! = -4 is returned if MA is larger than INTMAX in magnitude. +! IVAL = IUNKNO is returned as an indication that IVAL +! could not be computed without integer overflow. + + USE FMVALS + IMPLICIT NONE + + REAL (KIND(1.0D0)) :: MA(-1:LUNPCK) + + INTEGER IVAL,NDSAVE + + NCALL = NCALL + 1 + IF (KDEBUG == 1) CALL IMARGS('IMM2I ',1,MA,MA) + NDSAVE = NDIG + IF (NTRACE /= 0) THEN + NAMEST(NCALL) = 'IMM2I ' + CALL IMNTR(2,MA,MA,1) + ENDIF + + NDIG = INT(MA(1)) + IF (NDIG < 2) NDIG = 2 + IF (NDIG > NDG2MX) NDIG = 2 + KFLAG = 0 + CALL FMM2I(MA,IVAL) + + IF (ABS(NTRACE) >= 1 .AND. NCALL <= LVLTRC) THEN + CALL IMNTRI(1,IVAL,1) + ENDIF + NCALL = NCALL - 1 + NDIG = NDSAVE + RETURN + END SUBROUTINE IMM2I + + SUBROUTINE IMMAX(MA,MB,MC) + +! MC = MAX(MA,MB) + + USE FMVALS + IMPLICIT NONE + + REAL (KIND(1.0D0)) :: MA(-1:LUNPCK),MB(-1:LUNPCK),MC(-1:LUNPCK) + + INTEGER KWRNSV + LOGICAL IMCOMP + + KFLAG = 0 + NCALL = NCALL + 1 + IF (KDEBUG == 1) CALL IMARGS('IMMAX ',2,MA,MB) + IF (NTRACE /= 0) THEN + NAMEST(NCALL) = 'IMMAX ' + CALL IMNTR(2,MA,MB,2) + ENDIF + + KWRNSV = KWARN + KWARN = 0 + IF (MA(1) == MUNKNO .OR. MB(1) == MUNKNO) THEN + CALL IMST2M('UNKNOWN',MC) + KFLAG = -4 + ELSE IF (IMCOMP(MA,'LT',MB)) THEN + CALL IMEQ(MB,MC) + ELSE + CALL IMEQ(MA,MC) + ENDIF + + IF (MC(1) <= 1) MC(3) = 0 + KWARN = KWRNSV + IF (NTRACE /= 0) CALL IMNTR(1,MC,MC,1) + NCALL = NCALL - 1 + RETURN + END SUBROUTINE IMMAX + + SUBROUTINE IMMIN(MA,MB,MC) + +! MC = MIN(MA,MB) + + USE FMVALS + IMPLICIT NONE + + REAL (KIND(1.0D0)) :: MA(-1:LUNPCK),MB(-1:LUNPCK),MC(-1:LUNPCK) + + INTEGER KWRNSV + LOGICAL IMCOMP + + KFLAG = 0 + NCALL = NCALL + 1 + IF (KDEBUG == 1) CALL IMARGS('IMMIN ',2,MA,MB) + IF (NTRACE /= 0) THEN + NAMEST(NCALL) = 'IMMIN ' + CALL IMNTR(2,MA,MB,2) + ENDIF + + KWRNSV = KWARN + KWARN = 0 + IF (MA(1) == MUNKNO .OR. MB(1) == MUNKNO) THEN + CALL IMST2M('UNKNOWN',MC) + KFLAG = -4 + ELSE IF (IMCOMP(MA,'GT',MB)) THEN + CALL IMEQ(MB,MC) + ELSE + CALL IMEQ(MA,MC) + ENDIF + + IF (MC(1) <= 1) MC(3) = 0 + KWARN = KWRNSV + IF (NTRACE /= 0) CALL IMNTR(1,MC,MC,1) + NCALL = NCALL - 1 + RETURN + END SUBROUTINE IMMIN + + SUBROUTINE IMMOD(MA,MB,MC) + +! MC = MOD(MA,MB) + +! Use IMDIVR if both INT(MA/MB) and MOD(MA,MB) are needed. + + USE FMVALS + IMPLICIT NONE + + REAL (KIND(1.0D0)) :: MA(-1:LUNPCK),MB(-1:LUNPCK),MC(-1:LUNPCK) + INTEGER NDSAVE + + NCALL = NCALL + 1 + IF (KDEBUG == 1) CALL IMARGS('IMMOD ',2,MA,MB) + KFLAG = 0 + NDSAVE = NDIG + IF (NTRACE /= 0) THEN + NAMEST(NCALL) = 'IMMOD ' + CALL IMNTR(2,MA,MB,2) + ENDIF + + IF (MA(1) == MUNKNO .OR. MB(1) == MUNKNO) THEN + CALL IMST2M('UNKNOWN',MC) + KFLAG = -4 + GO TO 110 + ENDIF + + CALL IMDIVR(MA,MB,M03,MC) + + IF (MC(1) == MUNKNO) THEN + KFLAG = -4 + NAMEST(NCALL) = 'IMMOD ' + CALL FMWARN + ENDIF + + 110 IF (MC(1) <= 1) MC(3) = 0 + IF (NTRACE /= 0) CALL IMNTR(1,MC,MC,1) + NCALL = NCALL - 1 + NDIG = NDSAVE + RETURN + END SUBROUTINE IMMOD + + SUBROUTINE IMMPY(MA,MB,MC) + +! MC = MA * MB + + USE FMVALS + IMPLICIT NONE + + REAL (KIND(1.0D0)) :: MA(-1:LUNPCK),MB(-1:LUNPCK),MC(-1:LUNPCK) + + REAL (KIND(1.0D0)) :: MDAB + INTEGER KOVFL,NDSAVE + + NCALL = NCALL + 1 + IF (KDEBUG == 1) CALL IMARGS('IMMPY ',2,MA,MB) + KFLAG = 0 + NDSAVE = NDIG + IF (NTRACE /= 0) THEN + NAMEST(NCALL) = 'IMMPY ' + CALL IMNTR(2,MA,MB,2) + ENDIF + + IF (MA(1) <= 1) THEN + IF (MB(1) > 1) GO TO 110 + MDAB = MA(-1) * MA(2) * MB(-1) * MB(2) + IF (ABS(MDAB) < MBASE) THEN + MC(0) = MIN(MA(0),MB(0)) + MC(1) = 1 + IF (MDAB == 0) MC(1) = 0 + IF (MDAB >= 0) THEN + MC(2) = MDAB + MC(-1) = 1 + ELSE + MC(2) = -MDAB + MC(-1) = -1 + ENDIF + MC(3) = 0 + GO TO 120 + ELSE IF (ABS(MDAB) < MBASE*MBASE) THEN + MC(0) = MIN(MA(0),MB(0)) + MC(1) = 2 + IF (MDAB >= 0) THEN + MC(2) = AINT (MDAB/MBASE) + MC(3) = ABS(MDAB - MBASE*MC(2)) + MC(-1) = 1 + ELSE + MC(2) = AINT (-MDAB/MBASE) + MC(3) = ABS(-MDAB - MBASE*MC(2)) + MC(-1) = -1 + ENDIF + GO TO 120 + ENDIF + ENDIF + +! Check for special cases. + + 110 KOVFL = 0 + IF (MA(1) == MUNKNO .OR. MB(1) == MUNKNO) THEN + KFLAG = -4 + CALL IMST2M('UNKNOWN',MC) + GO TO 130 + ENDIF + IF (MA(2) == 0 .OR. MB(2) == 0) THEN + MC(-1) = 1 + MC(0) = NINT(NDG2MX*ALOGM2) + MC(1) = 0 + MC(2) = 0 + MC(3) = 0 + GO TO 130 + ENDIF + IF (MA(1) == MEXPOV .OR. MB(1) == MEXPOV) THEN + KOVFL = 1 + KFLAG = -5 + IF (MA(-1)*MB(-1) < 0) THEN + CALL IMST2M('-OVERFLOW',MC) + ELSE + CALL IMST2M('OVERFLOW',MC) + ENDIF + GO TO 130 + ENDIF + IF (MA(1) < 0 .OR. MB(1) < 0) THEN + KFLAG = -4 + NAMEST(NCALL) = 'IMMPY ' + CALL FMWARN + CALL IMST2M('UNKNOWN',MC) + GO TO 130 + ENDIF + IF (MB(1) == 1 .AND. MB(2) == 1 .AND. MB(-1) == 1) THEN + CALL IMEQ(MA,MC) + GO TO 120 + ELSE IF (MB(1) == 1 .AND. MB(2) == 1 .AND. MB(-1) == -1) THEN + CALL IMEQ(MA,MC) + IF (MC(1) /= MUNKNO .AND. MC(2) /= 0) MC(-1) = -MC(-1) + GO TO 120 + ELSE IF (MA(1) == 1 .AND. MA(2) == 1 .AND. MA(-1) == 1) THEN + CALL IMEQ(MB,MC) + GO TO 120 + ELSE IF (MA(1) == 1 .AND. MA(2) == 1 .AND. MA(-1) == -1) THEN + CALL IMEQ(MB,MC) + IF (MC(1) /= MUNKNO .AND. MC(2) /= 0) MC(-1) = -MC(-1) + GO TO 120 + ENDIF + NDIG = INT(MA(1) + MB(1)) + IF (NDIG > NDIGMX) THEN + IF (NCALL == 1 .OR. NDIG > NDG2MX) THEN + IF (MA(-1)*MB(-1) > 0) THEN + CALL IMST2M('OVERFLOW',MC) + ELSE + CALL IMST2M('-OVERFLOW',MC) + ENDIF + KFLAG = -5 + NAMEST(NCALL) = 'IMMPY ' + CALL FMWARN + GO TO 130 + ENDIF + ENDIF + + IF (NDIG < 2) NDIG = 2 + IF (NDIG > NDG2MX) NDIG = NDG2MX + CALL IMMPY2(MA,MB) + +! Transfer to MC and fix the sign of the result. + + NDIG = MWA(1) + IF (NDIG < 2) NDIG = 2 + IF (NDIG > NDG2MX) NDIG = NDG2MX + IF (MA(-1)*MB(-1) < 0) THEN + CALL FMMOVE(MWA,MC) + MC(0) = NINT(NDIGMX*ALOGM2) + MC(-1) = -1 + ELSE + CALL FMMOVE(MWA,MC) + MC(0) = NINT(NDIGMX*ALOGM2) + MC(-1) = 1 + ENDIF + + IF (NDIG > NDIGMX) NDIG = 2 + 120 IF (MC(1) > NDIGMX) THEN + IF (NCALL == 1 .OR. MC(1) > NDG2MX) THEN + IF (MC(-1) > 0) THEN + CALL IMST2M('OVERFLOW',MC) + ELSE + CALL IMST2M('-OVERFLOW',MC) + ENDIF + KFLAG = -5 + NAMEST(NCALL) = 'IMMPY ' + IF (KOVFL /= 1) CALL FMWARN + ENDIF + ENDIF + + 130 IF (MC(1) <= 1) MC(3) = 0 + IF (NTRACE /= 0) CALL IMNTR(1,MC,MC,1) + NCALL = NCALL - 1 + NDIG = NDSAVE + RETURN + END SUBROUTINE IMMPY + + SUBROUTINE IMMPY2(MA,MB) + +! Internal multiplication of MA*MB. The result is returned in MWA. +! Both MA and MB are positive. + + USE FMVALS + IMPLICIT NONE + + REAL (KIND(1.0D0)) :: MA(-1:LUNPCK),MB(-1:LUNPCK) + + REAL (KIND(1.0D0)) :: MAXMWA,MBJ,MBM1,MKT,MMAX + INTEGER J,JM1,K,KB,KL,KLMA,KLMB,N1 + + N1 = NDIG + 1 + MWA(1) = MA(1) + MB(1) + MWA(N1+1) = 0 + +! The multiplication loop begins here. + +! MAXMWA is an upper bound on the size of values in MWA +! divided by (MBASE-1). It is used to determine +! whether to normalize before the next digit is +! multiplied. + + MBM1 = MBASE - 1 + MMAX = INTMAX - MBASE + MMAX = MIN(AINT (MAXINT/MBM1 - MBM1),MMAX) + MBJ = MB(2) + MWA(2) = 0 + KLMA = INT(MA(1)) + DO K = KLMA+3, N1 + MWA(K) = 0 + ENDDO + +! (Inner Loop) + + DO K = 2, KLMA+1 + MWA(K+1) = MA(K)*MBJ + ENDDO + MAXMWA = MBJ + KLMB = INT(MB(1)) + DO J = 3, KLMB+1 + MBJ = MB(J) + IF (MBJ /= 0) THEN + MAXMWA = MAXMWA + MBJ + JM1 = J - 1 + KL = KLMA + 1 + +! Major (Inner Loop) + + DO K = J+1, J+KLMA + MWA(K) = MWA(K) + MA(K-JM1)*MBJ + ENDDO + ENDIF + + IF (MAXMWA > MMAX) THEN + MAXMWA = 0 + +! Here normalization is only required for the +! range of digits currently changing in MWA. + + DO KB = JM1+KL, JM1+2, -1 + MKT = INT (MWA(KB)/MBASE) + MWA(KB-1) = MWA(KB-1) + MKT + MWA(KB) = MWA(KB) - MKT*MBASE + ENDDO + ENDIF + ENDDO + +! Perform the final normalization. (Inner Loop) + + DO KB = N1, 3, -1 + MKT = INT (MWA(KB)/MBASE) + MWA(KB-1) = MWA(KB-1) + MKT + MWA(KB) = MWA(KB) - MKT*MBASE + ENDDO + + RETURN + END SUBROUTINE IMMPY2 + + SUBROUTINE IMMPYI(MA,IVAL,MB) + +! MB = MA * IVAL + +! Multiplication by a one word integer. + + USE FMVALS + IMPLICIT NONE + + REAL (KIND(1.0D0)) :: MA(-1:LUNPCK),MB(-1:LUNPCK) + REAL (KIND(1.0D0)) :: MAS,MCARRY,MDAB,MKT,MVAL + INTEGER IVAL,J,KA,KB,KC,KOVFL,KSHIFT,N1,NDSAVE,NMVAL, & + NTRSAV,NV2 + + NCALL = NCALL + 1 + IF (KDEBUG == 1) CALL IMARGS('IMMPYI',1,MA,MA) + KFLAG = 0 + NDSAVE = NDIG + NTRSAV = NTRACE + NTRACE = 0 + NTRACE = NTRSAV + IF (NTRACE /= 0) THEN + NAMEST(NCALL) = 'IMMPYI' + CALL IMNTR(2,MA,MA,1) + CALL IMNTRI(2,IVAL,0) + ENDIF + MAS = MA(-1) + + IF (MA(1) <= 1) THEN + MDAB = MA(-1) * MA(2) * IVAL + IF (ABS(MDAB) < MBASE) THEN + MB(0) = MA(0) + MB(1) = 1 + IF (MDAB == 0) MB(1) = 0 + MB(-1) = 1 + IF (MDAB < 0) MB(-1) = -1 + MB(2) = ABS(MDAB) + MB(3) = 0 + GO TO 120 + ELSE IF (ABS(MDAB) < MBASE*MBASE) THEN + MB(0) = MA(0) + MB(1) = 2 + MB(-1) = 1 + IF (MDAB < 0) MB(-1) = -1 + MDAB = ABS(MDAB) + MB(2) = AINT (MDAB/MBASE) + MB(3) = MDAB - MBASE*MB(2) + GO TO 120 + ENDIF + ENDIF + +! Check for special cases. + + KOVFL = 0 + IF (MA(1) == MEXPOV) KOVFL = 1 + IF (MA(1) < 0) THEN + KFLAG = -4 + NAMEST(NCALL) = 'IMMPYI' + CALL FMWARN + CALL IMST2M('UNKNOWN',MB) + GO TO 130 + ENDIF + IF (MA(1) == MUNKNO) THEN + KFLAG = -4 + CALL IMST2M('UNKNOWN',MB) + GO TO 130 + ELSE IF (IVAL == 0) THEN + CALL IMI2M(0,MB) + GO TO 120 + ELSE IF (IVAL == 1) THEN + CALL IMEQ(MA,MB) + GO TO 120 + ELSE IF (IVAL == -1) THEN + CALL IMEQ(MA,MB) + IF (MB(1) /= MUNKNO .AND. MB(2) /= 0) MB(-1) = -MB(-1) + GO TO 120 + ELSE IF (MA(1) == 1 .AND. MA(2)*MA(-1) == 1) THEN + CALL IMI2M(IVAL,MB) + GO TO 120 + ELSE IF (MA(1) == 1 .AND. MA(2)*MA(-1) == -1) THEN + CALL IMI2M(IVAL,MB) + IF (MB(1) /= MUNKNO .AND. MB(2) /= 0) MB(-1) = -MB(-1) + GO TO 120 + ELSE IF (MA(1) == MEXPOV) THEN + KFLAG = -5 + CALL IMST2M('OVERFLOW',MB) + GO TO 110 + ENDIF + +! Work with positive numbers. + + MVAL = ABS(IVAL) + NMVAL = INT(MVAL) + NV2 = NMVAL - 1 + NDIG = INT(MA(1)) + N1 = NDIG + 1 + +! To leave room for normalization, shift the product +! to the right KSHIFT places in MWA. + + KSHIFT = INT((LOG(DBLE(MA(2)+1)*DBLE(MVAL)))/DLOGMB) + +! If IVAL is too big, use IMMPY. + + IF (KSHIFT > NDIG .OR. MVAL > MAXINT/MBASE .OR. & + NMVAL /= ABS(IVAL) .OR. NV2 /= ABS(IVAL)-1) THEN + CALL IMI2M(IVAL,M01) + CALL IMMPY(MA,M01,MB) + GO TO 120 + ENDIF + + MWA(1) = MA(1) + KSHIFT + KA = 2 + KSHIFT + KB = N1 + KSHIFT + KC = NDIG + 5 + DO J = KB, KC + MWA(J) = 0 + ENDDO + + MCARRY = 0 + +! This is the main multiplication loop. + + DO J = KB, KA, -1 + MKT = MA(J-KSHIFT)*MVAL + MCARRY + MCARRY = INT (MKT/MBASE) + MWA(J) = MKT - MCARRY*MBASE + ENDDO + +! Resolve the final carry. + + DO J = KA-1, 2, -1 + MKT = INT (MCARRY/MBASE) + MWA(J) = MCARRY - MKT*MBASE + MCARRY = MKT + ENDDO + +! Now the first significant digit in the product is in +! MWA(2) or MWA(3). + + MB(0) = MA(0) + IF (MWA(2) == 0) THEN + MB(1) = MWA(1) - 1 + DO J = 3, KB + MB(J-1) = MWA(J) + ENDDO + ELSE + MB(1) = MWA(1) + DO J = 2, KB + MB(J) = MWA(J) + ENDDO + ENDIF + +! Put the sign on the result. + + 110 MB(-1) = 1 + IF ((IVAL > 0 .AND. MAS < 0) .OR. (IVAL < 0 .AND.MAS > 0)) & + MB(-1) = -1 + + 120 IF (MB(1) > NDIGMX) THEN + IF (NCALL == 1 .OR. MB(1) > NDG2MX) THEN + IF (MB(-1) > 0) THEN + CALL IMST2M('OVERFLOW',MB) + ELSE + CALL IMST2M('-OVERFLOW',MB) + ENDIF + KFLAG = -5 + NAMEST(NCALL) = 'IMMPYI' + IF (KOVFL /= 1) CALL FMWARN + ENDIF + ENDIF + + 130 IF (MB(1) <= 1) MB(3) = 0 + IF (NTRACE /= 0) CALL IMNTR(1,MB,MB,1) + NCALL = NCALL - 1 + NDIG = NDSAVE + RETURN + END SUBROUTINE IMMPYI + + SUBROUTINE IMMPYM(MA,MB,MC,MD) + +! MD = MA * MB mod MC + +! This routine is slightly faster than calling IMMPY and IMMOD +! separately, and it works for cases where IMMPY would return +! OVERFLOW. + + USE FMVALS + IMPLICIT NONE + + REAL (KIND(1.0D0)) :: MA(-1:LUNPCK),MB(-1:LUNPCK),MC(-1:LUNPCK), & + MD(-1:LUNPCK) + REAL (KIND(1.0D0)) :: MAS,MAXMWA,MBM1,MBS,MC1,MCARRY, & + MDC,MDAB,MKT,MLMAX,MQD + DOUBLE PRECISION XB,XBASE,XBR,XMWA + INTEGER J,JB,JL,K,KA,KB,KL,KLTFLG,KPTMWA,N1,NA1,NC1,NDSAVE, & + NGUARD,NL,NMCWDS,NTRSAV + LOGICAL IMCOMP + + NCALL = NCALL + 1 + IF (KDEBUG == 1) CALL IMARGS('IMMPYM',2,MA,MB) + NDSAVE = NDIG + KFLAG = 0 + IF (NTRACE /= 0) THEN + NAMEST(NCALL) = 'IMMPYM' + CALL IMNTR(2,MA,MB,2) + IF (ABS(NTRACE) >= 2 .AND. NCALL <= LVLTRC) THEN + IF (NTRACE < 0) THEN + NDIG = MAX(2,INT(MC(1))) + IF (NDIG > NDG2MX) NDIG = 2 + NTRSAV = NTRACE + IF (NTRACE < -2) NTRACE = -2 + CALL IMNTRJ(MC,NDIG) + NTRACE = NTRSAV + NDIG = NDSAVE + ELSE + CALL IMPRNT(MC) + ENDIF + ENDIF + ENDIF + + IF (MA(1) <= 1) THEN + IF (MB(1) > 1) GO TO 110 + IF (MA(1) < 0 .OR. MB(1) < 0) GO TO 110 + MDAB = MA(-1) * MA(2) * MB(-1) * MB(2) + IF (MC(1) <= 2) THEN + IF (MC(2) == 0) GO TO 110 + IF (MC(1) <= 1) THEN + MDC = MC(-1) * MC(2) + ELSE + MDC = MC(-1) * (MC(2)*MBASE + MC(3)) + ENDIF + MDAB = MOD(MDAB,MDC) + ENDIF + IF (ABS(MDAB) < MBASE) THEN + MD(0) = MIN(MA(0),MB(0),MC(0)) + MD(1) = 1 + IF (MDAB == 0) MD(1) = 0 + MD(-1) = 1 + IF (MDAB < 0) MD(-1) = -1 + MD(2) = ABS(MDAB) + MD(3) = 0 + GO TO 160 + ELSE IF (ABS(MDAB) < MBASE*MBASE) THEN + MD(0) = MIN(MA(0),MB(0),MC(0)) + MD(1) = 2 + MD(-1) = 1 + IF (MDAB < 0) MD(-1) = -1 + MDAB = ABS(MDAB) + MD(2) = AINT (MDAB/MBASE) + MD(3) = MDAB - MBASE*MD(2) + GO TO 160 + ENDIF + ENDIF + +! Check for special cases. + + 110 IF (MA(1) == MUNKNO .OR. MB(1) == MUNKNO .OR. MC(1) == MUNKNO) THEN + KFLAG = -4 + CALL IMST2M('UNKNOWN',MD) + GO TO 170 + ELSE IF (MC(2) == 0 .OR. MA(1) < 0 .OR. MB(1) < 0 .OR. MC(1) < 0) THEN + KFLAG = -4 + NAMEST(NCALL) = 'IMMPYM' + CALL FMWARN + CALL IMST2M('UNKNOWN',MD) + GO TO 170 + ELSE IF (MA(2) == 0 .OR. MB(2) == 0) THEN + CALL IMI2M(0,MD) + GO TO 170 + ELSE IF (MC(1) == 1 .AND. MC(2) == 1) THEN + CALL IMI2M(0,MD) + GO TO 170 + ELSE IF (MB(1) == 1 .AND. MB(2) == 1 .AND. MB(-1) == 1) THEN + CALL IMMOD(MA,MC,MD) + GO TO 160 + ELSE IF (MB(1) == 1 .AND. MB(2) == 1 .AND. MB(-1) == -1) THEN + CALL IMMOD(MA,MC,MD) + IF (MD(1) /= MUNKNO .AND. MD(2) /= 0) MD(-1) = -MD(-1) + GO TO 160 + ELSE IF (MA(1) == 1 .AND. MA(2) == 1 .AND. MA(-1) == 1) THEN + CALL IMMOD(MB,MC,MD) + GO TO 160 + ELSE IF (MA(1) == 1 .AND. MA(2) == 1 .AND. MA(-1) == -1) THEN + CALL IMMOD(MB,MC,MD) + IF (MD(1) /= MUNKNO .AND. MD(2) /= 0) MD(-1) = -MD(-1) + GO TO 160 + ELSE IF (MA(1) > NDG2MX .OR. MB(1) > NDG2MX .OR. & + MC(1) > NDG2MX) THEN + KFLAG = -4 + NAMEST(NCALL) = 'IMMPYM' + CALL FMWARN + CALL IMST2M('UNKNOWN',MD) + GO TO 170 + ENDIF + + NDIG = INT(MA(1) + MB(1)) + IF (NDIG < 2) NDIG = 2 + IF (NDIG > LMWA) NDIG = LMWA + +! Save the sign of MA and MB and then work only with +! positive numbers. + + MAS = MA(-1) + MBS = MB(-1) + + N1 = NDIG + 1 + +! It is faster if the second argument is the one +! with fewer digits. + + IF (MA(1) < MB(1)) THEN + CALL IMMPY2(MB,MA) + ELSE + CALL IMMPY2(MA,MB) + ENDIF + +! Now do the division to find MWA mod MC. + + KLTFLG = 0 + IF (MWA(2) == 0) THEN + MWA(1) = MWA(1) - 1 + ELSE + DO J = N1, 2, -1 + MWA(J+1) = MWA(J) + ENDDO + MWA(2) = 0 + ENDIF + KL = INT(MC(1)) + IF (KL > LMWA) KL = 2 + DO J = -1, KL+1 + M01(J) = MC(J) + ENDDO + M01(-1) = 1 + IF (MWA(1) == M01(1) .AND. ABS(MWA(3)) <= M01(2)) THEN + DO J = 4, N1+1 + M02(J-1) = MWA(J) + ENDDO + M02(2) = ABS(MWA(3)) + M02(1) = MWA(1) + IF (IMCOMP(M02,'EQ',M01)) THEN + KLTFLG = 2 + ELSE IF (IMCOMP(M02,'LT',M01)) THEN + KLTFLG = 1 + ENDIF + ENDIF + IF (MWA(1) < MC(1) .OR. KLTFLG >= 1) THEN + IF (KLTFLG /= 2) THEN + DO J = 3, N1+1 + MD(J-1) = MWA(J) + ENDDO + MD(1) = MWA(1) + MD(0) = MIN(MA(0),MB(0),MC(0)) + ELSE + CALL IMI2M(0,MD) + ENDIF + GO TO 150 + ENDIF + + NDIG = INT(MWA(1)) + IF (NDIG < 2) NDIG = 2 + +! NGUARD is the number of guard digits used. + + NGUARD = 1 + NA1 = INT(MWA(1)) + 1 + NC1 = INT(MC(1)) + 1 + MWA(1) = MWA(1) - MC(1) + 1 + NL = NA1 + NGUARD + 3 + DO J = NA1+2, NL + MWA(J) = 0 + ENDDO + +! Work only with positive numbers. + + MC1 = MC(1) + +! NMCWDS is the number of words of MC used to +! compute the estimated quotient digit MQD. + + NMCWDS = 4 + IF (MBASE < 100) NMCWDS = 7 + +! XB is an approximation of MC used in +! estimating the quotient digits. + + XBASE = DBLE(MBASE) + XB = 0 + JL = NMCWDS + IF (JL <= NC1) THEN + DO J = 2, JL + XB = XB*XBASE + DBLE(MC(J)) + ENDDO + ELSE + DO J = 2, JL + IF (J <= NC1) THEN + XB = XB*XBASE + DBLE(MC(J)) + ELSE + XB = XB*XBASE + ENDIF + ENDDO + ENDIF + IF (JL+1 <= NC1) XB = XB + DBLE(MC(JL+1))/XBASE + XBR = 1.0D0/XB + +! MLMAX determines when to normalize all of MWA. + + MBM1 = MBASE - 1 + MLMAX = MAXINT/MBM1 + MKT = INTMAX - MBASE + MLMAX = MIN(MLMAX,MKT) + +! MAXMWA is an upper bound on the size of values in MWA +! divided by MBASE-1. It is used to determine whether +! normalization can be postponed. + + MAXMWA = 0 + +! KPTMWA points to the next digit in the quotient. + + KPTMWA = 2 + +! This is the start of the division loop. + +! XMWA is an approximation of the active part of MWA +! used in estimating quotient digits. + + 120 KL = KPTMWA + NMCWDS - 1 + IF (KL <= NL) THEN + XMWA = ((DBLE(MWA(KPTMWA))*XBASE & + + DBLE(MWA(KPTMWA+1)))*XBASE & + + DBLE(MWA(KPTMWA+2)))*XBASE & + + DBLE(MWA(KPTMWA+3)) + DO J = KPTMWA+4, KL + XMWA = XMWA*XBASE + DBLE(MWA(J)) + ENDDO + ELSE + XMWA = DBLE(MWA(KPTMWA)) + DO J = KPTMWA+1, KL + IF (J <= NL) THEN + XMWA = XMWA*XBASE + DBLE(MWA(J)) + ELSE + XMWA = XMWA*XBASE + ENDIF + ENDDO + ENDIF + +! MQD is the estimated quotient digit. + + MQD = AINT(XMWA*XBR) + IF (MQD < 0) MQD = MQD - 1 + + IF (MQD > 0) THEN + MAXMWA = MAXMWA + MQD + ELSE + MAXMWA = MAXMWA - MQD + ENDIF + +! See if MWA must be normalized. + + KA = KPTMWA + 1 + KB = KA + INT(MC1) - 1 + IF (MAXMWA >= MLMAX) THEN + DO J = KB, KA, -1 + IF (MWA(J) < 0) THEN + MCARRY = INT((-MWA(J)-1)/MBASE) + 1 + MWA(J) = MWA(J) + MCARRY*MBASE + MWA(J-1) = MWA(J-1) - MCARRY + ELSE IF (MWA(J) >= MBASE) THEN + MCARRY = -INT(MWA(J)/MBASE) + MWA(J) = MWA(J) + MCARRY*MBASE + MWA(J-1) = MWA(J-1) - MCARRY + ENDIF + ENDDO + XMWA = 0 + IF (KL <= NL) THEN + DO J = KPTMWA, KL + XMWA = XMWA*XBASE + DBLE(MWA(J)) + ENDDO + ELSE + DO J = KPTMWA, KL + IF (J <= NL) THEN + XMWA = XMWA*XBASE + DBLE(MWA(J)) + ELSE + XMWA = XMWA*XBASE + ENDIF + ENDDO + ENDIF + MQD = AINT(XMWA*XBR) + IF (MQD < 0) MQD = MQD - 1 + IF (MQD > 0) THEN + MAXMWA = MQD + ELSE + MAXMWA = -MQD + ENDIF + ENDIF + +! Subtract MQD*MC from MWA. + + JB = KA - 2 + IF (MQD /= 0) THEN + +! Major (Inner Loop) + + DO J = KA, KB + MWA(J) = MWA(J) - MQD*MC(J-JB) + ENDDO + ENDIF + + MWA(KA) = MWA(KA) + MWA(KA-1)*MBASE + MWA(KPTMWA) = MQD + + KPTMWA = KPTMWA + 1 + IF (KPTMWA-2 < MWA(1)) GO TO 120 + +! Final normalization. + + KPTMWA = KPTMWA - 1 + DO J = KPTMWA, 3, -1 + IF (MWA(J) < 0) THEN + MCARRY = INT((-MWA(J)-1)/MBASE) + 1 + MWA(J) = MWA(J) + MCARRY*MBASE + MWA(J-1) = MWA(J-1) - MCARRY + ELSE IF (MWA(J) >= MBASE) THEN + MCARRY = -INT(MWA(J)/MBASE) + MWA(J) = MWA(J) + MCARRY*MBASE + MWA(J-1) = MWA(J-1) - MCARRY + ENDIF + ENDDO + + 130 DO J = KPTMWA+INT(MC1), KPTMWA+2, -1 + IF (MWA(J) < 0) THEN + MCARRY = INT((-MWA(J)-1)/MBASE) + 1 + MWA(J) = MWA(J) + MCARRY*MBASE + MWA(J-1) = MWA(J-1) - MCARRY + ELSE IF (MWA(J) >= MBASE) THEN + MCARRY = -INT(MWA(J)/MBASE) + MWA(J) = MWA(J) + MCARRY*MBASE + MWA(J-1) = MWA(J-1) - MCARRY + ENDIF + ENDDO + +! Due to rounding, the remainder may not be between +! 0 and ABS(MC) here. Correct if necessary. + + IF (MWA(KA) < 0) THEN + DO J = KA, KB + MWA(J) = MWA(J) + MC(J-JB) + ENDDO + GO TO 130 + ELSE IF (MWA(KA) >= MBASE) THEN + DO J = KA, KB + MWA(J) = MWA(J) - MC(J-JB) + ENDDO + GO TO 130 + ENDIF + + IF (MWA(KPTMWA+1) /= 0) THEN + DO J = 1, INT(MC1) + MD(J+1) = MWA(KPTMWA+J) + ENDDO + MD(1) = MC1 + ELSE + DO J = 1, INT(MC1) + IF (MWA(KPTMWA+J) /= 0) THEN + DO K = J, INT(MC1) + MD(K-J+2) = MWA(KPTMWA+K) + ENDDO + MD(1) = MC1 + 1 - J + GO TO 140 + ENDIF + ENDDO + MD(1) = 0 + MD(2) = 0 + ENDIF + 140 IF (MD(1) <= 1) MD(3) = 0 + MD(0) = MIN(MA(0),MB(0),MC(0)) + + IF (MD(1) > M01(1) .OR. & + (MD(1) == M01(1) .AND. ABS(MD(2)) >= M01(2))) THEN + MD(-1) = 1 + IF (IMCOMP(MD,'GE',M01)) THEN + CALL IMSUB(MD,M01,M10) + CALL IMEQ(M10,MD) + ENDIF + ENDIF + + 150 MD(-1) = 1 + IF (MAS*MBS < 0) THEN + IF (MD(1) /= MUNKNO .AND. MD(2) /= 0) MD(-1) = -MD(-1) + ENDIF + + IF (NDIG > NDIGMX) NDIG = 2 + 160 IF (MD(1) == MUNKNO) THEN + KFLAG = -4 + NAMEST(NCALL) = 'IMMPYM' + CALL FMWARN + ENDIF + + 170 IF (MD(1) <= 1) MD(3) = 0 + IF (NTRACE /= 0) CALL IMNTR(1,MD,MD,1) + NCALL = NCALL - 1 + NDIG = NDSAVE + RETURN + END SUBROUTINE IMMPYM + + SUBROUTINE IMNTR(NTR,MA,MB,NARG) + +! Print IM numbers in base 10 format. +! This is used for trace output from the IM routines. + +! NTR = 1 if a result of an IM call is to be printed. +! = 2 to print input argument(s) to an IM call. + +! MA - the IM number to be printed. + +! MB - an optional second IM number to be printed. + +! NARG - the number of arguments. NARG = 1 if only MA is to be +! printed, and NARG = 2 if both MA and MB are to be printed. + + USE FMVALS + IMPLICIT NONE + + REAL (KIND(1.0D0)) :: MA(-1:LUNPCK),MB(-1:LUNPCK) + INTEGER NARG,NDSAVE,NTR,NTRSAV + CHARACTER(6) :: NAME + + IF (NTRACE == 0) RETURN + IF (NCALL > LVLTRC) RETURN + IF (NTR == 2 .AND. ABS(NTRACE) == 1) RETURN + + IF (NTR == 2) THEN + NAME = NAMEST(NCALL) + WRITE (KW,"(' Input to ',A6)") NAME + ELSE + NAME = NAMEST(NCALL) + IF (KFLAG == 0) THEN + WRITE (KW, & + "(' ',A6,15X,'Call level =',I2,5X,'MBASE ='," // & + "I10)" & + ) NAME,NCALL,INT(MBASE) + ELSE + WRITE (KW, & + "(' ',A6,6X,'Call level =',I2,4X,'MBASE ='," // & + "I10,4X,'KFLAG =',I3)" & + ) NAME,NCALL,INT(MBASE),KFLAG + ENDIF + ENDIF + + NDSAVE = NDIG + IF (NTRACE < 0) THEN + NDIG = MAX(2,INT(MA(1))) + IF (NDIG > NDG2MX) NDIG = 2 + NTRSAV = NTRACE + IF (NTRACE < -2) NTRACE = -2 + CALL IMNTRJ(MA,NDIG) + IF (NARG == 2) THEN + NDIG = MAX(2,INT(MB(1))) + IF (NDIG > NDG2MX) NDIG = 2 + CALL IMNTRJ(MB,NDIG) + ENDIF + NTRACE = NTRSAV + ENDIF + + IF (NTRACE > 0) THEN + CALL IMPRNT(MA) + IF (NARG == 2) CALL IMPRNT(MB) + ENDIF + + NDIG = NDSAVE + RETURN + END SUBROUTINE IMNTR + + SUBROUTINE IMNTRI(NTR,N,KNAM) + +! Internal routine for trace output of integer variables. + +! NTR = 1 for output values +! 2 for input values + +! N Integer to be printed. + +! KNAM is positive if the routine name is to be printed. + + USE FMVALS + IMPLICIT NONE + + INTEGER NTR,N,KNAM + + CHARACTER(6) :: NAME + + IF (NTRACE == 0) RETURN + IF (NCALL > LVLTRC) RETURN + IF (NTR == 2 .AND. ABS(NTRACE) == 1) RETURN + + IF (NTR == 2 .AND. KNAM > 0) THEN + NAME = NAMEST(NCALL) + WRITE (KW,"(' Input to ',A6)") NAME + ENDIF + IF (NTR == 1 .AND. KNAM > 0) THEN + NAME = NAMEST(NCALL) + IF (KFLAG == 0) THEN + WRITE (KW,"(' ',A6,15X,'Call level =',I2,5X,'MBASE =',I10)") & + NAME,NCALL,INT(MBASE) + ELSE + WRITE (KW, & + "(' ',A6,6X,'Call level =',I2,4X,'MBASE ='," // & + "I10,4X,'KFLAG =',I3)" & + ) NAME,NCALL,INT(MBASE),KFLAG + ENDIF + ENDIF + + WRITE (KW,"(1X,I18)") N + + RETURN + END SUBROUTINE IMNTRI + + SUBROUTINE IMNTRJ(MA,ND) + +! Print trace output in internal base MBASE format. The number to +! be printed is in MA. + +! ND is the number of base MBASE digits to be printed. + + USE FMVALS + IMPLICIT NONE + + REAL (KIND(1.0D0)) :: MA(-1:LUNPCK) + INTEGER ND + + CHARACTER(50) :: FORM + INTEGER J,L,N,N1 + + N1 = ND + 1 + + L = INT(LOG10(DBLE(MBASE-1))) + 2 + N = (KSWIDE-23)/L + IF (N > 10) N = 5*(N/5) + IF (ND <= N) THEN + WRITE (FORM,"(' (1X,I19,I',I2,',',I3,'I',I2,') ')") L+2, N-1, L + ELSE + WRITE (FORM, & + "(' (1X,I19,I',I2,',',I3,'I',I2,'/(22X,',I3,'I',I2,')) ')" & + ) L+2, N-1, L, N, L + ENDIF + IF (INT(MA(1)) >= 2) THEN + WRITE (KW,FORM) INT(MA(1)),INT(MA(-1)*MA(2)),(INT(MA(J)),J=3,N1) + ELSE + WRITE (KW,FORM) INT(MA(1)),INT(MA(-1)*MA(2)),(0,J=3,N1) + ENDIF + + RETURN + END SUBROUTINE IMNTRJ + + SUBROUTINE IMNTRR(NTR,X,KNAM) + +! Internal routine for trace output of real variables. + +! NTR - 1 for output values +! 2 for input values + +! X - Double precision value to be printed if NX == 1 + +! KNAM - Positive if the routine name is to be printed. + + USE FMVALS + IMPLICIT NONE + + INTEGER NTR,KNAM + DOUBLE PRECISION X + + CHARACTER(6) :: NAME + + IF (NTRACE == 0) RETURN + IF (NCALL > LVLTRC) RETURN + IF (NTR == 2 .AND. ABS(NTRACE) == 1) RETURN + + IF (NTR == 2 .AND. KNAM > 0) THEN + NAME = NAMEST(NCALL) + WRITE (KW,"(' Input to ',A6)") NAME + ENDIF + IF (NTR == 1 .AND. KNAM > 0) THEN + NAME = NAMEST(NCALL) + IF (KFLAG == 0) THEN + WRITE (KW,"(' ',A6,15X,'Call level =',I2,5X,'MBASE =',I10)") & + NAME,NCALL,INT(MBASE) + ELSE + WRITE (KW, & + "(' ',A6,6X,'Call level =',I2,4X,'MBASE ='," // & + "I10,4X,'KFLAG =',I3)" & + ) NAME,NCALL,INT(MBASE),KFLAG + ENDIF + ENDIF + + WRITE (KW,"(1X,D30.20)") X + + RETURN + END SUBROUTINE IMNTRR + + SUBROUTINE IMOUT(MA,LINE,LB) + +! Convert an integer multiple precision number to a character array +! for output. + +! MA is an IM number to be converted to an A1 character +! array in base 10 format +! LINE is the CHARACTER*1 array in which the result is returned. +! LB is the length of LINE. + + USE FMVALS + IMPLICIT NONE + + INTEGER JF1SAV,JF2SAV,LB,NDSAVE + CHARACTER LINE(LB) + REAL (KIND(1.0D0)) :: MA(-1:LUNPCK) + + NCALL = NCALL + 1 + IF (KDEBUG == 1) CALL IMARGS('IMOUT ',1,MA,MA) + KFLAG = 0 + NDSAVE = NDIG + NAMEST(NCALL) = 'IMOUT ' + + NDSAVE = NDIG + JF1SAV = JFORM1 + JF2SAV = JFORM2 + JFORM1 = 2 + JFORM2 = 0 + NDIG = MAX(2,INT(MA(1))) + IF (NDIG > NDG2MX) NDIG = 2 + CALL FMOUT(MA,LINE,LB) + + NDIG = NDSAVE + JFORM1 = JF1SAV + JFORM2 = JF2SAV + NCALL = NCALL - 1 + RETURN + END SUBROUTINE IMOUT + + SUBROUTINE IMPACK(MA,MP) + +! MA is packed two base NDIG digits per word and returned in MP. + + USE FMVALS + IMPLICIT NONE + + REAL (KIND(1.0D0)) :: MA(-1:LUNPCK),MP(-1:LPACK) + + INTEGER J,KP,KMA1 + + KMA1 = INT(MA(1)) + IF (KMA1 <= 2 .OR. KMA1 > NDG2MX) KMA1 = 2 + KP = 2 + MP(0) = MA(0) + MP(1) = MA(1) + MP(2) = ABS(MA(2))*MBASE + MA(3) + MP(-1) = 1 + IF (MA(-1) < 0) MP(-1) = -1 + IF (KMA1 >= 4) THEN + DO J = 4, KMA1, 2 + KP = KP + 1 + MP(KP) = MA(J)*MBASE + MA(J+1) + ENDDO + ENDIF + IF (MOD(KMA1,2) == 1) MP(KP+1) = MA(KMA1+1)*MBASE + RETURN + END SUBROUTINE IMPACK + + SUBROUTINE IMPMOD(MA,MB,MC,MD) + +! MD = MOD(MA**MB,MC) + +! The binary multiplication method used requires an average of +! 1.5 * LOG2(MB) operations. + + USE FMVALS + IMPLICIT NONE + + REAL (KIND(1.0D0)) :: MA(-1:LUNPCK),MB(-1:LUNPCK),MC(-1:LUNPCK), & + MD(-1:LUNPCK) + REAL (KIND(1.0D0)) :: MACCA,MACCB,MBS + INTEGER IREM,KWRNSV,NDSAVE,NTRSAV + + KFLAG = 0 + NCALL = NCALL + 1 + IF (KDEBUG == 1) CALL IMARGS('IMPMOD',2,MA,MB) + IF (KDEBUG == 1) CALL IMARGS('IMPMOD',1,MC,MC) + NDSAVE = NDIG + IF (NTRACE /= 0) THEN + NAMEST(NCALL) = 'IMPMOD' + CALL IMNTR(2,MA,MB,2) + IF (ABS(NTRACE) >= 2 .AND. NCALL <= LVLTRC) THEN + IF (NTRACE < 0) THEN + NDIG = MAX(2,INT(MC(1))) + IF (NDIG > NDG2MX) NDIG = 2 + NTRSAV = NTRACE + IF (NTRACE < -2) NTRACE = -2 + CALL IMNTRJ(MC,NDIG) + NTRACE = NTRSAV + NDIG = NDSAVE + ELSE + CALL IMPRNT(MC) + ENDIF + ENDIF + ENDIF + MBS = MB(-1) + MACCA = MA(0) + MACCB = MB(0) + +! Check for special cases. + + IF (MA(1) == MUNKNO .OR. MB(1) == MUNKNO .OR. MC(1) == MUNKNO .OR. & + MA(1) == MEXPOV .OR. MB(1) == MEXPOV .OR. MC(1) == MEXPOV .OR. & + MA(1) < 0 .OR. MB(1) < 0 .OR. MC(1) < 0 .OR. & + (MB(-1)*MB(2) <= 0 .AND. MA(2) == 0) .OR. MC(2) == 0) THEN + KFLAG = -4 + IF (MA(1) /= MUNKNO .AND. MB(1) /= MUNKNO .AND. MC(1) /= MUNKNO) THEN + NAMEST(NCALL) = 'IMPMOD' + CALL FMWARN + ENDIF + CALL IMST2M('UNKNOWN',MD) + IF (NTRACE /= 0) CALL IMNTR(1,MD,MD,1) + NDIG = NDSAVE + NCALL = NCALL - 1 + RETURN + ENDIF + + IF (MB(2) == 0) THEN + CALL IMI2M(1,MD) + IF (NTRACE /= 0) CALL IMNTR(1,MD,MD,1) + NDIG = NDSAVE + NCALL = NCALL - 1 + RETURN + ENDIF + + IF (MB(1) == 1 .AND. ABS(MB(2)) == 1) THEN + KWRNSV = KWARN + KWARN = 0 + IF (MB(-1) == 1) THEN + CALL IMMOD(MA,MC,MD) + ELSE + CALL IMI2M(1,M05) + CALL IMDIVR(M05,MA,M04,M06) + CALL IMMOD(M04,MC,MD) + ENDIF + IF (NTRACE /= 0) CALL IMNTR(1,MD,MD,1) + NDIG = NDSAVE + NCALL = NCALL - 1 + KWARN = KWRNSV + RETURN + ENDIF + + IF (MA(2) == 0) THEN + CALL IMI2M(0,MD) + IF (NTRACE /= 0) CALL IMNTR(1,MD,MD,1) + NDIG = NDSAVE + NCALL = NCALL - 1 + RETURN + ENDIF + +! Initialize. + + KWRNSV = KWARN + KWARN = 0 + CALL IMABS(MB,M06) + CALL IMDIVR(MA,MC,M04,M05) + CALL IMEQ(MC,M04) + CALL IMDVIR(M06,2,MD,IREM) + IF (IREM == 0) THEN + CALL IMI2M(1,MD) + ELSE + CALL IMEQ(M05,MD) + ENDIF + CALL IMDVIR(M06,2,M11,IREM) + CALL IMEQ(M11,M06) + +! This is the multiplication loop. + + 110 CALL IMDVIR(M06,2,M11,IREM) + CALL IMEQ(M11,M06) + CALL IMMPYM(M05,M05,M04,M13) + CALL IMEQ(M13,M05) + IF (IREM == 1) THEN + CALL IMMPYM(M05,MD,M04,M13) + CALL IMEQ(M13,MD) + ENDIF + IF (M06(2) > 0 .AND. MD(2) /= 0) GO TO 110 + + IF (MBS < 0) THEN + CALL IMI2M(1,M05) + CALL IMDIVR(M05,MD,M11,M06) + CALL IMEQ(M11,MD) + ENDIF + KWARN = KWRNSV + MD(0) = MIN(MACCA,MACCB) + IF (KFLAG < 0) THEN + NAMEST(NCALL) = 'IMPMOD' + CALL FMWARN + ENDIF + IF (MD(1) <= 1) MD(3) = 0 + IF (NTRACE /= 0) CALL IMNTR(1,MD,MD,1) + NDIG = NDSAVE + NCALL = NCALL - 1 + RETURN + END SUBROUTINE IMPMOD + + SUBROUTINE IMPRNT(MA) + +! Print MA in base 10 format. + + USE FMVALS + IMPLICIT NONE + + REAL (KIND(1.0D0)) :: MA(-1:LUNPCK) + + INTEGER JF1SAV,JF2SAV,NDSAVE + + NDSAVE = NDIG + JF1SAV = JFORM1 + JF2SAV = JFORM2 + JFORM1 = 2 + JFORM2 = 0 + NDIG = MAX(2,INT(MA(1))) + IF (NDIG > NDG2MX) NDIG = 2 + CALL FMPRNT(MA) + JFORM1 = JF1SAV + JFORM2 = JF2SAV + NDIG = NDSAVE + RETURN + END SUBROUTINE IMPRNT + + SUBROUTINE IMPWR(MA,MB,MC) + +! MC = MA ** MB + +! The binary multiplication method used requires an average of +! 1.5 * LOG2(MB) multiplications. + + USE FMVALS + IMPLICIT NONE + + REAL (KIND(1.0D0)) :: MA(-1:LUNPCK),MB(-1:LUNPCK),MC(-1:LUNPCK) + REAL (KIND(1.0D0)) :: MACCA,MACCB,MAS,MBS + INTEGER IREM,IREMB,JSIGN,KWRNSV + + KFLAG = 0 + NCALL = NCALL + 1 + IF (KDEBUG == 1) CALL IMARGS('IMPWR ',2,MA,MB) + IF (NTRACE /= 0) THEN + NAMEST(NCALL) = 'IMPWR ' + CALL IMNTR(2,MA,MB,2) + ENDIF + MAS = MA(-1) + MBS = MB(-1) + MACCA = MA(0) + MACCB = MB(0) + KWRNSV = KWARN + +! Check for special cases. + + IF (MA(1) == MUNKNO .OR. MB(1) == MUNKNO .OR. MA(1) < 0 .OR. & + MB(1) < 0 .OR. ((MB(-1) < 0 .OR. MB(2) == 0) .AND. MA(2) == 0)) THEN + KFLAG = -4 + IF (MA(1) /= MUNKNO .AND. MB(1) /= MUNKNO) THEN + KWARN = KWRNSV + NAMEST(NCALL) = 'IMPWR ' + CALL FMWARN + ENDIF + CALL IMST2M('UNKNOWN',MC) + GO TO 130 + ENDIF + + IF (MB(2) == 0) THEN + CALL IMI2M(1,MC) + GO TO 130 + ENDIF + + IF (MA(1) == 1 .AND. MA(2) == 1) THEN + KWARN = 0 + IF (MAS == 1) THEN + CALL IMI2M(1,MC) + ELSE + CALL IMI2M(2,M05) + CALL IMDIVR(MB,M05,M11,M06) + CALL IMEQ(M11,M05) + IF (M06(1) == MUNKNO) THEN + KFLAG = -4 + KWARN = KWRNSV + NAMEST(NCALL) = 'IMPWR ' + CALL FMWARN + CALL IMST2M('UNKNOWN',MC) + ELSE IF (M06(2) == 0) THEN + CALL IMI2M(1,MC) + ELSE + CALL IMI2M(-1,MC) + ENDIF + ENDIF + GO TO 130 + ENDIF + + IF (MB(1) == 1 .AND. MB(2) == 1) THEN + KWARN = 0 + IF (MBS == 1) THEN + CALL IMEQ(MA,MC) + ELSE + CALL IMI2M(1,M05) + CALL IMDIVR(M05,MA,MC,M06) + ENDIF + GO TO 130 + ENDIF + + IF (MA(2) == 0) THEN + CALL IMI2M(0,MC) + GO TO 130 + ENDIF + + IF (MB(1) == MEXPOV) THEN + IF (MBS < 0) THEN + CALL IMI2M(0,MC) + ELSE IF (MAS > 0) THEN + CALL IMST2M('OVERFLOW',MC) + KFLAG = -5 + ELSE + KFLAG = -4 + KWARN = KWRNSV + NAMEST(NCALL) = 'IMPWR ' + CALL FMWARN + CALL IMST2M('UNKNOWN',MC) + ENDIF + GO TO 130 + ENDIF + + IF (MA(1) == MEXPOV) THEN + JSIGN = 1 + IF (MA(-1) < 0) JSIGN = -1 + IF (MBS > 0) THEN + CALL IMDVIR(MB,2,MC,IREM) + CALL IMST2M('OVERFLOW',MC) + MC(-1) = JSIGN**IREM + KFLAG = -5 + ELSE + CALL IMI2M(0,MC) + ENDIF + GO TO 130 + ENDIF + +! Initialize. + + KWARN = 0 + CALL IMABS(MB,M06) + + CALL IMEQ(MA,M05) + + CALL IMDVIR(MB,2,MC,IREMB) + IF (IREMB == 0) THEN + CALL IMI2M(1,MC) + ELSE + CALL IMEQ(M05,MC) + ENDIF + CALL IMDVIR(M06,2,M11,IREM) + CALL IMEQ(M11,M06) + +! This is the multiplication loop. + + 110 CALL IMDVIR(M06,2,M11,IREM) + CALL IMEQ(M11,M06) + CALL IMSQR(M05,M12) + CALL IMEQ(M12,M05) + IF (IREM == 1) THEN + CALL IMMPY(M05,MC,M10) + CALL IMEQ(M10,MC) + ENDIF + IF (M05(1) == MEXPOV) THEN + CALL IMEQ(M05,MC) + IF (MAS < 0 .AND. IREMB == 1) MC(-1) = -1 + GO TO 120 + ENDIF + IF (M06(2) > 0) GO TO 110 + + 120 IF (MBS < 0) THEN + CALL IMI2M(1,M05) + CALL IMDIVR(M05,MC,M11,M06) + CALL IMEQ(M11,MC) + ENDIF + + MC(0) = MIN(MACCA,MACCB) + IF (MC(1) > NDIGMX) THEN + IF (NCALL == 1 .OR. MC(1) > NDG2MX) THEN + IF (MC(-1) > 0) THEN + CALL IMST2M('OVERFLOW',MC) + ELSE + CALL IMST2M('-OVERFLOW',MC) + ENDIF + KFLAG = -5 + KWARN = KWRNSV + NAMEST(NCALL) = 'IMPWR ' + CALL FMWARN + ENDIF + ENDIF + + 130 IF (MC(1) <= 1) MC(3) = 0 + KWARN = KWRNSV + IF (NTRACE /= 0) THEN + NAMEST(NCALL) = 'IMPWR ' + CALL IMNTR(1,MC,MC,1) + ENDIF + NCALL = NCALL - 1 + RETURN + END SUBROUTINE IMPWR + + SUBROUTINE IMREAD(KREAD,MA) + +! Read MA on unit KREAD. Multi-line numbers will have '&' as the +! last nonblank character on all but the last line. Only one +! number is allowed on the line(s). + USE FMVALS + IMPLICIT NONE + + REAL (KIND(1.0D0)) :: MA(-1:LUNPCK) + INTEGER KREAD + + INTEGER NDSAVE,KWRNSV + + NCALL = NCALL + 1 + NDSAVE = NDIG + NDIG = NDIGMX + CALL FMREAD(KREAD,M02) + KWRNSV = KWARN + KWARN = 0 + CALL FMNINT(M02,MA) + IF (MA(1) <= 1) MA(3) = 0 + KWARN = KWRNSV + NDIG = NDSAVE + NCALL = NCALL - 1 + RETURN + END SUBROUTINE IMREAD + + SUBROUTINE IMSIGN(MA,MB,MC) + +! MC = SIGN(MA,MB) + +! MC is set to ABS(MA) if MB is positive or zero, +! or -ABS(MA) if MB is negative. + + USE FMVALS + IMPLICIT NONE + + REAL (KIND(1.0D0)) :: MA(-1:LUNPCK),MB(-1:LUNPCK),MC(-1:LUNPCK) + + INTEGER KWRNSV,NDSAVE + + KFLAG = 0 + NCALL = NCALL + 1 + IF (KDEBUG == 1) CALL IMARGS('IMSIGN',2,MA,MB) + NDSAVE = NDIG + IF (NTRACE /= 0) THEN + NAMEST(NCALL) = 'IMSIGN' + CALL IMNTR(2,MA,MB,2) + ENDIF + + NDIG = INT(MA(1)) + IF (NDIG < 2) NDIG = 2 + IF (NDIG > NDG2MX) NDIG = 2 + KWRNSV = KWARN + KWARN = 0 + IF (MA(1) == MUNKNO .OR. MB(1) == MUNKNO) THEN + CALL IMST2M('UNKNOWN',MC) + KFLAG = -4 + ELSE IF (MA(1) < 0 .OR. MB(1) < 0) THEN + KFLAG = -4 + NAMEST(NCALL) = 'IMSIGN' + CALL FMWARN + CALL IMST2M('UNKNOWN',MC) + ELSE IF (MB(-1) >= 0) THEN + CALL IMEQ(MA,MC) + MC(-1) = 1 + ELSE + CALL IMEQ(MA,MC) + IF (MC(1) /= MUNKNO .AND. MC(2) /= 0) MC(-1) = -1 + ENDIF + + IF (MC(1) <= 1) MC(3) = 0 + KWARN = KWRNSV + IF (NTRACE /= 0) CALL IMNTR(1,MC,MC,1) + NCALL = NCALL - 1 + NDIG = NDSAVE + RETURN + END SUBROUTINE IMSIGN + + SUBROUTINE IMSQR(MA,MB) + +! MB = MA * MA + + USE FMVALS + IMPLICIT NONE + + REAL (KIND(1.0D0)) :: MA(-1:LUNPCK),MB(-1:LUNPCK) + + REAL (KIND(1.0D0)) :: MDAB + INTEGER KOVFL,NDSAVE + + NCALL = NCALL + 1 + IF (KDEBUG == 1) CALL IMARGS('IMSQR ',1,MA,MA) + KFLAG = 0 + NDSAVE = NDIG + IF (NTRACE /= 0) THEN + NAMEST(NCALL) = 'IMSQR ' + CALL IMNTR(2,MA,MA,1) + ENDIF + + IF (MA(1) <= 1) THEN + IF (MA(1) < 0) GO TO 110 + MDAB = MA(2) * MA(2) + IF (ABS(MDAB) < MBASE) THEN + MB(0) = MA(0) + MB(1) = 1 + IF (MDAB == 0) MB(1) = 0 + MB(2) = MDAB + MB(3) = 0 + GO TO 120 + ELSE IF (ABS(MDAB) < MBASE*MBASE) THEN + MB(0) = MA(0) + MB(1) = 2 + MB(2) = AINT (MDAB/MBASE) + MB(3) = MDAB - MBASE*MB(2) + GO TO 120 + ENDIF + ENDIF + +! Check for special cases. + + 110 KOVFL = 0 + IF (MA(1) == MUNKNO) THEN + KFLAG = -4 + CALL IMST2M('UNKNOWN',MB) + GO TO 130 + ENDIF + IF (MA(2) == 0) THEN + MB(-1) = 1 + MB(0) = NINT(NDG2MX*ALOGM2) + MB(1) = 0 + MB(2) = 0 + MB(3) = 0 + GO TO 130 + ENDIF + IF (MA(1) == MEXPOV) THEN + KOVFL = 1 + KFLAG = -5 + CALL IMST2M('OVERFLOW',MB) + GO TO 130 + ENDIF + IF (MA(1) == 1 .AND. ABS(MA(2)) == 1) THEN + CALL IMI2M(1,MB) + GO TO 120 + ELSE IF (MA(1) < 0) THEN + KFLAG = -4 + NAMEST(NCALL) = 'IMSQR ' + CALL FMWARN + CALL IMST2M('UNKNOWN',MB) + GO TO 130 + ENDIF + + NDIG = INT(MA(1) + MA(1)) + IF (NDIG > NDIGMX) THEN + IF (NCALL == 1 .OR. NDIG > NDG2MX) THEN + CALL IMST2M('OVERFLOW',MB) + KFLAG = -5 + NAMEST(NCALL) = 'IMSQR ' + CALL FMWARN + GO TO 130 + ENDIF + ENDIF + + IF (NDIG < 2) NDIG = 2 + IF (NDIG > NDG2MX) NDIG = NDG2MX + + CALL IMSQR2(MA,MB) + + IF (NDIG > NDIGMX) NDIG = 2 + 120 IF (MB(1) > NDIGMX) THEN + IF (NCALL == 1 .OR. MB(1) > NDG2MX) THEN + IF (MB(-1) > 0) THEN + CALL IMST2M('OVERFLOW',MB) + ELSE + CALL IMST2M('-OVERFLOW',MB) + ENDIF + KFLAG = -5 + NAMEST(NCALL) = 'IMSQR ' + IF (KOVFL /= 1) CALL FMWARN + ENDIF + ENDIF + + 130 IF (MB(1) <= 1) MB(3) = 0 + MB(-1) = 1 + IF (NTRACE /= 0) CALL IMNTR(1,MB,MB,1) + NCALL = NCALL - 1 + NDIG = NDSAVE + RETURN + END SUBROUTINE IMSQR + + SUBROUTINE IMSQR2(MA,MB) + +! MB = MA*MA. + + USE FMVALS + IMPLICIT NONE + + REAL (KIND(1.0D0)) :: MA(-1:LUNPCK),MB(-1:LUNPCK) + + REAL (KIND(1.0D0)) :: MAXMAX,MAXMWA,MBJ,MBKJ,MBM1, & + MBNORM,MK,MKA,MKT,MMAX,MT + INTEGER J,JM1,K,KB,KI,KJ,KL,KNZ,KOVUN,KWA, & + L,N1 + + IF (MBLOGS /= MBASE) CALL FMCONS + IF (ABS(MA(1)) > NDG2MX/2 .OR. KDEBUG == 1 .OR. & + MBASE*MBASE <= MXBASE/(4*MBASE)) THEN + KOVUN = 0 + IF (MA(1) == MEXPOV .OR. MA(1) == MEXPUN) KOVUN = 1 + IF (MA(1) == MUNKNO) KOVUN = 2 + NCALL = NCALL + 1 + CALL IMMPY(MA,MA,MB) + NCALL = NCALL - 1 + IF ((KFLAG < 0 .AND. KOVUN == 0) .OR. & + (KFLAG == -4 .AND. KOVUN == 1)) THEN + NAMEST(NCALL) = 'IMSQR ' + CALL FMWARN + ENDIF + GO TO 120 + ELSE IF (MA(2) == 0) THEN + CALL IMEQ(MA,MB) + GO TO 120 + ENDIF + KFLAG = 0 + MAXMAX = 0 + + N1 = INT(MA(1)) + 1 + MWA(1) = MA(1) + MA(1) + + L = N1 + INT(MA(1)) + MWA(L+1) = 0 + +! The multiplication loop begins here. + +! MBNORM is the minimum number of digits that can be +! multiplied before normalization is required. +! MAXMWA is an upper bound on the size of values in MWA +! divided by (MBASE-1). It is used to determine +! whether to normalize before the next digit is +! multiplied. + + MBM1 = MBASE - 1 + MBNORM = AINT (MAXINT/(MBM1*MBM1)) + MMAX = INTMAX - MBASE + MMAX = MIN(AINT (MAXINT/MBM1 - MBM1),MMAX) + IF (MBNORM > 1) THEN + MBJ = MA(2) + +! Count the trailing zeros in MA. + + IF (MA(N1) /= 0) THEN + KNZ = N1 + ELSE + DO J = INT(MA(1)), 2, -1 + IF (MA(J) /= 0) THEN + KNZ = J + GO TO 110 + ENDIF + ENDDO + ENDIF + + 110 MWA(2) = 0 + MWA(3) = 0 + DO K = N1+1, L + MWA(K) = 0 + ENDDO + +! (Inner Loop) + + DO K = 3, N1 + MWA(K+1) = MA(K)*MBJ + ENDDO + MAXMWA = MBJ + DO J = 3, N1 + MBJ = MA(J) + IF (MBJ /= 0) THEN + MAXMWA = MAXMWA + MBJ + JM1 = J - 1 + KL = MIN(KNZ,L-JM1) + +! Major (Inner Loop) + + DO K = 2*J, JM1+KL + MWA(K) = MWA(K) + MA(K-JM1)*MBJ + ENDDO + ENDIF + + IF (MAXMWA > MMAX) THEN + MAXMAX = MAX(MAXMAX,MAXMWA) + MAXMWA = 0 + +! Normalization is only required for the +! range of digits currently changing in MWA. + + DO KB = JM1+KL, 2*J, -1 + MKT = INT (MWA(KB)/MBASE) + MWA(KB-1) = MWA(KB-1) + MKT + MWA(KB) = MWA(KB) - MKT*MBASE + ENDDO + ENDIF + ENDDO + +! Double MWA, add the square terms, and perform +! the final normalization. (Inner Loop) + + IF (2*MAX(MAXMAX,MAXMWA)+MBASE > MMAX) THEN + DO KB = L, 4, -1 + MKT = INT (MWA(KB)/MBASE) + MWA(KB-1) = MWA(KB-1) + MKT + MWA(KB) = MWA(KB) - MKT*MBASE + ENDDO + ENDIF + + DO J = 3, L-1, 2 + IF ((J+1)/2 <= N1) THEN + MKA = MA((J+1)/2) + MWA(J) = 2*MWA(J) + MKA*MKA + MWA(J+1) = 2*MWA(J+1) + ELSE + MWA(J) = 2*MWA(J) + MWA(J+1) = 2*MWA(J+1) + ENDIF + ENDDO + IF (MOD(L,2) == 1) THEN + IF ((L+1)/2 <= N1) THEN + MKA = MA((L+1)/2) + MWA(L) = 2*MWA(L) + MKA*MKA + ELSE + MWA(L) = 2*MWA(L) + ENDIF + ENDIF + + DO KB = L, 3, -1 + MKT = INT (MWA(KB)/MBASE) + MWA(KB-1) = MWA(KB-1) + MKT + MWA(KB) = MWA(KB) - MKT*MBASE + ENDDO + + ELSE + +! If normalization must be done for each digit, combine +! the two loops and normalize as the digits are multiplied. + + DO J = 2, L + MWA(J) = 0 + ENDDO + KJ = NDIG + 2 + DO J = 2, N1 + KJ = KJ - 1 + MBKJ = MA(KJ) + IF (MBKJ == 0) CYCLE + KL = L - KJ + 1 + IF (KL > N1) KL = N1 + KI = KL + 2 + KWA = KL+ KJ + 1 + MK = 0 + DO K = 2, KL + MT = MA(KI-K)*MBKJ + MWA(KWA-K) + MK + MK = INT (MT/MBASE) + MWA(KWA-K) = MT - MBASE*MK + ENDDO + MWA(KWA-KL-1) = MK + ENDDO + + ENDIF + +! The multiplication is complete. + + NDIG = MWA(1) + IF (NDIG < 2) NDIG = 2 + IF (NDIG > NDG2MX) NDIG = NDG2MX + CALL FMMOVE(MWA,MB) + MB(0) = NINT(NDIGMX*ALOGM2) + + IF (KFLAG < 0) THEN + NAMEST(NCALL) = 'IMSQR ' + CALL FMWARN + ENDIF + + 120 MB(-1) = 1 + RETURN + END SUBROUTINE IMSQR2 + + SUBROUTINE IMST2M(STRING,MA) + +! MA = STRING + +! Convert a character string to IM format. + + USE FMVALS + IMPLICIT NONE + + CHARACTER(*) :: STRING + REAL (KIND(1.0D0)) :: MA(-1:LUNPCK) + + INTEGER J,LB,KFSAVE + + IF (MBLOGS /= MBASE) CALL FMCONS + NCALL = NCALL + 1 + NAMEST(NCALL) = 'IMST2M' + LB = MIN(LEN(STRING),LMBUFF) + KFSAVE = KFLAG + + DO J = 1, LB + CMBUFF(J) = STRING(J:J) + ENDDO + + CALL IMINP(CMBUFF,MA,1,LB) + + IF (MA(1) <= 1) MA(3) = 0 + IF (KFSAVE /= 0) KFLAG = KFSAVE + NCALL = NCALL - 1 + RETURN + END SUBROUTINE IMST2M + + SUBROUTINE IMSUB(MA,MB,MC) + +! MC = MA - MB + + USE FMVALS + IMPLICIT NONE + + REAL (KIND(1.0D0)) :: MA(-1:LUNPCK),MB(-1:LUNPCK),MC(-1:LUNPCK) + + REAL (KIND(1.0D0)) :: MDA,MDAB,MDB + INTEGER NDSAVE + + NCALL = NCALL + 1 + IF (KDEBUG == 1) CALL IMARGS('IMSUB ',2,MA,MB) + KFLAG = 0 + NDSAVE = NDIG + IF (NTRACE /= 0) THEN + NAMEST(NCALL) = 'IMSUB ' + CALL IMNTR(2,MA,MB,2) + ENDIF + + IF (MA(1) <= 2) THEN + IF (MB(1) > 2 .OR. MA(1) < 0 .OR. MB(1) < 0) GO TO 110 + IF (MA(1) <= 1) THEN + MDA = MA(-1) * MA(2) + ELSE + MDA = MA(-1) * (MA(2)*MBASE + MA(3)) + ENDIF + IF (MB(1) <= 1) THEN + MDB = MB(-1) * MB(2) + ELSE + MDB = MB(-1) * (MB(2)*MBASE + MB(3)) + ENDIF + MDAB = MDA - MDB + IF (ABS(MDAB) < MBASE) THEN + MC(0) = MIN(MA(0),MB(0)) + MC(1) = 1 + IF (MDAB == 0) MC(1) = 0 + MC(-1) = 1 + IF (MDAB < 0) MC(-1) = -1 + MC(2) = ABS(MDAB) + MC(3) = 0 + IF (MDA == 0 .OR. MDB == 0) KFLAG = 1 + GO TO 120 + ELSE IF (ABS(MDAB) < MBASE*MBASE) THEN + MC(0) = MIN(MA(0),MB(0)) + MC(1) = 2 + MC(-1) = 1 + IF (MDAB < 0) MC(-1) = -1 + MDAB = ABS(MDAB) + MC(2) = AINT (MDAB/MBASE) + MC(3) = MDAB - MBASE*MC(2) + IF (MDA == 0 .OR. MDB == 0) KFLAG = 1 + GO TO 120 + ENDIF + ENDIF + +! Check for special cases. + + 110 IF (MA(1) > NDG2MX .OR. MB(1) > NDG2MX .OR. & + MA(1) < 0 .OR. MB(1) < 0) THEN + IF (MA(1) == MUNKNO .OR. MB(1) == MUNKNO) THEN + CALL IMST2M('UNKNOWN',MC) + KFLAG = -4 + GO TO 130 + ENDIF + IF (MA(1) == MEXPOV) THEN + IF (MA(-1) == -MB(-1) .OR. MB(2) == 0) THEN + MC(-1) = MA(-1) + MC(0) = MA(0) + MC(1) = MA(1) + MC(2) = MA(2) + MC(3) = MA(3) + KFLAG = -5 + GO TO 130 + ELSE + KFLAG = -4 + NAMEST(NCALL) = 'IMSUB ' + CALL FMWARN + CALL IMST2M('UNKNOWN',MC) + GO TO 130 + ENDIF + ENDIF + IF (MB(1) == MEXPOV) THEN + IF (-MB(-1) == MA(-1) .OR. MA(2) == 0) THEN + MC(-1) = -MB(-1) + MC(0) = MB(0) + MC(1) = MB(1) + MC(2) = MB(2) + MC(3) = MB(3) + KFLAG = -5 + GO TO 130 + ELSE + KFLAG = -4 + NAMEST(NCALL) = 'IMSUB ' + CALL FMWARN + CALL IMST2M('UNKNOWN',MC) + GO TO 130 + ENDIF + ENDIF + KFLAG = -4 + NAMEST(NCALL) = 'IMSUB ' + CALL FMWARN + CALL IMST2M('UNKNOWN',MC) + GO TO 130 + ENDIF + +! IMADD2 will negate MB and add. + + KSUB = 1 + CALL IMADD2(MA,MB,MC) + KSUB = 0 + + 120 IF (MC(1) > NDIGMX) THEN + IF (NCALL == 1 .OR. MC(1) > NDG2MX) THEN + IF (MC(-1) > 0) THEN + CALL IMST2M('OVERFLOW',MC) + ELSE + CALL IMST2M('-OVERFLOW',MC) + ENDIF + KFLAG = -5 + NAMEST(NCALL) = 'IMSUB ' + CALL FMWARN + ENDIF + ENDIF + + 130 IF (MC(1) <= 1) MC(3) = 0 + IF (NTRACE /= 0) CALL IMNTR(1,MC,MC,1) + NCALL = NCALL - 1 + NDIG = NDSAVE + RETURN + END SUBROUTINE IMSUB + + SUBROUTINE IMUNPK(MP,MA) + +! MP is unpacked and the value returned in MA. + + USE FMVALS + IMPLICIT NONE + + REAL (KIND(1.0D0)) :: MA(-1:LUNPCK),MP(-1:LPACK) + + INTEGER J,KP,KMA1 + + KMA1 = INT(MP(1)) + IF (KMA1 <= 2 .OR. KMA1 > NDG2MX) KMA1 = 2 + KP = 2 + MA(0) = MP(0) + MA(1) = MP(1) + MA(2) = AINT (ABS(MP(2))/MBASE) + MA(3) = ABS(MP(2)) - MA(2)*MBASE + MA(-1) = 1 + IF (MP(-1) < 0) MA(-1) = -1 + IF (KMA1 >= 4) THEN + DO J = 4, KMA1, 2 + KP = KP + 1 + MA(J) = AINT (MP(KP)/MBASE) + MA(J+1) = MP(KP) - MA(J)*MBASE + ENDDO + ENDIF + IF (MOD(KMA1,2) == 1) MA(KMA1+1) = AINT (MP(KP+1)/MBASE) + RETURN + END SUBROUTINE IMUNPK + + SUBROUTINE IMWRIT(KWRITE,MA) + +! Write MA on unit KWRITE. Multi-line numbers will have '&' as the +! last nonblank character on all but the last line. These numbers can +! then be read easily using IMREAD. + + USE FMVALS + IMPLICIT NONE + + INTEGER KWRITE + REAL (KIND(1.0D0)) :: MA(-1:LUNPCK) + + INTEGER J,K,KSAVE,L,LAST,LB,ND,NDSAVE,NEXP + + NCALL = NCALL + 1 + IF (KDEBUG == 1) CALL IMARGS('IMWRIT',1,MA,MA) + NAMEST(NCALL) = 'IMWRIT' + NDSAVE = NDIG + NDIG = MAX(2,INT(MA(1))) + IF (NDIG > NDG2MX) NDIG = 2 + + KSAVE = KFLAG + ND = INT(REAL(NDIG)*LOG10(REAL(MBASE))) + 1 + IF (ND < 2) ND = 2 + NEXP = INT(2.0*LOG10(REAL(MXBASE))) + 6 + LB = MIN(ND+NEXP,LMBUFF) + + CALL IMOUT(MA,CMBUFF,LB) + + KFLAG = KSAVE + NDIG = NDSAVE + LAST = LB + 1 + DO J = 1, LB + IF (CMBUFF(LAST-J) /= ' ' .OR. J == LB) THEN + L = LAST - J + IF (MOD(L,73) /= 0) THEN + WRITE (KWRITE,"(4X,73A1,' &')") (CMBUFF(K),K=1,L) + ELSE + IF (L > 73) WRITE (KWRITE,"(4X,73A1,' &')") & + (CMBUFF(K),K=1,L-73) + WRITE (KWRITE,"(4X,73A1)") (CMBUFF(K),K=L-72,L) + ENDIF + NCALL = NCALL - 1 + RETURN + ENDIF + ENDDO + NCALL = NCALL - 1 + RETURN + END SUBROUTINE IMWRIT + +! These versions of the IM routines use packed IM numbers. + + + SUBROUTINE IPABS(MA,MB) + USE FMVALS + IMPLICIT NONE + REAL (KIND(1.0D0)) :: MA(-1:LPACK),MB(-1:LPACK) + CALL IMUNPK(MA,MPA) + CALL IMABS(MPA,MPB) + CALL IMPACK(MPB,MB) + RETURN + END SUBROUTINE IPABS + + SUBROUTINE IPADD(MA,MB,MC) + USE FMVALS + IMPLICIT NONE + REAL (KIND(1.0D0)) :: MA(-1:LPACK),MB(-1:LPACK),MC(-1:LPACK) + CALL IMUNPK(MA,MPA) + CALL IMUNPK(MB,MPB) + CALL IMADD(MPA,MPB,MPC) + CALL IMPACK(MPC,MC) + RETURN + END SUBROUTINE IPADD + + SUBROUTINE IPBIG(MA) + USE FMVALS + IMPLICIT NONE + REAL (KIND(1.0D0)) :: MA(-1:LPACK) + CALL IMBIG(MPB) + CALL IMPACK(MPB,MA) + RETURN + END SUBROUTINE IPBIG + + FUNCTION IPCOMP(MA,LREL,MB) + USE FMVALS + IMPLICIT NONE + LOGICAL IPCOMP,IMCOMP + CHARACTER(*) :: LREL + REAL (KIND(1.0D0)) :: MA(-1:LPACK),MB(-1:LPACK) + CALL IMUNPK(MA,MPA) + CALL IMUNPK(MB,MPB) + IPCOMP = IMCOMP(MPA,LREL,MPB) + RETURN + END FUNCTION IPCOMP + + SUBROUTINE IPDIM(MA,MB,MC) + USE FMVALS + IMPLICIT NONE + REAL (KIND(1.0D0)) :: MA(-1:LPACK),MB(-1:LPACK),MC(-1:LPACK) + CALL IMUNPK(MA,MPA) + CALL IMUNPK(MB,MPB) + CALL IMDIM(MPA,MPB,MPC) + CALL IMPACK(MPC,MC) + RETURN + END SUBROUTINE IPDIM + + SUBROUTINE IPDIV(MA,MB,MC) + USE FMVALS + IMPLICIT NONE + REAL (KIND(1.0D0)) :: MA(-1:LPACK),MB(-1:LPACK),MC(-1:LPACK) + CALL IMUNPK(MA,MPA) + CALL IMUNPK(MB,MPB) + CALL IMDIV(MPA,MPB,MPC) + CALL IMPACK(MPC,MC) + RETURN + END SUBROUTINE IPDIV + + SUBROUTINE IPDIVI(MA,IVAL,MB) + USE FMVALS + IMPLICIT NONE + REAL (KIND(1.0D0)) :: MA(-1:LPACK),MB(-1:LPACK) + INTEGER IVAL + CALL IMUNPK(MA,MPA) + CALL IMDIVI(MPA,IVAL,MPB) + CALL IMPACK(MPB,MB) + RETURN + END SUBROUTINE IPDIVI + + SUBROUTINE IPDIVR(MA,MB,MC,MD) + USE FMVALS + IMPLICIT NONE + REAL (KIND(1.0D0)) :: MA(-1:LPACK),MB(-1:LPACK),MC(-1:LPACK), & + MD(-1:LPACK) + CALL IMUNPK(MA,MPA) + CALL IMUNPK(MB,MPB) + CALL IMDIVR(MPA,MPB,MPC,MPD) + CALL IMPACK(MPC,MC) + CALL IMPACK(MPD,MD) + RETURN + END SUBROUTINE IPDIVR + + SUBROUTINE IPDVIR(MA,IVAL,MB,IREM) + USE FMVALS + IMPLICIT NONE + REAL (KIND(1.0D0)) :: MA(-1:LPACK),MB(-1:LPACK) + INTEGER IVAL,IREM + CALL IMUNPK(MA,MPA) + CALL IMDVIR(MPA,IVAL,MPB,IREM) + CALL IMPACK(MPB,MB) + RETURN + END SUBROUTINE IPDVIR + + SUBROUTINE IPEQ(MA,MB) + USE FMVALS + IMPLICIT NONE + REAL (KIND(1.0D0)) :: MA(-1:LPACK),MB(-1:LPACK) + CALL IMUNPK(MA,MPA) + CALL IMEQ(MPA,MPB) + CALL IMPACK(MPB,MB) + RETURN + END SUBROUTINE IPEQ + + SUBROUTINE IPFM2I(MA,MB) + USE FMVALS + IMPLICIT NONE + REAL (KIND(1.0D0)) :: MA(-1:LPACK),MB(-1:LPACK) + CALL FMUNPK(MA,MPA) + CALL IMFM2I(MPA,MPB) + CALL IMPACK(MPB,MB) + RETURN + END SUBROUTINE IPFM2I + + SUBROUTINE IPFORM(FORM,MA,STRING) + USE FMVALS + IMPLICIT NONE + CHARACTER(*) :: FORM,STRING + REAL (KIND(1.0D0)) :: MA(-1:LPACK) + CALL IMUNPK(MA,MPA) + CALL IMFORM(FORM,MPA,STRING) + RETURN + END SUBROUTINE IPFORM + + SUBROUTINE IPFPRT(FORM,MA) + USE FMVALS + IMPLICIT NONE + CHARACTER(*) :: FORM + REAL (KIND(1.0D0)) :: MA(-1:LPACK) + CALL IMUNPK(MA,MPA) + CALL IMFPRT(FORM,MPA) + RETURN + END SUBROUTINE IPFPRT + + SUBROUTINE IPGCD(MA,MB,MC) + USE FMVALS + IMPLICIT NONE + REAL (KIND(1.0D0)) :: MA(-1:LPACK),MB(-1:LPACK),MC(-1:LPACK) + CALL IMUNPK(MA,MPA) + CALL IMUNPK(MB,MPB) + CALL IMGCD(MPA,MPB,MPC) + CALL IMPACK(MPC,MC) + RETURN + END SUBROUTINE IPGCD + + SUBROUTINE IPI2FM(MA,MB) + USE FMVALS + IMPLICIT NONE + REAL (KIND(1.0D0)) :: MA(-1:LPACK),MB(-1:LPACK) + CALL IMUNPK(MA,MPA) + CALL IMI2FM(MPA,MPB) + CALL FMPACK(MPB,MB) + RETURN + END SUBROUTINE IPI2FM + + SUBROUTINE IPI2M(IVAL,MA) + USE FMVALS + IMPLICIT NONE + REAL (KIND(1.0D0)) :: MA(-1:LPACK) + INTEGER IVAL + CALL IMI2M(IVAL,MPA) + CALL IMPACK(MPA,MA) + RETURN + END SUBROUTINE IPI2M + + SUBROUTINE IPINP(LINE,MA,LA,LB) + USE FMVALS + IMPLICIT NONE + INTEGER LA,LB + CHARACTER LINE(LB) + REAL (KIND(1.0D0)) :: MA(-1:LPACK) + CALL IMINP(LINE,MPA,LA,LB) + CALL IMPACK(MPA,MA) + RETURN + END SUBROUTINE IPINP + + SUBROUTINE IPM2DP(MA,DVAL) + USE FMVALS + IMPLICIT NONE + REAL (KIND(1.0D0)) :: MA(-1:LPACK) + DOUBLE PRECISION DVAL + CALL IMUNPK(MA,MPA) + CALL IMM2DP(MPA,DVAL) + RETURN + END SUBROUTINE IPM2DP + + SUBROUTINE IPM2I(MA,IVAL) + USE FMVALS + IMPLICIT NONE + REAL (KIND(1.0D0)) :: MA(-1:LPACK) + INTEGER IVAL + CALL IMUNPK(MA,MPA) + CALL IMM2I(MPA,IVAL) + RETURN + END SUBROUTINE IPM2I + + SUBROUTINE IPMAX(MA,MB,MC) + USE FMVALS + IMPLICIT NONE + REAL (KIND(1.0D0)) :: MA(-1:LPACK),MB(-1:LPACK),MC(-1:LPACK) + CALL IMUNPK(MA,MPA) + CALL IMUNPK(MB,MPB) + CALL IMMAX(MPA,MPB,MPC) + CALL IMPACK(MPC,MC) + RETURN + END SUBROUTINE IPMAX + + SUBROUTINE IPMIN(MA,MB,MC) + USE FMVALS + IMPLICIT NONE + REAL (KIND(1.0D0)) :: MA(-1:LPACK),MB(-1:LPACK),MC(-1:LPACK) + CALL IMUNPK(MA,MPA) + CALL IMUNPK(MB,MPB) + CALL IMMIN(MPA,MPB,MPC) + CALL IMPACK(MPC,MC) + RETURN + END SUBROUTINE IPMIN + + SUBROUTINE IPMOD(MA,MB,MC) + USE FMVALS + IMPLICIT NONE + REAL (KIND(1.0D0)) :: MA(-1:LPACK),MB(-1:LPACK),MC(-1:LPACK) + CALL IMUNPK(MA,MPA) + CALL IMUNPK(MB,MPB) + CALL IMMOD(MPA,MPB,MPC) + CALL IMPACK(MPC,MC) + RETURN + END SUBROUTINE IPMOD + + SUBROUTINE IPMPY(MA,MB,MC) + USE FMVALS + IMPLICIT NONE + REAL (KIND(1.0D0)) :: MA(-1:LPACK),MB(-1:LPACK),MC(-1:LPACK) + CALL IMUNPK(MA,MPA) + CALL IMUNPK(MB,MPB) + CALL IMMPY(MPA,MPB,MPC) + CALL IMPACK(MPC,MC) + RETURN + END SUBROUTINE IPMPY + + SUBROUTINE IPMPYI(MA,IVAL,MB) + USE FMVALS + IMPLICIT NONE + REAL (KIND(1.0D0)) :: MA(-1:LPACK),MB(-1:LPACK) + INTEGER IVAL + CALL IMUNPK(MA,MPA) + CALL IMMPYI(MPA,IVAL,MPB) + CALL IMPACK(MPB,MB) + RETURN + END SUBROUTINE IPMPYI + + SUBROUTINE IPMPYM(MA,MB,MC,MD) + USE FMVALS + IMPLICIT NONE + REAL (KIND(1.0D0)) :: MA(-1:LPACK),MB(-1:LPACK),MC(-1:LPACK), & + MD(-1:LPACK) + CALL IMUNPK(MA,MPA) + CALL IMUNPK(MB,MPB) + CALL IMUNPK(MC,MPC) + CALL IMMPYM(MPA,MPB,MPC,MPD) + CALL IMPACK(MPD,MD) + RETURN + END SUBROUTINE IPMPYM + + SUBROUTINE IPOUT(MA,LINE,LB) + USE FMVALS + IMPLICIT NONE + REAL (KIND(1.0D0)) :: MA(-1:LPACK) + INTEGER LB + CHARACTER LINE(LB) + CALL IMUNPK(MA,MPA) + CALL IMOUT(MPA,LINE,LB) + RETURN + END SUBROUTINE IPOUT + + SUBROUTINE IPPMOD(MA,MB,MC,MD) + USE FMVALS + IMPLICIT NONE + REAL (KIND(1.0D0)) :: MA(-1:LPACK),MB(-1:LPACK),MC(-1:LPACK), & + MD(-1:LPACK) + CALL IMUNPK(MA,MPA) + CALL IMUNPK(MB,MPB) + CALL IMUNPK(MC,MPC) + CALL IMPMOD(MPA,MPB,MPC,MPD) + CALL IMPACK(MPD,MD) + RETURN + END SUBROUTINE IPPMOD + + SUBROUTINE IPPRNT(MA) + USE FMVALS + IMPLICIT NONE + REAL (KIND(1.0D0)) :: MA(-1:LPACK) + CALL IMUNPK(MA,MPA) + CALL IMPRNT(MPA) + RETURN + END SUBROUTINE IPPRNT + + SUBROUTINE IPPWR(MA,MB,MC) + USE FMVALS + IMPLICIT NONE + REAL (KIND(1.0D0)) :: MA(-1:LPACK),MB(-1:LPACK),MC(-1:LPACK) + CALL IMUNPK(MA,MPA) + CALL IMUNPK(MB,MPB) + CALL IMPWR(MPA,MPB,MPC) + CALL IMPACK(MPC,MC) + RETURN + END SUBROUTINE IPPWR + + SUBROUTINE IPREAD(KREAD,MA) + USE FMVALS + IMPLICIT NONE + REAL (KIND(1.0D0)) :: MA(-1:LPACK) + INTEGER KREAD + CALL IMREAD(KREAD,MPA) + CALL IMPACK(MPA,MA) + RETURN + END SUBROUTINE IPREAD + + SUBROUTINE IPSIGN(MA,MB,MC) + USE FMVALS + IMPLICIT NONE + REAL (KIND(1.0D0)) :: MA(-1:LPACK),MB(-1:LPACK),MC(-1:LPACK) + CALL IMUNPK(MA,MPA) + CALL IMUNPK(MB,MPB) + CALL IMSIGN(MPA,MPB,MPC) + CALL IMPACK(MPC,MC) + RETURN + END SUBROUTINE IPSIGN + + SUBROUTINE IPSQR(MA,MB) + USE FMVALS + IMPLICIT NONE + REAL (KIND(1.0D0)) :: MA(-1:LPACK),MB(-1:LPACK) + CALL IMUNPK(MA,MPA) + CALL IMSQR(MPA,MPB) + CALL IMPACK(MPB,MB) + RETURN + END SUBROUTINE IPSQR + + SUBROUTINE IPST2M(STRING,MA) + USE FMVALS + IMPLICIT NONE + CHARACTER(*) :: STRING + REAL (KIND(1.0D0)) :: MA(-1:LPACK) + CALL IMST2M(STRING,MPA) + CALL IMPACK(MPA,MA) + RETURN + END SUBROUTINE IPST2M + + SUBROUTINE IPSUB(MA,MB,MC) + USE FMVALS + IMPLICIT NONE + REAL (KIND(1.0D0)) :: MA(-1:LPACK),MB(-1:LPACK),MC(-1:LPACK) + CALL IMUNPK(MA,MPA) + CALL IMUNPK(MB,MPB) + CALL IMSUB(MPA,MPB,MPC) + CALL IMPACK(MPC,MC) + RETURN + END SUBROUTINE IPSUB + + SUBROUTINE IPWRIT(KWRITE,MA) + USE FMVALS + IMPLICIT NONE + INTEGER KWRITE + REAL (KIND(1.0D0)) :: MA(-1:LPACK) + CALL IMUNPK(MA,MPA) + CALL IMWRIT(KWRITE,MPA) + RETURN + END SUBROUTINE IPWRIT + +! The ZM routines perform complex multiple-precision arithmetic. + + + SUBROUTINE ZMSET(NPREC) + +! Set precision to at least NPREC significant digits for using +! ZM arithmetic. + + USE FMVALS + IMPLICIT NONE + + INTEGER NPREC + +! Set JFORMZ to ' 1.23 + 4.56 i ' format. + + JFORMZ = 1 + +! Set JPRNTZ to print real and imaginary parts on one +! line whenever possible. + + JPRNTZ = 1 + +! Use FMSET to initialize the other variables. + + CALL FMSET(NPREC) + + RETURN + END SUBROUTINE ZMSET + + SUBROUTINE ZMABS(MA,MBFM) + +! MBFM = ABS(MA) + +! Complex absolute value. The result is a real FM number. + + USE FMVALS + IMPLICIT NONE + + REAL (KIND(1.0D0)) :: MA(-1:LUNPKZ),MBFM(-1:LUNPCK) + REAL (KIND(1.0D0)) :: MACCMB,MAIZ,MARZ,MXEXP1,MXSAVE + INTEGER KASAVE,KOVUN,KRESLT,NDSAVE,NTRSAV + + NTRSAV = NTRACE + IF (NTRACE /= 0) THEN + NCALL = NCALL + 1 + NAMEST(NCALL) = 'ZMABS ' + CALL ZMNTR(2,MA,MA,1) + NCALL = NCALL - 1 + ENDIF + NTRACE = 0 + CALL ZMENTR('ZMABS ',MA,MA,1,MZ01,KRESLT,NDSAVE,MXSAVE,KASAVE, & + KOVUN) + NTRACE = NTRSAV + IF (KRESLT /= 0) THEN + CALL FMEQ(MZ01,MBFM) + NCALL = NCALL + 1 + IF (NTRACE /= 0) CALL FMNTR(1,MBFM,MBFM,1,1) + NCALL = NCALL - 1 + RETURN + ENDIF + MARZ = MA(0) + MAIZ = MA(KPTIMU) + KACCSW = 0 + CALL ZMEQU(MA,MZ05,NDSAVE,NDIG) + +! Check for special cases. + + MXEXP1 = INT(MXEXP2/2.01D0) + IF (MA(2) == 0) THEN + CALL FMABS(MZ05(KPTIMU-1),MBFM) + GO TO 110 + ELSE IF (MA(KPTIMU+2) == 0) THEN + CALL FMABS(MZ05,MBFM) + GO TO 110 + ELSE IF (MA(1) == MEXPOV .OR. MA(KPTIMU+1) == MEXPOV) THEN + CALL FMI2M(1,MBFM) + MBFM(1) = MAX(MZ05(1),MZ05(KPTIMU+1)) + GO TO 110 + ELSE IF (MA(1) == MEXPUN) THEN + IF (MA(KPTIMU+1) > -MXEXP1+NDIG+1) THEN + CALL FMABS(MZ05(KPTIMU-1),MBFM) + ELSE + CALL FMST2M('UNKNOWN',MBFM) + KFLAG = -4 + ENDIF + GO TO 110 + ELSE IF (MA(KPTIMU+1) == MEXPUN) THEN + IF (MA(1) > -MXEXP1+NDIG+1) THEN + CALL FMABS(MZ05,MBFM) + ELSE + CALL FMST2M('UNKNOWN',MBFM) + KFLAG = -4 + ENDIF + GO TO 110 + ELSE IF (MA(1) /= MUNKNO .AND. MA(KPTIMU+1) /= MUNKNO) THEN + IF (MA(1) > MA(KPTIMU+1)+NDIG+1) THEN + CALL FMABS(MZ05,MBFM) + GO TO 110 + ELSE IF (MA(KPTIMU+1) > MA(1)+NDIG+1) THEN + CALL FMABS(MZ05(KPTIMU-1),MBFM) + GO TO 110 + ENDIF + ENDIF + + CALL FMSQR(MZ05,M01) + CALL FMSQR(MZ05(KPTIMU-1),M02) + CALL FMADD(M01,M02,MBFM) + CALL FMSQRT_R1(MBFM) + + 110 MACCMB = MBFM(0) + MBFM(0) = MIN(MACCMB,MARZ,MAIZ) + CALL ZMEXI2(MBFM,NDSAVE,MXSAVE,KASAVE,KOVUN) + RETURN + END SUBROUTINE ZMABS + + SUBROUTINE ZMACOS(MA,MB) + +! MB = ACOS(MA). + + USE FMVALS + IMPLICIT NONE + + REAL (KIND(1.0D0)) :: MA(-1:LUNPKZ),MB(-1:LUNPKZ) + REAL (KIND(1.0D0)) :: MACCMB,MAIZ,MARZ,MXSAVE + INTEGER J,KASAVE,KOVUN,KRESLT,NDSAVE + + CALL ZMENTR('ZMACOS',MA,MA,1,MB,KRESLT,NDSAVE,MXSAVE,KASAVE, & + KOVUN) + IF (KRESLT /= 0) RETURN + MARZ = MA(0) + MAIZ = MA(KPTIMU) + KACCSW = 0 + + CALL ZMEQU(MA,MZ07,NDSAVE,NDIG) + +! Check for special cases. + + IF (MA(2) == 0 .AND. MA(KPTIMU+2) == 0) THEN + CALL FMPI(MZ01) + CALL FMDIVI_R1(MZ01,2) + CALL FMI2M(0,MZ01(KPTIMU-1)) + GO TO 110 + ELSE IF (MA(KPTIMU+2) == 0) THEN + CALL FMACOS(MZ07,MZ01) + IF (KFLAG == 0) THEN + CALL FMI2M(0,MZ01(KPTIMU-1)) + GO TO 110 + ENDIF + ENDIF + IF ((MA(2) == 0 .OR. MA(1)*2 <= -NDIG) .AND. & + (MA(KPTIMU+2) == 0 .OR. MA(KPTIMU+1)*2 <= -NDIG)) THEN + CALL FMPI(MZ01) + CALL FMDIVI_R1(MZ01,2) + CALL FMI2M(0,MZ01(KPTIMU-1)) + CALL ZMSUB(MZ01,MZ07,MZ08) + CALL ZMEQ(MZ08,MZ01) + GO TO 110 + ENDIF + + CALL ZMI2M(1,MZ03) + CALL ZMSUB(MZ03,MZ07,MZ02) + CALL ZMADD(MZ03,MZ07,MZ08) + CALL ZMEQ(MZ08,MZ03) + CALL ZMMPY(MZ02,MZ03,MZ08) + CALL ZMEQ(MZ08,MZ02) + CALL ZMSQRT(MZ02,MZ08) + CALL ZMEQ(MZ08,MZ02) + DO J = -1, NDIG+1 + MZ03(J) = MZ02(KPTIMU+J) + MZ03(KPTIMU+J) = MZ02(J) + ENDDO + IF (MZ03(1) /= MUNKNO .AND. MZ03(2) /= 0) MZ03(-1) = -MZ03(-1) + + IF ((MA(2) /= 0 .AND. MZ03(1) == MA(1) .AND. & + MZ03(-1)*MZ03(2) == MA(-1)*MA(2)) .OR. & + (MA(KPTIMU+2) /= 0 .AND. MZ03(KPTIMU+1) == MA(KPTIMU+1) .AND. & + MZ03(KPTIMU-1)*MZ03(KPTIMU+2) == MA(KPTIMU-1)*MA(KPTIMU+2)) ) THEN + CALL ZMADD(MZ07,MZ03,MZ08) + CALL ZMEQ(MZ08,MZ03) + + CALL FMSQR(MZ03,M04) + CALL FMSQR(MZ03(KPTIMU-1),M05) + CALL FMADD(M04,M05,M06) + CALL FMI2M(1,M03) + CALL FMSUB_R2(M06,M03) + IF (M03(1) < 0) THEN + NDIG = NDIG - INT(M03(1)) + IF (NDIG > NDG2MX) THEN + NAMEST(NCALL) = 'ZMACOS' + KFLAG = -9 + CALL ZMWARN + KRESLT = 12 + NDIG = NDSAVE + CALL ZMRSLT(MB,KRESLT) + IF (NTRACE /= 0) CALL ZMNTR(1,MB,MB,1) + NCALL = NCALL - 1 + MXEXP = MXSAVE + KACCSW = KASAVE + RETURN + ENDIF + CALL ZMEQ2_R1(MZ07,NDSAVE,NDIG) + CALL ZMI2M(1,MZ03) + CALL ZMSUB(MZ03,MZ07,MZ02) + CALL ZMADD(MZ03,MZ07,MZ08) + CALL ZMEQ(MZ08,MZ03) + CALL ZMMPY(MZ02,MZ03,MZ08) + CALL ZMEQ(MZ08,MZ02) + CALL ZMSQRT(MZ02,MZ08) + CALL ZMEQ(MZ08,MZ02) + DO J = -1, NDIG+1 + MZ03(J) = MZ02(KPTIMU+J) + MZ03(KPTIMU+J) = MZ02(J) + ENDDO + IF (MZ03(1) /= MUNKNO .AND. MZ03(2) /= 0) MZ03(-1) = -MZ03(-1) + CALL ZMADD(MZ07,MZ03,MZ08) + CALL ZMEQ(MZ08,MZ03) + ENDIF + + CALL ZMLN(MZ03,MZ08) + CALL ZMEQ(MZ08,MZ03) + DO J = -1, NDIG+1 + MZ01(J) = MZ03(KPTIMU+J) + MZ01(KPTIMU+J) = MZ03(J) + ENDDO + IF (MZ01(KPTIMU+1) /= MUNKNO .AND. MZ01(KPTIMU+2) /= 0) & + MZ01(KPTIMU-1) = -MZ01(KPTIMU-1) + ELSE + CALL ZMSUB(MZ07,MZ03,MZ08) + CALL ZMEQ(MZ08,MZ03) + + CALL FMSQR(MZ03,M04) + CALL FMSQR(MZ03(KPTIMU-1),M05) + CALL FMADD(M04,M05,M06) + CALL FMI2M(1,M03) + CALL FMSUB_R2(M06,M03) + IF (M03(1) < 0) THEN + NDIG = NDIG - INT(M03(1)) + IF (NDIG > NDG2MX) THEN + NAMEST(NCALL) = 'ZMACOS' + KFLAG = -9 + CALL ZMWARN + KRESLT = 12 + NDIG = NDSAVE + CALL ZMRSLT(MB,KRESLT) + IF (NTRACE /= 0) CALL ZMNTR(1,MB,MB,1) + NCALL = NCALL - 1 + MXEXP = MXSAVE + KACCSW = KASAVE + RETURN + ENDIF + CALL ZMEQ2_R1(MZ07,NDSAVE,NDIG) + CALL ZMI2M(1,MZ03) + CALL ZMSUB(MZ03,MZ07,MZ02) + CALL ZMADD(MZ03,MZ07,MZ08) + CALL ZMEQ(MZ08,MZ03) + CALL ZMMPY(MZ02,MZ03,MZ08) + CALL ZMEQ(MZ08,MZ02) + CALL ZMSQRT(MZ02,MZ08) + CALL ZMEQ(MZ08,MZ02) + DO J = -1, NDIG+1 + MZ03(J) = MZ02(KPTIMU+J) + MZ03(KPTIMU+J) = MZ02(J) + ENDDO + IF (MZ03(1) /= MUNKNO .AND. MZ03(2) /= 0) MZ03(-1) = -MZ03(-1) + CALL ZMSUB(MZ07,MZ03,MZ08) + CALL ZMEQ(MZ08,MZ03) + ENDIF + + CALL ZMLN(MZ03,MZ08) + CALL ZMEQ(MZ08,MZ03) + DO J = -1, NDIG+1 + MZ01(J) = MZ03(KPTIMU+J) + MZ01(KPTIMU+J) = MZ03(J) + ENDDO + IF (MZ01(1) /= MUNKNO .AND. MZ01(2) /= 0) MZ01(-1) = -MZ01(-1) + ENDIF + + 110 MACCMB = MZ01(0) + MZ01(0) = MIN(MACCMB,MARZ,MAIZ) + MACCMB = MZ01(KPTIMU) + MZ01(KPTIMU) = MIN(MACCMB,MARZ,MAIZ) + CALL ZMEXIT(MZ01,MB,NDSAVE,MXSAVE,KASAVE,KOVUN) + RETURN + END SUBROUTINE ZMACOS + + SUBROUTINE ZMADD(MA,MB,MC) + +! MC = MA + MB + + USE FMVALS + IMPLICIT NONE + + REAL (KIND(1.0D0)) :: MA(-1:LUNPKZ),MB(-1:LUNPKZ),MC(-1:LUNPKZ) + + INTEGER KASAVE,KF1,KOVUN,KRESLT,KWRNSV,NDSAVE,NTRSAV + REAL (KIND(1.0D0)) :: MAR,MAI,MBR,MBI,MXSAVE + + IF (ABS(MA(1)) > MEXPAB .OR. ABS(MA(KPTIMU+1)) > MEXPAB .OR. & + ABS(MB(1)) > MEXPAB .OR. ABS(MB(KPTIMU+1)) > MEXPAB .OR. & + KDEBUG >= 1) THEN + CALL ZMENTR('ZMADD ',MA,MB,2,MC,KRESLT,NDSAVE,MXSAVE,KASAVE, & + KOVUN) + IF (KRESLT /= 0) RETURN + NDIG = NDSAVE + MXEXP = MXSAVE + KACCSW = KASAVE + NTRSAV = NTRACE + NTRACE = 0 + ELSE + NCALL = NCALL + 1 + NTRSAV = NTRACE + IF (NTRACE /= 0) THEN + NAMEST(NCALL) = 'ZMADD ' + CALL ZMNTR(2,MA,MB,2) + NTRACE = 0 + ENDIF + KOVUN = 0 + ENDIF + +! Force FMADD to use more guard digits for user calls. + + NCALL = NCALL - 1 + + KWRNSV = KWARN + KWARN = 0 + MAR = MA(1) + IF (MA(2) == 0) MAR = MEXPUN - 1 + MAI = MA(KPTIMU+1) + IF (MA(KPTIMU+2) == 0) MAI = MEXPUN - 1 + MBR = MB(1) + IF (MB(2) == 0) MBR = MEXPUN - 1 + MBI = MB(KPTIMU+1) + IF (MB(KPTIMU+2) == 0) MBI = MEXPUN - 1 + + CALL FMADD(MA,MB,MC) + KF1 = KFLAG + CALL FMADD(MA(KPTIMU-1),MB(KPTIMU-1),MC(KPTIMU-1)) + + NCALL = NCALL + 1 + IF (NTRSAV /= 0) THEN + NTRACE = NTRSAV + NAMEST(NCALL) = 'ZMADD ' + ENDIF + KWARN = KWRNSV + IF (KFLAG == 1) KFLAG = KF1 + IF (KFLAG == 1) THEN + KFLAG = 0 + IF (MAR <= MBR .AND. MAI <= MBI) KFLAG = 1 + IF (MAR >= MBR .AND. MAI >= MBI) KFLAG = 1 + ENDIF + + IF (MC(1) == MUNKNO .OR. MC(KPTIMU+1) == MUNKNO) THEN + KFLAG = -4 + ELSE IF (MC(1) == MEXPOV .OR. MC(KPTIMU+1) == MEXPOV) THEN + KFLAG = -5 + ELSE IF (MC(1) == MEXPUN .OR. MC(KPTIMU+1) == MEXPUN) THEN + KFLAG = -6 + ENDIF + IF ((MC(1) == MUNKNO) & + .OR. (MC(KPTIMU+1) == MUNKNO) & + .OR. (MC(1) == MEXPUN .AND. KOVUN == 0) & + .OR. (MC(KPTIMU+1) == MEXPUN .AND. KOVUN == 0) & + .OR. (MC(1) == MEXPOV .AND. KOVUN == 0) & + .OR. (MC(KPTIMU+1) == MEXPOV .AND. KOVUN == 0)) THEN + NAMEST(NCALL) = 'ZMADD ' + CALL ZMWARN + ENDIF + IF (NTRACE /= 0) THEN + CALL ZMNTR(1,MC,MC,1) + ENDIF + NCALL = NCALL - 1 + RETURN + END SUBROUTINE ZMADD + + SUBROUTINE ZMADDI(MA,INTEG) + +! MA = MA + INTEG Increment by one-word (real) integer. + + USE FMVALS + IMPLICIT NONE + + REAL (KIND(1.0D0)) :: MA(-1:LUNPKZ) + INTEGER INTEG + + INTEGER KASAVE,KOVUN,KRESLT,KWRNSV,NDSAVE,NTRSAV + REAL (KIND(1.0D0)) :: MXSAVE + + IF (ABS(MA(1)) > MEXPAB .OR. ABS(MA(KPTIMU+1)) > MEXPAB .OR. & + KDEBUG >= 1) THEN + NTRSAV = NTRACE + IF (NTRACE /= 0) THEN + NCALL = NCALL + 1 + NAMEST(NCALL) = 'ZMADDI' + CALL ZMNTR(2,MA,MA,1) + CALL FMNTRI(2,INTEG,0) + NCALL = NCALL - 1 + ENDIF + NTRACE = 0 + CALL ZMENTR('ZMADDI',MA,MA,1,MZ01,KRESLT,NDSAVE,MXSAVE,KASAVE, & + KOVUN) + NTRACE = NTRSAV + IF (KRESLT /= 0) THEN + CALL FMEQ(MZ01,MA) + NCALL = NCALL + 1 + IF (NTRACE /= 0) CALL ZMNTR(1,MA,MA,1) + NCALL = NCALL - 1 + RETURN + ENDIF + NDIG = NDSAVE + MXEXP = MXSAVE + KACCSW = KASAVE + NTRSAV = NTRACE + ELSE + NCALL = NCALL + 1 + IF (NTRACE /= 0) THEN + NAMEST(NCALL) = 'ZMADDI' + CALL ZMNTR(2,MA,MA,1) + CALL FMNTRI(2,INTEG,0) + ENDIF + KOVUN = 0 + ENDIF + +! Force FMADDI to use more guard digits for user calls. + + NCALL = NCALL - 1 + NTRSAV = NTRACE + NTRACE = 0 + KWRNSV = KWARN + KWARN = 0 + + CALL FMADDI(MA,INTEG) + + NTRACE = NTRSAV + KWARN = KWRNSV + NCALL = NCALL + 1 + IF (NTRACE /= 0) NAMEST(NCALL) = 'ZMADDI' + IF (MA(1) == MUNKNO .OR. MA(KPTIMU+1) == MUNKNO) THEN + KFLAG = -4 + ELSE IF (MA(1) == MEXPOV .OR. MA(KPTIMU+1) == MEXPOV) THEN + KFLAG = -5 + ELSE IF (MA(1) == MEXPUN .OR. MA(KPTIMU+1) == MEXPUN) THEN + KFLAG = -6 + ENDIF + IF ((MA(1) == MUNKNO) & + .OR. (MA(KPTIMU+1) == MUNKNO) & + .OR. (MA(1) == MEXPUN .AND. KOVUN == 0) & + .OR. (MA(KPTIMU+1) == MEXPUN .AND. KOVUN == 0) & + .OR. (MA(1) == MEXPOV .AND. KOVUN == 0) & + .OR. (MA(KPTIMU+1) == MEXPOV .AND. KOVUN == 0)) THEN + NAMEST(NCALL) = 'ZMADDI' + CALL ZMWARN + ENDIF + IF (NTRACE /= 0) CALL ZMNTR(1,MA,MA,1) + NCALL = NCALL - 1 + RETURN + END SUBROUTINE ZMADDI + + SUBROUTINE ZMARG(MA,MBFM) + +! MBFM = ARG(MA) + +! Complex argument. The result is a real FM number. + + USE FMVALS + IMPLICIT NONE + + REAL (KIND(1.0D0)) :: MA(-1:LUNPKZ),MBFM(-1:LUNPCK) + REAL (KIND(1.0D0)) :: MXSAVE + INTEGER KASAVE,KOVUN,KRESLT,NDSAVE,NTRSAV + + NTRSAV = NTRACE + IF (NTRACE /= 0) THEN + NCALL = NCALL + 1 + NAMEST(NCALL) = 'ZMARG ' + CALL ZMNTR(2,MA,MA,1) + NCALL = NCALL - 1 + ENDIF + NTRACE = 0 + CALL ZMENTR('ZMARG ',MA,MA,1,MZ01,KRESLT,NDSAVE,MXSAVE,KASAVE, & + KOVUN) + NTRACE = NTRSAV + IF (KRESLT /= 0) THEN + CALL FMEQ(MZ01,MBFM) + NCALL = NCALL + 1 + IF (NTRACE /= 0) CALL FMNTR(1,MBFM,MBFM,1,1) + NCALL = NCALL - 1 + RETURN + ENDIF + KACCSW = 0 + CALL ZMEQU(MA,MZ07,NDSAVE,NDIG) + + CALL FMATN2(MZ07(KPTIMU-1),MZ07,MBFM) + + CALL ZMEXI2(MBFM,NDSAVE,MXSAVE,KASAVE,KOVUN) + RETURN + END SUBROUTINE ZMARG + + SUBROUTINE ZMASIN(MA,MB) + +! MB = ASIN(MA). + + USE FMVALS + IMPLICIT NONE + + REAL (KIND(1.0D0)) :: MA(-1:LUNPKZ),MB(-1:LUNPKZ) + REAL (KIND(1.0D0)) :: MACCMB,MAIZ,MARZ,MXSAVE + INTEGER J,KASAVE,KOVUN,KRESLT,NDSAVE + + CALL ZMENTR('ZMASIN',MA,MA,1,MB,KRESLT,NDSAVE,MXSAVE,KASAVE, & + KOVUN) + IF (KRESLT /= 0) RETURN + MARZ = MA(0) + MAIZ = MA(KPTIMU) + KACCSW = 0 + + CALL ZMEQU(MA,MZ07,NDSAVE,NDIG) + +! Check for special cases. + + IF (MA(2) == 0 .AND. MA(KPTIMU+2) == 0) THEN + CALL ZMI2M(0,MZ01) + GO TO 110 + ELSE IF ((MA(2) == 0 .OR. MA(1)*2 <= -NDIG) .AND. & + (MA(KPTIMU+2) == 0 .OR. MA(KPTIMU+1)*2 <= -NDIG)) THEN + CALL ZMEQ(MZ07,MZ01) + GO TO 110 + ELSE IF (MA(KPTIMU+2) == 0) THEN + CALL FMASIN(MZ07,MZ01) + IF (KFLAG == 0) THEN + CALL FMI2M(0,MZ01(KPTIMU-1)) + GO TO 110 + ENDIF + ENDIF + + CALL ZMI2M(1,MZ03) + CALL ZMSUB(MZ03,MZ07,MZ02) + CALL ZMADD(MZ03,MZ07,MZ08) + CALL ZMEQ(MZ08,MZ03) + CALL ZMMPY(MZ02,MZ03,MZ08) + CALL ZMEQ(MZ08,MZ02) + CALL ZMSQRT(MZ02,MZ08) + CALL ZMEQ(MZ08,MZ02) + DO J = -1, NDIG+1 + MZ03(J) = MZ07(KPTIMU+J) + MZ03(KPTIMU+J) = MZ07(J) + ENDDO + IF (MZ03(1) /= MUNKNO .AND. MZ03(2) /= 0) MZ03(-1) = -MZ03(-1) + + IF ((MZ02(2) /= 0 .AND. MZ03(1) == MZ02(1) .AND. & + MZ03(-1)*MZ03(2) == MZ02(-1)*MZ02(2)) .OR. & + (MZ02(KPTIMU+2) /= 0 .AND. MZ03(KPTIMU+1) == MZ02(KPTIMU+1) .AND. & + MZ03(KPTIMU-1)*MZ03(KPTIMU+2) == & + MZ02(KPTIMU-1)*MZ02(KPTIMU+2)) ) THEN + CALL ZMADD(MZ02,MZ03,MZ08) + CALL ZMEQ(MZ08,MZ03) + CALL FMSQR(MZ03,M04) + CALL FMSQR(MZ03(KPTIMU-1),M05) + CALL FMADD(M04,M05,M06) + CALL FMI2M(1,M03) + CALL FMSUB_R2(M06,M03) + IF (M03(1) < 0) THEN + NDIG = NDIG - INT(M03(1)) + IF (NDIG > NDG2MX) THEN + NAMEST(NCALL) = 'ZMASIN' + KFLAG = -9 + CALL ZMWARN + KRESLT = 12 + NDIG = NDSAVE + CALL ZMRSLT(MB,KRESLT) + IF (NTRACE /= 0) CALL ZMNTR(1,MB,MB,1) + NCALL = NCALL - 1 + MXEXP = MXSAVE + KACCSW = KASAVE + RETURN + ENDIF + CALL ZMEQ2_R1(MZ07,NDSAVE,NDIG) + CALL ZMI2M(1,MZ03) + CALL ZMSUB(MZ03,MZ07,MZ02) + CALL ZMADD(MZ03,MZ07,MZ08) + CALL ZMEQ(MZ08,MZ03) + CALL ZMMPY(MZ02,MZ03,MZ08) + CALL ZMEQ(MZ08,MZ02) + CALL ZMSQRT(MZ02,MZ08) + CALL ZMEQ(MZ08,MZ02) + DO J = -1, NDIG+1 + MZ03(J) = MZ07(KPTIMU+J) + MZ03(KPTIMU+J) = MZ07(J) + ENDDO + IF (MZ03(1) /= MUNKNO .AND. MZ03(2) /= 0) MZ03(-1) = -MZ03(-1) + CALL ZMADD(MZ02,MZ03,MZ08) + CALL ZMEQ(MZ08,MZ03) + ENDIF + + CALL ZMLN(MZ03,MZ08) + CALL ZMEQ(MZ08,MZ03) + DO J = -1, NDIG+1 + MZ01(J) = MZ03(KPTIMU+J) + MZ01(KPTIMU+J) = MZ03(J) + ENDDO + IF (MZ01(KPTIMU+1) /= MUNKNO .AND. MZ01(KPTIMU+2) /= 0) & + MZ01(KPTIMU-1) = -MZ01(KPTIMU-1) + ELSE + CALL ZMSUB(MZ02,MZ03,MZ08) + CALL ZMEQ(MZ08,MZ03) + + CALL FMSQR(MZ03,M04) + CALL FMSQR(MZ03(KPTIMU-1),M05) + CALL FMADD(M04,M05,M06) + CALL FMI2M(1,M03) + CALL FMSUB_R2(M06,M03) + IF (M03(1) < 0) THEN + NDIG = NDIG - INT(M03(1)) + IF (NDIG > NDG2MX) THEN + NAMEST(NCALL) = 'ZMASIN' + KFLAG = -9 + CALL ZMWARN + KRESLT = 12 + NDIG = NDSAVE + CALL ZMRSLT(MB,KRESLT) + IF (NTRACE /= 0) CALL ZMNTR(1,MB,MB,1) + NCALL = NCALL - 1 + MXEXP = MXSAVE + KACCSW = KASAVE + RETURN + ENDIF + CALL ZMEQ2_R1(MZ07,NDSAVE,NDIG) + CALL ZMI2M(1,MZ03) + CALL ZMSUB(MZ03,MZ07,MZ02) + CALL ZMADD(MZ03,MZ07,MZ08) + CALL ZMEQ(MZ08,MZ03) + CALL ZMMPY(MZ02,MZ03,MZ08) + CALL ZMEQ(MZ08,MZ02) + CALL ZMSQRT(MZ02,MZ08) + CALL ZMEQ(MZ08,MZ02) + DO J = -1, NDIG+1 + MZ03(J) = MZ07(KPTIMU+J) + MZ03(KPTIMU+J) = MZ07(J) + ENDDO + IF (MZ03(1) /= MUNKNO .AND. MZ03(2) /= 0) MZ03(-1) = -MZ03(-1) + CALL ZMSUB(MZ02,MZ03,MZ08) + CALL ZMEQ(MZ08,MZ03) + ENDIF + CALL ZMLN(MZ03,MZ08) + CALL ZMEQ(MZ08,MZ03) + DO J = -1, NDIG+1 + MZ01(J) = MZ03(KPTIMU+J) + MZ01(KPTIMU+J) = MZ03(J) + ENDDO + IF (MZ01(1) /= MUNKNO .AND. MZ01(2) /= 0) MZ01(-1) = -MZ01(-1) + ENDIF + + 110 MACCMB = MZ01(0) + MZ01(0) = MIN(MACCMB,MARZ,MAIZ) + MACCMB = MZ01(KPTIMU) + MZ01(KPTIMU) = MIN(MACCMB,MARZ,MAIZ) + CALL ZMEXIT(MZ01,MB,NDSAVE,MXSAVE,KASAVE,KOVUN) + RETURN + END SUBROUTINE ZMASIN + + SUBROUTINE ZMATAN(MA,MB) + +! MB = ATAN(MA). + + USE FMVALS + IMPLICIT NONE + + REAL (KIND(1.0D0)) :: MA(-1:LUNPKZ),MB(-1:LUNPKZ) + REAL (KIND(1.0D0)) :: MACCMB,MAIZ,MARZ,MXSAVE + INTEGER J,JTERM,KASAVE,KOVUN,KRESLT,NDSAVE + LOGICAL FMCOMP + REAL X + + CALL ZMENTR('ZMATAN',MA,MA,1,MB,KRESLT,NDSAVE,MXSAVE,KASAVE, & + KOVUN) + IF (KRESLT /= 0) RETURN + MARZ = MA(0) + MAIZ = MA(KPTIMU) + KACCSW = 0 + + CALL ZMEQU(MA,MZ07,NDSAVE,NDIG) + +! Check for special cases. + + IF (MA(2) == 0 .AND. MA(KPTIMU+2) == 0) THEN + CALL ZMI2M(0,MZ04) + GO TO 120 + ELSE IF ((MA(2) == 0 .OR. MA(1)*2 <= -NDIG) .AND. & + (MA(KPTIMU+2) == 0 .OR. MA(KPTIMU+1)*2 <= -NDIG)) THEN + CALL ZMEQ(MZ07,MZ04) + GO TO 120 + ELSE IF (MA(KPTIMU+2) == 0) THEN + CALL FMATAN(MZ07,MZ04) + IF (KFLAG == 0) THEN + CALL FMI2M(0,MZ04(KPTIMU-1)) + GO TO 120 + ENDIF + ENDIF + + X = 1.0E+5 + CALL FMDPM(DBLE(X),M02) + CALL FMABS(MZ07,M03) + CALL FMABS(MZ07(KPTIMU-1),M04) + CALL FMADD_R2(M03,M04) + + IF (FMCOMP(M04,'GE',M02)) THEN + CALL ZMI2M(0,MZ04) + CALL FMPI(MZ04) + CALL FMDIVI_R1(MZ04,2) + IF (MA(-1) < 0 .AND. MZ04(1) /= MUNKNO .AND. MZ04(2) /= 0) & + MZ04(-1) = -MZ04(-1) + CALL ZMI2M(1,MZ02) + CALL ZMDIV(MZ02,MZ07,MZ08) + CALL ZMEQ(MZ08,MZ02) + CALL ZMEQ(MZ02,MZ03) + CALL ZMSUB(MZ04,MZ02,MZ08) + CALL ZMEQ(MZ08,MZ04) + IF (MA(1) > NDIG .OR. MA(KPTIMU+1) > NDIG) GO TO 120 + CALL ZMSQR(MZ02,MZ08) + CALL ZMEQ(MZ08,MZ02) + JTERM = 1 + 110 CALL ZMMPY(MZ03,MZ02,MZ08) + CALL ZMEQ(MZ08,MZ03) + JTERM = JTERM + 2 + CALL FMEQ(MZ03,M05) + CALL FMEQ(MZ03(KPTIMU-1),M06) + CALL ZMDIVI(MZ03,JTERM,MZ08) + CALL ZMEQ(MZ08,MZ03) + CALL ZMADD(MZ04,MZ03,MZ08) + CALL ZMEQ(MZ08,MZ04) + IF (KFLAG /= 0) GO TO 120 + CALL FMEQ(M05,MZ03) + CALL FMEQ(M06,MZ03(KPTIMU-1)) + CALL ZMMPY(MZ03,MZ02,MZ08) + CALL ZMEQ(MZ08,MZ03) + JTERM = JTERM + 2 + CALL FMEQ(MZ03,M05) + CALL FMEQ(MZ03(KPTIMU-1),M06) + CALL ZMDIVI(MZ03,JTERM,MZ08) + CALL ZMEQ(MZ08,MZ03) + CALL ZMSUB(MZ04,MZ03,MZ08) + CALL ZMEQ(MZ08,MZ04) + IF (KFLAG /= 0) GO TO 120 + CALL FMEQ(M05,MZ03) + CALL FMEQ(M06,MZ03(KPTIMU-1)) + GO TO 110 + ELSE + CALL ZM2I2M(0,1,MZ02) + CALL ZMSUB(MZ02,MZ07,MZ03) + CALL ZMADD(MZ02,MZ07,MZ08) + CALL ZMEQ(MZ08,MZ02) + CALL ZMDIV(MZ02,MZ03,MZ08) + CALL ZMEQ(MZ08,MZ03) + + CALL FMSQR(MZ03,M04) + CALL FMSQR(MZ03(KPTIMU-1),M05) + CALL FMADD(M04,M05,M06) + CALL FMI2M(1,M03) + CALL FMSUB_R2(M06,M03) + IF (M03(1) < 0) THEN + NDIG = NDIG - INT(M03(1)) + IF (NDIG > NDG2MX) THEN + NAMEST(NCALL) = 'ZMATAN' + KFLAG = -9 + CALL ZMWARN + KRESLT = 12 + NDIG = NDSAVE + CALL ZMRSLT(MB,KRESLT) + IF (NTRACE /= 0) CALL ZMNTR(1,MB,MB,1) + NCALL = NCALL - 1 + MXEXP = MXSAVE + KACCSW = KASAVE + RETURN + ENDIF + CALL ZMEQ2_R1(MZ07,NDSAVE,NDIG) + CALL ZM2I2M(0,1,MZ02) + CALL ZMSUB(MZ02,MZ07,MZ03) + CALL ZMADD(MZ02,MZ07,MZ08) + CALL ZMEQ(MZ08,MZ02) + CALL ZMDIV(MZ02,MZ03,MZ08) + CALL ZMEQ(MZ08,MZ03) + ENDIF + + CALL ZMLN(MZ03,MZ08) + CALL ZMEQ(MZ08,MZ03) + CALL ZMDIVI(MZ03,2,MZ08) + CALL ZMEQ(MZ08,MZ03) + DO J = -1, NDIG+1 + MZ04(J) = MZ03(KPTIMU+J) + MZ04(KPTIMU+J) = MZ03(J) + ENDDO + IF (MZ04(1) /= MUNKNO .AND. MZ04(2) /= 0) MZ04(-1) = -MZ04(-1) + ENDIF + + 120 MACCMB = MZ04(0) + MZ04(0) = MIN(MACCMB,MARZ,MAIZ) + MACCMB = MZ04(KPTIMU) + MZ04(KPTIMU) = MIN(MACCMB,MARZ,MAIZ) + CALL ZMEXIT(MZ04,MB,NDSAVE,MXSAVE,KASAVE,KOVUN) + RETURN + END SUBROUTINE ZMATAN + + SUBROUTINE ZMCHSH(MA,MB,MC) + +! MB = COSH(MA), MC = SINH(MA). + +! If both the hyperbolic sine and cosine are needed, this routine +! is faster than calling both ZMCOS and ZMSIN. + +! MB and MC must be distinct arrays. + + USE FMVALS + IMPLICIT NONE + + REAL (KIND(1.0D0)) :: MA(-1:LUNPKZ),MB(-1:LUNPKZ),MC(-1:LUNPKZ) + REAL (KIND(1.0D0)) :: MACCMB,MAIZ,MARZ,MXSAVE + INTEGER KASAVE,KOVUN,KRESLT,KRSAVE,NCSAVE,NDSAVE + + NCSAVE = NCALL + CALL ZMENTR('ZMCHSH',MA,MA,1,MB,KRESLT,NDSAVE,MXSAVE,KASAVE, & + KOVUN) + NCALL = NCSAVE + 1 + IF (KRESLT /= 0) THEN + CALL ZMEQ(MB,MC) + IF (NTRACE /= 0) THEN + CALL ZMNTR(1,MB,MB,1) + IF (ABS(NTRACE) >= 1 .AND. NCALL <= LVLTRC) THEN + IF (NTRACE < 0) THEN + CALL ZMNTRJ(MC,NDIG) + ELSE + CALL ZMPRNT(MC) + ENDIF + ENDIF + ENDIF + NCALL = NCALL - 1 + RETURN + ENDIF + MARZ = MA(0) + MAIZ = MA(KPTIMU) + KACCSW = 0 + KRSAVE = KRAD + KRAD = 1 + + CALL ZMEQU(MA,MZ07,NDSAVE,NDIG) + +! Check for special cases. + + IF (MA(2) == 0 .AND. MA(KPTIMU+2) == 0) THEN + CALL ZMI2M(1,MZ01) + CALL ZMI2M(0,MC) + GO TO 110 + ELSE IF (MA(KPTIMU+2) == 0) THEN + CALL FMCHSH(MZ07,MZ01,MC) + CALL FMI2M(0,MZ01(KPTIMU-1)) + CALL FMI2M(0,MC(KPTIMU-1)) + GO TO 110 + ELSE IF (MA(2) == 0) THEN + CALL FMCSSN(MZ07(KPTIMU-1),MZ01,MC(KPTIMU-1)) + CALL FMI2M(0,MZ01(KPTIMU-1)) + CALL FMI2M(0,MC) + GO TO 110 + ENDIF + +! Find SINH(REAL(MA)) and COSH(REAL(MA)). + + CALL FMCHSH(MZ07,MZ02,MZ02(KPTIMU-1)) + +! Find SIN(IMAG(MA)) and COS(IMAG(MA)). + + CALL FMCSSN(MZ07(KPTIMU-1),MZ03,MZ03(KPTIMU-1)) + +! COSH(MA) = COSH(REAL(MA))*COS(IMAG(MA)) + +! SINH(REAL(MA))*SIN(IMAG(MA)) i + + CALL FMMPY(MZ02,MZ03,MZ01) + CALL FMMPY(MZ02(KPTIMU-1),MZ03(KPTIMU-1),MZ01(KPTIMU-1)) + +! SINH(MA) = SINH(REAL(MA))*COS(IMAG(MA)) + +! COSH(REAL(MA))*SIN(IMAG(MA)) i + + CALL FMMPY(MZ02(KPTIMU-1),MZ03,MC) + CALL FMMPY(MZ02,MZ03(KPTIMU-1),MC(KPTIMU-1)) + + 110 MACCMB = MZ01(0) + MZ01(0) = MIN(MACCMB,MARZ,MAIZ) + MACCMB = MZ01(KPTIMU) + MZ01(KPTIMU) = MIN(MACCMB,MARZ,MAIZ) + MC(0) = MZ01(0) + MC(KPTIMU) = MZ01(KPTIMU) + KACCSW = KASAVE + CALL ZMEQ2_R1(MC,NDIG,NDSAVE) + CALL ZMEXIT(MZ01,MB,NDSAVE,MXSAVE,KASAVE,KOVUN) + IF (NTRACE /= 0) THEN + IF (ABS(NTRACE) >= 1 .AND. NCALL+1 <= LVLTRC) THEN + IF (NTRACE < 0) THEN + CALL ZMNTRJ(MC,NDIG) + ELSE + CALL ZMPRNT(MC) + ENDIF + ENDIF + ENDIF + KRAD = KRSAVE + RETURN + END SUBROUTINE ZMCHSH + + SUBROUTINE ZMCMPX(MAFM,MBFM,MC) + +! MC = COMPLEX( MAFM , MBFM ) + +! MAFM and MBFM are real FM numbers, MC is a complex ZM number. + + USE FMVALS + IMPLICIT NONE + + REAL (KIND(1.0D0)) :: MAFM(-1:LUNPCK),MBFM(-1:LUNPCK),MC(-1:LUNPKZ) + + KFLAG = 0 + NCALL = NCALL + 1 + NAMEST(NCALL) = 'ZMCMPX' + IF (NTRACE /= 0) CALL FMNTR(2,MAFM,MBFM,2,1) + + CALL FMEQ(MAFM,MC) + CALL FMEQ(MBFM,MC(KPTIMU-1)) + + IF (NTRACE /= 0) CALL ZMNTR(1,MC,MC,1) + NCALL = NCALL - 1 + RETURN + END SUBROUTINE ZMCMPX + + SUBROUTINE ZMCONJ(MA,MB) + +! MB = CONJG(MA) + +! Complex conjugate. + + USE FMVALS + IMPLICIT NONE + + REAL (KIND(1.0D0)) :: MA(-1:LUNPKZ),MB(-1:LUNPKZ) + + KFLAG = 0 + NCALL = NCALL + 1 + NAMEST(NCALL) = 'ZMCONJ' + IF (NTRACE /= 0) CALL ZMNTR(2,MA,MA,1) + + CALL FMEQ(MA,MB) + CALL FMEQ(MA(KPTIMU-1),MB(KPTIMU-1)) + IF (MB(KPTIMU+1) /= MUNKNO .AND. MB(KPTIMU+2) /= 0) & + MB(KPTIMU-1) = -MB(KPTIMU-1) + + IF (NTRACE /= 0) CALL ZMNTR(1,MB,MB,1) + NCALL = NCALL - 1 + RETURN + END SUBROUTINE ZMCONJ + + SUBROUTINE ZMCOS(MA,MB) + +! MB = COS(MA). + + USE FMVALS + IMPLICIT NONE + + REAL (KIND(1.0D0)) :: MA(-1:LUNPKZ),MB(-1:LUNPKZ) + REAL (KIND(1.0D0)) :: MACCMB,MAIZ,MARZ,MXSAVE + INTEGER KASAVE,KOVUN,KRESLT,KRSAVE,NDSAVE + + CALL ZMENTR('ZMCOS ',MA,MA,1,MB,KRESLT,NDSAVE,MXSAVE,KASAVE, & + KOVUN) + IF (KRESLT /= 0) RETURN + MARZ = MA(0) + MAIZ = MA(KPTIMU) + KACCSW = 0 + KRSAVE = KRAD + KRAD = 1 + + CALL ZMEQU(MA,MZ07,NDSAVE,NDIG) + +! Check for special cases. + + IF (MA(2) == 0 .AND. MA(KPTIMU+2) == 0) THEN + CALL ZMI2M(1,MZ01) + GO TO 110 + ELSE IF (MA(KPTIMU+2) == 0) THEN + CALL FMCOS(MZ07,MZ01) + CALL FMI2M(0,MZ01(KPTIMU-1)) + GO TO 110 + ELSE IF (MA(2) == 0) THEN + CALL FMCOSH(MZ07(KPTIMU-1),MZ01) + CALL FMI2M(0,MZ01(KPTIMU-1)) + GO TO 110 + ENDIF + +! Find COS(REAL(MA)) and SIN(REAL(MA)). + + CALL FMCSSN(MZ07,MZ01,MZ01(KPTIMU-1)) + +! Find COSH(IMAG(MA)) and SINH(IMAG(MA)). + + CALL FMCHSH(MZ07(KPTIMU-1),M05,M06) + +! COS(MA) = COS(REAL(MA))*COSH(IMAG(MA)) - +! SIN(REAL(MA))*SINH(IMAG(MA)) i + + CALL FMMPY_R1(MZ01,M05) + IF (M06(1) /= MUNKNO .AND. M06(2) /= 0) M06(-1) = -M06(-1) + CALL FMMPY_R1(MZ01(KPTIMU-1),M06) + + 110 MACCMB = MZ01(0) + MZ01(0) = MIN(MACCMB,MARZ,MAIZ) + MACCMB = MZ01(KPTIMU) + MZ01(KPTIMU) = MIN(MACCMB,MARZ,MAIZ) + CALL ZMEXIT(MZ01,MB,NDSAVE,MXSAVE,KASAVE,KOVUN) + KRAD = KRSAVE + RETURN + END SUBROUTINE ZMCOS + + SUBROUTINE ZMCOSH(MA,MB) + +! MB = COSH(MA). + + USE FMVALS + IMPLICIT NONE + + REAL (KIND(1.0D0)) :: MA(-1:LUNPKZ),MB(-1:LUNPKZ) + REAL (KIND(1.0D0)) :: MACCMB,MAIZ,MARZ,MXSAVE + INTEGER KASAVE,KOVUN,KRESLT,KRSAVE,NDSAVE + + CALL ZMENTR('ZMCOSH',MA,MA,1,MB,KRESLT,NDSAVE,MXSAVE,KASAVE, & + KOVUN) + IF (KRESLT /= 0) RETURN + MARZ = MA(0) + MAIZ = MA(KPTIMU) + KACCSW = 0 + KRSAVE = KRAD + KRAD = 1 + + CALL ZMEQU(MA,MZ07,NDSAVE,NDIG) + +! Check for special cases. + + IF (MA(2) == 0 .AND. MA(KPTIMU+2) == 0) THEN + CALL ZMI2M(1,MZ01) + GO TO 110 + ELSE IF (MA(2) == 0) THEN + CALL FMCOS(MZ07(KPTIMU-1),MZ01) + CALL FMI2M(0,MZ01(KPTIMU-1)) + GO TO 110 + ELSE IF (MA(KPTIMU+2) == 0) THEN + CALL FMCOSH(MZ07,MZ01) + CALL FMI2M(0,MZ01(KPTIMU-1)) + GO TO 110 + ENDIF + +! Find COS(IMAG(MA)) and SIN(IMAG(MA)). + + CALL FMCSSN(MZ07(KPTIMU-1),MZ01,MZ01(KPTIMU-1)) + +! Find COSH(REAL(MA)) and SINH(REAL(MA)). + + CALL FMCHSH(MZ07,M05,M06) + +! COSH(MA) = COSH(REAL(MA))*COS(IMAG(MA)) + +! SINH(REAL(MA))*SIN(IMAG(MA)) i + + CALL FMMPY_R1(MZ01,M05) + CALL FMMPY_R1(MZ01(KPTIMU-1),M06) + + 110 MACCMB = MZ01(0) + MZ01(0) = MIN(MACCMB,MARZ,MAIZ) + MACCMB = MZ01(KPTIMU) + MZ01(KPTIMU) = MIN(MACCMB,MARZ,MAIZ) + CALL ZMEXIT(MZ01,MB,NDSAVE,MXSAVE,KASAVE,KOVUN) + KRAD = KRSAVE + RETURN + END SUBROUTINE ZMCOSH + + SUBROUTINE ZMCSSN(MA,MB,MC) + +! MB = COS(MA), MC = SIN(MA). + +! If both the sine and cosine are needed, this routine is faster +! than calling both ZMCOS and ZMSIN. + +! MB and MC must be distinct arrays. + + USE FMVALS + IMPLICIT NONE + + REAL (KIND(1.0D0)) :: MA(-1:LUNPKZ),MB(-1:LUNPKZ),MC(-1:LUNPKZ) + REAL (KIND(1.0D0)) :: MACCMB,MAIZ,MARZ,MXSAVE + INTEGER KASAVE,KOVUN,KRESLT,KRSAVE,NCSAVE,NDSAVE + + NCSAVE = NCALL + CALL ZMENTR('ZMCSSN',MA,MA,1,MB,KRESLT,NDSAVE,MXSAVE,KASAVE, & + KOVUN) + NCALL = NCSAVE + 1 + IF (KRESLT /= 0) THEN + CALL ZMEQ(MB,MC) + IF (NTRACE /= 0) THEN + CALL ZMNTR(1,MB,MB,1) + IF (ABS(NTRACE) >= 1 .AND. NCALL <= LVLTRC) THEN + IF (NTRACE < 0) THEN + CALL ZMNTRJ(MC,NDIG) + ELSE + CALL ZMPRNT(MC) + ENDIF + ENDIF + ENDIF + NCALL = NCALL - 1 + RETURN + ENDIF + MARZ = MA(0) + MAIZ = MA(KPTIMU) + KACCSW = 0 + KRSAVE = KRAD + KRAD = 1 + + CALL ZMEQU(MA,MZ07,NDSAVE,NDIG) + +! Check for special cases. + + IF (MA(2) == 0 .AND. MA(KPTIMU+2) == 0) THEN + CALL ZMI2M(1,MZ01) + CALL ZMI2M(0,MC) + GO TO 110 + ELSE IF (MA(KPTIMU+2) == 0) THEN + CALL FMCSSN(MZ07,MZ01,MC) + CALL FMI2M(0,MZ01(KPTIMU-1)) + CALL FMI2M(0,MC(KPTIMU-1)) + GO TO 110 + ELSE IF (MA(2) == 0) THEN + CALL FMCHSH(MZ07(KPTIMU-1),MZ01,MC(KPTIMU-1)) + CALL FMI2M(0,MZ01(KPTIMU-1)) + CALL FMI2M(0,MC) + GO TO 110 + ENDIF + +! Find SIN(REAL(MA)) and COS(REAL(MA)). + + CALL FMCSSN(MZ07,MZ02,MZ02(KPTIMU-1)) + +! Find SINH(IMAG(MA)) and COSH(IMAG(MA)). + + CALL FMCHSH(MZ07(KPTIMU-1),MZ03,MZ03(KPTIMU-1)) + +! COS(MA) = COS(REAL(MA))*COSH(IMAG(MA)) - +! SIN(REAL(MA))*SINH(IMAG(MA)) i + + CALL FMMPY(MZ02,MZ03,MZ01) + CALL FMMPY(MZ02(KPTIMU-1),MZ03(KPTIMU-1),MZ01(KPTIMU-1)) + IF (MZ01(KPTIMU+1) /= MUNKNO .AND. MZ01(KPTIMU+2) /= 0) & + MZ01(KPTIMU-1) = -MZ01(KPTIMU-1) + +! SIN(MA) = SIN(REAL(MA))*COSH(IMAG(MA)) + +! COS(REAL(MA))*SINH(IMAG(MA)) i + + CALL FMMPY(MZ02(KPTIMU-1),MZ03,MC) + CALL FMMPY(MZ02,MZ03(KPTIMU-1),MC(KPTIMU-1)) + + 110 MACCMB = MZ01(0) + MZ01(0) = MIN(MACCMB,MARZ,MAIZ) + MACCMB = MZ01(KPTIMU) + MZ01(KPTIMU) = MIN(MACCMB,MARZ,MAIZ) + MC(0) = MZ01(0) + MC(KPTIMU) = MZ01(KPTIMU) + KACCSW = KASAVE + CALL ZMEQ2_R1(MC,NDIG,NDSAVE) + CALL ZMEXIT(MZ01,MB,NDSAVE,MXSAVE,KASAVE,KOVUN) + IF (NTRACE /= 0) THEN + IF (ABS(NTRACE) >= 1 .AND. NCALL+1 <= LVLTRC) THEN + IF (NTRACE < 0) THEN + CALL ZMNTRJ(MC,NDIG) + ELSE + CALL ZMPRNT(MC) + ENDIF + ENDIF + ENDIF + KRAD = KRSAVE + RETURN + END SUBROUTINE ZMCSSN + + SUBROUTINE ZMDIV(MA,MB,MC) + +! MC = MA / MB + + USE FMVALS + IMPLICIT NONE + + REAL (KIND(1.0D0)) :: MA(-1:LUNPKZ),MB(-1:LUNPKZ),MC(-1:LUNPKZ) + REAL (KIND(1.0D0)) :: MACCMB,MAIZ,MARZ,MBIZ,MBRZ,MXSAVE,MZ11SV,MZ1KSV + INTEGER IEXTRA,J,KASAVE,KOVUN,KRESLT,KWRNSV,NDGSV2,NDSAVE,NGOAL, & + NTRSAV + + IF (ABS(MA(1)) > MEXPAB .OR. ABS(MA(KPTIMU+1)) > MEXPAB .OR. & + ABS(MB(1)) > MEXPAB .OR. ABS(MB(KPTIMU+1)) > MEXPAB .OR. & + KDEBUG >= 1) THEN + CALL ZMENTR('ZMDIV ',MA,MB,2,MC,KRESLT,NDSAVE,MXSAVE,KASAVE, & + KOVUN) + IF (KRESLT /= 0) RETURN + ELSE + NCALL = NCALL + 1 + IF (NTRACE /= 0) THEN + NAMEST(NCALL) = 'ZMDIV ' + CALL ZMNTR(2,MA,MB,2) + ENDIF + NDSAVE = NDIG + IF (NCALL == 1) THEN + NDIG = MAX(NDIG+NGRD52,2) + IF (NDIG > NDG2MX) THEN + NAMEST(NCALL) = 'ZMDIV ' + KFLAG = -9 + CALL ZMWARN + KRESLT = 12 + NDIG = NDSAVE + CALL ZMRSLT(MC,KRESLT) + IF (NTRACE /= 0) CALL ZMNTR(1,MC,MC,1) + NCALL = NCALL - 1 + RETURN + ENDIF + IF (MBASE >= 100*ABS(MA(2)) .OR. & + MBASE >= 100*ABS(MA(KPTIMU+2))) THEN + NDIG = MIN(NDIG+1,NDG2MX) + ELSE IF (MBASE >= 100*ABS(MB(2)) .OR. & + MBASE >= 100*ABS(MB(KPTIMU+2))) THEN + NDIG = MIN(NDIG+1,NDG2MX) + ENDIF + ENDIF + KASAVE = KACCSW + KACCSW = 1 + MXSAVE = MXEXP + MXEXP = MXEXP2 + KOVUN = 0 + ENDIF + IF (MBASE < 1000 .OR. KROUND /= 1 .OR. KRPERF == 1) THEN + IF (NCALL == 1) NDIG = MIN(NDG2MX,MAX(NDIG,2*NDSAVE+10)) + ENDIF + + MARZ = MA(0) + MBRZ = MB(0) + MAIZ = MA(KPTIMU) + MBIZ = MB(KPTIMU) + NTRSAV = NTRACE + NTRACE = 0 + KWRNSV = KWARN + KWARN = 0 + IEXTRA = 0 + MZ11SV = -MUNKNO + MZ1KSV = -MUNKNO + + 110 CALL FMEQU(MA,M17,NDSAVE,NDIG) + CALL FMEQU(MA(KPTIMU-1),M18,NDSAVE,NDIG) + CALL FMEQU(MB,M19,NDSAVE,NDIG) + CALL FMEQU(MB(KPTIMU-1),M20,NDSAVE,NDIG) + IF (NCALL == 1) THEN + M17(0) = NINT(NDIG*ALOGM2) + M19(0) = M17(0) + M18(0) = M17(0) + M20(0) = M17(0) + ENDIF + +! Check for special cases. + + IF (MB(KPTIMU+2) == 0) THEN + CALL FMDIVD(M17,M18,M19,MZ01,MZ01(KPTIMU-1)) + GO TO 130 + ELSE IF (MB(2) == 0) THEN + CALL FMDIVD(M18,M17,M20,MZ01,MZ01(KPTIMU-1)) + IF (MZ01(KPTIMU+1) /= MUNKNO .AND. MZ01(KPTIMU+2) /= 0) & + MZ01(KPTIMU-1) = -MZ01(KPTIMU-1) + GO TO 130 + ENDIF + IF (MA(1) == MB(1) .AND. MA(2) == MB(2) .AND. MA(-1) == MB(-1)) THEN + IF (MA(KPTIMU+1) == MB(KPTIMU+1) .AND. & + MA(KPTIMU+2) == MB(KPTIMU+2) .AND. & + MA(KPTIMU-1) == MB(KPTIMU-1)) THEN + DO J = 3, NDSAVE+1 + IF (MA(J) /= MB(J)) GO TO 120 + IF (MA(KPTIMU+J) /= MB(KPTIMU+J)) GO TO 120 + ENDDO + IF (ABS(MA(1)) < MEXPOV .AND. ABS(MA(KPTIMU+1)) < MEXPOV & + .AND. ABS(MB(1)) < MEXPOV .AND. & + ABS(MB(KPTIMU+1)) < MEXPOV) THEN + CALL ZMI2M(1,MZ01) + GO TO 130 + ENDIF + ENDIF + ENDIF + IF (MA(1) == MB(1) .AND. MA(2) == MB(2) .AND. (-MA(-1)) == MB(-1)) THEN + IF (MA(KPTIMU+1) == MB(KPTIMU+1) .AND. & + MA(KPTIMU+2) == MB(KPTIMU+2) .AND. & + (-MA(KPTIMU-1)) == MB(KPTIMU-1)) THEN + DO J = 3, NDSAVE+1 + IF (MA(J) /= MB(J)) GO TO 120 + IF (MA(KPTIMU+J) /= MB(KPTIMU+J)) GO TO 120 + ENDDO + IF (ABS(MA(1)) < MEXPOV .AND. ABS(MA(KPTIMU+1)) < MEXPOV & + .AND. ABS(MB(1)) < MEXPOV .AND. & + ABS(MB(KPTIMU+1)) < MEXPOV) THEN + CALL ZMI2M(-1,MZ01) + GO TO 130 + ENDIF + ENDIF + ENDIF + 120 IF (MZ11SV /= -MUNKNO) THEN + +! If a retry is being done due to cancellation, try a slower +! but more stable form of the division formula. + + CALL FMMPYE(M19,M17,M18,M19, & + MZ01,MZ01(KPTIMU-1),M03) + CALL FMMPYE(M20,M18,M17,M20, & + M01,M02,M04) + CALL FMADD_R2(M03,M04) + CALL FMADD_R1(MZ01,M01) + CALL FMSUB_R1(MZ01(KPTIMU-1),M02) + CALL FMDIVD(MZ01,MZ01(KPTIMU-1),M04,MZ08,MZ08(KPTIMU-1)) + CALL ZMEQ(MZ08,MZ01) + IF (ABS(MZ01(1)) < MEXPOV .AND. & + ABS(MZ01(KPTIMU+1)) < MEXPOV) GO TO 130 + ENDIF + +! Normal method for ( a + b i ) / ( c + d i ): + +! If abs(c) << abs(d) Then + +! P = c / d +! result = ( a*P + b )/( c*P + d ) + +! ( b*P - a )/( c*P + d ) i + +! Else + +! P = d / c +! result = ( b*P + a )/( d*P + c ) + +! ( b - a*P )/( d*P + c ) i + + KACCSW = 0 + IF (MB(1) <= MB(KPTIMU+1)) THEN + CALL FMDIV(M19,M20,M04) + CALL FMMPYE(M04,M17,M18,M19,MZ01,MZ01(KPTIMU-1),M03) + IF (MA(KPTIMU-1)*MZ01(-1) < 0) THEN + KACCSW = 1 + ELSE + KACCSW = 0 + ENDIF + CALL FMADD_R2(M18,MZ01) + IF (M03(-1)*MB(KPTIMU-1) < 0) THEN + KACCSW = 1 + ELSE + KACCSW = 0 + ENDIF + CALL FMADD_R1(M03,M20) + IF (MZ01(KPTIMU-1)*MA(-1) < 0) THEN + KACCSW = 0 + ELSE + KACCSW = 1 + ENDIF + CALL FMSUB_R1(MZ01(KPTIMU-1),M17) + KACCSW = 0 + CALL FMDIVD(MZ01,MZ01(KPTIMU-1),M03,MZ08,MZ08(KPTIMU-1)) + CALL ZMEQ(MZ08,MZ01) + ELSE + CALL FMDIV(M20,M19,M04) + CALL FMMPYE(M04,M18,M17,M20, & + MZ01,MZ01(KPTIMU-1),M03) + IF (MA(-1)*MZ01(-1) < 0) THEN + KACCSW = 1 + ELSE + KACCSW = 0 + ENDIF + CALL FMADD_R2(M17,MZ01) + IF (M03(-1)*MB(-1) < 0) THEN + KACCSW = 1 + ELSE + KACCSW = 0 + ENDIF + CALL FMADD_R1(M03,M19) + IF (MZ01(KPTIMU-1)*MA(KPTIMU-1) < 0) THEN + KACCSW = 0 + ELSE + KACCSW = 1 + ENDIF + CALL FMSUB_R2(M18,MZ01(KPTIMU-1)) + KACCSW = 0 + CALL FMDIVD(MZ01,MZ01(KPTIMU-1),M03,MZ08,MZ08(KPTIMU-1)) + CALL ZMEQ(MZ08,MZ01) + ENDIF + KACCSW = 1 + +! Check for too much cancellation. + + IF (NCALL <= 1) THEN + NGOAL = INT(REAL(NDSAVE)*ALOGM2) + 7 + ELSE + NGOAL = INT(-MXEXP2) + ENDIF + IF (MZ01(0) <= NGOAL .OR. MZ01(KPTIMU) <= NGOAL) THEN + IF (MZ11SV-MZ01(1) >= IEXTRA-1 .AND. MZ01(KPTIMU) > NGOAL) & + GO TO 130 + IF (MZ1KSV-MZ01(KPTIMU+1) >= IEXTRA-1 .AND. MZ01(0) > NGOAL) & + GO TO 130 + IF (MZ11SV > -MUNKNO .AND. MZ01(0) > NGOAL .AND. & + MZ01(KPTIMU+2) == 0) GO TO 130 + IF (MZ11SV > -MUNKNO .AND. MZ01(KPTIMU) > NGOAL .AND. & + MZ01(2) == 0) GO TO 130 + IEXTRA = INT(REAL(MAX(NGOAL-MZ01(0),NGOAL-MZ01(KPTIMU))) & + /ALOGM2 + 23.03/ALOGMB) + 1 + MZ11SV = MZ01(1) + MZ1KSV = MZ01(KPTIMU+1) + NDIG = NDIG + IEXTRA + IF (NDIG > NDG2MX) THEN + NAMEST(NCALL) = 'ZMDIV ' + KFLAG = -9 + CALL ZMWARN + NDIG = NDSAVE + CALL ZMST2M('UNKNOWN+UNKNOWN*i',MZ01) + GO TO 130 + ENDIF + GO TO 110 + ENDIF + + 130 MXEXP = MXSAVE + NTRACE = NTRSAV + NDGSV2 = NDIG + NDIG = NDSAVE + KWARN = KWRNSV + MACCMB = MZ01(0) + MZ01(0) = MIN(MACCMB,MARZ,MAIZ,MBRZ,MBIZ) + MACCMB = MZ01(KPTIMU) + MZ01(KPTIMU) = MIN(MACCMB,MARZ,MAIZ,MBRZ,MBIZ) + CALL ZMEQ2(MZ01,MC,NDGSV2,NDSAVE) + IF (MC(1) >= MEXPOV .OR. MC(1) <= -MEXPOV .OR. & + MC(KPTIMU+1) >= MEXPOV .OR. MC(KPTIMU+1) <= -MEXPOV) THEN + IF (MC(1) == MUNKNO .OR. MC(KPTIMU+1) == MUNKNO) THEN + KFLAG = -4 + ELSE IF (MC(1) == MEXPOV .OR. MC(KPTIMU+1) == MEXPOV) THEN + KFLAG = -5 + ELSE IF (MC(1) == MEXPUN .OR. MC(KPTIMU+1) == MEXPUN) THEN + KFLAG = -6 + ENDIF + IF ((MC(1) == MUNKNO) & + .OR. (MC(KPTIMU+1) == MUNKNO) & + .OR. (MC(1) == MEXPUN .AND. KOVUN == 0) & + .OR. (MC(KPTIMU+1) == MEXPUN .AND. KOVUN == 0) & + .OR. (MC(1) == MEXPOV .AND. KOVUN == 0) & + .OR. (MC(KPTIMU+1) == MEXPOV .AND. KOVUN == 0)) THEN + NAMEST(NCALL) = 'ZMDIV ' + CALL ZMWARN + ENDIF + ENDIF + IF (NTRACE /= 0) CALL ZMNTR(1,MC,MC,1) + KACCSW = KASAVE + NCALL = NCALL - 1 + RETURN + END SUBROUTINE ZMDIV + + SUBROUTINE ZMDIVI(MA,INTEG,MB) + +! MB = MA / INTEG Divide by one-word (real) integer. + + USE FMVALS + IMPLICIT NONE + + REAL (KIND(1.0D0)) :: MA(-1:LUNPKZ),MB(-1:LUNPKZ) + INTEGER INTEG + + INTEGER KASAVE,KOVUN,KRESLT,KWRNSV,NDSAVE,NTRSAV + REAL (KIND(1.0D0)) :: MXSAVE + + IF (ABS(MA(1)) > MEXPAB .OR. ABS(MA(KPTIMU+1)) > MEXPAB .OR. & + KDEBUG >= 1) THEN + NTRSAV = NTRACE + IF (NTRACE /= 0) THEN + NCALL = NCALL + 1 + NAMEST(NCALL) = 'ZMDIVI' + CALL ZMNTR(2,MA,MA,1) + CALL FMNTRI(2,INTEG,0) + NCALL = NCALL - 1 + ENDIF + NTRACE = 0 + CALL ZMENTR('ZMDIVI',MA,MA,1,MB,KRESLT,NDSAVE,MXSAVE,KASAVE, & + KOVUN) + NTRACE = NTRSAV + IF (KRESLT /= 0) THEN + NCALL = NCALL + 1 + IF (NTRACE /= 0) CALL ZMNTR(1,MB,MB,1) + NCALL = NCALL - 1 + RETURN + ENDIF + NDIG = NDSAVE + MXEXP = MXSAVE + KACCSW = KASAVE + ELSE + NCALL = NCALL + 1 + IF (NTRACE /= 0) THEN + NAMEST(NCALL) = 'ZMDIVI' + CALL ZMNTR(2,MA,MA,1) + CALL FMNTRI(2,INTEG,0) + ENDIF + KOVUN = 0 + ENDIF + +! Force FMDIVI to use more guard digits for user calls. + + NCALL = NCALL - 1 + NTRSAV = NTRACE + NTRACE = 0 + KWRNSV = KWARN + KWARN = 0 + + CALL FMDIVI(MA,INTEG,MB) + CALL FMDIVI(MA(KPTIMU-1),INTEG,MB(KPTIMU-1)) + + NTRACE = NTRSAV + KWARN = KWRNSV + NCALL = NCALL + 1 + IF (NTRACE /= 0) NAMEST(NCALL) = 'ZMDIVI' + IF (MB(1) == MUNKNO .OR. MB(KPTIMU+1) == MUNKNO) THEN + KFLAG = -4 + ELSE IF (MB(1) == MEXPOV .OR. MB(KPTIMU+1) == MEXPOV) THEN + KFLAG = -5 + ELSE IF (MB(1) == MEXPUN .OR. MB(KPTIMU+1) == MEXPUN) THEN + KFLAG = -6 + ENDIF + IF ((MB(1) == MUNKNO) & + .OR. (MB(KPTIMU+1) == MUNKNO) & + .OR. (MB(1) == MEXPUN .AND. KOVUN == 0) & + .OR. (MB(KPTIMU+1) == MEXPUN .AND. KOVUN == 0) & + .OR. (MB(1) == MEXPOV .AND. KOVUN == 0) & + .OR. (MB(KPTIMU+1) == MEXPOV .AND. KOVUN == 0)) THEN + NAMEST(NCALL) = 'ZMDIVI' + CALL ZMWARN + ENDIF + IF (NTRACE /= 0) CALL ZMNTR(1,MB,MB,1) + NCALL = NCALL - 1 + RETURN + END SUBROUTINE ZMDIVI + + SUBROUTINE ZMENTR(NROUTN,MA,MB,NARGS,MC,KRESLT,NDSAVE,MXSAVE, & + KASAVE,KOVUN) + +! Do the argument checking and increasing of precision, overflow +! threshold, etc., upon entry to a ZM routine. + +! NROUTN - routine name of calling routine +! MA - first input argument +! MB - second input argument (optional) +! NARGS - number of input arguments +! MC - result argument +! KRESLT - returned nonzero if the input arguments give the result +! immediately (e.g., MA*0 or OVERFLOW*MB) +! NDSAVE - saves the value of NDIG after NDIG is increased +! MXSAVE - saves the value of MXEXP +! KASAVE - saves the value of KACCSW +! KOVUN - returned nonzero if an input argument is (+ or -) overflow +! or underflow. + + USE FMVALS + IMPLICIT NONE + + CHARACTER(6) :: NROUTN + REAL (KIND(1.0D0)) :: MA(-1:LUNPKZ),MB(-1:LUNPKZ),MC(-1:LUNPKZ),MXSAVE + INTEGER NARGS,KRESLT,NDSAVE,KASAVE,KOVUN + + REAL (KIND(1.0D0)) :: MBS + INTEGER J,KWRNSV,NDS + + KRESLT = 0 + NCALL = NCALL + 1 + KFLAG = 0 + NAMEST(NCALL) = NROUTN + IF (NTRACE /= 0) CALL ZMNTR(2,MA,MB,NARGS) + + IF (MBLOGS /= MBASE) CALL FMCONS + KOVUN = 0 + IF (MA(1) == MEXPOV .OR. MA(1) == MEXPUN .OR. & + MA(KPTIMU+1) == MEXPOV .OR. MA(KPTIMU+1) == MEXPUN) KOVUN = 1 + IF (NARGS == 2) THEN + IF (MB(1) == MEXPOV .OR. MB(1) == MEXPUN .OR. & + MB(KPTIMU+1) == MEXPOV .OR. MB(KPTIMU+1) == MEXPUN) KOVUN = 1 + ENDIF + KASAVE = KACCSW + MXSAVE = MXEXP + +! Check the validity of parameters if this is a user call. + + IF (NCALL > 1 .AND. KDEBUG == 0) GO TO 130 + +! Check NDIG. + + IF (NDIG < 2 .OR. NDIG > NDIGMX) THEN + KFLAG = -1 + CALL ZMWARN + NDS = NDIG + IF (NDIG < 2) NDIG = 2 + IF (NDIG > NDIGMX) NDIG = NDIGMX + WRITE (KW, & + "(' NDIG was',I10,'. It has been changed to',I10,'.')" & + ) NDS,NDIG + KRESLT = 12 + GO TO 130 + ENDIF + +! Check MBASE. + + IF (MBASE < 2 .OR. MBASE > MXBASE) THEN + KFLAG = -2 + CALL ZMWARN + MBS = MBASE + IF (MBASE < 2) MBASE = 2 + IF (MBASE > MXBASE) MBASE = MXBASE + WRITE (KW, & + "(' MBASE was',I10,'. It has been changed to',I10,'.')" & + ) INT(MBS),INT(MBASE) + CALL FMCONS + KRESLT = 12 + GO TO 130 + ENDIF + +! Check exponent range. + + IF (MA(1) > MXEXP+1 .OR. MA(1) < -MXEXP) THEN + IF ((ABS(MA(1)) /= MEXPOV .AND. ABS(MA(1)) /= MUNKNO) .OR. & + ABS(MA(2)) /= 1) THEN + KFLAG = -3 + CALL ZMWARN + KRESLT = 12 + GO TO 130 + ENDIF + ENDIF + IF (MA(KPTIMU+1) > MXEXP+1 .OR. MA(KPTIMU+1) < -MXEXP) THEN + IF ((ABS(MA(KPTIMU+1)) /= MEXPOV .AND. & + ABS(MA(KPTIMU+1)) /= MUNKNO) .OR. & + ABS(MA(KPTIMU+2)) /= 1) THEN + KFLAG = -3 + CALL ZMWARN + KRESLT = 12 + GO TO 130 + ENDIF + ENDIF + IF (NARGS == 2) THEN + IF (MB(1) > MXEXP+1 .OR. MB(1) < -MXEXP) THEN + IF ((ABS(MB(1)) /= MEXPOV .AND. ABS(MB(1)) /= MUNKNO) .OR. & + ABS(MB(2)) /= 1) THEN + KFLAG = -3 + CALL ZMWARN + KRESLT = 12 + GO TO 130 + ENDIF + ENDIF + IF (MB(KPTIMU+1) > MXEXP+1 .OR. MB(KPTIMU+1) < -MXEXP) THEN + IF ((ABS(MB(KPTIMU+1)) /= MEXPOV .AND. & + ABS(MB(KPTIMU+1)) /= MUNKNO) .OR. & + ABS(MB(KPTIMU+2)) /= 1) THEN + KFLAG = -3 + CALL ZMWARN + KRESLT = 12 + GO TO 130 + ENDIF + ENDIF + ENDIF + +! Check for properly normalized digits in the +! input arguments. + + IF (ABS(MA(1)-INT(MA(1))) /= 0) KFLAG = 1 + IF (ABS(MA(KPTIMU+1)-INT(MA(KPTIMU+1))) /= 0) KFLAG = KPTIMU + 1 + IF (MA(2) <= (-1) .OR. MA(2) >= MBASE .OR. & + ABS(MA(2)-INT(MA(2))) /= 0) KFLAG = 2 + IF (MA(KPTIMU+2) <= (-1) .OR. MA(KPTIMU+2) >= MBASE .OR. & + ABS(MA(KPTIMU+2)-INT(MA(KPTIMU+2))) /= 0) KFLAG = KPTIMU + 2 + IF (KDEBUG == 0) GO TO 110 + DO J = 3, NDIG+1 + IF (MA(J) < 0 .OR. MA(J) >= MBASE .OR. & + ABS(MA(J)-INT(MA(J))) /= 0) THEN + KFLAG = J + GO TO 110 + ENDIF + ENDDO + DO J = KPTIMU+3, KPTIMU+NDIG+1 + IF (MA(J) < 0 .OR. MA(J) >= MBASE .OR. & + ABS(MA(J)-INT(MA(J))) /= 0) THEN + KFLAG = J + GO TO 110 + ENDIF + ENDDO + 110 IF (KFLAG /= 0) THEN + J = KFLAG + KFLAG = -4 + KWRNSV = KWARN + IF (KWARN >= 2) KWARN = 1 + CALL ZMWARN + KWARN = KWRNSV + IF (KWARN >= 1) THEN + IF (J < KPTIMU) THEN + WRITE (KW,*) ' First invalid array element: MA(', & + J,') = ',MA(J) + ELSE + WRITE (KW,*) ' First invalid array element: MA(', & + KPTIMU,'+',J-KPTIMU,') = ',MA(J) + ENDIF + ENDIF + IF (KWARN >= 2) THEN + STOP + ENDIF + KRESLT = 12 + GO TO 130 + ENDIF + IF (NARGS == 2) THEN + IF (ABS(MB(1)-INT(MB(1))) /= 0) KFLAG = 1 + IF (ABS(MB(KPTIMU+1)-INT(MB(KPTIMU+1))) /= 0) & + KFLAG = KPTIMU + 1 + IF (MB(2) <= (-1) .OR. MB(2) >= MBASE .OR. & + ABS(MB(2)-INT(MB(2))) /= 0) KFLAG = 2 + IF (MB(KPTIMU+2) <= (-1) .OR. MB(KPTIMU+2) >= MBASE .OR. & + ABS(MB(KPTIMU+2)-INT(MB(KPTIMU+2))) /= 0) & + KFLAG = KPTIMU + 2 + IF (KDEBUG == 0) GO TO 120 + DO J = 3, NDIG+1 + IF (MB(J) < 0 .OR. MB(J) >= MBASE .OR. & + ABS(MB(J)-INT(MB(J))) /= 0) THEN + KFLAG = J + GO TO 120 + ENDIF + ENDDO + DO J = KPTIMU+3, KPTIMU+NDIG+1 + IF (MB(J) < 0 .OR. MB(J) >= MBASE .OR. & + ABS(MB(J)-INT(MB(J))) /= 0) THEN + KFLAG = J + GO TO 120 + ENDIF + ENDDO + 120 IF (KFLAG /= 0) THEN + J = KFLAG + MBS = MB(J) + KFLAG = -4 + KWRNSV = KWARN + IF (KWARN >= 2) KWARN = 1 + CALL ZMWARN + KWARN = KWRNSV + IF (KWARN >= 1) THEN + IF (J < KPTIMU) THEN + WRITE (KW,*) ' First invalid array element: MB(', & + J,') = ',MB(J) + ELSE + WRITE (KW,*) ' First invalid array element: MB(', & + KPTIMU,'+',J-KPTIMU,') = ',MB(J) + ENDIF + ENDIF + IF (KWARN >= 2) THEN + STOP + ENDIF + KRESLT = 12 + GO TO 130 + ENDIF + ENDIF + +! Increase the working precision. + + 130 NDSAVE = NDIG + IF (NCALL == 1) THEN + NDIG = MAX(NDIG+NGRD52,2) + IF (NDIG > NDG2MX) THEN + KFLAG = -9 + CALL ZMWARN + KRESLT = 12 + NDIG = NDSAVE + ENDIF + IF (MBASE >= 100*ABS(MA(2)) .OR. & + MBASE >= 100*ABS(MA(KPTIMU+2))) THEN + NDIG = MIN(NDIG+1,NDG2MX) + ELSE IF (NARGS == 2 .AND. (MBASE >= 100*ABS(MB(2)) .OR. & + MBASE >= 100*ABS(MB(KPTIMU+2)))) THEN + NDIG = MIN(NDIG+1,NDG2MX) + ENDIF + ENDIF + IF ((MA(1) == MUNKNO .AND. MA(KPTIMU+1) == MUNKNO) .OR. & + (MB(1) == MUNKNO .AND. MB(KPTIMU+1) == MUNKNO)) THEN + KFLAG = -4 + KRESLT = 12 + ENDIF + IF (KRESLT /= 0) THEN + NDIG = NDSAVE + CALL ZMRSLT(MC,KRESLT) + IF (NTRACE /= 0) CALL ZMNTR(1,MC,MC,1) + NCALL = NCALL - 1 + RETURN + ENDIF + + KACCSW = 1 + +! Extend the overflow/underflow threshold. + + MXEXP = MXEXP2 + RETURN + END SUBROUTINE ZMENTR + + SUBROUTINE ZMEQ(MA,MB) + +! MB = MA + +! This is the standard form of equality, where MA and MB both +! have precision NDIG. Use ZMEQU for assignments that also +! change precision. + + USE FMVALS + IMPLICIT NONE + + REAL (KIND(1.0D0)) :: MA(-1:LUNPKZ),MB(-1:LUNPKZ) + + CALL FMEQ(MA,MB) + CALL FMEQ(MA(KPTIMU-1),MB(KPTIMU-1)) + RETURN + END SUBROUTINE ZMEQ + + SUBROUTINE ZMEQ2(MA,MB,NDA,NDB) + +! Set MB (having NDB digits) equal to MA (having NDA digits). + +! If MB has less precision than MA, the result is rounded to +! NDB digits. + +! If MB has more precision, the result has zero digits padded on the +! right. + + USE FMVALS + IMPLICIT NONE + + REAL (KIND(1.0D0)) :: MA(-1:LUNPKZ),MB(-1:LUNPKZ) + INTEGER NDA,NDB + + CALL FMEQ2(MA,MB,NDA,NDB) + CALL FMEQ2(MA(KPTIMU-1),MB(KPTIMU-1),NDA,NDB) + RETURN + END SUBROUTINE ZMEQ2 + + SUBROUTINE ZMEQ2_R1(MA,NDA,NDB) + +! Change precision of MA from NDA digits on input to NDB digits on output. + +! If NDB is less than NDA the result is rounded to NDB digits. + +! If NDB is greater than NDA the result has zero digits padded on the +! right. + + USE FMVALS + IMPLICIT NONE + + REAL (KIND(1.0D0)) :: MA(-1:LUNPKZ) + INTEGER NDA,NDB + + CALL FMEQ2_R1(MA,NDA,NDB) + CALL FMEQ2_R1(MA(KPTIMU-1),NDA,NDB) + RETURN + END SUBROUTINE ZMEQ2_R1 + + SUBROUTINE ZMEQU(MA,MB,NDA,NDB) + +! Set MB (having NDB digits) equal to MA (having NDA digits). + + USE FMVALS + IMPLICIT NONE + + REAL (KIND(1.0D0)) :: MA(-1:LUNPKZ),MB(-1:LUNPKZ) + INTEGER NDA,NDB + + CALL FMEQ2(MA,MB,NDA,NDB) + CALL FMEQ2(MA(KPTIMU-1),MB(KPTIMU-1),NDA,NDB) + RETURN + END SUBROUTINE ZMEQU + + SUBROUTINE ZMEXIT(MT,MC,NDSAVE,MXSAVE,KASAVE,KOVUN) + +! Upon exit from an ZM routine the result MT (having precision NDIG) +! is rounded and returned in MC (having precision NDSAVE). +! The values of NDIG, MXEXP, and KACCSW are restored to the values +! NDSAVE,MXSAVE,KASAVE. +! KOVUN is nonzero if one of the routine's input arguments was overflow +! or underflow. + + USE FMVALS + IMPLICIT NONE + + REAL (KIND(1.0D0)) :: MT(-1:LUNPKZ),MC(-1:LUNPKZ),MXSAVE + INTEGER NDSAVE,KASAVE,KOVUN + + INTEGER KFSAVE,KWRNSV + + KWRNSV = KWARN + KWARN = 0 + MXEXP = MXSAVE + KFSAVE = KFLAG + KACCSW = KASAVE + CALL ZMEQ2(MT,MC,NDIG,NDSAVE) + IF (KFLAG /= -5 .AND. KFLAG /= -6) KFLAG = KFSAVE + NDIG = NDSAVE + KWARN = KWRNSV + IF (KFLAG == 1) KFLAG = 0 + IF (MC(1) == MEXPUN .OR. MC(KPTIMU+1) == MEXPUN) KFLAG = -6 + IF (MC(1) == MEXPOV .OR. MC(KPTIMU+1) == MEXPOV) KFLAG = -5 + IF (MC(1) == MUNKNO .OR. MC(KPTIMU+1) == MUNKNO) THEN + IF (KFLAG /= -9) KFLAG = -4 + ENDIF + IF ((MC(1) == MUNKNO .AND. KFLAG /= -9) .OR. & + (MC(KPTIMU+1) == MUNKNO .AND. KFLAG /= -9) .OR. & + (MC(1) == MEXPUN .AND. KOVUN == 0) .OR. & + (MC(KPTIMU+1) == MEXPUN .AND. KOVUN == 0) .OR. & + (MC(1) == MEXPOV .AND. KOVUN == 0) .OR. & + (MC(KPTIMU+1) == MEXPOV .AND. KOVUN == 0)) CALL ZMWARN + IF (NTRACE /= 0) CALL ZMNTR(1,MC,MC,1) + NCALL = NCALL - 1 + RETURN + END SUBROUTINE ZMEXIT + + SUBROUTINE ZMEXI2(MXFM,NDSAVE,MXSAVE,KASAVE,KOVUN) + +! This routine is used upon exit for complex functions that +! return real FM results. + + USE FMVALS + IMPLICIT NONE + + REAL (KIND(1.0D0)) :: MXFM(-1:LUNPCK),MXSAVE + INTEGER NDSAVE,KASAVE,KOVUN + + INTEGER KFSAVE,KWRNSV + + KWRNSV = KWARN + KWARN = 0 + MXEXP = MXSAVE + KFSAVE = KFLAG + KACCSW = KASAVE + CALL FMEQ2_R1(MXFM,NDIG,NDSAVE) + IF (KFLAG /= -5 .AND. KFLAG /= -6) KFLAG = KFSAVE + NDIG = NDSAVE + KWARN = KWRNSV + IF (KFLAG == 1) KFLAG = 0 + IF (MXFM(1) == MUNKNO) THEN + IF (KFLAG >= 0) KFLAG = -4 + ELSE IF (MXFM(1) == MEXPOV) THEN + KFLAG = -5 + ELSE IF (MXFM(1) == MEXPUN) THEN + KFLAG = -6 + ENDIF + IF ((MXFM(1) == MUNKNO .AND. KFLAG /= -9) & + .OR. (MXFM(1) == MEXPUN .AND. KOVUN == 0) & + .OR. (MXFM(1) == MEXPOV .AND. KOVUN == 0)) CALL ZMWARN + IF (NTRACE /= 0) CALL ZMNTR2(1,MXFM,MXFM,1) + NCALL = NCALL - 1 + RETURN + END SUBROUTINE ZMEXI2 + + SUBROUTINE ZMEXP(MA,MB) + +! MB = EXP(MA). + + USE FMVALS + IMPLICIT NONE + + REAL (KIND(1.0D0)) :: MA(-1:LUNPKZ),MB(-1:LUNPKZ) + REAL (KIND(1.0D0)) :: MACCMB,MAIZ,MARZ,MXSAVE + INTEGER KASAVE,KOVUN,KRESLT,KRSAVE,KWRNSV,NDSAVE + + CALL ZMENTR('ZMEXP ',MA,MA,1,MB,KRESLT,NDSAVE,MXSAVE,KASAVE, & + KOVUN) + IF (KRESLT /= 0) RETURN + MARZ = MA(0) + MAIZ = MA(KPTIMU) + KACCSW = 0 + KRSAVE = KRAD + KRAD = 1 + + CALL ZMEQU(MA,MZ05,NDSAVE,NDIG) + +! Check for special cases. + + IF (MA(2) == 0 .AND. MA(KPTIMU+2) == 0) THEN + CALL ZMI2M(1,MZ01) + GO TO 110 + ELSE IF (MA(2) == 0) THEN + CALL FMI2M(1,M06) + ELSE + CALL FMEXP(MZ05,M06) + ENDIF + + CALL FMCSSN(MZ05(KPTIMU-1),MZ01,MZ01(KPTIMU-1)) + + KWRNSV = KWARN + KWARN = 0 + CALL FMMPYD(M06,MZ01,MZ01(KPTIMU-1),MZ05,MZ05(KPTIMU-1)) + CALL ZMEQ(MZ05,MZ01) + KWARN = KWRNSV + + 110 MACCMB = MZ01(0) + MZ01(0) = MIN(MACCMB,MARZ,MAIZ) + MACCMB = MZ01(KPTIMU) + MZ01(KPTIMU) = MIN(MACCMB,MARZ,MAIZ) + CALL ZMEXIT(MZ01,MB,NDSAVE,MXSAVE,KASAVE,KOVUN) + KRAD = KRSAVE + RETURN + END SUBROUTINE ZMEXP + + SUBROUTINE ZMFORM(FORM1,FORM2,MA,STRING) + +! Convert MA to STRING using FORM1 format for the real part and +! FORM2 format for the imaginary part. + + USE FMVALS + IMPLICIT NONE + + CHARACTER(*) :: FORM1,FORM2,STRING + REAL (KIND(1.0D0)) :: MA(-1:LUNPKZ) + + INTEGER J,KWIDIM,KWIDRE,LAST,LSIGN + + NCALL = NCALL + 1 + NAMEST(NCALL) = 'ZMFORM' + STRING = ' ' + CALL ZMFPCM(FORM1,MA,KWIDRE,CMBUFZ) + CALL FMEQ(MA(KPTIMU-1),M02) + IF (M02(-1) > 0) THEN + LSIGN = 1 + ELSE + LSIGN = -1 + IF (M02(1) /= MUNKNO .AND. M02(2) /= 0) M02(-1) = -M02(-1) + ENDIF + CALL ZMFPCM(FORM2,M02,KWIDIM,CMBUFF) + + CMBUFZ(KWIDRE+1) = ' ' + IF (LSIGN == 1) THEN + CMBUFZ(KWIDRE+2) = '+' + ELSE + CMBUFZ(KWIDRE+2) = '-' + ENDIF + CMBUFZ(KWIDRE+3) = ' ' + DO J = 1, KWIDIM + CMBUFZ(KWIDRE+3+J) = CMBUFF(J) + ENDDO + CMBUFZ(KWIDRE+4+KWIDIM) = ' ' + CMBUFZ(KWIDRE+5+KWIDIM) = 'i' + IF (JFORMZ == 2) CMBUFZ(KWIDRE+5+KWIDIM) = 'I' + LAST = KWIDRE + KWIDIM + 5 + + IF (M02(1) == MEXPOV .OR. M02(1) == MEXPUN) THEN + DO J = KWIDRE+3, LAST + IF (CMBUFZ(J) == 'O' .OR. CMBUFZ(J) == 'U') THEN + CMBUFZ(J-2) = ' ' + EXIT + ENDIF + ENDDO + ENDIF + + IF (LAST <= LEN(STRING)) THEN + DO J = 1, LAST + STRING(J:J) = CMBUFZ(J) + ENDDO + ELSE + DO J = 1, LAST + STRING(J:J) = '*' + ENDDO + ENDIF + NCALL = NCALL - 1 + RETURN + END SUBROUTINE ZMFORM + + SUBROUTINE ZMFPCM(FORM,MA,KWI,CMB) + +! Internal routine to convert MA to base 10 using FORM format. +! The result is returned in CMB and the field width is KWI. + + USE FMVALS + IMPLICIT NONE + + CHARACTER(*) :: FORM + REAL (KIND(1.0D0)) :: MA(-1:LUNPCK) + INTEGER KWI + CHARACTER CMB(LMBUFF) + CHARACTER(20) :: FORMB + INTEGER J,JF1SAV,JF2SAV,JPT,K1,K2,K3,KD,KWD,KSAVE,LAST,LB, & + LENGFM,LFIRST,ND,NEXP + + KSAVE = KFLAG + JF1SAV = JFORM1 + JF2SAV = JFORM2 + LENGFM = LEN(FORM) + KWI = 75 + KWD = 40 + IF (INDEX(FORM,'I') > 0 .OR. INDEX(FORM,'i') > 0) THEN + K1 = MAX(INDEX(FORM,'I'),INDEX(FORM,'i')) + 1 + K2 = LENGFM + WRITE (FORMB,"('(I',I5,')')") K2-K1+1 + IF (K2 >= K1) THEN + READ (FORM(K1:K2),FORMB) KWI + ELSE + KWI = 50 + ENDIF + KWI = MAX(1,MIN(KWI,LMBUFF-11)) + JFORM1 = 2 + JFORM2 = 0 + KWD = KWI + 11 + CALL FMNINT(MA,M03) + IF (M03(2) /= 0) THEN + CALL FMOUT(M03,CMB,KWD) + ELSE + DO J = 1, KWD + CMB(J) = ' ' + ENDDO + CMB(2) = '0' + ENDIF + LFIRST = 1 + LAST = 1 + DO J = 1, KWD + IF (CMB(KWD+1-J) /= ' ') LFIRST = KWD+1-J + IF (CMB(J) /= ' ') LAST = J + ENDDO + JPT = 1 + IF (LAST-LFIRST+1 > KWI) GO TO 110 + IF (LAST <= KWI) THEN + DO J = LAST, LFIRST, -1 + JPT = KWI - LAST + J + CMB(JPT) = CMB(J) + ENDDO + DO J = 1, JPT-1 + CMB(J) = ' ' + ENDDO + ELSE + DO J = LFIRST, LAST + JPT = KWI - LAST + J + CMB(JPT) = CMB(J) + ENDDO + ENDIF + ELSE IF (INDEX(FORM,'F') > 0 .OR. INDEX(FORM,'f') > 0) THEN + K1 = MAX(INDEX(FORM,'F'),INDEX(FORM,'f')) + 1 + K2 = INDEX(FORM(1:LENGFM),'.') + K3 = LENGFM + IF (K2 > K1) THEN + WRITE (FORMB,"('(I',I5,')')") K2-K1 + READ (FORM(K1:K2-1),FORMB) KWI + ELSE + KWI = 50 + ENDIF + IF (K3 > K2) THEN + WRITE (FORMB,"('(I',I5,')')") K3-K2 + READ (FORM(K2+1:K3),FORMB) KD + ELSE + KD = 0 + ENDIF + KWI = MAX(1,MIN(KWI,LMBUFF)) + KD = MAX(0,MIN(KD,KWI-2)) + JFORM1 = 2 + JFORM2 = KD + ND = INT(REAL(NDIG)*LOG10(REAL(MBASE))) + 1 + IF (ND < 2) ND = 2 + NEXP = INT(2.0*LOG10(REAL(MXBASE))) + 6 + LB = MAX(JFORM2+NEXP,ND+NEXP) + LB = MIN(LB,LMBUFF) + KWD = LB + CALL FMOUT(MA,CMB,KWD) + LFIRST = 1 + LAST = 1 + DO J = 1, KWD + IF (CMB(KWD+1-J) /= ' ') LFIRST = KWD+1-J + IF (CMB(J) /= ' ') LAST = J + ENDDO + IF (LAST-LFIRST+1 > KWI) THEN + +! Not enough room for this F format, or FMOUT converted +! it to E format to avoid showing no significant digits. +! See if a shortened form will fit in E format. + + NEXP = INT(LOG10((ABS(MA(1))+1)*LOG10(DBLE(MBASE))+1)+1) + ND = KWI - NEXP - 5 + IF (ND < 1) THEN + GO TO 110 + ELSE + JFORM1 = 0 + JFORM2 = ND + CALL FMOUT(MA,CMB,KWI) + LFIRST = 1 + LAST = 1 + DO J = 1, KWI + IF (CMB(KWI+1-J) /= ' ') LFIRST = KWI+1-J + IF (CMB(J) /= ' ') LAST = J + ENDDO + ENDIF + ENDIF + JPT = 1 + IF (LAST <= KWI) THEN + DO J = LAST, LFIRST, -1 + JPT = KWI - LAST + J + CMB(JPT) = CMB(J) + ENDDO + DO J = 1, JPT-1 + CMB(J) = ' ' + ENDDO + ELSE + DO J = LFIRST, LAST + JPT = KWI - LAST + J + CMB(JPT) = CMB(J) + ENDDO + ENDIF + ELSE IF (INDEX(FORM,'1PE') > 0 .OR. INDEX(FORM,'1pe') > 0) THEN + K1 = MAX(INDEX(FORM,'E'),INDEX(FORM,'e')) + 1 + K2 = INDEX(FORM(1:LENGFM),'.') + K3 = LENGFM + IF (K2 > K1) THEN + WRITE (FORMB,"('(I',I5,')')") K2-K1 + READ (FORM(K1:K2-1),FORMB) KWI + ELSE + KWI = 50 + ENDIF + IF (K3 > K2) THEN + WRITE (FORMB,"('(I',I5,')')") K3-K2 + READ (FORM(K2+1:K3),FORMB) KD + ELSE + KD = 0 + ENDIF + KWI = MAX(1,MIN(KWI,LMBUFF)) + KD = MAX(0,MIN(KD,KWI-2)) + JFORM1 = 1 + JFORM2 = KD + CALL FMOUT(MA,CMB,KWI) + ELSE IF (INDEX(FORM,'E') > 0 .OR. INDEX(FORM,'e') > 0) THEN + K1 = MAX(INDEX(FORM,'E'),INDEX(FORM,'e')) + 1 + K2 = INDEX(FORM(1:LENGFM),'.') + K3 = LENGFM + IF (K2 > K1) THEN + WRITE (FORMB,"('(I',I5,')')") K2-K1 + READ (FORM(K1:K2-1),FORMB) KWI + ELSE + KWI = 50 + ENDIF + IF (K3 > K2) THEN + WRITE (FORMB,"('(I',I5,')')") K3-K2 + READ (FORM(K2+1:K3),FORMB) KD + ELSE + KD = 0 + ENDIF + KWI = MAX(1,MIN(KWI,LMBUFF)) + KD = MAX(0,MIN(KD,KWI-2)) + JFORM1 = 0 + JFORM2 = KD + CALL FMOUT(MA,CMB,KWI) + ELSE + GO TO 110 + ENDIF + + JFORM1 = JF1SAV + JFORM2 = JF2SAV + KFLAG = KSAVE + RETURN + +! Error condition. + + 110 KFLAG = -8 + DO J = 1, KWI + CMB(J) = '*' + ENDDO + JFORM1 = JF1SAV + JFORM2 = JF2SAV + KFLAG = KSAVE + RETURN + END SUBROUTINE ZMFPCM + + SUBROUTINE ZMFPRT(FORM1,FORM2,MA) + +! Print MA in base 10 using FORM1 format for the real part and +! FORM2 format for the imaginary part. + + USE FMVALS + IMPLICIT NONE + + CHARACTER(*) :: FORM1,FORM2 + REAL (KIND(1.0D0)) :: MA(-1:LUNPKZ) + + CHARACTER(20) :: FORM + INTEGER J,K,KWIDIM,KWIDRE,LAST,LSIGN + + NCALL = NCALL + 1 + NAMEST(NCALL) = 'ZMFPRT' + + CALL ZMFPCM(FORM1,MA,KWIDRE,CMBUFZ) + CALL FMEQ(MA(KPTIMU-1),M02) + IF (M02(-1) >= 0) THEN + LSIGN = 1 + ELSE + LSIGN = -1 + IF (M02(1) /= MUNKNO .AND. M02(2) /= 0) M02(-1) = -M02(-1) + ENDIF + CALL ZMFPCM(FORM2,M02,KWIDIM,CMBUFF) + + CMBUFZ(KWIDRE+1) = ' ' + IF (LSIGN == 1) THEN + CMBUFZ(KWIDRE+2) = '+' + ELSE + CMBUFZ(KWIDRE+2) = '-' + ENDIF + CMBUFZ(KWIDRE+3) = ' ' + DO J = 1, KWIDIM + CMBUFZ(KWIDRE+3+J) = CMBUFF(J) + ENDDO + CMBUFZ(KWIDRE+4+KWIDIM) = ' ' + CMBUFZ(KWIDRE+5+KWIDIM) = 'i' + IF (JFORMZ == 2) CMBUFZ(KWIDRE+5+KWIDIM) = 'I' + LAST = KWIDRE + KWIDIM + 5 + + IF (M02(1) == MEXPOV .OR. M02(1) == MEXPUN) THEN + DO J = KWIDRE+3, LAST + IF (CMBUFZ(J) == 'O' .OR. CMBUFZ(J) == 'U') THEN + CMBUFZ(J-2) = ' ' + EXIT + ENDIF + ENDDO + ENDIF + + WRITE (FORM,"(' (6X,',I3,'A1) ')") KSWIDE-7 + WRITE (KW,FORM) (CMBUFZ(K),K=1,LAST) + NCALL = NCALL - 1 + RETURN + END SUBROUTINE ZMFPRT + + SUBROUTINE ZMI2M(INTEG,MA) + +! MA = INTEG + +! The real part of MA is set to the one word integer value INTEG. +! The imaginary part is set to zero. + + USE FMVALS + IMPLICIT NONE + + INTEGER INTEG + REAL (KIND(1.0D0)) :: MA(-1:LUNPKZ) + + NCALL = NCALL + 1 + NAMEST(NCALL) = 'ZMI2M ' + IF (NTRACE /= 0) CALL ZMNTRI(2,INTEG,1) + + CALL FMI2M(INTEG,MA) + CALL FMI2M(0,MA(KPTIMU-1)) + + IF (NTRACE /= 0) CALL ZMNTR(1,MA,MA,1) + NCALL = NCALL - 1 + RETURN + END SUBROUTINE ZMI2M + + SUBROUTINE ZM2I2M(INTEG1,INTEG2,MA) + +! MA = INTEG1 + INTEG2 i + + USE FMVALS + IMPLICIT NONE + + INTEGER INTEG1,INTEG2 + REAL (KIND(1.0D0)) :: MA(-1:LUNPKZ) + + NCALL = NCALL + 1 + NAMEST(NCALL) = 'ZM2I2M' + IF (NTRACE /= 0) THEN + CALL ZMNTRI(2,INTEG1,1) + CALL ZMNTRI(2,INTEG2,0) + ENDIF + + CALL FMI2M(INTEG1,MA) + CALL FMI2M(INTEG2,MA(KPTIMU-1)) + + IF (NTRACE /= 0) CALL ZMNTR(1,MA,MA,1) + NCALL = NCALL - 1 + RETURN + END SUBROUTINE ZM2I2M + + SUBROUTINE ZMIMAG(MA,MBFM) + +! MBFM = IMAG(MA) imaginary part of MA + +! MA is a complex ZM number, MBFM is a real FM number. + + USE FMVALS + IMPLICIT NONE + + REAL (KIND(1.0D0)) :: MA(-1:LUNPKZ),MBFM(-1:LUNPCK) + + KFLAG = 0 + NCALL = NCALL + 1 + NAMEST(NCALL) = 'ZMIMAG' + IF (NTRACE /= 0) CALL ZMNTR(2,MA,MA,1) + + CALL FMEQ(MA(KPTIMU-1),MBFM) + + IF (NTRACE /= 0) CALL FMNTR(1,MBFM,MBFM,1,1) + NCALL = NCALL - 1 + RETURN + END SUBROUTINE ZMIMAG + + SUBROUTINE ZMINP(LINE,MA,LA,LB) + +! Convert an A1 character string to floating point multiple precision +! complex format. + +! LINE is an A1 character array of length LB to be converted +! to ZM format and returned in MA. +! LA is a pointer telling the routine where in the array to begin +! the conversion. This allows more than one number to be stored +! in an array and converted in place. +! LB is a pointer to the last character of the field for that number. + +! The input numbers may be in integer or any real format. +! In exponential format the 'E' may also be 'D', 'Q', or 'M'. + +! The following are all valid input strings: + +! 1.23 + 4.56 I +! 1.23 + 4.56*I +! 2 + i +! -i +! 1.23 +! 4.56i +! ( 1.23 , 4.56 ) + +! So that ZMINP will convert any output from ZMOUT, LINE is tested +! to see if the input contains any of the special symbols +OVERFLOW, +! -OVERFLOW, +UNDERFLOW, -UNDERFLOW, or UNKNOWN. +! For user input the abbreviations OVFL, UNFL, UNKN may be used. + + USE FMVALS + IMPLICIT NONE + + INTEGER LA,LB + CHARACTER LINE(LB) + REAL (KIND(1.0D0)) :: MA(-1:LUNPKZ) + INTEGER J,JSTATE,K,KASAVE,KDIGFL,KFLAG1,KIFLAG,KPT, & + KRSAVE,KSIGN,KSTART,KSTOP,KSTOPI,KSTOPR,KSTRTI,KSTRTR, & + KTYPE,KVAL,NDSAVE,NTRSAV + +! Simulate a finite-state automaton to scan the input line +! and build the number. States 2-8 refer to the real part, +! states 10-16 refer to the imaginary part. +! States of the machine: + +! 1. Initial entry to the subroutine +! 2. Sign of the number +! 3. Scanning digits before a decimal point +! 4. Decimal point +! 5. Scanning digits after a decimal point +! 6. E, D, Q, or M - precision indicator before the exponent +! 7. Sign of the exponent +! 8. Scanning exponent +! 9. Comma between the real and imaginary part +! 10. Sign of the number +! 11. Scanning digits before a decimal point +! 12. Decimal point +! 13. Scanning digits after a decimal point +! 14. E, D, Q, or M - precision indicator before the exponent +! 15. Sign of the exponent +! 16. Scanning exponent +! 17. Syntax error + +! Character types recognized by the machine: + +! 1. Sign (+,-) +! 2. Numeral (0,1,...,9) +! 3. Decimal point (.) +! 4. Precision indicator (E,D,Q,M) +! 5. Illegal character for number +! 6. Comma (,) +! 7. Character to be ignored ' ' '(' ')' '*' + +! All blanks are ignored. The analysis of the number proceeds as +! follows: If the simulated machine is in state JSTATE and a character +! of type JTYPE is encountered the new state of the machine is given by +! JTRANS(JSTATE,JTYPE). + +! State 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 + + INTEGER :: JTRANS(16,4) = RESHAPE( (/ & + 2, 17, 10, 10, 10, 7, 17, 10, 10, 17, 17, 17, 17, 15, 17, 17, & + 3, 3, 3, 5, 5, 8, 8, 8, 11, 11, 11, 13, 13, 16, 16, 16, & + 4, 4, 4, 17, 17, 17, 17, 17, 12, 12, 12, 17, 17, 17, 17, 17, & + 6, 6, 6, 6, 6, 8, 17, 17, 14, 14, 14, 14, 14, 16, 17, 17 /) & + , (/ 16,4 /) ) + + IF (MBLOGS /= MBASE) CALL FMCONS + NCALL = NCALL + 1 + NAMEST(NCALL) = 'ZMINP ' + NDSAVE = NDIG + KASAVE = KACCSW + KRSAVE = KROUND + KROUND = 1 + KFLAG = 0 + +! Initialize two hash tables that are used for character +! look-up during input conversion. + + IF (LHASH == 0) CALL FMHTBL + +! Since arithmetic tracing is not usually desired during +! I/O conversion, disable tracing during this routine. + + NTRSAV = NTRACE + NTRACE = 0 + +! Increase the working precision. + + IF (NCALL <= 2) THEN + K = NGRD52 + NDIG = MAX(NDIG+K,2) + IF (NDIG > NDG2MX) THEN + KFLAG = -9 + CALL ZMWARN + MA(-1) = 1 + MA(0) = NINT(NDSAVE*ALOGM2) + MA(1) = MUNKNO + MA(2) = 1 + MA(KPTIMU-1) = 1 + MA(KPTIMU) = NINT(NDSAVE*ALOGM2) + MA(KPTIMU+1) = MUNKNO + MA(KPTIMU+2) = 1 + DO J = 2, NDSAVE + MA(J+1) = 0 + MA(KPTIMU+J+1) = 0 + ENDDO + GO TO 110 + ENDIF + ENDIF + KSTART = LA + KSTOP = LB + JSTATE = 1 + KSTRTR = 0 + KSTOPR = 0 + KSTRTI = 0 + KSTOPI = 0 + KDIGFL = 0 + KIFLAG = 0 + KSIGN = 1 + +! Scan the number. + + DO J = KSTART, KSTOP + IF (LINE(J) == ' ' .OR. LINE(J) == '(' .OR. LINE(J) == ')' & + .OR. LINE(J) == '*') CYCLE + IF (LINE(J) == 'I' .OR. LINE(J) == 'i') THEN + KIFLAG = 1 + IF (KSTRTI == 0) THEN + KSTRTI = KSTRTR + KSTOPI = KSTOPR + KSTRTR = 0 + KSTOPR = 0 + ENDIF + CYCLE + ENDIF + + KPT = ICHAR(LINE(J)) + IF (KPT < LHASH1 .OR. KPT > LHASH2) THEN + WRITE (KW, & + "(/' Error in input conversion.'/" // & + "' ICHAR function was out of range for the current'," // & + "' dimensions.'/' ICHAR(''',A,''') gave the value '," // & + "I12,', which is outside the currently'/' dimensioned'," // & + "' bounds of (',I5,':',I5,') for variables KHASHT '," // & + "'and KHASHV.'/' Re-define the two parameters '," // & + "'LHASH1 and LHASH2 so the dimensions will'/' contain'," // & + "' all possible output values from ICHAR.'//)" & + ) LINE(J),KPT,LHASH1,LHASH2 + KTYPE = 5 + KVAL = 0 + ELSE + KTYPE = KHASHT(KPT) + KVAL = KHASHV(KPT) + ENDIF + IF (KTYPE == 2 .OR. KTYPE == 5) KDIGFL = 1 + IF (LINE(J) == ',') THEN + IF (JSTATE < 9) THEN + JSTATE = 9 + ELSE + GO TO 120 + ENDIF + ELSE + IF (KTYPE >= 5) KTYPE = 2 + IF (JSTATE < 17) JSTATE = JTRANS(JSTATE,KTYPE) + ENDIF + IF (JSTATE == 9 .OR. JSTATE == 10) KDIGFL = 0 + IF (JSTATE == 2 .OR. JSTATE == 10) KSIGN = KVAL + + IF (JSTATE >= 2 .AND. JSTATE <= 8) THEN + IF (KSTRTR == 0) KSTRTR = J + KSTOPR = J + ENDIF + IF (JSTATE >= 10 .AND. JSTATE <= 16) THEN + IF (KSTRTI == 0) KSTRTI = J + KSTOPI = J + ENDIF + + ENDDO + +! Form the number and return. + + IF (KSTRTR > 0) THEN + CALL FMINP(LINE,MA,KSTRTR,KSTOPR) + ELSE + CALL FMIM(0,MA) + ENDIF + KFLAG1 = KFLAG + + IF (KSTRTI > 0) THEN + IF (KIFLAG == 1 .AND. KDIGFL == 0) THEN + CALL FMIM(KSIGN,MA(KPTIMU-1)) + ELSE + CALL FMINP(LINE,MA(KPTIMU-1),KSTRTI,KSTOPI) + ENDIF + ELSE IF (KIFLAG == 1) THEN + CALL FMIM(1,MA(KPTIMU-1)) + ELSE + CALL FMIM(0,MA(KPTIMU-1)) + ENDIF + + IF (KFLAG1 /= 0 .OR. KFLAG /= 0 .OR. JSTATE == 17) GO TO 120 + + 110 NDIG = NDSAVE + KACCSW = KASAVE + NTRACE = NTRSAV + KROUND = KRSAVE + IF (KFLAG == 1) KFLAG = 0 + MA(0) = NINT(NDIG*ALOGM2) + MA(KPTIMU) = MA(0) + NCALL = NCALL - 1 + RETURN + +! Error in converting the number. + + 120 KFLAG = -7 + CALL ZMWARN + MA(-1) = 1 + MA(0) = NINT(NDIG*ALOGM2) + MA(1) = MUNKNO + MA(2) = 1 + MA(KPTIMU-1) = 1 + MA(KPTIMU) = NINT(NDIG*ALOGM2) + MA(KPTIMU+1) = MUNKNO + MA(KPTIMU+2) = 1 + DO J = 2, NDSAVE + MA(J+1) = 0 + MA(KPTIMU+J+1) = 0 + ENDDO + GO TO 110 + END SUBROUTINE ZMINP + + SUBROUTINE ZMINT(MA,MB) + +! MB = INT(MA) + +! The integer parts of both real and imaginary values are returned. + + USE FMVALS + IMPLICIT NONE + + REAL (KIND(1.0D0)) :: MA(-1:LUNPKZ),MB(-1:LUNPKZ) + + NCALL = NCALL + 1 + NAMEST(NCALL) = 'ZMINT ' + IF (NTRACE /= 0) CALL ZMNTR(2,MA,MA,1) + + CALL FMINT(MA,MB) + CALL FMINT(MA(KPTIMU-1),MB(KPTIMU-1)) + + IF (NTRACE /= 0) CALL ZMNTR(1,MB,MB,1) + NCALL = NCALL - 1 + RETURN + END SUBROUTINE ZMINT + + SUBROUTINE ZMIPWR(MA,IVAL,MB) + +! MB = MA ** IVAL + +! Raise a ZM number to an integer power. +! The binary multiplication method used requires an average of +! 1.5 * LOG2(IVAL) multiplications. + + USE FMVALS + IMPLICIT NONE + + INTEGER IVAL + REAL (KIND(1.0D0)) :: MA(-1:LUNPKZ),MB(-1:LUNPKZ) + REAL (KIND(1.0D0)) :: MA2,MACCMB,MAIZ,MARZ,MXSAVE + INTEGER I2N,K,KASAVE,KOVUN,KWRNSV,LVLSAV,NDSAVE + REAL XVAL + + NCALL = NCALL + 1 + NAMEST(NCALL) = 'ZMIPWR' + NDSAVE = NDIG + IF (NTRACE /= 0) THEN + CALL ZMNTR(2,MA,MA,1) + CALL FMNTRI(2,IVAL,0) + ENDIF + KOVUN = 0 + MARZ = MA(0) + MAIZ = MA(KPTIMU) + IF (MA(1) == MEXPOV .OR. MA(1) == MEXPUN .OR. & + MA(KPTIMU+1) == MEXPOV .OR. MA(KPTIMU+1) == MEXPUN) KOVUN = 1 + + IF (MBLOGS /= MBASE) CALL FMCONS + KFLAG = 0 + KASAVE = KACCSW + MXSAVE = MXEXP + MXEXP = MXEXP2 + +! Check for special cases. + + IF (MA(1) == MUNKNO .OR. MA(KPTIMU+1) == MUNKNO .OR. & + (IVAL <= 0 .AND. MA(2) == 0 .AND. MA(KPTIMU+2) == 0)) THEN + MA2 = MA(2) + KFLAG = -4 + IF (IVAL <= 0 .AND. MA2 == 0) CALL ZMWARN + CALL ZMST2M('UNKNOWN+UNKNOWN*i',MB) + IF (NTRACE /= 0) CALL ZMNTR(1,MB,MB,1) + NCALL = NCALL - 1 + MXEXP = MXSAVE + RETURN + ENDIF + + IF (IVAL == 0) THEN + CALL ZMI2M(1,MB) + IF (NTRACE /= 0) CALL ZMNTR(1,MB,MB,1) + NCALL = NCALL - 1 + MXEXP = MXSAVE + RETURN + ENDIF + + IF (ABS(IVAL) == 1) THEN + KWRNSV = KWARN + KWARN = 0 + IF (IVAL == 1) THEN + CALL ZMEQ(MA,MB) + ELSE + K = INT((5.0D0*DLOGTN)/DLOGMB + 2.0D0) + NDIG = MIN(MAX(NDIG+K,2),NDG2MX) + IF (MBASE < 1000 .OR. KROUND /= 1 .OR. KRPERF == 1) THEN + IF (NCALL == 1) NDIG = MIN(NDG2MX,MAX(NDIG,2*NDSAVE+10)) + ENDIF + CALL ZMI2M(1,MZ02) + CALL ZMEQU(MA,MZ05,NDSAVE,NDIG) + CALL ZMDIV(MZ02,MZ05,MB) + CALL ZMEQ2_R1(MB,NDIG,NDSAVE) + NDIG = NDSAVE + ENDIF + IF (NTRACE /= 0) CALL ZMNTR(1,MB,MB,1) + NCALL = NCALL - 1 + KWARN = KWRNSV + MXEXP = MXSAVE + RETURN + ENDIF + + IF (MA(2) == 0 .AND. MA(KPTIMU+2) == 0) THEN + CALL ZMI2M(0,MB) + IF (NTRACE /= 0) CALL ZMNTR(1,MB,MB,1) + NCALL = NCALL - 1 + MXEXP = MXSAVE + RETURN + ENDIF + + IF (MA(KPTIMU+2) == 0) THEN + NCALL = NCALL - 1 + LVLSAV = LVLTRC + LVLTRC = LVLTRC - 1 + CALL FMIPWR(MA,IVAL,MB) + CALL FMIM(0,MB(KPTIMU-1)) + NCALL = NCALL + 1 + LVLTRC = LVLSAV + IF (NTRACE /= 0) THEN + NAMEST(NCALL) = 'ZMIPWR' + CALL ZMNTR(1,MB,MB,1) + ENDIF + NCALL = NCALL - 1 + MXEXP = MXSAVE + RETURN + ENDIF + + IF (MA(2) == 0) THEN + NCALL = NCALL - 1 + LVLSAV = LVLTRC + LVLTRC = LVLTRC - 1 + IF (IVAL >= 0) THEN + I2N = MOD(IVAL,4) + ELSE + I2N = MOD(4 - MOD(ABS(IVAL),4),4) + ENDIF + IF (I2N == 0) THEN + CALL FMIPWR(MA(KPTIMU-1),IVAL,MB) + CALL FMIM(0,MB(KPTIMU-1)) + ELSE IF (I2N == 1) THEN + CALL FMIPWR(MA(KPTIMU-1),IVAL,MB(KPTIMU-1)) + CALL FMIM(0,MB) + ELSE IF (I2N == 2) THEN + CALL FMIPWR(MA(KPTIMU-1),IVAL,MB) + CALL FMIM(0,MB(KPTIMU-1)) + IF (MB(1) /= MUNKNO .AND. MB(2) /= 0) MB(-1) = -MB(-1) + ELSE IF (I2N == 3) THEN + CALL FMIPWR(MA(KPTIMU-1),IVAL,MB(KPTIMU-1)) + CALL FMIM(0,MB) + IF (MB(KPTIMU+1) /= MUNKNO .AND. MB(KPTIMU+2) /= 0) & + MB(KPTIMU-1) = -MB(KPTIMU-1) + ENDIF + NCALL = NCALL + 1 + LVLTRC = LVLSAV + IF (NTRACE /= 0) THEN + NAMEST(NCALL) = 'ZMIPWR' + CALL ZMNTR(1,MB,MB,1) + ENDIF + NCALL = NCALL - 1 + MXEXP = MXSAVE + RETURN + ENDIF + +! Increase the working precision. + + IF (NCALL == 1) THEN + XVAL = ABS(IVAL) + 1 + K = INT((5.0*REAL(DLOGTN) + 1.5*LOG(XVAL))/ALOGMB + 2.0) + NDIG = MAX(NDIG+K,2) + IF (MBASE < 1000 .OR. KROUND /= 1 .OR. KRPERF == 1) THEN + NDIG = MIN(NDG2MX,MAX(NDIG,2*NDSAVE+10)) + ENDIF + ELSE + XVAL = ABS(IVAL) + 1 + K = INT(LOG(XVAL)/ALOGMB + 1.0) + NDIG = NDIG + K + ENDIF + IF (NDIG > NDG2MX) THEN + KFLAG = -9 + CALL ZMWARN + NDIG = NDSAVE + CALL ZMST2M('UNKNOWN+UNKNOWN*i',MB) + IF (NTRACE /= 0) CALL ZMNTR(1,MB,MB,1) + MXEXP = MXSAVE + KACCSW = KASAVE + NCALL = NCALL - 1 + RETURN + ENDIF + +! Initialize. + + KWRNSV = KWARN + KWARN = 0 + K = ABS(IVAL) + + CALL ZMEQ2(MA,MZ02,NDSAVE,NDIG) + + IF (MOD(K,2) == 0) THEN + CALL ZMI2M(1,MB) + ELSE + CALL ZMEQ(MZ02,MB) + ENDIF + +! This is the multiplication loop. + + 110 K = K/2 + CALL ZMSQR(MZ02,MZ08) + CALL ZMEQ(MZ08,MZ02) + IF (MOD(K,2) == 1) THEN + CALL ZMMPY(MZ02,MB,MZ08) + CALL ZMEQ(MZ08,MB) + ENDIF + IF (K > 1) GO TO 110 + +! Invert if the exponent is negative. + + IF (IVAL < 0) THEN + CALL ZMI2M(1,MZ02) + CALL ZMDIV(MZ02,MB,MZ08) + CALL ZMEQ(MZ08,MB) + ENDIF + KWARN = KWRNSV + +! Round the result and return. + + MACCMB = MB(0) + MB(0) = MIN(MACCMB,MARZ,MAIZ) + MACCMB = MB(KPTIMU) + MB(KPTIMU) = MIN(MACCMB,MARZ,MAIZ) + CALL ZMEQ(MB,MZ01) + CALL ZMEXIT(MZ01,MB,NDSAVE,MXSAVE,KASAVE,KOVUN) + RETURN + END SUBROUTINE ZMIPWR + + SUBROUTINE ZMLG10(MA,MB) + +! MB = LOG10(MA). + + USE FMVALS + IMPLICIT NONE + + REAL (KIND(1.0D0)) :: MA(-1:LUNPKZ),MB(-1:LUNPKZ) + REAL (KIND(1.0D0)) :: MACCMB,MAIZ,MARZ,MXSAVE + INTEGER KASAVE,KOVUN,KRESLT,KRSAVE,NDSAVE + + CALL ZMENTR('ZMLG10',MA,MA,1,MB,KRESLT,NDSAVE,MXSAVE,KASAVE, & + KOVUN) + IF (KRESLT /= 0) RETURN + MARZ = MA(0) + MAIZ = MA(KPTIMU) + KACCSW = 0 + KRSAVE = KRAD + KRAD = 1 + + CALL ZMEQU(MA,MZ07,NDSAVE,NDIG) + CALL ZMLN(MZ07,MZ02) + CALL FMLNI(10,M03) + CALL FMDIVD(MZ02,MZ02(KPTIMU-1),M03,MZ01,MZ01(KPTIMU-1)) + + MACCMB = MZ01(0) + MZ01(0) = MIN(MACCMB,MARZ,MAIZ) + MACCMB = MZ01(KPTIMU) + MZ01(KPTIMU) = MIN(MACCMB,MARZ,MAIZ) + CALL ZMEXIT(MZ01,MB,NDSAVE,MXSAVE,KASAVE,KOVUN) + KRAD = KRSAVE + RETURN + END SUBROUTINE ZMLG10 + + SUBROUTINE ZMLN(MA,MB) + +! MB = LN(MA). + + USE FMVALS + IMPLICIT NONE + + REAL (KIND(1.0D0)) :: MA(-1:LUNPKZ),MB(-1:LUNPKZ) + REAL (KIND(1.0D0)) :: MACCMB,MAIZ,MARZ,MXSAVE + INTEGER KASAVE,KF1,KOVUN,KRESLT,KRSAVE,NDSAVE + LOGICAL FMCOMP + + CALL ZMENTR('ZMLN ',MA,MA,1,MB,KRESLT,NDSAVE,MXSAVE,KASAVE, & + KOVUN) + IF (KRESLT /= 0) RETURN + MARZ = MA(0) + MAIZ = MA(KPTIMU) + KACCSW = 0 + KRSAVE = KRAD + KRAD = 1 + + CALL ZMEQU(MA,MZ06,NDSAVE,NDIG) + +! Check for special cases. + + IF (MA(2) == 0 .AND. MA(KPTIMU+2) == 0) THEN + KFLAG = -4 + CALL ZMST2M('UNKNOWN+UNKNOWN*i',MZ01) + GO TO 110 + ELSE IF (MA(KPTIMU+2) == 0) THEN + IF (MA(-1) < 0) THEN + CALL FMEQ(MZ06,MZ01) + IF (MZ01(1) /= MUNKNO .AND. MZ01(2) /= 0) MZ01(-1) = -MZ01(-1) + CALL FMLN(MZ01,M13) + CALL FMEQ(M13,MZ01) + CALL FMPI(MZ01(KPTIMU-1)) + ELSE + CALL FMLN(MZ06,MZ01) + CALL FMI2M(0,MZ01(KPTIMU-1)) + ENDIF + GO TO 110 + ELSE IF (MA(2) == 0) THEN + IF (MA(KPTIMU-1) < 0) THEN + CALL FMEQ(MZ06(KPTIMU-1),MZ01) + IF (MZ01(1) /= MUNKNO .AND. MZ01(2) /= 0) MZ01(-1) = -MZ01(-1) + CALL FMLN(MZ01,M13) + CALL FMEQ(M13,MZ01) + CALL FMPI(MZ01(KPTIMU-1)) + CALL FMDIVI_R1(MZ01(KPTIMU-1),-2) + ELSE + CALL FMLN(MZ06(KPTIMU-1),MZ01) + CALL FMPI(MZ01(KPTIMU-1)) + CALL FMDIVI_R1(MZ01(KPTIMU-1),2) + ENDIF + GO TO 110 + ENDIF + +! Ln(a + b i) = Ln(Abs(a + b i)) + Arg(a + b i) i. + + CALL FMABS(MZ06,M03) + CALL FMABS(MZ06(KPTIMU-1),M04) + +! Check for cancellation in Ln(x). + + CALL FMI2M(1,M05) + KF1 = 0 + IF (FMCOMP(M03,'EQ',M05) .AND. M04(1) <= (-NDIG)) KF1 = 1 + IF (FMCOMP(M04,'EQ',M05) .AND. M03(1) <= (-NDIG)) KF1 = 1 + + IF (FMCOMP(M03,'GE',M04)) THEN + CALL FMSUB(MZ06,M05,M03) + CALL FMADD(MZ06,M05,M04) + CALL FMMPY_R1(M03,M04) + CALL FMSQR(MZ06(KPTIMU-1),M04) + CALL FMADD_R2(M03,M04) + ELSE + CALL FMSUB(MZ06(KPTIMU-1),M05,M03) + CALL FMADD(MZ06(KPTIMU-1),M05,M04) + CALL FMMPY_R1(M03,M04) + CALL FMSQR(MZ06,M04) + CALL FMADD_R2(M03,M04) + ENDIF + CALL ZMABS(MZ06,MZ01) + CALL FMADD(MZ01,M05,M03) + CALL FMDIV_R2(M04,M03) + IF (KF1 == 1) THEN + CALL FMEQ(M03,MZ01) + CALL FMATN2(MZ06(KPTIMU-1),MZ06,MZ01(KPTIMU-1)) + GO TO 110 + ELSE IF (M03(1) < 0) THEN + NDIG = NDIG - INT(M03(1)) + IF (NDIG > NDG2MX) THEN + NAMEST(NCALL) = 'ZMLN ' + KFLAG = -9 + CALL ZMWARN + KRESLT = 12 + NDIG = NDSAVE + CALL ZMRSLT(MB,KRESLT) + IF (NTRACE /= 0) CALL ZMNTR(1,MB,MB,1) + NCALL = NCALL - 1 + MXEXP = MXSAVE + KACCSW = KASAVE + RETURN + ENDIF + CALL ZMEQ2_R1(MZ06,NDSAVE,NDIG) + CALL ZMABS(MZ06,MZ01) + ENDIF + + CALL FMLN(MZ01,M13) + CALL FMEQ(M13,MZ01) + CALL FMATN2(MZ06(KPTIMU-1),MZ06,MZ01(KPTIMU-1)) + + 110 MACCMB = MZ01(0) + MZ01(0) = MIN(MACCMB,MARZ,MAIZ) + MACCMB = MZ01(KPTIMU) + MZ01(KPTIMU) = MIN(MACCMB,MARZ,MAIZ) + CALL ZMEXIT(MZ01,MB,NDSAVE,MXSAVE,KASAVE,KOVUN) + KRAD = KRSAVE + RETURN + END SUBROUTINE ZMLN + + SUBROUTINE ZMM2I(MA,INTEG) + +! INTEG = MA + +! INTEG is set to the integer value of the real part of MA + + USE FMVALS + IMPLICIT NONE + + REAL (KIND(1.0D0)) :: MA(-1:LUNPKZ) + INTEGER INTEG + + NCALL = NCALL + 1 + NAMEST(NCALL) = 'ZMM2I ' + IF (NTRACE /= 0) CALL ZMNTR(2,MA,MA,1) + + CALL FMM2I(MA,INTEG) + + IF (NTRACE /= 0) CALL ZMNTRI(1,INTEG,1) + NCALL = NCALL - 1 + RETURN + END SUBROUTINE ZMM2I + + SUBROUTINE ZMM2Z(MA,ZVAL) + +! ZVAL = MA + +! Complex variable ZVAL is set to MA. + + USE FMVALS + IMPLICIT NONE + + REAL (KIND(1.0D0)) :: MA(-1:LUNPKZ) + COMPLEX ZVAL + + REAL DI,DR + + NCALL = NCALL + 1 + NAMEST(NCALL) = 'ZMM2Z ' + IF (NTRACE /= 0) CALL ZMNTR(2,MA,MA,1) + + CALL FMM2SP(MA,DR) + CALL FMM2SP(MA(KPTIMU-1),DI) + ZVAL = CMPLX(DR,DI) + + IF (NTRACE /= 0) CALL ZMNTRZ(1,ZVAL,1) + NCALL = NCALL - 1 + RETURN + END SUBROUTINE ZMM2Z + + SUBROUTINE ZMMPY(MA,MB,MC) + +! MC = MA * MB + + USE FMVALS + IMPLICIT NONE + + REAL (KIND(1.0D0)) :: MA(-1:LUNPKZ),MB(-1:LUNPKZ),MC(-1:LUNPKZ) + REAL (KIND(1.0D0)) :: MACCMB,MAIZ,MARZ,MBIZ,MBRZ,MXSAVE,MZ11SV + INTEGER IEXTRA,KASAVE,KMETHD,KOVUN,KRESLT,KWRNSV,NDGSV2,NDSAVE, & + NGOAL,NTRSAV + + IF (ABS(MA(1)) > MEXPAB .OR. ABS(MA(KPTIMU+1)) > MEXPAB .OR. & + ABS(MB(1)) > MEXPAB .OR. ABS(MB(KPTIMU+1)) > MEXPAB .OR. & + KDEBUG >= 1) THEN + CALL ZMENTR('ZMMPY ',MA,MB,2,MC,KRESLT,NDSAVE,MXSAVE,KASAVE, & + KOVUN) + IF (KRESLT /= 0) RETURN + ELSE + NCALL = NCALL + 1 + IF (NTRACE /= 0) THEN + NAMEST(NCALL) = 'ZMMPY ' + CALL ZMNTR(2,MA,MB,2) + ENDIF + NDSAVE = NDIG + IF (NCALL == 1) THEN + NDIG = MAX(NDIG+NGRD52,2) + IF (NDIG > NDG2MX) THEN + NAMEST(NCALL) = 'ZMMPY ' + KFLAG = -9 + CALL ZMWARN + KRESLT = 12 + NDIG = NDSAVE + CALL ZMRSLT(MC,KRESLT) + IF (NTRACE /= 0) CALL ZMNTR(1,MC,MC,1) + NCALL = NCALL - 1 + RETURN + ENDIF + IF (MBASE >= 100*ABS(MA(2)) .OR. & + MBASE >= 100*ABS(MA(KPTIMU+2))) THEN + NDIG = MIN(NDIG+1,NDG2MX) + ELSE IF (MBASE >= 100*ABS(MB(2)) .OR. & + MBASE >= 100*ABS(MB(KPTIMU+2))) THEN + NDIG = MIN(NDIG+1,NDG2MX) + ENDIF + ENDIF + KASAVE = KACCSW + KACCSW = 1 + MXSAVE = MXEXP + MXEXP = MXEXP2 + KOVUN = 0 + ENDIF + IF (MBASE < 1000 .OR. KROUND /= 1 .OR. KRPERF == 1) THEN + IF (NCALL == 1) NDIG = MIN(NDG2MX,MAX(NDIG,2*NDSAVE+10)) + ENDIF + + MARZ = MA(0) + MBRZ = MB(0) + MAIZ = MA(KPTIMU) + MBIZ = MB(KPTIMU) + MZ11SV = -MUNKNO + NTRSAV = NTRACE + NTRACE = 0 + KWRNSV = KWARN + KWARN = 0 + + 110 CALL FMEQU(MA,M17,NDSAVE,NDIG) + CALL FMEQU(MA(KPTIMU-1),M18,NDSAVE,NDIG) + CALL FMEQU(MB,M19,NDSAVE,NDIG) + CALL FMEQU(MB(KPTIMU-1),M20,NDSAVE,NDIG) + IF (NCALL == 1) THEN + M17(0) = NINT(NDIG*ALOGM2) + M19(0) = M17(0) + M18(00) = M17(0) + M20(00) = M17(0) + ENDIF + +! Check for special cases. + + KMETHD = 1 + IF (NDIG >= 35) KMETHD = 2 + + IF (MB(KPTIMU+2) == 0) THEN + CALL FMMPYD(M19,M17,M18,MZ01,MZ01(KPTIMU-1)) + ELSE IF (MB(2) == 0) THEN + CALL FMMPYD(M20,M18,M17,MZ01,MZ01(KPTIMU-1)) + IF (MZ01(1) /= MUNKNO .AND. MZ01(2) /= 0) MZ01(-1) = -MZ01(-1) + ELSE IF (MA(KPTIMU+2) == 0) THEN + CALL FMMPYD(M17,M19,M20,MZ01,MZ01(KPTIMU-1)) + ELSE IF (MA(2) == 0) THEN + CALL FMMPYD(M18,M20,M19,MZ01,MZ01(KPTIMU-1)) + IF (MZ01(1) /= MUNKNO .AND. MZ01(2) /= 0) MZ01(-1) = -MZ01(-1) + ELSE IF (KMETHD == 1) THEN + +! Method 1 for ( a + b i ) * ( c + d i ) + +! result = a*c - b*d + ( a*d + b*c ) i + + KACCSW = 0 + CALL FMMPYD(M17,M19,M20,MZ01,MZ01(KPTIMU-1)) + CALL FMMPYD(M18,M20,M19,M01,M02) + IF (MZ01(-1)*M01(-1) < 0) THEN + KACCSW = 0 + ELSE + KACCSW = 1 + ENDIF + CALL FMSUB_R1(MZ01,M01) + IF (MZ01(KPTIMU-1)*M02(-1) < 0) THEN + KACCSW = 1 + ELSE + KACCSW = 0 + ENDIF + CALL FMADD_R1(MZ01(KPTIMU-1),M02) + KACCSW = 1 + ELSE + +! Method 2 for ( a + b i ) * ( c + d i ) + +! P = ( a + b )*( c + d ) +! result = a*c - b*d + ( P - a*c - b*d ) i + + CALL FMADD(M17,M18,M01) + CALL FMADD(M19,M20,M02) + CALL FMMPY_R1(M01,M02) + + CALL FMMPY(M17,M19,M02) + CALL FMMPY(M18,M20,M03) + + CALL FMSUB(M02,M03,MZ01) + CALL FMSUB(M01,M02,MZ01(KPTIMU-1)) + CALL FMSUB_R1(MZ01(KPTIMU-1),M03) + ENDIF + +! Check for too much cancellation. + + IF (NCALL <= 1) THEN + NGOAL = INT(REAL(NDSAVE)*ALOGM2) + 7 + ELSE + NGOAL = INT(-MXEXP2) + ENDIF + IF (MZ01(0) <= NGOAL .OR. MZ01(KPTIMU) <= NGOAL) THEN + IF (MZ11SV > -MUNKNO .AND. MZ01(0) > NGOAL .AND. & + MZ01(KPTIMU+2) == 0) GO TO 120 + IF (MZ11SV > -MUNKNO .AND. MZ01(KPTIMU) > NGOAL .AND. & + MZ01(2) == 0) GO TO 120 + IEXTRA = INT(REAL(MAX(NGOAL-MZ01(0),NGOAL-MZ01(KPTIMU))) & + /ALOGM2 + 23.03/ALOGMB) + 1 + NDIG = NDIG + IEXTRA + IF (NDIG > NDG2MX) THEN + NAMEST(NCALL) = 'ZMMPY ' + KFLAG = -9 + CALL ZMWARN + NDIG = NDSAVE + CALL ZMST2M('UNKNOWN+UNKNOWN*i',MZ01) + GO TO 120 + ENDIF + MZ11SV = MZ01(1) + GO TO 110 + ENDIF + + 120 MXEXP = MXSAVE + NTRACE = NTRSAV + NDGSV2 = NDIG + NDIG = NDSAVE + KWARN = KWRNSV + MACCMB = MZ01(0) + MZ01(0) = MIN(MACCMB,MARZ,MAIZ,MBRZ,MBIZ) + MACCMB = MZ01(KPTIMU) + MZ01(KPTIMU) = MIN(MACCMB,MARZ,MAIZ,MBRZ,MBIZ) + CALL ZMEQ2(MZ01,MC,NDGSV2,NDSAVE) + IF (MC(1) >= MEXPOV .OR. MC(1) <= -MEXPOV .OR. & + MC(KPTIMU+1) >= MEXPOV .OR. MC(KPTIMU+1) <= -MEXPOV) THEN + IF (MC(1) == MUNKNO .OR. MC(KPTIMU+1) == MUNKNO) THEN + KFLAG = -4 + ELSE IF (MC(1) == MEXPOV .OR. MC(KPTIMU+1) == MEXPOV) THEN + KFLAG = -5 + ELSE IF (MC(1) == MEXPUN .OR. MC(KPTIMU+1) == MEXPUN) THEN + KFLAG = -6 + ENDIF + IF ((MC(1) == MUNKNO) & + .OR. (MC(KPTIMU+1) == MUNKNO) & + .OR. (MC(1) == MEXPUN .AND. KOVUN == 0) & + .OR. (MC(KPTIMU+1) == MEXPUN .AND. KOVUN == 0) & + .OR. (MC(1) == MEXPOV .AND. KOVUN == 0) & + .OR. (MC(KPTIMU+1) == MEXPOV .AND. KOVUN == 0)) THEN + NAMEST(NCALL) = 'ZMMPY ' + CALL ZMWARN + ENDIF + ENDIF + IF (NTRACE /= 0) CALL ZMNTR(1,MC,MC,1) + KACCSW = KASAVE + NCALL = NCALL - 1 + RETURN + END SUBROUTINE ZMMPY + + SUBROUTINE ZMMPYI(MA,INTEG,MB) + +! MB = MA * INTEG Multiply by one-word (real) integer. + + USE FMVALS + IMPLICIT NONE + + REAL (KIND(1.0D0)) :: MA(-1:LUNPKZ),MB(-1:LUNPKZ) + INTEGER INTEG + + INTEGER KASAVE,KOVUN,KRESLT,KWRNSV,NDSAVE,NTRSAV + REAL (KIND(1.0D0)) :: MXSAVE + + IF (ABS(MA(1)) > MEXPAB .OR. ABS(MA(KPTIMU+1)) > MEXPAB .OR. & + KDEBUG >= 1) THEN + NTRSAV = NTRACE + IF (NTRACE /= 0) THEN + NCALL = NCALL + 1 + NAMEST(NCALL) = 'ZMMPYI' + CALL ZMNTR(2,MA,MA,1) + CALL FMNTRI(2,INTEG,0) + NCALL = NCALL - 1 + ENDIF + NTRACE = 0 + CALL ZMENTR('ZMMPYI',MA,MA,1,MB,KRESLT,NDSAVE,MXSAVE,KASAVE, & + KOVUN) + NTRACE = NTRSAV + IF (KRESLT /= 0) THEN + NCALL = NCALL + 1 + IF (NTRACE /= 0) CALL ZMNTR(1,MB,MB,1) + NCALL = NCALL - 1 + RETURN + ENDIF + NDIG = NDSAVE + MXEXP = MXSAVE + KACCSW = KASAVE + NTRSAV = NTRACE + ELSE + NCALL = NCALL + 1 + IF (NTRACE /= 0) THEN + NAMEST(NCALL) = 'ZMMPYI' + CALL ZMNTR(2,MA,MA,1) + CALL FMNTRI(2,INTEG,0) + ENDIF + KOVUN = 0 + ENDIF + +! Force FMMPYI to use more guard digits for user calls. + + NCALL = NCALL - 1 + NTRSAV = NTRACE + NTRACE = 0 + KWRNSV = KWARN + KWARN = 0 + + CALL FMMPYI(MA,INTEG,MB) + CALL FMMPYI(MA(KPTIMU-1),INTEG,MB(KPTIMU-1)) + + NTRACE = NTRSAV + KWARN = KWRNSV + NCALL = NCALL + 1 + IF (NTRACE /= 0) NAMEST(NCALL) = 'ZMMPYI' + IF (MB(1) == MUNKNO .OR. MB(KPTIMU+1) == MUNKNO) THEN + KFLAG = -4 + ELSE IF (MB(1) == MEXPOV .OR. MB(KPTIMU+1) == MEXPOV) THEN + KFLAG = -5 + ELSE IF (MB(1) == MEXPUN .OR. MB(KPTIMU+1) == MEXPUN) THEN + KFLAG = -6 + ENDIF + IF ((MB(1) == MUNKNO) & + .OR. (MB(KPTIMU+1) == MUNKNO) & + .OR. (MB(1) == MEXPUN .AND. KOVUN == 0) & + .OR. (MB(KPTIMU+1) == MEXPUN .AND. KOVUN == 0) & + .OR. (MB(1) == MEXPOV .AND. KOVUN == 0) & + .OR. (MB(KPTIMU+1) == MEXPOV .AND. KOVUN == 0)) THEN + NAMEST(NCALL) = 'ZMMPYI' + CALL ZMWARN + ENDIF + IF (NTRACE /= 0) CALL ZMNTR(1,MB,MB,1) + NCALL = NCALL - 1 + RETURN + END SUBROUTINE ZMMPYI + + SUBROUTINE ZMNINT(MA,MB) + +! MB = NINT(MA) + +! The nearest integers to both real and imaginary parts are returned. + + USE FMVALS + IMPLICIT NONE + + REAL (KIND(1.0D0)) :: MA(-1:LUNPKZ),MB(-1:LUNPKZ) + + NCALL = NCALL + 1 + NAMEST(NCALL) = 'ZMNINT' + IF (NTRACE /= 0) CALL ZMNTR(2,MA,MA,1) + + CALL FMNINT(MA,MB) + CALL FMNINT(MA(KPTIMU-1),MB(KPTIMU-1)) + + IF (NTRACE /= 0) CALL ZMNTR(1,MB,MB,1) + NCALL = NCALL - 1 + RETURN + END SUBROUTINE ZMNINT + + SUBROUTINE ZMNTR(NTR,MA,MB,NARG) + +! Print ZM numbers in base 10 format using ZMOUT for conversion. +! This is used for trace output from the ZM routines. + +! NTR = 1 if a result of an ZM call is to be printed. +! = 2 to print input argument(s) to an ZM call. + +! MA - the ZM number to be printed. + +! MB - an optional second ZM number to be printed. + +! NARG - the number of arguments. NARG = 1 if only MA is to be +! printed, and NARG = 2 if both MA and MB are to be printed. + + +! NTRACE and LVLTRC (in module FMVALS) control trace printout. + +! NTRACE = 0 No printout except warnings and errors. + +! NTRACE = 1 The result of each call to one of the routines +! is printed in base 10, using ZMOUT. + +! NTRACE = -1 The result of each call to one of the routines +! is printed in internal base MBASE format. + +! NTRACE = 2 The input arguments and result of each call to one +! of the routines is printed in base 10, using ZMOUT. + +! NTRACE = -2 The input arguments and result of each call to one +! of the routines is printed in base MBASE format. + +! LVLTRC defines the call level to which the trace is done. LVLTRC = 1 +! means only FM routines called directly by the user are traced, +! LVLTRC = K prints traces for ZM or FM routines with call +! levels up to and including level K. + + USE FMVALS + IMPLICIT NONE + + REAL (KIND(1.0D0)) :: MA(-1:LUNPKZ),MB(-1:LUNPKZ) + INTEGER NTR,NARG + + CHARACTER(6) :: NAME + + IF (NTRACE == 0) RETURN + IF (NCALL > LVLTRC) RETURN + IF (NTR == 2 .AND. ABS(NTRACE) == 1) RETURN + + IF (NTR == 2) THEN + NAME = NAMEST(NCALL) + WRITE (KW,"(' Input to ',A6)") NAME + ELSE + NAME = NAMEST(NCALL) + IF (KFLAG == 0) THEN + WRITE (KW, & + "(' ',A6,15X,'Call level =',I2,5X,'MBASE ='," // & + "I10,5X,'NDIG =',I6)" & + ) NAME,NCALL,INT(MBASE),NDIG + ELSE + WRITE (KW, & + "(' ',A6,6X,'Call level =',I2,4X,'MBASE ='," // & + "I10,4X,'NDIG =',I6,4X,'KFLAG =',I3)" & + ) NAME,NCALL,INT(MBASE),NDIG,KFLAG + ENDIF + ENDIF + +! Check for base MBASE internal format trace. + + IF (NTRACE < 0) THEN + CALL ZMNTRJ(MA,NDIG) + IF (NARG == 2) CALL ZMNTRJ(MB,NDIG) + ENDIF + +! Check for base 10 trace using ZMOUT. + + IF (NTRACE > 0) THEN + CALL ZMPRNT(MA) + + IF (NARG == 2) THEN + CALL ZMPRNT(MB) + ENDIF + ENDIF + + RETURN + END SUBROUTINE ZMNTR + + SUBROUTINE ZMNTR2(NTR,MAFM,MBFM,NARG) + +! Print real FM numbers in base 10 format using FMOUT for conversion. + + USE FMVALS + IMPLICIT NONE + + REAL (KIND(1.0D0)) :: MAFM(-1:LUNPCK),MBFM(-1:LUNPCK) + INTEGER NTR,NARG + + CHARACTER(6) :: NAME + + IF (NTRACE == 0) RETURN + IF (NCALL > LVLTRC) RETURN + IF (NTR == 2 .AND. ABS(NTRACE) == 1) RETURN + + IF (NTR == 2) THEN + NAME = NAMEST(NCALL) + WRITE (KW,"(' Input to ',A6)") NAME + ELSE + NAME = NAMEST(NCALL) + IF (KFLAG == 0) THEN + WRITE (KW, & + "(' ',A6,15X,'Call level =',I2,5X,'MBASE ='," // & + "I10,5X,'NDIG =',I6)" & + ) NAME,NCALL,INT(MBASE),NDIG + ELSE + WRITE (KW, & + "(' ',A6,6X,'Call level =',I2,4X,'MBASE ='," // & + "I10,4X,'NDIG =',I6,4X,'KFLAG =',I3)" & + ) NAME,NCALL,INT(MBASE),NDIG,KFLAG + ENDIF + ENDIF + +! Check for base MBASE internal format trace. + + IF (NTRACE < 0) THEN + CALL FMNTRJ(MAFM,NDIG) + IF (NARG == 2) CALL FMNTRJ(MBFM,NDIG) + ENDIF + +! Check for base 10 trace using FMOUT. + + IF (NTRACE > 0) THEN + CALL FMPRNT(MAFM) + + IF (NARG == 2) THEN + CALL FMPRNT(MBFM) + ENDIF + ENDIF + + RETURN + END SUBROUTINE ZMNTR2 + + SUBROUTINE ZMNTRI(NTR,N,KNAM) + +! Internal routine for trace output of integer variables. + +! NTR = 1 for output values +! 2 for input values + +! N Integer to be printed. + +! KNAM is positive if the routine name is to be printed. + + USE FMVALS + IMPLICIT NONE + + INTEGER NTR,N,KNAM + + CHARACTER(6) :: NAME + + IF (NTRACE == 0) RETURN + IF (NCALL > LVLTRC) RETURN + IF (NTR == 2 .AND. ABS(NTRACE) == 1) RETURN + + IF (NTR == 2 .AND. KNAM > 0) THEN + NAME = NAMEST(NCALL) + WRITE (KW,"(' Input to ',A6)") NAME + ENDIF + IF (NTR == 1 .AND. KNAM > 0) THEN + NAME = NAMEST(NCALL) + IF (KFLAG == 0) THEN + WRITE (KW, & + "(' ',A6,15X,'Call level =',I2,5X,'MBASE ='," // & + "I10,5X,'NDIG =',I6)" & + ) NAME,NCALL,INT(MBASE),NDIG + ELSE + WRITE (KW, & + "(' ',A6,6X,'Call level =',I2,4X,'MBASE ='," // & + "I10,4X,'NDIG =',I6,4X,'KFLAG =',I3)" & + ) NAME,NCALL,INT(MBASE),NDIG,KFLAG + ENDIF + ENDIF + + WRITE (KW,"(1X,I18)") N + + RETURN + END SUBROUTINE ZMNTRI + + SUBROUTINE ZMNTRJ(MA,ND) + +! Print trace output in internal base MBASE format. The number to +! be printed is in MA. + +! ND is the number of base MBASE digits to be printed. + + USE FMVALS + IMPLICIT NONE + + REAL (KIND(1.0D0)) :: MA(-1:LUNPKZ) + INTEGER ND + + CHARACTER(50) :: FORM + INTEGER J,L,N,N1 + + N1 = ND + 1 + + L = INT(LOG10(DBLE(MBASE-1))) + 2 + N = (KSWIDE-23)/L + IF (N > 10) N = 5*(N/5) + IF (ND <= N) THEN + WRITE (FORM,"(' (1X,I19,I',I2,',',I3,'I',I2,') ')") L+2, N-1, L + ELSE + WRITE (FORM, & + "(' (1X,I19,I',I2,',',I3,'I',I2," // & + "'/(22X,',I3,'I',I2,')) ')" & + ) L+2, N-1, L, N, L + ENDIF + WRITE (KW,FORM) INT(MA(1)),INT(MA(-1)*MA(2)),(INT(MA(J)),J=3,N1) + WRITE (KW,FORM) INT(MA(KPTIMU+1)),INT(MA(KPTIMU-1)*MA(KPTIMU+2)), & + (INT(MA(KPTIMU+J)),J=3,N1) + + RETURN + END SUBROUTINE ZMNTRJ + + SUBROUTINE ZMNTRZ(NTR,X,KNAM) + +! Internal routine for trace output of complex variables. + +! NTR - 1 for output values +! 2 for input values + +! X - Complex value to be printed if NX == 1 + +! KNAM - Positive if the routine name is to be printed. + + USE FMVALS + IMPLICIT NONE + + INTEGER NTR,KNAM + COMPLEX X + + CHARACTER(6) :: NAME + DOUBLE PRECISION XREAL,XIMAG + + IF (NTRACE == 0) RETURN + IF (NCALL > LVLTRC) RETURN + IF (NTR == 2 .AND. ABS(NTRACE) == 1) RETURN + + IF (NTR == 2 .AND. KNAM > 0) THEN + NAME = NAMEST(NCALL) + WRITE (KW,"(' Input to ',A6)") NAME + ENDIF + IF (NTR == 1 .AND. KNAM > 0) THEN + NAME = NAMEST(NCALL) + IF (KFLAG == 0) THEN + WRITE (KW, & + "(' ',A6,15X,'Call level =',I2,5X,'MBASE ='," // & + "I10,5X,'NDIG =',I6)" & + ) NAME,NCALL,INT(MBASE),NDIG + ELSE + WRITE (KW, & + "(' ',A6,6X,'Call level =',I2,4X,'MBASE ='," // & + "I10,4X,'NDIG =',I6,4X,'KFLAG =',I3)" & + ) NAME,NCALL,INT(MBASE),NDIG,KFLAG + ENDIF + ENDIF + + XREAL = DBLE(X) + XIMAG = DBLE(AIMAG(X)) + IF (XIMAG >= 0.0D0) THEN + WRITE (KW,"(1X,D30.20,' +',D30.20,' i')") XREAL,XIMAG + ELSE + WRITE (KW,"(1X,D30.20,' -',D30.20,' i')") XREAL,ABS(XIMAG) + ENDIF + + RETURN + END SUBROUTINE ZMNTRZ + + SUBROUTINE ZMOUT(MA,LINE,LB,LAST1,LAST2) + +! Convert a floating multiple precision number to a character array +! for output. + +! MA is an ZM number to be converted to an A1 character +! array in base 10 format +! LINE is the CHARACTER*1 array in which the result is returned. +! LB is the length of LINE. +! LAST1 is the position of the last nonblank character of the +! real part of the number in LINE. +! LAST2 is the position of the last nonblank character of the +! imaginary part of the number in LINE. + +! JFORM1 and JFORM2 determine the format of the two FM numbers +! making up the complex value MA. See FMOUT for details. + +! JFORMZ determines the format of the real and imaginary parts. + +! JFORMZ = 1 normal setting : 1.23 - 4.56 i +! = 2 use capital I : 1.23 - 4.56 I +! = 3 parenthesis format ( 1.23 , -4.56 ) + +! LINE should be dimensioned at least 4*(LOG10(MBASE)*NDIG + 15) on a +! 32-bit machine to allow for up to 10 digit exponents. Replace +! 15 by 20 if 48-bit integers are used, 25 for 64-bit integers, etc. + + USE FMVALS + IMPLICIT NONE + + REAL (KIND(1.0D0)) :: MA(-1:LUNPKZ),MI(-1:LUNPCK) + INTEGER LB,LAST1,LAST2 + CHARACTER LINE(LB) + + REAL (KIND(1.0D0)) :: MAIMS + INTEGER J,KPT,LB2,ND,NEXP + + NCALL = NCALL + 1 + NAMEST(NCALL) = 'ZMOUT ' + DO J = 1, LB + LINE(J) = ' ' + ENDDO + ND = INT(REAL(NDIG)*LOG10(REAL(MBASE))) + 1 + IF (ND < 2) ND = 2 + NEXP = INT(2.0*LOG10(REAL(MXBASE))) + 6 + KPT = 1 + IF (JFORMZ == 3) KPT = 3 + LB2 = MAX(JFORM2+NEXP,ND+NEXP) + LB2 = MIN(LB+1-KPT,LB2) + CALL FMOUT(MA,LINE(KPT),LB2) + + IF (JFORMZ == 3) LINE(1) = '(' + LAST1 = 1 + DO J = LB2, 1, -1 + IF (LINE(J) /= ' ') THEN + LAST1 = J + GO TO 110 + ENDIF + ENDDO + + 110 MAIMS = MA(KPTIMU-1) + DO J = -1, NDIG+1 + MI(J) = MA(KPTIMU+J) + ENDDO + LINE(LAST1+1) = ' ' + IF (JFORMZ == 3) THEN + LINE(LAST1+2) = ',' + ELSE + IF (MAIMS < 0) THEN + MI(-1) = 1 + LINE(LAST1+2) = '-' + ELSE + LINE(LAST1+2) = '+' + ENDIF + ENDIF + + KPT = LAST1 + 3 + LB2 = MAX(JFORM2+NEXP,ND+NEXP) + LB2 = MIN(LB+1-KPT,LB2+2) + CALL FMOUT(MI,LINE(KPT),LB2) + LAST1 = KPT + DO J = LB2+KPT-1, KPT, -1 + IF (LINE(J) /= ' ') THEN + LAST2 = J + GO TO 120 + ENDIF + ENDDO + + 120 LAST2 = LAST2 + 2 + LINE(LAST2) = 'i' + IF (JFORMZ == 2) LINE(LAST2) = 'I' + IF (JFORMZ == 3) LINE(LAST2) = ')' + + IF (LINE(KPT) == ' ' .AND. LINE(KPT+1) == '+') THEN + DO J = KPT+2, LAST2 + LINE(J-2) = LINE(J) + ENDDO + LINE(LAST2-1) = ' ' + LINE(LAST2) = ' ' + LAST2 = LAST2 - 2 + ENDIF + + NCALL = NCALL - 1 + RETURN + END SUBROUTINE ZMOUT + + SUBROUTINE ZMPACK(MA,MP) + +! MA is packed two base NDIG digits per word and returned in MP. + + USE FMVALS + IMPLICIT NONE + + REAL (KIND(1.0D0)) :: MA(-1:LUNPKZ),MP(-1:LPACKZ) + CALL FMPACK(MA,MP) + CALL FMPACK(MA(KPTIMU-1),MP(KPTIMP)) + RETURN + END SUBROUTINE ZMPACK + + SUBROUTINE ZMPRNT(MA) + +! Print MA in base 10 format. + +! ZMPRNT can be called directly by the user for easy output +! in M format. MA is converted using ZMOUT and printed. + + USE FMVALS + IMPLICIT NONE + + REAL (KIND(1.0D0)) :: MA(-1:LUNPKZ) + + CHARACTER(20) :: FORM + INTEGER K,KSAVE,LAST1,LAST2,LB,LBZ,ND,NEXP + + KSAVE = KFLAG + ND = INT(REAL(NDIG)*LOG10(REAL(MBASE))) + 1 + IF (ND < 2) ND = 2 + NEXP = INT(2.0*LOG10(REAL(MXBASE))) + 6 + LB = MAX(JFORM2+NEXP,ND+NEXP) + + IF (2*LB+7 <= LMBUFZ .AND. JPRNTZ == 1) THEN + LBZ = 2*LB + 7 + CALL ZMOUT(MA,CMBUFZ,LBZ,LAST1,LAST2) + WRITE (FORM,"(' (6X,',I3,'A1) ')") KSWIDE-7 + WRITE (KW,FORM) (CMBUFZ(K),K=1,LAST2) + ELSE + CALL FMPRNT(MA) + CALL FMPRNT(MA(KPTIMU-1)) + ENDIF + KFLAG = KSAVE + RETURN + END SUBROUTINE ZMPRNT + + SUBROUTINE ZMPWR(MA,MB,MC) + +! MC = MA ** MB. + + USE FMVALS + IMPLICIT NONE + + REAL (KIND(1.0D0)) :: MA(-1:LUNPKZ),MB(-1:LUNPKZ),MC(-1:LUNPKZ) +! MZ06, MZ07 + + REAL (KIND(1.0D0)) :: MACCMB,MAIZ,MARZ,MBIZ,MBRZ,MXSAVE,MTEMP + INTEGER IEXTRA,INTMB,J,JSIN,JCOS,JSWAP,K,KASAVE,KOVUN, & + KRADSV,KRESLT,KWRNSV,NDSAVE + LOGICAL FMCOMP + REAL XVAL + + CALL ZMENTR('ZMPWR ',MA,MB,2,MC,KRESLT,NDSAVE,MXSAVE,KASAVE, & + KOVUN) + IF (KRESLT /= 0) RETURN + MARZ = MA(0) + MBRZ = MB(0) + MAIZ = MA(KPTIMU) + MBIZ = MB(KPTIMU) + KACCSW = 0 + NDIG = MIN(NDIG+1,NDG2MX) + IF (MBASE < 1000 .OR. KROUND /= 1 .OR. KRPERF == 1) THEN + IF (NCALL == 1) NDIG = MIN(NDG2MX,MAX(NDIG,2*NDSAVE+10)) + ENDIF + + CALL ZMEQU(MA,MZ06,NDSAVE,NDIG) + CALL ZMEQU(MB,MZ07,NDSAVE,NDIG) + +! Check for special cases. + + IF (MA(2) == 0 .AND. MA(KPTIMU+2) == 0) THEN + IF (MB(-1) > 0 .AND. MB(KPTIMU+2) == 0) THEN + CALL ZMI2M(0,MZ02) + GO TO 110 + ELSE + KFLAG = -4 + CALL ZMST2M('UNKNOWN+UNKNOWN*i',MZ02) + GO TO 110 + ENDIF + ENDIF + IF (MB(KPTIMU+2) == 0) THEN + KWRNSV = KWARN + KWARN = 0 + CALL FMMI(MZ07,INTMB) + KWARN = KWRNSV + IF (KFLAG == 0) THEN + IF (NCALL == 1) THEN + XVAL = ABS(INTMB) + 1 + K = INT((1.5*LOG(XVAL))/ALOGMB + 2.0) + NDIG = MAX(NDIG+K,2) + IF (NDIG > NDG2MX) THEN + KFLAG = -9 + CALL ZMWARN + NDIG = NDSAVE + CALL ZMST2M('UNKNOWN+UNKNOWN*i',MC) + IF (NTRACE /= 0) CALL ZMNTR(1,MC,MC,1) + NCALL = NCALL - 1 + RETURN + ENDIF + IF (MBASE < 1000 .OR. KROUND /= 1 .OR. KRPERF == 1) THEN + NDIG = MIN(NDG2MX,MAX(NDIG,2*NDSAVE+10)) + ENDIF + IF (MBASE >= 100*ABS(MA(2)) .OR. & + MBASE >= 100*ABS(MA(KPTIMU+2))) THEN + NDIG = MIN(NDIG+1,NDG2MX) + ENDIF + ENDIF + CALL ZMEQ2_R1(MZ06,NDSAVE,NDIG) + CALL ZMIPWR(MZ06,INTMB,MZ03) + CALL ZMEQ(MZ03,MZ02) + GO TO 110 + ENDIF + ENDIF + +! Check for cases where ABS(MA) is very close to 1, and +! avoid cancellation. + + CALL FMABS(MZ06,M03) + CALL FMABS(MZ06(KPTIMU-1),M04) + CALL FMI2M(1,M05) + IF (FMCOMP(M03,'EQ',M05) .AND. & + (M04(1) <= (-NDIG).OR.M04(2) == 0)) THEN + IF (MA(-1) > 0) THEN + +! (1+c)**b = 1 + b*c + ... + + CALL ZMI2M(1,MZ02) + CALL ZMSUB(MZ06,MZ02,MZ08) + CALL ZMEQ(MZ08,MZ02) + CALL ZMMPY(MZ07,MZ02,MZ08) + CALL ZMEQ(MZ08,MZ02) + CALL FMADD_R1(MZ02,M05) + ELSE + +! (-1+c)**b = (-1)**b * (1 - b*c + ... ) + + CALL ZMI2M(-1,MZ02) + CALL ZMSUB(MZ06,MZ02,MZ08) + CALL ZMEQ(MZ08,MZ02) + CALL ZMMPY(MZ07,MZ02,MZ08) + CALL ZMEQ(MZ08,MZ02) + CALL ZMMPYI(MZ02,-1,MZ08) + CALL ZMEQ(MZ08,MZ02) + CALL FMADD_R1(MZ02,M05) + KRADSV = KRAD + KRAD = 0 + IF (MA(KPTIMU-1) >= 0) THEN + CALL FMMPYI(MZ07,180,M06) + ELSE + CALL FMMPYI(MZ07,-180,M06) + ENDIF + CALL FMCSSN(M06,MZ03,MZ03(KPTIMU-1)) + KRAD = KRADSV + CALL FMPI(M05) + CALL FMMPY_R1(M05,MZ07(KPTIMU-1)) + IF (MA(KPTIMU-1) >= 0) CALL FMMPYI_R1(M05,-1) + CALL FMEXP(M05,M12) + CALL FMEQ(M12,M05) + CALL FMMPYD(M05,MZ03,MZ03(KPTIMU-1),MZ08,MZ08(KPTIMU-1)) + CALL ZMEQ(MZ08,MZ03) + CALL ZMMPY(MZ02,MZ03,MZ08) + CALL ZMEQ(MZ08,MZ02) + ENDIF + GO TO 110 + ENDIF + IF (FMCOMP(M04,'EQ',M05) .AND. & + (M03(1) <= (-NDIG).OR.M03(2) == 0)) THEN + IF (MA(KPTIMU-1) > 0) THEN + +! (i+c)**b = i**b * (1 - b*c*i - ... ) + + CALL ZM2I2M(0,1,MZ02) + CALL ZMSUB(MZ06,MZ02,MZ08) + CALL ZMEQ(MZ08,MZ02) + CALL ZMMPY(MZ07,MZ02,MZ08) + CALL ZMEQ(MZ08,MZ02) + DO J = -1, NDIG+1 + MTEMP = MZ02(J) + MZ02(J) = MZ02(KPTIMU+J) + MZ02(KPTIMU+J) = MTEMP + ENDDO + IF (MZ02(KPTIMU+1) /= MUNKNO .AND. MZ02(KPTIMU+2) /= 0) & + MZ02(KPTIMU-1) = -MZ02(KPTIMU-1) + CALL FMADD_R1(MZ02,M05) + KRADSV = KRAD + KRAD = 0 + CALL FMMPYI(MZ07,90,M06) + CALL FMCSSN(M06,MZ03,MZ03(KPTIMU-1)) + KRAD = KRADSV + CALL FMPI(M05) + CALL FMMPY_R1(M05,MZ07(KPTIMU-1)) + CALL FMDIVI_R1(M05,-2) + CALL FMEXP(M05,M12) + CALL FMEQ(M12,M05) + CALL FMMPYD(M05,MZ03,MZ03(KPTIMU-1),MZ08,MZ08(KPTIMU-1)) + CALL ZMEQ(MZ08,MZ03) + CALL ZMMPY(MZ02,MZ03,MZ08) + CALL ZMEQ(MZ08,MZ02) + ELSE + +! (-i+c)**b = (-i)**b * (1 + b*c*i - ... ) + + CALL ZM2I2M(0,-1,MZ02) + CALL ZMSUB(MZ06,MZ02,MZ08) + CALL ZMEQ(MZ08,MZ02) + CALL ZMMPY(MZ07,MZ02,MZ08) + CALL ZMEQ(MZ08,MZ02) + DO J = -1, NDIG+1 + MTEMP = MZ02(J) + MZ02(J) = MZ02(KPTIMU+J) + MZ02(KPTIMU+J) = MTEMP + ENDDO + IF (MZ02(1) /= MUNKNO .AND. MZ02(2) /= 0) MZ02(-1) = -MZ02(-1) + CALL FMADD_R1(MZ02,M05) + KRADSV = KRAD + KRAD = 0 + CALL FMMPYI(MZ07,-90,M06) + CALL FMCSSN(M06,MZ03,MZ03(KPTIMU-1)) + KRAD = KRADSV + CALL FMPI(M05) + CALL FMMPY_R1(M05,MZ07(KPTIMU-1)) + CALL FMDIVI_R1(M05,2) + CALL FMEXP(M05,M12) + CALL FMEQ(M12,M05) + CALL FMMPYD(M05,MZ03,MZ03(KPTIMU-1),MZ08,MZ08(KPTIMU-1)) + CALL ZMEQ(MZ08,MZ03) + CALL ZMMPY(MZ02,MZ03,MZ08) + CALL ZMEQ(MZ08,MZ02) + ENDIF + GO TO 110 + ENDIF + + CALL ZMLN(MZ06,MZ02) + CALL ZMMPY(MZ07,MZ02,MZ08) + CALL ZMEQ(MZ08,MZ02) + KWRNSV = KWARN + KWARN = 0 + CALL FMEQ(MZ02(KPTIMU-1),MZ01) + CALL FMRDC(MZ01,JSIN,JCOS,JSWAP) + KWARN = KWRNSV + IF (KFLAG == -9) THEN + IEXTRA = INT(MZ01(1)) + ELSE + IEXTRA = INT(MZ02(KPTIMU+1) - MZ01(1)) + ENDIF + IF (IEXTRA > 1) THEN + NDIG = NDIG + IEXTRA + IF (NDIG > NDG2MX) THEN + KFLAG = -9 + CALL ZMWARN + NDIG = NDIG - IEXTRA + CALL ZMST2M('UNKNOWN+UNKNOWN*i',MZ02) + GO TO 110 + ENDIF + CALL ZMEQ2_R1(MZ06,NDSAVE,NDIG) + CALL ZMEQ2_R1(MZ07,NDSAVE,NDIG) + CALL ZMLN(MZ06,MZ02) + CALL ZMMPY(MZ07,MZ02,MZ08) + CALL ZMEQ(MZ08,MZ02) + ENDIF + + CALL ZMEXP(MZ02,MZ06) + CALL ZMEQ(MZ06,MZ02) + + 110 MACCMB = MZ02(0) + MZ02(0) = MIN(MACCMB,MARZ,MAIZ,MBRZ,MBIZ) + MACCMB = MZ02(KPTIMU) + MZ02(KPTIMU) = MIN(MACCMB,MARZ,MAIZ,MBRZ,MBIZ) + CALL ZMEXIT(MZ02,MC,NDSAVE,MXSAVE,KASAVE,KOVUN) + RETURN + END SUBROUTINE ZMPWR + + SUBROUTINE ZMREAD(KREAD,MA) + +! Read MA on unit KREAD. Multi-line numbers will have '&' as the +! last nonblank character on all but the last line. Only one +! number is allowed on the line(s). + + USE FMVALS + IMPLICIT NONE + + INTEGER KREAD + REAL (KIND(1.0D0)) :: MA(-1:LUNPKZ) + + CHARACTER LINE(80) + INTEGER J,LB + + NCALL = NCALL + 1 + NAMEST(NCALL) = 'ZMREAD' + LB = 0 + + 110 READ (KREAD,"(80A1)",ERR=120,END=120) LINE + +! Scan the line and look for '&' + + DO J = 1, 80 + IF (LINE(J) == '&') GO TO 110 + IF (LINE(J) /= ' ') THEN + LB = LB + 1 + IF (LB > LMBUFZ) THEN + KFLAG = -8 + GO TO 130 + ENDIF + CMBUFZ(LB) = LINE(J) + ENDIF + ENDDO + + CALL ZMINP(CMBUFZ,MA,1,LB) + + NCALL = NCALL - 1 + RETURN + +! If there is an error, return UNKNOWN. + + 120 KFLAG = -4 + 130 CALL ZMWARN + CALL ZMST2M('UNKNOWN+UNKNOWN*i',MA) + NCALL = NCALL - 1 + RETURN + END SUBROUTINE ZMREAD + + SUBROUTINE ZMREAL(MA,MBFM) + +! MBFM = REAL(MA) + +! MA is a complex ZM number, MBFM is a real FM number. + + USE FMVALS + IMPLICIT NONE + + REAL (KIND(1.0D0)) :: MA(-1:LUNPKZ),MBFM(-1:LUNPCK) + + KFLAG = 0 + NCALL = NCALL + 1 + NAMEST(NCALL) = 'ZMREAL' + IF (NTRACE /= 0) CALL ZMNTR(2,MA,MA,1) + + CALL FMEQ(MA,MBFM) + + IF (NTRACE /= 0) CALL FMNTR(1,MBFM,MBFM,1,1) + NCALL = NCALL - 1 + RETURN + END SUBROUTINE ZMREAL + + SUBROUTINE ZMRPWR(MA,IVAL,JVAL,MB) + +! MB = MA ** (IVAL/JVAL) + +! Raise a ZM number to a rational power. + + USE FMVALS + IMPLICIT NONE + + REAL (KIND(1.0D0)) :: MA(-1:LUNPKZ),MB(-1:LUNPKZ) + INTEGER IVAL,JVAL + REAL (KIND(1.0D0)) :: MA2,MACCMB,MAIZ,MARZ,MR1,MXSAVE + INTEGER IJSIGN,INVERT,IVAL2,J,JVAL2,K,KASAVE,KOVUN,KST,L,LVAL, & + NDSAVE + REAL XVAL + + DOUBLE PRECISION AR,BR,F,THETA,X + INTEGER NSTACK(19) + + NCALL = NCALL + 1 + NAMEST(NCALL) = 'ZMRPWR' + NDSAVE = NDIG + IF (NTRACE /= 0) THEN + CALL ZMNTR(2,MA,MA,1) + CALL FMNTRI(2,IVAL,0) + CALL FMNTRI(2,JVAL,0) + ENDIF + MARZ = MA(0) + MAIZ = MA(KPTIMU) + KOVUN = 0 + IF (MA(1) == MEXPOV .OR. MA(1) == MEXPUN .OR. & + MA(KPTIMU+1) == MEXPOV .OR. MA(KPTIMU+1) == MEXPUN) KOVUN = 1 + + IF (MBLOGS /= MBASE) CALL FMCONS + KFLAG = 0 + IJSIGN = 1 + IVAL2 = ABS(IVAL) + JVAL2 = ABS(JVAL) + IF (IVAL > 0 .AND. JVAL < 0) IJSIGN = -1 + IF (IVAL < 0 .AND. JVAL > 0) IJSIGN = -1 + IF (IVAL2 > 0 .AND. JVAL2 > 0) CALL FMGCDI(IVAL2,JVAL2) + +! Check for special cases. + + IF (MA(1) == MUNKNO .OR. MA(KPTIMU+1) == MUNKNO .OR. & + (IJSIGN <= 0 .AND. MA(2) == 0 .AND. MA(KPTIMU+2) == 0) .OR. & + JVAL == 0) THEN + MA2 = MA(2) + KFLAG = -4 + IF (IVAL <= 0 .AND. MA2 == 0) CALL ZMWARN + CALL ZMST2M('UNKNOWN+UNKNOWN*i',MB) + IF (NTRACE /= 0) CALL ZMNTR(1,MB,MB,1) + NCALL = NCALL - 1 + RETURN + ENDIF + + IF (IVAL == 0) THEN + CALL ZMI2M(1,MB) + IF (NTRACE /= 0) CALL ZMNTR(1,MB,MB,1) + NCALL = NCALL - 1 + RETURN + ENDIF + +! Increase the working precision. + + IF (NCALL == 1) THEN + XVAL = MAX(ABS(IVAL),ABS(JVAL)) + 1 + K = INT((5.0*REAL(DLOGTN) + LOG(XVAL))/ALOGMB + 2.0) + NDIG = MAX(NDIG+K,2) + IF (MBASE < 1000 .OR. KROUND /= 1 .OR. KRPERF == 1) THEN + NDIG = MIN(NDG2MX,MAX(NDIG,2*NDSAVE+10)) + ENDIF + ELSE + XVAL = MAX(ABS(IVAL),ABS(JVAL)) + 1 + K = INT(LOG(XVAL)/ALOGMB + 1.0) + NDIG = NDIG + K + ENDIF + IF (NDIG > NDG2MX) THEN + KFLAG = -9 + CALL ZMWARN + NDIG = NDSAVE + CALL ZMST2M('UNKNOWN+UNKNOWN*i',MB) + IF (NTRACE /= 0) CALL ZMNTR(1,MB,MB,1) + NCALL = NCALL - 1 + RETURN + ENDIF + IF (MBASE >= 100*ABS(MA(2)) .OR. & + MBASE >= 100*ABS(MA(KPTIMU+2))) THEN + NDIG = MIN(NDIG+1,NDG2MX) + ENDIF + KASAVE = KACCSW + MXSAVE = MXEXP + MXEXP = MXEXP2 + + CALL ZMEQ2(MA,MZ04,NDSAVE,NDIG) + IF (IVAL2 == 1 .AND. JVAL2 == 2) THEN + CALL ZMSQRT(MZ04,MB) + IF (IJSIGN < 0) THEN + CALL ZMI2M(1,MZ01) + CALL ZMDIV(MZ01,MB,MZ02) + CALL ZMEQ(MZ02,MB) + ENDIF + GO TO 110 + ENDIF + +! Generate the first approximation to MA**(1/JVAL2). + + CALL ZMI2M(0,MB) + CALL FMDIG(NSTACK,KST) + NDIG = NSTACK(1) + CALL FMSQR(MZ04,MZ03) + CALL FMSQR(MZ04(KPTIMU-1),M03) + CALL FMADD_R1(MZ03,M03) + CALL FMSQRT_R1(MZ03) + IF (MZ03(1) >= MEXPOV) THEN + KFLAG = -4 + CALL ZMWARN + MXEXP = MXSAVE + KACCSW = KASAVE + NDIG = NDSAVE + CALL ZMST2M('UNKNOWN+UNKNOWN*i',MB) + IF (NTRACE /= 0) CALL ZMNTR(1,MB,MB,1) + NCALL = NCALL - 1 + RETURN + ENDIF + +! Invert MA if ABS(MA) > 1 and IVAL or JVAL is large. + + INVERT = 0 + IF (IVAL > 5 .OR. JVAL > 5) THEN + IF (MZ03(1) > 0) THEN + INVERT = 1 + NDIG = NSTACK(KST) + CALL ZMI2M(1,MB) + CALL ZMDIV(MB,MZ04,MZ08) + CALL ZMEQ(MZ08,MZ04) + NDIG = NSTACK(1) + CALL FMDIV_R2(MB,MZ03) + ENDIF + ENDIF + + CALL FMDIV(MZ04,MZ03,M03) + CALL FMM2DP(M03,AR) + CALL FMDIV(MZ04(KPTIMU-1),MZ03,M03) + CALL FMM2DP(M03,BR) + MR1 = MZ03(1) + MZ03(1) = 0 + CALL FMM2DP(MZ03,X) + L = INT(MR1/JVAL2) + F = MR1/DBLE(JVAL2) - L + X = X**(1.0D0/JVAL2) * DBLE(MBASE)**F + CALL FMDPM(X,M03) + M03(1) = M03(1) + L + + THETA = ATAN2(BR,AR) + X = COS(THETA/JVAL2) + CALL FMDPM(X,MB) + X = SIN(THETA/JVAL2) + CALL FMDPM(X,MB(KPTIMU-1)) + CALL FMMPY_R2(M03,MB) + CALL FMMPY_R2(M03,MB(KPTIMU-1)) + +! Newton iteration. + + DO J = 1, KST + NDIG = NSTACK(J) + IF (J < KST) NDIG = NDIG + 1 + LVAL = JVAL2 - 1 + CALL ZMIPWR(MB,LVAL,MZ03) + CALL ZMDIV(MZ04,MZ03,MZ08) + CALL ZMEQ(MZ08,MZ03) + CALL ZMMPYI(MB,LVAL,MZ08) + CALL ZMEQ(MZ08,MB) + CALL ZMADD(MB,MZ03,MZ08) + CALL ZMEQ(MZ08,MB) + CALL ZMDIVI(MB,JVAL2,MZ08) + CALL ZMEQ(MZ08,MB) + ENDDO + + CALL ZMIPWR(MB,IJSIGN*IVAL2,MZ03) + CALL ZMEQ(MZ03,MB) + IF (INVERT == 1) THEN + CALL ZMI2M(1,MZ03) + CALL ZMDIV(MZ03,MB,MZ08) + CALL ZMEQ(MZ08,MB) + ENDIF + +! Round the result and return. + + 110 MACCMB = MB(0) + MB(0) = MIN(MACCMB,MARZ,MAIZ) + MACCMB = MB(KPTIMU) + MB(KPTIMU) = MIN(MACCMB,MARZ,MAIZ) + CALL ZMEQ(MB,MZ01) + CALL ZMEXIT(MZ01,MB,NDSAVE,MXSAVE,KASAVE,KOVUN) + RETURN + END SUBROUTINE ZMRPWR + + SUBROUTINE ZMRSLT(MC,KRESLT) + +! Handle results that are special cases, such as overflow, +! underflow, and unknown. + +! MC is the result that is returned + +! KRESLT is the result code. Result codes handled here: + +! 0 - Perform the normal operation +! 12 - The result is 'UNKNOWN' + + USE FMVALS + IMPLICIT NONE + + REAL (KIND(1.0D0)) :: MC(-1:LUNPKZ) + INTEGER KRESLT + + INTEGER KFSAVE + + KFSAVE = KFLAG + + IF (KRESLT == 12 .OR. KRESLT < 0 .OR. KRESLT > 15) THEN + CALL ZMST2M('UNKNOWN+UNKNOWN*i',MC) + KFLAG = KFSAVE + RETURN + ENDIF + + RETURN + END SUBROUTINE ZMRSLT + + SUBROUTINE ZMSIN(MA,MB) + +! MB = SIN(MA). + + USE FMVALS + IMPLICIT NONE + + REAL (KIND(1.0D0)) :: MA(-1:LUNPKZ),MB(-1:LUNPKZ) + REAL (KIND(1.0D0)) :: MACCMB,MAIZ,MARZ,MXSAVE + INTEGER KASAVE,KOVUN,KRESLT,KRSAVE,NDSAVE + + CALL ZMENTR('ZMSIN ',MA,MA,1,MB,KRESLT,NDSAVE,MXSAVE,KASAVE, & + KOVUN) + IF (KRESLT /= 0) RETURN + MARZ = MA(0) + MAIZ = MA(KPTIMU) + KACCSW = 0 + KRSAVE = KRAD + KRAD = 1 + + CALL ZMEQU(MA,MZ07,NDSAVE,NDIG) + +! Check for special cases. + + IF (MA(2) == 0 .AND. MA(KPTIMU+2) == 0) THEN + CALL ZMI2M(0,MZ01) + GO TO 110 + ELSE IF (MA(1) < (-NDIG) .AND. MA(KPTIMU+1) < (-NDIG)) THEN + CALL ZMEQ(MZ07,MZ01) + GO TO 110 + ELSE IF (MA(KPTIMU+2) == 0) THEN + CALL FMSIN(MZ07,MZ01) + CALL FMI2M(0,MZ01(KPTIMU-1)) + GO TO 110 + ELSE IF (MA(2) == 0) THEN + CALL FMSINH(MZ07(KPTIMU-1),MZ01(KPTIMU-1)) + CALL FMI2M(0,MZ01) + GO TO 110 + ENDIF + +! Find COS(REAL(MA)) and SIN(REAL(MA)). + + CALL FMCSSN(MZ07,MZ01(KPTIMU-1),MZ01) + +! Find COSH(IMAG(MA)) and SINH(IMAG(MA)). + + CALL FMCHSH(MZ07(KPTIMU-1),M05,M06) + +! SIN(MA) = SIN(REAL(MA))*COSH(IMAG(MA)) + +! COS(REAL(MA))*SINH(IMAG(MA)) i + + CALL FMMPY_R1(MZ01,M05) + CALL FMMPY_R1(MZ01(KPTIMU-1),M06) + + 110 MACCMB = MZ01(0) + MZ01(0) = MIN(MACCMB,MARZ,MAIZ) + MACCMB = MZ01(KPTIMU) + MZ01(KPTIMU) = MIN(MACCMB,MARZ,MAIZ) + CALL ZMEXIT(MZ01,MB,NDSAVE,MXSAVE,KASAVE,KOVUN) + KRAD = KRSAVE + RETURN + END SUBROUTINE ZMSIN + + SUBROUTINE ZMSINH(MA,MB) + +! MB = SINH(MA). + + USE FMVALS + IMPLICIT NONE + + REAL (KIND(1.0D0)) :: MA(-1:LUNPKZ),MB(-1:LUNPKZ) + REAL (KIND(1.0D0)) :: MACCMB,MAIZ,MARZ,MXSAVE + INTEGER KASAVE,KOVUN,KRESLT,KRSAVE,NDSAVE + + CALL ZMENTR('ZMSINH',MA,MA,1,MB,KRESLT,NDSAVE,MXSAVE,KASAVE, & + KOVUN) + IF (KRESLT /= 0) RETURN + MARZ = MA(0) + MAIZ = MA(KPTIMU) + KACCSW = 0 + KRSAVE = KRAD + KRAD = 1 + + CALL ZMEQU(MA,MZ07,NDSAVE,NDIG) + +! Check for special cases. + + IF (MA(2) == 0 .AND. MA(KPTIMU+2) == 0) THEN + CALL ZMI2M(0,MZ01) + GO TO 110 + ELSE IF (MA(1) < (-NDIG) .AND. MA(KPTIMU+1) < (-NDIG)) THEN + CALL ZMEQ(MZ07,MZ01) + GO TO 110 + ELSE IF (MA(2) == 0) THEN + CALL FMSIN(MZ07(KPTIMU-1),MZ01(KPTIMU-1)) + CALL FMI2M(0,MZ01) + GO TO 110 + ELSE IF (MA(KPTIMU+2) == 0) THEN + CALL FMSINH(MZ07,MZ01) + CALL FMI2M(0,MZ01(KPTIMU-1)) + GO TO 110 + ENDIF + +! Find SIN(IMAG(MA)) and COS(IMAG(MA)). + + CALL FMCSSN(MZ07(KPTIMU-1),MZ01,MZ01(KPTIMU-1)) + +! Find SINH(REAL(MA)) and COSH(REAL(MA)). + + CALL FMCHSH(MZ07,M05,M06) + +! SINH(MA) = SINH(REAL(MA))*COS(IMAG(MA)) + +! COSH(REAL(MA))*SIN(IMAG(MA)) i + + CALL FMMPY_R1(MZ01,M06) + CALL FMMPY_R1(MZ01(KPTIMU-1),M05) + + 110 MACCMB = MZ01(0) + MZ01(0) = MIN(MACCMB,MARZ,MAIZ) + MACCMB = MZ01(KPTIMU) + MZ01(KPTIMU) = MIN(MACCMB,MARZ,MAIZ) + CALL ZMEXIT(MZ01,MB,NDSAVE,MXSAVE,KASAVE,KOVUN) + KRAD = KRSAVE + RETURN + END SUBROUTINE ZMSINH + + SUBROUTINE ZMSQR(MA,MB) + +! MB = MA * MA + + USE FMVALS + IMPLICIT NONE + + REAL (KIND(1.0D0)) :: MA(-1:LUNPKZ),MB(-1:LUNPKZ) + REAL (KIND(1.0D0)) :: MACCMB,MAIZ,MARZ,MXSAVE + INTEGER KASAVE,KOVUN,KRESLT,KWRNSV,NDGSV2,NDSAVE,NTRSAV + + IF (ABS(MA(1)) > MEXPAB .OR. ABS(MA(KPTIMU+1)) > MEXPAB .OR. & + KDEBUG >= 1) THEN + CALL ZMENTR('ZMSQR ',MA,MA,1,MB,KRESLT,NDSAVE,MXSAVE,KASAVE, & + KOVUN) + IF (KRESLT /= 0) RETURN + ELSE + NCALL = NCALL + 1 + IF (NTRACE /= 0) THEN + NAMEST(NCALL) = 'ZMSQR ' + CALL ZMNTR(2,MA,MA,1) + ENDIF + NDSAVE = NDIG + IF (NCALL == 1) THEN + NDIG = MAX(NDIG+NGRD52,2) + IF (NDIG > NDG2MX) THEN + NAMEST(NCALL) = 'ZMSQR ' + KFLAG = -9 + CALL ZMWARN + KRESLT = 12 + NDIG = NDSAVE + CALL ZMRSLT(MB,KRESLT) + IF (NTRACE /= 0) CALL ZMNTR(1,MB,MB,1) + NCALL = NCALL - 1 + RETURN + ENDIF + IF (MBASE >= 100*ABS(MA(2)) .OR. & + MBASE >= 100*ABS(MA(KPTIMU+2))) THEN + NDIG = MIN(NDIG+1,NDG2MX) + ENDIF + ENDIF + KASAVE = KACCSW + KACCSW = 0 + MXSAVE = MXEXP + MXEXP = MXEXP2 + KOVUN = 0 + ENDIF + IF (MBASE < 1000 .OR. KROUND /= 1 .OR. KRPERF == 1) THEN + IF (NCALL == 1) NDIG = MIN(NDG2MX,MAX(NDIG,2*NDSAVE+10)) + ENDIF + + MARZ = MA(0) + MAIZ = MA(KPTIMU) + NTRSAV = NTRACE + NTRACE = 0 + KWRNSV = KWARN + KWARN = 0 + + CALL ZMEQU(MA,MZ07,NDSAVE,NDIG) + IF (NCALL == 1) THEN + MZ07(0) = NINT(NDIG*ALOGM2) + MZ07(KPTIMU) = MZ07(0) + ENDIF + +! Check for special cases. + + IF (MA(KPTIMU+2) == 0) THEN + CALL FMSQR(MZ07,MZ01) + CALL FMI2M(0,MZ01(KPTIMU-1)) + ELSE IF (MA(2) == 0) THEN + CALL FMSQR(MZ07(KPTIMU-1),MZ01) + IF (MZ01(1) /= MUNKNO .AND. MZ01(2) /= 0) MZ01(-1) = -MZ01(-1) + CALL FMI2M(0,MZ01(KPTIMU-1)) + ELSE + CALL FMADD(MZ07,MZ07(KPTIMU-1),M02) + CALL FMSUB(MZ07,MZ07(KPTIMU-1),M03) + CALL FMMPY(M02,M03,MZ01) + CALL FMMPY(MZ07,MZ07(KPTIMU-1),M03) + CALL FMADD(M03,M03,MZ01(KPTIMU-1)) + ENDIF + + MXEXP = MXSAVE + NTRACE = NTRSAV + NDGSV2 = NDIG + NDIG = NDSAVE + KWARN = KWRNSV + MACCMB = MZ01(0) + MZ01(0) = MIN(MACCMB,MARZ,MAIZ) + MACCMB = MZ01(KPTIMU) + MZ01(KPTIMU) = MIN(MACCMB,MARZ,MAIZ) + KACCSW = KASAVE + CALL ZMEQ2(MZ01,MB,NDGSV2,NDSAVE) + IF (MB(1) >= MEXPOV .OR. MB(1) <= -MEXPOV .OR. & + MB(KPTIMU+1) >= MEXPOV .OR. MB(KPTIMU+1) <= -MEXPOV) THEN + IF (MB(1) == MUNKNO .OR. MB(KPTIMU+1) == MUNKNO) THEN + KFLAG = -4 + ELSE IF (MB(1) == MEXPOV .OR. MB(KPTIMU+1) == MEXPOV) THEN + KFLAG = -5 + ELSE IF (MB(1) == MEXPUN .OR. MB(KPTIMU+1) == MEXPUN) THEN + KFLAG = -6 + ENDIF + IF ((MB(1) == MUNKNO) & + .OR. (MB(KPTIMU+1) == MUNKNO) & + .OR. (MB(1) == MEXPUN .AND. KOVUN == 0) & + .OR. (MB(KPTIMU+1) == MEXPUN .AND. KOVUN == 0) & + .OR. (MB(1) == MEXPOV .AND. KOVUN == 0) & + .OR. (MB(KPTIMU+1) == MEXPOV .AND. KOVUN == 0)) THEN + NAMEST(NCALL) = 'ZMSQR ' + CALL ZMWARN + ENDIF + ENDIF + IF (NTRACE /= 0) CALL ZMNTR(1,MB,MB,1) + NCALL = NCALL - 1 + RETURN + END SUBROUTINE ZMSQR + + SUBROUTINE ZMSQRT(MA,MB) + +! MB = SQRT(MA). Principal Square Root. + + USE FMVALS + IMPLICIT NONE + + REAL (KIND(1.0D0)) :: MA(-1:LUNPKZ),MB(-1:LUNPKZ) + REAL (KIND(1.0D0)) :: MACCMB,MAIZ,MARZ,MXEXP1,MXSAVE + INTEGER KASAVE,KOVUN,KRESLT,KWRNSV,NDSAVE,NTRSAV + + IF (ABS(MA(1)) > MEXPAB .OR. ABS(MA(KPTIMU+1)) > MEXPAB .OR. & + KDEBUG >= 1) THEN + CALL ZMENTR('ZMSQRT',MA,MA,1,MB,KRESLT,NDSAVE,MXSAVE,KASAVE, & + KOVUN) + IF (KRESLT /= 0) RETURN + ELSE + NCALL = NCALL + 1 + IF (NTRACE /= 0) THEN + NAMEST(NCALL) = 'ZMSQRT' + CALL ZMNTR(2,MA,MA,1) + ENDIF + NDSAVE = NDIG + IF (NCALL == 1) THEN + NDIG = MAX(NDIG+NGRD52,2) + IF (NDIG > NDG2MX) THEN + NAMEST(NCALL) = 'ZMSQRT' + KFLAG = -9 + CALL ZMWARN + KRESLT = 12 + NDIG = NDSAVE + CALL ZMRSLT(MB,KRESLT) + IF (NTRACE /= 0) CALL ZMNTR(1,MB,MB,1) + NCALL = NCALL - 1 + RETURN + ENDIF + IF (MBASE >= 100*ABS(MA(2)) .OR. & + MBASE >= 100*ABS(MA(KPTIMU+2))) THEN + NDIG = MIN(NDIG+1,NDG2MX) + ENDIF + ENDIF + KASAVE = KACCSW + KACCSW = 0 + MXSAVE = MXEXP + MXEXP = MXEXP2 + KOVUN = 0 + ENDIF + IF (MBASE < 1000 .OR. KROUND /= 1 .OR. KRPERF == 1) THEN + IF (NCALL == 1) NDIG = MIN(NDG2MX,MAX(NDIG,2*NDSAVE+10)) + ENDIF + + NTRSAV = NTRACE + NTRACE = 0 + KWRNSV = KWARN + KWARN = 0 + MARZ = MA(0) + MAIZ = MA(KPTIMU) + + CALL ZMEQU(MA,MZ05,NDSAVE,NDIG) + +! Check for special cases. + + MXEXP1 = INT(MXEXP2/2.01D0) + IF (MA(2) == 0 .AND. MA(KPTIMU+2) == 0) THEN + CALL ZMI2M(0,MZ01) + GO TO 110 + ELSE IF (MA(2) == 0) THEN + CALL FMABS(MZ05(KPTIMU-1),M01) + CALL FMDIVI(M01,2,M03) + CALL FMSQRT_R1(M03) + ELSE IF (MA(KPTIMU+2) == 0) THEN + CALL FMABS(MZ05,M03) + CALL FMSQRT_R1(M03) + ELSE IF (MA(1) == MEXPUN) THEN + IF (MA(KPTIMU+1) <= -MXEXP1+NDIG+1) THEN + CALL ZMST2M('UNKNOWN + UNKNOWN i',MZ01) + GO TO 110 + ENDIF + ELSE IF (MA(KPTIMU+1) == MEXPUN) THEN + IF (MA(1) <= -MXEXP1+NDIG+1) THEN + CALL ZMST2M('UNKNOWN + UNKNOWN i',MZ01) + GO TO 110 + ENDIF + ELSE + CALL FMSQR(MZ05,M01) + CALL FMSQR(MZ05(KPTIMU-1),M02) + CALL FMADD(M01,M02,M03) + CALL FMSQRT_R1(M03) + CALL FMABS(MZ05,M02) + CALL FMADD_R2(M02,M03) + CALL FMDIVI_R1(M03,2) + CALL FMSQRT_R1(M03) + ENDIF + + CALL FMADD(M03,M03,M02) + IF (MA(-1) >= 0) THEN + CALL FMDIV(MZ05(KPTIMU-1),M02,MZ01(KPTIMU-1)) + CALL FMEQ(M03,MZ01) + ELSE + IF (MA(KPTIMU-1) >= 0) THEN + CALL FMDIV(MZ05(KPTIMU-1),M02,MZ01) + CALL FMEQ(M03,MZ01(KPTIMU-1)) + ELSE + CALL FMDIV(MZ05(KPTIMU-1),M02,MZ01) + CALL FMEQ(M03,MZ01(KPTIMU-1)) + IF (MZ01(1) /= MUNKNO .AND. MZ01(2) /= 0) MZ01(-1) = -MZ01(-1) + IF (MZ01(KPTIMU+1) /= MUNKNO .AND. MZ01(KPTIMU+2) /= 0) & + MZ01(KPTIMU-1) = -MZ01(KPTIMU-1) + ENDIF + ENDIF + + 110 MXEXP = MXSAVE + MACCMB = MZ01(0) + MZ01(0) = MIN(MACCMB,MARZ,MAIZ) + MACCMB = MZ01(KPTIMU) + MZ01(KPTIMU) = MIN(MACCMB,MARZ,MAIZ) + KACCSW = KASAVE + CALL ZMEQ2(MZ01,MB,NDIG,NDSAVE) + + IF (MB(1) == MUNKNO .OR. MB(KPTIMU+1) == MUNKNO) THEN + KFLAG = -4 + ELSE IF (MB(1) == MEXPOV .OR. MB(KPTIMU+1) == MEXPOV) THEN + KFLAG = -5 + ELSE IF (MB(1) == MEXPUN .OR. MB(KPTIMU+1) == MEXPUN) THEN + KFLAG = -6 + ENDIF + NTRACE = NTRSAV + NDIG = NDSAVE + KWARN = KWRNSV + IF ((MB(1) == MUNKNO) & + .OR. (MB(KPTIMU+1) == MUNKNO) & + .OR. (MB(1) == MEXPUN .AND. KOVUN == 0) & + .OR. (MB(KPTIMU+1) == MEXPUN .AND. KOVUN == 0) & + .OR. (MB(1) == MEXPOV .AND. KOVUN == 0) & + .OR. (MB(KPTIMU+1) == MEXPOV .AND. KOVUN == 0)) THEN + NAMEST(NCALL) = 'ZMSQRT' + CALL ZMWARN + ENDIF + IF (NTRACE /= 0) CALL ZMNTR(1,MB,MB,1) + NCALL = NCALL - 1 + RETURN + END SUBROUTINE ZMSQRT + + SUBROUTINE ZMST2M(STRING,MA) + +! MA = STRING + +! Convert a character string to FM format. +! This is often more convenient than using ZMINP, which converts an +! array of CHARACTER*1 values. + + USE FMVALS + IMPLICIT NONE + + CHARACTER(*) :: STRING + REAL (KIND(1.0D0)) :: MA(-1:LUNPKZ) + + INTEGER J,LB,KFSAVE + + NCALL = NCALL + 1 + NAMEST(NCALL) = 'ZMST2M' + LB = LEN(STRING) + KFSAVE = KFLAG + + DO J = 1, LB + CMBUFZ(J) = STRING(J:J) + ENDDO + + CALL ZMINP(CMBUFZ,MA,1,LB) + + IF (KFSAVE /= 0) KFLAG = KFSAVE + NCALL = NCALL - 1 + RETURN + END SUBROUTINE ZMST2M + + SUBROUTINE ZMSUB(MA,MB,MC) + +! MC = MA - MB + + USE FMVALS + IMPLICIT NONE + + REAL (KIND(1.0D0)) :: MA(-1:LUNPKZ),MB(-1:LUNPKZ),MC(-1:LUNPKZ) + + INTEGER KASAVE,KF1,KOVUN,KRESLT,KWRNSV,NDSAVE,NTRSAV + REAL (KIND(1.0D0)) :: MXSAVE + + IF (ABS(MA(1)) > MEXPAB .OR. ABS(MA(KPTIMU+1)) > MEXPAB .OR. & + ABS(MB(1)) > MEXPAB .OR. ABS(MB(KPTIMU+1)) > MEXPAB .OR. & + KDEBUG >= 1) THEN + CALL ZMENTR('ZMSUB ',MA,MB,2,MC,KRESLT,NDSAVE,MXSAVE,KASAVE, & + KOVUN) + IF (KRESLT /= 0) RETURN + NDIG = NDSAVE + MXEXP = MXSAVE + KACCSW = KASAVE + ELSE + NCALL = NCALL + 1 + IF (NTRACE /= 0) THEN + NAMEST(NCALL) = 'ZMSUB ' + CALL ZMNTR(2,MA,MB,2) + ENDIF + KOVUN = 0 + ENDIF + +! Force FMSUB to use more guard digits for user calls. + + NCALL = NCALL - 1 + NTRSAV = NTRACE + NTRACE = 0 + KWRNSV = KWARN + KWARN = 0 + + CALL FMSUB(MA,MB,MC) + KF1 = KFLAG + CALL FMSUB(MA(KPTIMU-1),MB(KPTIMU-1),MC(KPTIMU-1)) + + NTRACE = NTRSAV + KWARN = KWRNSV + NCALL = NCALL + 1 + IF (NTRACE /= 0) NAMEST(NCALL) = 'ZMSUB ' + IF (KFLAG == 1) KFLAG = KF1 + + IF (MC(1) == MUNKNO .OR. MC(KPTIMU+1) == MUNKNO) THEN + KFLAG = -4 + ELSE IF (MC(1) == MEXPOV .OR. MC(KPTIMU+1) == MEXPOV) THEN + KFLAG = -5 + ELSE IF (MC(1) == MEXPUN .OR. MC(KPTIMU+1) == MEXPUN) THEN + KFLAG = -6 + ENDIF + IF ((MC(1) == MUNKNO) & + .OR. (MC(KPTIMU+1) == MUNKNO) & + .OR. (MC(1) == MEXPUN .AND. KOVUN == 0) & + .OR. (MC(KPTIMU+1) == MEXPUN .AND. KOVUN == 0) & + .OR. (MC(1) == MEXPOV .AND. KOVUN == 0) & + .OR. (MC(KPTIMU+1) == MEXPOV .AND. KOVUN == 0)) THEN + NAMEST(NCALL) = 'ZMSUB ' + CALL ZMWARN + ENDIF + IF (NTRACE /= 0) CALL ZMNTR(1,MC,MC,1) + NCALL = NCALL - 1 + RETURN + END SUBROUTINE ZMSUB + + SUBROUTINE ZMTAN(MA,MB) + +! MB = TAN(MA). + + USE FMVALS + IMPLICIT NONE + + REAL (KIND(1.0D0)) :: MA(-1:LUNPKZ),MB(-1:LUNPKZ) + REAL (KIND(1.0D0)) :: MACCMB,MAIZ,MARZ,MXSAVE + INTEGER IEXTRA,KASAVE,KOVUN,KRESLT,KRSAVE,NDSAVE,NGOAL + + CALL ZMENTR('ZMTAN ',MA,MA,1,MB,KRESLT,NDSAVE,MXSAVE,KASAVE, & + KOVUN) + IF (KRESLT /= 0) RETURN + MARZ = MA(0) + MAIZ = MA(KPTIMU) + KRSAVE = KRAD + KRAD = 1 + + 110 CALL ZMEQU(MA,MZ07,NDSAVE,NDIG) + +! Check for special cases. + + IF (MA(2) == 0 .AND. MA(KPTIMU+2) == 0) THEN + CALL ZMI2M(0,MZ01) + GO TO 120 + ELSE IF (MA(1) < (-NDIG) .AND. MA(KPTIMU+1) < (-NDIG)) THEN + CALL ZMEQ(MZ07,MZ01) + GO TO 120 + ELSE IF (MA(KPTIMU+2) == 0) THEN + CALL FMTAN(MZ07,MZ01) + CALL FMI2M(0,MZ01(KPTIMU-1)) + GO TO 120 + ELSE IF (MA(2) == 0) THEN + CALL FMTANH(MZ07(KPTIMU-1),MZ01(KPTIMU-1)) + CALL FMI2M(0,MZ01) + GO TO 120 + ENDIF + +! Find SIN(2*REAL(MA)) and COS(2*REAL(MA)). + + CALL FMADD(MZ07,MZ07,MZ01) + CALL FMCSSN(MZ01,MZ01(KPTIMU-1),M06) + CALL FMEQ(M06,MZ01) + +! Find SINH(2*IMAG(MA)) and COSH(2*IMAG(MA)). + + CALL FMADD(MZ07(KPTIMU-1),MZ07(KPTIMU-1),M06) + CALL FMCHSH(M06,M05,M14) + CALL FMEQ(M14,M06) + +! TAN(MA) = SIN(2*REAL(MA)) / +! (COS(2*REAL(MA))+COSH(2*IMAG(MA)) + +! SINH(2*IMAG(MA)) / +! (COS(2*REAL(MA))+COSH(2*IMAG(MA)) i + + CALL FMADD_R2(MZ01(KPTIMU-1),M05) + IF (M05(2) == 0) THEN + MZ01(0) = 0 + NGOAL = INT(REAL(NDSAVE)*ALOGM2) + 7 + GO TO 130 + ELSE IF (M05(1) == MEXPOV) THEN + CALL FMDIV_R1(MZ01,M05) + CALL FMIM(1,MZ01(KPTIMU-1)) + IF (M06(-1) < 0 .AND. MZ01(KPTIMU+1) /= MUNKNO .AND. & + MZ01(KPTIMU+2) /= 0) MZ01(KPTIMU-1) = -MZ01(KPTIMU-1) + ELSE + CALL FMDIVD(MZ01,M06,M05,MZ08,MZ08(KPTIMU-1)) + CALL ZMEQ(MZ08,MZ01) + ENDIF + +! Check for too much cancellation. + + 120 IF (NCALL <= 1) THEN + NGOAL = INT(REAL(NDSAVE)*ALOGM2) + 7 + ELSE + NGOAL = INT(-MXEXP2) + ENDIF + 130 IF (MZ01(0) <= NGOAL .OR. MZ01(KPTIMU) <= NGOAL) THEN + IEXTRA = INT(REAL(MAX(NGOAL-MZ01(0),NGOAL-MZ01(KPTIMU))) & + /ALOGM2 + 23.03/ALOGMB) + 1 + NDIG = NDIG + IEXTRA + IF (NDIG > NDG2MX) THEN + KFLAG = -9 + CALL ZMWARN + NDIG = NDIG - IEXTRA + CALL ZMST2M('UNKNOWN+UNKNOWN*i',MZ01) + GO TO 140 + ENDIF + GO TO 110 + ENDIF + + 140 MACCMB = MZ01(0) + MZ01(0) = MIN(MACCMB,MARZ,MAIZ) + MACCMB = MZ01(KPTIMU) + MZ01(KPTIMU) = MIN(MACCMB,MARZ,MAIZ) + CALL ZMEXIT(MZ01,MB,NDSAVE,MXSAVE,KASAVE,KOVUN) + KRAD = KRSAVE + RETURN + END SUBROUTINE ZMTAN + + SUBROUTINE ZMTANH(MA,MB) + +! MB = TANH(MA). + + USE FMVALS + IMPLICIT NONE + + REAL (KIND(1.0D0)) :: MA(-1:LUNPKZ),MB(-1:LUNPKZ) + REAL (KIND(1.0D0)) :: MACCMB,MAIZ,MARZ,MXSAVE + INTEGER IEXTRA,KASAVE,KOVUN,KRESLT,KRSAVE,NDSAVE,NGOAL + + CALL ZMENTR('ZMTANH',MA,MA,1,MB,KRESLT,NDSAVE,MXSAVE,KASAVE, & + KOVUN) + IF (KRESLT /= 0) RETURN + MARZ = MA(0) + MAIZ = MA(KPTIMU) + KRSAVE = KRAD + KRAD = 1 + + 110 CALL ZMEQU(MA,MZ07,NDSAVE,NDIG) + +! Check for special cases. + + IF (MA(2) == 0 .AND. MA(KPTIMU+2) == 0) THEN + CALL ZMI2M(0,MZ01) + GO TO 120 + ELSE IF (MA(1) < (-NDIG) .AND. MA(KPTIMU+1) < (-NDIG)) THEN + CALL ZMEQ(MZ07,MZ01) + GO TO 120 + ELSE IF (MA(2) == 0) THEN + CALL FMTAN(MZ07(KPTIMU-1),MZ01(KPTIMU-1)) + CALL FMI2M(0,MZ01) + GO TO 120 + ELSE IF (MA(KPTIMU+2) == 0) THEN + CALL FMTANH(MZ07,MZ01) + CALL FMI2M(0,MZ01(KPTIMU-1)) + GO TO 120 + ENDIF + +! Find SIN(2*IMAG(MA)) and COS(2*IMAG(MA)). + + CALL FMADD(MZ07(KPTIMU-1),MZ07(KPTIMU-1),MZ01) + CALL FMCSSN(MZ01,MZ01(KPTIMU-1),M06) + CALL FMEQ(M06,MZ01) + +! Find SINH(2*REAL(MA)) and COSH(2*REAL(MA)). + + CALL FMADD(MZ07,MZ07,M06) + CALL FMCHSH(M06,M05,M14) + CALL FMEQ(M14,M06) + +! TANH(MA) = SINH(2*REAL(MA)) / +! (COS(2*IMAG(MA))+COSH(2*REAL(MA)) + +! SIN(2*IMAG(MA)) / +! (COS(2*IMAG(MA))+COSH(2*REAL(MA)) i + + CALL FMADD_R2(MZ01(KPTIMU-1),M05) + IF (M05(2) == 0) THEN + MZ01(0) = 0 + NGOAL = INT(REAL(NDSAVE)*ALOGM2) + 7 + GO TO 130 + ELSE IF (M05(1) == MEXPOV) THEN + CALL FMDIV(MZ01,M05,MZ01(KPTIMU-1)) + CALL FMIM(1,MZ01) + IF (M06(-1) < 0) MZ01(-1) = -1 + ELSE + CALL FMDIVD(MZ01,M06,M05,MZ08(KPTIMU-1),MZ08) + CALL ZMEQ(MZ08,MZ01) + ENDIF + +! Check for too much cancellation. + + 120 IF (NCALL <= 1) THEN + NGOAL = INT(REAL(NDSAVE)*ALOGM2) + 7 + ELSE + NGOAL = INT(-MXEXP2) + ENDIF + 130 IF (MZ01(0) <= NGOAL .OR. MZ01(KPTIMU) <= NGOAL) THEN + IEXTRA = INT(REAL(MAX(NGOAL-MZ01(0),NGOAL-MZ01(KPTIMU))) & + /ALOGM2 + 23.03/ALOGMB) + 1 + NDIG = NDIG + IEXTRA + IF (NDIG > NDG2MX) THEN + KFLAG = -9 + CALL ZMWARN + NDIG = NDIG - IEXTRA + CALL ZMST2M('UNKNOWN+UNKNOWN*i',MZ01) + GO TO 140 + ENDIF + GO TO 110 + ENDIF + + 140 MACCMB = MZ01(0) + MZ01(0) = MIN(MACCMB,MARZ,MAIZ) + MACCMB = MZ01(KPTIMU) + MZ01(KPTIMU) = MIN(MACCMB,MARZ,MAIZ) + CALL ZMEXIT(MZ01,MB,NDSAVE,MXSAVE,KASAVE,KOVUN) + KRAD = KRSAVE + RETURN + END SUBROUTINE ZMTANH + + SUBROUTINE ZMUNPK(MP,MA) + +! MP is unpacked and the value returned in MA. + + USE FMVALS + IMPLICIT NONE + + REAL (KIND(1.0D0)) :: MA(-1:LUNPKZ),MP(-1:LPACKZ) + + CALL FMUNPK(MP,MA) + CALL FMUNPK(MP(KPTIMP),MA(KPTIMU-1)) + RETURN + END SUBROUTINE ZMUNPK + + SUBROUTINE ZMWARN + +! Called by one of the ZM routines to print a warning message +! if any error condition arises in that routine. + + USE FMVALS + IMPLICIT NONE + + CHARACTER(6) :: NAME + + INTEGER NCS + + IF (KFLAG >= 0 .OR. NCALL /= 1 .OR. KWARN <= 0) RETURN + NCS = NCALL + NAME = NAMEST(NCALL) + WRITE (KW,"(/' Error of type KFLAG =',I3," // & + "' in FM package in routine ',A6/)" & + ) KFLAG,NAME + + 110 NCALL = NCALL - 1 + IF (NCALL > 0) THEN + NAME = NAMEST(NCALL) + WRITE (KW,"( ' called from ',A6)") NAME + GO TO 110 + ENDIF + + IF (KFLAG == -1) THEN + WRITE (KW,"(' NDIG must be between 2 and',I10/)") NDIGMX + ELSE IF (KFLAG == -2) THEN + WRITE (KW,"(' MBASE must be between 2 and',I10/)") INT(MXBASE) + ELSE IF (KFLAG == -3) THEN + WRITE (KW, & + "(' An input argument is not a valid FM number.'," // & + "' Its exponent is out of range.'/)" & + ) + WRITE (KW,"(' UNKNOWN has been returned.'/)") + ELSE IF (KFLAG == -4 .OR. KFLAG == -7) THEN + WRITE (KW,"(' Invalid input argument for this routine.'/)") + WRITE (KW,"(' UNKNOWN has been returned.'/)") + ELSE IF (KFLAG == -5) THEN + WRITE (KW,"(' The result has overflowed.'/)") + ELSE IF (KFLAG == -6) THEN + WRITE (KW,"(' The result has underflowed.'/)") + ELSE IF (KFLAG == -8 .AND. NAME == 'ZMOUT ') THEN + WRITE (KW, & + "(' The result array is not big enough to hold the'," // & + "' output character string'/' in the current format.'/" // & + "' The result ''***...***'' has been returned.'/)" & + ) + ELSE IF (KFLAG == -8 .AND. NAME == 'ZMREAD') THEN + WRITE (KW, & + "(' The CMBUFF array is not big enough to hold the'," // & + "' input character string'/" // & + "' UNKNOWN has been returned.'/)" & + ) + ELSE IF (KFLAG == -9) THEN + WRITE (KW, & + "(' Precision could not be raised enough to'" // & + ",' provide all requested guard digits.'/)" & + ) + WRITE (KW, & + "(I23,' digits were requested (NDIG).'/" // & + "' Maximum number of digits currently available'," // & + "' (NDG2MX) is',I7,'.'/)" & + ) NDIG,NDG2MX + WRITE (KW,"(' UNKNOWN has been returned.'/)") + ENDIF + + NCALL = NCS + IF (KWARN >= 2) THEN + STOP + ENDIF + RETURN + END SUBROUTINE ZMWARN + + SUBROUTINE ZMWRIT(KWRITE,MA) + +! Write MA on unit KWRITE under the current format. Multi-line numbers +! will have '&' as the last nonblank character on all but the last +! line of the real part and the imaginary part. +! These numbers can then be read easily using ZMREAD. + + USE FMVALS + IMPLICIT NONE + + INTEGER KWRITE + REAL (KIND(1.0D0)) :: MA(-1:LUNPKZ) + + INTEGER J,K,KSAVE,L,LAST,LAST1,LAST2,LB,ND,NEXP + + NCALL = NCALL + 1 + NAMEST(NCALL) = 'ZMWRIT' + KSAVE = KFLAG + ND = INT(REAL(NDIG)*LOG10(REAL(MBASE))) + 1 + IF (ND < 2) ND = 2 + NEXP = INT(2.0*LOG10(REAL(MXBASE))) + 6 + LB = 2*MAX(JFORM2+NEXP,ND+NEXP) + 3 + LB = MIN(LB,LMBUFZ) + CALL ZMOUT(MA,CMBUFZ,LB,LAST1,LAST2) + KFLAG = KSAVE + LAST = LAST2 + 1 + DO J = 1, LAST2 + IF (CMBUFZ(LAST-J) /= ' ' .OR. J == LAST2) THEN + L = LAST - J + IF (MOD(L,73) /= 0) THEN + WRITE (KWRITE,"(4X,73A1,' &')") (CMBUFZ(K),K=1,L) + ELSE + WRITE (KWRITE,"(4X,73A1,' &')") (CMBUFZ(K),K=1,L-73) + WRITE (KWRITE,"(4X,73A1)") (CMBUFZ(K),K=L-72,L) + ENDIF + NCALL = NCALL - 1 + RETURN + ENDIF + ENDDO + NCALL = NCALL - 1 + RETURN + END SUBROUTINE ZMWRIT + + SUBROUTINE ZMZ2M(ZVAL,MA) + +! MA = ZVAL + +! ZVAL is complex and is converted to ZM form. + + USE FMVALS + IMPLICIT NONE + + COMPLEX ZVAL + REAL (KIND(1.0D0)) :: MA(-1:LUNPKZ) + + NCALL = NCALL + 1 + NAMEST(NCALL) = 'ZMZ2M ' + IF (NTRACE /= 0) CALL ZMNTRZ(2,ZVAL,1) + + CALL FMSP2M(REAL(ZVAL),MA) + CALL FMSP2M(AIMAG(ZVAL),MA(KPTIMU-1)) + + IF (NTRACE /= 0) CALL ZMNTR(1,MA,MA,1) + NCALL = NCALL - 1 + RETURN + END SUBROUTINE ZMZ2M + +! Here are the routines which work with packed ZM numbers. All names +! are the same as unpacked versions with 'ZM' replaced by 'ZP'. + +! To convert a program using the ZM package from unpacked calls to +! packed calls make these changes to the program: +! '(-1:LUNPKZ)' to '(-1:LUNPKZ)' in dimensions. +! 'CALL ZM' to 'CALL ZP' + +! This packed format is not available when using the FM, IM, or ZM +! derived types. + + + SUBROUTINE ZPABS(MA,MBFM) + USE FMVALS + IMPLICIT NONE + REAL (KIND(1.0D0)) :: MA(-1:LPACKZ),MBFM(-1:LPACK) + CALL ZMUNPK(MA,MPX) + CALL ZMABS(MPX,MPA) + CALL FMPACK(MPA,MBFM) + RETURN + END SUBROUTINE ZPABS + + SUBROUTINE ZPACOS(MA,MB) + USE FMVALS + IMPLICIT NONE + REAL (KIND(1.0D0)) :: MA(-1:LPACKZ),MB(-1:LPACKZ) + CALL ZMUNPK(MA,MPX) + CALL ZMACOS(MPX,MPY) + CALL ZMPACK(MPY,MB) + RETURN + END SUBROUTINE ZPACOS + + SUBROUTINE ZPADD(MA,MB,MC) + USE FMVALS + IMPLICIT NONE + REAL (KIND(1.0D0)) :: MA(-1:LPACKZ),MB(-1:LPACKZ),MC(-1:LPACKZ) + CALL ZMUNPK(MA,MPX) + CALL ZMUNPK(MB,MPY) + CALL ZMADD(MPX,MPY,MPZ) + CALL ZMPACK(MPZ,MC) + RETURN + END SUBROUTINE ZPADD + + SUBROUTINE ZPADDI(MA,INTEG) + USE FMVALS + IMPLICIT NONE + REAL (KIND(1.0D0)) :: MA(-1:LPACKZ) + INTEGER INTEG + CALL ZMUNPK(MA,MPX) + CALL ZMADDI(MPX,INTEG) + CALL ZMPACK(MPX,MA) + RETURN + END SUBROUTINE ZPADDI + + SUBROUTINE ZPARG(MA,MBFM) + USE FMVALS + IMPLICIT NONE + REAL (KIND(1.0D0)) :: MA(-1:LPACKZ),MBFM(-1:LPACK) + CALL ZMUNPK(MA,MPX) + CALL ZMARG(MPX,MPA) + CALL FMPACK(MPA,MBFM) + RETURN + END SUBROUTINE ZPARG + + SUBROUTINE ZPASIN(MA,MB) + USE FMVALS + IMPLICIT NONE + REAL (KIND(1.0D0)) :: MA(-1:LPACKZ),MB(-1:LPACKZ) + CALL ZMUNPK(MA,MPX) + CALL ZMASIN(MPX,MPY) + CALL ZMPACK(MPY,MB) + RETURN + END SUBROUTINE ZPASIN + + SUBROUTINE ZPATAN(MA,MB) + USE FMVALS + IMPLICIT NONE + REAL (KIND(1.0D0)) :: MA(-1:LPACKZ),MB(-1:LPACKZ) + CALL ZMUNPK(MA,MPX) + CALL ZMATAN(MPX,MPY) + CALL ZMPACK(MPY,MB) + RETURN + END SUBROUTINE ZPATAN + + SUBROUTINE ZPCHSH(MA,MB,MC) + USE FMVALS + IMPLICIT NONE + REAL (KIND(1.0D0)) :: MA(-1:LPACKZ),MB(-1:LPACKZ),MC(-1:LPACKZ) + CALL ZMUNPK(MA,MPX) + CALL ZMCHSH(MPX,MPY,MPZ) + CALL ZMPACK(MPY,MB) + CALL ZMPACK(MPZ,MC) + RETURN + END SUBROUTINE ZPCHSH + + SUBROUTINE ZPCMPX(MAFM,MBFM,MC) + USE FMVALS + IMPLICIT NONE + REAL (KIND(1.0D0)) :: MAFM(-1:LPACK),MBFM(-1:LPACK),MC(-1:LPACKZ) + CALL FMUNPK(MAFM,MPA) + CALL FMUNPK(MBFM,MPB) + CALL ZMCMPX(MPA,MPB,MPX) + CALL ZMPACK(MPX,MC) + RETURN + END SUBROUTINE ZPCMPX + + SUBROUTINE ZPCONJ(MA,MB) + USE FMVALS + IMPLICIT NONE + REAL (KIND(1.0D0)) :: MA(-1:LPACKZ),MB(-1:LPACKZ) + CALL ZMUNPK(MA,MPX) + CALL ZMCONJ(MPX,MPY) + CALL ZMPACK(MPY,MB) + RETURN + END SUBROUTINE ZPCONJ + + SUBROUTINE ZPCOS(MA,MB) + USE FMVALS + IMPLICIT NONE + REAL (KIND(1.0D0)) :: MA(-1:LPACKZ),MB(-1:LPACKZ) + CALL ZMUNPK(MA,MPX) + CALL ZMCOS(MPX,MPY) + CALL ZMPACK(MPY,MB) + RETURN + END SUBROUTINE ZPCOS + + SUBROUTINE ZPCOSH(MA,MB) + USE FMVALS + IMPLICIT NONE + REAL (KIND(1.0D0)) :: MA(-1:LPACKZ),MB(-1:LPACKZ) + CALL ZMUNPK(MA,MPX) + CALL ZMCOSH(MPX,MPY) + CALL ZMPACK(MPY,MB) + RETURN + END SUBROUTINE ZPCOSH + + SUBROUTINE ZPCSSN(MA,MB,MC) + USE FMVALS + IMPLICIT NONE + REAL (KIND(1.0D0)) :: MA(-1:LPACKZ),MB(-1:LPACKZ),MC(-1:LPACKZ) + CALL ZMUNPK(MA,MPX) + CALL ZMCSSN(MPX,MPY,MPZ) + CALL ZMPACK(MPY,MB) + CALL ZMPACK(MPZ,MC) + RETURN + END SUBROUTINE ZPCSSN + + SUBROUTINE ZPDIV(MA,MB,MC) + USE FMVALS + IMPLICIT NONE + REAL (KIND(1.0D0)) :: MA(-1:LPACKZ),MB(-1:LPACKZ),MC(-1:LPACKZ) + CALL ZMUNPK(MA,MPX) + CALL ZMUNPK(MB,MPY) + CALL ZMDIV(MPX,MPY,MPZ) + CALL ZMPACK(MPZ,MC) + RETURN + END SUBROUTINE ZPDIV + + SUBROUTINE ZPDIVI(MA,INTEG,MB) + USE FMVALS + IMPLICIT NONE + REAL (KIND(1.0D0)) :: MA(-1:LPACKZ),MB(-1:LPACKZ) + INTEGER INTEG + CALL ZMUNPK(MA,MPX) + CALL ZMDIVI(MPX,INTEG,MPY) + CALL ZMPACK(MPY,MB) + RETURN + END SUBROUTINE ZPDIVI + + SUBROUTINE ZPEQ(MA,MB) + USE FMVALS + IMPLICIT NONE + REAL (KIND(1.0D0)) :: MA(-1:LPACKZ),MB(-1:LPACKZ) + CALL FPEQ(MA,MB) + CALL FPEQ(MA(KPTIMP),MB(KPTIMP)) + RETURN + END SUBROUTINE ZPEQ + + SUBROUTINE ZPEQU(MA,MB,NDA,NDB) + USE FMVALS + IMPLICIT NONE + REAL (KIND(1.0D0)) :: MA(-1:LPACKZ),MB(-1:LPACKZ) + INTEGER NDA,NDB + CALL FPEQU(MA,MB,NDA,NDB) + CALL FPEQU(MA(KPTIMP),MB(KPTIMP),NDA,NDB) + RETURN + END SUBROUTINE ZPEQU + + SUBROUTINE ZPEXP(MA,MB) + USE FMVALS + IMPLICIT NONE + REAL (KIND(1.0D0)) :: MA(-1:LPACKZ),MB(-1:LPACKZ) + CALL ZMUNPK(MA,MPX) + CALL ZMEXP(MPX,MPY) + CALL ZMPACK(MPY,MB) + RETURN + END SUBROUTINE ZPEXP + + SUBROUTINE ZPFORM(FORM1,FORM2,MA,STRING) + USE FMVALS + IMPLICIT NONE + REAL (KIND(1.0D0)) :: MA(-1:LPACKZ) + CHARACTER(*) :: FORM1,FORM2,STRING + CALL ZMUNPK(MA,MPX) + CALL ZMFORM(FORM1,FORM2,MPX,STRING) + RETURN + END SUBROUTINE ZPFORM + + SUBROUTINE ZPFPRT(FORM1,FORM2,MA) + USE FMVALS + IMPLICIT NONE + REAL (KIND(1.0D0)) :: MA(-1:LPACKZ) + CHARACTER(*) :: FORM1,FORM2 + CALL ZMUNPK(MA,MPX) + CALL ZMFPRT(FORM1,FORM2,MPX) + RETURN + END SUBROUTINE ZPFPRT + + SUBROUTINE ZP2I2M(INTEG1,INTEG2,MA) + USE FMVALS + IMPLICIT NONE + INTEGER INTEG1,INTEG2 + REAL (KIND(1.0D0)) :: MA(-1:LPACKZ) + CALL ZM2I2M(INTEG1,INTEG2,MPX) + CALL ZMPACK(MPX,MA) + RETURN + END SUBROUTINE ZP2I2M + + SUBROUTINE ZPI2M(INTEG,MA) + USE FMVALS + IMPLICIT NONE + INTEGER INTEG + REAL (KIND(1.0D0)) :: MA(-1:LPACKZ) + CALL ZMI2M(INTEG,MPX) + CALL ZMPACK(MPX,MA) + RETURN + END SUBROUTINE ZPI2M + + SUBROUTINE ZPIMAG(MA,MBFM) + USE FMVALS + IMPLICIT NONE + REAL (KIND(1.0D0)) :: MA(-1:LPACKZ),MBFM(-1:LPACK) + CALL ZMUNPK(MA,MPX) + CALL ZMIMAG(MPX,MPA) + CALL FMPACK(MPA,MBFM) + RETURN + END SUBROUTINE ZPIMAG + + SUBROUTINE ZPINT(MA,MB) + USE FMVALS + IMPLICIT NONE + REAL (KIND(1.0D0)) :: MA(-1:LPACKZ),MB(-1:LPACKZ) + CALL ZMUNPK(MA,MPX) + CALL ZMINT(MPX,MPY) + CALL ZMPACK(MPY,MB) + RETURN + END SUBROUTINE ZPINT + + SUBROUTINE ZPINP(LINE,MA,LA,LB) + USE FMVALS + IMPLICIT NONE + INTEGER LA,LB + CHARACTER LINE(LB) + REAL (KIND(1.0D0)) :: MA(-1:LPACKZ) + CALL ZMINP(LINE,MPX,LA,LB) + CALL ZMPACK(MPX,MA) + RETURN + END SUBROUTINE ZPINP + + SUBROUTINE ZPIPWR(MA,INTEG,MB) + USE FMVALS + IMPLICIT NONE + REAL (KIND(1.0D0)) :: MA(-1:LPACKZ),MB(-1:LPACKZ) + INTEGER INTEG + CALL ZMUNPK(MA,MPX) + CALL ZMIPWR(MPX,INTEG,MPY) + CALL ZMPACK(MPY,MB) + RETURN + END SUBROUTINE ZPIPWR + + SUBROUTINE ZPLG10(MA,MB) + USE FMVALS + IMPLICIT NONE + REAL (KIND(1.0D0)) :: MA(-1:LPACKZ),MB(-1:LPACKZ) + CALL ZMUNPK(MA,MPX) + CALL ZMLG10(MPX,MPY) + CALL ZMPACK(MPY,MB) + RETURN + END SUBROUTINE ZPLG10 + + SUBROUTINE ZPLN(MA,MB) + USE FMVALS + IMPLICIT NONE + REAL (KIND(1.0D0)) :: MA(-1:LPACKZ),MB(-1:LPACKZ) + CALL ZMUNPK(MA,MPX) + CALL ZMLN(MPX,MPY) + CALL ZMPACK(MPY,MB) + RETURN + END SUBROUTINE ZPLN + + SUBROUTINE ZPM2I(MA,INTEG) + USE FMVALS + IMPLICIT NONE + REAL (KIND(1.0D0)) :: MA(-1:LPACKZ) + INTEGER INTEG + CALL ZMUNPK(MA,MPX) + CALL ZMM2I(MPX,INTEG) + RETURN + END SUBROUTINE ZPM2I + + SUBROUTINE ZPM2Z(MA,ZVAL) + USE FMVALS + IMPLICIT NONE + COMPLEX ZVAL + REAL (KIND(1.0D0)) :: MA(-1:LPACKZ) + CALL ZMUNPK(MA,MPX) + CALL ZMM2Z(MPX,ZVAL) + RETURN + END SUBROUTINE ZPM2Z + + SUBROUTINE ZPMPY(MA,MB,MC) + USE FMVALS + IMPLICIT NONE + REAL (KIND(1.0D0)) :: MA(-1:LPACKZ),MB(-1:LPACKZ),MC(-1:LPACKZ) + CALL ZMUNPK(MA,MPX) + CALL ZMUNPK(MB,MPY) + CALL ZMMPY(MPX,MPY,MPZ) + CALL ZMPACK(MPZ,MC) + RETURN + END SUBROUTINE ZPMPY + + SUBROUTINE ZPMPYI(MA,INTEG,MB) + USE FMVALS + IMPLICIT NONE + REAL (KIND(1.0D0)) :: MA(-1:LPACKZ),MB(-1:LPACKZ) + INTEGER INTEG + CALL ZMUNPK(MA,MPX) + CALL ZMMPYI(MPX,INTEG,MPY) + CALL ZMPACK(MPY,MB) + RETURN + END SUBROUTINE ZPMPYI + + SUBROUTINE ZPNINT(MA,MB) + USE FMVALS + IMPLICIT NONE + REAL (KIND(1.0D0)) :: MA(-1:LPACKZ),MB(-1:LPACKZ) + CALL ZMUNPK(MA,MPX) + CALL ZMNINT(MPX,MPY) + CALL ZMPACK(MPY,MB) + RETURN + END SUBROUTINE ZPNINT + + SUBROUTINE ZPOUT(MA,LINE,LB,LAST1,LAST2) + USE FMVALS + IMPLICIT NONE + REAL (KIND(1.0D0)) :: MA(-1:LPACKZ) + INTEGER LB,LAST1,LAST2 + CHARACTER LINE(LB) + CALL ZMUNPK(MA,MPX) + CALL ZMOUT(MPX,LINE,LB,LAST1,LAST2) + RETURN + END SUBROUTINE ZPOUT + + SUBROUTINE ZPPRNT(MA) + USE FMVALS + IMPLICIT NONE + REAL (KIND(1.0D0)) :: MA(-1:LPACKZ) + CALL ZMUNPK(MA,MPX) + CALL ZMPRNT(MPX) + RETURN + END SUBROUTINE ZPPRNT + + SUBROUTINE ZPPWR(MA,MB,MC) + USE FMVALS + IMPLICIT NONE + REAL (KIND(1.0D0)) :: MA(-1:LPACKZ),MB(-1:LPACKZ),MC(-1:LPACKZ) + CALL ZMUNPK(MA,MPX) + CALL ZMUNPK(MB,MPY) + CALL ZMPWR(MPX,MPY,MPZ) + CALL ZMPACK(MPZ,MC) + RETURN + END SUBROUTINE ZPPWR + + SUBROUTINE ZPREAD(KREAD,MA) + USE FMVALS + IMPLICIT NONE + INTEGER KREAD + REAL (KIND(1.0D0)) :: MA(-1:LPACKZ) + CALL ZMREAD(KREAD,MPX) + CALL ZMPACK(MPX,MA) + RETURN + END SUBROUTINE ZPREAD + + SUBROUTINE ZPREAL(MA,MBFM) + USE FMVALS + IMPLICIT NONE + REAL (KIND(1.0D0)) :: MA(-1:LPACKZ),MBFM(-1:LPACK) + CALL ZMUNPK(MA,MPX) + CALL ZMREAL(MPX,MPA) + CALL FMPACK(MPA,MBFM) + RETURN + END SUBROUTINE ZPREAL + + SUBROUTINE ZPRPWR(MA,IVAL,JVAL,MB) + USE FMVALS + IMPLICIT NONE + REAL (KIND(1.0D0)) :: MA(-1:LPACKZ),MB(-1:LPACKZ) + INTEGER IVAL,JVAL + CALL ZMUNPK(MA,MPX) + CALL ZMRPWR(MPX,IVAL,JVAL,MPY) + CALL ZMPACK(MPY,MB) + RETURN + END SUBROUTINE ZPRPWR + + SUBROUTINE ZPSET(NPREC) + USE FMVALS + IMPLICIT NONE + INTEGER NPREC + CALL ZMSET(NPREC) + RETURN + END SUBROUTINE ZPSET + + SUBROUTINE ZPSIN(MA,MB) + USE FMVALS + IMPLICIT NONE + REAL (KIND(1.0D0)) :: MA(-1:LPACKZ),MB(-1:LPACKZ) + CALL ZMUNPK(MA,MPX) + CALL ZMSIN(MPX,MPY) + CALL ZMPACK(MPY,MB) + RETURN + END SUBROUTINE ZPSIN + + SUBROUTINE ZPSINH(MA,MB) + USE FMVALS + IMPLICIT NONE + REAL (KIND(1.0D0)) :: MA(-1:LPACKZ),MB(-1:LPACKZ) + CALL ZMUNPK(MA,MPX) + CALL ZMSINH(MPX,MPY) + CALL ZMPACK(MPY,MB) + RETURN + END SUBROUTINE ZPSINH + + SUBROUTINE ZPSQR(MA,MB) + USE FMVALS + IMPLICIT NONE + REAL (KIND(1.0D0)) :: MA(-1:LPACKZ),MB(-1:LPACKZ) + CALL ZMUNPK(MA,MPX) + CALL ZMSQR(MPX,MPY) + CALL ZMPACK(MPY,MB) + RETURN + END SUBROUTINE ZPSQR + + SUBROUTINE ZPSQRT(MA,MB) + USE FMVALS + IMPLICIT NONE + REAL (KIND(1.0D0)) :: MA(-1:LPACKZ),MB(-1:LPACKZ) + CALL ZMUNPK(MA,MPX) + CALL ZMSQRT(MPX,MPY) + CALL ZMPACK(MPY,MB) + RETURN + END SUBROUTINE ZPSQRT + + SUBROUTINE ZPST2M(STRING,MA) + USE FMVALS + IMPLICIT NONE + CHARACTER(*) :: STRING + REAL (KIND(1.0D0)) :: MA(-1:LPACKZ) + CALL ZMST2M(STRING,MPX) + CALL ZMPACK(MPX,MA) + RETURN + END SUBROUTINE ZPST2M + + SUBROUTINE ZPSUB(MA,MB,MC) + USE FMVALS + IMPLICIT NONE + REAL (KIND(1.0D0)) :: MA(-1:LPACKZ),MB(-1:LPACKZ),MC(-1:LPACKZ) + CALL ZMUNPK(MA,MPX) + CALL ZMUNPK(MB,MPY) + CALL ZMSUB(MPX,MPY,MPZ) + CALL ZMPACK(MPZ,MC) + RETURN + END SUBROUTINE ZPSUB + + SUBROUTINE ZPTAN(MA,MB) + USE FMVALS + IMPLICIT NONE + REAL (KIND(1.0D0)) :: MA(-1:LPACKZ),MB(-1:LPACKZ) + CALL ZMUNPK(MA,MPX) + CALL ZMTAN(MPX,MPY) + CALL ZMPACK(MPY,MB) + RETURN + END SUBROUTINE ZPTAN + + SUBROUTINE ZPTANH(MA,MB) + USE FMVALS + IMPLICIT NONE + REAL (KIND(1.0D0)) :: MA(-1:LPACKZ),MB(-1:LPACKZ) + CALL ZMUNPK(MA,MPX) + CALL ZMTANH(MPX,MPY) + CALL ZMPACK(MPY,MB) + RETURN + END SUBROUTINE ZPTANH + + SUBROUTINE ZPWRIT(KWRITE,MA) + USE FMVALS + IMPLICIT NONE + INTEGER KWRITE + REAL (KIND(1.0D0)) :: MA(-1:LPACKZ) + CALL ZMUNPK(MA,MPX) + CALL ZMWRIT(KWRITE,MPX) + RETURN + END SUBROUTINE ZPWRIT + + SUBROUTINE ZPZ2M(ZVAL,MA) + USE FMVALS + IMPLICIT NONE + COMPLEX ZVAL + REAL (KIND(1.0D0)) :: MA(-1:LPACKZ) + CALL ZMZ2M(ZVAL,MPX) + CALL ZMPACK(MPX,MA) + RETURN + END SUBROUTINE ZPZ2M + +! These FM routines perform the Gamma and Related Functions. + + + SUBROUTINE FMARG2(KROUTN,NARGS,MA,MB,KRESLT) + +! Check the input arguments to a routine for special cases. + +! KROUTN - Name of the subroutine that was called +! NARGS - The number of input arguments (1 or 2) +! MA - First input argument +! MB - Second input argument (if NARGS is 2) +! KRESLT - Result code returned to the calling routine. + + USE FMVALS + IMPLICIT NONE + + CHARACTER(6) :: KROUTN + REAL (KIND(1.0D0)) :: MA(-1:LUNPCK),MB(-1:LUNPCK) + INTEGER NARGS,KRESLT + + INTEGER NCATMA,NCATMB + + INTEGER, PARAMETER :: & + KFACT(15) = (/ 12,12, 0,12, 0, 0, 8, 8, 8, 0, 0, 8, 0, 4, 4 /), & + KGAM(15) = (/ 12,12, 0,12, 0, 0, 3,12, 4, 0, 0, 8, 0, 4, 4 /), & + KLNGM(15) = (/ 12,12, 0,12,12,12,12,12,12, 0, 0,11, 0, 0, 4 /), & + KPSI(15) = (/ 12,12, 0,12, 0, 0, 4,12, 3, 0, 0, 0, 0, 0,12 /) + + CALL FMARGS(KROUTN,NARGS,MA,MB,KRESLT) + IF (KFLAG /= 0) RETURN + +! Check for special cases. + + CALL FMCAT(MA,NCATMA) + NCATMB = 0 + IF (NARGS == 2) CALL FMCAT(MB,NCATMB) + + IF (KROUTN == 'FMFACT') THEN + KRESLT = KFACT(NCATMA) + GO TO 110 + ENDIF + + IF (KROUTN == 'FMGAM ') THEN + KRESLT = KGAM(NCATMA) + GO TO 110 + ENDIF + + IF (KROUTN == 'FMLNGM') THEN + KRESLT = KLNGM(NCATMA) + GO TO 110 + ENDIF + + IF (KROUTN == 'FMPSI ') THEN + KRESLT = KPSI(NCATMA) + GO TO 110 + ENDIF + + KRESLT = 0 + RETURN + + 110 IF (KRESLT == 12) THEN + KFLAG = -4 + CALL FMWRN2 + ENDIF + IF (KRESLT == 3 .OR. KRESLT == 4) THEN + IF (NCATMA == 1 .OR. NCATMA == 7 .OR. NCATMA == 9 .OR. & + NCATMA == 15 .OR. NCATMB == 1 .OR. NCATMB == 7 .OR. & + NCATMB == 9 .OR. NCATMB == 15) THEN + KFLAG = -5 + ELSE + KFLAG = -5 + CALL FMWRN2 + ENDIF + ENDIF + IF (KRESLT == 5 .OR. KRESLT == 6) THEN + IF (NCATMA == 1 .OR. NCATMA == 7 .OR. NCATMA == 9 .OR. & + NCATMA == 15 .OR. NCATMB == 1 .OR. NCATMB == 7 .OR. & + NCATMB == 9 .OR. NCATMB == 15) THEN + KFLAG = -6 + ELSE + KFLAG = -6 + CALL FMWRN2 + ENDIF + ENDIF + RETURN + END SUBROUTINE FMARG2 + + SUBROUTINE FMBERN(N,MA,MB) + +! MB = MA*B(N) where B(N) is the Nth Bernoulli number. + + USE FMVALS + IMPLICIT NONE + + INTEGER N + REAL (KIND(1.0D0)) :: MA(-1:LUNPCK),MB(-1:LUNPCK) +! MBERN is the array used to save Bernoulli numbers so they +! do not have to be re-computed on subsequent calls. + +! Only the even-numbered Bernoulli numbers are stored. +! B(2N) starts in MBERN(NPTBRN(N)) for 2N >= 28. +! The first few numbers have small numerators and +! denominators, and they are done using FMMPYI and FMDIVI, +! and are not stored in MBERN. + + DOUBLE PRECISION U,X,B + REAL (KIND(1.0D0)) :: MACCA,MACMAX,MNEXP,MXSAVE + INTEGER IEXTRA,INTNDG,J,J2,JSIZE,K,KASAVE,KOVUN,KRESLT,L,LARGE, & + LARGED,N2,NBOT,NDGOAL,NDIV,NDOLD,NDP,NDSAV1,NDSAV2,NDSAVE, & + NEEDED,NEXTD,NEXTN,NGOAL,NMPY,NSTART,NTD,NTN,NTOP,NUMTRY,NX + + IF (NTRACE /= 0) THEN + NCALL = NCALL + 1 + NAMEST(NCALL) = 'FMBERN' + CALL FMNTRI(2,N,1) + NCALL = NCALL - 1 + ENDIF + IF (MBLOGS /= MBASE) CALL FMCONS + IF (ABS(MA(1)) > MEXPAB) THEN + CALL FMENT2('FMBERN',MA,MA,1,0,MB,KRESLT,NDSAVE,MXSAVE,KASAVE, & + KOVUN) + IF (KRESLT /= 0) RETURN + ELSE + NCALL = NCALL + 1 + NAMEST(NCALL) = 'FMBERN' + IF (NTRACE /= 0) CALL FMNTR(2,MA,MA,1,0) + KOVUN = 0 + IF (MA(1) == MEXPOV .OR. MA(1) == MEXPUN) KOVUN = 1 + NDSAVE = NDIG + IF (NCALL == 1) THEN + K = INT(5.0/ALOGMT + 2.0 + (REAL(NDIG)*ALOGMT)**0.35/ALOGMT) + NDIG = MAX(NDIG+K,2) + IF (NDIG > NDG2MX) THEN + KFLAG = -9 + CALL FMWARN + NDIG = NDSAVE + KRESLT = 12 + CALL FMRSLT(MA,MA,MB,KRESLT) + IF (NTRACE /= 0) CALL FMNTR(1,MB,MB,1,1) + NCALL = NCALL - 1 + RETURN + ENDIF + ENDIF + KASAVE = KACCSW + MXSAVE = MXEXP + MXEXP = MXEXP2 + ENDIF + + KACCSW = 1 + MACCA = MA(0) + CALL FMEQ2(MA,M20,NDSAVE,NDIG) + M20(0) = NINT(NDIG*ALOGM2) + NUMTRY = 0 + +! Check for special cases. + + 110 IF (N >= 2 .AND. N <= 26) THEN + CALL FMBER2(N,M20,M19) + GO TO 130 + ELSE IF (N == 0) THEN + CALL FMEQ(M20,M19) + GO TO 130 + ELSE IF (N == 1) THEN + CALL FMDIVI(M20,-2,M19) + GO TO 130 + ELSE IF (MOD(N,2) == 1 .OR. N < 0) THEN + CALL FMI2M(0,M19) + GO TO 130 + ELSE IF (MA(2) == 0) THEN + CALL FMI2M(0,M19) + GO TO 130 + ENDIF + +! See if B(N) has already been computed with sufficient +! precision. + + N2 = N/2 + IF (MBASE == MBSBRN) THEN + IF (N < NUMBRN .AND. NPTBRN(N2+1)-NPTBRN(N2) >= NDIG+3) THEN + CALL FMMPY(MBERN(NPTBRN(N2)),M20,M19) + GO TO 130 + ELSE IF (N == NUMBRN .AND. NWDBRN-NPTBRN(N2) >= NDIG+2) THEN + CALL FMMPY(MBERN(NPTBRN(N2)),M20,M19) + GO TO 130 + ENDIF + ENDIF + + IF (MBSBRN /= MBASE) THEN + NUMBRN = 0 + NWDBRN = 0 + ENDIF + +! See if the MBERN array is big enough to hold the +! additional Bernoulli numbers up to B(N). + + NSTART = 28 + IF (MBSBRN == MBASE .AND. NUMBRN >= 28) THEN + NSTART = NUMBRN + 2 + DO J = 28, NUMBRN-2, 2 + J2 = J/2 + JSIZE = NPTBRN(J2+1) - NPTBRN(J2) + IF (JSIZE < NDIG+3) THEN + NSTART = J + NWDBRN = NPTBRN(J2) - 1 + GO TO 120 + ENDIF + ENDDO + JSIZE = NWDBRN - NPTBRN(NUMBRN/2) + IF (JSIZE < NDIG+2) THEN + NSTART = NUMBRN + NWDBRN = NPTBRN(NUMBRN/2) - 1 + GO TO 120 + ENDIF + ENDIF + + 120 NEEDED = ((N-NSTART)/2+1)*(NDIG+3) + IF (NEEDED > LMBERN-NWDBRN) THEN + KFLAG = -11 + CALL FMWRN2 + WRITE (KW,*) ' Out of memory for storing Bernoulli numbers in FMBERN.' + WRITE (KW,*) ' For B(',N,') with NDIG = ',NDIG,', ',NEEDED+NWDBRN, & + ' words are needed.' + WRITE (KW,*) ' The current dimension of MBERN is ',LMBERN + WRITE (KW,*) ' ' + MXEXP = MXSAVE + NDIG = NDSAVE + CALL FMST2M('UNKNOWN',MB) + IF (NTRACE /= 0) CALL FMNTR(1,MB,MB,1,1) + NCALL = NCALL - 1 + KACCSW = KASAVE + RETURN + ENDIF + +! Compute more Bernoulli numbers. + + X = 1.0D0 + B = DBLE(MBASE) + NDP = 0 + DO J = 1, 80 + X = X/B + IF ((1.0D0+X) <= 1.0D0) THEN + NDP = J-1 + IF (NDIG <= NDP) X = 4.0D0*DPPI*DPPI + EXIT + ENDIF + ENDDO + INTNDG = INT(ALOGMX/ALOGMB + 1.0) + NX = INT(DBLE(NDIG)*DLOGMB/DLOGTW + 2.0D0) + + DO J = NSTART, N, 2 + +! Check to see if J is large enough so that the formula +! B(J) = -B(J-2)*(J-1)*J/(2*pi)**2 can be used. + + IF (J >= NX .AND. NDIG <= NDP .AND. J > 28) THEN + J2 = J/2 + MNEXP = MBERN(NPTBRN(J2-1)+2) + MBERN(NPTBRN(J2-1)+2) = 0 + CALL FMM2DP(MBERN(NPTBRN(J2-1)),U) + MBERN(NPTBRN(J2-1)+2) = MNEXP + U = -U*(J*J-J)/X + NPTBRN(J2) = NWDBRN + 1 + NUMBRN = J + MBSBRN = MBASE + NWDBRN = NPTBRN(J2) + NDIG + 02 + CALL FMDPM(U,MBERN(NPTBRN(J2))) + MBERN(NPTBRN(J2)+2) = MBERN(NPTBRN(J2)+2) + MNEXP + CYCLE + ENDIF + + IF (J >= NX .AND. J > 28) THEN + J2 = J/2 + NPTBRN(J2) = NWDBRN + 1 + NUMBRN = J + MBSBRN = MBASE + NWDBRN = NPTBRN(J2) + NDIG + 02 + CALL FMPI(M17) + CALL FMSQR_R1(M17) + IF (MOD(J,4) == 0 .OR. MOD(J,4) == 1) THEN + L = -(J*J-J)/4 + CALL FMMPYI(MBERN(NPTBRN(J2-1)),L,M18) + ELSE + L = -(J*J-J) + CALL FMMPYI(MBERN(NPTBRN(J2-1)),L,M18) + CALL FMDIVI_R1(M18,4) + ENDIF + CALL FMDIV(M18,M17,MBERN(NPTBRN(J2))) + CYCLE + ENDIF + +! Use the recurrence involving a sum of binomial +! coefficients times previous B's. + + NTOP = J + 3 + NBOT = J - 6 + LARGE = INT(INTMAX/NTOP) + LARGED = MIN(LARGE,INT(MXBASE)) + CALL FMCMBI(NTOP,NBOT,M17) + IF (NBOT <= 26) THEN + CALL FMBER2(NBOT,M17,M18) + ELSE + CALL FMMPY(MBERN(NPTBRN(NBOT/2)),M17,M18) + ENDIF + NDSAV1 = NDIG + DO NBOT = J-12, 0, -6 + NTN = NBOT + 6 + NTD = NTOP - NBOT - 5 + NEXTN = NTN + NEXTD = NTD + IF (NBOT >= 6) THEN + NDSAV2 = NDIG + DO K = 1, 5 + NEXTN = NEXTN - 1 + NEXTD = NEXTD + 1 + NMPY = NTN*NEXTN + NDIV = NTD*NEXTD + IF (NMPY <= LARGE .AND. NDIV <= LARGED) THEN + NTN = NMPY + NTD = NDIV + ELSE + CALL FMGCDI(NMPY,NDIV) + IF (NMPY <= LARGE .AND. NDIV <= LARGED) THEN + NTN = NMPY + NTD = NDIV + ELSE + NDIG = MAX(2,MIN(NDSAV2,INT(M17(1))+INTNDG)) + CALL FMMPYI_R1(M17,NTN) + CALL FMDIVI_R1(M17,NTD) + NTN = NEXTN + NTD = NEXTD + ENDIF + ENDIF + ENDDO + NDIG = MAX(2,MIN(NDSAV2,INT(M17(1))+INTNDG)) + CALL FMMPYI_R1(M17,NTN) + CALL FMDIVI_R1(M17,NTD) + NDIG = NDSAV2 + ELSE + CALL FMCMBI(NTOP,NBOT,M17) + ENDIF + M17(0) = NINT(NDIG*ALOGM2) + +! Now M17 is the combination NTOP choose NBOT. + + IF (NBOT <= 26) THEN + CALL FMBER2(NBOT,M17,M19) + ELSE + CALL FMMPY(MBERN(NPTBRN(NBOT/2)),M17,M19) + ENDIF + NDIG = NDSAV1 + CALL FMADD_R1(M18,M19) + NDIG = MAX(2,NDSAV1-INT(M18(1)-M19(1))) + ENDDO + + NDIG = NDSAV1 + IF (MOD(J,6) == 4) THEN + CALL FMI2M(NTOP,M16) + CALL FMDIVI(M16,-6,M19) + CALL FMSUB_R2(M19,M18) + ELSE + CALL FMI2M(NTOP,M16) + CALL FMDIVI(M16,3,M19) + CALL FMSUB_R2(M19,M18) + ENDIF + + J2 = J/2 + NPTBRN(J2) = NWDBRN + 1 + NUMBRN = J + MBSBRN = MBASE + NWDBRN = NPTBRN(J2) + NDIG + 02 + + CALL FMMPYI_R1(M18,6) + NTN = NTOP*(NTOP-1) + LARGE = INT(INTMAX/NTOP) + IF (NTN > MXBASE .OR. NTOP > LARGE) THEN + CALL FMDIVI_R1(M18,NTOP) + NTN = NTOP - 1 + CALL FMDIVI_R1(M18,NTN) + NTN = NTOP - 2 + CALL FMDIVI(M18,NTN,MBERN(NPTBRN(J2))) + ELSE IF (NTN*(NTOP-2) > MXBASE .OR. NTN > LARGE) THEN + CALL FMDIVI_R1(M18,NTN) + NTN = NTOP - 2 + CALL FMDIVI(M18,NTN,MBERN(NPTBRN(J2))) + ELSE + NTN = NTN*(NTOP-2) + CALL FMDIVI(M18,NTN,MBERN(NPTBRN(J2))) + ENDIF + ENDDO + + CALL FMMPY(MBERN(NPTBRN(N2)),M20,M19) + +! Check for too much cancellation. + + 130 IF (NCALL <= 1) THEN + NGOAL = INT(REAL(NDSAVE)*ALOGM2) + 17 + ELSE + NGOAL = INT(-MXEXP2) + ENDIF + IF (M19(0) <= NGOAL) THEN + IF (NUMTRY > 0) THEN + NDGOAL = INT(REAL(NGOAL)/ALOGM2 + 1.0) + DO J = 1, NDGOAL+1 + IF (MRETRY(J) /= M19(J)) GO TO 140 + ENDDO + GO TO 150 + ENDIF + 140 IEXTRA = INT(REAL(NGOAL-M19(0))/ALOGM2 + 23.03/ALOGMB) + 1 + NDOLD = NDIG + NDIG = NDIG + IEXTRA + IF (NDIG > NDG2MX) THEN + KFLAG = -9 + CALL FMWRN2 + NDIG = NDIG - IEXTRA + CALL FMST2M('UNKNOWN',M19) + GO TO 150 + ENDIF + CALL FMEQ2_R1(M20,NDSAVE,NDIG) + NUMTRY = NUMTRY + 1 + CALL FMEQ2(M19,MRETRY,NDOLD,NDIG) + GO TO 110 + ENDIF + + 150 MACMAX = NINT(NDSAVE*ALOGM2) + M19(0) = MIN(M19(0),MACCA,MACMAX) + CALL FMEXT2(M19,MB,NDSAVE,MXSAVE,KASAVE,KOVUN) + RETURN + END SUBROUTINE FMBERN + + SUBROUTINE FMBER2(N,MA,MB) + +! Internal routine for small Bernoulli numbers. + +! MB = MA*B(N) for N an even integer between 2 and 26. + + USE FMVALS + IMPLICIT NONE + + INTEGER N + REAL (KIND(1.0D0)) :: MA(-1:LUNPCK),MB(-1:LUNPCK) + INTEGER N2 + INTEGER :: NBTOP(13) = (/ & + 1, 1, 1, 1, 5, -691, 7, -3617, 43867, -174611, & + 854513, -236364091, 8553103 /) + INTEGER :: NBBOT(13) = (/ & + 6, -30, 42, -30, 66, 2730, 6, 510, 798, 330, & + 138, 2730, 6 /) + + IF (N <= 0) THEN + CALL FMEQ(MA,MB) + RETURN + ELSE IF (N == 1) THEN + CALL FMDIVI(MA,-2,MB) + RETURN + ELSE IF (MOD(N,2) == 1) THEN + CALL FMI2M(0,MB) + RETURN + ENDIF + + N2 = N/2 + + IF (N <= 26) THEN + IF (NBTOP(N2) == 1) THEN + CALL FMDIVI(MA,NBBOT(N2),MB) + ELSE + CALL FMMPYI(MA,NBTOP(N2),MB) + CALL FMDIVI_R1(MB,NBBOT(N2)) + ENDIF + ENDIF + RETURN + END SUBROUTINE FMBER2 + + SUBROUTINE FMBETA(MA,MB,MC) + +! MC = beta(MA,MB). beta(MA,MB) = gamma(MA) * gamma(MB) / gamma(MA+MB) + + USE FMVALS + IMPLICIT NONE + + REAL (KIND(1.0D0)) :: MA(-1:LUNPCK),MB(-1:LUNPCK),MC(-1:LUNPCK) + REAL (KIND(1.0D0)) :: MACCA,MACCB,MACMAX,MXSAVE,MZERO + INTEGER IEXTRA,J,K,K10,K11,KASAVE,KB,KC,KFLKB,KFLNKB,KOVUN,KRESLT, & + KWRNSV,N,NB,NBOT,NDGOAL,NDOLD,NDSAVE,NGOAL,NK,NKB,NUMTRY + LOGICAL FMCOMP + REAL X + + CALL FMENT2('FMBETA',MA,MB,2,1,MC,KRESLT,NDSAVE,MXSAVE,KASAVE, & + KOVUN) + IF (KRESLT /= 0) RETURN + KACCSW = 1 + MACCA = MA(0) + MACCB = MB(0) + CALL FMEQ2(MA,M29,NDSAVE,NDIG) + M29(0) = NINT(NDIG*ALOGM2) + CALL FMEQ2(MB,M30,NDSAVE,NDIG) + M30(0) = NINT(NDIG*ALOGM2) + CALL FMEQ(M29,M32) + NUMTRY = 0 + + 110 CALL FMADD(M29,M30,M28) + IF (M29(2) == 0 .OR. M30(2) == 0) THEN + CALL FMST2M('UNKNOWN',M33) + KFLAG = -4 + GO TO 140 + ENDIF + IF (FMCOMP(M28,'==',M29)) THEN + IF (M30(1) > MEXPAB) THEN + CALL FMABS(M30,M23) + CALL FMDPM(DLOGMB,M16) + CALL FMMPY_R2(M16,M23) + J = (M29(1)+1) + CALL FMMPYI_R1(M23,J) + ELSE + CALL FMABS(M30,M23) + ENDIF + CALL FMI2M(1,M16) + CALL FMULP(M16,M17) + CALL FMEQ(M17,M16) + IF (FMCOMP(M23,'<=',M16)) THEN + CALL FMGAM(M30,M33) + GO TO 140 + ENDIF + ENDIF + IF (FMCOMP(M28,'==',M30)) THEN + IF (M29(1) > MEXPAB) THEN + CALL FMABS(M29,M23) + CALL FMDPM(DLOGMB,M16) + CALL FMMPY_R2(M16,M23) + J = (M30(1)+1) + CALL FMMPYI_R1(M23,J) + ELSE + CALL FMABS(M29,M23) + ENDIF + CALL FMI2M(1,M16) + CALL FMULP(M16,M17) + CALL FMEQ(M17,M16) + IF (FMCOMP(M23,'<=',M16)) THEN + CALL FMGAM(M29,M33) + GO TO 140 + ENDIF + ENDIF + IF (M29(1) == MEXPOV) THEN + IF (M29(-1)*M29(2) > 0 .AND. M30(-1) > 0 .AND. M30(1) >= 1) THEN + CALL FMST2M('UNDERFLOW',M33) + KFLAG = -6 + GO TO 140 + ENDIF + ENDIF + IF (M30(1) == MEXPOV) THEN + IF (M30(-1)*M30(2) > 0 .AND. M29(-1) > 0 .AND. M29(1) >= 1) THEN + CALL FMST2M('UNDERFLOW',M33) + KFLAG = -6 + GO TO 140 + ENDIF + ENDIF + +! See if any of the terms are negative integers. + + CALL FMINT(M29,M18) + IF (M29(-1) < 0) THEN + IF (FMCOMP(M29,'==',M18)) THEN + CALL FMST2M('UNKNOWN',M33) + KFLAG = -4 + GO TO 140 + ENDIF + ENDIF + CALL FMINT(M30,M19) + IF (M30(-1) < 0) THEN + IF (FMCOMP(M30,'==',M19)) THEN + CALL FMST2M('UNKNOWN',M33) + KFLAG = -4 + GO TO 140 + ENDIF + ENDIF + IF (M28(2) == 0) THEN + CALL FMI2M(0,M33) + GO TO 120 + ELSE IF (M28(-1) < 0) THEN + CALL FMSUB(M29,M18,M16) + CALL FMSUB(M30,M19,M23) + CALL FMADD_R2(M16,M23) + CALL FMINT(M23,M24) + IF (FMCOMP(M23,'==',M24)) THEN + CALL FMI2M(0,M33) + GO TO 120 + ENDIF + ENDIF + +! See if any of the terms are small integers. + + KWRNSV = KWARN + KWARN = 0 + CALL FMM2I(M29,N) + KFLKB = KFLAG + CALL FMM2I(M30,K) + KFLNKB = KFLAG + CALL FMM2I(M28,NK) + KWARN = KWRNSV + NB = N + K - 2 + KB = N - 1 + NKB = K - 1 + + IF (KFLKB == 0 .AND. KFLNKB == 0) THEN + IF (MIN(KB,NKB) <= 200) THEN + CALL FMCMBI(NB,KB,M33) + CALL FMI2M(N+K-1,M18) + CALL FMMPY_R1(M33,M18) + CALL FMI2M(1,M16) + CALL FMDIV_R2(M16,M33) + GO TO 120 + ENDIF + ENDIF + NBOT = 0 + IF (KFLKB == 0 .AND. N <= 200) THEN + CALL FMEQ(M30,M31) + CALL FMPOCH(M31,N,M15) + CALL FMEQ(M15,M31) + CALL FMFCTI(KB,M21) + CALL FMDIV(M21,M31,M32) + IF (ABS(M32(1)) < MXSAVE) THEN + CALL FMEQ(M32,M33) + GO TO 140 + ENDIF + NBOT = 1 + ELSE IF (KFLNKB == 0 .AND. K <= 200) THEN + CALL FMEQ(M29,M31) + CALL FMPOCH(M31,K,M15) + CALL FMEQ(M15,M31) + CALL FMFCTI(NKB,M21) + CALL FMDIV(M21,M31,M32) + IF (ABS(M32(1)) < MXSAVE) THEN + CALL FMEQ(M32,M33) + GO TO 140 + ENDIF + NBOT = 1 + ENDIF + IF (NBOT == 1) THEN + CALL FMEQ2(MA,M29,NDSAVE,NDIG) + M29(0) = NINT(NDIG*ALOGM2) + CALL FMEQ2(MB,M30,NDSAVE,NDIG) + M30(0) = NINT(NDIG*ALOGM2) + CALL FMEQ(M29,M32) + CALL FMADD(M29,M30,M28) + ENDIF + +! General case. Use FMGAM, unless one of the numbers +! is too big. If so, use FMLNGM. + + X = ALOGMB*REAL(MXEXP) + CALL FMSP2M(X/LOG(X),M17) + CALL FMABS(M28,M04) + CALL FMABS(M29,M05) + CALL FMABS(M30,M06) + IF (FMCOMP(M04,'>=',M17) .OR. FMCOMP(M05,'>=',M17) .OR. & + FMCOMP(M06,'>=',M17)) THEN + +! See if one argument is not very large and the other is +! much larger. For many of these cases, Stirling's formula +! can be used to simplify Beta and avoid cancellation. + + IF (M29(1) > M30(1)) THEN + CALL FMEQ(M29,M20) + CALL FMEQ(M30,M21) + ELSE + CALL FMEQ(M30,M20) + CALL FMEQ(M29,M21) + ENDIF + IF (M20(1) > NDIG .AND. M20(1) >= M21(1)+NDIG) THEN + IF (M21(-1) < 0) THEN + IF (M21(1) > NDIG) THEN + KFLAG = -9 + CALL FMWRN2 + NDIG = NDIG - IEXTRA + CALL FMST2M('UNKNOWN',M33) + GO TO 140 + ELSE + CALL FMI2M(2,M04) + CALL FMEQ(M21,M05) + M05(-1) = -M05(-1) + CALL FMINT(M05,M16) + CALL FMMOD(M16,M04,M22) + IF (M22(2) == 0) THEN + CALL FMADD(M20,M21,M27) + CALL FMLN(M27,M16) + CALL FMMPY(M21,M16,M27) + CALL FMI2M(1,M16) + CALL FMADD(M21,M16,M28) + CALL FMEQ(M21,M31) + CALL FMLNGM(M28,M14) + CALL FMEQ(M14,M28) + CALL FMSUB(M28,M27,M16) + CALL FMEXP(M16,M23) + CALL FMDIV_R1(M23,M31) + CALL FMEQ(M23,M33) + GO TO 120 + ENDIF + ENDIF + ENDIF + CALL FMADD(M20,M21,M27) + CALL FMLN(M27,M16) + CALL FMMPY(M21,M16,M27) + CALL FMEQ(M21,M31) + CALL FMLNGM(M31,M28) + CALL FMSUB(M28,M27,M16) + CALL FMEXP(M16,M23) + CALL FMEQ(M23,M33) + GO TO 120 + ENDIF + +! See if both arguments are large. For many of these cases, +! Stirling's formula can be used to detect cases where the +! result will underflow. + + CALL FMDPM(1.0D7,M16) + IF (FMCOMP(M29,'>',M16) .AND. FMCOMP(M30,'>',M16)) THEN + CALL FMADD(M29,M30,M16) + CALL FMLN(M16,M26) + CALL FMMPY_R2(M16,M26) + IF (M26(1) /= MUNKNO .AND. M26(2) /= 0) M26(-1) = -M26(-1) + CALL FMLN(M29,M16) + CALL FMMPY_R2(M29,M16) + CALL FMADD_R1(M26,M16) + CALL FMLN(M30,M16) + CALL FMMPY_R2(M30,M16) + CALL FMADD_R1(M26,M16) + CALL FMEXP(M26,M27) + IF (M27(1) == MEXPUN) THEN + CALL FMEQ(M27,M33) + GO TO 140 + ENDIF + ENDIF + +! Compute IEXTRA, the number of extra digits required +! to compensate for cancellation error. + + MZERO = 0 + IEXTRA = INT(MAX(M28(1),M29(1),M30(1),MZERO)) + IF (IEXTRA > 0 .AND. NDIG+IEXTRA <= NDG2MX) THEN + CALL FMEQ2_R1(M29,NDIG,NDIG+IEXTRA) + CALL FMEQ2_R1(M30,NDIG,NDIG+IEXTRA) + ENDIF + NDIG = NDIG + IEXTRA + IF (NDIG > NDG2MX) THEN + KFLAG = -9 + CALL FMWRN2 + NDIG = NDIG - IEXTRA + CALL FMST2M('UNKNOWN',M33) + GO TO 140 + ENDIF + CALL FMADD(M29,M30,M28) + CALL FMI2M(1,M20) + CALL FMI2M(2,M21) + CALL FMEQ(M28,M33) + K10 = 0 + K11 = 0 + KC = 0 + IF (M29(-1) < 0) THEN + CALL FMINT(M29,M22) + CALL FMMOD(M22,M21,M23) + IF (M23(2) == 0) THEN + K10 = 1 + CALL FMADD_R1(M29,M20) + ENDIF + ENDIF + IF (M30(-1) < 0) THEN + CALL FMINT(M30,M22) + CALL FMMOD(M22,M21,M23) + IF (M23(2) == 0) THEN + K11 = 1 + CALL FMADD_R1(M30,M20) + ENDIF + ENDIF + IF (M33(-1) < 0) THEN + CALL FMINT(M33,M22) + CALL FMMOD(M22,M21,M23) + IF (M23(2) == 0) THEN + KC = 1 + CALL FMADD_R1(M33,M20) + ENDIF + ENDIF + CALL FMLNGM(M29,M28) + CALL FMLNGM(M30,M31) + CALL FMADD_R1(M28,M31) + CALL FMLNGM(M33,M31) + CALL FMSUB(M28,M31,M16) + CALL FMEXP(M16,M28) + IF (K10 == 1 .OR. K11 == 1 .OR. KC == 1) THEN + CALL FMI2M(1,M20) + IF (K10 == 1) THEN + CALL FMSUB_R1(M29,M20) + CALL FMDIV_R1(M28,M29) + ENDIF + IF (K11 == 1) THEN + CALL FMSUB_R1(M30,M20) + CALL FMDIV_R1(M28,M30) + ENDIF + IF (KC == 1) THEN + CALL FMSUB_R1(M33,M20) + CALL FMMPY_R1(M28,M33) + ENDIF + ENDIF + CALL FMEQ(M28,M33) + ELSE + CALL FMEQ(M28,M33) + CALL FMGAM(M29,M31) + CALL FMEQ(M31,M29) + CALL FMGAM(M30,M31) + CALL FMEQ(M31,M30) + CALL FMGAM(M33,M31) + CALL FMEQ(M31,M33) + CALL FMMPY(M29,M30,M18) + CALL FMDIV_R2(M18,M33) + ENDIF + +! Check for too much cancellation. + + 120 IF (NCALL <= 1) THEN + NGOAL = INT(REAL(NDSAVE)*ALOGM2) + 17 + ELSE + NGOAL = INT(-MXEXP2) + ENDIF + IF (M33(0) <= NGOAL) THEN + IF (NUMTRY > 0) THEN + NDGOAL = INT(REAL(NGOAL)/ALOGM2 + 1.0) + DO J = 1, NDGOAL+1 + IF (MRETRY(J) /= M33(J)) GO TO 130 + ENDDO + GO TO 140 + ENDIF + 130 IEXTRA = INT(REAL(NGOAL-M33(0))/ALOGM2 + 23.03/ALOGMB) + 1 + NDOLD = NDIG + NDIG = NDIG + IEXTRA + IF (NDIG > NDG2MX) THEN + KFLAG = -9 + CALL FMWRN2 + NDIG = NDIG - IEXTRA + CALL FMST2M('UNKNOWN',M33) + GO TO 140 + ENDIF + CALL FMEQ2(MA,M29,NDSAVE,NDIG) + CALL FMEQ2(MB,M30,NDSAVE,NDIG) + NUMTRY = NUMTRY + 1 + CALL FMEQ2(M33,MRETRY,NDOLD,NDIG) + GO TO 110 + ENDIF + + 140 MACMAX = NINT(NDSAVE*ALOGM2) + M33(0) = MIN(M33(0),MACCA,MACCB,MACMAX) + CALL FMEXT2(M33,MC,NDSAVE,MXSAVE,KASAVE,KOVUN) + RETURN + END SUBROUTINE FMBETA + + SUBROUTINE FMCMBI(N,K,MA) + +! Internal routine for computing binomial coefficients for integers. + +! MA = N choose K. + + USE FMVALS + IMPLICIT NONE + + INTEGER N,K + REAL (KIND(1.0D0)) :: MA(-1:LUNPCK) + + INTEGER INTNDG,J,KSTART,KT,L,LARGE,LARGED,NDIV,NDSAVE,NEXTD,NEXTN, & + NMPY,NTD,NTN + + IF (MBLOGS /= MBASE) CALL FMCONS + L = MIN(K,N-K) + IF (L <= 0) THEN + CALL FMI2M(1,MA) + RETURN + ENDIF + IF (L <= 1) THEN + CALL FMI2M(N,MA) + RETURN + ENDIF + +! Find the largest value for N choose J using integers. + + NTN = N + NTD = 1 + LARGE = INT(INTMAX/N) + DO J = 2, L + IF (NTN <= LARGE) THEN + NTN = (NTN*((N+1)-J))/J + ELSE + CALL FMI2M(NTN,MA) + NTN = (N+1) - J + NTD = J + GO TO 110 + ENDIF + ENDDO + + 110 IF (NTD == 1) THEN + CALL FMI2M(NTN,MA) + RETURN + ENDIF + + INTNDG = INT(ALOGMX/ALOGMB + 1.0) + NEXTN = NTN + NEXTD = NTD + KSTART = NTD + 1 + NDSAVE = NDIG + +! Compute the rest of N choose K. + + LARGED = MIN(LARGE,INT(MXBASE)) + DO KT = KSTART, L + NEXTN = NEXTN - 1 + NEXTD = NEXTD + 1 + IF (NTN >= LARGE .OR. NTD >= LARGED) THEN + NDIG = MAX(2,MIN(NDSAVE,INT(MA(1))+INTNDG)) + CALL FMMPYI_R1(MA,NTN) + CALL FMDIVI_R1(MA,NTD) + NTN = NEXTN + NTD = NEXTD + CYCLE + ENDIF + NMPY = NTN*NEXTN + NDIV = NTD*NEXTD + IF (NMPY <= LARGE .AND. NDIV <= LARGED) THEN + NTN = NMPY + NTD = NDIV + ELSE + CALL FMGCDI(NMPY,NDIV) + IF (NMPY <= LARGE .AND. NDIV <= LARGED) THEN + NTN = NMPY + NTD = NDIV + ELSE + NDIG = MAX(2,MIN(NDSAVE,INT(MA(1))+INTNDG)) + CALL FMMPYI_R1(MA,NTN) + CALL FMDIVI_R1(MA,NTD) + NTN = NEXTN + NTD = NEXTD + ENDIF + ENDIF + ENDDO + NDIG = MAX(2,MIN(NDSAVE,INT(MA(1))+INTNDG)) + CALL FMGCDI(NTN,NTD) + CALL FMMPYI_R1(MA,NTN) + CALL FMDIVI_R1(MA,NTD) + NDIG = NDSAVE + MA(0) = NINT(ALOGM2*NDSAVE) + + RETURN + END SUBROUTINE FMCMBI + + SUBROUTINE FMCOMB(MA,MB,MC) + +! MC = MA choose MB. (Binomial coefficient -- uses gamma for non-integers) + +! MC = (MA)! / ( (MB)! * (MA-MB)! ) + + USE FMVALS + IMPLICIT NONE + + REAL (KIND(1.0D0)) :: MA(-1:LUNPCK),MB(-1:LUNPCK),MC(-1:LUNPCK) + REAL (KIND(1.0D0)) :: MACCA,MACCB,MACMAX,MXSAVE,MZERO + INTEGER IEXTRA,J,K,K09,K10,K11,KASAVE,KBOT,KC,KFLGK,KFLGNK,KOVUN, & + KRESLT,KSIGN,KWRNSV,LARGE,N,NBOT,NDGOAL,NDOLD,NDSAVE,NGOAL, & + NK,NUMTRY + LOGICAL FMCOMP + LOGICAL LC1,LC2,LC3 + REAL X + + CALL FMENT2('FMCOMB',MA,MB,2,1,MC,KRESLT,NDSAVE,MXSAVE,KASAVE, & + KOVUN) + IF (KRESLT /= 0) RETURN + KSIGN = 1 + KACCSW = 1 + MACCA = MA(0) + MACCB = MB(0) + CALL FMEQ2(MA,M29,NDSAVE,NDIG) + M29(0) = NINT(NDIG*ALOGM2) + CALL FMEQ2(MB,M30,NDSAVE,NDIG) + M30(0) = NINT(NDIG*ALOGM2) + NUMTRY = 0 + + 110 CALL FMSUB(M29,M30,M28) + IF (M30(2) == 0) THEN + CALL FMI2M(1,M32) + GO TO 120 + ENDIF + +! See if any of the terms are negative integers. + + CALL FMI2M(1,M22) + K10 = 0 + IF (M29(-1) < 0) THEN + CALL FMINT(M29,M18) + IF (FMCOMP(M29,'==',M18)) K10 = -1 + ENDIF + K11 = 0 + IF (M30(-1) < 0) THEN + CALL FMINT(M30,M19) + IF (FMCOMP(M30,'==',M19)) K11 = -1 + ENDIF + K09 = 0 + IF (FMCOMP(M29,'<',M30)) THEN + CALL FMMOD(M29,M22,M20) + CALL FMMOD(M30,M22,M21) + CALL FMSUB_R2(M20,M21) + CALL FMINT(M21,M20) + IF (FMCOMP(M21,'==',M20)) K09 = -1 + ENDIF + + CALL FMI2M(2,M21) + + IF (K11 == -1) THEN + CALL FMI2M(0,M32) + GO TO 120 + ELSE IF (M28(2) == 0) THEN + CALL FMI2M(1,M32) + GO TO 120 + ELSE IF (K09 == -1 .AND. K10 == 0) THEN + CALL FMI2M(0,M32) + GO TO 120 + ELSE IF (K10 == -1 .AND. K09 == 0) THEN + CALL FMST2M('UNKNOWN',M32) + KFLAG = -4 + GO TO 140 + ELSE IF (K10 == -1 .AND. K09 == -1) THEN + CALL FMMOD(M30,M21,M23) + IF (M23(2) /= 0) KSIGN = -1 + CALL FMSUB(M30,M29,M23) + CALL FMSUB(M23,M22,M29) + CALL FMSUB(M29,M30,M28) + ENDIF + +! Check for an obviously overflowed result. + + IF (M29(1) == MEXPOV) THEN + IF (M29(-1)*M29(2) > 0 .AND. M30(-1) > 0 .AND. M30(1) >= 1 & + .AND. M30(1) < MEXPOV) THEN + CALL FMST2M('OVERFLOW',M32) + KFLAG = -5 + GO TO 140 + ENDIF + ENDIF + IF (M29(1) >= 10000) THEN + CALL FMI2M(1,M16) + IF (FMCOMP(M30,'>',M16) .AND. FMCOMP(M30,'<',M29)) THEN + CALL FMSUB(M29,M30,M16) + CALL FMMIN(M30,M16,M24) + CALL FMSUB(M29,M24,M16) + CALL FMADDI(M16,1) + CALL FMDIV(M16,M24,M23) + CALL FMLN(M23,M16) + CALL FMADDI(M16,1) + CALL FMMPY(M24,M16,M23) + CALL FMDPM(6.283185D0,M06) + CALL FMMPY(M06,M24,M16) + CALL FMLN(M16,M06) + CALL FMDIVI(M06,2,M16) + CALL FMSUB_R1(M23,M16) + CALL FMEXP(M23,M12) + CALL FMEQ(M12,M23) + IF (M23(1) == MEXPOV) THEN + CALL FMST2M('OVERFLOW',M32) + KFLAG = -5 + GO TO 140 + ENDIF + ENDIF + ENDIF + +! See if any of the terms are small integers. + + KWRNSV = KWARN + KWARN = 0 + CALL FMM2I(M29,N) + CALL FMM2I(M30,K) + KFLGK = KFLAG + CALL FMM2I(M28,NK) + KFLGNK = KFLAG + KWARN = KWRNSV + + CALL FMI2M(1,M16) + CALL FMADD(M29,M16,M06) + CALL FMSUB_R1(M06,M16) + IF (KFLGK == 0 .AND. M06(2) == 0) THEN + CALL FMI2M(2,M32) + CALL FMMOD(M30,M32,M16) + CALL FMEQ(M16,M32) + IF (M32(2) == 0) THEN + CALL FMDIV(M29,M30,M32) + IF (M32(1) /= MUNKNO .AND. M32(2) /= 0) M32(-1) = -M32(-1) + ELSE + CALL FMDIV(M29,M30,M32) + ENDIF + GO TO 120 + ENDIF + IF (KFLGK == 0 .AND. KFLGNK == 0 .AND. N /= 0) THEN + IF (MIN(K,NK) <= 200) THEN + CALL FMCMBI(N,K,M32) + GO TO 120 + ENDIF + ENDIF + NBOT = 0 + IF (KFLGK == 0 .AND. K <= 200) NBOT = K + IF (KFLGNK == 0 .AND. NK <= 200) NBOT = NK + IF (NBOT > 0) THEN + LARGE = INT(MXBASE/NBOT) + KBOT = 1 + CALL FMEQ(M29,M18) + CALL FMEQ(M29,M19) + CALL FMI2M(-1,M20) + DO J = 2, NBOT + CALL FMADD_R1(M18,M20) + CALL FMMPY_R2(M18,M19) + KBOT = KBOT*J + IF (KBOT >= LARGE) THEN + CALL FMDIVI_R1(M19,KBOT) + KBOT = 1 + ENDIF + ENDDO + CALL FMDIVI(M19,KBOT,M32) + GO TO 120 + ENDIF + +! General case. Use FMFACT, unless one of the numbers +! is too big. If so, use FMLNGM. + + X = ALOGMB*REAL(MXEXP) + CALL FMSP2M(X/LOG(X),M17) + CALL FMABS(M28,M16) + LC1 = FMCOMP(M16,'>=',M17) + CALL FMABS(M29,M16) + LC2 = FMCOMP(M16,'>=',M17) + CALL FMABS(M30,M16) + LC3 = FMCOMP(M16,'>=',M17) + IF (LC1 .OR. LC2 .OR. LC3) THEN + +! See if the second argument is not very large and the first +! is much larger. For many of these cases, Stirling's formula +! can be used to simplify Comb and avoid cancellation. + + IF (M29(1) > M30(1) .AND. M29(-1) > 0 .AND. & + M30(-1) > 0) THEN + CALL FMEQ(M29,M20) + CALL FMEQ(M30,M21) + ELSE + CALL FMI2M(1,M20) + CALL FMI2M(1,M21) + ENDIF + IF (M20(1) > NDIG .AND. M20(1) >= M21(1)+NDIG) THEN + CALL FMI2M(1,M16) + CALL FMADD(M21,M16,M31) + CALL FMLN(M20,M16) + CALL FMADDI(M16,-1) + CALL FMMPY(M21,M16,M27) + CALL FMADD_R2(M21,M27) + CALL FMLNGM(M31,M28) + CALL FMSUB(M27,M28,M16) + CALL FMEXP(M16,M23) + CALL FMEQ(M23,M32) + GO TO 120 + ENDIF + +! Compute IEXTRA, the number of extra digits required +! to compensate for cancellation error. + + MZERO = 0 + IEXTRA = INT(MAX(M28(1),M29(1),M30(1),MZERO)) + IF (IEXTRA > 0 .AND. NDIG+IEXTRA <= NDG2MX) THEN + CALL FMEQ2_R1(M29,NDIG,NDIG+IEXTRA) + CALL FMEQ2_R1(M30,NDIG,NDIG+IEXTRA) + ENDIF + NDIG = NDIG + IEXTRA + IF (NDIG > NDG2MX) THEN + KFLAG = -9 + CALL FMWRN2 + NDIG = NDIG - IEXTRA + CALL FMST2M('UNKNOWN',M32) + CALL FMEXT2(M32,MC,NDSAVE,MXSAVE,KASAVE,KOVUN) + RETURN + ENDIF + CALL FMSUB(M29,M30,M28) + CALL FMI2M(1,M20) + CALL FMI2M(2,M21) + CALL FMADD(M28,M20,M32) + CALL FMADD_R1(M29,M20) + CALL FMADD_R1(M30,M20) + K10 = 0 + K11 = 0 + KC = 0 + IF (M29(-1) < 0) THEN + CALL FMINT(M29,M22) + CALL FMMOD(M22,M21,M23) + IF (M23(2) == 0) THEN + K10 = 1 + CALL FMADD_R1(M29,M20) + ENDIF + ENDIF + IF (M30(-1) < 0) THEN + CALL FMINT(M30,M22) + CALL FMMOD(M22,M21,M23) + IF (M23(2) == 0) THEN + K11 = 1 + CALL FMADD_R1(M30,M20) + ENDIF + ENDIF + IF (M32(-1) < 0) THEN + CALL FMINT(M32,M22) + CALL FMMOD(M22,M21,M23) + IF (M23(2) == 0) THEN + KC = 1 + CALL FMADD_R1(M32,M20) + ENDIF + ENDIF + CALL FMLNGM(M29,M28) + CALL FMLNGM(M30,M31) + CALL FMSUB_R1(M28,M31) + CALL FMLNGM(M32,M31) + CALL FMSUB_R1(M28,M31) + CALL FMEXP(M28,M12) + CALL FMEQ(M12,M28) + IF (K10 == 1 .OR. K11 == 1 .OR. KC == 1) THEN + CALL FMI2M(1,M20) + IF (K10 == 1) THEN + CALL FMSUB_R1(M29,M20) + CALL FMDIV_R1(M28,M29) + ENDIF + IF (K11 == 1) THEN + CALL FMSUB_R1(M30,M20) + CALL FMMPY_R1(M28,M30) + ENDIF + IF (KC == 1) THEN + CALL FMSUB_R1(M32,M20) + CALL FMMPY_R1(M28,M32) + ENDIF + ENDIF + CALL FMEQ(M28,M32) + ELSE + CALL FMEQ(M28,M32) + CALL FMFACT(M29,M31) + CALL FMEQ(M31,M29) + CALL FMFACT(M30,M31) + CALL FMEQ(M31,M30) + CALL FMFACT(M32,M31) + CALL FMEQ(M31,M32) + CALL FMMPY(M32,M30,M18) + CALL FMDIV(M29,M18,M32) + ENDIF + +! Check for too much cancellation. + + 120 IF (NCALL <= 1) THEN + NGOAL = INT(REAL(NDSAVE)*ALOGM2) + 17 + ELSE + NGOAL = INT(-MXEXP2) + ENDIF + IF (M32(0) <= NGOAL) THEN + IF (NUMTRY > 0) THEN + NDGOAL = INT(REAL(NGOAL)/ALOGM2 + 1.0) + DO J = 1, NDGOAL+1 + IF (MRETRY(J) /= M32(J)) GO TO 130 + ENDDO + GO TO 140 + ENDIF + 130 IEXTRA = INT(REAL(NGOAL-M32(0))/ALOGM2 + 23.03/ALOGMB) + 1 + NDOLD = NDIG + NDIG = NDIG + IEXTRA + IF (NDIG > NDG2MX) THEN + KFLAG = -9 + CALL FMWRN2 + NDIG = NDIG - IEXTRA + CALL FMST2M('UNKNOWN',M32) + GO TO 140 + ENDIF + CALL FMEQ2(MA,M29,NDSAVE,NDIG) + CALL FMEQ2(MB,M30,NDSAVE,NDIG) + NUMTRY = NUMTRY + 1 + CALL FMEQ2(M32,MRETRY,NDOLD,NDIG) + GO TO 110 + ENDIF + + 140 M32(-1) = KSIGN*M32(-1) + MACMAX = NINT(NDSAVE*ALOGM2) + M32(0) = MIN(M32(0),MACCA,MACCB,MACMAX) + CALL FMEXT2(M32,MC,NDSAVE,MXSAVE,KASAVE,KOVUN) + RETURN + END SUBROUTINE FMCOMB + + FUNCTION FMDPLG(A) + +! Internal routine for computing an approximation to +! Log(Gamma(A)) using Stirling's formula. + + USE FMVALS + IMPLICIT NONE + + DOUBLE PRECISION FMDPLG,A + + IF (MBLOGS /= MBASE) CALL FMCONS + IF (A > 0.0D0) THEN + FMDPLG = -A + (A-0.5D0)*LOG(A) + DLOGTP/2.0D0 + ELSE IF (A < 0.0D0) THEN + FMDPLG = -(A-1.0D0) - (0.5D0-A)*LOG(1.0D0-A) - & + DLOGTP/2.0D0 - LOG(ABS(SIN(DPPI*A))+1.0D-10) + & + DLOGPI + ELSE + +! A = 0 is really an approximation for some value in [-1,1]. + + FMDPLG = 0.0D0 + ENDIF + RETURN + END FUNCTION FMDPLG + + SUBROUTINE FMENT2(NROUTN,MA,MB,NARGS,KNAM,MC,KRESLT,NDSAVE,MXSAVE, & + KASAVE,KOVUN) + +! Do the argument checking and increasing of precision, overflow +! threshold, etc., upon entry to an FM routine. + +! NROUTN - routine name of calling routine +! MA - first input argument +! MB - second input argument (optional) +! NARGS - number of input arguments +! KNAM - positive if the routine name is to be printed. +! MC - result argument +! KRESLT - returned nonzero if the input arguments give the result +! immediately (e.g., MA*0 or OVERFLOW*MB) +! NDSAVE - saves the value of NDIG after NDIG is increased +! MXSAVE - saves the value of MXEXP +! KASAVE - saves the value of KACCSW +! KOVUN - returned nonzero if an input argument is (+ or -) overflow +! or underflow. + + USE FMVALS + IMPLICIT NONE + + CHARACTER(6) :: NROUTN + REAL (KIND(1.0D0)) :: MA(-1:LUNPCK),MB(-1:LUNPCK),MC(-1:LUNPCK),MXSAVE + INTEGER KNAM,NARGS,KRESLT,NDSAVE,KASAVE,KOVUN + + INTEGER K + + IF (MBLOGS /= MBASE) CALL FMCONS + NCALL = NCALL + 1 + NAMEST(NCALL) = NROUTN + IF (NTRACE /= 0) CALL FMNTR(2,MA,MB,NARGS,KNAM) + CALL FMARG2(NROUTN,NARGS,MA,MB,KRESLT) + + KOVUN = 0 + IF (MA(1) == MEXPOV .OR. MA(1) == MEXPUN) KOVUN = 1 + IF (NARGS == 2) THEN + IF (MB(1) == MEXPOV .OR. MB(1) == MEXPUN) KOVUN = 1 + ENDIF + +! Increase the working precision. + + NDSAVE = NDIG + MXSAVE = MXEXP + KASAVE = KACCSW + IF (NCALL == 1) THEN + K = INT(5.0/ALOGMT + 2.0 + (REAL(NDIG)*ALOGMT)**0.35/ALOGMT) + NDIG = MAX(NDIG+K,2) + IF (NDIG > NDG2MX) THEN + KFLAG = -9 + CALL FMWRN2 + KRESLT = 12 + ENDIF + ENDIF + + IF (KRESLT /= 0) THEN + IF (KRESLT == 9 .OR. KRESLT == 10 .OR. KRESLT >= 13) THEN + IF (KRAD == 1) THEN + CALL FMPI(MC) + ELSE + CALL FMI2M(180,MC) + ENDIF + IF (KRESLT <= 10) CALL FMDIVI_R1(MC,2) + IF (KRESLT >= 14) CALL FMDIVI_R1(MC,4) + CALL FMEQ2_R1(MC,NDIG,NDSAVE) + NDIG = NDSAVE + IF (KRESLT == 9 .OR. KRESLT == 14) MC(-1) = -1 + IF (NTRACE /= 0) CALL FMNTR(1,MC,MC,1,1) + NCALL = NCALL - 1 + RETURN + ENDIF + + NDIG = NDSAVE + CALL FMRSLT(MA,MB,MC,KRESLT) + IF (NTRACE /= 0 .AND. NROUTN /= 'FMIBTA') THEN + CALL FMNTR(1,MC,MC,1,1) + ENDIF + NCALL = NCALL - 1 + RETURN + ENDIF + +! Extend the overflow/underflow threshold. + + MXEXP = MXEXP2 + RETURN + END SUBROUTINE FMENT2 + + SUBROUTINE FMEULR(MA) + +! MA = Euler's constant ( 0.5772156649... ) + + USE FMVALS + IMPLICIT NONE + + REAL (KIND(1.0D0)) :: MA(-1:LUNPCK) + CHARACTER(2315) :: STRING + INTEGER K,KASAVE,NDMB,NDSAVE,NDSV + + IF (MBLOGS /= MBASE) CALL FMCONS + KFLAG = 0 + NCALL = NCALL + 1 + NAMEST(NCALL) = 'FMEULR' + IF (ABS(NTRACE) >= 2 .AND. NCALL <= LVLTRC) THEN + WRITE (KW,"(' Input to FMEULR')") + ENDIF + KASAVE = KACCSW + +! Increase the working precision. + + NDSAVE = NDIG + IF (NCALL == 1) THEN + K = INT(5.0/ALOGMT + 2.0 + (REAL(NDIG)*ALOGMT)**0.35/ALOGMT) + NDIG = MAX(NDIG+K,2) + IF (NDIG > NDG2MX) THEN + KFLAG = -9 + CALL FMWRN2 + NDIG = NDIG - K + CALL FMST2M('UNKNOWN',MA) + GO TO 110 + ENDIF + ENDIF + +! Check to see if Euler's constant has previously been +! saved in base MBASE with sufficient precision. + + IF (MBSEUL == MBASE .AND. NDGEUL >= NDIG) THEN + CALL FMEQ2(M_EULER,MA,NDGEUL,NDSAVE) + ELSE + +! Euler's constant is slower to compute (using PSI) than the +! other saved constants, so more digits are stored in STRING +! for quick conversion. + + NDMB = INT(2300.0*2.302585/ALOGMB) + IF (NDMB >= NDIG) THEN + NDSV = NDIG + NDIG = MIN(NDMB,NDG2MX) + STRING = '0.57721566490153286060651209008240243104215933593'// & + '9923598805767234884867726777664670936947063291746749514631'// & + '4472498070824809605040144865428362241739976449235362535003'// & + '3374293733773767394279259525824709491600873520394816567085'// & + '3233151776611528621199501507984793745085705740029921354786'// & + '1466940296043254215190587755352673313992540129674205137541'// & + '3954911168510280798423487758720503843109399736137255306088'// & + '9331267600172479537836759271351577226102734929139407984301'// & + '0341777177808815495706610750101619166334015227893586796549'// & + '7252036212879226555953669628176388792726801324310104765059'// & + '6370394739495763890657296792960100901512519595092224350140'// & + '9349871228247949747195646976318506676129063811051824197444'// & + '8678363808617494551698927923018773910729457815543160050021'// & + '8284409605377243420328547836701517739439870030237033951832'// & + '8690001558193988042707411542227819716523011073565833967348'// & + '7176504919418123000406546931429992977795693031005030863034'// & + '1856980323108369164002589297089098548682577736428825395492'// & + '5873629596133298574739302373438847070370284412920166417850'// & + '2487333790805627549984345907616431671031467107223700218107'// & + '4504441866475913480366902553245862544222534518138791243457'// & + '3501361297782278288148945909863846006293169471887149587525'// & + '4923664935204732436410972682761608775950880951262084045444'// & + '7799229915724829251625127842765965708321461029821461795195'// & + '7959095922704208989627971255363217948873764210660607065982'// & + '5619901028807561251991375116782176436190570584407835735015'// & + '8005607745793421314498850078641517161519456570617043245075'// & + '0081687052307890937046143066848179164968425491504967243121'// & + '8378387535648949508684541023406016225085155838672349441878'// & + '8044094077010688379511130787202342639522692097160885690838'// & + '2511378712836820491178925944784861991185293910293099059255'// & + '2669172744689204438697111471745715745732039352091223160850'// & + '8682755889010945168118101687497547096936667121020630482716'// & + '5895049327314860874940207006742590918248759621373842311442'// & + '6531350292303175172257221628324883811245895743862398703757'// & + '6628551303314392999540185313414158621278864807611003015211'// & + '9657800681177737635016818389733896639868957932991456388644'// & + '3103706080781744899579583245794189620260498410439225078604'// & + '6036252772602291968299586098833901378717142269178838195298'// & + '4456079160519727973604759102510995779133515791772251502549'// & + '2932463250287476779484215840507599290401855764599018627262' + CALL FMST2M(STRING,M_EULER) + M_EULER(0) = NINT(NDIG*ALOGM2) + MBSEUL = MBASE + NDGEUL = NDIG + IF (ABS(M_EULER(1)) > 10) NDGEUL = 0 + CALL FMEQ2(M_EULER,MA,NDIG,NDSAVE) + NDIG = NDSV + ELSE + NDSV = NDIG + NDIG = MIN(NDIG+2,NDG2MX) + CALL FMI2M(1,M_EULER) + CALL FMPSI(M_EULER,M14) + CALL FMEQ(M14,M_EULER) + M_EULER(-1) = ABS(M_EULER(-1)) + MBSEUL = MBASE + NDGEUL = NDIG + IF (ABS(M_EULER(1)) > 10) NDGEUL = 0 + CALL FMEQ2(M_EULER,MA,NDIG,NDSAVE) + NDIG = NDSV + ENDIF + ENDIF + + 110 NDIG = NDSAVE + KACCSW = KASAVE + IF (NTRACE /= 0) CALL FMNTR(1,MA,MA,1,1) + NCALL = NCALL - 1 + RETURN + END SUBROUTINE FMEULR + + SUBROUTINE FMEXT2(MT,MC,NDSAVE,MXSAVE,KASAVE,KOVUN) + +! Upon exit from an FM routine, the result MT (having precision NDIG) +! is rounded and returned in MC (having precision NDSAVE). +! The values of NDIG, MXEXP, and KACCSW are restored. +! KOVUN is nonzero if one of the routine's input arguments was overflow +! or underflow. + + USE FMVALS + IMPLICIT NONE + + REAL (KIND(1.0D0)) :: MT(-1:LUNPCK),MC(-1:LUNPCK),MXSAVE + INTEGER NDSAVE,KASAVE,KOVUN + + INTEGER KFSAVE,KWRNSV + + KWRNSV = KWARN + KWARN = 0 + MXEXP = MXSAVE + KFSAVE = KFLAG + CALL FMEQ2(MT,MC,NDIG,NDSAVE) + IF (KFLAG /= -5 .AND. KFLAG /= -6) KFLAG = KFSAVE + NDIG = NDSAVE + KWARN = KWRNSV + IF (KFLAG == 1) KFLAG = 0 + IF ((MC(1) == MUNKNO .AND. KFLAG /= -9) & + .OR. (MC(1) == MEXPUN .AND. KOVUN == 0) & + .OR. (MC(1) == MEXPOV .AND. KOVUN == 0)) CALL FMWRN2 + IF (NTRACE /= 0) CALL FMNTR(1,MC,MC,1,1) + NCALL = NCALL - 1 + KACCSW = KASAVE + RETURN + END SUBROUTINE FMEXT2 + + SUBROUTINE FMFACT(MA,MB) + +! MB = MA! ( = GAMMA(MA+1)) + + USE FMVALS + IMPLICIT NONE + + REAL (KIND(1.0D0)) :: MA(-1:LUNPCK),MB(-1:LUNPCK) + REAL (KIND(1.0D0)) :: MACCA,MACMAX,MXSAVE + INTEGER J,KASAVE,KOVUN,KRESLT,NDSAVE + + CALL FMENT2('FMFACT',MA,MA,1,1,MB,KRESLT,NDSAVE,MXSAVE,KASAVE, & + KOVUN) + IF (KRESLT /= 0) RETURN + MACCA = MA(0) + CALL FMEQ2(MA,MB,NDSAVE,NDIG) + MB(0) = NINT(NDIG*ALOGM2) + CALL FMADDI(MB,1) + CALL FMGAM(MB,M15) + CALL FMEQ(M15,MB) + MACMAX = NINT(NDSAVE*ALOGM2) + MB(0) = MIN(MB(0),MACCA,MACMAX) + DO J = -1, NDIG+1 + M01(J) = MB(J) + ENDDO + CALL FMEXT2(M01,MB,NDSAVE,MXSAVE,KASAVE,KOVUN) + RETURN + END SUBROUTINE FMFACT + + SUBROUTINE FMFCTI(NUM,MA) + +! MA = NUM factorial, where NUM is an integer. + + USE FMVALS + IMPLICIT NONE + + INTEGER NUM + REAL (KIND(1.0D0)) :: MA(-1:LUNPCK) + + INTEGER J,JK,K,LARGE + + CALL FMI2M(1,MA) + IF (NUM <= 1) RETURN + J = NUM + K = 1 + LARGE = INT(INTMAX/J) + DO JK = 2, J + K = K*JK + IF (K > LARGE) THEN + CALL FMMPYI_R1(MA,K) + K = 1 + ENDIF + ENDDO + IF (K > 1) CALL FMMPYI_R1(MA,K) + RETURN + END SUBROUTINE FMFCTI + + SUBROUTINE FMGAM(MA,MB) + +! MB = GAMMA(MA) + + USE FMVALS + IMPLICIT NONE + + REAL (KIND(1.0D0)) :: MA(-1:LUNPCK),MB(-1:LUNPCK) + REAL (KIND(1.0D0)) :: MACCA,MACMAX,MXSAVE + INTEGER IEXTRA,INTA,J,K,K0,K1,K2,KASAVE,KDIFF,KFL,KOVUN,KRESLT, & + KRFLCT,KRSAVE,KSIGN,KWRNSV,KWSAVE,LARGE,LSHIFT,NDGOAL, & + NDOLD,NDSAV2,NDSAVE,NGOAL,NUMTRY + LOGICAL FMCOMP + + CALL FMENT2('FMGAM ',MA,MA,1,1,MB,KRESLT,NDSAVE,MXSAVE,KASAVE, & + KOVUN) + IF (KRESLT /= 0) RETURN + KACCSW = 1 + MACCA = MA(0) + CALL FMEQ2(MA,M28,NDSAVE,NDIG) + M28(0) = NINT(NDIG*ALOGM2) + NUMTRY = 0 + +! See if there is a small integer separating this argument +! from the last one. + + IF (MBASE == MBSGAM .AND. NDIG <= NDGGAM) THEN + CALL FMSUB(M28,M_GAMMA_MA,M18) + IF (M18(2) == 0) THEN + CALL FMEQ(M_GAMMA_MB,M22) + GO TO 140 + ENDIF + KWRNSV = KWARN + KWARN = 0 + CALL FMM2I(M18,KDIFF) + KWARN = KWRNSV + IF (KFLAG == 0 .AND. ABS(KDIFF) <= 50) THEN + IF (KDIFF > 0) THEN + CALL FMEQ(M_GAMMA_MA,M21) + ELSE + CALL FMEQ(M28,M21) + ENDIF + CALL FMEQ(M21,M20) + DO J = 1, ABS(KDIFF)-1 + CALL FMI2M(1,M16) + CALL FMADD_R1(M21,M16) + CALL FMMPY_R1(M20,M21) + ENDDO + IF (KDIFF > 0) THEN + CALL FMMPY(M_GAMMA_MB,M20,M22) + ELSE + CALL FMDIV(M_GAMMA_MB,M20,M22) + ENDIF + GO TO 140 + ENDIF + ENDIF + + CALL FMEQ(M28,M_GAMMA_MB) + +! Near zero Gamma(x) is about 1/x. + + 110 IF (M_GAMMA_MB(1) < (-NDIG-3)) THEN + CALL FMI2M(1,M16) + CALL FMDIV(M16,M_GAMMA_MB,M22) + GO TO 140 + ENDIF + +! Check for special cases. + + KRFLCT = 0 + CALL FMDPM(DBLE(-0.5),M18) + IF (FMCOMP(M_GAMMA_MB,'<=',M18)) THEN + KRFLCT = 1 + KFL = 0 + IF (M28(1) <= NDSAVE) THEN + CALL FMINT(M_GAMMA_MB,M21) + IF (FMCOMP(M_GAMMA_MB,'==',M21)) KFL = -4 + ELSE + KFL = -4 + ENDIF + IF (KFL /= 0) THEN + CALL FMST2M('UNKNOWN',M22) + KFLAG = -4 + GO TO 140 + ELSE + CALL FMI2M(1,M16) + CALL FMSUB_R2(M16,M_GAMMA_MB) + ENDIF + ENDIF + +! To speed the asymptotic series calculation, increase +! the argument by LSHIFT. + + KWSAVE = KWARN + KWARN = 0 + CALL FMM2I(M_GAMMA_MB,INTA) + KWARN = KWSAVE + + IF (KFLAG == -4) THEN + LSHIFT = 0 + ELSE + LSHIFT = INT(MAX(0.0,REAL(NDIG)*ALOGMB/4.46-REAL(INTA))) + ENDIF + IF (LSHIFT > 0) LSHIFT = 4*(LSHIFT/4 + 1) + IF (KFLAG == 0) THEN + IF (INTA <= 200) THEN + IF (INTA <= 2) THEN + CALL FMI2M(1,M22) + GO TO 120 + ENDIF + INTA = INTA - 1 + CALL FMFCTI(INTA,M22) + GO TO 120 + ENDIF + ENDIF + + IF (LSHIFT /= 0) THEN + CALL FMI2M(LSHIFT,M16) + CALL FMADD(M_GAMMA_MB,M16,M27) + ELSE + CALL FMEQ(M_GAMMA_MB,M27) + ENDIF + +! Get Gamma for the shifted argument. + +! Compute IEXTRA, the number of extra digits required +! to compensate for cancellation error when the +! argument is large. + + IEXTRA = MIN(MAX(INT(M27(1))-1,0),INT(1.0+ALOGMX/ALOGMB)) + IF (IEXTRA > 0 .AND. NDIG+IEXTRA <= NDG2MX) THEN + CALL FMEQ2_R1(M27,NDIG,NDIG+IEXTRA) + CALL FMEQ2_R1(M_GAMMA_MB,NDIG,NDIG+IEXTRA) + ENDIF + NDSAV2 = NDIG + NDIG = NDIG + IEXTRA + IF (NDIG > NDG2MX .AND. KRFLCT == 1) THEN + KFLAG = -9 + CALL FMWRN2 + NDIG = NDIG - IEXTRA + CALL FMST2M('UNKNOWN',M22) + GO TO 140 + ELSE IF (NDIG > NDG2MX .AND. KRFLCT == 0) THEN + KFLAG = -5 + NDIG = NDIG - IEXTRA + CALL FMST2M('OVERFLOW',M22) + GO TO 140 + ENDIF + CALL FMLNGM(M27,M14) + CALL FMEQ(M14,M27) + CALL FMEXP(M27,M22) + + NDIG = NDSAV2 + +! Reverse the shifting. +! The product MA*(MA+1)*...*(MA+LSHIFT-1) is computed +! four terms at a time to reduce the number of FMMPY calls. + +! M17 is Z +! M18 is Z**2 +! M19 is Z**3 +! M20 is (Z+K)*...*(Z+K+3) +! M23 is the current product + + CALL FMEQ(M_GAMMA_MB,M17) + IF (LSHIFT > 0) THEN + CALL FMSQR(M17,M18) + CALL FMMPY(M17,M18,M19) + CALL FMSQR(M18,M20) + CALL FMMPYI(M19,6,M24) + CALL FMADD_R1(M20,M24) + CALL FMMPYI(M18,11,M24) + CALL FMADD_R1(M20,M24) + CALL FMMPYI(M17,6,M24) + CALL FMADD_R1(M20,M24) + CALL FMEQ(M20,M23) + CALL FMMPYI_R1(M19,16) + LARGE = INTMAX + DO K = 0, LSHIFT-8, 4 + CALL FMADD_R1(M20,M19) + K2 = 24*(2*K + 7) + CALL FMMPYI(M18,K2,M24) + CALL FMADD_R1(M20,M24) + IF (K <= SQRT(REAL(LARGE)/49.0)) THEN + K1 = 8*(6*K*K + 42*K + 79) + CALL FMMPYI(M17,K1,M24) + CALL FMADD_R1(M20,M24) + ELSE + K1 = 48*K + CALL FMMPYI(M17,K1,M24) + CALL FMMPYI_R1(M24,K) + CALL FMADD_R1(M20,M24) + K1 = 336*K + 632 + CALL FMMPYI(M17,K1,M24) + CALL FMADD_R1(M20,M24) + ENDIF + IF (K <= (REAL(LARGE)/17.0)**0.3333) THEN + K0 = 8*(2*K + 7)*(K*K + 7*K + 15) + CALL FMADDI(M20,K0) + ELSE IF (K <= SQRT(REAL(LARGE)*0.9)) THEN + K0 = 8*(2*K + 7) + CALL FMI2M(K0,M24) + K0 = K*K + 7*K + 15 + CALL FMMPYI_R1(M24,K0) + CALL FMADD_R1(M20,M24) + ELSE + K0 = 8*(2*K + 7) + CALL FMI2M(K0,M24) + CALL FMMPYI(M24,K,M21) + CALL FMMPYI_R1(M21,K) + CALL FMADD_R1(M20,M21) + K0 = 7*K + 15 + CALL FMMPYI_R1(M24,K0) + CALL FMADD_R1(M20,M24) + ENDIF + CALL FMMPY_R1(M23,M20) + ENDDO + CALL FMDIV_R1(M22,M23) + ENDIF + +! Use the reflection formula if MA was less than -1/2. + + 120 IF (KRFLCT == 1) THEN + +! Reduce the argument before multiplying by Pi. + + CALL FMNINT(M_GAMMA_MB,M18) + CALL FMDIVI(M18,2,M19) + CALL FMINT(M19,M08) + CALL FMEQ(M08,M19) + CALL FMMPYI(M19,2,M20) + KSIGN = -1 + IF (FMCOMP(M18,'==',M20)) KSIGN = 1 + CALL FMSUB(M_GAMMA_MB,M18,M21) + M21(0) = M_GAMMA_MB(0) + CALL FMPI(M23) + CALL FMMPY_R1(M23,M21) + KRSAVE = KRAD + KRAD = 1 + CALL FMSIN(M23,M12) + CALL FMEQ(M12,M23) + M23(-1) = KSIGN*M23(-1) + KRAD = KRSAVE + CALL FMDIV_R2(MPISAV,M23) + CALL FMDIV_R2(M23,M22) + ENDIF + +! Check for too much cancellation. + + IF (NCALL <= 1) THEN + NGOAL = INT(REAL(NDSAVE)*ALOGM2) + 17 + ELSE + NGOAL = INT(-MXEXP2) + ENDIF + IF (M22(0) <= NGOAL) THEN + IF (NUMTRY > 0) THEN + NDGOAL = INT(REAL(NGOAL)/ALOGM2 + 1.0) + DO J = 1, NDGOAL+1 + IF (MRETRY(J) /= M22(J)) GO TO 130 + ENDDO + GO TO 140 + ENDIF + 130 IEXTRA = INT(REAL(NGOAL-M22(0))/ALOGM2 + 23.03/ALOGMB) + 1 + NDOLD = NDIG + NDIG = NDIG + IEXTRA + IF (NDIG > NDG2MX) THEN + KFLAG = -9 + CALL FMWRN2 + NDIG = NDIG - IEXTRA + CALL FMST2M('UNKNOWN',M22) + GO TO 140 + ENDIF + CALL FMEQ2_R1(M28,NDSAVE,NDIG) + CALL FMEQ(M28,M_GAMMA_MB) + NUMTRY = NUMTRY + 1 + CALL FMEQ2(M22,MRETRY,NDOLD,NDIG) + GO TO 110 + ENDIF + + 140 MACMAX = NINT(NDSAVE*ALOGM2) + M22(0) = MIN(M22(0),MACCA,MACMAX) + + CALL FMEQ(M28,M_GAMMA_MA) + CALL FMEQ(M22,M_GAMMA_MB) + NDGGAM = NDIG + IF (ABS(M_GAMMA_MB(1)) > MEXPOV) NDGGAM = 0 + MBSGAM = MBASE + + CALL FMEXT2(M22,MB,NDSAVE,MXSAVE,KASAVE,KOVUN) + RETURN + END SUBROUTINE FMGAM + + SUBROUTINE FMIBTA(MX,MA,MB,MC) + +! MC = Incomplete Beta(MX,MA,MB) + +! Integral from 0 to MX of t**(MA-1) * (1-t)**(MB-1) dt. + +! 0 <= MX <= 1, 0 < MA, 0 <= MB. + +! Some comments below refer to this function and its arguments as B(x,a,b). + + USE FMVALS + IMPLICIT NONE + + REAL (KIND(1.0D0)) :: MX(-1:LUNPCK),MA(-1:LUNPCK),MB(-1:LUNPCK), & + MC(-1:LUNPCK) + REAL (KIND(1.0D0)) :: MACCA,MACCB,MACCX,MACMAX,MLA,MXSAVE + INTEGER IEXTRA,J,J4,JCHECK,JEXTRA,K,KASAVE,KASHIFT,KBIGAB,KBSHIFT, & + KICK,KOVUN,KPTMJ1,KPTMJ2,KPTMJ3,KPTMJ4,KPTMJ5,KPTMJ6,KPTMJ7, & + KRESLT,KRS,K_RETURN_CODE,NCSAVE,NDGOAL,NDIG2,NDOLD,NDS,NDSAV1, & + NDSAVE,NGOAL,NMETHD,NTERMS,NUMTRY,NWDS1,NWDSAV,NWDSCH + LOGICAL FMCOMP + + NCSAVE = NCALL + CALL FMENT2('FMIBTA',MX,MA,2,1,MC,KRESLT,NDSAVE,MXSAVE,KASAVE, & + KOVUN) + NCALL = NCSAVE + 1 + KRS = KRESLT + IF (MB(1) == MEXPOV .OR. MB(1) == MEXPUN) KOVUN = 1 + IF (ABS(NTRACE) >= 2 .AND. NCALL <= LVLTRC) THEN + NDS = NDIG + NDIG = NDSAVE + IF (NTRACE < 0) THEN + CALL FMNTRJ(MB,NDIG) + ELSE + CALL FMPRNT(MB) + ENDIF + NDIG = NDS + ENDIF + KRESLT = KRS + IF (MB(1) == MUNKNO) THEN + KRESLT = 12 + KFLAG = -4 + ENDIF + IF (KRESLT /= 0) THEN + NDIG = NDSAVE + CALL FMRSLT(MA,MB,MC,KRESLT) + IF (NTRACE /= 0) CALL FMNTR(1,MC,MC,1,1) + MXEXP = MXSAVE + KACCSW = KASAVE + NCALL = NCALL - 1 + RETURN + ENDIF + +! Use more digits for smaller bases. + + J = 1.06*NDSAVE + 51.0/ALOGM2 + 1.0 + NDIG = MAX(NDIG,J) + NDIG = MIN(NDIG,NDG2MX-16) + KACCSW = 1 + MACCX = MX(0) + MACCA = MA(0) + MACCB = MB(0) + CALL FMEQ2(MX,M36,NDSAVE,NDIG) + M36(0) = NINT(NDIG*ALOGM2) + CALL FMEQ2(MA,M37,NDSAVE,NDIG) + M37(0) = NINT(NDIG*ALOGM2) + CALL FMEQ2(MB,M38,NDSAVE,NDIG) + M38(0) = NINT(NDIG*ALOGM2) + +! Handle cases where at least one of X, A, B is underflow or +! overflow. Increasing any underflowed values to 1/HUGE makes +! the calculations more stable. If A is underflow and the final +! result is overflow, it is safe to return overflow. If X is +! underflow and the final result is underflow, it is safe to +! return underflow. If B is underflow, it is replaced by zero. +! Similarly, decreasing any overflowed A or B values to HUGE +! and then getting a final result of underflow means it is safe +! to return underflow. +! Any cases where the inequalities conflict, such as +! A = underflow, B = overflow, will return unknown. + + KBIGAB = 0 + IF (MA(1) == MEXPOV) THEN + CALL FMBIG(M37) + M37(1) = MXSAVE + 1 + KBIGAB = -1 + ENDIF + IF (MB(1) == MEXPOV) THEN + CALL FMBIG(M38) + M38(1) = MXSAVE + 1 + KBIGAB = -1 + ENDIF + IF (MX(1) == MEXPUN) THEN + CALL FMBIG(M36) + M36(1) = MXSAVE + 1 + CALL FMI2M(1,M16) + CALL FMDIV_R2(M16,M36) + KBIGAB = -1 + ENDIF + IF (MA(1) == MEXPUN) THEN + CALL FMBIG(M37) + M37(1) = MXSAVE + 1 + CALL FMI2M(1,M16) + CALL FMDIV_R2(M16,M37) + IF (KBIGAB < 0) THEN + KBIGAB = -9 + CALL FMI2M(0,M25) + GO TO 200 + ELSE + KBIGAB = 1 + ENDIF + ENDIF + IF (MB(1) == MEXPUN) THEN + CALL FMI2M(1,M16) + IF (FMCOMP(M36,'/=',M16)) THEN + CALL FMI2M(0,M38) + ENDIF + ENDIF + NWDSAV = NDIG + NUMTRY = 0 + NDGOAL = 0 + NWDS1 = 0 + KASHIFT = 0 + KBSHIFT = 0 + +! Check for special cases. + + 110 KICK = 0 + CALL FMIBTA2(K_RETURN_CODE,MXSAVE,NTERMS,NUMTRY,NMETHD) + IF (K_RETURN_CODE == 1) GO TO 180 + IF (K_RETURN_CODE == 2) GO TO 200 + +! Determine which method to use. + +! NMETHD = 1 means use the convergent series for B(x,a,b), +! = 2 means use continued fraction expansion 1 +! for B(x,a,b), +! = 3 means use the convergent series +! for B(1-x,b,a). +! = 4 means use continued fraction expansion 1 +! for B(1-x,b,a). +! = 5 means use continued fraction expansion 2 +! for B(x,a,b). +! = 6 means use continued fraction expansion 2 +! for B(1-x,b,a). + + CALL FMSQR(M37,M16) + CALL FMDPM(DBLE(.00173),M06) + CALL FMMPY(M06,M16,M05) + CALL FMSQR(M38,M16) + CALL FMDPM(DBLE(.01253),M06) + CALL FMMPY(M06,M16,M04) + CALL FMADD_R1(M05,M04) + CALL FMDPM(DBLE(.21583),M06) + CALL FMMPY(M06,M37,M04) + CALL FMADD_R1(M05,M04) + CALL FMDPM(DBLE(.03891),M06) + CALL FMMPY(M06,M38,M04) + CALL FMADD_R1(M05,M04) + CALL FMDPM(DBLE(9.14350),M04) + CALL FMADD_R1(M05,M04) + + CALL FMDPM(DBLE(.11709),M06) + CALL FMMPY(M06,M37,M04) + CALL FMDPM(DBLE(.62633),M06) + CALL FMMPY(M06,M38,M03) + CALL FMADD_R1(M04,M03) + CALL FMADDI(M04,1) + + CALL FMDIV(M04,M05,M40) + + CALL FMDPM(DBLE(.29217),M06) + CALL FMMPY(M06,M37,M05) + CALL FMDPM(DBLE(2.09304),M06) + CALL FMMPY(M06,M38,M04) + CALL FMADD_R1(M05,M04) + CALL FMDPM(DBLE(1.53724),M04) + CALL FMADD_R1(M05,M04) + + CALL FMDPM(DBLE(.29217),M06) + CALL FMMPY(M06,M37,M04) + CALL FMDPM(DBLE(2.09304),M06) + CALL FMMPY(M06,M38,M03) + CALL FMADD_R1(M04,M03) + CALL FMADDI(M04,1) + + CALL FMDIV(M04,M05,M41) + + CALL FMSQR(M37,M16) + CALL FMDPM(DBLE(.04038),M06) + CALL FMMPY(M06,M16,M05) + CALL FMSQR(M38,M16) + CALL FMDPM(DBLE(.05754),M06) + CALL FMMPY(M06,M16,M04) + CALL FMADD_R1(M05,M04) + CALL FMDPM(DBLE(.02670),M06) + CALL FMMPY(M06,M37,M04) + CALL FMADD_R1(M05,M04) + CALL FMDPM(DBLE(.56206),M06) + CALL FMMPY(M06,M38,M04) + CALL FMADD_R1(M05,M04) + CALL FMDPM(DBLE(0.13746),M04) + CALL FMADD_R1(M05,M04) + + CALL FMDPM(DBLE(.87312),M06) + CALL FMMPY(M06,M37,M04) + CALL FMDPM(DBLE(.20334),M06) + CALL FMMPY(M06,M38,M03) + CALL FMADD_R1(M04,M03) + CALL FMADDI(M04,1) + + CALL FMDIV(M04,M05,M42) + + CALL FMDPM(DBLE(.64584),M06) + CALL FMMPY(M06,M37,M05) + CALL FMDPM(DBLE(.64584),M06) + CALL FMMPY(M06,M38,M04) + CALL FMADD_R1(M05,M04) + CALL FMDPM(DBLE(6.31958),M04) + CALL FMADD_R1(M05,M04) + + CALL FMDPM(DBLE(.64584),M06) + CALL FMMPY(M06,M37,M04) + CALL FMADDI(M04,1) + + CALL FMDIV(M04,M05,M43) + + CALL FMSQR(M37,M16) + CALL FMDPM(DBLE(.11637),M06) + CALL FMMPY(M06,M16,M05) + CALL FMSQR(M38,M16) + CALL FMDPM(DBLE(.10718),M06) + CALL FMMPY(M06,M16,M04) + CALL FMADD_R1(M05,M04) + CALL FMDPM(DBLE(.92626),M06) + CALL FMMPY(M06,M37,M04) + CALL FMADD_R1(M05,M04) + CALL FMDPM(DBLE(.05518),M06) + CALL FMMPY(M06,M38,M04) + CALL FMADD_R1(M05,M04) + CALL FMDPM(DBLE(0.28962),M04) + CALL FMADD_R1(M05,M04) + + CALL FMDPM(DBLE(.99773),M06) + CALL FMMPY(M06,M37,M04) + CALL FMDPM(DBLE(.56855),M06) + CALL FMMPY(M06,M38,M03) + CALL FMADD_R1(M04,M03) + CALL FMADDI(M04,1) + + CALL FMDIV(M04,M05,M44) + + IF (FMCOMP(M36,'<=',M40)) THEN + NMETHD = 1 + ELSE IF (FMCOMP(M36,'>=',M41)) THEN + NMETHD = 3 + ELSE IF (FMCOMP(M36,'<',M44)) THEN + IF (FMCOMP(M36,'<',M42)) THEN + NMETHD = 2 + ELSE + NMETHD = 4 + ENDIF + ELSE + IF (FMCOMP(M36,'<',M43)) THEN + NMETHD = 5 + ELSE + NMETHD = 6 + ENDIF + ENDIF + IF (M38(1) <= 0 .AND. M37(1)+NDIG < 0) THEN + NMETHD = 1 + ENDIF + IF (NMETHD == 2) GO TO 130 + IF (NMETHD == 5) GO TO 150 + IF (NMETHD == 3 .OR. NMETHD == 4 .OR. NMETHD == 6) GO TO 160 + +! Method 1. Use the Pochhammer(1-B,N)*X**N/((A+N)*N!) +! series. + +! M19 and M25 hold the positive and negative parts +! of the current sum. +! M21 is the current term. +! M22 is J-B. +! M23 is 1. +! M24 is A+J. + + 120 JEXTRA = INT(0.06*NDIG) + IF (NDIG+JEXTRA > NDG2MX-6) JEXTRA = NDG2MX - 6 - NDIG + IF (NDIG+JEXTRA > NDIG) THEN + CALL FMEQ2_R1(M36,NDIG,NDIG+JEXTRA) + CALL FMEQ2_R1(M37,NDIG,NDIG+JEXTRA) + CALL FMEQ2_R1(M38,NDIG,NDIG+JEXTRA) + ENDIF + NDIG = NDIG + JEXTRA + CALL FMI2M(1,M21) + CALL FMDIV(M21,M37,M19) + CALL FMI2M(0,M25) + CALL FMEQ(M38,M22) + IF (M22(1) /= MUNKNO .AND. M22(2) /= 0) M22(-1) = -M22(-1) + CALL FMEQ(M37,M24) + CALL FMI2M(1,M23) + CALL FMI2M(0,M20) + CALL FMI2M(0,M26) + JCHECK = 5 + NDSAV1 = NDIG + +! Method 1 summation loop. + + METHOD1: DO J = 1, NTERMS + NDIG = NDSAV1 + CALL FMADD_R1(M22,M23) + IF (M22(2) == 0) M22(0) = M23(0) + NDIG2 = MIN(NDSAV1,MAX(2,NDSAV1-INT(M19(1)-M21(1)), & + NDSAV1-INT(M25(1)-M21(1)))) + NDIG = NDIG2 + CALL FMMPY_R1(M21,M22) + CALL FMMPY_R1(M21,M36) + IF (J > 1) CALL FMDIVI_R1(M21,J) + NDIG = NDSAV1 + CALL FMADD_R1(M24,M23) + NDIG = NDIG2 + CALL FMDIV(M21,M24,M20) + + NDIG = NDSAV1 + IF (INT(M20(-1)) < 0) THEN + CALL FMADD_R2(M20,M25) + ELSE + CALL FMADD_R2(M20,M19) + ENDIF + + IF (KFLAG < 0) EXIT + IF (MOD(J,JCHECK) == 0) THEN + CALL FMADD(M19,M25,M20) + DO K = NDIG+1, 1, -1 + IF (M20(K) /= M26(K)) THEN + CALL FMEQ(M20,M26) + CYCLE METHOD1 + ENDIF + ENDDO + EXIT + ENDIF + ENDDO METHOD1 + + CALL FMPWR(M36,M37,M16) + CALL FMADD(M19,M25,M06) + CALL FMMPY(M06,M16,M25) + + IF (NMETHD == 1) THEN + GO TO 180 + ELSE + GO TO 170 + ENDIF + +! Method 2. Continued fraction expansion for B(x,a,b). + +! M26 is the current approximation. +! M25 is the previous approximation. +! M21, M22 are the latest numerators (positive part). +! M41, M42 are the latest numerators (negative part). +! M23, M24 are the latest denominators (positive part). +! M43, M44 are the latest denominators (negative part). + + 130 JEXTRA = INT(MAX(1.0,5.76/ALOGMB + 1.0)) + NGRD52 + INT(0.152*NDIG) + IF (NDIG+JEXTRA > NDG2MX-6) JEXTRA = NDG2MX - 6 - NDIG + IF (NDIG+JEXTRA > NDIG) THEN + CALL FMEQ2_R1(M36,NDIG,NDIG+JEXTRA) + CALL FMEQ2_R1(M37,NDIG,NDIG+JEXTRA) + CALL FMEQ2_R1(M38,NDIG,NDIG+JEXTRA) + ENDIF + NDIG = NDIG + JEXTRA + CALL FMI2M(0,M21) + CALL FMI2M(1,M22) + CALL FMI2M(1,M23) + CALL FMI2M(1,M24) + CALL FMI2M(0,M41) + CALL FMI2M(0,M42) + CALL FMI2M(0,M43) + CALL FMI2M(0,M44) + CALL FMI2M(0,M25) + CALL FMI2M(0,M26) + CALL FMADD(M37,M24,M16) + CALL FMMPYI(M16,2,M27) + CALL FMSUB(M27,M24,M16) + CALL FMADD(M16,M38,M06) + CALL FMMPY(M06,M36,M28) + CALL FMMPY(M38,M36,M16) + CALL FMMPYI(M36,3,M06) + CALL FMSUB(M16,M06,M32) + CALL FMADD(M37,M38,M16) + CALL FMMPY(M16,M37,M06) + CALL FMMPY(M06,M36,M33) + CALL FMMPYI(M36,2,M16) + CALL FMADD(M32,M16,M34) + CALL FMSQR(M37,M16) + CALL FMADD(M16,M37,M35) + + JCHECK = 5 + +! Method 2 continued fraction loop. + + DO J = 0, NTERMS + CALL FMDIV(M33,M35,M19) + IF (M19(1) /= MUNKNO .AND. M19(2) /= 0) M19(-1) = -M19(-1) + IF (M19(-1)*M19(2) >= 0) THEN + CALL FMMPY(M19,M21,M16) + CALL FMADD(M16,M22,M21) + CALL FMMPY(M19,M41,M16) + CALL FMADD(M16,M42,M41) + CALL FMMPY(M19,M23,M16) + CALL FMADD(M16,M24,M23) + CALL FMMPY(M19,M43,M16) + CALL FMADD(M16,M44,M43) + ELSE + CALL FMEQ(M21,M40) + CALL FMMPY(M19,M41,M21) + CALL FMADD_R1(M21,M22) + CALL FMMPY(M19,M40,M41) + CALL FMADD_R1(M41,M42) + CALL FMEQ(M23,M40) + CALL FMMPY(M19,M43,M23) + CALL FMADD_R1(M23,M24) + CALL FMMPY(M19,M40,M43) + CALL FMADD_R1(M43,M44) + ENDIF + CALL FMADD_R1(M35,M27) + J4 = J*4 + CALL FMADDI(M35,J4) + CALL FMDIV(M34,M35,M20) + IF (M20(-1) >= 0) THEN + CALL FMMPY(M20,M22,M16) + CALL FMADD(M16,M21,M22) + CALL FMMPY(M20,M42,M16) + CALL FMADD(M16,M41,M42) + CALL FMMPY(M20,M24,M16) + CALL FMADD(M16,M23,M24) + CALL FMMPY(M20,M44,M16) + CALL FMADD(M16,M43,M44) + ELSE + CALL FMEQ(M22,M40) + CALL FMMPY(M20,M42,M22) + CALL FMADD_R1(M22,M21) + CALL FMMPY(M20,M40,M42) + CALL FMADD_R1(M42,M41) + CALL FMEQ(M24,M40) + CALL FMMPY(M20,M44,M24) + CALL FMADD_R1(M24,M23) + CALL FMMPY(M20,M40,M44) + CALL FMADD_R1(M44,M43) + ENDIF + +! Form the quotient and check for convergence. + + IF (MOD(J,JCHECK) == 0) THEN + CALL FMEQ(M26,M25) + CALL FMADD(M22,M42,M16) + CALL FMADD(M24,M44,M06) + CALL FMDIV(M16,M06,M26) + IF (KFLAG == -4) THEN + M25(0) = -2 + GO TO 180 + ENDIF + NGOAL = 1.06*(INT(REAL(NDSAVE)*ALOGM2) + 29) + IF (M26(0) < NGOAL) THEN + KICK = -2 + EXIT + ENDIF + + CALL FMSUB(M26,M25,M16) + CALL FMABS(M16,M40) + IF (J >= 1000*(NUMTRY+1)) THEN + IF (FMCOMP(M40,'>',M45)) THEN + KICK = -2 + EXIT + ENDIF + ENDIF + CALL FMEQ(M40,M45) + NWDSCH = NWDSAV + 1 + IF (NUMTRY == 1 .AND. (KASHIFT > 0 .OR. KBSHIFT > 0)) THEN + NWDSCH = NDIG - JEXTRA + ELSE IF (NUMTRY > 0 .AND. NDGOAL > 0) THEN + NWDSCH = NDGOAL + NWDS1 + NGRD22 + ELSE IF (NUMTRY > 0 .AND. NDGOAL <= 0) THEN + NWDSCH = INT(REAL(INT(REAL(NDSAVE)*ALOGM2)+17)/ALOGM2 & + + 1.0) + NWDS1 + NGRD22 + ENDIF + DO K = NWDSCH, 1, -1 + IF (M25(K) /= M26(K)) GO TO 140 + ENDDO + EXIT + ENDIF + + 140 CALL FMADD_R1(M35,M27) + K = 4*J + 2 + CALL FMADDI(M35,K) + K = 2*J + CALL FMMPYI(M36,K,M18) + CALL FMADD_R1(M33,M28) + CALL FMADD_R1(M33,M18) + CALL FMADD_R1(M34,M32) + CALL FMSUB_R1(M34,M18) + ENDDO + + CALL FMLN(M36,M23) + CALL FMMPY_R1(M23,M37) + IF (M36(1)*(-10) >= NDIG) THEN + CALL FMEQ(M36,M19) + CALL FMEQ(M36,M24) + DO K = 2, NTERMS + CALL FMMPY_R1(M19,M36) + CALL FMDIVI(M19,K,M16) + CALL FMADD_R1(M24,M16) + IF (KFLAG /= 0) EXIT + ENDDO + CALL FMMPY(M24,M38,M16) + IF (M16(1) /= MUNKNO .AND. M16(2) /= 0) M16(-1) = -M16(-1) + ELSE + CALL FMI2M(1,M16) + CALL FMSUB_R1(M16,M36) + CALL FMLN(M16,M24) + CALL FMMPY_R1(M24,M38) + ENDIF + CALL FMADD(M23,M24,M16) + CALL FMEXP(M16,M25) + CALL FMMPY_R2(M26,M25) + IF (M25(1) == MUNKNO) THEN + IF (M26(-1)*M26(2) > 0) THEN + CALL FMLN(M26,M16) + CALL FMADD(M16,M23,M06) + CALL FMADD(M06,M24,M16) + CALL FMEXP(M16,M25) + ELSE + CALL FMEQ(M26,M17) + IF (M17(1) /= MUNKNO .AND. M17(2) /= 0) M17(-1) = -M17(-1) + CALL FMLN(M17,M16) + CALL FMADD(M16,M23,M06) + CALL FMADD(M06,M24,M16) + CALL FMEXP(M16,M25) + IF (M25(1) /= MUNKNO .AND. M25(2) /= 0) M25(-1) = -M25(-1) + ENDIF + ENDIF + IF (ABS(M25(1)) < MEXPOV) CALL FMDIV_R1(M25,M37) + IF (NMETHD == 2) THEN + GO TO 180 + ELSE + GO TO 170 + ENDIF + +! Method 5. Continued fraction expansion 2 for B(x,a,b). + +! M26 is the current approximation. +! M25 is the previous approximation. +! M21, M22 are the latest numerators (positive part). +! M41, M42 are the latest numerators (negative part). +! M23, M24 are the latest denominators (positive part). +! M43, M44 are the latest denominators (negative part). + + 150 JEXTRA = INT(MAX(1.0,5.76/ALOGMB + 1.0)) + INT(0.07*NDIG) + IF (NDIG+JEXTRA > NDG2MX-6) JEXTRA = NDG2MX - 6 - NDIG + IF (NDIG+JEXTRA > NDIG) THEN + CALL FMEQ2_R1(M36,NDIG,NDIG+JEXTRA) + CALL FMEQ2_R1(M37,NDIG,NDIG+JEXTRA) + CALL FMEQ2_R1(M38,NDIG,NDIG+JEXTRA) + ENDIF + NDIG = NDIG + JEXTRA + KPTMJ1 = 0 + KPTMJ2 = (LUNPCK+3) + KPTMJ3 = 2*(LUNPCK+3) + KPTMJ4 = 3*(LUNPCK+3) + KPTMJ5 = 4*(LUNPCK+3) + KPTMJ6 = 5*(LUNPCK+3) + KPTMJ7 = 6*(LUNPCK+3) + + CALL FMI2M(0,M21) + CALL FMI2M(1,M22) + CALL FMI2M(1,M23) + CALL FMI2M(0,M25) + CALL FMI2M(0,M26) + + CALL FMSUB(M37,M22,M30) + CALL FMSUB(M30,M22,MJSUMS(KPTMJ5-1)) + CALL FMSQR(M36,MJSUMS(KPTMJ4-1)) + + IF (NMETHD == 6) THEN + CALL FMADD(M37,M38,M16) + CALL FMMPY(M16,M36,M06) + CALL FMSUB(M37,M06,M29) + CALL FMEQ2(MX,M28,NDSAVE,NDIG) + CALL FMADD(M37,M38,M16) + CALL FMMPY(M16,M28,M06) + CALL FMSUB(M06,M38,M31) + IF (M29(0) > M31(0)) CALL FMEQ(M29,M31) + ELSE + CALL FMADD(M37,M38,M16) + CALL FMMPY(M16,M36,M06) + CALL FMSUB(M37,M06,M31) + ENDIF + IF (M31(0) == 0 .AND. M31(2) == 0) THEN + M31(0) = M22(0) + ENDIF + + CALL FMI2M(0,M28) + CALL FMMPY(M30,M30,M29) + + CALL FMMPY(MJSUMS(KPTMJ4-1),MJSUMS(KPTMJ5-1),M18) + CALL FMADD(MJSUMS(KPTMJ5-1),M38,M19) + CALL FMMPY_R1(M18,M19) + CALL FMADD(M38,M22,M19) + CALL FMMPY(M18,M19,MJSUMS(KPTMJ1-1)) + + CALL FMSUB(MJSUMS(KPTMJ5-1),M22,M18) + CALL FMMPY_R2(MJSUMS(KPTMJ5-1),M18) + CALL FMADD(M30,M38,M16) + CALL FMMPY(M16,M38,M19) + CALL FMSUB(M19,M18,M16) + CALL FMMPYI(M16,2,M18) + CALL FMMPY(M18,MJSUMS(KPTMJ4-1),MJSUMS(KPTMJ2-1)) + + CALL FMMPY(MJSUMS(KPTMJ4-1),MJSUMS(KPTMJ5-1),M18) + CALL FMMPYI(M18,-6,MJSUMS(KPTMJ3-1)) + + CALL FMMPYI_R1(MJSUMS(KPTMJ4-1),-4) + + CALL FMMPYI(MJSUMS(KPTMJ5-1),4,M27) + + CALL FMI2M(4,M16) + CALL FMADD(M38,M16,M06) + CALL FMSUB(M06,M37,M16) + CALL FMMPY(M16,M36,M18) + CALL FMADD(MJSUMS(KPTMJ5-1),M31,M19) + CALL FMMPYI(M19,3,M16) + CALL FMADD(M18,M16,M19) + CALL FMMPY(M19,M30,MJSUMS(KPTMJ5-1)) + + CALL FMMPYI(M37,-2,M16) + CALL FMADD(M16,M38,M06) + CALL FMADDI(M06,3) + CALL FMMPY(M06,M36,M18) + CALL FMMPYI(M37,5,M19) + + CALL FMADD(M18,M19,M16) + CALL FMADD(M16,M31,M06) + CALL FMI2M(6,M16) + CALL FMSUB(M06,M16,M18) + CALL FMMPYI(M18,4,MJSUMS(KPTMJ6-1)) + + CALL FMI2M(2,M16) + CALL FMSUB(M36,M16,M18) + CALL FMMPYI(M18,-12,MJSUMS(KPTMJ7-1)) + + CALL FMADD(M22,M31,M16) + CALL FMMPY(M16,M37,M06) + CALL FMMPY(M06,M30,M31) + + CALL FMADD(M22,M37,M16) + CALL FMMPY(M16,M30,M32) + + CALL FMMPYI_R1(M30,4) + CALL FMDIV(M31,M32,M24) + CALL FMI2M(0,M41) + CALL FMI2M(0,M42) + CALL FMI2M(0,M43) + CALL FMI2M(0,M44) + IF (M24(-1) < 0) THEN + CALL FMEQ(M24,M44) + CALL FMI2M(0,M24) + ENDIF + JCHECK = 5 + +! Method 5 continued fraction loop. + + METHOD5: DO J = 1, NTERMS + CALL FMMPYI(MJSUMS(KPTMJ4-1),J,M18) + CALL FMADD_R1(M18,MJSUMS(KPTMJ3-1)) + CALL FMMPYI_R1(M18,J) + CALL FMADD_R1(M18,MJSUMS(KPTMJ2-1)) + CALL FMMPYI_R1(M18,J) + CALL FMADD_R1(M18,MJSUMS(KPTMJ1-1)) + + CALL FMADDI(M27,8) + CALL FMADD_R1(M28,M18) + CALL FMADD_R1(M29,M27) + CALL FMDIV(M28,M29,M18) + + CALL FMMPYI(MJSUMS(KPTMJ7-1),J,M19) + CALL FMADD_R1(M19,MJSUMS(KPTMJ6-1)) + CALL FMMPYI_R1(M19,J) + CALL FMADD_R1(M19,MJSUMS(KPTMJ5-1)) + + CALL FMADDI(M30,8) + + CALL FMADD_R1(M31,M19) + CALL FMADD_R1(M32,M30) + CALL FMDIV(M31,M32,M19) + + IF (M18(-1) >= 0 .AND. M19(-1) >= 0) THEN + CALL FMMPY(M18,M21,M20) + CALL FMMPY(M19,M22,M21) + CALL FMADD_R1(M20,M21) + CALL FMMPY(M18,M41,M40) + CALL FMMPY(M19,M42,M41) + CALL FMADD_R1(M40,M41) + CALL FMEQ(M22,M21) + CALL FMEQ(M20,M22) + CALL FMEQ(M42,M41) + CALL FMEQ(M40,M42) + CALL FMMPY(M18,M23,M20) + CALL FMMPY(M19,M24,M23) + CALL FMADD_R1(M20,M23) + CALL FMMPY(M18,M43,M40) + CALL FMMPY(M19,M44,M43) + CALL FMADD_R1(M40,M43) + CALL FMEQ(M24,M23) + CALL FMEQ(M20,M24) + CALL FMEQ(M44,M43) + CALL FMEQ(M40,M44) + ELSE IF (M18(-1) >= 0 .AND. M19(-1) < 0) THEN + CALL FMMPY(M18,M21,M16) + CALL FMMPY(M19,M42,M06) + CALL FMADD(M16,M06,M20) + CALL FMMPY(M18,M41,M16) + CALL FMMPY(M19,M22,M06) + CALL FMADD(M16,M06,M40) + CALL FMEQ(M22,M21) + CALL FMEQ(M20,M22) + CALL FMEQ(M42,M41) + CALL FMEQ(M40,M42) + CALL FMMPY(M18,M23,M16) + CALL FMMPY(M19,M44,M06) + CALL FMADD(M16,M06,M20) + CALL FMMPY(M18,M43,M16) + CALL FMMPY(M19,M24,M06) + CALL FMADD(M16,M06,M40) + CALL FMEQ(M24,M23) + CALL FMEQ(M20,M24) + CALL FMEQ(M44,M43) + CALL FMEQ(M40,M44) + ELSE IF (M18(-1) < 0 .AND. M19(-1) >= 0) THEN + CALL FMMPY(M18,M41,M20) + CALL FMMPY(M19,M22,M41) + CALL FMADD_R1(M20,M41) + CALL FMMPY(M18,M21,M40) + CALL FMMPY(M19,M42,M41) + CALL FMADD_R1(M40,M41) + CALL FMEQ(M22,M21) + CALL FMEQ(M20,M22) + CALL FMEQ(M42,M41) + CALL FMEQ(M40,M42) + CALL FMMPY(M18,M43,M20) + CALL FMMPY(M19,M24,M43) + CALL FMADD_R1(M20,M43) + CALL FMMPY(M18,M23,M40) + CALL FMMPY(M19,M44,M43) + CALL FMADD_R1(M40,M43) + CALL FMEQ(M24,M23) + CALL FMEQ(M20,M24) + CALL FMEQ(M44,M43) + CALL FMEQ(M40,M44) + ELSE + CALL FMMPY(M18,M41,M16) + CALL FMMPY(M19,M42,M06) + CALL FMADD(M16,M06,M20) + CALL FMMPY(M18,M21,M16) + CALL FMMPY(M19,M22,M06) + CALL FMADD(M16,M06,M40) + CALL FMEQ(M22,M21) + CALL FMEQ(M20,M22) + CALL FMEQ(M42,M41) + CALL FMEQ(M40,M42) + CALL FMMPY(M18,M43,M16) + CALL FMMPY(M19,M44,M06) + CALL FMADD(M16,M06,M20) + CALL FMMPY(M18,M23,M16) + CALL FMMPY(M19,M24,M06) + CALL FMADD(M16,M06,M40) + CALL FMEQ(M24,M23) + CALL FMEQ(M20,M24) + CALL FMEQ(M44,M43) + CALL FMEQ(M40,M44) + ENDIF + +! Form the quotient and check for convergence. + + IF (MOD(J,JCHECK) == 0) THEN + CALL FMEQ(M26,M25) + CALL FMADD(M22,M42,M16) + CALL FMADD(M24,M44,M06) + CALL FMDIV(M16,M06,M26) + IF (KFLAG == -4) THEN + M25(0) = -2 + GO TO 180 + ENDIF + NGOAL = 1.06*(INT(REAL(NDSAVE)*ALOGM2) + 29) + IF (M26(0) < NGOAL) THEN + KICK = -2 + EXIT + ENDIF + + CALL FMSUB(M26,M25,M16) + CALL FMABS(M16,M40) + IF (J >= 1000*(NUMTRY+1)) THEN + IF (FMCOMP(M40,'>',M45)) THEN + KICK = -2 + EXIT + ENDIF + ENDIF + CALL FMEQ(M40,M45) + NWDSCH = NWDSAV + 1 + IF (NUMTRY >= 1 .AND. (KASHIFT > 0 .OR. KBSHIFT > 0)) THEN + NWDSCH = NDIG - JEXTRA + ELSE IF (NUMTRY > 0 .AND. NDGOAL > 0) THEN + NWDSCH = NDGOAL + NWDS1 + NGRD22 + ELSE IF (NUMTRY > 0 .AND. NDGOAL <= 0) THEN + NWDSCH = INT(REAL(INT(REAL(NDSAVE)*ALOGM2)+17)/ALOGM2 & + + 1.0) + NWDS1 + NGRD22 + ENDIF + DO K = NWDSCH, 1, -1 + IF (M25(K) /= M26(K)) CYCLE METHOD5 + ENDDO + EXIT + ENDIF + + ENDDO METHOD5 + + CALL FMI2M(1,M16) + IF (FMCOMP(M36,'==',M16) .AND. NMETHD == 6) THEN + CALL FMEQ2(MX,M23,NDSAVE,NDIG) + CALL FMMPY_R1(M23,M37) + IF (M23(1) /= MUNKNO .AND. M23(2) /= 0) M23(-1) = -M23(-1) + ELSE IF (MX(1) <= -1 .AND. NMETHD == 6) THEN + CALL FMEQ2(MX,M23,NDSAVE,NDIG) + CALL FMEQ(M23,M19) + CALL FMEQ(M23,M24) + DO K = 2, NTERMS + CALL FMMPY_R1(M19,M23) + CALL FMDIVI(M19,K,M16) + CALL FMADD_R1(M24,M16) + IF (KFLAG /= 0) EXIT + ENDDO + CALL FMMPY(M24,M37,M23) + IF (M23(1) /= MUNKNO .AND. M23(2) /= 0) M23(-1) = -M23(-1) + ELSE + CALL FMLN(M36,M23) + CALL FMMPY_R1(M23,M37) + ENDIF + IF (NMETHD == 6) THEN + CALL FMEQ2(MX,M24,NDSAVE,NDIG) + CALL FMLN(M24,M13) + CALL FMEQ(M13,M24) + CALL FMMPY_R1(M24,M38) + ELSE IF (M36(1) <= -1) THEN + CALL FMEQ(M36,M19) + CALL FMEQ(M36,M24) + DO K = 2, NTERMS + CALL FMMPY_R1(M19,M36) + CALL FMDIVI(M19,K,M16) + CALL FMADD_R1(M24,M16) + IF (KFLAG /= 0) EXIT + ENDDO + CALL FMMPY_R1(M24,M38) + IF (M24(1) /= MUNKNO .AND. M24(2) /= 0) M24(-1) = -M24(-1) + ELSE + CALL FMI2M(1,M06) + CALL FMSUB(M06,M36,M16) + CALL FMLN(M16,M24) + CALL FMMPY_R1(M24,M38) + ENDIF + CALL FMADD(M23,M24,M16) + CALL FMEXP(M16,M25) + CALL FMMPY_R1(M25,M26) + IF (M25(1) == MUNKNO) THEN + IF (M26(-1)*M26(2) > 0) THEN + CALL FMLN(M26,M16) + CALL FMADD(M16,M23,M06) + CALL FMADD(M06,M24,M16) + CALL FMEXP(M16,M25) + ELSE + CALL FMEQ(M26,M17) + IF (M17(1) /= MUNKNO .AND. M17(2) /= 0) M17(-1) = -M17(-1) + CALL FMLN(M17,M16) + CALL FMADD(M16,M23,M06) + CALL FMADD(M06,M24,M16) + CALL FMEXP(M16,M25) + IF (M25(1) /= MUNKNO .AND. M25(2) /= 0) M25(-1) = -M25(-1) + ENDIF + ENDIF + IF (NMETHD == 5) THEN + GO TO 180 + ELSE + GO TO 170 + ENDIF + +! Method 3, 4, or 6. B(X,A,B) = B(A,B) - B(1-X,B,A). + + 160 MLA = M36(0) + CALL FMI2M(1,M16) + CALL FMSUB_R2(M16,M36) + M36(0) = MLA + DO J = -1, NDIG+1 + MLA = M37(J) + M37(J) = M38(J) + M38(J) = MLA + ENDDO + IF (NMETHD == 3) THEN + GO TO 120 + ELSE IF (NMETHD == 4) THEN + GO TO 130 + ELSE + GO TO 150 + ENDIF + 170 K = NWDS1 + CALL FMEQ(M25,M34) + CALL FMBETA(M37,M38,M39) + NWDS1 = INT(MAX(M39(1),M34(1))) + CALL FMSUB(M39,M34,M25) + NWDS1 = MAX(0,NWDS1-INT(M25(1))) + IF (K /= NWDS1 .AND. NUMTRY >= 1) THEN + IF (KASHIFT == 0 .AND. KBSHIFT == 0) M25(0) = -1 + ENDIF + +! Check for too much cancellation. + + 180 K = KFLAG + IF (KICK < 0) M25(0) = KICK + +! Reverse the translation if KASHIFT is positive. +! This is used when a is small and a retry was required +! because of cancellation. + + IF (KASHIFT > 0 .AND. M25(0) > 0) THEN + CALL FMEQ2(MX,M26,NDSAVE,NDIG) + CALL FMEQ2(MA,M27,NDSAVE,NDIG) + CALL FMEQ2(MB,M28,NDSAVE,NDIG) + IF (KBSHIFT > 0) CALL FMADDI(M28,KBSHIFT) + CALL FMI2M(1,M23) + CALL FMADD(M27,M28,M20) + CALL FMI2M(1,M16) + CALL FMADD(M27,M16,M06) + CALL FMDIV(M20,M06,M24) + CALL FMI2M(1,M16) + CALL FMSUB(M16,M26,M21) + CALL FMEQ(M26,M22) + CALL FMMPY(M24,M26,M16) + CALL FMADD_R1(M23,M16) + CALL FMEQ(M20,M18) + CALL FMEQ(M27,M19) + CALL FMADDI(M19,1) + DO J = 2, KASHIFT-1 + CALL FMADDI(M18,1) + CALL FMADDI(M19,1) + CALL FMMPY_R1(M24,M18) + CALL FMDIV_R1(M24,M19) + CALL FMMPY_R1(M22,M26) + CALL FMMPY(M24,M22,M17) + CALL FMADD_R1(M23,M17) + ENDDO + IF (M26(1)*(-10) >= NDIG) THEN + CALL FMEQ(M26,M19) + CALL FMEQ(M26,M21) + DO K = 2, NTERMS + CALL FMMPY_R1(M19,M26) + CALL FMDIVI(M19,K,M16) + CALL FMADD_R1(M21,M16) + IF (KFLAG /= 0) EXIT + ENDDO + CALL FMMPY(M21,M28,M16) + IF (M16(1) /= MUNKNO .AND. M16(2) /= 0) M16(-1) = -M16(-1) + CALL FMEXP(M16,M22) + CALL FMEQ(M23,M19) + CALL FMPWR(M26,M27,M16) + CALL FMMPY(M23,M16,M06) + CALL FMMPY(M06,M22,M16) + CALL FMDIV(M16,M27,M23) + IF (M23(1) == MUNKNO) THEN + CALL FMLN(M26,M16) + CALL FMMPY(M27,M16,M23) + CALL FMLN(M19,M16) + CALL FMADD_R2(M16,M23) + CALL FMMPY(M21,M28,M16) + CALL FMSUB_R1(M23,M16) + CALL FMLN(M27,M16) + CALL FMSUB_R2(M23,M16) + CALL FMEXP(M16,M23) + ENDIF + ELSE + CALL FMPWR(M26,M27,M16) + CALL FMMPY_R1(M23,M16) + CALL FMPWR(M21,M28,M16) + CALL FMMPY_R1(M23,M16) + CALL FMDIV_R1(M23,M27) + ENDIF + CALL FMMPY(M25,M24,M16) + CALL FMI2M(KASHIFT-1,M06) + CALL FMADD_R2(M20,M06) + CALL FMMPY_R1(M16,M06) + CALL FMDIV(M16,M27,M24) + CALL FMADD(M24,M23,M25) + ENDIF + +! Reverse the translation if KBSHIFT is positive. +! This is used when x is close to 1, b is small, +! and a retry was required because of cancellation. + + IF (KBSHIFT > 0 .AND. M25(0) > 0) THEN + CALL FMEQ2(MX,M26,NDSAVE,NDIG) + CALL FMEQ2(MA,M27,NDSAVE,NDIG) + CALL FMEQ2(MB,M28,NDSAVE,NDIG) + CALL FMI2M(1,M23) + CALL FMI2M(1,M16) + CALL FMADD(M28,M16,M06) + CALL FMADD(M27,M28,M16) + CALL FMDIV(M16,M06,M24) + CALL FMADD(M27,M28,M20) + CALL FMI2M(1,M16) + CALL FMSUB(M16,M26,M21) + CALL FMEQ(M21,M22) + CALL FMMPY(M24,M22,M16) + CALL FMADD_R1(M23,M16) + CALL FMEQ(M20,M18) + CALL FMEQ(M28,M19) + CALL FMADDI(M19,1) + DO J = 2, KBSHIFT-1 + CALL FMADDI(M18,1) + CALL FMADDI(M19,1) + CALL FMMPY_R1(M24,M18) + CALL FMDIV_R1(M24,M19) + CALL FMMPY_R1(M22,M21) + CALL FMMPY(M24,M22,M17) + CALL FMADD_R1(M23,M17) + ENDDO + IF (M26(1)*(-10) >= NDIG) THEN + CALL FMEQ(M26,M19) + CALL FMEQ(M26,M21) + DO K = 2, NTERMS + CALL FMMPY_R1(M19,M26) + CALL FMDIVI(M19,K,M16) + CALL FMADD_R1(M21,M16) + IF (KFLAG /= 0) EXIT + ENDDO + CALL FMMPY(M21,M28,M16) + IF (M16(1) /= MUNKNO .AND. M16(2) /= 0) M16(-1) = -M16(-1) + CALL FMEXP(M16,M21) + CALL FMPWR(M26,M27,M16) + CALL FMMPY(M23,M16,M06) + CALL FMMPY(M06,M21,M16) + CALL FMDIV(M16,M28,M23) + ELSE + CALL FMPWR(M26,M27,M16) + CALL FMMPY_R1(M23,M16) + CALL FMPWR(M21,M28,M16) + CALL FMMPY_R1(M23,M16) + CALL FMDIV_R1(M23,M28) + ENDIF + CALL FMMPY(M25,M24,M16) + CALL FMI2M(KBSHIFT-1,M06) + CALL FMADD_R2(M20,M06) + CALL FMMPY_R1(M16,M06) + CALL FMDIV(M16,M28,M24) + CALL FMSUB(M24,M23,M25) + ENDIF + IF (NCALL <= 1) THEN + NGOAL = 1.06*(INT(REAL(NDSAVE)*ALOGM2) + 29) + ELSE + NGOAL = INT(-MXEXP2) + ENDIF + NDGOAL = INT(REAL(NGOAL)/ALOGM2 + 1.0) + IF (M25(0) <= NGOAL) THEN + IF (NUMTRY > 0) THEN + IF (M25(2) == 0 .OR. K < 0) GO TO 190 + DO J = 1, NDGOAL+1 + IF (MRETRY(J) /= M25(J)) GO TO 190 + ENDDO + CALL FMI2M(1,M19) + M25(0) = M19(0) + GO TO 200 + ENDIF + 190 IEXTRA = INT(REAL(NGOAL-M25(0))/ALOGM2 + 23.03/ALOGMB) + 1 + NDOLD = NDIG + NDIG = NDIG + IEXTRA + IF (M25(0) < 0) NDIG = NDOLD + 10*2**NUMTRY + IF (NDIG > NDG2MX-6 .AND. NDOLD < NDG2MX-6) NDIG = NDG2MX - 6 + IF (NDIG > NDG2MX-6) THEN + KFLAG = -9 + CALL FMWRN2 + NDIG = NDOLD + CALL FMST2M('UNKNOWN',M25) + GO TO 200 + ENDIF + CALL FMEQ2_R1(M36,NDSAVE,NDIG) + CALL FMEQ2_R1(M37,NDSAVE,NDIG) + CALL FMEQ2_R1(M38,NDSAVE,NDIG) + IF (NMETHD == 3 .OR. NMETHD == 4 .OR. NMETHD == 6) THEN + CALL FMEQ2(MX,M36,NDSAVE,NDIG) + DO J = -1, NDIG+1 + MLA = M37(J) + M37(J) = M38(J) + M38(J) = MLA + ENDDO + ENDIF + + IF (KASHIFT > 0) THEN + CALL FMEQ2(MA,M37,NDSAVE,NDIG) + IF (KASHIFT <= 2000) THEN + KASHIFT = 9*KASHIFT + ELSE + KASHIFT = NDIG + ENDIF + CALL FMADDI(M37,KASHIFT) + ENDIF + IF (KBSHIFT > 0) THEN + CALL FMEQ2(MB,M38,NDSAVE,NDIG) + IF (KBSHIFT <= 2000) THEN + KBSHIFT = 9*KBSHIFT + ELSE + KBSHIFT = NDIG + ENDIF + CALL FMADDI(M38,KBSHIFT) + ENDIF + +! Check to see if a retry is about to be done for +! small a and large b. If so, raise a by 2*NDIG to +! reduce the potential cancellation error. + + CALL FMI2M(200,M16) + IF (NUMTRY == 0 .AND. FMCOMP(M37,'<=',M16) .AND. & + FMCOMP(M38,'>=',M37)) THEN + KASHIFT = 2*NDIG + CALL FMADDI(M37,2*NDIG) + ENDIF + +! Check to see if a retry is about to be done for +! a > 100 and b < 2. If so, raise b by 2*NDIG to +! reduce the potential cancellation error. + + CALL FMI2M(100,M16) + CALL FMI2M(2,M06) + IF (NUMTRY == 0 .AND. FMCOMP(M37,'>=',M16) .AND. & + FMCOMP(M38,'<=',M06)) THEN + KBSHIFT = 2*NDIG + CALL FMADDI(M38,2*NDIG) + ENDIF + + CALL FMI2M(40*NUMTRY,M16) + CALL FMI2M(100,M06) + IF (NUMTRY > 0 .AND. KASHIFT == 0 .AND. FMCOMP(M37,'<=',M16) & + .AND. FMCOMP(M38,'>=',M06)) THEN + KASHIFT = 2*NDIG + CALL FMADDI(M37,2*NDIG) + ENDIF + + CALL FMI2M(40*NUMTRY,M16) + CALL FMI2M(100,M06) + IF (NUMTRY > 0 .AND. KBSHIFT == 0 .AND. FMCOMP(M37,'>=',M16) & + .AND. FMCOMP(M38,'<=',M06)) THEN + KBSHIFT = 2*NDIG + CALL FMADDI(M38,2*NDIG) + ENDIF + + NUMTRY = NUMTRY + 1 + CALL FMEQ2(M25,MRETRY,NDOLD,NDIG) + IF (KASHIFT == 2*NDIG .OR. KBSHIFT == 2*NDIG) THEN + NDIG = MAX(NDIG,NDOLD+2) + ENDIF + GO TO 110 + ENDIF + + 200 MACMAX = NINT(NDSAVE*ALOGM2) + M25(0) = MIN(M25(0),MACCX,MACCA,MACCB,MACMAX) + IF (KBIGAB /= 0) THEN + IF ((M25(1) >= -MXSAVE .AND. KBIGAB == -1) .OR. & + (M25(1) <= MXSAVE+1 .AND. KBIGAB == 1) .OR. & + (KBIGAB == -9)) THEN + CALL FMST2M('UNKNOWN',M25) + KFLAG = -4 + ENDIF + ENDIF + CALL FMEXT2(M25,MC,NDSAVE,MXSAVE,KASAVE,KOVUN) + RETURN + END SUBROUTINE FMIBTA + + SUBROUTINE FMIBTA2(K_RETURN_CODE,MXSAVE,NTERMS,NUMTRY,NMETHD) + +! Check for various special cases in Incomplete Beta. + + USE FMVALS + IMPLICIT NONE + + REAL (KIND(1.0D0)) :: MXSAVE + INTEGER IEXTRA,J,J4,JSWITCH,K,KPT,K_RETURN_CODE,N,NDOLD, & + NDSAV1,NMETHD,NTERMS,NUMTRY,NUP + INTEGER, PARAMETER :: KPRIME(8) = (/ 2, 3, 5, 7, 11, 13, 17, 19 /) + LOGICAL FMCOMP + + K_RETURN_CODE = 0 + CALL FMI2M(0,M39) + CALL FMBIG(M45) + NDSAV1 = NDIG + +! If B is small, use more guard digits. + + CALL FMDPM(1.0D-10,M16) + IF (FMCOMP(M38,'<=',M16)) THEN + IEXTRA = NGRD52 + IF (NDIG+IEXTRA <= NDG2MX) THEN + CALL FMEQ2_R1(M36,NDIG,NDIG+IEXTRA) + CALL FMEQ2_R1(M37,NDIG,NDIG+IEXTRA) + CALL FMEQ2_R1(M38,NDIG,NDIG+IEXTRA) + ENDIF + NDOLD = NDIG + NDIG = NDIG + IEXTRA + IF (NUMTRY > 0 .AND. NDIG > NDG2MX-6) NDIG = NDG2MX - 6 + IF (NDIG > NDG2MX-6) THEN + KFLAG = -9 + CALL FMWRN2 + NDIG = NDOLD + CALL FMST2M('UNKNOWN',M25) + K_RETURN_CODE = 2 + RETURN + ENDIF + ENDIF + + NTERMS = INT(INTMAX/10) + NMETHD = 0 + +! Check for special cases. + + IF (M36(2) == 0) THEN + CALL FMI2M(0,M25) + K_RETURN_CODE = 1 + RETURN + ENDIF + CALL FMI2M(1,M32) + IF (FMCOMP(M32,'==',M36)) THEN + IEXTRA = MIN(NDIG+NGRD52,NDG2MX) - NDIG + CALL FMEQ2_R1(M36,NDIG,NDIG+IEXTRA) + CALL FMEQ2_R1(M37,NDIG,NDIG+IEXTRA) + CALL FMEQ2_R1(M38,NDIG,NDIG+IEXTRA) + NDIG = NDIG + IEXTRA + CALL FMBETA(M37,M38,M35) + CALL FMEQ(M35,M25) + K_RETURN_CODE = 1 + RETURN + ELSE IF (M36(-1) < 0 .OR. FMCOMP(M36,'>',M32)) THEN + CALL FMST2M('UNKNOWN',M25) + KFLAG = -4 + K_RETURN_CODE = 2 + RETURN + ENDIF + IF (M37(-1) < 0) THEN + CALL FMST2M('UNKNOWN',M25) + KFLAG = -4 + K_RETURN_CODE = 2 + RETURN + ENDIF + IF (M38(-1) < 0) THEN + CALL FMST2M('UNKNOWN',M25) + KFLAG = -4 + K_RETURN_CODE = 2 + RETURN + ENDIF + IF (M37(1) < (-NDIG) .AND. M38(1) < (-NDIG)) THEN + CALL FMSUB(M32,M36,M16) + CALL FMLN(M16,M25) + CALL FMDIV(M32,M37,M16) + CALL FMSUB(M16,M25,M17) + CALL FMPWR(M36,M37,M16) + CALL FMMPY(M17,M16,M25) + K_RETURN_CODE = 1 + RETURN + ENDIF + CALL FMI2M(1,M16) + CALL FMSUB(M16,M38,M06) + CALL FMMPY(M36,M06,M16) + CALL FMADD(M16,M32,M06) + IF (FMCOMP(M06,'==',M32)) THEN + CALL FMLN(M36,M16) + CALL FMMPY(M37,M16,M25) + CALL FMLN(M37,M16) + CALL FMSUB_R2(M25,M16) + CALL FMEXP(M16,M25) + K_RETURN_CODE = 2 + RETURN + ENDIF + +! When A or B is large, check for an underflowed result. + + CALL FMDPM(1.0D+7,M16) + IF (FMCOMP(M37,'>',M16) .OR. FMCOMP(M38,'>',M16)) THEN + +! If B is much larger than A, approximate BETA(A,B) and use +! that as an upper bound. + + IF (M38(1) >= M37(1)+NDIG) THEN + CALL FMADD(M38,M37,M16) + CALL FMLN(M16,M27) + CALL FMMPY_R2(M37,M27) + CALL FMEQ(M37,M31) + CALL FMLNGM(M31,M28) + CALL FMSUB(M28,M27,M16) + CALL FMEXP(M16,M25) + IF (M25(1) <= -MXSAVE-1) THEN + K_RETURN_CODE = 2 + RETURN + ENDIF + ENDIF + +! If A > 2 > B, use the bound +! C = min( X , (A-2)/(A+B-2) ) +! BETA(X,A,B) < (A-1)*X/B * C**(A-2) * (1-C)**B +! +! An alternate bound is also tried: +! C = min( X , (A-1)/(A+B-2) ) +! BETA(X,A,B) < C**A * (1-C)**(1-B) + + CALL FMI2M(2,M16) + IF (FMCOMP(M37,'>',M16) .AND. FMCOMP(M37,'>',M16)) THEN + CALL FMI2M(2,M05) + CALL FMSUB(M37,M05,M16) + CALL FMADD(M37,M38,M06) + CALL FMSUB_R1(M06,M05) + CALL FMDIV_R1(M16,M06) + CALL FMMIN(M36,M16,M27) + CALL FMI2M(1,M16) + CALL FMSUB_R2(M37,M16) + CALL FMLN(M16,M31) + CALL FMLN(M36,M16) + CALL FMADD_R1(M31,M16) + CALL FMLN(M38,M16) + CALL FMSUB_R1(M31,M16) + CALL FMI2M(2,M06) + CALL FMSUB(M37,M06,M25) + CALL FMLN(M27,M16) + CALL FMMPY_R2(M25,M16) + CALL FMADD_R1(M31,M16) + CALL FMI2M(1,M06) + CALL FMSUB(M06,M27,M16) + CALL FMLN(M16,M25) + CALL FMMPY(M38,M25,M16) + CALL FMADD_R1(M31,M16) + CALL FMEXP(M31,M25) + IF (M25(1) <= -MXSAVE-1) THEN + K_RETURN_CODE = 2 + RETURN + ENDIF + CALL FMI2M(1,M06) + CALL FMSUB(M37,M06,M16) + CALL FMADD(M37,M38,M06) + CALL FMI2M(2,M05) + CALL FMSUB_R1(M06,M05) + CALL FMDIV_R1(M16,M06) + CALL FMMIN(M36,M16,M27) + CALL FMI2M(1,M06) + CALL FMSUB(M06,M27,M16) + CALL FMLN(M16,M31) + CALL FMSUB(M38,M06,M05) + CALL FMMPY_R2(M05,M31) + CALL FMLN(M36,M16) + CALL FMMPY_R2(M37,M16) + CALL FMADD_R2(M16,M31) + CALL FMEXP(M31,M25) + IF (M25(1) <= -MXSAVE-1) THEN + K_RETURN_CODE = 2 + RETURN + ENDIF + ENDIF + +! If A > 2 and B > 2, use the bound +! C = min( X , (A-1)/(A+B-2) ) +! BETA(X,A,B) < X * C**(A-1) * (1-C)**(B-1) + + CALL FMI2M(2,M16) + IF (FMCOMP(M37,'>',M16) .AND. FMCOMP(M38,'>',M16)) THEN + CALL FMI2M(1,M06) + CALL FMSUB(M37,M06,M16) + CALL FMADD(M37,M38,M06) + CALL FMI2M(2,M05) + CALL FMSUB_R1(M06,M05) + CALL FMDIV_R1(M16,M06) + CALL FMMIN(M36,M16,M27) + CALL FMI2M(1,M06) + CALL FMSUB(M06,M27,M16) + CALL FMLN(M16,M31) + CALL FMSUB(M38,M06,M05) + CALL FMMPY_R2(M05,M31) + CALL FMLN(M27,M16) + CALL FMSUB(M37,M06,M05) + CALL FMMPY_R2(M05,M16) + CALL FMADD_R2(M16,M31) + CALL FMLN(M36,M16) + CALL FMADD_R2(M16,M31) + CALL FMEXP(M31,M25) + IF (M25(1) <= -MXSAVE-1) THEN + K_RETURN_CODE = 2 + RETURN + ENDIF + ENDIF + ENDIF + +! Check for cases where X is large enough so that at this +! precision, B(X,A,B) = B(A,B). These are often unstable, +! so it is better to use Beta. + + CALL FMI2M(1,M16) + CALL FMI2M(2,M05) + CALL FMADD(M37,M38,M06) + IF (FMCOMP(M37,'>',M16) .AND. FMCOMP(M06,'>',M05)) THEN + CALL FMI2M(1,M06) + CALL FMSUB(M37,M06,M16) + CALL FMADD(M37,M38,M06) + CALL FMI2M(2,M05) + CALL FMSUB_R1(M06,M05) + CALL FMDIV(M16,M06,M35) + CALL FMI2M(1,M16) + CALL FMADD(M37,M38,M06) + CALL FMADDI(M06,-3) + IF (FMCOMP(M35,'<',M16) .AND. FMCOMP(M36,'>',M35) .AND. & + M06(2) /= 0) THEN + CALL FMI2M(1,M06) + CALL FMSUB(M37,M06,M05) + CALL FMSUB(M38,M06,M16) + CALL FMMPY_R2(M05,M16) + CALL FMADD(M37,M38,M05) + CALL FMI2M(3,M06) + CALL FMSUB_R2(M05,M06) + CALL FMDIV(M16,M06,M34) + IF (M34(-1) >= 0) THEN + CALL FMI2M(1,M06) + CALL FMSUB_R2(M37,M06) + CALL FMSQRT(M34,M16) + CALL FMADD(M06,M16,M34) + CALL FMADD(M37,M38,M06) + CALL FMI2M(2,M05) + CALL FMSUB_R1(M06,M05) + CALL FMDIV_R1(M34,M06) + ELSE + CALL FMDPM(DBLE(1.1),M34) + ENDIF + CALL FMI2M(1,M16) + IF (FMCOMP(M34,'>',M35) .AND. FMCOMP(M34,'<',M16) .AND. & + FMCOMP(M36,'>=',M34)) THEN + +! Approximate B(A,B). + + CALL FMADD(M37,M38,M16) + IF (FMCOMP(M16,'==',M37)) THEN + CALL FMLN(M38,M16) + CALL FMDPM(0.5D0,M06) + CALL FMSUB_R2(M38,M06) + CALL FMMPY(M06,M16,M33) + CALL FMSUB_R1(M33,M38) + CALL FMDPM(DLOGTP/2.0D0,M16) + CALL FMSUB_R1(M33,M16) + CALL FMLN(M37,M16) + CALL FMMPY_R2(M38,M16) + CALL FMSUB_R1(M33,M16) + ELSE IF (FMCOMP(M16,'==',M38)) THEN + CALL FMLN(M37,M16) + CALL FMDP2M(0.5D0,M06) + CALL FMSUB_R2(M37,M06) + CALL FMMPY(M06,M16,M33) + CALL FMSUB_R1(M33,M37) + CALL FMDPM(DLOGTP/2.0D0,M16) + CALL FMSUB_R1(M33,M16) + CALL FMLN(M38,M16) + CALL FMMPY_R2(M37,M16) + CALL FMSUB_R1(M33,M16) + ELSE + CALL FMLN(M37,M16) + CALL FMDP2M(0.5D0,M06) + CALL FMSUB_R2(M37,M06) + CALL FMMPY(M06,M16,M33) + CALL FMLN(M38,M16) + CALL FMDP2M(0.5D0,M06) + CALL FMSUB_R2(M38,M06) + CALL FMMPY_R2(M06,M16) + CALL FMADD_R1(M33,M16) + CALL FMADD(M37,M38,M16) + CALL FMLN(M16,M06) + CALL FMDP2M(0.5D0,M05) + CALL FMSUB_R2(M16,M05) + CALL FMMPY(M05,M06,M16) + CALL FMSUB_R1(M33,M16) + CALL FMDPM(DLOGTP/2.0D0,M16) + CALL FMSUB_R1(M33,M16) + ENDIF + CALL FMEXP(M33,M12) + CALL FMEQ(M12,M33) + +! Bound the area from X to 1. + + CALL FMI2M(1,M16) + CALL FMSUB(M16,M36,M06) + IF (FMCOMP(M06,'==',M16)) THEN + CALL FMLN(M36,M16) + CALL FMI2M(1,M05) + CALL FMSUB(M37,M05,M06) + CALL FMMPY(M06,M16,M32) + CALL FMSUB(M38,M05,M06) + CALL FMMPY(M36,M06,M16) + CALL FMSUB_R1(M32,M16) + CALL FMSUB(M05,M36,M16) + CALL FMDIVI_R1(M16,2) + CALL FMLN(M16,M17) + CALL FMSUB_R1(M32,M17) + ELSE + CALL FMLN(M36,M16) + CALL FMI2M(1,M05) + CALL FMSUB(M37,M05,M06) + CALL FMMPY(M06,M16,M32) + CALL FMSUB(M38,M05,M06) + CALL FMSUB(M05,M36,M16) + CALL FMLN(M16,M17) + CALL FMMPY_R2(M06,M17) + CALL FMADD_R1(M32,M17) + CALL FMDIVI_R1(M16,2) + CALL FMLN(M16,M17) + CALL FMADD_R1(M32,M17) + ENDIF + CALL FMEXP(M32,M12) + CALL FMEQ(M12,M32) + CALL FMSUB(M33,M32,M16) + IF (FMCOMP(M16,'==',M33)) THEN + CALL FMEQ(M32,M40) + CALL FMBETA(M37,M38,M35) + CALL FMSUB(M35,M40,M16) + IF (FMCOMP(M16,'==',M35)) THEN + M35(0) = 1.06*M35(0) + CALL FMEQ(M35,M25) + K_RETURN_CODE = 1 + RETURN + ENDIF + ENDIF + ENDIF + ENDIF + ELSE IF (M37(1) < 1 .AND. FMCOMP(M38,'>',M16)) THEN + +! Approximate B(A,B). + + CALL FMADD(M37,M38,M16) + IF (FMCOMP(M16,'==',M37)) THEN + CALL FMLN(M38,M16) + CALL FMDP2M(0.5D0,M06) + CALL FMSUB_R2(M38,M06) + CALL FMMPY(M06,M16,M33) + CALL FMSUB_R1(M33,M38) + CALL FMDPM(DLOGTP/2.0D0,M16) + CALL FMSUB_R1(M33,M16) + CALL FMLN(M37,M16) + CALL FMMPY_R2(M38,M16) + CALL FMSUB_R1(M33,M16) + ELSE IF (FMCOMP(M16,'==',M38)) THEN + CALL FMLN(M37,M16) + CALL FMDP2M(0.5D0,M06) + CALL FMSUB_R2(M37,M06) + CALL FMMPY(M06,M16,M33) + CALL FMSUB_R1(M33,M37) + CALL FMDPM(DLOGTP/2.0D0,M16) + CALL FMSUB_R1(M33,M16) + CALL FMLN(M38,M16) + CALL FMMPY_R2(M37,M16) + CALL FMSUB_R1(M33,M16) + ELSE + CALL FMLN(M37,M16) + CALL FMDP2M(0.5D0,M06) + CALL FMSUB_R2(M37,M06) + CALL FMMPY(M06,M16,M33) + CALL FMLN(M38,M16) + CALL FMDP2M(0.5D0,M06) + CALL FMSUB_R2(M38,M06) + CALL FMMPY_R2(M06,M16) + CALL FMADD_R1(M33,M16) + CALL FMADD(M37,M38,M16) + CALL FMLN(M16,M06) + CALL FMDP2M(0.5D0,M05) + CALL FMSUB_R2(M16,M05) + CALL FMMPY(M05,M06,M16) + CALL FMSUB_R1(M33,M16) + CALL FMDPM(DLOGTP/2.0D0,M16) + CALL FMSUB_R1(M33,M16) + ENDIF + CALL FMEXP(M33,M12) + CALL FMEQ(M12,M33) + +! Bound the area from X to 1. + + CALL FMI2M(1,M16) + CALL FMSUB(M16,M36,M06) + IF (FMCOMP(M06,'==',M16)) THEN + CALL FMLN(M36,M16) + CALL FMI2M(1,M05) + CALL FMSUB(M37,M05,M06) + CALL FMMPY(M06,M16,M32) + CALL FMSUB(M38,M05,M06) + CALL FMMPY(M36,M06,M16) + CALL FMSUB_R1(M32,M16) + CALL FMSUB(M05,M36,M16) + CALL FMDIVI_R1(M16,2) + CALL FMLN(M16,M17) + CALL FMSUB_R1(M32,M17) + CALL FMEXP(M32,M12) + CALL FMEQ(M12,M32) + ELSE + CALL FMLN(M36,M16) + CALL FMI2M(1,M05) + CALL FMSUB(M37,M05,M06) + CALL FMMPY(M06,M16,M32) + CALL FMSUB(M38,M05,M06) + CALL FMSUB(M05,M36,M16) + CALL FMLN(M16,M17) + CALL FMMPY_R2(M06,M17) + CALL FMADD_R1(M32,M17) + CALL FMDIVI_R1(M16,2) + CALL FMLN(M16,M17) + CALL FMADD_R1(M32,M17) + CALL FMEXP(M32,M12) + CALL FMEQ(M12,M32) + ENDIF + CALL FMSUB(M33,M32,M16) + IF (FMCOMP(M16,'==',M33)) THEN + CALL FMBETA(M37,M38,M35) + M35(0) = 1.06*M35(0) + CALL FMEQ(M35,M25) + K_RETURN_CODE = 1 + RETURN + ENDIF + ENDIF + +! If B is small enough, use one of two series or an asymptotic +! series, depending on the size of X and A. + + CALL FMI2M(1,M05) + CALL FMADD(M05,M38,M06) + CALL FMADD(M37,M38,M16) + IF ((FMCOMP(M06,'==',M05) .AND. FMCOMP(M16,'==',M37)) ) THEN + CALL FMDP2M(0.5D0,M16) + IF (FMCOMP(M36,'<=',M16)) THEN + CALL FMI2M(0,M26) + CALL FMEQ(M36,M27) + CALL FMI2M(1,M06) + CALL FMADD(M37,M06,M16) + CALL FMDIV(M27,M16,M28) + CALL FMEQ(M37,M18) + CALL FMADDI(M18,1) + NDSAV1 = NDIG + DO J = 2, NTERMS + CALL FMADD_R1(M26,M28) + IF (KFLAG /= 0 .AND. J >= 3) EXIT + NDIG = MIN(NDSAV1,MAX(2,NDSAV1-INT(M26(1)-M28(1))+1)) + CALL FMMPY_R1(M27,M36) + CALL FMADDI(M18,1) + CALL FMDIV(M27,M18,M28) + NDIG = NDSAV1 + ENDDO + CALL FMPWR(M36,M37,M16) + CALL FMI2M(1,M05) + CALL FMDIV(M05,M37,M06) + CALL FMADD(M06,M26,M05) + CALL FMMPY(M16,M05,M26) + CALL FMEQ(M26,M25) + K_RETURN_CODE = 1 + RETURN + ENDIF + CALL FMDP2M(0.5D0,M16) + CALL FMI2M(20,M06) + IF ((FMCOMP(M36,'>',M16) .AND. FMCOMP(M37,'<',M06))) THEN + CALL FMI2M(0,M26) + CALL FMI2M(1,M16) + CALL FMSUB(M16,M36,M29) + CALL FMI2M(1,M06) + CALL FMADD(M38,M06,M16) + CALL FMPWR(M29,M16,M27) + CALL FMI2M(1,M16) + CALL FMSUB(M16,M37,M06) + CALL FMMPY_R2(M06,M27) + + CALL FMEQ(M27,M28) + NDSAV1 = NDIG + DO J = 2, NTERMS + CALL FMADD_R1(M26,M28) + IF (KFLAG /= 0 .AND. J >= 3) EXIT + NDIG = MIN(NDSAV1,MAX(2,NDSAV1-INT(M26(1)-M28(1))+1)) + CALL FMI2M(J,M06) + CALL FMSUB(M06,M37,M16) + CALL FMMPY(M27,M16,M06) + CALL FMMPY(M06,M29,M16) + CALL FMDIVI(M16,J,M27) + CALL FMDIVI(M27,J,M28) + NDIG = NDSAV1 + ENDDO + CALL FMLN(M29,M16) + CALL FMI2M(1,M06) + CALL FMDIV(M06,M37,M05) + CALL FMSUB(M05,M16,M06) + CALL FMSUB(M06,M26,M27) + CALL FMEULR(M28) + CALL FMI2M(1,M16) + CALL FMADD(M37,M16,M29) + CALL FMPSI(M29,M14) + CALL FMEQ(M14,M29) + CALL FMSUB(M27,M28,M16) + CALL FMSUB(M16,M29,M25) + K_RETURN_CODE = 1 + RETURN + ENDIF + + CALL FMDP2M(0.5D0,M16) + CALL FMI2M(20,M06) + IF ((FMCOMP(M36,'>',M16) .AND. FMCOMP(M37,'>=',M06))) THEN + CALL FMSP2M(0.7*REAL(NDIG)*ALOGMT,M32) + IF (FMCOMP(M37,'>=',M32)) THEN + NUP = 0 + CALL FMEQ(M37,M39) + CALL FMI2M(0,M40) + ELSE + CALL FMSUB(M32,M37,M16) + CALL FMADDI(M16,1) + CALL FMM2I(M16,NUP) + CALL FMI2M(NUP,M16) + CALL FMADD(M37,M16,M39) + CALL FMI2M(1,M40) + CALL FMEQ(M37,M27) + NDSAV1 = NDIG + DO J = 1, NUP-1 + CALL FMMPY_R1(M27,M36) + CALL FMI2M(J,M16) + CALL FMADD(M37,M16,M06) + CALL FMDIV(M27,M06,M28) + NDIG = NDSAV1 + CALL FMADD_R1(M40,M28) + NDIG = MIN(NDSAV1, & + MAX(2,NDSAV1-INT(M40(1)-M28(1))+1)) + ENDDO + NDIG = NDSAV1 + CALL FMPWR(M36,M37,M16) + CALL FMMPY(M40,M16,M17) + CALL FMI2M(1,M06) + CALL FMSUB(M06,M36,M16) + CALL FMPWR(M16,M38,M40) + CALL FMMPY_R2(M17,M40) + CALL FMDIV_R1(M40,M37) + ENDIF + + CALL FMI2M(1,M06) + CALL FMDIVI(M06,2,M16) + CALL FMSUB(M39,M16,M33) + CALL FMLN(M36,M16) + CALL FMMPY(M33,M16,M34) + IF (M34(1) /= MUNKNO .AND. M34(2) /= 0) M34(-1) = -M34(-1) + CALL FMIGM2(M38,M34,M35) + CALL FMPWR(M34,M38,M16) + CALL FMEQ(M34,M17) + IF (M17(1) /= MUNKNO .AND. M17(2) /= 0) M17(-1) = -M17(-1) + CALL FMEXP(M17,M06) + CALL FMMPY(M06,M16,M17) + CALL FMDIV_R1(M35,M17) + CALL FMEQ(M35,M26) + CALL FMSQR(M33,M16) + CALL FMMPYI(M16,4,M27) + CALL FMI2M(1,M28) + CALL FMI2M(1,M29) + CALL FMI2M(1,M30) + CALL FMLN(M36,M16) + CALL FMDIVI(M16,2,M06) + CALL FMSQR(M06,M32) + NDSAV1 = NDIG + J4 = 0 + DO J = 1, NTERMS + JSWITCH = MAX(2,INT(NDIG*DLOGMB/(2.0D0*LOG(23.0)) + 2)) + IF (J < JSWITCH) THEN + J4 = 0 + CALL FMMPYI_R1(M29,4) + CALL FMMPYI(M30,2*J-1,M16) + CALL FMMPYI(M16,2*J,M30) + CALL FMI2M(2,M06) + CALL FMSUB(M06,M29,M16) + CALL FMDIV(M16,M30,M31) + CALL FMBERN(2*J,M31,M11) + CALL FMEQ(M11,M31) + ELSE + IF (J4 == 0) THEN + J4 = 1 + N = 2*J + DO K = 1, 8 + KPT = (K-1)*(NDSAV1+3) + CALL FMI2M(KPRIME(K),MJSUMS(KPT-1)) + CALL FMIPWR(MJSUMS(KPT-1),N,M16) + CALL FMEQ(M16,MJSUMS(KPT-1)) + ENDDO + ELSE + DO K = 1, 8 + KPT = (K-1)*(NDSAV1+3) + CALL FMMPYI(MJSUMS(KPT-1),KPRIME(K)**2, & + MJSUMS(KPT-1)) + ENDDO + ENDIF + CALL FMPI(M22) + CALL FMI2M(1,M18) + CALL FMI2M(1,M19) + DO K = 1, 8 + KPT = (K-1)*(NDSAV1+3) + CALL FMEQ(MJSUMS(KPT-1),M21) + CALL FMI2M(KPRIME(K)**2-1,M16) + CALL FMSUB(M21,M18,M06) + CALL FMDIV_R2(M16,M06) + CALL FMSUB(M18,M06,M20) + CALL FMI2M(1,M16) + IF (FMCOMP(M20,'==',M16)) EXIT + CALL FMMPY_R1(M19,M20) + ENDDO + CALL FMEQ(MJSUMS,M21) + CALL FMI2M(-1,M06) + CALL FMSQR(M22,M17) + CALL FMDIV(M06,M17,M16) + CALL FMI2M(2,M06) + CALL FMSUB(M06,M21,M05) + CALL FMI2M(8,M06) + CALL FMSUB_R1(M06,M21) + CALL FMDIV(M05,M06,M17) + CALL FMMPY(M16,M17,M06) + CALL FMMPY(M06,M19,M20) + CALL FMMPY_R2(M20,M31) + ENDIF + CALL FMI2M(2*J-2,M06) + CALL FMADD(M38,M06,M16) + CALL FMMPY(M16,M35,M06) + CALL FMMPYI(M06,2*J-1,M35) + CALL FMI2M(2*J-1,M06) + CALL FMADD(M34,M06,M16) + CALL FMMPY(M28,M16,M06) + CALL FMADD_R1(M35,M06) + CALL FMDIV_R1(M35,M27) + CALL FMMPY_R1(M28,M32) + CALL FMMPY(M31,M35,M23) + NDIG = NDSAV1 + CALL FMADD_R1(M26,M23) + IF (KFLAG /= 0 .AND. J >= 3) EXIT + NDIG = MIN(NDSAV1,MAX(2,NDSAV1-INT(M26(1)-M23(1))+1)) + ENDDO + NDIG = NDSAV1 + CALL FMPWR(M36,M33,M16) + CALL FMLN(M36,M17) + IF (M17(1) /= MUNKNO .AND. M17(2) /= 0) M17(-1) = -M17(-1) + CALL FMPWR(M17,M38,M25) + CALL FMMPY(M26,M16,M06) + CALL FMMPY_R2(M06,M25) + CALL FMADD_R2(M40,M25) + K_RETURN_CODE = 1 + RETURN + ENDIF + ENDIF + +! If A or B is large in magnitude, use more guard digits. + + IEXTRA = MIN(MAX(INT(M37(1)),INT(M38(1)),0) , & + INT(1.0+ALOGMX/ALOGMB)) + IF (IEXTRA > 0 .AND. NDIG+IEXTRA <= NDG2MX) THEN + CALL FMEQ2_R1(M36,NDIG,NDIG+IEXTRA) + CALL FMEQ2_R1(M37,NDIG,NDIG+IEXTRA) + CALL FMEQ2_R1(M38,NDIG,NDIG+IEXTRA) + ENDIF + NDOLD = NDIG + NDIG = NDIG + IEXTRA + IF (NUMTRY > 0 .AND. NDIG > NDG2MX-6) NDIG = NDG2MX - 6 + IF (NDIG > NDG2MX-6) THEN + KFLAG = -9 + CALL FMWRN2 + NDIG = NDOLD + CALL FMST2M('UNKNOWN',M25) + K_RETURN_CODE = 2 + ENDIF + RETURN + END SUBROUTINE FMIBTA2 + + SUBROUTINE FMIGM1(MA,MB,MC) + +! MC = Incomplete Gamma(MA,MB) + +! Integral from 0 to MB of e**(-t) * t**(MA-1) dt. + +! This is (lower case) gamma(a,x). + + USE FMVALS + IMPLICIT NONE + + REAL (KIND(1.0D0)) :: MA(-1:LUNPCK),MB(-1:LUNPCK),MC(-1:LUNPCK) + DOUBLE PRECISION FMDPLG,X,A,B,SMALL,BIG,TOL,T1,BIGJ + REAL (KIND(1.0D0)) :: MACCA,MACCB,MACMAX,MAXE,MODA2,MXSAVE + INTEGER IEXTRA,INTA,INTG,J,JCHECK,JEXTRA,JTERMS,K,KASAVE,KFLAGA, & + KFLAGI,KFLAGX,KFLGOK,KMID,KOVUN,KRESLT,KWRNSV,KXNEG,LESS, & + NDGOAL,NDIG2,NDOLD,NDSAV1,NDSAVE,NGOAL,NMETHD,NMNNDG, & + NMXDIF,NT,NTERMS,NUMTRY + LOGICAL FMCOMP + REAL C,C1,C2,D,T,TLNB,Y + + CALL FMENT2('FMIGM1',MA,MB,2,1,MC,KRESLT,NDSAVE,MXSAVE,KASAVE, & + KOVUN) + IF (KRESLT /= 0) RETURN + + KACCSW = 1 + MACCA = MA(0) + MACCB = MB(0) + CALL FMEQ2(MA,M31,NDSAVE,NDIG) + M31(0) = NINT(NDIG*ALOGM2) + CALL FMEQ2(MB,M32,NDSAVE,NDIG) + M32(0) = NINT(NDIG*ALOGM2) + NUMTRY = 0 + + 110 NTERMS = INT(INTMAX/10) + +! Check for special cases. + +! See if A is small enough so that the result is X**A/A. + + CALL FMI2M(1,M16) + CALL FMADD(M31,M16,M06) + IF (FMCOMP(M06,'==',M16)) THEN + CALL FMPWR(M32,M31,M16) + CALL FMDIV(M16,M31,M25) + IF (M25(1) /= MUNKNO) GO TO 180 + ENDIF + +! Check to see if X is large enough so that the result +! is Gamma(A). + + CALL FMI2M(1,M16) + CALL FMDIV(M31,M32,M06) + M06(-1) = 1 + CALL FMDPM(DBLE(0.001),M05) + IF (FMCOMP(M32,'>',M16) .AND. FMCOMP(M06,'<=',M05)) THEN + CALL FMI2M(1,M06) + CALL FMSUB(M31,M06,M16) + CALL FMLN(M32,M17) + CALL FMMPY(M16,M17,M06) + CALL FMSUB(M06,M32,M17) + CALL FMEXP(M17,M30) + IF (M30(1) /= MUNKNO) THEN + CALL FMGAM(M31,M29) + IF (M29(1) > M30(1)+NDIG .AND. & + M29(1) /= MUNKNO) THEN + CALL FMEQ(M29,M25) + GO TO 180 + ENDIF + ENDIF + ENDIF + +! A,X are double precision approximations to the two +! arguments to this function. +! INTA = A if A is a small integer. It is used to limit +! the number of terms used in the asymptotic series +! and in the continued fraction expansion. + + INTA = NTERMS + KWRNSV = KWARN + KWARN = 0 + CALL FMM2I(M31,INTG) + KFLAGI = KFLAG + IF (KFLAG == 0) INTA = INTG + CALL FMM2DP(M31,A) + KFLAGA = KFLAG + IF (KFLAG /= 0 .AND. M31(1) < 0) THEN + A = 1.0D0/DPMAX + IF (M31(-1) < 0) A = -A + KFLAGA = 0 + ENDIF + CALL FMM2DP(M32,X) + KFLAGX = KFLAG + IF (KFLAG /= 0 .AND. M32(1) < 0) THEN + X = 1.0D0/DPMAX + IF (M32(-1) < 0) X = -X + KFLAGX = 0 + ENDIF + KWARN = KWRNSV + +! If A or X is large in magnitude, use more guard digits. + + IEXTRA = MIN(MAX(INT(M31(1)),INT(M32(1)),0) , & + INT(1.0+ALOGMX/ALOGMB)) + IF (IEXTRA > 0 .AND. NDIG+IEXTRA <= NDG2MX) THEN + CALL FMEQ2_R1(M31,NDIG,NDIG+IEXTRA) + CALL FMEQ2_R1(M32,NDIG,NDIG+IEXTRA) + ENDIF + NDOLD = NDIG + NDIG = NDIG + IEXTRA + IF (NDIG > NDG2MX) THEN + KFLAG = -9 + CALL FMWRN2 + NDIG = NDOLD + CALL FMST2M('UNKNOWN',M25) + GO TO 180 + ENDIF + +! KXNEG = 1 if X is negative and A is a positive integer. + + KXNEG = 0 + +! MODA2 = MOD(A,2) when KXNEG is 1. + + MODA2 = 0 + + IF (M31(1) == MEXPOV .OR. M32(1) == MEXPOV) THEN + IF (M31(1) == MEXPOV .AND. M31(2) /= 0 .AND. & + M31(-1) == 1) THEN + IF (M32(2) == 0) THEN + CALL FMI2M(0,M25) + GO TO 160 + ENDIF + IF (M32(1) == MEXPOV .AND. M32(2) /= 0 .AND. & + M32(-1) == 1) THEN + CALL FMST2M('OVERFLOW',M25) + KFLAG = -5 + GO TO 160 + ELSE IF (M32(-1) > 0) THEN + CALL FMI2M(1,M25) + IF (FMCOMP(M32,'<=',M25)) THEN + CALL FMST2M('UNDERFLOW',M25) + KFLAG = -6 + GO TO 160 + ELSE + CALL FMST2M('OVERFLOW',M25) + KFLAG = -5 + GO TO 160 + ENDIF + ENDIF + ENDIF + IF (M32(1) == MEXPOV .AND. M32(2) /= 0 .AND. & + M32(-1) == 1) THEN + CALL FMGAM(M31,M30) + CALL FMEQ(M30,M25) + GO TO 160 + ENDIF + IF (M32(1) == MEXPOV .AND. M32(-1) < 0 .AND. & + M31(-1) > 0.AND. M31(2) > 0) THEN + IF (M31(1) /= MEXPOV) THEN + CALL FMINT(M31,M24) + IF (FMCOMP(M31,'==',M24)) THEN + CALL FMI2M(2,M21) + CALL FMMOD(M24,M21,M16) + CALL FMEQ(M16,M21) + IF (M21(2) /= 0) THEN + CALL FMST2M('-OVERFLOW',M25) + KFLAG = -5 + GO TO 160 + ELSE + CALL FMST2M('OVERFLOW',M25) + KFLAG = -5 + GO TO 160 + ENDIF + ENDIF + ENDIF + ENDIF + CALL FMST2M('UNKNOWN',M25) + KFLAG = -4 + GO TO 180 + ENDIF + + IF (M31(1) == MEXPUN .OR. M32(1) == MEXPUN) THEN + CALL FMABS(M31,M06) + CALL FMI2M(1,M16) + IF (FMCOMP(M06,'<',M16) .AND. M32(1) == MEXPUN) THEN + CALL FMST2M('UNKNOWN',M25) + KFLAG = -4 + GO TO 180 + ENDIF + CALL FMABS(M31,M06) + CALL FMI2M(1,M16) + IF (FMCOMP(M06,'>=',M16) .AND. M32(1) == MEXPUN .AND. & + M32(-1) > 0) THEN + CALL FMST2M('UNDERFLOW',M25) + KFLAG = -6 + GO TO 180 + ENDIF + ENDIF + + IF (M31(-1) < 0 .OR. M31(2) == 0) THEN + CALL FMINT(M31,M24) + IF (FMCOMP(M31,'==',M24)) THEN + CALL FMST2M('UNKNOWN',M25) + KFLAG = -4 + GO TO 180 + ENDIF + ENDIF + IF (M32(2) == 0) THEN + IF (M31(-1) <= 0) THEN + CALL FMST2M('UNKNOWN',M25) + KFLAG = -4 + GO TO 180 + ELSE + CALL FMI2M(0,M25) + GO TO 180 + ENDIF + ENDIF + IF (M32(-1) < 0) THEN + CALL FMINT(M31,M24) + IF (FMCOMP(M31,'==',M24)) THEN + KXNEG = 1 + CALL FMI2M(2,M21) + CALL FMMOD(M24,M21,M16) + CALL FMEQ(M16,M21) + IF (M21(2) /= 0) MODA2 = 1 + ELSE + CALL FMST2M('UNKNOWN',M25) + KFLAG = -4 + GO TO 180 + ENDIF + ENDIF + CALL FMMAX(M31,M32,M16) + CALL FMMIN(M31,M32,M17) + CALL FMDPM(1.0D6,M05) + CALL FMDPM(1.0D2,M06) + IF (FMCOMP(M16,'>=',M05) .AND. FMCOMP(M17,'>=',M06)) THEN + CALL FMI2M(1,M16) + CALL FMSUB(M31,M16,M18) + CALL FMMIN(M18,M32,M20) + CALL FMADDI(M20,-1) + CALL FMLN(M20,M16) + CALL FMMPY(M18,M16,M06) + CALL FMSUB(M06,M20,M16) + CALL FMEXP(M16,M22) + IF ((M22(1) == MEXPOV .AND. M22(2) /= 0 .AND. & + M22(-1) > 0) .OR. M22(1) > MXSAVE+1) THEN + CALL FMST2M('OVERFLOW',M25) + KFLAG = -5 + GO TO 160 + ENDIF + ENDIF + +! Determine which method to use. + +! NMETHD = 1 means use the convergent series, +! = 2 means use the asymptotic series, +! = 3 means use the continued fraction expansion. + + CALL FMI2M(-10000,M20) + CALL FMI2M(10000,M21) + CALL FMABS(M31,M23) + CALL FMABS(M32,M24) + CALL FMSUB(M24,M23,M22) + IF (FMCOMP(M22,'<=',M20)) THEN + NMETHD = 1 + ELSE IF (FMCOMP(M22,'>=',M21) .AND. M31(-1) > 0 & + .AND. M32(-1) > 0) THEN + NMETHD = 2 + ELSE IF (FMCOMP(M22,'>=',M21)) THEN + NMETHD = 3 + ELSE IF (M31(-1) > 0 .AND. M32(-1) > 0) THEN + CALL FMDP2M(SQRT(DPMAX),M20) + IF (FMCOMP(M32,'>=',M20)) THEN + KFLAG = -5 + CALL FMST2M('OVERFLOW',M25) + GO TO 160 + ENDIF + + C2 = REAL(DBLE(NDSAVE)*DLOGMB) + C1 = REAL(DBLE(C2)/10.0D0 + A + 10.0D0) + C2 = REAL(MAX( 10.0D0 , DBLE(C2)/6.0D0 , & + A - 3.5D0*A/(SQRT(A)+1.0D0))) + IF (X < C1) THEN + NMETHD = 1 + ELSE + NMETHD = 3 + ENDIF + IF (X > C2) THEN + +! Check that the smallest term in the asymptotic series is +! small enough to give the required accuracy. + + T1 = FMDPLG(A) + SMALL = T1 - FMDPLG(-ABS(X)) - (A+ABS(X))*LOG(ABS(X)) + TOL = -DBLE(NDIG+2)*DLOGMB - 12.0D0 + B = 1.0D0 + IF (A > ABS(X)) B = A - ABS(X) + BIG = T1 - FMDPLG(A-B) - B*LOG(ABS(X)) + IF (SMALL < TOL+BIG) NMETHD = 2 + ENDIF + ELSE IF (M31(-1) < 0 .AND. M32(-1) > 0) THEN + TLNB = REAL(NDIG)*ALOGMB + C = 0.75/TLNB**0.35 + D = 0.80*TLNB**0.70 + IF (KFLAGA == 0 .AND. KFLAGX == 0) THEN + T = REAL(-A) - D/C + Y = D + C*T/2.0 + (C/2.0)*SQRT(T**2 + T + (2.0/C)**2) + IF (X > Y) THEN + NMETHD = 3 + ELSE + NMETHD = 1 + ENDIF + ELSE + CALL FMDPM(DBLE(C),M16) + CALL FMMPY(M16,M31,M20) + M20(-1) = 1 + IF (FMCOMP(M32,'>',M20)) THEN + NMETHD = 3 + ELSE + NMETHD = 1 + ENDIF + ENDIF + ELSE IF (M31(-1) > 0 .AND. M32(-1) < 0) THEN + CALL FMDPM(DBLE(-0.8),M16) + CALL FMMPY(M16,M31,M20) + IF (FMCOMP(M20,'<',M32)) THEN + NMETHD = 1 + ELSE + NMETHD = 3 + ENDIF + ENDIF + + IF (NMETHD == 2) GO TO 130 + IF (NMETHD == 3) GO TO 150 + +! Method 1. Use the X**N/Pochhammer(A+1,N) series. + +! M25 is the current sum. +! M21 is the current term. +! M20 is (A+N)/X. +! M29 is 1/X + +! Raise the precision if A is negative and near an integer, +! to compensate for cancellation when (A+N)/X is near zero. + + IF (M31(-1) < 0) THEN + CALL FMNINT(M31,M25) + CALL FMSUB(M31,M25,M29) + IEXTRA = MAX(-INT(M29(1)),0) + IF (IEXTRA > 0 .AND. NDIG+IEXTRA <= NDG2MX) THEN + CALL FMEQ2_R1(M31,NDIG,NDIG+IEXTRA) + CALL FMEQ2_R1(M32,NDIG,NDIG+IEXTRA) + ENDIF + NDOLD = NDIG + NDIG = NDIG + IEXTRA + IF (NDIG > NDG2MX) THEN + KFLAG = -9 + CALL FMWRN2 + NDIG = NDOLD + CALL FMST2M('UNKNOWN',M25) + GO TO 180 + ENDIF + ENDIF + + JEXTRA = 0 + + 120 CALL FMI2M(1,M25) + CALL FMI2M(1,M18) + CALL FMADD(M31,M18,M20) + CALL FMDIV(M32,M20,M21) + CALL FMDIV_R1(M20,M32) + CALL FMDIV(M18,M32,M29) + NDSAV1 = NDIG + MAXE = 1 + +! If A is negative and ABS(A) > ABS(X), the terms in the +! series first decrease, then increase, then decrease. +! Try to predict the number of extra digits required to +! keep the precision from prematurely becoming too small. + + KFLGOK = 1 + IF (M31(-1) < 0) THEN + IF (KFLAGA == 0) THEN + IF (ABS(A) > 1.0D3) THEN + NMETHD = 3 + GO TO 150 + ENDIF + ELSE + NMETHD = 3 + GO TO 150 + ENDIF + KFLGOK = 0 + CALL FMABS(M31,M05) + CALL FMABS(M32,M06) + IF (FMCOMP(M05,'>',M06)) THEN + IF (JEXTRA == 0) THEN + IF (KFLAGA == 0 .AND. KFLAGX == 0) THEN + T1 = FMDPLG(A+AINT(-ABS(X)-A)) - & + FMDPLG(A+1.0D0+AINT(ABS(X)-A)) + T1 = (T1 + 2.0D0*ABS(X)*LOG(ABS(X)+1.0D-10))/ & + DLOGMB + T1 = MAX(0.0D0,T1+1.0D0) + JEXTRA = INT(MIN(DBLE(NDIGMX),T1)) + ENDIF + ENDIF + +! If A is negative and ABS(A) is much bigger than ABS(X), +! the later increase in the size of the terms can be +! ignored. + + IF (KFLAGA == 0 .AND. KFLAGX == 0) THEN + T1 = (AINT(X-A)*LOG(ABS(X)+1.0D-10) + FMDPLG(A+1.0D0) & + - FMDPLG(A+1.0D0+AINT(X-A))) / DLOGMB + IF (T1 < -DBLE(NDIG)) KFLGOK = 1 + ELSE + KFLGOK = 1 + ENDIF + ENDIF + ENDIF + + NMNNDG = NDSAV1 + NMXDIF = 0 + +! Method 1 summation loop. + + DO J = 1, NTERMS + NDIG = NDSAV1 + MAXE = MAX(MAXE,M21(1)) + CALL FMADD_R1(M25,M21) + IF (KFLAG /= 0) THEN + IF (KFLGOK == 0 .AND. KFLAGA == 0 .AND. KFLAGX == 0) THEN + IF (DBLE(J) > X-A) EXIT + ELSE + EXIT + ENDIF + ENDIF + + CALL FMADD_R1(M20,M29) + + NDIG2 = MAX(2,NDSAV1-INT(M25(1)-M21(1))) + NDIG = MIN(NDSAV1,NDIG2+JEXTRA) + NMNNDG = MIN(NMNNDG,NDIG) + NMXDIF = MAX(NMXDIF,NDIG-NMNNDG) + CALL FMDIV_R1(M21,M20) + ENDDO + + NDIG = NDSAV1 + IF (NMXDIF > JEXTRA+1) THEN + JEXTRA = NMXDIF + GO TO 120 + ENDIF + + CALL FMABS(M32,M16) + CALL FMLN(M16,M17) + CALL FMMPY(M31,M17,M06) + CALL FMSUB(M06,M32,M29) + CALL FMEXP(M29,M30) + CALL FMDIV(M25,M31,M24) + CALL FMMPY(M30,M24,M23) + IF (M23(1) == MUNKNO) THEN + CALL FMLN(M25,M16) + CALL FMLN(M31,M17) + CALL FMADD(M29,M16,M06) + CALL FMSUB(M06,M17,M29) + CALL FMEXP(M29,M25) + ELSE + CALL FMEQ(M23,M25) + ENDIF + IF (KXNEG == 1 .AND. MODA2 == 1 .AND. M25(1) /= MUNKNO .AND. & + M25(2) /= 0) THEN + M25(-1) = -M25(-1) + ENDIF + + GO TO 160 + +! Method 2. Use the Pochhammer(A-N,N)/X**N series. + +! M25 is the current sum. +! M21 is the current term. +! M20 is (A-N)/X. +! M29 is -1/X + +! Raise the precision if A is positive and near an integer, +! to compensate for cancellation when (A-N)/X is near zero. + + 130 IF (M31(-1) > 0) THEN + CALL FMNINT(M31,M25) + CALL FMSUB(M31,M25,M29) + IEXTRA = MAX(-INT(M29(1)),0) + IF (IEXTRA > 0 .AND. NDIG+IEXTRA <= NDG2MX) THEN + CALL FMEQ2_R1(M31,NDIG,NDIG+IEXTRA) + CALL FMEQ2_R1(M32,NDIG,NDIG+IEXTRA) + ENDIF + NDOLD = NDIG + NDIG = NDIG + IEXTRA + IF (NDIG > NDG2MX) THEN + KFLAG = -9 + CALL FMWRN2 + NDIG = NDOLD + CALL FMST2M('UNKNOWN',M25) + GO TO 180 + ENDIF + ENDIF + + CALL FMGAM(M31,M30) + IF (KFLAGA == 0 .AND. KFLAGX == 0) THEN + NT = INT(((A-1)*LOG(ABS(X)+1.0D-10) - X)/DLOGMB) + LESS = MAX(0,INT(M30(1)) - NT - 1) + IF (LESS > NDIG .AND. ABS(A) < ABS(X)) THEN + CALL FMEQ(M30,M25) + GO TO 160 + ENDIF + ENDIF + IF (KFLAG /= 0) THEN + CALL FMEQ(M30,M25) + GO TO 160 + ENDIF + IF (KXNEG == 0) THEN + CALL FMLN(M32,M29) + CALL FMMPY(M31,M29,M16) + CALL FMSUB(M16,M32,M25) + CALL FMSUB_R2(M25,M29) + CALL FMEXP(M29,M21) + ELSE + CALL FMI2M(1,M16) + CALL FMSUB(M31,M16,M25) + CALL FMPWR(M32,M25,M29) + CALL FMEXP(M32,M24) + CALL FMDIV(M29,M24,M21) + ENDIF + +! Here M21 is X**(A-1)/EXP(X). + + M21(-1) = -M21(-1) + CALL FMEQ(M30,M25) + CALL FMDIV(M31,M32,M20) + CALL FMI2M(1,M16) + CALL FMDIV(M16,M32,M29) + IF (M29(1) /= MUNKNO .AND. M29(2) /= 0) M29(-1) = -M29(-1) + NDSAV1 = NDIG + +! Disable NDIG reduction until the terms in the sum +! begin to decrease in size. + + BIGJ = 0 + IF (KFLAGA == 0 .AND. KFLAGX == 0) BIGJ = ABS(A) - ABS(X) + JTERMS = NTERMS + IF (KFLAGI == 0 .AND. INTA > 0) THEN + JTERMS = INTA + ELSE IF (KFLAGA == 0 .AND. KFLAGX == 0) THEN + T1 = A + ABS(X) + IF (T1 > 0 .AND. T1 < DBLE(NTERMS)) JTERMS = INT(T1) + 2 + ENDIF + +! Method 2 summation loop. + + DO J = 1, JTERMS + NDIG = NDSAV1 + CALL FMADD_R1(M25,M21) + IF (KFLAG /= 0 .AND. J > 1) GO TO 140 + CALL FMADD_R1(M20,M29) + IF (REAL(J) >= BIGJ) THEN + NDIG2 = MAX(2,NDSAV1-INT(M25(1)-M21(1))) + NDIG = MIN(NDSAV1,NDIG2) + ENDIF + CALL FMMPY_R1(M21,M20) + ENDDO + + 140 NDIG = NDSAV1 + GO TO 160 + +! Method 3. Use the continued fraction expansion. + +! M29 is the current approximation. +! M25 is the previous approximation. +! M21, M22 are the latest numerators. +! M23, M24 are the latest denominators. + + 150 CALL FMGAM(M31,M30) + NDSAV1 = NDIG + IF (KFLAGA == 0 .AND. KFLAGX == 0) THEN + NT = INT(((A-1)*LOG(ABS(X)+1.0D-10) - X)/DLOGMB) + LESS = MAX(0,INT(M30(1)) - NT - 1) + IF (LESS > NDIG) THEN + CALL FMEQ(M30,M25) + GO TO 160 + ENDIF + NDIG = MAX(2,NDIG-LESS) + ENDIF + JEXTRA = INT(MAX(1.0,5.76/ALOGMB + 1.0)) + IF (NDIG+JEXTRA > NDG2MX) JEXTRA = NDG2MX - NDIG + IF (NDIG+JEXTRA > NDSAV1) THEN + CALL FMEQ2_R1(M31,NDSAV1,NDSAV1+JEXTRA) + CALL FMEQ2_R1(M32,NDSAV1,NDSAV1+JEXTRA) + ENDIF + NDIG = NDIG + JEXTRA + CALL FMI2M(0,M21) + CALL FMI2M(1,M22) + CALL FMI2M(1,M23) + CALL FMEQ2(M32,M24,NDSAV1,NDIG) + CALL FMI2M(0,M29) + CALL FMEQ2(M31,M20,NDSAV1,NDIG) + IF (M20(1) /= MUNKNO .AND. M20(2) /= 0) M20(-1) = -M20(-1) + CALL FMI2M(1,M19) + + JCHECK = 10 + IF (INTA == 1) CALL FMDIV(M22,M32,M29) + +! Method 3 continued fraction loop. + + METHOD3: DO J = 1, MIN(NTERMS,INTA-1) + CALL FMADD_R1(M20,M19) + CALL FMMPY_R2(M20,M21) + CALL FMADD_R2(M22,M21) + CALL FMMPY_R2(M20,M23) + CALL FMADD_R2(M24,M23) + CALL FMMPY(M32,M21,M18) + CALL FMMPYI_R1(M22,J) + CALL FMADD_R2(M18,M22) + CALL FMMPY(M32,M23,M18) + CALL FMMPYI_R1(M24,J) + CALL FMADD_R2(M18,M24) + +! Normalize to make overflow or underflow less likely. + + KMID = INT((MAX(M21(1),M22(1),M23(1),M24(1)) + & + MIN(M21(1),M22(1),M23(1),M24(1))) / 2) + M21(1) = M21(1) - KMID + M22(1) = M22(1) - KMID + M23(1) = M23(1) - KMID + M24(1) = M24(1) - KMID + +! Form the quotient and check for convergence. + + IF (MOD(J,JCHECK) == 0 .OR. J == INTA-1) THEN + CALL FMEQ(M29,M25) + CALL FMDIV(M22,M24,M29) + DO K = NDIG-JEXTRA, 1, -1 + IF (M25(K) /= M29(K)) CYCLE METHOD3 + ENDDO + EXIT + ENDIF + ENDDO METHOD3 + + CALL FMEQ2_R1(M29,NDIG,NDSAV1) + NDIG = NDSAV1 + IF (M32(-1) > 0) THEN + CALL FMLN(M32,M16) + CALL FMMPY(M31,M16,M06) + CALL FMSUB(M06,M32,M16) + CALL FMEXP(M16,M24) + ELSE IF (KFLAGI == 0) THEN + CALL FMEXP(M32,M25) + CALL FMIPWR(M32,INTA,M16) + CALL FMDIV(M16,M25,M24) + ELSE + CALL FMABS(M32,M16) + CALL FMLN(M16,M17) + CALL FMMPY(M31,M17,M06) + CALL FMSUB(M06,M32,M16) + CALL FMEXP(M16,M24) + IF (MODA2 == 1) M24(-1) = -1 + ENDIF + + IF (M24(1) /= MEXPOV) THEN + CALL FMMPY(M24,M29,M25) + ELSE IF (M24(1)+M29(1) >= MXEXP2/2) THEN + CALL FMEQ(M24,M25) + IF (M29(-1) < 0 .AND. M25(1) /= MUNKNO .AND. & + M25(2) /= 0) M25(-1) = -M25(-1) + ELSE + CALL FMMPY(M24,M29,M25) + ENDIF + CALL FMSUB_R2(M30,M25) + +! Check for too much cancellation. + + 160 IF (NCALL <= 1) THEN + NGOAL = INT(REAL(NDSAVE)*ALOGM2) + 17 + ELSE + NGOAL = INT(-MXEXP2) + ENDIF + IF (M25(0) <= NGOAL) THEN + IF (NUMTRY > 0) THEN + NDGOAL = INT(REAL(NGOAL)/ALOGM2 + 1.0) + DO J = 1, NDGOAL+1 + IF (MRETRY(J) /= M25(J)) GO TO 170 + ENDDO + GO TO 180 + ENDIF + 170 IEXTRA = INT(REAL(NGOAL-M25(0))/ALOGM2 + 23.03/ALOGMB) + 1 + NDOLD = NDIG + NDIG = NDIG + IEXTRA + IF (NDIG > NDG2MX) THEN + KFLAG = -9 + CALL FMWRN2 + NDIG = NDOLD + CALL FMST2M('UNKNOWN',M25) + GO TO 180 + ENDIF + CALL FMEQ2_R1(M31,NDSAVE,NDIG) + CALL FMEQ2_R1(M32,NDSAVE,NDIG) + NUMTRY = NUMTRY + 1 + CALL FMEQ2(M25,MRETRY,NDOLD,NDIG) + GO TO 110 + ENDIF + + 180 MACMAX = NINT(NDSAVE*ALOGM2) + M25(0) = MIN(M25(0),MACCA,MACCB,MACMAX) + CALL FMEXT2(M25,MC,NDSAVE,MXSAVE,KASAVE,KOVUN) + RETURN + END SUBROUTINE FMIGM1 + + SUBROUTINE FMIGM2(MA,MB,MC) + +! MC = Incomplete Gamma(MA,MB) + +! Integral from MB to infinity of e**(-t) * t**(MA-1) dt. + +! This is (upper case) Gamma(a,x). + + USE FMVALS + IMPLICIT NONE + + REAL (KIND(1.0D0)) :: MA(-1:LUNPCK),MB(-1:LUNPCK),MC(-1:LUNPCK) + DOUBLE PRECISION FMDPLG,X,A,B,SMALL,BIG,TOL,T1,T2,BIGJ,C1,C2 + REAL (KIND(1.0D0)) :: MACCA,MACCB,MACMAX,MAS,MAXM09,MBS,MODA2,MXSAVE + INTEGER IEXTRA,INTA,INTG,J,JCHECK,JEXTRA,JTERMS,K,KABIGR,KASAVE, & + KFLAGA,KFLAGI,KFLAGX,KFLGOK,KMETH4,KMID,KOVUN,KRESLT, & + KWRNSV,KXNEG,N,NDGOAL,NDIG2,NDOLD,NDSAV1,NDSAVE,NGOAL, & + NMETHD,NMNNDG,NMXDIF,NTERMS,NUMTRY + LOGICAL FMCOMP + + CALL FMENT2('FMIGM2',MA,MB,2,1,MC,KRESLT,NDSAVE,MXSAVE,KASAVE, & + KOVUN) + IF (KRESLT /= 0) RETURN + + KACCSW = 1 + MAS = MA(-1) + MBS = MB(-1) + MACCA = MA(0) + MACCB = MB(0) + CALL FMEQ2(MA,M31,NDSAVE,NDIG) + M31(0) = NINT(NDIG*ALOGM2) + CALL FMEQ2(MB,M32,NDSAVE,NDIG) + M32(0) = NINT(NDIG*ALOGM2) + KMETH4 = 0 + NUMTRY = 0 + + 110 NTERMS = INT(INTMAX/10) + +! A,X are double precision approximations to the two +! arguments to this function. +! INTA = A if A is a small integer. It is used to limit +! the number of terms used in the asymptotic series +! and in the continued fraction expansion. + + INTA = NTERMS + KWRNSV = KWARN + KWARN = 0 + CALL FMM2I(M31,INTG) + KFLAGI = KFLAG + IF (KFLAG == 0) INTA = INTG + CALL FMM2DP(M31,A) + KFLAGA = KFLAG + IF (KFLAG /= 0 .AND. M31(1) < 0) THEN + A = 1.0D0/DPMAX + IF (M31(-1) < 0) A = -A + KFLAGA = 0 + ENDIF + CALL FMM2DP(M32,X) + KFLAGX = KFLAG + IF (KFLAG /= 0 .AND. M32(1) < 0) THEN + X = 1.0D0/DPMAX + IF (M32(-1) < 0) X = -X + KFLAGX = 0 + ENDIF + KWARN = KWRNSV + +! If A or X is large in magnitude use more guard digits. + + IEXTRA = MIN(MAX(INT(M31(1)),INT(M32(1)),0) , & + INT(1.0+ALOGMX/ALOGMB)) + IF (IEXTRA > 0 .AND. NDIG+IEXTRA <= NDG2MX) THEN + CALL FMEQ2_R1(M31,NDIG,NDIG+IEXTRA) + CALL FMEQ2_R1(M32,NDIG,NDIG+IEXTRA) + ENDIF + NDIG = NDIG + IEXTRA + IF (NDIG > NDG2MX) THEN + KFLAG = -9 + CALL FMWRN2 + NDIG = NDIG - IEXTRA + CALL FMST2M('UNKNOWN',M25) + GO TO 190 + ENDIF + +! KXNEG = 1 if X is negative and A is a positive integer. + + KXNEG = 0 + +! MODA2 = MOD(A,2) when KXNEG is 1. + + MODA2 = 0 + +! Check for special cases. + + IF (M31(1) == MEXPOV .OR. M32(1) == MEXPOV) THEN + IF (M31(1) == MEXPOV .AND. M31(2) /= 0 .AND. & + M31(-1) > 0) THEN + IF (M32(1) /= MEXPOV) THEN + CALL FMST2M('OVERFLOW',M25) + KFLAG = -5 + GO TO 170 + ENDIF + ENDIF + IF (M32(1) == MEXPOV .AND. M32(2) /= 0 .AND. & + M32(-1) > 0) THEN + CALL FMBIG(M26) + M26(1) = MXSAVE + 1 + CALL FMLN(M26,M16) + CALL FMDIV(M26,M16,M27) + IF (FMCOMP(M31,'<=',M27)) THEN + CALL FMST2M('UNDERFLOW',M25) + KFLAG = -6 + GO TO 170 + ELSE + CALL FMST2M('UNKNOWN',M25) + KFLAG = -4 + GO TO 190 + ENDIF + ENDIF + IF (M32(1) == MEXPOV .AND. M32(-1) < 0 .AND. & + M31(-1) > 0 .AND. M31(2) /= 0) THEN + IF (M31(1) /= MEXPOV) THEN + CALL FMINT(M31,M24) + IF (FMCOMP(M31,'==',M24)) THEN + CALL FMI2M(2,M21) + CALL FMMOD(M24,M21,M16) + CALL FMEQ(M16,M21) + IF (M21(2) /= 0) THEN + CALL FMST2M('OVERFLOW',M25) + KFLAG = -5 + GO TO 170 + ELSE + CALL FMST2M('-OVERFLOW',M25) + KFLAG = -5 + GO TO 170 + ENDIF + ENDIF + ENDIF + ENDIF + IF (M31(1) == MEXPOV .AND. M31(-1) < 0 .AND. & + M31(2) /= 0) THEN + IF (M32(1) /= MEXPOV .AND. M32(-1) > 0 .AND. & + M32(2) /= 0) THEN + CALL FMI2M(1,M16) + IF (FMCOMP(M32,'<',M16)) THEN + CALL FMST2M('OVERFLOW',M25) + KFLAG = -5 + GO TO 170 + ELSE + CALL FMST2M('UNDERFLOW',M25) + KFLAG = -6 + GO TO 170 + ENDIF + ENDIF + ENDIF + CALL FMST2M('UNKNOWN',M25) + KFLAG = -4 + GO TO 190 + ENDIF + + IF (M31(1) == MEXPUN .OR. M32(1) == MEXPUN) THEN + IF (M31(1) == MEXPUN .AND. M32(1) == MEXPUN) THEN + CALL FMST2M('UNKNOWN',M25) + KFLAG = -4 + GO TO 190 + ENDIF + IF (M32(1) == MEXPUN .AND. M32(-1) > 0 .AND. & + M32(2) /= 0) THEN + IF (M31(1) >= 1) THEN + CALL FMGAM(M31,M30) + CALL FMEQ(M30,M25) + GO TO 170 + ELSE + CALL FMST2M('UNKNOWN',M25) + KFLAG = -4 + GO TO 190 + ENDIF + ENDIF + ENDIF + + IF (M32(2) == 0) THEN + IF (M31(-1) < 0 .OR. M31(2) == 0) THEN + CALL FMST2M('UNKNOWN',M25) + KFLAG = -4 + GO TO 190 + ELSE + CALL FMGAM(M31,M30) + CALL FMEQ(M30,M25) + GO TO 170 + ENDIF + ENDIF + IF (M32(-1) < 0) THEN + CALL FMINT(M31,M24) + IF (FMCOMP(M31,'==',M24) .AND. M31(-1)*M31(2) > 0) THEN + KXNEG = 1 + CALL FMI2M(2,M21) + CALL FMMOD(M24,M21,M16) + CALL FMEQ(M16,M21) + IF (M21(2) /= 0) MODA2 = 1 + ELSE + CALL FMST2M('UNKNOWN',M25) + KFLAG = -4 + GO TO 190 + ENDIF + ENDIF + IF (M32(1) == MEXPUN) THEN + CALL FMGAM(M31,M30) + CALL FMEQ(M30,M25) + GO TO 170 + ENDIF + IF (M31(1) == MEXPUN) THEN + CALL FMI2M(0,M31) + MAS = 1 + ENDIF + CALL FMMAX(M31,M32,M16) + CALL FMMIN(M31,M32,M17) + CALL FMDPM(1.0D6,M05) + CALL FMDPM(1.0D2,M06) + IF (FMCOMP(M16,'>=',M05) .AND. FMCOMP(M17,'>=',M06)) THEN + CALL FMI2M(1,M16) + CALL FMSUB(M31,M16,M18) + CALL FMMAX(M18,M32,M20) + CALL FMADDI(M20,1) + CALL FMLN(M20,M16) + CALL FMMPY(M18,M16,M06) + CALL FMSUB(M06,M20,M16) + CALL FMEXP(M16,M22) + IF ((M22(1) == MEXPOV .AND. M22(-1) > 0 .AND. & + M22(2) /= 0) .OR. M22(1) > MXSAVE+1) THEN + CALL FMST2M('OVERFLOW',M25) + KFLAG = -5 + GO TO 170 + ENDIF + ENDIF +! Determine which method to use. + +! NMETHD = 1 means use the convergent series, +! = 2 means use the asymptotic series, +! = 3 means use the continued fraction expansion, +! = 4 means use an O(A**2) formula. + + CALL FMI2M(-10000,M20) + CALL FMI2M(10000,M21) + CALL FMABS(M31,M23) + CALL FMABS(M32,M24) + CALL FMSUB(M24,M23,M22) + KABIGR = 1 + IF (M22(2) >= 0 .AND. M22(-1) > 0) KABIGR = 0 + NMETHD = 0 + IF (FMCOMP(M22,'<=',M20)) THEN + IF (M31(-1) > 0 .AND. M31(2) /= 0) THEN + NMETHD = 1 + ELSE + NMETHD = 3 + ENDIF + ELSE IF (FMCOMP(M22,'>=',M21) .AND. M31(-1) > 0 .AND. & + M31(2) > 0 .AND. M32(-1) > 0 .AND. & + M32(2) > 0) THEN + NMETHD = 2 + ELSE IF (FMCOMP(M22,'>=',M21)) THEN + NMETHD = 3 + ELSE IF (M31(-1) > 0 .AND. M32(-1) > 0 .AND. & + M32(2) > 0) THEN + CALL FMDP2M(SQRT(DPMAX),M20) + IF (FMCOMP(M32,'>=',M20)) THEN + KFLAG = -5 + CALL FMST2M('OVERFLOW',M25) + GO TO 170 + ENDIF + + IF (M31(-1) > 0 .AND. M31(2) /= 0) THEN + C2 = DBLE(NDSAVE)*DLOGMB/6.0D0 + C1 = MAX( 10.0D0 , C2 , A ) + C2 = MAX( 10.0D0 , C2 , A - 6.5D0*A/(SQRT(A)+1.0D0) ) + ELSE + C1 = MAX( 15.0D0 , DBLE(NDSAVE)*DLOGMB/5.0D0 ) + C2 = C1 + ENDIF + IF (X < MIN(C1,C2)) THEN + IF (-2*M31(1) > NDIG .OR. M31(2) == 0) THEN + NMETHD = 4 + ELSE + NMETHD = 1 + ENDIF + ELSE IF (X > C2) THEN + +! Check that the smallest term in the asymptotic series is +! small enough to give the required accuracy. + + T1 = FMDPLG(A) + SMALL = T1 - FMDPLG(-ABS(X)) - (A+ABS(X))*LOG(ABS(X)) + TOL = -DBLE(NDIG+2)*DLOGMB - 12.0D0 + B = 1.0D0 + IF (A > ABS(X)) B = A - ABS(X) + BIG = T1 - FMDPLG(A-B) - B*LOG(ABS(X)) + IF (SMALL < TOL+BIG) NMETHD = 2 + ENDIF + IF (NMETHD == 0 .AND. X > C1) NMETHD = 3 + IF (NMETHD == 0) NMETHD = 1 + ELSE IF (M31(-1) < 0 .AND. M32(-1) > 0 .AND. & + M32(2) > 0) THEN + CALL FMDP2M(SQRT(DPMAX),M20) + IF (FMCOMP(M32,'>=',M20)) THEN + KFLAG = -6 + CALL FMST2M('UNDERFLOW',M25) + GO TO 170 + ENDIF + + C1 = MAX( 10.0D0 , DBLE(NDSAVE)*DLOGMB/7.0D0 ) + C2 = -2.0D0*A + IF (X < C1) THEN + IF (-2*M31(1) > NDIG) THEN + NMETHD = 4 + ELSE + NMETHD = 1 + ENDIF + ELSE IF (X > C2) THEN + T1 = FMDPLG(A) + SMALL = T1 - FMDPLG(-ABS(X)) - (A+ABS(X))*LOG(ABS(X)) + TOL = -DBLE(NDIG+2)*DLOGMB - 12.0D0 + B = 1.0D0 + IF (A > ABS(X)) B = A - ABS(X) + BIG = T1 - FMDPLG(A-B) - B*LOG(ABS(X)) + IF (SMALL < TOL+BIG) NMETHD = 2 + ENDIF + IF (NMETHD == 0 .AND. X > C1) NMETHD = 3 + IF (NMETHD == 0) NMETHD = 1 + ELSE IF (M31(-1) > 0 .AND. M31(2) > 0 .AND. & + M32(-1) < 0) THEN + CALL FMEQ(M32,M20) + IF (M20(1) /= MUNKNO .AND. M20(2) /= 0) M20(-1) = -M20(-1) + CALL FMMPYI(M31,2,M21) + IF (FMCOMP(M20,'<',M31)) THEN + NMETHD = 1 + ELSE IF (FMCOMP(M20,'<',M21)) THEN + NMETHD = 3 + ELSE + NMETHD = 2 + ENDIF + ENDIF + + IF (NMETHD == 2) GO TO 130 + IF (NMETHD == 3) GO TO 150 + IF (NMETHD == 4) GO TO 160 + +! Method 1. Use the X**N/Pochhammer(A+1,N) series. + +! M25 is the current sum. +! M21 is the current term. +! M20 is (A+N)/X. +! M29 is 1/X + +! Raise the precision if A is negative and near an integer, +! to compensate for cancellation when (A+N)/X is near zero. +! Raise the precision if A is positive and near zero, since +! there will be cancellation in subtracting the sum from +! Gamma(A). +! If A is a negative integer use method 3 or 4. + + IEXTRA = 0 + IF (M31(-1) < 0) THEN + IF (KFLAGA == 0) THEN + IF (ABS(A) > 1.0D3) THEN + NMETHD = 3 + GO TO 150 + ENDIF + ELSE + NMETHD = 3 + GO TO 150 + ENDIF + CALL FMNINT(M31,M25) + IF (FMCOMP(M25,'==',M31)) THEN + IF (KFLAGI == 0) THEN + IF (KFLAGX /= 0) THEN + GO TO 150 + ELSE + IF (ABS(X) <= 20.0D0) THEN + C1 = 0.7D0*(DBLE(NDSAVE)*DLOGMB* & + (20.0D0-X))**0.75D0 + IF (ABS(A) > C1) THEN + GO TO 150 + ELSE + GO TO 160 + ENDIF + ELSE + GO TO 150 + ENDIF + ENDIF + ELSE + GO TO 150 + ENDIF + ENDIF + CALL FMSUB(M31,M25,M29) + IEXTRA = MAX(-2*INT(M29(1)),-INT(M31(1))+1,0) + ELSE + IEXTRA = MAX(-INT(M31(1))+1,0) + ENDIF + +! Raise the precision further as X increases in magnitude. + + IF (KFLAGX == 0 .AND. KFLAGA == 0) THEN + T1 = (0.92D0 + (X-A) + (A-0.5D0)*LOG(ABS(A)+1.0D-10) - & + (A-1.0D0)*LOG(ABS(X)+1.0D-10))/DLOGMB + IF (T1 > 0 .AND. ABS(X) > 1.0D0) THEN + IF (A < 0.0D0 .OR. X >= A) THEN + IEXTRA = IEXTRA + MAX(0,INT(T1)+1) + ENDIF + ENDIF + ENDIF + + IF (IEXTRA > 0 .AND. NDIG+IEXTRA <= NDG2MX) THEN + CALL FMEQ2_R1(M31,NDIG,NDIG+IEXTRA) + CALL FMEQ2_R1(M32,NDIG,NDIG+IEXTRA) + ENDIF + NDIG = NDIG + IEXTRA + IF (NDIG > NDG2MX) THEN + KFLAG = -9 + CALL FMWRN2 + NDIG = NDIG - IEXTRA + CALL FMST2M('UNKNOWN',M25) + GO TO 190 + ENDIF + + JEXTRA = 0 + + 120 IF (KABIGR == 1) THEN + CALL FMGAM(M31,M30) + IF (KFLAG /= 0) THEN + CALL FMEQ(M30,M25) + GO TO 170 + ENDIF + CALL FMEQ(M30,M25) + ELSE + CALL FMI2M(0,M25) + ENDIF + + MAXM09 = M25(1) + + CALL FMABS(M32,M29) + CALL FMLN(M29,M13) + CALL FMEQ(M13,M29) + CALL FMMPY_R2(M31,M29) + CALL FMSUB_R1(M29,M32) + CALL FMEXP(M29,M30) + CALL FMDIV(M30,M31,M21) + IF (M21(1) == MUNKNO) THEN + CALL FMLN(M31,M24) + CALL FMSUB_R1(M29,M24) + CALL FMEXP(M29,M21) + ENDIF + IF (KXNEG == 1 .AND. MODA2 == 1 .AND. M21(1) /= MUNKNO .AND. & + M21(2) /= 0) THEN + M21(-1) = -M21(-1) + ENDIF + + IF (M21(1) /= MUNKNO .AND. M21(2) /= 0) THEN + M21(-1) = -M21(-1) + ENDIF + CALL FMADD_R1(M25,M21) + MAXM09 = MAX(MAXM09,M25(1)) + + CALL FMI2M(1,M18) + CALL FMADD(M31,M18,M20) + CALL FMDIV_R1(M21,M20) + CALL FMMPY_R1(M21,M32) + CALL FMDIV_R1(M20,M32) + CALL FMDIV(M18,M32,M29) + NDSAV1 = NDIG + +! If A is negative and ABS(A) > ABS(X), the terms in the +! series first decrease, then increase, then decrease. +! Try to predict the number of extra digits required to +! keep the precision from prematurely becoming too small. + + KFLGOK = 1 + IF (M31(-1) < 0) THEN + KFLGOK = 0 + M31(-1) = 1 + M32(-1) = 1 + IF (FMCOMP(M31,'>',M32)) THEN + IF (JEXTRA == 0) THEN + IF (KFLAGA == 0 .AND. KFLAGX == 0) THEN + T1 = FMDPLG(A+AINT(-ABS(X)-A)) - & + FMDPLG(A+1.0D0+AINT(ABS(X)-A)) + T1 = (T1 + 2.0D0*ABS(X)*LOG(ABS(X)+1.0D-10))/ & + DLOGMB + T1 = MAX(0.0D0,T1+1.0D0) + JEXTRA = INT(MIN(DBLE(NDIGMX),T1)) + ENDIF + ENDIF + +! If A is negative and ABS(A) is much bigger than ABS(X), +! then the later increase in the size of the terms can be +! ignored. + + IF (KFLAGA == 0 .AND. KFLAGX == 0) THEN + T1 = (AINT(X-A)*LOG(ABS(X)+1.0D-10) + FMDPLG(A+1.0D0) & + - FMDPLG(A+1.0D0+AINT(X-A))) / DLOGMB + IF (T1 < -DBLE(NDIG)) KFLGOK = 1 + ELSE + KFLGOK = 1 + ENDIF + ENDIF + M31(-1) = MAS + M32(-1) = MBS + ENDIF + + NMNNDG = NDSAV1 + NMXDIF = 0 + +! Method 1 summation loop. + + DO J = 1, NTERMS + NDIG = NDSAV1 + CALL FMADD_R1(M25,M21) + MAXM09 = MAX(MAXM09,M25(1)) + IF (KFLAG /= 0) THEN + IF (KFLGOK == 0 .AND. KFLAGA == 0 .AND. KFLAGX == 0) THEN + IF (DBLE(J) > X-A) EXIT + ELSE + EXIT + ENDIF + ENDIF + + CALL FMADD_R1(M20,M29) + + NDIG2 = MAX(2,NDSAV1-INT(M25(1)-M21(1))) + NDIG = MIN(NDSAV1,NDIG2+JEXTRA) + NMNNDG = MIN(NMNNDG,NDIG) + NMXDIF = MAX(NMXDIF,NDIG-NMNNDG) + CALL FMDIV_R1(M21,M20) + ENDDO + + NDIG = NDSAV1 + IF (KABIGR == 0) THEN + CALL FMEQ(M25,M29) + CALL FMGAM(M31,M30) + IF (KFLAG /= 0) THEN + CALL FMEQ(M30,M25) + GO TO 170 + ENDIF + CALL FMADD(M30,M29,M25) + ENDIF + +! If too much cancellation occurred, raise the precision +! and do the calculation again. + + IEXTRA = NDIG - NDSAVE + IF (INT(MAXM09-M25(1)) >= IEXTRA-NGRD52/2) THEN + IEXTRA = IEXTRA + NGRD52 + IF (IEXTRA > 0 .AND. NDIG+IEXTRA <= NDG2MX) THEN + CALL FMEQ2_R1(M31,NDIG,NDIG+IEXTRA) + CALL FMEQ2_R1(M32,NDIG,NDIG+IEXTRA) + ENDIF + NDIG = NDIG + IEXTRA + IF (NDIG > NDG2MX) THEN + KFLAG = -9 + CALL FMWRN2 + NDIG = NDIG - IEXTRA + CALL FMST2M('UNKNOWN',M25) + GO TO 190 + ENDIF + GO TO 120 + ENDIF + + GO TO 170 + +! Method 2. Use the Pochhammer(A-N,N)/X**N series. + +! M25 is the current sum. +! M21 is the current term. +! M20 is (A-N)/X. +! M29 is -1/X + + 130 CALL FMABS(M32,M29) + CALL FMLN(M29,M13) + CALL FMEQ(M13,M29) + CALL FMMPY(M31,M29,M25) + CALL FMSUB_R2(M25,M29) + CALL FMSUB_R1(M29,M32) + CALL FMEXP(M29,M21) + IF (KXNEG == 1 .AND. MODA2 == 0 .AND. M21(1) /= MUNKNO .AND. & + M21(2) /= 0) M21(-1) = -M21(-1) + IF (ABS(M21(1)) >= MXEXP2) THEN + CALL FMEQ(M21,M25) + GO TO 170 + ENDIF + +! Here M21 is X**(A-1)/EXP(X). + + CALL FMI2M(0,M25) + CALL FMEQ(M31,M20) + CALL FMDIV_R1(M20,M32) + CALL FMI2M(1,M18) + CALL FMDIV(M18,M32,M29) + IF (M29(1) /= MUNKNO .AND. M29(2) /= 0) M29(-1) = -M29(-1) + NDSAV1 = NDIG + +! Disable NDIG reduction until the terms in the sum +! begin to decrease in size. + + BIGJ = 0 + IF (KFLAGA == 0 .AND. KFLAGX == 0) BIGJ = ABS(A) - ABS(X) + JTERMS = NTERMS + IF (KFLAGI == 0 .AND. INTA > 0) THEN + JTERMS = INTA + ELSE IF (KFLAGX == 0) THEN + IF (KFLAGA == 0) THEN + T1 = A + ABS(X) + IF (T1 > 0 .AND. T1 < DBLE(NTERMS)) JTERMS = INT(T1) + 2 + ELSE IF (M31(1) < 0) THEN + T1 = ABS(X) + IF (T1 > 0 .AND. T1 < DBLE(NTERMS)) JTERMS = INT(T1) + 2 + ENDIF + ENDIF + +! Method 2 summation loop. + + DO J = 1, JTERMS + NDIG = NDSAV1 + CALL FMADD_R1(M25,M21) + IF (KFLAG /= 0 .AND. J > 1) GO TO 140 + CALL FMADD_R1(M20,M29) + IF (REAL(J) >= BIGJ) THEN + NDIG2 = MAX(2,NDSAV1-INT(M25(1)-M21(1))) + NDIG = MIN(NDSAV1,NDIG2) + ENDIF + CALL FMMPY_R1(M21,M20) + ENDDO + + 140 NDIG = NDSAV1 + GO TO 170 + +! Method 3. Use the continued fraction expansion. + +! M29 is the current approximation. +! M25 is the previous approximation. +! M21, M22 are the latest numerators. +! M23, M24 are the latest denominators. + +! Raise the precision so that convergence of the +! continued fraction expansion is easier to detect. + + 150 JEXTRA = INT(MAX(1.0,5.76/ALOGMB + 1.0)) + +! Raise the precision further for small X if A is positive. + + IF (KFLAGX == 0 .AND. KFLAGA == 0) THEN + T1 = (0.92D0 + (ABS(X)-A) + (A-0.5D0)*LOG(ABS(A)+1.0D-10) - & + (A-1.0D0)*LOG(ABS(X)+1.0D-10))/DLOGMB + IF (T1 > 0.0D0 .AND. A > 0.0D0) THEN + IF (ABS(X) < A) THEN + JEXTRA = JEXTRA + MAX(0,INT(1.5D0*T1)+1) + IF (NDIG+JEXTRA > NDG2MX) THEN + NDIG = NDIG + JEXTRA + KFLAG = -9 + CALL FMWRN2 + NDIG = NDIG - JEXTRA + CALL FMST2M('UNKNOWN',M25) + GO TO 190 + ENDIF + ENDIF + ENDIF + ENDIF + NDSAV1 = NDIG + IF (NDIG+JEXTRA > NDG2MX) JEXTRA = NDG2MX - NDIG + IF (NDIG+JEXTRA > NDSAV1) THEN + CALL FMEQ2_R1(M31,NDSAV1,NDSAV1+JEXTRA) + CALL FMEQ2_R1(M32,NDSAV1,NDSAV1+JEXTRA) + ENDIF + NDIG = NDIG + JEXTRA + CALL FMI2M(0,M21) + CALL FMI2M(1,M22) + CALL FMI2M(1,M23) + CALL FMEQ2(M32,M24,NDSAV1,NDIG) + CALL FMI2M(0,M29) + CALL FMEQ2(M31,M20,NDSAV1,NDIG) + IF (M20(1) /= MUNKNO .AND. M20(2) /= 0) M20(-1) = -M20(-1) + CALL FMI2M(1,M19) + + JTERMS = NTERMS + JCHECK = 10 + IF (INTA == 1) CALL FMDIV(M22,M32,M29) + IF (INTA > 0) JTERMS = INTA - 1 + +! Method 3 continued fraction loop. + + METHOD3: DO J = 1, JTERMS + CALL FMADD_R1(M20,M19) + CALL FMMPY_R2(M20,M21) + CALL FMADD_R2(M22,M21) + CALL FMMPY_R2(M20,M23) + CALL FMADD_R2(M24,M23) + CALL FMMPYI_R1(M22,J) + CALL FMMPY(M32,M21,M30) + CALL FMADD_R2(M30,M22) + CALL FMMPYI_R1(M24,J) + CALL FMMPY(M32,M23,M30) + CALL FMADD_R2(M30,M24) + +! Normalize to make overflow or underflow less likely. + + KMID = INT((MAX(M21(1),M22(1),M23(1),M24(1)) + & + MIN(M21(1),M22(1),M23(1),M24(1))) / 2) + M21(1) = M21(1) - KMID + M22(1) = M22(1) - KMID + M23(1) = M23(1) - KMID + M24(1) = M24(1) - KMID + +! Form the quotient and check for convergence. + + IF (MOD(J,JCHECK) == 0 .OR. J == INTA-1) THEN + CALL FMEQ(M29,M25) + CALL FMDIV(M22,M24,M29) + DO K = NDIG-JEXTRA, 1, -1 + IF (M25(K) /= M29(K)) CYCLE METHOD3 + ENDDO + EXIT + ENDIF + ENDDO METHOD3 + + CALL FMEQ2_R1(M29,NDIG,NDSAV1) + NDIG = NDSAV1 + CALL FMABS(M32,M24) + CALL FMLN(M24,M13) + CALL FMEQ(M13,M24) + CALL FMMPY_R2(M31,M24) + CALL FMSUB_R1(M24,M32) + CALL FMEXP(M24,M12) + CALL FMEQ(M12,M24) + IF (KXNEG == 1 .AND. MODA2 == 1 .AND. M24(1) /= MUNKNO .AND. & + M24(2) /= 0) M24(-1) = -M24(-1) + IF (ABS(M24(1)) >= MXEXP2) THEN + CALL FMEQ(M24,M25) + IF (M29(-1) < 0 .AND. M25(1) /= MUNKNO .AND. & + M25(2) /= 0) M25(-1) = -M25(-1) + GO TO 170 + ENDIF + + CALL FMMPY(M24,M29,M25) + GO TO 170 + +! Method 4. Use the O(A**2) formula when A is small. + +! M25 is the current term. +! M29 is the current sum. + +! Raise the precision if X is larger than A +! in magnitude. The terms initially increase in size, +! and the final sum is small. + + 160 IEXTRA = 0 + +! If A is a negative integer, replace it by zero and later +! use a recurrence to recover the original function value. + + IF (KFLAGI == 0 .AND. INTA < 0) THEN + CALL FMI2M(0,M31) + A = 0.0D0 + KMETH4 = 1 + ENDIF + + IF (KFLAGX == 0) THEN + IF (KFLAGA == 0) THEN + T1 = ABS(X) - ABS(A) + ELSE + T1 = ABS(X) + ENDIF + IF (T1 > 0) THEN + T2 = (T1 + LOG(T1))/DLOGMB + IF (T2 > DBLE(MXEXP2/10)) T2 = DBLE(MXEXP2/10) + IEXTRA = INT(MAX(0.0D0,T2)) + ENDIF + T1 = ABS(X)+1.0D-10 + T2 = (T1 - 0.5D0*LOG(6.2831853D0*T1))/DLOGMB + IF (T2 > DBLE(MXEXP2/10)) T2 = DBLE(MXEXP2/10) + IEXTRA = IEXTRA + INT(MAX(0.0D0,T2)) + ENDIF + + IF (IEXTRA > 0 .AND. NDIG+IEXTRA <= NDG2MX) THEN + CALL FMEQ2_R1(M31,NDIG,NDIG+IEXTRA) + CALL FMEQ2_R1(M32,NDIG,NDIG+IEXTRA) + ENDIF + NDIG = NDIG + IEXTRA + IF (NDIG > NDG2MX) THEN + KFLAG = -9 + CALL FMWRN2 + NDIG = NDIG - IEXTRA + CALL FMST2M('UNKNOWN',M25) + GO TO 190 + ENDIF + + CALL FMEULR(M29) + CALL FMEQ(M29,M30) + M29(-1) = -1 + CALL FMABS(M32,M25) + CALL FMLN(M25,M24) + CALL FMSUB_R1(M29,M24) + IF (M31(2) /= 0 .AND. M31(1) >= -NDIG-1) THEN + CALL FMSQR(M24,M16) + CALL FMMPY(M16,M31,M06) + CALL FMDIVI(M06,2,M25) + CALL FMSUB_R1(M29,M25) + CALL FMSQR(M30,M23) + CALL FMPI(M22) + CALL FMSQR(M22,M16) + CALL FMDIVI(M16,6,M22) + CALL FMADD(M22,M23,M16) + CALL FMMPY(M16,M31,M06) + CALL FMDIVI(M06,2,M23) + CALL FMADD_R1(M29,M23) + ENDIF + + NDSAV1 = NDIG + CALL FMI2M(1,M23) + CALL FMADD(M31,M23,M22) + IF (FMCOMP(M23,'==',M22)) THEN + CALL FMI2M(-1,M25) + DO J = 1, NTERMS + NDIG2 = MAX(2,NDSAV1-INT(M29(1)-M25(1))) + NDIG = MIN(NDSAV1,NDIG2) + CALL FMMPY_R1(M25,M32) + IF (M25(1) /= MUNKNO .AND. M25(2) /= 0) M25(-1) = -M25(-1) + CALL FMDIVI_R1(M25,J) + CALL FMDIVI(M25,J,M24) + NDIG = NDSAV1 + CALL FMADD_R1(M29,M24) + IF (KFLAG /= 0) EXIT + ENDDO + ELSE + CALL FMPWR(M32,M31,M25) + IF (M25(1) /= MUNKNO .AND. M25(2) /= 0) M25(-1) = -M25(-1) + CALL FMEQ(M31,M30) + DO J = 1, NTERMS + NDIG2 = MAX(2,NDSAV1-INT(M29(1)-M25(1))) + NDIG = MIN(NDSAV1,NDIG2) + CALL FMMPY_R1(M25,M32) + IF (M25(1) /= MUNKNO .AND. M25(2) /= 0) M25(-1) = -M25(-1) + CALL FMDIVI_R1(M25,J) + NDIG = NDSAV1 + CALL FMADD_R1(M30,M23) + NDIG = MIN(NDSAV1,NDIG2) + CALL FMDIV(M25,M30,M24) + NDIG = NDSAV1 + CALL FMADD_R1(M29,M24) + IF (KFLAG /= 0) EXIT + ENDDO + ENDIF + CALL FMEQ(M29,M25) + +! Use the recurrence relation if A was a negative integer. + + IF (KFLAGI == 0 .AND. INTA < 0) THEN + N = -INTA + CALL FMI2M(1,M29) + CALL FMDIV_R1(M29,M32) + CALL FMEQ(M29,M24) + CALL FMEQ(M29,M23) + DO J = 1, N-1 + CALL FMMPYI_R1(M24,J) + CALL FMMPY_R1(M24,M23) + IF (M24(1) /= MUNKNO .AND. M24(2) /= 0) M24(-1) = -M24(-1) + CALL FMADD_R1(M29,M24) + ENDDO + CALL FMEXP(M32,M23) + CALL FMDIV_R1(M29,M23) + CALL FMSUB_R1(M25,M29) + CALL FMFCTI(N,M23) + CALL FMDIV_R1(M25,M23) + IF (MOD(N,2) == 1 .AND. M25(1) /= MUNKNO .AND. & + M25(2) /= 0) M25(-1) = -M25(-1) + ENDIF + +! Check for too much cancellation. + + 170 IF (NCALL <= 1) THEN + NGOAL = INT(REAL(NDSAVE)*ALOGM2) + 17 + ELSE + NGOAL = INT(-MXEXP2) + ENDIF + IF (M25(0) <= NGOAL) THEN + IF (NUMTRY > 0) THEN + NDGOAL = INT(REAL(NGOAL)/ALOGM2 + 1.0) + DO J = 1, NDGOAL+1 + IF (MRETRY(J) /= M25(J)) GO TO 180 + ENDDO + GO TO 190 + ENDIF + 180 IEXTRA = INT(REAL(NGOAL-M25(0))/ALOGM2 + 23.03/ALOGMB) + 1 + NDOLD = NDIG + NDIG = NDIG + IEXTRA + IF (NDIG > NDG2MX) THEN + KFLAG = -9 + CALL FMWRN2 + NDIG = NDIG - IEXTRA + CALL FMST2M('UNKNOWN',M25) + GO TO 190 + ENDIF + CALL FMEQ2_R1(M31,NDSAVE,NDIG) + IF (KMETH4 == 1) THEN + CALL FMI2M(INTA,M31) + ENDIF + CALL FMEQ2_R1(M32,NDSAVE,NDIG) + NUMTRY = NUMTRY + 1 + CALL FMEQ2(M25,MRETRY,NDOLD,NDIG) + GO TO 110 + ENDIF + + 190 MACMAX = NINT(NDSAVE*ALOGM2) + M25(0) = MIN(M25(0),MACCA,MACCB,MACMAX) + CALL FMEXT2(M25,MC,NDSAVE,MXSAVE,KASAVE,KOVUN) + RETURN + END SUBROUTINE FMIGM2 + + SUBROUTINE FMLNGM(MA,MB) + +! MB = LN(GAMMA(MA)) + + USE FMVALS + IMPLICIT NONE + + REAL (KIND(1.0D0)) :: MA(-1:LUNPCK),MB(-1:LUNPCK) + REAL (KIND(1.0D0)) :: MACCA,MACMAX,MAS,MXSAVE + INTEGER IEXTRA,INTA,J,J2,K,K0,K1,K2,KASAVE,KFL,KOVUN,KPT,KRESLT, & + KRSAVE,KSIGN,KWRNSV,LSHIFT,NDENOM,NDGOAL,NDIG2,NDMB,NDOLD, & + NDSAV1,NDSAVE,NDSV,NGOAL,NMXDIF,NTERM,NUMTRY + LOGICAL FMCOMP + CHARACTER(155) :: STRING + + CALL FMENT2('FMLNGM',MA,MA,1,1,MB,KRESLT,NDSAVE,MXSAVE,KASAVE, & + KOVUN) + IF (KRESLT /= 0) RETURN + MAS = MA(-1) + KACCSW = 1 + MACCA = MA(0) + CALL FMEQ2(MA,M25,NDSAVE,NDIG) + M25(0) = NINT(NDIG*ALOGM2) + CALL FMEQ(M25,M26) + NUMTRY = 0 + +! Near zero Gamma(x) is about 1/x. + + 110 IF (M26(1) < (-NDIG-3)) THEN + CALL FMLN(M26,M22) + IF (M22(1) /= MUNKNO .AND. M22(2) /= 0) M22(-1) = -M22(-1) + GO TO 140 + ENDIF + +! Check for special cases. + + IF (MAS < 0) THEN + KFL = 0 + IF (M25(1) <= NDSAVE) THEN + CALL FMINT(M26,M21) + IF (FMCOMP(M26,'==',M21)) KFL = -4 + CALL FMI2M(2,M22) + M21(-1) = 1 + CALL FMMOD(M21,M22,M16) + CALL FMEQ(M16,M22) + IF (M22(2) == 0) KFL = -4 + ELSE + KFL = -4 + ENDIF + IF (KFL /= 0) THEN + CALL FMST2M('UNKNOWN',M22) + KFLAG = -4 + GO TO 160 + ELSE + CALL FMI2M(1,M16) + CALL FMSUB_R2(M16,M26) + ENDIF + ENDIF + +! To speed the asymptotic series calculation, increase +! the argument by LSHIFT. + + IEXTRA = 0 + KWRNSV = KWARN + KWARN = 0 + CALL FMM2I(M26,INTA) + KWARN = KWRNSV + + IF (KFLAG == -4) THEN + LSHIFT = 0 + ELSE + LSHIFT = INT(MAX(0.0,REAL(NDIG)*ALOGMB/4.46-REAL(INTA))) + ENDIF + IF (LSHIFT > 0) LSHIFT = 4*(LSHIFT/4 + 1) + IF (KFLAG == 0) THEN + IF (LSHIFT > 0 .OR. INTA <= 10) THEN + IF (INTA <= 2) THEN + CALL FMI2M(0,M22) + GO TO 140 + ENDIF + INTA = INTA - 1 + CALL FMFCTI(INTA,M26) + CALL FMLN(M26,M22) + GO TO 140 + ENDIF + ENDIF + + IF (LSHIFT /= 0) THEN + CALL FMI2M(LSHIFT,M16) + CALL FMADD(M26,M16,M24) + ELSE + CALL FMEQ(M26,M24) + ENDIF + +! Sum the asymptotic series. + +! M26 is Z +! M24 is Z + LSHIFT +! M21 is X**J2 = (1/(Z+LSHIFT)**2)**J2 +! M22 is the current power of X +! M23 is the current term in the sum +! MJSUMS is the partial sum + + J2 = INT(0.3*ALOGMB + 0.2*SQRT(REAL(NDIG))) + J2 = MAX(1,MIN(LJSUMS/(LUNPCK+3),J2)) + NDSAV1 = NDIG + CALL FMI2M(1,M22) + J = -2*J2 + CALL FMIPWR(M24,J,M21) + IF (ABS(M21(1)) >= MEXPAB) THEN + J2 = 1 + CALL FMIPWR(M24,-2,M21) + ENDIF + DO J = 1, J2 + NTERM = 2*J + CALL FMBERN(NTERM,M22,M23) + IF (KFLAG == -11) THEN + CALL FMST2M('UNKNOWN',M22) + KFLAG = -4 + GO TO 160 + ENDIF + NDENOM = NTERM*(NTERM-1) + KPT = (J-1)*(NDSAV1+3) + CALL FMDIVI(M23,NDENOM,MJSUMS(KPT-1)) + ENDDO + + NDIG2 = NDIG + 120 CALL FMMPY_R1(M22,M21) + NMXDIF = 2 + DO J = 1, J2 + NTERM = NTERM + 2 + CALL FMBERN(NTERM,M22,M23) + IF (KFLAG == -11) THEN + CALL FMST2M('UNKNOWN',M22) + KFLAG = -4 + GO TO 160 + ENDIF + NDENOM = NTERM*(NTERM-1) + IF (NDENOM <= MXBASE) THEN + CALL FMDIVI_R1(M23,NDENOM) + ELSE + CALL FMDIVI_R1(M23,NTERM) + NDENOM = NTERM - 1 + CALL FMDIVI_R1(M23,NDENOM) + ENDIF + NDIG = NDSAV1 + KPT = (J-1)*(NDSAV1+3) + CALL FMADD_R1(MJSUMS(KPT-1),M23) + NMXDIF = MAX(NMXDIF,NDSAV1-INT(MJSUMS(KPT+1)-M23(1))) + NDIG = NDIG2 + IF (KFLAG /= 0) GO TO 130 + ENDDO + NDIG2 = NMXDIF + NDIG = NDIG2 + GO TO 120 + +! Put the J2 concurrent sums back together. + + 130 NDIG = NDSAV1 + IF (J2 > 1) THEN + KPT = (J2-1)*(NDSAV1+3) + CALL FMSQR(M24,M23) + CALL FMI2M(1,M16) + CALL FMDIV_R2(M16,M23) + CALL FMEQ(MJSUMS(KPT-1),M21) + DO J = J2-1, 1, -1 + CALL FMMPY_R1(M21,M23) + KPT = (J-1)*(NDSAV1+3) + CALL FMADD_R1(M21,MJSUMS(KPT-1)) + ENDDO + CALL FMEQ(M21,MJSUMS) + ENDIF + +! Add the log terms to the asymptotic series. + +! M22 is the current sum as the log terms are added +! M23 is now LN(Z+LSHIFT) + + CALL FMDIV(MJSUMS,M24,M22) + CALL FMLN(M24,M23) + IF (MBASE /= MBS2PI .OR. NDIG > NDG2PI) THEN + NDMB = INT(150.0*2.302585/ALOGMB) + IF (NDMB >= NDIG) THEN + NDSV = NDIG + NDIG = MIN(NDMB,NDG2MX) + STRING = '1.837877066409345483560659472811235279722794'// & + '94727556682563430308096553139185452079538948659727190'// & + '8395244011293249268674892733725763681587144311751830445' + CALL FMST2M(STRING,M_LN_2PI) + M_LN_2PI(0) = NINT(NDIG*ALOGM2) + MBS2PI = MBASE + NDG2PI = NDIG + IF (ABS(M_LN_2PI(1)) > 10) NDG2PI = 0 + NDIG = NDSV + ELSE + NDSV = NDIG + NDIG = MIN(NDIG+2,NDG2MX) + CALL FMPI(M21) + CALL FMMPYI(M21,2,M16) + CALL FMLN(M16,M_LN_2PI) + MBS2PI = MBASE + NDG2PI = NDIG + IF (ABS(M_LN_2PI(1)) > 10) NDG2PI = 0 + NDIG = NDSV + ENDIF + ENDIF + CALL FMSUB(M_LN_2PI,M23,M16) + CALL FMDIVI(M16,2,M21) + CALL FMADD_R1(M22,M21) + CALL FMSUB_R1(M22,M24) + CALL FMMPY(M23,M24,M21) + CALL FMADD_R1(M22,M21) + +! Now the log of gamma of the shifted argument has been +! computed. Reverse the shifting. +! The product MA*(MA+1)*...*(MA+LSHIFT-1) is computed +! four terms at a time to reduce the number of FMMPY calls. + +! M26 is Z +! M17 is Z**2 +! M18 is Z**3 +! M19 is (Z+K)*...*(Z+K+3) +! M23 is the current product + + IF (LSHIFT > 0) THEN + CALL FMSQR(M26,M17) + CALL FMMPY(M26,M17,M18) + CALL FMSQR(M17,M19) + CALL FMMPYI(M18,6,M24) + CALL FMADD_R1(M19,M24) + CALL FMMPYI(M17,11,M24) + CALL FMADD_R1(M19,M24) + CALL FMMPYI(M26,6,M24) + CALL FMADD_R1(M19,M24) + CALL FMEQ(M19,M23) + CALL FMMPYI_R1(M18,16) + DO K = 0, LSHIFT-8, 4 + CALL FMADD_R1(M19,M18) + K2 = 24*(2*K + 7) + CALL FMMPYI(M17,K2,M24) + CALL FMADD_R1(M19,M24) + IF (K <= SQRT(REAL(INTMAX)/49.0)) THEN + K1 = 8*(6*K*K + 42*K + 79) + CALL FMMPYI(M26,K1,M24) + CALL FMADD_R1(M19,M24) + ELSE + K1 = 48*K + CALL FMMPYI(M26,K1,M24) + CALL FMMPYI_R1(M24,K) + CALL FMADD_R1(M19,M24) + K1 = 336*K + 632 + CALL FMMPYI(M26,K1,M24) + CALL FMADD_R1(M19,M24) + ENDIF + IF (K <= (REAL(INTMAX)/17.0)**0.3333) THEN + K0 = 8*(2*K + 7)*(K*K + 7*K + 15) + CALL FMADDI(M19,K0) + ELSE IF (K <= SQRT(REAL(INTMAX)*0.9)) THEN + K0 = 8*(2*K + 7) + CALL FMI2M(K0,M24) + K0 = K*K + 7*K + 15 + CALL FMMPYI_R1(M24,K0) + CALL FMADD_R1(M19,M24) + ELSE + K0 = 8*(2*K + 7) + CALL FMI2M(K0,M24) + CALL FMMPYI(M24,K,M21) + CALL FMMPYI_R1(M21,K) + CALL FMADD_R1(M19,M21) + K0 = 7*K + 15 + CALL FMMPYI_R1(M24,K0) + CALL FMADD_R1(M19,M24) + ENDIF + CALL FMMPY_R1(M23,M19) + ENDDO + CALL FMLN(M23,M13) + CALL FMEQ(M13,M23) + CALL FMSUB_R1(M22,M23) + ENDIF + +! Use the reflection formula if MA was negative. + + IF (MAS < 0) THEN + +! Reduce the argument before multiplying by Pi. + + CALL FMNINT(M26,M17) + CALL FMDIVI(M17,2,M18) + CALL FMINT(M18,M08) + CALL FMEQ(M08,M18) + CALL FMMPYI(M18,2,M19) + KSIGN = -1 + IF (FMCOMP(M17,'==',M19)) KSIGN = 1 + CALL FMSUB(M26,M17,M21) + M21(0) = M26(0) + CALL FMPI(M23) + CALL FMMPY_R1(M23,M21) + KRSAVE = KRAD + KRAD = 1 + CALL FMSIN(M23,M12) + CALL FMEQ(M12,M23) + M23(-1) = KSIGN*M23(-1) + KRAD = KRSAVE + CALL FMDIV_R2(MPISAV,M23) + CALL FMLN(M23,M13) + CALL FMEQ(M13,M23) + CALL FMSUB_R2(M23,M22) + ENDIF + +! Check for too much cancellation. + + 140 IF (NCALL <= 1) THEN + NGOAL = INT(REAL(NDSAVE)*ALOGM2) + 17 + ELSE + NGOAL = INT(-MXEXP2) + ENDIF + IF (M22(0) <= NGOAL) THEN + IF (NUMTRY > 0) THEN + NDGOAL = INT(REAL(NGOAL)/ALOGM2 + 1.0) + DO J = 1, NDGOAL+1 + IF (MRETRY(J) /= M22(J)) GO TO 150 + ENDDO + GO TO 160 + ENDIF + 150 IEXTRA = INT(REAL(NGOAL-M22(0))/ALOGM2 + 23.03/ALOGMB) + 1 + NDOLD = NDIG + NDIG = NDIG + IEXTRA + IF (NDIG > NDG2MX) THEN + KFLAG = -9 + CALL FMWRN2 + NDIG = NDIG - IEXTRA + CALL FMST2M('UNKNOWN',M22) + GO TO 160 + ENDIF + CALL FMEQ2_R1(M25,NDSAVE,NDIG) + CALL FMEQ(M25,M26) + NUMTRY = NUMTRY + 1 + CALL FMEQ2(M22,MRETRY,NDOLD,NDIG) + GO TO 110 + ENDIF + + 160 MACMAX = NINT(NDSAVE*ALOGM2) + M22(0) = MIN(M22(0),MACCA,MACMAX) + CALL FMEXT2(M22,MB,NDSAVE,MXSAVE,KASAVE,KOVUN) + RETURN + END SUBROUTINE FMLNGM + + SUBROUTINE FMPGAM(N,MA,MB) + +! MB = POLYGAMMA(N,MA) (Nth Derivative of PSI) + + USE FMVALS + IMPLICIT NONE + + INTEGER N + REAL (KIND(1.0D0)) :: MA(-1:LUNPCK),MB(-1:LUNPCK) + REAL (KIND(1.0D0)) :: MACCA,MACMAX,MXSAVE + INTEGER IEXTRA,INTA,J,J2,JN,JNC,JPT,JSTART,K,KASAVE,KFL,KOVUN,KPT, & + KPT1,KPT2,KRESLT,KRFLCT,KRSAVE,KWRNSV,LSHIFT,N1,NBOT,NC, & + NDGOAL,NDIG2,NDOLD,NDSAV1,NDSAVE,NDSV2,NGOAL,NMXDIF,NTERM, & + NTOP,NUMTRY + +! Set the coefficients used in computing various +! derivatives of COT(Pi*X) for the reflection formula. + + INTEGER :: KGCD(14) = & + (/ 1, 2, 2, 8, 8, 16, 16, 128, 128, 256, 256, 1024, & + 1024, 2048 /) + INTEGER :: KCOEFF(56) = (/ & + 1, 1, 3, 1, 3, 2, & + 15, 15, 2, 45, 60, 17, & + 315, 525, 231, 17, 315, 630, 378, 62, & + 2835, 6615, 5040, 1320, 62, & + 14175, 37800, 34965, 12720, 1382, & + 155925, 467775, 509355, 238425, 42306, 1382, & + 467775, 1559250, 1954260, 1121670, 280731, 21844, & + 6081075, 22297275, 31621590, 21531510, 7012005, & + 907725, 21844, & + 42567525, 170270100, 269594325, 212612400, 85630545, & + 15839460, 929569 /) + LOGICAL FMCOMP + + IF (NTRACE /= 0) THEN + NCALL = NCALL + 1 + NAMEST(NCALL) = 'FMPGAM' + CALL FMNTRI(2,N,1) + NCALL = NCALL - 1 + ENDIF + CALL FMENT2('FMPGAM',MA,MA,1,0,MB,KRESLT,NDSAVE,MXSAVE,KASAVE, & + KOVUN) + IF (KRESLT /= 0) RETURN + KACCSW = 1 + MACCA = MA(0) + CALL FMEQ2(MA,M28,NDSAVE,NDIG) + M28(0) = NINT(NDIG*ALOGM2) + CALL FMEQ(M28,M27) + NUMTRY = 0 + + 110 IF (N == 0) THEN + CALL FMPSI(M28,M24) + GO TO 150 + ENDIF + IF (N < 0 .OR. MA(2) == 0) THEN + CALL FMST2M('UNKNOWN',M24) + KFLAG = -4 + GO TO 170 + ENDIF + +! Near zero PGAM(x) is about n!/(-x)**(n+1). + + IF (M27(1) < (-NDIG-1)) THEN + CALL FMFCTI(N,M26) + IF (M27(1) /= MUNKNO .AND. M27(2) /= 0) M27(-1) = -M27(-1) + CALL FMIPWR(M27,N+1,M25) + CALL FMDIV(M26,M25,M24) + GO TO 150 + ENDIF + +! Check for special cases. + + KRFLCT = 0 + CALL FMDP2M(-0.5D0,M18) + IF (FMCOMP(M27,'<=',M18)) THEN + KRFLCT = 1 + KFL = 0 + IF (MA(1) <= NDSAVE) THEN + CALL FMINT(M27,M23) + IF (FMCOMP(M27,'==',M23)) KFL = -4 + ELSE + KFL = -4 + ENDIF + IF (KFL /= 0) THEN + CALL FMST2M('UNKNOWN',M24) + KFLAG = -4 + GO TO 170 + ELSE + CALL FMI2M(1,M16) + CALL FMSUB_R2(M16,M27) + ENDIF + ENDIF + IF (MA(1) > NDIG+3) THEN + CALL FMIPWR(M27,-N,M24) + IF (M24(1) /= MEXPUN) THEN + CALL FMFCTI(N-1,M23) + CALL FMMPY_R1(M24,M23) + ENDIF + IF (MOD(N-1,2) == 1 .AND. M24(1) /= MUNKNO .AND. & + M24(2) /= 0) M24(-1) = -M24(-1) + GO TO 150 + ENDIF + +! To speed the asymptotic series calculation, increase +! the argument by LSHIFT. + + IEXTRA = 0 + KWRNSV = KWARN + KWARN = 0 + CALL FMM2I(M27,INTA) + KWARN = KWRNSV + + IF (KFLAG == -4) THEN + LSHIFT = 0 + ELSE + LSHIFT = INT(MAX(0.0,REAL(NDIG)*ALOGMB/4.46-REAL(INTA))) + LSHIFT = LSHIFT + (7*N)/20 + ENDIF + IF (LSHIFT > 0) LSHIFT = 4*(LSHIFT/4 + 1) + + IF (LSHIFT /= 0) THEN + CALL FMI2M(LSHIFT,M16) + CALL FMADD(M27,M16,M26) + ELSE + CALL FMEQ(M27,M26) + ENDIF + +! Sum the asymptotic series. + + J2 = INT(0.3*ALOGMB + 0.2*SQRT(REAL(NDIG))) + J2 = MAX(1,MIN(LJSUMS/(LUNPCK+3),J2)) + +! M27 is Z +! M26 is Z + LSHIFT +! M23 is X**J2 = (1/(Z+LSHIFT)**2)**J2 +! M24 is the current power of X times the quotient of +! factorials in each term +! M25 is the current term in the sum +! M22 is (N+1)! +! MJSUMS holds the partial sums + + NDSAV1 = NDIG + CALL FMFCTI(N+1,M22) + CALL FMDIVI(M22,2,M24) + J = -2*J2 + CALL FMIPWR(M26,J,M23) + IF (ABS(M23(1)) >= MEXPAB) THEN + J2 = 1 + CALL FMIPWR(M26,-2,M23) + ENDIF + DO J = 1, J2 + NTERM = 2*J + KPT = (J-1)*(NDSAV1+3) + CALL FMBERN(NTERM,M24,MJSUMS(KPT-1)) + IF (KFLAG == -11) THEN + CALL FMST2M('UNKNOWN',M24) + KFLAG = -4 + GO TO 170 + ENDIF + NTOP = (N+NTERM)*(N+NTERM+1) + CALL FMMPYI_R1(M24,NTOP) + NBOT = (NTERM+1)*(NTERM+2) + CALL FMDIVI_R1(M24,NBOT) + ENDDO + + NDIG2 = NDIG + 120 CALL FMMPY_R1(M24,M23) + NMXDIF = 2 + DO J = 1, J2 + NTERM = NTERM + 2 + CALL FMBERN(NTERM,M24,M25) + IF (KFLAG == -11) THEN + CALL FMST2M('UNKNOWN',M24) + KFLAG = -4 + GO TO 170 + ENDIF + NDIG = NDSAV1 + KPT = (J-1)*(NDSAV1+3) + CALL FMADD_R1(MJSUMS(KPT-1),M25) + IF (KFLAG /= 0) THEN + GO TO 130 + ELSE + NMXDIF = MAX(NMXDIF,NDSAV1-INT(MJSUMS(KPT+1)-M25(1))) + NDIG = NDIG2 + NTOP = (N+NTERM)*(N+NTERM+1) + CALL FMMPYI_R1(M24,NTOP) + NBOT = (NTERM+1)*(NTERM+2) + CALL FMDIVI_R1(M24,NBOT) + ENDIF + ENDDO + NDIG2 = NMXDIF + NDIG = NDIG2 + GO TO 120 + +! Put the J2 concurrent sums back together. + + 130 NDIG = NDSAV1 + IF (J2 > 1) THEN + KPT = (J2-1)*(NDSAV1+3) + CALL FMI2M(1,M23) + CALL FMSQR(M26,M25) + CALL FMDIV_R2(M23,M25) + CALL FMEQ(MJSUMS(KPT-1),M23) + DO J = J2-1, 1, -1 + CALL FMMPY_R1(M23,M25) + KPT = (J-1)*(NDSAV1+3) + CALL FMADD_R1(M23,MJSUMS(KPT-1)) + ENDDO + CALL FMEQ(M23,MJSUMS) + ENDIF + CALL FMIPWR(M26,N+2,M19) + CALL FMDIV_R1(MJSUMS,M19) + +! Add the initial terms to the asymptotic series. + + CALL FMDIVI(M22,N+1,M23) + CALL FMDIVI(M23,N,M22) + CALL FMMPYI(M26,2,M20) + CALL FMI2M(N,M24) + CALL FMADD_R1(M20,M24) + CALL FMMPY_R1(M20,M22) + CALL FMMPYI_R1(M19,2) + CALL FMDIV_R1(M19,M26) + CALL FMDIV(M20,M19,M24) + CALL FMADD_R2(MJSUMS,M24) + IF (MOD(N-1,2) == 1 .AND. M24(1) /= MUNKNO .AND. & + M24(2) /= 0) M24(-1) = -M24(-1) + +! Now PGAM of the shifted argument has been +! computed. Reverse the shifting. +! The sum 1/(MA)**(N+1) + ... + 1/(MA+LSHIFT-1)**(N+1) +! is computed. + +! M27 is Z +! M23 is N! +! M24 is the sum of the asymptotic series +! M25 is the sum 1/(MA)**(N+1) + ... + +! 1/(MA+LSHIFT-1)**(N+1) + + IF (LSHIFT > 0) THEN + CALL FMI2M(1,M19) + CALL FMEQ(M27,M20) + N1 = -(N + 1) + CALL FMIPWR(M20,N1,M25) + DO K = 1, LSHIFT-1 + CALL FMADD_R1(M20,M19) + CALL FMIPWR(M20,N1,M26) + CALL FMADD_R1(M25,M26) + ENDDO + CALL FMMPY_R2(M23,M25) + IF (MOD(N+1,2) == 1 .AND. M25(1) /= MUNKNO .AND. & + M25(2) /= 0) M25(-1) = -M25(-1) + CALL FMADD_R1(M24,M25) + ENDIF + +! Use the reflection formula if MA was less than -1/2. + + IF (KRFLCT == 1) THEN + +! M25 is COT(Pi*Z) +! M23 is M25**2 + +! Reduce the argument before multiplying by Pi. + + CALL FMMPYI(M27,2,M18) + CALL FMINT(M18,M23) + IF (FMCOMP(M18,'==',M23)) THEN + CALL FMI2M(0,M25) + CALL FMEQ(M25,M23) + ELSE + CALL FMNINT(M27,M18) + CALL FMSUB(M27,M18,M23) + NDSV2 = NDIG + 140 CALL FMPI(M25) + CALL FMMPY_R1(M25,M23) + KRSAVE = KRAD + KRAD = 1 + CALL FMTAN(M25,M12) + CALL FMEQ(M12,M25) + KRAD = KRSAVE + IF ((M25(1) < 0 .OR. M25(1) > 1) .AND. & + NDSV2 == NDIG) THEN + IEXTRA = INT(MAX(-M25(1),M25(1))) + IF (IEXTRA > 0 .AND. NDIG+IEXTRA <= NDG2MX) THEN + CALL FMEQ2_R1(M23,NDIG,NDIG+IEXTRA) + ENDIF + NDIG = NDIG + IEXTRA + IF (NDIG > NDG2MX) THEN + KFLAG = -9 + CALL FMWRN2 + NDIG = NDIG - IEXTRA + CALL FMST2M('UNKNOWN',M24) + GO TO 170 + ENDIF + GO TO 140 + ENDIF + + NDIG = NDSV2 + CALL FMI2M(1,M18) + CALL FMDIV_R2(M18,M25) + CALL FMSQR(M25,M23) + ENDIF + NC = (N+1)/2 + +! For N up to 14, use the stored coefficients to compute +! the Nth derivative of Cot(Pi*Z). +! For larger N, the coefficients are generated from a +! recurrence relation and stored as FM numbers. + + IF (N <= 14) THEN + JSTART = (N*N + 4 - MOD(N,2))/4 + IF (N <= 2) THEN + CALL FMI2M(1,M19) + ELSE + CALL FMMPYI(M23,KCOEFF(JSTART),M19) + ENDIF + DO J = 2, NC + CALL FMI2M(KCOEFF(JSTART+J-1),M20) + CALL FMADD_R1(M19,M20) + IF (J < NC) CALL FMMPY_R1(M19,M23) + ENDDO + IF (MOD(N,2) == 0) CALL FMMPY_R1(M19,M25) + IF (N > 1) CALL FMMPYI_R1(M19,KGCD(N)) + ELSE + IF (NC*(NDIG+3) > LJSUMS) THEN + KFLAG = -12 + CALL FMWRN2 + WRITE (KW, & + "(' For PGAM(',I5,',*) with NDIG =',I5,',',I7," // & + "' words are needed'/' in array MJSUMS.'," // & + "' The current dimension of MJSUMS IS',I7/)" & + ) N,NDIG,NC*(NDIG+3),LJSUMS + MXEXP = MXSAVE + NDIG = NDSAVE + CALL FMST2M('UNKNOWN',MB) + IF (NTRACE /= 0) CALL FMNTR(1,MB,MB,1,1) + NCALL = NCALL - 1 + KACCSW = KASAVE + RETURN + ENDIF + + DO J = 1, 7 + JPT = (J-1)*(NDIG+3) + CALL FMI2M(KCOEFF(J+49),MJSUMS(JPT-1)) + CALL FMMPYI_R1(MJSUMS(JPT-1),KGCD(14)) + ENDDO + DO JN = 15, N + JNC = (JN+1)/2 + DO K = JNC, 2, -1 + KPT1 = (K-2)*(NDIG+3) + KPT2 = (K-1)*(NDIG+3) + IF (K == JNC .AND. MOD(JN,2) == 1) THEN + CALL FMEQ(MJSUMS(KPT1-1),MJSUMS(KPT2-1)) + ELSE + CALL FMADD(MJSUMS(KPT1-1),MJSUMS(KPT2-1), & + MJSUMS(KPT2-1)) + CALL FMMPYI(MJSUMS(KPT2-1),JN-2*(K-1), & + MJSUMS(KPT2-1)) + ENDIF + ENDDO + CALL FMMPYI_R1(MJSUMS,JN) + ENDDO + +! MJSUMS now has the coefficients needed for the polynomial +! in Cot**2 that defines the Nth derivative of Cot. + + CALL FMEQ(MJSUMS,M19) + DO J = 2, NC + CALL FMMPY_R1(M19,M23) + KPT = (J-1)*(NDIG+3) + CALL FMADD_R1(M19,MJSUMS(KPT-1)) + ENDDO + IF (MOD(N,2) == 0) CALL FMMPY_R1(M19,M25) + ENDIF + +! To complete the calculation of the Nth derivative of +! Cot, multiply the polynomial in Cot**2 by Csc**2. + + CALL FMADD(M23,M18,M20) + CALL FMMPY_R1(M19,M20) + + CALL FMIPWR(MPISAV,N+1,M20) + CALL FMMPY_R1(M19,M20) + IF (MOD(N,2) == 1 .AND. M24(1) /= MUNKNO .AND. & + M24(2) /= 0) M24(-1) = -M24(-1) + CALL FMADD_R1(M24,M19) + ENDIF + +! Check for too much cancellation. + + 150 IF (NCALL <= 1) THEN + NGOAL = INT(REAL(NDSAVE)*ALOGM2) + 17 + ELSE + NGOAL = INT(-MXEXP2) + ENDIF + IF (M24(0) <= NGOAL) THEN + IF (NUMTRY > 0) THEN + NDGOAL = INT(REAL(NGOAL)/ALOGM2 + 1.0) + DO J = 1, NDGOAL+1 + IF (MRETRY(J) /= M24(J)) GO TO 160 + ENDDO + GO TO 170 + ENDIF + 160 IEXTRA = INT(REAL(NGOAL-M24(0))/ALOGM2 + 23.03/ALOGMB) + 1 + NDOLD = NDIG + NDIG = NDIG + IEXTRA + IF (NDIG > NDG2MX) THEN + KFLAG = -9 + CALL FMWRN2 + NDIG = NDIG - IEXTRA + CALL FMST2M('UNKNOWN',M24) + GO TO 170 + ENDIF + CALL FMEQ2_R1(M28,NDSAVE,NDIG) + CALL FMEQ(M28,M27) + NUMTRY = NUMTRY + 1 + CALL FMEQ2(M24,MRETRY,NDOLD,NDIG) + GO TO 110 + ENDIF + + 170 MACMAX = NINT(NDSAVE*ALOGM2) + M24(0) = MIN(M24(0),MACCA,MACMAX) + CALL FMEXT2(M24,MB,NDSAVE,MXSAVE,KASAVE,KOVUN) + RETURN + END SUBROUTINE FMPGAM + + SUBROUTINE FMPOCH(MA,N,MB) + +! MB = MA*(MA+1)*(MA+2)*...*(MA+N-1) (Pochhammer's symbol) + +! MB = Gamma(MA+N)/Gamma(MA) + +! For negative N, Pochhammer(MA,N) = 1/Pochhammer(MA+N,-N). + + USE FMVALS + IMPLICIT NONE + + REAL (KIND(1.0D0)) :: MA(-1:LUNPCK),MB(-1:LUNPCK) + INTEGER N + REAL (KIND(1.0D0)) :: MA2,MAS,MACCA,MACMAX,MBSIGN,MXSAVE + INTEGER IEXTRA,J,K,K0,K1,K2,KASAVE,KLAST,KM08,KMB,KOVUN,KRESLT, & + LT,NDGOAL,NDOLD,NDSAVE,NGOAL,NT,NUMTRY + LOGICAL FMCOMP + REAL T + + CALL FMENT2('FMPOCH',MA,MA,1,1,MB,KRESLT,NDSAVE,MXSAVE,KASAVE, & + KOVUN) + CALL FMNTRI(2,N,0) + IF (KRESLT /= 0) RETURN + + MA2 = MA(2) + MAS = MA(-1) + NT = N + KACCSW = 1 + MACCA = MA(0) + CALL FMEQ2(MA,M30,NDSAVE,NDIG) + M30(0) = NINT(NDIG*ALOGM2) + CALL FMEQ(M30,M27) + NUMTRY = 0 + +! Check for special cases. + + 110 IEXTRA = 0 + IF (NT < 0) THEN + CALL FMADDI(M30,NT) + CALL FMEQ(M30,M27) + NT = -NT + MA2 = M30(2) + MAS = M30(-1) + ENDIF + IF (MA2 == 0) THEN + IF (NT > 0) THEN + CALL FMI2M(0,M23) + GO TO 130 + ELSE + CALL FMST2M('UNKNOWN',M23) + KFLAG = -4 + GO TO 150 + ENDIF + ENDIF + IF (NT == 0) THEN + CALL FMI2M(1,M23) + GO TO 130 + ELSE IF (NT == 1) THEN + CALL FMEQ2(M30,M23,NDSAVE,NDIG) + GO TO 130 + ENDIF + CALL FMI2M(1,M16) + CALL FMADD(M30,M16,M17) + IF (M30(1) == MEXPOV) THEN + CALL FMST2M('OVERFLOW',M23) + IF (MAS < 0) M23(-1) = (-1)**NT + GO TO 130 + ELSE IF (M30(1) == MEXPUN) THEN + IF (NT == 2) THEN + CALL FMST2M('UNDERFLOW',M23) + IF (MAS < 0) M23(-1) = -1 + ELSE + CALL FMST2M('UNKNOWN',M23) + KFLAG = -4 + ENDIF + GO TO 150 + ELSE IF (FMCOMP(M17,'==',M16)) THEN + T = NDIG + J = INT(15.21*SQRT(T)*ALOGMT + 42.87*SQRT(T) + 30.0) + IF (NT <= J) THEN + K1 = NT - 1 + CALL FMFCTI(K1,M23) + CALL FMMPY_R2(M30,M23) + GO TO 130 + ENDIF + ENDIF + +! Look for cases where overflow is easy to detect. + + CALL FMI2M(NT,M21) + CALL FMABS(M27,M19) + IF (M27(1) > 0 .AND. FMCOMP(M21,'<',M19)) THEN + CALL FMADD(M27,M21,M20) + M20(-1) = 1 + CALL FMMIN(M19,M20,M22) + IF (INT(M22(1))-1 > INTMAX/NT) THEN + CALL FMST2M('OVERFLOW',M23) + IF (M27(-1) > 0) THEN + M23(-1) = 1 + ELSE + M23(-1) = (-1)**MOD(NT,2) + ENDIF + KFLAG = -5 + GO TO 130 + ENDIF + ENDIF + +! For large values of MA, the result is MA**NT. + + LT = NDIG + 3 + INT(2.0D0*LOG(DBLE(NT))/DLOGMB) + IF (M30(1) > LT) THEN + CALL FMIPWR(M27,NT,M23) + GO TO 130 + ENDIF + + MBSIGN = 1 + IF (MAS < 0) THEN + CALL FMINT(M27,M20) + CALL FMI2M(NT,M21) + CALL FMADD(M27,M21,M22) + IF (FMCOMP(M27,'==',M20)) THEN + +! If MA is a negative integer and MA+NT is positive, +! then the result is zero. + + IF (M22(-1)*M22(2) > 0) THEN + CALL FMI2M(0,M23) + GO TO 130 + ENDIF + ENDIF + +! If MA is negative and MA+NT-1 is negative, +! then use the reflection formula Pochhammer(MA,NT) = +! (-1)**NT*Pochhammer(-MA-(NT-1),NT). + + CALL FMI2M(1,M23) + IF (FMCOMP(M22,'<',M23)) THEN + +! Extra guard digits may be required to insure the +! reflection formula is accurate. + + IEXTRA = MAX(INT(M27(1)),IEXTRA) + IF (IEXTRA > 0 .AND. NDIG+IEXTRA <= NDG2MX) THEN + CALL FMEQ2_R1(M27,NDIG,NDIG+IEXTRA) + ENDIF + NDIG = NDIG + IEXTRA + IF (NDIG > NDG2MX) THEN + KFLAG = -9 + CALL FMWRN2 + NDIG = NDIG - IEXTRA + CALL FMST2M('UNKNOWN',M23) + GO TO 150 + ENDIF + CALL FMI2M(NT-1,M23) + IF (M27(1) /= MUNKNO .AND. M27(2) /= 0) M27(-1) = -M27(-1) + CALL FMSUB_R1(M27,M23) + IF (MOD(NT,2) == 1) MBSIGN = -1 + ENDIF + ENDIF + +! If NT is large enough, it is faster to use two +! calls to FMLNGM. The formula below gives a rough +! approximation of where to change methods. + + T = NDIG + J = INT(15.21*SQRT(T)*ALOGMT + 42.87*SQRT(T) + 25.03) + IF (NT > J) THEN + CALL FMI2M(NT,M16) + CALL FMADD(M27,M16,M28) + +! Compute IEXTRA, the number of extra digits required +! to compensate for cancellation error. + + IF (MAX(M27(1),M28(1)) > IEXTRA) THEN + IEXTRA = INT(MAX(M27(1),M28(1))) + ENDIF + IF (IEXTRA > 0 .AND. NDIG+IEXTRA <= NDG2MX) THEN + CALL FMEQ2_R1(M27,NDIG,NDIG+IEXTRA) + ENDIF + NDIG = NDIG + IEXTRA + IF (NDIG > NDG2MX) THEN + KFLAG = -9 + CALL FMWRN2 + NDIG = NDIG - IEXTRA + CALL FMST2M('UNKNOWN',M23) + GO TO 150 + ENDIF + + CALL FMI2M(-1,M29) + IF (IEXTRA > 0) THEN + CALL FMI2M(NT,M16) + CALL FMADD(M27,M16,M28) + ENDIF + CALL FMI2M(2,M21) + KMB = 0 + IF (M27(-1) < 0) THEN + CALL FMMOD(M27,M21,M20) + IF (FMCOMP(M20,'>',M29)) KMB = 1 + ENDIF + KM08 = 0 + IF (M28(-1) < 0) THEN + CALL FMMOD(M28,M21,M20) + IF (FMCOMP(M20,'>',M29)) KM08 = 1 + ENDIF + CALL FMI2M(1,M29) + IF (M27(-1) < 0 .AND. KMB == 1) THEN + CALL FMEQ(M27,M29) + CALL FMI2M(1,M16) + CALL FMADD_R1(M27,M16) + CALL FMLNGM(M27,M14) + CALL FMEQ(M14,M27) + ELSE + CALL FMLNGM(M27,M14) + CALL FMEQ(M14,M27) + ENDIF + IF (M28(-1) < 0 .AND. KM08 == 1) THEN + CALL FMI2M(-1,M19) + CALL FMADD_R1(M28,M19) + CALL FMMPY_R1(M29,M28) + CALL FMLNGM(M28,M14) + CALL FMEQ(M14,M28) + ELSE + CALL FMLNGM(M28,M14) + CALL FMEQ(M14,M28) + ENDIF + + CALL FMSUB(M28,M27,M23) + CALL FMEXP(M23,M12) + CALL FMEQ(M12,M23) + CALL FMMPY_R1(M23,M29) + GO TO 120 + ENDIF + +! Compute the product Z*(Z+1)*...*(Z+NT-1) +! four terms at a time to reduce the number of FMMPY calls. + +! M27 is Z +! M18 is Z**2 +! M19 is Z**3 +! M20 is (Z+K)*...*(Z+K+3) +! M23 is the current product + +! If M27 is negative and M27+NT is positive, extra +! digits are required when M27 is close to an integer. + + IF (M27(-1) < 0) THEN + CALL FMI2M(NT,M20) + CALL FMADD(M27,M20,M21) + IF (M21(-1)*M21(2) > 0) THEN + CALL FMNINT(M27,M22) + IF (M22(2) /= 0) THEN + CALL FMSUB(M27,M22,M21) + IEXTRA = MAX(IEXTRA,NDIG-NDSAVE) + IF (MAX(M27(1),M21(1)) > IEXTRA) THEN + IEXTRA = INT(MAX(M27(1),M21(1))) + ENDIF + IF (IEXTRA > 0 .AND. NDIG+IEXTRA <= NDG2MX) THEN + CALL FMEQ2_R1(M27,NDIG,NDIG+IEXTRA) + ENDIF + NDIG = NDIG + IEXTRA + IF (NDIG > NDG2MX) THEN + KFLAG = -9 + CALL FMWRN2 + NDIG = NDIG - IEXTRA + CALL FMST2M('UNKNOWN',M23) + GO TO 150 + ENDIF + ENDIF + ENDIF + ENDIF + + CALL FMI2M(1,M23) + IF (NT >= 4) THEN + CALL FMSQR(M27,M18) + CALL FMMPY(M27,M18,M19) + CALL FMSQR(M18,M20) + CALL FMMPYI(M19,6,M24) + CALL FMADD_R1(M20,M24) + CALL FMMPYI(M18,11,M24) + CALL FMADD_R1(M20,M24) + CALL FMMPYI(M27,6,M24) + CALL FMADD_R1(M20,M24) + CALL FMEQ(M20,M23) + CALL FMMPYI_R1(M19,16) + DO K = 0, NT-8, 4 + CALL FMADD_R1(M20,M19) + K2 = 24*(2*K + 7) + CALL FMMPYI(M18,K2,M24) + CALL FMADD_R1(M20,M24) + IF (K <= SQRT(REAL(INTMAX)/49.0)) THEN + K1 = 8*(6*K*K + 42*K + 79) + CALL FMMPYI(M27,K1,M24) + CALL FMADD_R1(M20,M24) + ELSE + K1 = 48*K + CALL FMMPYI(M27,K1,M24) + CALL FMMPYI_R1(M24,K) + CALL FMADD_R1(M20,M24) + K1 = 336*K + 632 + CALL FMMPYI(M27,K1,M24) + CALL FMADD_R1(M20,M24) + ENDIF + IF (K <= (REAL(INTMAX)/17.0)**0.3333) THEN + K0 = 8*(2*K + 7)*(K*K + 7*K + 15) + CALL FMADDI(M20,K0) + ELSE IF (K <= SQRT(REAL(INTMAX)*0.9)) THEN + K0 = 8*(2*K + 7) + CALL FMI2M(K0,M24) + K0 = K*K + 7*K + 15 + CALL FMMPYI_R1(M24,K0) + CALL FMADD_R1(M20,M24) + ELSE + K0 = 8*(2*K + 7) + CALL FMI2M(K0,M24) + CALL FMMPYI(M24,K,M21) + CALL FMMPYI_R1(M21,K) + CALL FMADD_R1(M20,M21) + K0 = 7*K + 15 + CALL FMMPYI_R1(M24,K0) + CALL FMADD_R1(M20,M24) + ENDIF + CALL FMMPY_R1(M23,M20) + ENDDO + ENDIF + + KLAST = (NT/4)*4 + DO J = KLAST, NT-1 + CALL FMI2M(J,M21) + CALL FMADD_R2(M27,M21) + CALL FMMPY_R1(M23,M21) + ENDDO + +! If the reflection formula was used, multiply by (-1)**NT. + + 120 M23(-1) = MBSIGN*M23(-1) + +! Check for too much cancellation. + + 130 IF (NCALL <= 1) THEN + NGOAL = INT(REAL(NDSAVE)*ALOGM2) + 17 + ELSE + NGOAL = INT(-MXEXP2) + ENDIF + IF (M23(0) <= NGOAL) THEN + IF (NUMTRY > 0) THEN + NDGOAL = INT(REAL(NGOAL)/ALOGM2 + 1.0) + DO J = 1, NDGOAL+1 + IF (MRETRY(J) /= M23(J)) GO TO 140 + ENDDO + GO TO 150 + ENDIF + 140 IEXTRA = INT(REAL(NGOAL-M23(0))/ALOGM2 + 23.03/ALOGMB) + 1 + NDOLD = NDIG + NDIG = NDIG + IEXTRA + IF (NDIG > NDG2MX) THEN + KFLAG = -9 + CALL FMWRN2 + NDIG = NDIG - IEXTRA + CALL FMST2M('UNKNOWN',M23) + GO TO 150 + ENDIF + CALL FMEQ2_R1(M30,NDSAVE,NDIG) + CALL FMEQ(M30,M27) + NUMTRY = NUMTRY + 1 + CALL FMEQ2(M23,MRETRY,NDOLD,NDIG) + GO TO 110 + ENDIF + + 150 MACMAX = NINT(NDSAVE*ALOGM2) + IF (N < 0) THEN + CALL FMI2M(1,M18) + CALL FMDIV_R2(M18,M23) + ENDIF + M23(0) = MIN(M23(0),MACCA,MACMAX) + CALL FMEXT2(M23,MB,NDSAVE,MXSAVE,KASAVE,KOVUN) + RETURN + END SUBROUTINE FMPOCH + + SUBROUTINE FMPSI(MA,MB) + +! MB = PSI(MA) (Derivative of Ln(Gamma(MA)) + + USE FMVALS + IMPLICIT NONE + + REAL (KIND(1.0D0)) :: MA(-1:LUNPCK),MB(-1:LUNPCK) + REAL (KIND(1.0D0)) :: MACCA,MACMAX,MXSAVE + INTEGER IEXTRA,INTA,J,J2,K,K0,K0B,K1,K1B,K2,KASAVE,KFL,KOVUN,KPT, & + KRESLT,KRFLCT,KRSAVE,KWRNSV,LSHIFT,NDENOM,NDGOAL,NDIG2, & + NDOLD,NDSAV1,NDSAVE,NGOAL,NMXDIF,NTERM,NUMTRY + LOGICAL FMCOMP + + CALL FMENT2('FMPSI ',MA,MA,1,1,MB,KRESLT,NDSAVE,MXSAVE,KASAVE, & + KOVUN) + IF (KRESLT /= 0) RETURN + KACCSW = 1 + MACCA = MA(0) + CALL FMEQ2(MA,M25,NDSAVE,NDIG) + M25(0) = NINT(NDIG*ALOGM2) + CALL FMEQ(M25,M26) + NUMTRY = 0 + +! Near zero Psi(x) is about -1/x. + + 110 IF (M26(1) < (-NDIG-1)) THEN + CALL FMI2M(-1,M16) + CALL FMDIV(M16,M26,M22) + GO TO 140 + ENDIF + +! Check for special cases. + + KRFLCT = 0 + CALL FMDPM(DBLE(-0.5),M18) + IF (FMCOMP(M26,'<=',M18)) THEN + KRFLCT = 1 + KFL = 0 + IF (MA(1) <= NDSAVE) THEN + CALL FMINT(M26,M21) + IF (FMCOMP(M26,'==',M21)) KFL = -4 + ELSE + KFL = -4 + ENDIF + IF (KFL /= 0) THEN + CALL FMST2M('UNKNOWN',M22) + KFLAG = -4 + GO TO 160 + ELSE + CALL FMI2M(1,M16) + CALL FMSUB_R2(M16,M26) + ENDIF + ENDIF + +! To speed the asymptotic series calculation, increase +! the argument by LSHIFT. + + IEXTRA = 0 + KWRNSV = KWARN + KWARN = 0 + CALL FMM2I(M26,INTA) + KWARN = KWRNSV + + IF (KFLAG == -4) THEN + LSHIFT = 0 + ELSE + LSHIFT = INT(MAX(0.0,REAL(NDIG)*ALOGMB/4.46-REAL(INTA))) + ENDIF + IF (LSHIFT > 0) LSHIFT = 4*(LSHIFT/4 + 1) + + IF (LSHIFT /= 0) THEN + CALL FMI2M(LSHIFT,M16) + CALL FMADD(M26,M16,M24) + ELSE + CALL FMEQ(M26,M24) + ENDIF + +! Sum the asymptotic series. + + J2 = INT(0.3*ALOGMB + 0.2*SQRT(REAL(NDIG))) + J2 = MAX(1,MIN(LJSUMS/(LUNPCK+3),J2)) + +! M26 is Z +! M24 is Z + LSHIFT +! M21 is X**J2 = (1/(Z+LSHIFT)**2)**J2 +! M22 is the current power of X +! M23 is the current term in the sum +! MJSUMS is the partial sum + + NDSAV1 = NDIG + CALL FMI2M(1,M22) + J = -2*J2 + CALL FMIPWR(M24,J,M21) + IF (ABS(M21(1)) >= MEXPAB) THEN + J2 = 1 + CALL FMIPWR(M24,-2,M21) + ENDIF + DO J = 1, J2 + NTERM = 2*J + CALL FMBERN(NTERM,M22,M23) + IF (KFLAG == -11) THEN + CALL FMST2M('UNKNOWN',M22) + KFLAG = -4 + GO TO 160 + ENDIF + NDENOM = NTERM + KPT = (J-1)*(NDSAV1+3) + CALL FMDIVI(M23,NDENOM,MJSUMS(KPT-1)) + ENDDO + + NDIG2 = NDIG + 120 CALL FMMPY_R1(M22,M21) + NMXDIF = 2 + DO J = 1, J2 + NTERM = NTERM + 2 + CALL FMBERN(NTERM,M22,M23) + IF (KFLAG == -11) THEN + CALL FMST2M('UNKNOWN',M22) + KFLAG = -4 + GO TO 160 + ENDIF + NDENOM = NTERM + CALL FMDIVI_R1(M23,NDENOM) + NDIG = NDSAV1 + KPT = (J-1)*(NDSAV1+3) + CALL FMADD_R1(MJSUMS(KPT-1),M23) + NMXDIF = MAX(NMXDIF,NDSAV1-INT(MJSUMS(KPT+1)-M23(1))) + NDIG = NDIG2 + IF (KFLAG /= 0) GO TO 130 + ENDDO + NDIG2 = NMXDIF + NDIG = NDIG2 + GO TO 120 + +! Put the J2 concurrent sums back together. + + 130 NDIG = NDSAV1 + CALL FMI2M(1,M21) + CALL FMSQR(M24,M23) + CALL FMDIV_R2(M21,M23) + IF (J2 > 1) THEN + KPT = (J2-1)*(NDSAV1+3) + CALL FMEQ(MJSUMS(KPT-1),M21) + DO J = J2-1, 1, -1 + CALL FMMPY_R1(M21,M23) + KPT = (J-1)*(NDSAV1+3) + CALL FMADD_R1(M21,MJSUMS(KPT-1)) + ENDDO + CALL FMEQ(M21,MJSUMS) + ENDIF + +! Add the log term to the asymptotic series. + +! M22 is the current sum as the log terms are added +! M23 is now LN(Z+LSHIFT) + + CALL FMMPY(MJSUMS,M23,M22) + CALL FMLN(M24,M23) + CALL FMI2M(1,M18) + CALL FMDIV(M18,M24,M19) + CALL FMDIVI_R1(M19,2) + CALL FMSUB_R2(M23,M19) + CALL FMSUB_R2(M19,M22) + +! Now Psi of the shifted argument has been +! computed. Reverse the shifting. +! The sum 1/(MA) + ... + 1/(MA+LSHIFT-1) is computed. + +! M26 is Z +! M18 is X**2 +! M19 is 16*Z**3 +! M20 is the current four-term numerator +! M21 is the current four-term denominator +! M23 is the current sum + + IF (LSHIFT > 0) THEN + CALL FMSQR(M26,M18) + CALL FMMPY(M26,M18,M19) + CALL FMSQR(M18,M20) + CALL FMMPYI(M19,6,M24) + CALL FMADD_R1(M20,M24) + CALL FMMPYI(M18,11,M24) + CALL FMADD_R1(M20,M24) + CALL FMMPYI(M26,6,M24) + CALL FMADD(M20,M24,M21) + CALL FMMPYI(M19,4,M20) + CALL FMMPYI(M18,18,M24) + CALL FMADD_R1(M20,M24) + CALL FMMPYI(M26,22,M24) + CALL FMADD_R1(M20,M24) + CALL FMI2M(6,M24) + CALL FMADD_R1(M20,M24) + CALL FMDIV(M20,M21,M23) + CALL FMMPYI_R1(M19,16) + DO K = 4, LSHIFT-4, 4 + CALL FMADD_R1(M21,M19) + + CALL FMMPYI(M18,48,M24) + CALL FMADD_R1(M20,M24) + + K2 = 8*(6*K - 3) + CALL FMMPYI(M18,K2,M24) + CALL FMADD_R1(M21,M24) + + K1 = 16*(6*K - 3) + CALL FMMPYI(M26,K1,M24) + CALL FMADD_R1(M20,M24) + + IF (K <= SQRT(REAL(INTMAX)/49.0)) THEN + K1 = 8*(6*K*K - 6*K + 7) + CALL FMMPYI(M26,K1,M24) + CALL FMADD_R1(M21,M24) + + CALL FMI2M(K1,M24) + CALL FMADD_R1(M20,M24) + ELSE + K1 = 48*K + CALL FMMPYI(M26,K1,M24) + CALL FMMPYI_R1(M24,K) + CALL FMADD_R1(M21,M24) + K1B = 8*(-6*K + 7) + CALL FMMPYI(M26,K1B,M24) + CALL FMADD_R1(M21,M24) + + CALL FMI2M(K1,M24) + CALL FMMPYI_R1(M24,K) + CALL FMADD_R1(M20,M24) + CALL FMI2M(K1B,M24) + CALL FMADD_R1(M20,M24) + ENDIF + IF (K <= (REAL(INTMAX)/17.0)**0.3333) THEN + K0 = 8*(2*K - 1)*(K*K - K + 3) + CALL FMI2M(K0,M24) + CALL FMADD_R1(M21,M24) + ELSE IF (K <= SQRT(REAL(INTMAX)*0.9)) THEN + K0 = 8*(2*K - 1) + CALL FMI2M(K0,M24) + K0B = K*K - K + 3 + CALL FMMPYI_R1(M24,K0B) + CALL FMADD_R1(M21,M24) + ELSE + K0 = 8*(2*K - 1) + CALL FMI2M(K0,M24) + CALL FMMPYI_R1(M24,K) + CALL FMMPYI_R1(M24,K) + CALL FMADD_R1(M21,M24) + K0B = -K + 3 + CALL FMI2M(K0,M24) + CALL FMMPYI_R1(M24,K0B) + CALL FMADD_R1(M21,M24) + ENDIF + CALL FMDIV(M20,M21,M24) + CALL FMADD_R1(M23,M24) + ENDDO + CALL FMSUB_R1(M22,M23) + ENDIF + +! Use the reflection formula if MA was less than -1/2. + + IF (KRFLCT == 1) THEN + +! Reduce the argument before multiplying by Pi. + + CALL FMNINT(M26,M18) + CALL FMSUB(M26,M18,M21) + M21(0) = M26(0) + CALL FMPI(M23) + CALL FMMPY_R1(M23,M21) + KRSAVE = KRAD + KRAD = 1 + CALL FMTAN(M23,M12) + CALL FMEQ(M12,M23) + KRAD = KRSAVE + CALL FMDIV_R2(MPISAV,M23) + CALL FMADD_R1(M22,M23) + ENDIF + +! Check for too much cancellation. + + 140 IF (NCALL <= 1) THEN + NGOAL = INT(REAL(NDSAVE)*ALOGM2) + 17 + ELSE + NGOAL = INT(-MXEXP2) + ENDIF + IF (M22(0) <= NGOAL) THEN + IF (NUMTRY > 0) THEN + NDGOAL = INT(REAL(NGOAL)/ALOGM2 + 1.0) + DO J = 1, NDGOAL+1 + IF (MRETRY(J) /= M22(J)) GO TO 150 + ENDDO + GO TO 160 + ENDIF + 150 IEXTRA = INT(REAL(NGOAL-M22(0))/ALOGM2 + 23.03/ALOGMB) + 1 + NDOLD = NDIG + NDIG = NDIG + IEXTRA + IF (NDIG > NDG2MX) THEN + KFLAG = -9 + CALL FMWRN2 + NDIG = NDIG - IEXTRA + CALL FMST2M('UNKNOWN',M22) + GO TO 160 + ENDIF + CALL FMEQ2_R1(M25,NDSAVE,NDIG) + CALL FMEQ(M25,M26) + NUMTRY = NUMTRY + 1 + CALL FMEQ2(M22,MRETRY,NDOLD,NDIG) + GO TO 110 + ENDIF + + 160 MACMAX = NINT(NDSAVE*ALOGM2) + M22(0) = MIN(M22(0),MACCA,MACMAX) + CALL FMEXT2(M22,MB,NDSAVE,MXSAVE,KASAVE,KOVUN) + RETURN + END SUBROUTINE FMPSI + + SUBROUTINE FMWRN2 + +! Called by one of the FM routines to print a warning message +! if any error condition arises in that routine. + + USE FMVALS + IMPLICIT NONE + + CHARACTER(6) :: NAME + + INTEGER NCS + + IF (KFLAG >= 0 .OR. NCALL /= 1 .OR. KWARN <= 0) RETURN + NCS = NCALL + NAME = NAMEST(NCALL) + WRITE (KW, & + "(/' Error of type KFLAG =',I3," // & + "' in FM package in routine ',A6/)" & + ) KFLAG,NAME + + 110 NCALL = NCALL - 1 + IF (NCALL > 0) THEN + NAME = NAMEST(NCALL) + WRITE (KW,"( ' called from ',A6)") NAME + GO TO 110 + ENDIF + + IF (KFLAG == -1) THEN + WRITE (KW,"(' NDIG must be between 2 and',I10/)") NDIGMX + ELSE IF (KFLAG == -2) THEN + WRITE (KW,"(' MBASE must be between 2 and',I10/)") INT(MXBASE) + ELSE IF (KFLAG == -3) THEN + WRITE (KW, & + "(' An input argument is not a valid FM number.'," // & + "' Its exponent is out of range.'/)" & + ) + WRITE (KW,"(' UNKNOWN has been returned.'/)") + ELSE IF (KFLAG == -4 .OR. KFLAG == -7) THEN + WRITE (KW,"(' Invalid input argument for this routine.'/)") + WRITE (KW,"(' UNKNOWN has been returned.'/)") + ELSE IF (KFLAG == -5) THEN + WRITE (KW,"(' The result has overflowed.'/)") + ELSE IF (KFLAG == -6) THEN + WRITE (KW,"(' The result has underflowed.'/)") + ELSE IF (KFLAG == -8) THEN + WRITE (KW, & + "(' The result array is not big enough to hold the'," // & + "' output character string'/' in the current format.'/" // & + "' The result ''***...***'' has been returned.'/)" & + ) + ELSE IF (KFLAG == -9) THEN + WRITE (KW, & + "(' Precision could not be raised enough to'" // & + ",' provide all requested guard digits.'/)" & + ) + WRITE (KW, & + "(I23,' digits were requested (NDIG).'/" // & + "' Maximum number of digits currently available'," // & + "' (NDG2MX) is',I7,'.'/)" & + ) NDIG,NDG2MX + WRITE (KW,"(' UNKNOWN has been returned.'/)") + ELSE IF (KFLAG == -10) THEN + IF (NAMEST(NCS) == 'FMM2SP') THEN + WRITE (KW, & + "(' An FM number was too small in magnitude to '," // & + "'convert to single precision.'/)" & + ) + ELSE + WRITE (KW, & + "(' An FM number was too small in magnitude to '," // & + "'convert to double precision.'/)" & + ) + ENDIF + WRITE (KW,"(' Zero has been returned.'/)") + ELSE IF (KFLAG == -11) THEN + WRITE (KW,"(' Array MBERN is not large enough.')") + ELSE IF (KFLAG == -12) THEN + WRITE (KW,"(' Array MJSUMS is not large enough.')") + ENDIF + + NCALL = NCS + IF (KWARN >= 2) THEN + STOP + ENDIF + RETURN + END SUBROUTINE FMWRN2 + +! Packed versions of routines for special functions. + + SUBROUTINE FPBERN(INT,MA,MB) + USE FMVALS + IMPLICIT NONE + REAL (KIND(1.0D0)) :: MA(-1:LPACK),MB(-1:LPACK) + INTEGER INT + CALL FMUNPK(MA,MPA) + CALL FMBERN(INT,MPA,MPB) + CALL FMPACK(MPB,MB) + RETURN + END SUBROUTINE FPBERN + + SUBROUTINE FPBETA(MA,MB,MC) + USE FMVALS + IMPLICIT NONE + REAL (KIND(1.0D0)) :: MA(-1:LPACK),MB(-1:LPACK),MC(-1:LPACK) + CALL FMUNPK(MA,MPA) + CALL FMUNPK(MB,MPB) + CALL FMBETA(MPA,MPB,MPC) + CALL FMPACK(MPC,MC) + RETURN + END SUBROUTINE FPBETA + + SUBROUTINE FPCMBI(N,K,MA) + USE FMVALS + IMPLICIT NONE + REAL (KIND(1.0D0)) :: MA(-1:LPACK) + INTEGER K,N + CALL FMCMBI(N,K,MPA) + CALL FMPACK(MPA,MA) + RETURN + END SUBROUTINE FPCMBI + + SUBROUTINE FPCOMB(MA,MB,MC) + USE FMVALS + IMPLICIT NONE + REAL (KIND(1.0D0)) :: MA(-1:LPACK),MB(-1:LPACK),MC(-1:LPACK) + CALL FMUNPK(MA,MPA) + CALL FMUNPK(MB,MPB) + CALL FMCOMB(MPA,MPB,MPC) + CALL FMPACK(MPC,MC) + RETURN + END SUBROUTINE FPCOMB + + SUBROUTINE FPEULR(MA) + USE FMVALS + IMPLICIT NONE + REAL (KIND(1.0D0)) :: MA(-1:LPACK) + CALL FMEULR(MPA) + CALL FMPACK(MPA,MA) + RETURN + END SUBROUTINE FPEULR + + SUBROUTINE FPFACT(MA,MB) + USE FMVALS + IMPLICIT NONE + REAL (KIND(1.0D0)) :: MA(-1:LPACK),MB(-1:LPACK) + CALL FMUNPK(MA,MPA) + CALL FMFACT(MPA,MPB) + CALL FMPACK(MPB,MB) + RETURN + END SUBROUTINE FPFACT + + SUBROUTINE FPGAM(MA,MB) + USE FMVALS + IMPLICIT NONE + REAL (KIND(1.0D0)) :: MA(-1:LPACK),MB(-1:LPACK) + CALL FMUNPK(MA,MPA) + CALL FMGAM(MPA,MPB) + CALL FMPACK(MPB,MB) + RETURN + END SUBROUTINE FPGAM + + SUBROUTINE FPIBTA(MA,MB,MC,MD) + USE FMVALS + IMPLICIT NONE + REAL (KIND(1.0D0)) :: MA(-1:LPACK),MB(-1:LPACK),MC(-1:LPACK),MD(-1:LPACK) + CALL FMUNPK(MA,MPA) + CALL FMUNPK(MB,MPB) + CALL FMUNPK(MC,MPC) + CALL FMIBTA(MPA,MPB,MPC,MPD) + CALL FMPACK(MPD,MD) + RETURN + END SUBROUTINE FPIBTA + + SUBROUTINE FPIGM1(MA,MB,MC) + USE FMVALS + IMPLICIT NONE + REAL (KIND(1.0D0)) :: MA(-1:LPACK),MB(-1:LPACK),MC(-1:LPACK) + CALL FMUNPK(MA,MPA) + CALL FMUNPK(MB,MPB) + CALL FMIGM1(MPA,MPB,MPC) + CALL FMPACK(MPC,MC) + RETURN + END SUBROUTINE FPIGM1 + + SUBROUTINE FPIGM2(MA,MB,MC) + USE FMVALS + IMPLICIT NONE + REAL (KIND(1.0D0)) :: MA(-1:LPACK),MB(-1:LPACK),MC(-1:LPACK) + CALL FMUNPK(MA,MPA) + CALL FMUNPK(MB,MPB) + CALL FMIGM2(MPA,MPB,MPC) + CALL FMPACK(MPC,MC) + RETURN + END SUBROUTINE FPIGM2 + + SUBROUTINE FPLNGM(MA,MB) + USE FMVALS + IMPLICIT NONE + REAL (KIND(1.0D0)) :: MA(-1:LPACK),MB(-1:LPACK) + CALL FMUNPK(MA,MPA) + CALL FMLNGM(MPA,MPB) + CALL FMPACK(MPB,MB) + RETURN + END SUBROUTINE FPLNGM + + SUBROUTINE FPPGAM(N,MA,MB) + USE FMVALS + IMPLICIT NONE + REAL (KIND(1.0D0)) :: MA(-1:LPACK),MB(-1:LPACK) + INTEGER N + CALL FMUNPK(MA,MPA) + CALL FMPGAM(N,MPA,MPB) + CALL FMPACK(MPB,MB) + RETURN + END SUBROUTINE FPPGAM + + SUBROUTINE FPPOCH(MA,N,MB) + USE FMVALS + IMPLICIT NONE + REAL (KIND(1.0D0)) :: MA(-1:LPACK),MB(-1:LPACK) + INTEGER N + CALL FMUNPK(MA,MPA) + CALL FMPOCH(MPA,N,MPB) + CALL FMPACK(MPB,MB) + RETURN + END SUBROUTINE FPPOCH + + SUBROUTINE FPPSI(MA,MB) + USE FMVALS + IMPLICIT NONE + REAL (KIND(1.0D0)) :: MA(-1:LPACK),MB(-1:LPACK) + CALL FMUNPK(MA,MPA) + CALL FMPSI(MPA,MPB) + CALL FMPACK(MPB,MB) + RETURN + END SUBROUTINE FPPSI + +! Interface routines for calling with the FM, IM, and ZM derived types. + + SUBROUTINE FM_ABS(MA,MB) + USE FMZM + TYPE ( FM ) MA,MB + CALL FMABS(MA%MFM,MB%MFM) + END SUBROUTINE + + SUBROUTINE FM_ACOS(MA,MB) + USE FMZM + TYPE ( FM ) MA,MB + CALL FMACOS(MA%MFM,MB%MFM) + END SUBROUTINE + + SUBROUTINE FM_ADD(MA,MB,MC) + USE FMZM + TYPE ( FM ) MA,MB,MC + CALL FMADD(MA%MFM,MB%MFM,MC%MFM) + END SUBROUTINE + + SUBROUTINE FM_ADD_R1(MA,MB) + USE FMZM + TYPE ( FM ) MA,MB + CALL FMADD_R1(MA%MFM,MB%MFM) + END SUBROUTINE + + SUBROUTINE FM_ADD_R2(MA,MB) + USE FMZM + TYPE ( FM ) MA,MB + CALL FMADD_R2(MA%MFM,MB%MFM) + END SUBROUTINE + + SUBROUTINE FM_ADDI(MA,IVAL) + USE FMZM + TYPE ( FM ) MA + INTEGER IVAL + CALL FMADDI(MA%MFM,IVAL) + END SUBROUTINE + + SUBROUTINE FM_ASIN(MA,MB) + USE FMZM + TYPE ( FM ) MA,MB + CALL FMASIN(MA%MFM,MB%MFM) + END SUBROUTINE + + SUBROUTINE FM_ATAN(MA,MB) + USE FMZM + TYPE ( FM ) MA,MB + CALL FMATAN(MA%MFM,MB%MFM) + END SUBROUTINE + + SUBROUTINE FM_ATN2(MA,MB,MC) + USE FMZM + TYPE ( FM ) MA,MB,MC + CALL FMATN2(MA%MFM,MB%MFM,MC%MFM) + END SUBROUTINE + + SUBROUTINE FM_BIG(MA) + USE FMZM + TYPE ( FM ) MA + CALL FMBIG(MA%MFM) + END SUBROUTINE + + SUBROUTINE FM_CHSH(MA,MB,MC) + USE FMZM + TYPE ( FM ) MA,MB,MC + CALL FMCHSH(MA%MFM,MB%MFM,MC%MFM) + END SUBROUTINE + + FUNCTION FM_COMP(MA,LREL,MB) + USE FMZM + LOGICAL FM_COMP,FMCOMP + TYPE ( FM ) MA,MB + CHARACTER(*) :: LREL + FM_COMP = FMCOMP(MA%MFM,LREL,MB%MFM) + END FUNCTION + + SUBROUTINE FM_COS(MA,MB) + USE FMZM + TYPE ( FM ) MA,MB + CALL FMCOS(MA%MFM,MB%MFM) + END SUBROUTINE + + SUBROUTINE FM_COSH(MA,MB) + USE FMZM + TYPE ( FM ) MA,MB + CALL FMCOSH(MA%MFM,MB%MFM) + END SUBROUTINE + + SUBROUTINE FM_CSSN(MA,MB,MC) + USE FMZM + TYPE ( FM ) MA,MB,MC + CALL FMCSSN(MA%MFM,MB%MFM,MC%MFM) + END SUBROUTINE + + SUBROUTINE FM_DIM(MA,MB,MC) + USE FMZM + TYPE ( FM ) MA,MB,MC + CALL FMDIM(MA%MFM,MB%MFM,MC%MFM) + END SUBROUTINE + + SUBROUTINE FM_DIV(MA,MB,MC) + USE FMZM + TYPE ( FM ) MA,MB,MC + CALL FMDIV(MA%MFM,MB%MFM,MC%MFM) + END SUBROUTINE + + SUBROUTINE FM_DIV_R1(MA,MB) + USE FMZM + TYPE ( FM ) MA,MB + CALL FMDIV_R1(MA%MFM,MB%MFM) + END SUBROUTINE + + SUBROUTINE FM_DIV_R2(MA,MB) + USE FMZM + TYPE ( FM ) MA,MB + CALL FMDIV_R2(MA%MFM,MB%MFM) + END SUBROUTINE + + SUBROUTINE FM_DIVI(MA,IVAL,MB) + USE FMZM + TYPE ( FM ) MA,MB + INTEGER IVAL + CALL FMDIVI(MA%MFM,IVAL,MB%MFM) + END SUBROUTINE + + SUBROUTINE FM_DIVI_R1(MA,IVAL) + USE FMZM + TYPE ( FM ) MA + INTEGER IVAL + CALL FMDIVI_R1(MA%MFM,IVAL) + END SUBROUTINE + + SUBROUTINE FM_DP2M(X,MA) + USE FMZM + TYPE ( FM ) MA + DOUBLE PRECISION X + CALL FMDP2M(X,MA%MFM) + END SUBROUTINE + + SUBROUTINE FM_DPM(X,MA) + USE FMZM + TYPE ( FM ) MA + DOUBLE PRECISION X + CALL FMDPM(X,MA%MFM) + END SUBROUTINE + + SUBROUTINE FM_EQ(MA,MB) + USE FMZM + TYPE ( FM ) MA,MB + CALL FMEQ(MA%MFM,MB%MFM) + END SUBROUTINE + + SUBROUTINE FM_EQU(MA,MB,NA,NB) + USE FMZM + INTEGER NA,NB + TYPE ( FM ) MA,MB + CALL FMEQU(MA%MFM,MB%MFM,NA,NB) + END SUBROUTINE + + SUBROUTINE FM_EXP(MA,MB) + USE FMZM + TYPE ( FM ) MA,MB + CALL FMEXP(MA%MFM,MB%MFM) + END SUBROUTINE + + SUBROUTINE FM_FORM(FORM,MA,STRING) + USE FMZM + CHARACTER(*) :: FORM,STRING + TYPE ( FM ) MA + CALL FMFORM(FORM,MA%MFM,STRING) + END SUBROUTINE + + SUBROUTINE FM_FPRT(FORM,MA) + USE FMZM + CHARACTER(*) :: FORM + TYPE ( FM ) MA + CALL FMFPRT(FORM,MA%MFM) + END SUBROUTINE + + SUBROUTINE FM_I2M(IVAL,MA) + USE FMZM + TYPE ( FM ) MA + INTEGER IVAL + CALL FMI2M(IVAL,MA%MFM) + END SUBROUTINE + + SUBROUTINE FM_INP(LINE,MA,LA,LB) + USE FMZM + INTEGER LA,LB + CHARACTER LINE(LB) + TYPE ( FM ) MA + CALL FMINP(LINE,MA%MFM,LA,LB) + END SUBROUTINE + + SUBROUTINE FM_INT(MA,MB) + USE FMZM + TYPE ( FM ) MA,MB + CALL FMINT(MA%MFM,MB%MFM) + END SUBROUTINE + + SUBROUTINE FM_IPWR(MA,IVAL,MB) + USE FMZM + TYPE ( FM ) MA,MB + INTEGER IVAL + CALL FMIPWR(MA%MFM,IVAL,MB%MFM) + END SUBROUTINE + + SUBROUTINE FM_LG10(MA,MB) + USE FMZM + TYPE ( FM ) MA,MB + CALL FMLG10(MA%MFM,MB%MFM) + END SUBROUTINE + + SUBROUTINE FM_LN(MA,MB) + USE FMZM + TYPE ( FM ) MA,MB + CALL FMLN(MA%MFM,MB%MFM) + END SUBROUTINE + + SUBROUTINE FM_LNI(IVAL,MA) + USE FMZM + TYPE ( FM ) MA + INTEGER IVAL + CALL FMLNI(IVAL,MA%MFM) + END SUBROUTINE + + SUBROUTINE FM_M2DP(MA,X) + USE FMZM + TYPE ( FM ) MA + DOUBLE PRECISION X + CALL FMM2DP(MA%MFM,X) + END SUBROUTINE + + SUBROUTINE FM_M2I(MA,IVAL) + USE FMZM + TYPE ( FM ) MA + INTEGER IVAL + CALL FMM2I(MA%MFM,IVAL) + END SUBROUTINE + + SUBROUTINE FM_M2SP(MA,X) + USE FMZM + TYPE ( FM ) MA + REAL X + CALL FMM2SP(MA%MFM,X) + END SUBROUTINE + + SUBROUTINE FM_MAX(MA,MB,MC) + USE FMZM + TYPE ( FM ) MA,MB,MC + CALL FMMAX(MA%MFM,MB%MFM,MC%MFM) + END SUBROUTINE + + SUBROUTINE FM_MIN(MA,MB,MC) + USE FMZM + TYPE ( FM ) MA,MB,MC + CALL FMMIN(MA%MFM,MB%MFM,MC%MFM) + END SUBROUTINE + + SUBROUTINE FM_MOD(MA,MB,MC) + USE FMZM + TYPE ( FM ) MA,MB,MC + CALL FMMOD(MA%MFM,MB%MFM,MC%MFM) + END SUBROUTINE + + SUBROUTINE FM_MPY(MA,MB,MC) + USE FMZM + TYPE ( FM ) MA,MB,MC + CALL FMMPY(MA%MFM,MB%MFM,MC%MFM) + END SUBROUTINE + + SUBROUTINE FM_MPY_R1(MA,MB) + USE FMZM + TYPE ( FM ) MA,MB + CALL FMMPY_R1(MA%MFM,MB%MFM) + END SUBROUTINE + + SUBROUTINE FM_MPY_R2(MA,MB) + USE FMZM + TYPE ( FM ) MA,MB + CALL FMMPY_R2(MA%MFM,MB%MFM) + END SUBROUTINE + + SUBROUTINE FM_MPYI(MA,IVAL,MB) + USE FMZM + TYPE ( FM ) MA,MB + INTEGER IVAL + CALL FMMPYI(MA%MFM,IVAL,MB%MFM) + END SUBROUTINE + + SUBROUTINE FM_MPYI_R1(MA,IVAL) + USE FMZM + TYPE ( FM ) MA + INTEGER IVAL + CALL FMMPYI_R1(MA%MFM,IVAL) + END SUBROUTINE + + SUBROUTINE FM_NINT(MA,MB) + USE FMZM + TYPE ( FM ) MA,MB + CALL FMNINT(MA%MFM,MB%MFM) + END SUBROUTINE + + SUBROUTINE FM_OUT(MA,LINE,LB) + USE FMZM + INTEGER LB + CHARACTER LINE(LB) + TYPE ( FM ) MA + CALL FMOUT(MA%MFM,LINE,LB) + END SUBROUTINE + + SUBROUTINE FM_PI(MA) + USE FMZM + TYPE ( FM ) MA + CALL FMPI(MA%MFM) + END SUBROUTINE + + SUBROUTINE FM_PRNT(MA) + USE FMZM + TYPE ( FM ) MA + CALL FMPRNT(MA%MFM) + END SUBROUTINE + + SUBROUTINE FM_PWR(MA,MB,MC) + USE FMZM + TYPE ( FM ) MA,MB,MC + CALL FMPWR(MA%MFM,MB%MFM,MC%MFM) + END SUBROUTINE + + SUBROUTINE FM_READ(KREAD,MA) + USE FMZM + INTEGER KREAD + TYPE ( FM ) MA + CALL FMREAD(KREAD,MA%MFM) + END SUBROUTINE + + SUBROUTINE FM_RPWR(MA,IVAL,JVAL,MB) + USE FMZM + TYPE ( FM ) MA,MB + INTEGER IVAL,JVAL + CALL FMRPWR(MA%MFM,IVAL,JVAL,MB%MFM) + END SUBROUTINE + + SUBROUTINE FM_SET(NPREC) + INTEGER NPREC + CALL FMSET(NPREC) + END SUBROUTINE + + SUBROUTINE FM_SIGN(MA,MB,MC) + USE FMZM + TYPE ( FM ) MA,MB,MC + CALL FMSIGN(MA%MFM,MB%MFM,MC%MFM) + END SUBROUTINE + + SUBROUTINE FM_SIN(MA,MB) + USE FMZM + TYPE ( FM ) MA,MB + CALL FMSIN(MA%MFM,MB%MFM) + END SUBROUTINE + + SUBROUTINE FM_SINH(MA,MB) + USE FMZM + TYPE ( FM ) MA,MB + CALL FMSINH(MA%MFM,MB%MFM) + END SUBROUTINE + + SUBROUTINE FM_SP2M(X,MA) + USE FMZM + TYPE ( FM ) MA + REAL X + CALL FMSP2M(X,MA%MFM) + END SUBROUTINE + + SUBROUTINE FM_SQR(MA,MB) + USE FMZM + TYPE ( FM ) MA,MB + CALL FMSQR(MA%MFM,MB%MFM) + END SUBROUTINE + + SUBROUTINE FM_SQR_R1(MA) + USE FMZM + TYPE ( FM ) MA + CALL FMSQR_R1(MA%MFM) + END SUBROUTINE + + SUBROUTINE FM_SQRT(MA,MB) + USE FMZM + TYPE ( FM ) MA,MB + CALL FMSQRT(MA%MFM,MB%MFM) + END SUBROUTINE + + SUBROUTINE FM_SQRT_R1(MA) + USE FMZM + TYPE ( FM ) MA + CALL FMSQRT_R1(MA%MFM) + END SUBROUTINE + + SUBROUTINE FM_ST2M(STRING,MA) + USE FMZM + TYPE ( FM ) MA + CHARACTER(*) :: STRING + CALL FMST2M(STRING,MA%MFM) + END SUBROUTINE + + SUBROUTINE FM_SUB(MA,MB,MC) + USE FMZM + TYPE ( FM ) MA,MB,MC + CALL FMSUB(MA%MFM,MB%MFM,MC%MFM) + END SUBROUTINE + + SUBROUTINE FM_SUB_R1(MA,MB) + USE FMZM + TYPE ( FM ) MA,MB + CALL FMSUB_R1(MA%MFM,MB%MFM) + END SUBROUTINE + + SUBROUTINE FM_SUB_R2(MA,MB) + USE FMZM + TYPE ( FM ) MA,MB + CALL FMSUB_R2(MA%MFM,MB%MFM) + END SUBROUTINE + + SUBROUTINE FM_TAN(MA,MB) + USE FMZM + TYPE ( FM ) MA,MB + CALL FMTAN(MA%MFM,MB%MFM) + END SUBROUTINE + + SUBROUTINE FM_TANH(MA,MB) + USE FMZM + TYPE ( FM ) MA,MB + CALL FMTANH(MA%MFM,MB%MFM) + END SUBROUTINE + + SUBROUTINE FM_ULP(MA,MB) + USE FMZM + TYPE ( FM ) MA,MB + CALL FMULP(MA%MFM,MB%MFM) + END SUBROUTINE + + SUBROUTINE FM_WRIT(KWRITE,MA) + USE FMZM + INTEGER KWRITE + TYPE ( FM ) MA + CALL FMWRIT(KWRITE,MA%MFM) + END SUBROUTINE + + SUBROUTINE IM_ABS(MA,MB) + USE FMZM + TYPE ( IM ) MA,MB + CALL IMABS(MA%MIM,MB%MIM) + END SUBROUTINE + + SUBROUTINE IM_ADD(MA,MB,MC) + USE FMZM + TYPE ( IM ) MA,MB,MC + CALL IMADD(MA%MIM,MB%MIM,MC%MIM) + END SUBROUTINE + + SUBROUTINE IM_BIG(MA) + USE FMZM + TYPE ( IM ) MA + CALL IMBIG(MA%MIM) + END SUBROUTINE + + FUNCTION IM_COMP(MA,LREL,MB) + USE FMZM + LOGICAL IM_COMP,IMCOMP + TYPE ( IM ) MA,MB + CHARACTER(*) :: LREL + IM_COMP = IMCOMP(MA%MIM,LREL,MB%MIM) + END FUNCTION + + SUBROUTINE IM_DIM(MA,MB,MC) + USE FMZM + TYPE ( IM ) MA,MB,MC + CALL IMDIM(MA%MIM,MB%MIM,MC%MIM) + END SUBROUTINE + + SUBROUTINE IM_DIV(MA,MB,MC) + USE FMZM + TYPE ( IM ) MA,MB,MC + CALL IMDIV(MA%MIM,MB%MIM,MC%MIM) + END SUBROUTINE + + SUBROUTINE IM_DIVI(MA,IVAL,MB) + USE FMZM + TYPE ( IM ) MA,MB + INTEGER IVAL + CALL IMDIVI(MA%MIM,IVAL,MB%MIM) + END SUBROUTINE + + SUBROUTINE IM_DIVR(MA,MB,MC,MD) + USE FMZM + TYPE ( IM ) MA,MB,MC,MD + CALL IMDIVR(MA%MIM,MB%MIM,MC%MIM,MD%MIM) + END SUBROUTINE + + SUBROUTINE IM_DVIR(MA,IVAL,MB,IREM) + USE FMZM + TYPE ( IM ) MA,MB + INTEGER IVAL,IREM + CALL IMDVIR(MA%MIM,IVAL,MB%MIM,IREM) + END SUBROUTINE + + SUBROUTINE IM_EQ(MA,MB) + USE FMZM + TYPE ( IM ) MA,MB + CALL IMEQ(MA%MIM,MB%MIM) + END SUBROUTINE + + SUBROUTINE IM_FM2I(MA,MB) + USE FMZM + TYPE ( FM ) MA + TYPE ( IM ) MB + CALL IMFM2I(MA%MFM,MB%MIM) + END SUBROUTINE + + SUBROUTINE IM_FORM(FORM,MA,STRING) + USE FMZM + CHARACTER(*) :: FORM,STRING + TYPE ( IM ) MA + CALL IMFORM(FORM,MA%MIM,STRING) + END SUBROUTINE + + SUBROUTINE IM_FPRT(FORM,MA) + USE FMZM + CHARACTER(*) :: FORM + TYPE ( IM ) MA + CALL IMFPRT(FORM,MA%MIM) + END SUBROUTINE + + SUBROUTINE IM_GCD(MA,MB,MC) + USE FMZM + TYPE ( IM ) MA,MB,MC + CALL IMGCD(MA%MIM,MB%MIM,MC%MIM) + END SUBROUTINE + + SUBROUTINE IM_I2FM(MA,MB) + USE FMZM + TYPE ( IM ) MA + TYPE ( FM ) MB + CALL IMI2FM(MA%MIM,MB%MFM) + END SUBROUTINE + + SUBROUTINE IM_I2M(IVAL,MA) + USE FMZM + TYPE ( IM ) MA + INTEGER IVAL + CALL IMI2M(IVAL,MA%MIM) + END SUBROUTINE + + SUBROUTINE IM_INP(LINE,MA,LA,LB) + USE FMZM + INTEGER LA,LB + CHARACTER LINE(LB) + TYPE ( IM ) MA + CALL IMINP(LINE,MA%MIM,LA,LB) + END SUBROUTINE + + SUBROUTINE IM_M2DP(MA,X) + USE FMZM + TYPE ( IM ) MA + DOUBLE PRECISION X + CALL IMM2DP(MA%MIM,X) + END SUBROUTINE + + SUBROUTINE IM_M2I(MA,IVAL) + USE FMZM + TYPE ( IM ) MA + INTEGER IVAL + CALL IMM2I(MA%MIM,IVAL) + END SUBROUTINE + + SUBROUTINE IM_MAX(MA,MB,MC) + USE FMZM + TYPE ( IM ) MA,MB,MC + CALL IMMAX(MA%MIM,MB%MIM,MC%MIM) + END SUBROUTINE + + SUBROUTINE IM_MIN(MA,MB,MC) + USE FMZM + TYPE ( IM ) MA,MB,MC + CALL IMMIN(MA%MIM,MB%MIM,MC%MIM) + END SUBROUTINE + + SUBROUTINE IM_MOD(MA,MB,MC) + USE FMZM + TYPE ( IM ) MA,MB,MC + CALL IMMOD(MA%MIM,MB%MIM,MC%MIM) + END SUBROUTINE + + SUBROUTINE IM_MPY(MA,MB,MC) + USE FMZM + TYPE ( IM ) MA,MB,MC + CALL IMMPY(MA%MIM,MB%MIM,MC%MIM) + END SUBROUTINE + + SUBROUTINE IM_MPYI(MA,IVAL,MB) + USE FMZM + TYPE ( IM ) MA,MB + INTEGER IVAL + CALL IMMPYI(MA%MIM,IVAL,MB%MIM) + END SUBROUTINE + + SUBROUTINE IM_MPYM(MA,MB,MC,MD) + USE FMZM + TYPE ( IM ) MA,MB,MC,MD + CALL IMMPYM(MA%MIM,MB%MIM,MC%MIM,MD%MIM) + END SUBROUTINE + + SUBROUTINE IM_OUT(MA,LINE,LB) + USE FMZM + INTEGER LB + CHARACTER LINE(LB) + TYPE ( IM ) MA + CALL IMOUT(MA%MIM,LINE,LB) + END SUBROUTINE + + SUBROUTINE IM_PMOD(MA,MB,MC,MD) + USE FMZM + TYPE ( IM ) MA,MB,MC,MD + CALL IMPMOD(MA%MIM,MB%MIM,MC%MIM,MD%MIM) + END SUBROUTINE + + SUBROUTINE IM_PRNT(MA) + USE FMZM + TYPE ( IM ) MA + CALL IMPRNT(MA%MIM) + END SUBROUTINE + + SUBROUTINE IM_PWR(MA,MB,MC) + USE FMZM + TYPE ( IM ) MA,MB,MC + CALL IMPWR(MA%MIM,MB%MIM,MC%MIM) + END SUBROUTINE + + SUBROUTINE IM_READ(KREAD,MA) + USE FMZM + INTEGER KREAD + TYPE ( IM ) MA + CALL IMREAD(KREAD,MA%MIM) + END SUBROUTINE + + SUBROUTINE IM_SET(NPREC) + INTEGER NPREC + CALL FMSET(NPREC) + END SUBROUTINE + + SUBROUTINE IM_SIGN(MA,MB,MC) + USE FMZM + TYPE ( IM ) MA,MB,MC + CALL IMSIGN(MA%MIM,MB%MIM,MC%MIM) + END SUBROUTINE + + SUBROUTINE IM_SQR(MA,MB) + USE FMZM + TYPE ( IM ) MA,MB + CALL IMSQR(MA%MIM,MB%MIM) + END SUBROUTINE + + SUBROUTINE IM_ST2M(STRING,MA) + USE FMZM + TYPE ( IM ) MA + CHARACTER(*) :: STRING + CALL IMST2M(STRING,MA%MIM) + END SUBROUTINE + + SUBROUTINE IM_SUB(MA,MB,MC) + USE FMZM + TYPE ( IM ) MA,MB,MC + CALL IMSUB(MA%MIM,MB%MIM,MC%MIM) + END SUBROUTINE + + SUBROUTINE IM_WRIT(KWRITE,MA) + USE FMZM + INTEGER KWRITE + TYPE ( IM ) MA + CALL IMWRIT(KWRITE,MA%MIM) + END SUBROUTINE + + SUBROUTINE ZM_ABS(MA,MB) + USE FMZM + TYPE ( ZM ) MA + TYPE ( FM ) MB + CALL ZMABS(MA%MZM,MB%MFM) + END SUBROUTINE + + SUBROUTINE ZM_ACOS(MA,MB) + USE FMZM + TYPE ( ZM ) MA,MB + CALL ZMACOS(MA%MZM,MB%MZM) + END SUBROUTINE + + SUBROUTINE ZM_ADD(MA,MB,MC) + USE FMZM + TYPE ( ZM ) MA,MB,MC + CALL ZMADD(MA%MZM,MB%MZM,MC%MZM) + END SUBROUTINE + + SUBROUTINE ZM_ADDI(MA,IVAL) + USE FMZM + TYPE ( ZM ) MA + INTEGER IVAL + CALL ZMADDI(MA%MZM,IVAL) + END SUBROUTINE + + SUBROUTINE ZM_ARG(MA,MB) + USE FMZM + TYPE ( ZM ) MA + TYPE ( FM ) MB + CALL ZMARG(MA%MZM,MB%MFM) + END SUBROUTINE + + SUBROUTINE ZM_ASIN(MA,MB) + USE FMZM + TYPE ( ZM ) MA,MB + CALL ZMASIN(MA%MZM,MB%MZM) + END SUBROUTINE + + SUBROUTINE ZM_ATAN(MA,MB) + USE FMZM + TYPE ( ZM ) MA,MB + CALL ZMATAN(MA%MZM,MB%MZM) + END SUBROUTINE + + SUBROUTINE ZM_CHSH(MA,MB,MC) + USE FMZM + TYPE ( ZM ) MA,MB,MC + CALL ZMCHSH(MA%MZM,MB%MZM,MC%MZM) + END SUBROUTINE + + SUBROUTINE ZM_CMPX(MA,MB,MC) + USE FMZM + TYPE ( FM ) MA,MB + TYPE ( ZM ) MC + CALL ZMCMPX(MA%MFM,MB%MFM,MC%MZM) + END SUBROUTINE + + SUBROUTINE ZM_CONJ(MA,MB) + USE FMZM + TYPE ( ZM ) MA,MB + CALL ZMCONJ(MA%MZM,MB%MZM) + END SUBROUTINE + + SUBROUTINE ZM_COS(MA,MB) + USE FMZM + TYPE ( ZM ) MA,MB + CALL ZMCOS(MA%MZM,MB%MZM) + END SUBROUTINE + + SUBROUTINE ZM_COSH(MA,MB) + USE FMZM + TYPE ( ZM ) MA,MB + CALL ZMCOSH(MA%MZM,MB%MZM) + END SUBROUTINE + + SUBROUTINE ZM_CSSN(MA,MB,MC) + USE FMZM + TYPE ( ZM ) MA,MB,MC + CALL ZMCSSN(MA%MZM,MB%MZM,MC%MZM) + END SUBROUTINE + + SUBROUTINE ZM_DIV(MA,MB,MC) + USE FMZM + TYPE ( ZM ) MA,MB,MC + CALL ZMDIV(MA%MZM,MB%MZM,MC%MZM) + END SUBROUTINE + + SUBROUTINE ZM_DIVI(MA,IVAL,MB) + USE FMZM + TYPE ( ZM ) MA,MB + INTEGER IVAL + CALL ZMDIVI(MA%MZM,IVAL,MB%MZM) + END SUBROUTINE + + SUBROUTINE ZM_EQ(MA,MB) + USE FMZM + TYPE ( ZM ) MA,MB + CALL ZMEQ(MA%MZM,MB%MZM) + END SUBROUTINE + + SUBROUTINE ZM_EQU(MA,MB,NA,NB) + USE FMZM + INTEGER NA,NB + TYPE ( ZM ) MA,MB + CALL ZMEQU(MA%MZM,MB%MZM,NA,NB) + END SUBROUTINE + + SUBROUTINE ZM_EXP(MA,MB) + USE FMZM + TYPE ( ZM ) MA,MB + CALL ZMEXP(MA%MZM,MB%MZM) + END SUBROUTINE + + SUBROUTINE ZM_FORM(FORM1,FORM2,MA,STRING) + USE FMZM + CHARACTER(*) :: FORM1,FORM2,STRING + TYPE ( ZM ) MA + CALL ZMFORM(FORM1,FORM2,MA%MZM,STRING) + END SUBROUTINE + + SUBROUTINE ZM_FPRT(FORM1,FORM2,MA) + USE FMZM + CHARACTER(*) :: FORM1,FORM2 + TYPE ( ZM ) MA + CALL ZMFPRT(FORM1,FORM2,MA%MZM) + END SUBROUTINE + + SUBROUTINE ZM_I2M(IVAL,MA) + USE FMZM + TYPE ( ZM ) MA + INTEGER IVAL + CALL ZMI2M(IVAL,MA%MZM) + END SUBROUTINE + + SUBROUTINE ZM_2I2M(IVAL1,IVAL2,MA) + USE FMZM + TYPE ( ZM ) MA + INTEGER IVAL1,IVAL2 + CALL ZM2I2M(IVAL1,IVAL2,MA%MZM) + END SUBROUTINE + + SUBROUTINE ZM_IMAG(MA,MB) + USE FMZM + TYPE ( ZM ) MA + TYPE ( FM ) MB + CALL ZMIMAG(MA%MZM,MB%MFM) + END SUBROUTINE + + SUBROUTINE ZM_INP(LINE,MA,LA,LB) + USE FMZM + INTEGER LA,LB + CHARACTER LINE(LB) + TYPE ( ZM ) MA + CALL ZMINP(LINE,MA%MZM,LA,LB) + END SUBROUTINE + + SUBROUTINE ZM_INT(MA,MB) + USE FMZM + TYPE ( ZM ) MA,MB + CALL ZMINT(MA%MZM,MB%MZM) + END SUBROUTINE + + SUBROUTINE ZM_IPWR(MA,IVAL,MB) + USE FMZM + TYPE ( ZM ) MA,MB + INTEGER IVAL + CALL ZMIPWR(MA%MZM,IVAL,MB%MZM) + END SUBROUTINE + + SUBROUTINE ZM_LG10(MA,MB) + USE FMZM + TYPE ( ZM ) MA,MB + CALL ZMLG10(MA%MZM,MB%MZM) + END SUBROUTINE + + SUBROUTINE ZM_LN(MA,MB) + USE FMZM + TYPE ( ZM ) MA,MB + CALL ZMLN(MA%MZM,MB%MZM) + END SUBROUTINE + + SUBROUTINE ZM_M2I(MA,IVAL) + USE FMZM + TYPE ( ZM ) MA + INTEGER IVAL + CALL ZMM2I(MA%MZM,IVAL) + END SUBROUTINE + + SUBROUTINE ZM_M2Z(MA,ZVAL) + USE FMZM + TYPE ( ZM ) MA + COMPLEX ZVAL + CALL ZMM2Z(MA%MZM,ZVAL) + END SUBROUTINE + + SUBROUTINE ZM_MPY(MA,MB,MC) + USE FMZM + TYPE ( ZM ) MA,MB,MC + CALL ZMMPY(MA%MZM,MB%MZM,MC%MZM) + END SUBROUTINE + + SUBROUTINE ZM_MPYI(MA,IVAL,MB) + USE FMZM + TYPE ( ZM ) MA,MB + INTEGER IVAL + CALL ZMMPYI(MA%MZM,IVAL,MB%MZM) + END SUBROUTINE + + SUBROUTINE ZM_NINT(MA,MB) + USE FMZM + TYPE ( ZM ) MA,MB + CALL ZMNINT(MA%MZM,MB%MZM) + END SUBROUTINE + + SUBROUTINE ZM_OUT(MA,LINE,LB,LAST1,LAST2) + USE FMZM + INTEGER LB,LAST1,LAST2 + CHARACTER LINE(LB) + TYPE ( ZM ) MA + CALL ZMOUT(MA%MZM,LINE,LB,LAST1,LAST2) + END SUBROUTINE + + SUBROUTINE ZM_PRNT(MA) + USE FMZM + TYPE ( ZM ) MA + CALL ZMPRNT(MA%MZM) + END SUBROUTINE + + SUBROUTINE ZM_PWR(MA,MB,MC) + USE FMZM + TYPE ( ZM ) MA,MB,MC + CALL ZMPWR(MA%MZM,MB%MZM,MC%MZM) + END SUBROUTINE + + SUBROUTINE ZM_READ(KREAD,MA) + USE FMZM + INTEGER KREAD + TYPE ( ZM ) MA + CALL ZMREAD(KREAD,MA%MZM) + END SUBROUTINE + + SUBROUTINE ZM_REAL(MA,MB) + USE FMZM + TYPE ( ZM ) MA + TYPE ( FM ) MB + CALL ZMREAL(MA%MZM,MB%MFM) + END SUBROUTINE + + SUBROUTINE ZM_RPWR(MA,IVAL,JVAL,MB) + USE FMZM + TYPE ( ZM ) MA,MB + INTEGER IVAL,JVAL + CALL ZMRPWR(MA%MZM,IVAL,JVAL,MB%MZM) + END SUBROUTINE + + SUBROUTINE ZM_SET(NPREC) + INTEGER NPREC + CALL ZMSET(NPREC) + END SUBROUTINE + + SUBROUTINE ZM_SIN(MA,MB) + USE FMZM + TYPE ( ZM ) MA,MB + CALL ZMSIN(MA%MZM,MB%MZM) + END SUBROUTINE + + SUBROUTINE ZM_SINH(MA,MB) + USE FMZM + TYPE ( ZM ) MA,MB + CALL ZMSINH(MA%MZM,MB%MZM) + END SUBROUTINE + + SUBROUTINE ZM_SQR(MA,MB) + USE FMZM + TYPE ( ZM ) MA,MB + CALL ZMSQR(MA%MZM,MB%MZM) + END SUBROUTINE + + SUBROUTINE ZM_SQRT(MA,MB) + USE FMZM + TYPE ( ZM ) MA,MB + CALL ZMSQRT(MA%MZM,MB%MZM) + END SUBROUTINE + + SUBROUTINE ZM_ST2M(STRING,MA) + USE FMZM + TYPE ( ZM ) MA + CHARACTER(*) :: STRING + CALL ZMST2M(STRING,MA%MZM) + END SUBROUTINE + + SUBROUTINE ZM_SUB(MA,MB,MC) + USE FMZM + TYPE ( ZM ) MA,MB,MC + CALL ZMSUB(MA%MZM,MB%MZM,MC%MZM) + END SUBROUTINE + + SUBROUTINE ZM_TAN(MA,MB) + USE FMZM + TYPE ( ZM ) MA,MB + CALL ZMTAN(MA%MZM,MB%MZM) + END SUBROUTINE + + SUBROUTINE ZM_TANH(MA,MB) + USE FMZM + TYPE ( ZM ) MA,MB + CALL ZMTANH(MA%MZM,MB%MZM) + END SUBROUTINE + + SUBROUTINE ZM_WRIT(KWRITE,MA) + USE FMZM + INTEGER KWRITE + TYPE ( ZM ) MA + CALL ZMWRIT(KWRITE,MA%MZM) + END SUBROUTINE + + SUBROUTINE ZM_Z2M(ZVAL,MA) + USE FMZM + TYPE ( ZM ) MA + COMPLEX ZVAL + CALL ZMZ2M(ZVAL,MA%MZM) + END SUBROUTINE + + SUBROUTINE FM_BERN(N,MA,MB) + USE FMZM + TYPE ( FM ) MA,MB + INTEGER N + CALL FMBERN(N,MA%MFM,MB%MFM) + END SUBROUTINE + + SUBROUTINE FM_BETA(MA,MB,MC) + USE FMZM + TYPE ( FM ) MA,MB,MC + CALL FMBETA(MA%MFM,MB%MFM,MC%MFM) + END SUBROUTINE + + SUBROUTINE FM_COMB(MA,MB,MC) + USE FMZM + TYPE ( FM ) MA,MB,MC + CALL FMCOMB(MA%MFM,MB%MFM,MC%MFM) + END SUBROUTINE + + SUBROUTINE FM_EULR(MA) + USE FMZM + TYPE ( FM ) MA + CALL FMEULR(MA%MFM) + END SUBROUTINE + + SUBROUTINE FM_FACT(MA,MB) + USE FMZM + TYPE ( FM ) MA,MB + CALL FMFACT(MA%MFM,MB%MFM) + END SUBROUTINE + + SUBROUTINE FM_GAM(MA,MB) + USE FMZM + TYPE ( FM ) MA,MB + CALL FMGAM(MA%MFM,MB%MFM) + END SUBROUTINE + + SUBROUTINE FM_IBTA(MA,MB,MC,MD) + USE FMZM + TYPE ( FM ) MA,MB,MC,MD + CALL FMIBTA(MA%MFM,MB%MFM,MC%MFM,MD%MFM) + END SUBROUTINE + + SUBROUTINE FM_IGM1(MA,MB,MC) + USE FMZM + TYPE ( FM ) MA,MB,MC + CALL FMIGM1(MA%MFM,MB%MFM,MC%MFM) + END SUBROUTINE + + SUBROUTINE FM_IGM2(MA,MB,MC) + USE FMZM + TYPE ( FM ) MA,MB,MC + CALL FMIGM2(MA%MFM,MB%MFM,MC%MFM) + END SUBROUTINE + + SUBROUTINE FM_LNGM(MA,MB) + USE FMZM + TYPE ( FM ) MA,MB + CALL FMLNGM(MA%MFM,MB%MFM) + END SUBROUTINE + + SUBROUTINE FM_PGAM(N,MA,MB) + USE FMZM + TYPE ( FM ) MA,MB + INTEGER N + CALL FMPGAM(N,MA%MFM,MB%MFM) + END SUBROUTINE + + SUBROUTINE FM_POCH(MA,N,MB) + USE FMZM + TYPE ( FM ) MA,MB + INTEGER N + CALL FMPOCH(MA%MFM,N,MB%MFM) + END SUBROUTINE + + SUBROUTINE FM_PSI(MA,MB) + USE FMZM + TYPE ( FM ) MA,MB + CALL FMPSI(MA%MFM,MB%MFM) + END SUBROUTINE diff --git a/src/fmlib/FMSAVE.F90 b/src/fmlib/FMSAVE.F90 new file mode 100644 index 0000000000000000000000000000000000000000..864b714a3d9a8c440684e141afa4c1d4c01fdf70 --- /dev/null +++ b/src/fmlib/FMSAVE.F90 @@ -0,0 +1,544 @@ + MODULE FMVALS + +! These are the global and saved variables used by the FM and ZM packages. +! See the User's Manual in the ReadMe file for further description of some +! of these variables. + +! They are initialized assuming the program will run on a 32-bit computer +! with variables in FM.f having names beginning with 'M' being declared +! as having 64-bit representations (DOUBLE PRECISION). + +! For a machine with a different architecture, or for setting the precision +! level to a different value, CALL FMSET(NPREC) before doing any multiple +! precision operations. FMSET tries to initialize the variables to the +! best values for the given machine. To have the values chosen by FMSET +! written on unit KW, CALL FMVARS. + +! Base and precision will be set to give slightly more than 50 decimal +! digits of precision, giving the user 50 significant digits of precision +! along with several base ten guard digits. + +! MBASE is set to 10**7. +! JFORM1 and JFORM2 are set to 1PE format displaying 50 significant digits. + +! The trace option is set off. +! The mode for angles in trig functions is set to radians. +! The rounding mode is set to symmetric rounding (to nearest), with the +! option for perfect rounding off. +! Warning error message level is set to 1. +! Cancellation error monitor is set off. +! Screen width for output is set to 80 columns. +! The exponent character for FM output is set to 'M'. +! Debug error checking is set off. + +! KW, the unit number for all FM output, is set to 6. + +! The size of all arrays is controlled by defining two parameters: +! NDIGMX is the maximum value the user can set NDIG, +! NBITS is an upper bound for the number of bits used to represent +! integers in an M-variable word. + + INTEGER, PARAMETER :: NDIGMX = 55 +! Integer initialization +! INTEGER, PARAMETER :: NDIGMX = 80 + INTEGER, PARAMETER :: NBITS = 64 + + INTEGER, PARAMETER :: LPACK = (NDIGMX+1)/2 + 1 + INTEGER, PARAMETER :: LUNPCK = (11*NDIGMX)/5 + 30 + INTEGER, PARAMETER :: LMWA = 2*LUNPCK + INTEGER, PARAMETER :: LJSUMS = 8*(LUNPCK+3) + INTEGER, PARAMETER :: LMBUFF = ((LUNPCK+4)*(NBITS-1)*301)/2000 + 6 + +! KW is the unit number for standard output from the +! FM package. This includes trace output and error +! messages. + + INTEGER, SAVE :: KW = 6 + +! MAXINT should be set to a very large integer, possibly +! the largest representable integer for the current +! machine. For most 32-bit machines, MAXINT is set +! to 2**53 - 1 = 9.007D+15 when double precision +! arithmetic is used for M-variables. Using integer +! M-variables usually gives MAXINT = 2**31 - 1 = +! 2147483647. +! Setting MAXINT to a smaller number is ok, but this +! unnecessarily restricts the permissible range of +! MBASE and MXEXP. + + REAL (KIND(1.0D0)), SAVE :: MAXINT = 9007199254740991.0D0 +! Integer initialization +! INTEGER, SAVE :: MAXINT = 2147483647 + +! INTMAX is a large value close to the overflow threshold +! for integer variables. It is usually 2**31 - 1 +! for machines with 32-bit integer arithmetic. + + INTEGER, SAVE :: INTMAX = 2147483647 + +! DPMAX should be set to a value near the machine's double +! precision overflow threshold, so that DPMAX and +! 1.0D0/DPMAX are both representable in double +! precision. + + DOUBLE PRECISION, SAVE :: DPMAX = 1.797D+308/5.0D0 + +! SPMAX should be set to a value near the machine's single +! precision overflow threshold, so that 1.01*SPMAX +! and 1.0/SPMAX are both representable in single +! precision. + + REAL, SAVE :: SPMAX = 3.40E+38/5.0 + +! NDG2MX is the maximum value for NDIG that can be used +! internally. FM routines may raise NDIG above +! NDIGMX temporarily, to compute correctly +! rounded results. +! In the definition of LUNPCK, the '11/5' condition +! allows for carrying at least NDIG guard digits +! when the option for perfect rounding is selected. +! The '+ 30' condition allows for the need to carry +! many guard digits when using a small base like 2. + + INTEGER, PARAMETER :: NDG2MX = LUNPCK - 2 + +! MXBASE is the maximum value for MBASE. + + REAL (KIND(1.0D0)), SAVE :: MXBASE = 94906265.0D0 +! Integer initialization +! INTEGER, SAVE :: MXBASE = 46340 + +! MBASE is the currently used base for arithmetic. + + REAL (KIND(1.0D0)), SAVE :: MBASE = 1.0D7 +! Integer initialization +! INTEGER, SAVE :: MBASE = 10000 + +! NDIG is the number of digits currently being carried. + + INTEGER, SAVE :: NDIG = 9 +! Integer initialization +! INTEGER, SAVE :: NDIG = 14 + +! KFLAG is the flag for error conditions. + + INTEGER, SAVE :: KFLAG = 0 + +! NTRACE is the trace switch. Default is no printing. + + INTEGER, SAVE :: NTRACE = 0 + +! LVLTRC is the trace level. Default is to trace only +! routines called directly by the user. + + INTEGER, SAVE :: LVLTRC = 1 + +! NCALL is the call stack pointer. + + INTEGER, SAVE :: NCALL = 0 + +! NAMEST is the call stack. + + INTEGER, PRIVATE :: I + CHARACTER(6), SAVE :: NAMEST(0:50) = (/ ('MAIN ' , I = 0, 50) /) + +! Some constants that are often needed are stored with the +! maximum precision to which they have been computed in the +! currently used base. This speeds up the trig, log, power, +! and exponential functions. + +! NDIGPI is the number of digits available in the currently +! stored value of pi (MPISAV). + + INTEGER, SAVE :: NDIGPI = 0 + +! MBSPI is the value of MBASE for the currently stored +! value of pi. + + REAL (KIND(1.0D0)), SAVE :: MBSPI = 0.0D0 +! Integer initialization +! INTEGER, SAVE :: MBSPI = 0 + +! NDIGE is the number of digits available in the currently +! stored value of e (MESAV). + + INTEGER, SAVE :: NDIGE = 0 + +! MBSE is the value of MBASE for the currently stored +! value of e. + + REAL (KIND(1.0D0)), SAVE :: MBSE = 0.0D0 +! Integer initialization +! INTEGER, SAVE :: MBSE = 0 + +! NDIGLB is the number of digits available in the currently +! stored value of LN(MBASE) (MLBSAV). + + INTEGER, SAVE :: NDIGLB = 0 + +! MBSLB is the value of MBASE for the currently stored +! value of LN(MBASE). + + REAL (KIND(1.0D0)), SAVE :: MBSLB = 0.0D0 +! Integer initialization +! INTEGER, SAVE :: MBSLB = 0 + +! NDIGLI is the number of digits available in the currently +! stored values of the four logarithms used by FMLNI +! MLN1 - MLN4. + + INTEGER, SAVE :: NDIGLI = 0 + +! MBSLI is the value of MBASE for the currently stored +! values of MLN1 - MLN4. + + REAL (KIND(1.0D0)), SAVE :: MBSLI = 0.0D0 +! Integer initialization +! INTEGER, SAVE :: MBSLI = 0 + +! MXEXP is the current maximum exponent. +! MXEXP2 is the internal maximum exponent. This is used to +! define the overflow and underflow thresholds. +! +! These values are chosen so that FM routines can raise the +! overflow/underflow limit temporarily while computing +! intermediate results, and so that EXP(INTMAX) is greater +! than MXBASE**(MXEXP2+1). +! +! The overflow threshold is MBASE**(MXEXP+1), and the +! underflow threshold is MBASE**(-MXEXP-1). +! This means the valid exponents in the first word of an FM +! number can range from -MXEXP to MXEXP+1 (inclusive). + + REAL (KIND(1.0D0)), SAVE :: MXEXP = 58455923.0D0 +! Integer initialization +! INTEGER, SAVE :: MXEXP = 99940964 + + REAL (KIND(1.0D0)), SAVE :: MXEXP2 = 117496405.0D0 +! Integer initialization +! INTEGER, SAVE :: MXEXP2 = 200881337 + +! KACCSW is a switch used to enable cancellation error +! monitoring. Routines where cancellation is +! not a problem run faster by skipping the +! cancellation monitor calculations. +! KACCSW = 0 means no error monitoring, +! = 1 means error monitoring is done. + + INTEGER, SAVE :: KACCSW = 0 + +! MEXPUN is the exponent used as a special symbol for +! underflowed results. + + REAL (KIND(1.0D0)), SAVE :: MEXPUN = -118671369.0D0 +! Integer initialization +! INTEGER, SAVE :: MEXPUN = -202890150 + +! MEXPOV is the exponent used as a special symbol for +! overflowed results. + + REAL (KIND(1.0D0)), SAVE :: MEXPOV = 118671369.0D0 +! Integer initialization +! INTEGER, SAVE :: MEXPOV = 202890150 + +! MUNKNO is the exponent used as a special symbol for +! unknown FM results (1/0, SQRT(-3.0), ...). + + REAL (KIND(1.0D0)), SAVE :: MUNKNO = 119858082.0D0 +! Integer initialization +! INTEGER, SAVE :: MUNKNO = 204919051 + +! RUNKNO is returned from FM to real or double conversion +! routines when no valid result can be expressed in +! real or double precision. On systems that provide +! a value for undefined results (e.g., Not A Number) +! setting RUNKNO to that value is reasonable. On +! other systems set it to a value that is likely to +! make any subsequent results obviously wrong that +! use it. In either case a KFLAG = -4 condition is +! also returned. + + REAL, SAVE :: RUNKNO = -1.01*(3.40E+38/3.0) + +! IUNKNO is returned from FM to integer conversion routines +! when no valid result can be expressed as a one word +! integer. KFLAG = -4 is also set. + + INTEGER, SAVE :: IUNKNO = -117496405 + +! JFORM1 indicates the format used by FMOUT. + + INTEGER, SAVE :: JFORM1 = 1 + +! JFORM2 indicates the number of digits used in FMOUT. + + INTEGER, SAVE :: JFORM2 = 50 + +! KRAD = 1 indicates that trig functions use radians, +! = 0 means use degrees. + + INTEGER, SAVE :: KRAD = 1 + +! KWARN = 0 indicates that no warning message is printed +! and execution continues when UNKNOWN or another +! exception is produced. +! = 1 means print a warning message and continue. +! = 2 means print a warning message and stop. + + INTEGER, SAVE :: KWARN = 1 + +! KROUND = 1 causes all results to be rounded to the +! nearest FM number, or to the value with +! an even last digit if the result is halfway +! between two FM numbers. +! = 0 causes all results to be rounded toward zero +! (chopped). +! = -1 causes all results to be rounded toward minus +! infinity. +! = 2 causes all results to be rounded toward plus +! infinity. +! Regardless of KROUND, when an FM function is called +! all intermediate operations are rounded to nearest. +! Only the final result returned to the user is rounded +! according to KROUND. + + INTEGER, SAVE :: KROUND = 1 + +! KRPERF = 1 causes more guard digits to be used, to get +! perfect rounding in the mode set by KROUND. +! This slows execution speed. +! = 0 causes a smaller number of guard digits used, +! to give nearly perfect rounding. This number +! is chosen so that the last intermediate result +! should have error less than 0.001 unit in the +! last place of the final rounded result. + + INTEGER, SAVE :: KRPERF = 0 + +! KSWIDE defines the maximum screen width to be used for +! all unit KW output. + + INTEGER, SAVE :: KSWIDE = 80 + +! KESWCH = 1 causes input to FMINP with no digits before +! the exponent letter to be treated as if there +! were a leading '1'. This is sometimes better +! for interactive input: 'E7' converts to +! 10.0**7. +! = 0 causes a leading zero to be assumed. This +! gives compatibility with Fortran: 'E7' +! converts to 0.0. + + INTEGER, SAVE :: KESWCH = 1 + +! CMCHAR defines the exponent letter to be used for +! FM variable output from FMOUT, as in 1.2345M+678. +! Change it to 'E' for output to be read by a +! non-FM program. + + CHARACTER, SAVE :: CMCHAR = 'M' + +! KSUB is an internal flag set during subtraction so that +! the addition routine will negate its second argument. + + INTEGER, SAVE :: KSUB = 0 + +! JRSIGN is an internal flag set during arithmetic operations +! so that the rounding routine will know the sign of the +! final result. + + INTEGER, SAVE :: JRSIGN = 0 + +! KDEBUG = 0 Error checking is not done for valid input +! arguments and parameters like NDIG and MBASE +! upon entry to each routine. +! = 1 Error checking is done. + + INTEGER, SAVE :: KDEBUG = 0 + +! LHASH is a flag variable used to indicate when to initialize +! two hash tables that are used for character look-up +! during input conversion. LHASH = 1 means that the tables +! have been built. +! LHASH1 and LHASH2 are the array dimensions of the tables. +! KHASHT and KHASHV are the two tables. + + INTEGER, SAVE :: LHASH = 0 + INTEGER, PARAMETER :: LHASH1 = 0 + INTEGER, PARAMETER :: LHASH2 = 256 + INTEGER, SAVE :: KHASHT(LHASH1:LHASH2),KHASHV(LHASH1:LHASH2) + +! DPEPS is the approximate machine precision. + + DOUBLE PRECISION, SAVE :: DPEPS = 2.220446049250313D-16 + +! Saved constants that depend on MBASE. + + REAL (KIND(1.0D0)), SAVE :: MBLOGS = 1.0D7 +! Integer initialization +! INTEGER, SAVE :: MBLOGS = 0 +! (Setting MBLOGS to zero here will cause the other variables that +! depend on MBASE to automatically be defined when the first FM +! operation is done.) + + REAL, SAVE :: ALOGMB = 1.611810E+1 + REAL, SAVE :: ALOGM2 = 2.325350E+1 + REAL, SAVE :: ALOGMX = 3.673680E+1 + REAL, SAVE :: ALOGMT = 7.0E0 + + INTEGER, SAVE :: NGRD21 = 1 + INTEGER, SAVE :: NGRD52 = 2 + INTEGER, SAVE :: NGRD22 = 2 + REAL (KIND(1.0D0)), SAVE :: MEXPAB = 2.3499281D+7 +! Integer initialization +! INTEGER, SAVE :: MEXPAB = 23499281 + + DOUBLE PRECISION, SAVE :: DLOGMB = 1.611809565095832D+1 + DOUBLE PRECISION, SAVE :: DLOGTN = 2.302585092994046D+0 + DOUBLE PRECISION, SAVE :: DLOGTW = 6.931471805599453D-1 + DOUBLE PRECISION, SAVE :: DPPI = 3.141592653589793D+0 + DOUBLE PRECISION, SAVE :: DLOGTP = 1.837877066409345D+0 + DOUBLE PRECISION, SAVE :: DLOGPI = 1.144729885849400D+0 + DOUBLE PRECISION, SAVE :: DLOGEB = 2.236222824932432D+0 + + REAL (KIND(1.0D0)), SAVE :: MBASEL = 0.0D0 +! Integer initialization +! INTEGER, SAVE :: MBASEL = 0 + REAL (KIND(1.0D0)), SAVE :: MBASEN = 0.0D0 +! Integer initialization +! INTEGER, SAVE :: MBASEN = 0 + + INTEGER, SAVE :: NDIGL = 0 + INTEGER, SAVE :: NDIGN = 0 + INTEGER, SAVE :: NGUARL = 0 + INTEGER, SAVE :: N21 + INTEGER, SAVE :: NGRDN + +! These variables are used by FM_RANDOM_NUMBER. +! MBRAND is the base used for the random number arithmetic. +! It needs to remain the same even if the user changes MBASE. + + REAL (KIND(1.0D0)), SAVE :: MBRAND = 1.0D7 +! Integer initialization +! INTEGER, SAVE :: MBRAND = 10000 + + REAL (KIND(1.0D0)), SAVE, DIMENSION(-1:LUNPCK) :: MRNX,MRNA,MRNM,MRNC + INTEGER, SAVE :: START_RANDOM_SEQUENCE = -1 + +! Work areas for temporary FM calculations. + + REAL (KIND(1.0D0)), SAVE, DIMENSION(1:LMWA) :: MWA,MWD,MWE + REAL (KIND(1.0D0)), SAVE, DIMENSION(-1:LUNPCK) :: & + MPA,MPB,MPC,MPD,MPMA,MPMB, & + MLV2,MLV3,MLV4,MLV5, & + M01,M02,M03,M04,M05,M06,M07,M08,M09,M10, & + M11,M12,M13,M14,M15,M16,M17,M18,M19,M20, & + M21,M22,M23,M24,M25,M26,M27,M28,M29,M30, & + M31,M32,M33,M34,M35,M36,M37,M38,M39,M40, & + M41,M42,M43,M44,M45 + REAL (KIND(1.0D0)), SAVE :: MJSUMS(-1:LJSUMS) + INTEGER, SAVE :: NDIGMX_BASE = 0 + CHARACTER, SAVE :: CMBUFF(LMBUFF) + +! Saved FM constants. + + REAL (KIND(1.0D0)), SAVE, DIMENSION(-1:LUNPCK) :: MPISAV,MESAV, & + MLBSAV,MLN1,MLN2,MLN3,MLN4 + +! Set JFORMZ to ' 1.23 + 4.56 i ' format. + + INTEGER, SAVE :: JFORMZ = 1 + +! Set JPRNTZ to print real and imaginary parts on one +! line whenever possible. + + INTEGER, SAVE :: JPRNTZ = 1 + +! These arrays are work areas for temporary ZM calculations. + + INTEGER, PARAMETER :: LPACKZ = 2*LPACK+2 + INTEGER, PARAMETER :: LUNPKZ = 2*LUNPCK+2 + INTEGER, PARAMETER :: KPTIMP = LPACK+1 + INTEGER, PARAMETER :: KPTIMU = LUNPCK+1 + REAL (KIND(1.0D0)), SAVE, DIMENSION(-1:LUNPKZ) :: MZ01,MZ02, & + MZ03,MZ04,MZ05,MZ06,MZ07,MZ08,MPX,MPY,MPZ + INTEGER, PARAMETER :: LMBUFZ = 2*LMBUFF+10 + CHARACTER, SAVE, DIMENSION(LMBUFZ) :: CMBUFZ + +! MBERN is the array used to save Bernoulli numbers so they +! do not have to be re-computed on subsequent calls. +! MBSBRN is the value of MBASE for the currently saved +! Bernoulli numbers. + + REAL (KIND(1.0D0)), SAVE :: MBSBRN = 0.0D0 +! Integer initialization +! INTEGER, SAVE :: MBSBRN = 0 + +! NWDBRN is the total number of words used for the saved +! Bernoulli numbers. + + INTEGER, SAVE :: NWDBRN = 0 + +! NUMBRN is the number of the largest Bernoulli number +! saved using base MBSBRN. + + INTEGER, SAVE :: NUMBRN = 0 + +! LMBERN is the size of the array MBERN for saving Bernoulli numbers. + + INTEGER, PARAMETER :: LMBERN = 250000 + REAL (KIND(1.0D0)), SAVE, DIMENSION(-1:LMBERN) :: MBERN + +! B(2N) starts in MBERN(NPTBRN(N)) for 2N >= 28. +! NPTBRN(N) is -1 if B(2N) has not been computed +! previously. + + INTEGER, SAVE :: NPTBRN(LMBERN/10) = (/ (-1 , I = 1, LMBERN/10) /) + +! M_EULER is the saved value of Euler's constant. +! M_GAMMA_MA is the last input value to FMGAM, and +! M_GAMMA_MB is the corresponding output value. +! M_LN_2PI holds the saved value of LN(2*pi). + + REAL (KIND(1.0D0)), SAVE, DIMENSION(-1:LUNPCK) :: & + M_EULER,M_GAMMA_MA,M_GAMMA_MB,M_LN_2PI + +! MBSGAM is the value of MBASE used in the currently stored +! value of M_GAMMA_MA and M_GAMMA_MB. +! NDGGAM is the maximum NDIG used in the currently stored +! value of M_GAMMA_MA and M_GAMMA_MB. + + REAL (KIND(1.0D0)), SAVE :: MBSGAM = 0.0D0 +! Integer initialization +! INTEGER, SAVE :: MBSGAM = 0 + + INTEGER, SAVE :: NDGGAM = 0 + +! MBS2PI is the value of MBASE used in the currently stored +! value of LN(2*pi). +! NDG2PI is the maximum NDIG used in the currently stored +! value of LN(2*pi). + + REAL (KIND(1.0D0)), SAVE :: MBS2PI = 0.0D0 +! Integer initialization +! INTEGER, SAVE :: MBS2PI = 0 + + INTEGER, SAVE :: NDG2PI = 0 + +! MBSEUL is the value of MBASE used in the currently stored +! value of M_EULER. +! NDGEUL is the maximum NDIG used in the currently stored +! value of M_EULER. + + REAL (KIND(1.0D0)), SAVE :: MBSEUL = 0.0D0 +! Integer initialization +! INTEGER, SAVE :: MBSEUL = 0 + + INTEGER, SAVE :: NDGEUL = 0 + +! MRETRY is used to detect convergence in some cases where +! cancellation error forces a retry. + + REAL (KIND(1.0D0)), SAVE, DIMENSION(-1:LUNPCK) :: MRETRY + + END MODULE diff --git a/src/fmlib/FMZM90.F90 b/src/fmlib/FMZM90.F90 new file mode 100644 index 0000000000000000000000000000000000000000..5c309b48576bb60b4592dfd29049a14c314a5b6b --- /dev/null +++ b/src/fmlib/FMZM90.F90 @@ -0,0 +1,7396 @@ + MODULE FMZM_1 + +! FMZM 1.2 David M. Smith + +! This module extends the definition of Fortran-90 arithmetic and function +! operations so they also apply to multiple precision numbers, using version +! 1.2 of FM. +! There are three multiple precision data types: +! FM (multiple precision real) +! IM (multiple precision integer) +! ZM (multiple precision complex) + +! Some of the interface routines assume that the precision chosen in the +! calling program (using FMSET) represents more significant digits than does +! the machine's double precision. + +! Most of the functions defined in this module are multiple precision versions +! of standard Fortran-90 functions. In addition, there are functions for +! direct conversion, formatting, and some mathematical special functions. + +! TO_FM is a function for converting other types of numbers to type FM. Note +! that TO_FM(3.12) converts the REAL constant to FM, but it is accurate only +! to single precision. TO_FM(3.12D0) agrees with 3.12 to double precision +! accuracy, and TO_FM('3.12') or TO_FM(312)/TO_FM(100) agrees to full FM +! accuracy. + +! TO_IM converts to type IM, and TO_ZM converts to type ZM. + +! Functions are also supplied for converting the three multiple precision types +! to the other numeric data types: +! TO_INT converts to machine precision integer +! TO_SP converts to single precision +! TO_DP converts to double precision +! TO_SPZ converts to single precision complex +! TO_DPZ converts to double precision complex + +! WARNING: When multiple precision type declarations are inserted in an +! existing program, take care in converting functions like DBLE(X), +! where X has been declared as a multiple precision type. If X +! was single precision in the original program, then replacing +! the DBLE(X) by TO_DP(X) in the new version could lose accuracy. +! For this reason, the Fortran type-conversion functions defined +! in this module assume that results should be multiple precision +! whenever inputs are. Examples: +! DBLE(TO_FM('1.23E+123456')) is type FM +! REAL(TO_FM('1.23E+123456')) is type FM +! REAL(TO_ZM('3.12+4.56i')) is type FM = TO_FM('3.12') +! INT(TO_FM('1.23')) is type IM = TO_IM(1) +! INT(TO_IM('1E+23')) is type IM +! CMPLX(TO_FM('1.23'),TO_FM('4.56')) is type ZM + +! Programs using this module may sometimes need to call FM, IM, or ZM routines +! directly. This is normally the case when routines are needed that are not +! Fortran-90 intrinsics, such as the formatting subroutine FMFORM. In a +! program using this module, suppose MAFM has been declared with +! TYPE ( FM ) MAFM. To use the routine FMFORM, which expects the second +! argument to be an array and not a derived type, the call would have to be +! CALL FMFORM('F65.60',MAFM%MFM,ST1) so that the array contained in MAFM is +! passed. + +! As an alternative so the user can refer directly to the FM-, IM-, and ZM-type +! variables and avoid the cumbersome "%MFM" suffixes, the FM package provides a +! collection of interface routines to supply any needed argument conversions. +! For each FM, IM, and ZM routine that is designed to be called by the user, +! there is also a version that assumes any multiple-precision arguments are +! derived types instead of arrays. Each interface routine has the same name as +! the original with an underscore after the first two letters of the routine +! name. To convert the number to a character string with F65.60 format, use +! CALL FM_FORM('F65.60',MAFM,ST1) if MAFM is of TYPE ( FM ), or use +! CALL FMFORM('F65.60',MA,ST1) if MA is declared as an array. All the routines +! shown below may be used this way. + +! For each of the operations =, == , /= , < , <= , > , >= , +, -, *, /, +! and **, the interface module defines all mixed mode variations involving one +! of the three multiple precision derived types and another argument having one +! of the types: { integer, real, double, complex, complex double, FM, IM, ZM }. +! So mixed mode expressions such as +! MAFM = 12 +! MAFM = MAFM + 1 +! IF (ABS(MAFM) > 1.0D-23) THEN +! are handled correctly. + +! Not all the named functions are defined for all three multiple precision +! derived types, so the list below shows which can be used. The labels "real", +! "integer", and "complex" refer to types FM, IM, and ZM respectively, "string" +! means the function accepts character strings (e.g., TO_FM('3.45')), and +! "other" means the function can accept any of the machine precision data types +! integer, real, double, complex, or complex double. For functions that accept +! two or more arguments, like ATAN2 or MAX, all the arguments must be of the +! same type. + + +! AVAILABLE OPERATIONS: + +! = +! + +! - +! * +! / +! ** +! == +! /= +! < +! <= +! > +! >= +! ABS real integer complex +! ACOS real complex +! AIMAG complex +! AINT real complex +! ANINT real complex +! ASIN real complex +! ATAN real complex +! ATAN2 real +! BTEST integer +! CEILING real complex +! CMPLX real integer +! CONJ complex +! COS real complex +! COSH real complex +! DBLE real integer complex +! DIGITS real integer complex +! DIM real integer +! DINT real complex +! DOTPRODUCT real integer complex +! EPSILON real +! EXP real complex +! EXPONENT real +! FLOOR real integer complex +! FRACTION real complex +! HUGE real integer complex +! INT real integer complex +! LOG real complex +! LOG10 real complex +! MATMUL real integer complex +! MAX real integer +! MAXEXPONENT real +! MIN real integer +! MINEXPONENT real +! MOD real integer +! MODULO real integer +! NEAREST real +! NINT real integer complex +! PRECISION real complex +! RADIX real integer complex +! RANGE real integer complex +! REAL real integer complex +! RRSPACING real +! SCALE real complex +! SETEXPONENT real +! SIGN real integer +! SIN real complex +! SINH real complex +! SPACING real +! SQRT real complex +! TAN real complex +! TANH real complex +! TINY real integer complex +! TO_FM real integer complex string other +! TO_IM real integer complex string other +! TO_ZM real integer complex string other +! TO_INT real integer complex +! TO_SP real integer complex +! TO_DP real integer complex +! TO_SPZ real integer complex +! TO_DPZ real integer complex + +! Some other functions are defined that do not correspond to machine precision +! intrinsic functions. These include formatting functions, integer modular +! functions and GCD, and the Gamma function and its related functions. +! N below is a machine precision integer, J1, J2, J3 are TYPE (IM), FMT, FMTR, +! FMTI are character strings, A,B,X are TYPE (FM), and Z is TYPE (ZM). +! The three formatting functions return a character string containing the +! formatted number, the three TYPE (IM) functions return a TYPE (IM) result, +! and the 12 special functions return TYPE (FM) results. + +! Formatting functions: + +! FM_FORMAT(FMT,A) Put A into FMT (real) format +! IM_FORMAT(FMT,J1) Put J1 into FMT (integer) format +! ZM_FORMAT(FMTR,FMTI,Z) Put Z into (complex) format, FMTR for the real +! part and FMTI for the imaginary part + +! Examples: +! ST = FM_FORMAT('F65.60',A) +! WRITE (*,*) ' A = ',TRIM(ST) +! ST = FM_FORMAT('E75.60',B) +! WRITE (*,*) ' B = ',ST(1:75) +! ST = IM_FORMAT('I50',J1) +! WRITE (*,*) ' J1 = ',ST(1:50) +! ST = ZM_FORMAT('F35.30','F30.25',Z) +! WRITE (*,*) ' Z = ',ST(1:70) + +! These functions are used for one-line output. The returned character +! strings are of length 200. Avoid using the formatting function in the +! write list, as in +! WRITE (*,*) ' J1 = ',IM_FORMAT('I50',J1)(1:50) +! since the formatting functions may themselves execute an internal WRITE +! and that would cause a recursive write reference. + +! For higher precision numbers, the output can be broken onto multiple +! lines automatically by calling subroutines FM_PRNT, IM_PRNT, ZM_PRNT, +! or the line breaks can be done by hand after calling one of the +! subroutines FM_FORM, IM_FORM, ZM_FORM. + +! For ZM_FORMAT the length of the output is 5 more than the sum of the +! two field widths. + +! Integer functions: + +! GCD(J1,J2) Greatest Common Divisor of J1 and J2. +! MULTIPLY_MOD(J1,J2,J3) J1 * J2 mod J3 +! POWER_MOD(J1,J2,J3) J1 ** J2 mod J3 + +! Special functions: + +! BERNOULLI(N) Nth Bernoulli number +! BETA(A,B) Integral (0 to 1) t**(A-1) * (1-t)**(B-1) dt +! BINOMIAL(A,B) Binomial Coefficient A! / ( B! (A-B)! ) +! FACTORIAL(A) A! +! GAMMA(A) Integral (0 to infinity) t**(A-1) * exp(-t) dt +! INCOMPLETE_BETA(X,A,B) Integral (0 to X) t**(A-1) * (1-t)**(B-1) dt +! INCOMPLETE_GAMMA1(A,X) Integral (0 to X) t**(A-1) * exp(-t) dt +! INCOMPLETE_GAMMA2(A,X) Integral (X to infinity) t**(A-1) * exp(-t) dt +! LOG_GAMMA(A) Ln( GAMMA(A) ) +! POLYGAMMA(N,A) Nth derivative of Psi(x), evaluated at A +! POCHHAMMER(A,N) A*(A+1)*(A+2)*...*(A+N-1) +! PSI(A) Derivative of Ln(Gamma(x)), evaluated at A + + +! To keep the FM variables hidden from a program that uses this +! module, these parameters are set to the same values as the +! corresponding ones in the FM_VARIABLES module. + + USE FMVALS, ONLY : NDIGMX_2 => NDIGMX + INTEGER, PARAMETER, PRIVATE :: LUNPCK_2 = (11*NDIGMX_2)/5 + 30 + INTEGER, PARAMETER, PRIVATE :: LUNPKZ_2 = 2*LUNPCK_2+2 + + TYPE FM + REAL (KIND(1.0D0)) :: MFM(-1:LUNPCK_2) + END TYPE + + TYPE IM + REAL (KIND(1.0D0)) :: MIM(-1:LUNPCK_2) + END TYPE + + TYPE ZM + REAL (KIND(1.0D0)) :: MZM(-1:LUNPKZ_2) + END TYPE + + REAL (KIND(1.0D0)), SAVE, DIMENSION(-1:LUNPCK_2) :: MTFM,MUFM,MVFM + REAL (KIND(1.0D0)), SAVE, DIMENSION(-1:LUNPCK_2) :: MTIM,MUIM,MVIM + REAL (KIND(1.0D0)), SAVE, DIMENSION(-1:LUNPKZ_2) :: MTZM,MUZM,MVZM + + END MODULE FMZM_1 + + MODULE FMZM_2 + USE FMZM_1 + +! These abbreviations are used for operations +! on the various data types. + +! I Integer +! R Real +! D Double Precision +! Z Complex +! C Complex Double Precision +! FM Multiple precision real +! IM Multiple precision integer +! ZM Multiple precision complex + +! For example, the "=" procedure FMEQ_FMD is for statements like +! X = A, where X is type FM and A is type Double Precision. + + INTERFACE ASSIGNMENT (=) + MODULE PROCEDURE FMEQ_IFM + MODULE PROCEDURE FMEQ_IIM + MODULE PROCEDURE FMEQ_IZM + MODULE PROCEDURE FMEQ_RFM + MODULE PROCEDURE FMEQ_RIM + MODULE PROCEDURE FMEQ_RZM + MODULE PROCEDURE FMEQ_DFM + MODULE PROCEDURE FMEQ_DIM + MODULE PROCEDURE FMEQ_DZM + MODULE PROCEDURE FMEQ_ZFM + MODULE PROCEDURE FMEQ_ZIM + MODULE PROCEDURE FMEQ_ZZM + MODULE PROCEDURE FMEQ_CFM + MODULE PROCEDURE FMEQ_CIM + MODULE PROCEDURE FMEQ_CZM + MODULE PROCEDURE FMEQ_FMI + MODULE PROCEDURE FMEQ_FMR + MODULE PROCEDURE FMEQ_FMD + MODULE PROCEDURE FMEQ_FMZ + MODULE PROCEDURE FMEQ_FMC + MODULE PROCEDURE FMEQ_FMFM + MODULE PROCEDURE FMEQ_FMIM + MODULE PROCEDURE FMEQ_FMZM + MODULE PROCEDURE FMEQ_IMI + MODULE PROCEDURE FMEQ_IMR + MODULE PROCEDURE FMEQ_IMD + MODULE PROCEDURE FMEQ_IMZ + MODULE PROCEDURE FMEQ_IMC + MODULE PROCEDURE FMEQ_IMFM + MODULE PROCEDURE FMEQ_IMIM + MODULE PROCEDURE FMEQ_IMZM + MODULE PROCEDURE FMEQ_ZMI + MODULE PROCEDURE FMEQ_ZMR + MODULE PROCEDURE FMEQ_ZMD + MODULE PROCEDURE FMEQ_ZMZ + MODULE PROCEDURE FMEQ_ZMC + MODULE PROCEDURE FMEQ_ZMFM + MODULE PROCEDURE FMEQ_ZMIM + MODULE PROCEDURE FMEQ_ZMZM + END INTERFACE + + INTERFACE OPERATOR ( == ) + MODULE PROCEDURE FMLEQ_IFM + MODULE PROCEDURE FMLEQ_IIM + MODULE PROCEDURE FMLEQ_IZM + MODULE PROCEDURE FMLEQ_RFM + MODULE PROCEDURE FMLEQ_RIM + MODULE PROCEDURE FMLEQ_RZM + MODULE PROCEDURE FMLEQ_DFM + MODULE PROCEDURE FMLEQ_DIM + MODULE PROCEDURE FMLEQ_DZM + MODULE PROCEDURE FMLEQ_ZFM + MODULE PROCEDURE FMLEQ_ZIM + MODULE PROCEDURE FMLEQ_ZZM + MODULE PROCEDURE FMLEQ_CFM + MODULE PROCEDURE FMLEQ_CIM + MODULE PROCEDURE FMLEQ_CZM + MODULE PROCEDURE FMLEQ_FMI + MODULE PROCEDURE FMLEQ_FMR + MODULE PROCEDURE FMLEQ_FMD + MODULE PROCEDURE FMLEQ_FMZ + MODULE PROCEDURE FMLEQ_FMC + MODULE PROCEDURE FMLEQ_FMFM + MODULE PROCEDURE FMLEQ_FMIM + MODULE PROCEDURE FMLEQ_FMZM + MODULE PROCEDURE FMLEQ_IMI + MODULE PROCEDURE FMLEQ_IMR + MODULE PROCEDURE FMLEQ_IMD + MODULE PROCEDURE FMLEQ_IMZ + MODULE PROCEDURE FMLEQ_IMC + MODULE PROCEDURE FMLEQ_IMFM + MODULE PROCEDURE FMLEQ_IMIM + MODULE PROCEDURE FMLEQ_IMZM + MODULE PROCEDURE FMLEQ_ZMI + MODULE PROCEDURE FMLEQ_ZMR + MODULE PROCEDURE FMLEQ_ZMD + MODULE PROCEDURE FMLEQ_ZMZ + MODULE PROCEDURE FMLEQ_ZMC + MODULE PROCEDURE FMLEQ_ZMFM + MODULE PROCEDURE FMLEQ_ZMIM + MODULE PROCEDURE FMLEQ_ZMZM + END INTERFACE + + + CONTAINS + +! = + + SUBROUTINE FMEQ_IFM(IVAL,MA) + TYPE ( FM ) MA + INTEGER IVAL + INTENT (INOUT) :: IVAL + INTENT (IN) :: MA + CALL FMM2I(MA%MFM,IVAL) + END SUBROUTINE + + SUBROUTINE FMEQ_IIM(IVAL,MA) + TYPE ( IM ) MA + INTEGER IVAL + INTENT (INOUT) :: IVAL + INTENT (IN) :: MA + CALL IMM2I(MA%MIM,IVAL) + END SUBROUTINE + + SUBROUTINE FMEQ_IZM(IVAL,MA) + TYPE ( ZM ) MA + INTEGER IVAL + INTENT (INOUT) :: IVAL + INTENT (IN) :: MA + CALL ZMM2I(MA%MZM,IVAL) + END SUBROUTINE + + SUBROUTINE FMEQ_RFM(R,MA) + TYPE ( FM ) MA + REAL R + INTENT (INOUT) :: R + INTENT (IN) :: MA + CALL FMM2SP(MA%MFM,R) + END SUBROUTINE + + SUBROUTINE FMEQ_RIM(R,MA) + TYPE ( IM ) MA + REAL R + INTENT (INOUT) :: R + INTENT (IN) :: MA + CALL IMI2FM(MA%MIM,MTFM) + CALL FMM2SP(MTFM,R) + END SUBROUTINE + + SUBROUTINE FMEQ_RZM(R,MA) + TYPE ( ZM ) MA + REAL R + INTENT (INOUT) :: R + INTENT (IN) :: MA + CALL ZMREAL(MA%MZM,MTFM) + CALL FMM2SP(MTFM,R) + END SUBROUTINE + + SUBROUTINE FMEQ_DFM(D,MA) + TYPE ( FM ) MA + DOUBLE PRECISION D + INTENT (INOUT) :: D + INTENT (IN) :: MA + CALL FMM2DP(MA%MFM,D) + END SUBROUTINE + + SUBROUTINE FMEQ_DIM(D,MA) + TYPE ( IM ) MA + DOUBLE PRECISION D + INTENT (INOUT) :: D + INTENT (IN) :: MA + CALL IMM2DP(MA%MIM,D) + END SUBROUTINE + + SUBROUTINE FMEQ_DZM(D,MA) + TYPE ( ZM ) MA + DOUBLE PRECISION D + INTENT (INOUT) :: D + INTENT (IN) :: MA + CALL ZMREAL(MA%MZM,MTFM) + CALL FMM2DP(MTFM,D) + END SUBROUTINE + + SUBROUTINE FMEQ_ZFM(Z,MA) + TYPE ( FM ) MA + COMPLEX Z + REAL R + INTENT (INOUT) :: Z + INTENT (IN) :: MA + CALL FMM2SP(MA%MFM,R) + Z = CMPLX( R , 0.0 ) + END SUBROUTINE + + SUBROUTINE FMEQ_ZIM(Z,MA) + TYPE ( IM ) MA + COMPLEX Z + DOUBLE PRECISION D + INTENT (INOUT) :: Z + INTENT (IN) :: MA + CALL IMM2DP(MA%MIM,D) + Z = CMPLX( REAL(D) , 0.0 ) + END SUBROUTINE + + SUBROUTINE FMEQ_ZZM(Z,MA) + TYPE ( ZM ) MA + COMPLEX Z + INTENT (INOUT) :: Z + INTENT (IN) :: MA + CALL ZMM2Z(MA%MZM,Z) + END SUBROUTINE + + SUBROUTINE FMEQ_CFM(C,MA) + TYPE ( FM ) MA + COMPLEX (KIND(0.0D0)) :: C + DOUBLE PRECISION D + INTENT (INOUT) :: C + INTENT (IN) :: MA + CALL FMM2DP(MA%MFM,D) + C = CMPLX( D , 0.0D0 , KIND(0.0D0) ) + END SUBROUTINE + + SUBROUTINE FMEQ_CIM(C,MA) + TYPE ( IM ) MA + COMPLEX (KIND(0.0D0)) :: C + DOUBLE PRECISION D + INTENT (INOUT) :: C + INTENT (IN) :: MA + CALL IMM2DP(MA%MIM,D) + C = CMPLX( D , 0.0D0 , KIND(0.0D0) ) + END SUBROUTINE + + SUBROUTINE FMEQ_CZM(C,MA) + TYPE ( ZM ) MA + COMPLEX (KIND(0.0D0)) :: C + DOUBLE PRECISION D1,D2 + INTENT (INOUT) :: C + INTENT (IN) :: MA + CALL ZMREAL(MA%MZM,MTFM) + CALL FMM2DP(MTFM,D1) + CALL ZMIMAG(MA%MZM,MTFM) + CALL FMM2DP(MTFM,D2) + C = CMPLX( D1 , D2 , KIND(0.0D0) ) + END SUBROUTINE + + SUBROUTINE FMEQ_FMI(MA,IVAL) + TYPE ( FM ) MA + INTEGER IVAL + INTENT (INOUT) :: MA + INTENT (IN) :: IVAL + CALL FMI2M(IVAL,MA%MFM) + END SUBROUTINE + + SUBROUTINE FMEQ_FMR(MA,R) + TYPE ( FM ) MA + REAL R + INTENT (INOUT) :: MA + INTENT (IN) :: R + CALL FMSP2M(R,MA%MFM) + END SUBROUTINE + + SUBROUTINE FMEQ_FMD(MA,D) + TYPE ( FM ) MA + DOUBLE PRECISION D + INTENT (INOUT) :: MA + INTENT (IN) :: D + CALL FMDP2M(D,MA%MFM) + END SUBROUTINE + + SUBROUTINE FMEQ_FMZ(MA,Z) + TYPE ( FM ) MA + COMPLEX Z + REAL R + INTENT (INOUT) :: MA + INTENT (IN) :: Z + R = REAL(Z) + CALL FMSP2M(R,MA%MFM) + END SUBROUTINE + + SUBROUTINE FMEQ_FMC(MA,C) + TYPE ( FM ) MA + COMPLEX (KIND(0.0D0)) :: C + DOUBLE PRECISION D + INTENT (INOUT) :: MA + INTENT (IN) :: C + D = REAL(C,KIND(0.0D0)) + CALL FMDP2M(D,MA%MFM) + END SUBROUTINE + + SUBROUTINE FMEQ_FMFM(MA,MB) + TYPE ( FM ) MA,MB + INTENT (INOUT) :: MA + INTENT (IN) :: MB + CALL FMEQ(MB%MFM,MA%MFM) + END SUBROUTINE + + SUBROUTINE FMEQ_FMIM(MA,MB) + TYPE ( FM ) MA + TYPE ( IM ) MB + INTENT (INOUT) :: MA + INTENT (IN) :: MB + CALL IMI2FM(MB%MIM,MA%MFM) + END SUBROUTINE + + SUBROUTINE FMEQ_FMZM(MA,MB) + TYPE ( FM ) MA + TYPE ( ZM ) MB + INTENT (INOUT) :: MA + INTENT (IN) :: MB + CALL ZMREAL(MB%MZM,MA%MFM) + END SUBROUTINE + + SUBROUTINE FMEQ_IMI(MA,IVAL) + TYPE ( IM ) MA + INTEGER IVAL + INTENT (INOUT) :: MA + INTENT (IN) :: IVAL + CALL IMI2M(IVAL,MA%MIM) + END SUBROUTINE + + SUBROUTINE FMEQ_IMR(MA,R) + TYPE ( IM ) MA + INTEGER IVAL + REAL R + CHARACTER(25) :: ST + INTENT (INOUT) :: MA + INTENT (IN) :: R + IF (ABS(R) < HUGE(1)) THEN + IVAL = INT(R) + CALL IMI2M(IVAL,MA%MIM) + ELSE + WRITE (ST,'(E25.16)') R + CALL IMST2M(ST,MA%MIM) + ENDIF + END SUBROUTINE + + SUBROUTINE FMEQ_IMD(MA,D) + TYPE ( IM ) MA + INTEGER IVAL + DOUBLE PRECISION D + CHARACTER(25) :: ST + INTENT (INOUT) :: MA + INTENT (IN) :: D + IF (ABS(D) < HUGE(1)) THEN + IVAL = INT(D) + CALL IMI2M(IVAL,MA%MIM) + ELSE + WRITE (ST,'(E25.16)') D + CALL IMST2M(ST,MA%MIM) + ENDIF + END SUBROUTINE + + SUBROUTINE FMEQ_IMZ(MA,Z) + TYPE ( IM ) MA + COMPLEX Z + REAL R + CHARACTER(25) :: ST + INTENT (INOUT) :: MA + INTENT (IN) :: Z + R = REAL(Z) + IF (ABS(R) < HUGE(1)) THEN + IVAL = INT(R) + CALL IMI2M(IVAL,MA%MIM) + ELSE + WRITE (ST,'(E25.16)') R + CALL IMST2M(ST,MA%MIM) + ENDIF + END SUBROUTINE + + SUBROUTINE FMEQ_IMC(MA,C) + TYPE ( IM ) MA + COMPLEX (KIND(0.0D0)) :: C + DOUBLE PRECISION D + CHARACTER(25) :: ST + INTENT (INOUT) :: MA + INTENT (IN) :: C + D = REAL(C) + IF (ABS(D) < HUGE(1)) THEN + IVAL = INT(D) + CALL IMI2M(IVAL,MA%MIM) + ELSE + WRITE (ST,'(E25.16)') D + CALL IMST2M(ST,MA%MIM) + ENDIF + END SUBROUTINE + + SUBROUTINE FMEQ_IMFM(MA,MB) + TYPE ( IM ) MA + TYPE ( FM ) MB + INTENT (INOUT) :: MA + INTENT (IN) :: MB + CALL IMFM2I(MB%MFM,MA%MIM) + END SUBROUTINE + + SUBROUTINE FMEQ_IMIM(MA,MB) + TYPE ( IM ) MA,MB + INTENT (INOUT) :: MA + INTENT (IN) :: MB + CALL IMEQ(MB%MIM,MA%MIM) + END SUBROUTINE + + SUBROUTINE FMEQ_IMZM(MA,MB) + TYPE ( IM ) MA + TYPE ( ZM ) MB + INTENT (INOUT) :: MA + INTENT (IN) :: MB + CALL ZMREAL(MB%MZM,MTFM) + CALL IMFM2I(MTFM,MA%MIM) + END SUBROUTINE + + SUBROUTINE FMEQ_ZMI(MA,IVAL) + TYPE ( ZM ) MA + INTEGER IVAL + INTENT (INOUT) :: MA + INTENT (IN) :: IVAL + CALL ZMI2M(IVAL,MA%MZM) + END SUBROUTINE + + SUBROUTINE FMEQ_ZMR(MA,R) + TYPE ( ZM ) MA + REAL R + COMPLEX Z + INTENT (INOUT) :: MA + INTENT (IN) :: R + Z = CMPLX(R,0.0) + CALL ZMZ2M(Z,MA%MZM) + END SUBROUTINE + + SUBROUTINE FMEQ_ZMD(MA,D) + TYPE ( ZM ) MA + DOUBLE PRECISION D + INTENT (INOUT) :: MA + INTENT (IN) :: D + CALL FMDP2M(D,MTFM) + CALL FMDP2M(0.0D0,MUFM) + CALL ZMCMPX(MTFM,MUFM,MA%MZM) + END SUBROUTINE + + SUBROUTINE FMEQ_ZMZ(MA,Z) + TYPE ( ZM ) MA + COMPLEX Z + INTENT (INOUT) :: MA + INTENT (IN) :: Z + CALL ZMZ2M(Z,MA%MZM) + END SUBROUTINE + + SUBROUTINE FMEQ_ZMC(MA,C) + TYPE ( ZM ) MA + COMPLEX (KIND(0.0D0)) :: C + DOUBLE PRECISION D + INTENT (INOUT) :: MA + INTENT (IN) :: C + D = REAL(C,KIND(0.0D0)) + CALL FMDP2M(D,MTFM) + D = AIMAG(C) + CALL FMDP2M(D,MUFM) + CALL ZMCMPX(MTFM,MUFM,MA%MZM) + END SUBROUTINE + + SUBROUTINE FMEQ_ZMFM(MA,MB) + TYPE ( FM ) MB + TYPE ( ZM ) MA + INTENT (INOUT) :: MA + INTENT (IN) :: MB + CALL FMI2M(0,MTFM) + CALL ZMCMPX(MB%MFM,MTFM,MA%MZM) + END SUBROUTINE + + SUBROUTINE FMEQ_ZMIM(MA,MB) + TYPE ( IM ) MB + TYPE ( ZM ) MA + INTENT (INOUT) :: MA + INTENT (IN) :: MB + CALL IMI2FM(MB%MIM,MTFM) + CALL FMI2M(0,MUFM) + CALL ZMCMPX(MTFM,MUFM,MA%MZM) + END SUBROUTINE + + SUBROUTINE FMEQ_ZMZM(MA,MB) + TYPE ( ZM ) MA,MB + INTENT (INOUT) :: MA + INTENT (IN) :: MB + CALL ZMEQ(MB%MZM,MA%MZM) + END SUBROUTINE + +! == + + FUNCTION FMLEQ_IFM(IVAL,MA) + LOGICAL FMLEQ_IFM,FMCOMP + TYPE ( FM ) MA + INTEGER IVAL + INTENT (IN) :: IVAL,MA + CALL FMI2M(IVAL,MTFM) + FMLEQ_IFM = FMCOMP(MTFM,'EQ',MA%MFM) + END FUNCTION + + FUNCTION FMLEQ_IIM(IVAL,MA) + LOGICAL FMLEQ_IIM,IMCOMP + TYPE ( IM ) MA + INTEGER IVAL + INTENT (IN) :: IVAL,MA + CALL IMI2M(IVAL,MTIM) + FMLEQ_IIM = IMCOMP(MTIM,'EQ',MA%MIM) + END FUNCTION + + FUNCTION FMLEQ_IZM(IVAL,MA) + LOGICAL FMLEQ_IZM,FMCOMP,L1,L2 + TYPE ( ZM ) MA + INTEGER IVAL + INTENT (IN) :: IVAL,MA + CALL FMI2M(IVAL,MTFM) + CALL ZMREAL(MA%MZM,MUFM) + L1 = FMCOMP(MTFM,'EQ',MUFM) + CALL FMI2M(0,MTFM) + CALL ZMIMAG(MA%MZM,MUFM) + L2 = FMCOMP(MTFM,'EQ',MUFM) + FMLEQ_IZM = L1.AND.L2 + END FUNCTION + + FUNCTION FMLEQ_RFM(R,MA) + LOGICAL FMLEQ_RFM,FMCOMP + TYPE ( FM ) MA + REAL R + INTENT (IN) :: R,MA + CALL FMSP2M(R,MTFM) + FMLEQ_RFM = FMCOMP(MTFM,'EQ',MA%MFM) + END FUNCTION + + FUNCTION FMLEQ_RIM(R,MA) + USE FMVALS + LOGICAL FMLEQ_RIM,FMCOMP + TYPE ( IM ) MA + INTEGER KA,NDSAVE + REAL R + INTENT (IN) :: R,MA + NDSAVE = NDIG + KA = MA%MIM(1) + NDIG = MAX(KA+NGRD52,NDIG) + CALL FMSP2M(R,MTFM) + CALL IMI2FM(MA%MIM,MUFM) + FMLEQ_RIM = FMCOMP(MTFM,'EQ',MUFM) + NDIG = NDSAVE + END FUNCTION + + FUNCTION FMLEQ_RZM(R,MA) + LOGICAL FMLEQ_RZM,FMCOMP,L1,L2 + TYPE ( ZM ) MA + REAL R + INTENT (IN) :: R,MA + CALL FMSP2M(R,MTFM) + CALL ZMREAL(MA%MZM,MUFM) + L1 = FMCOMP(MTFM,'EQ',MUFM) + CALL FMI2M(0,MTFM) + CALL ZMIMAG(MA%MZM,MUFM) + L2 = FMCOMP(MTFM,'EQ',MUFM) + FMLEQ_RZM = L1.AND.L2 + END FUNCTION + + FUNCTION FMLEQ_DFM(D,MA) + LOGICAL FMLEQ_DFM,FMCOMP + TYPE ( FM ) MA + DOUBLE PRECISION D + INTENT (IN) :: D,MA + CALL FMDP2M(D,MTFM) + FMLEQ_DFM = FMCOMP(MTFM,'EQ',MA%MFM) + END FUNCTION + + FUNCTION FMLEQ_DIM(D,MA) + USE FMVALS + LOGICAL FMLEQ_DIM,FMCOMP + TYPE ( IM ) MA + DOUBLE PRECISION D + INTEGER KA,NDSAVE + INTENT (IN) :: D,MA + NDSAVE = NDIG + KA = MA%MIM(1) + NDIG = MAX(KA+NGRD52,NDIG) + CALL FMDP2M(D,MTFM) + CALL IMI2FM(MA%MIM,MUFM) + FMLEQ_DIM = FMCOMP(MTFM,'EQ',MUFM) + NDIG = NDSAVE + END FUNCTION + + FUNCTION FMLEQ_DZM(D,MA) + LOGICAL FMLEQ_DZM,FMCOMP,L1,L2 + TYPE ( ZM ) MA + DOUBLE PRECISION D + INTENT (IN) :: D,MA + CALL FMDP2M(D,MTFM) + CALL ZMREAL(MA%MZM,MUFM) + L1 = FMCOMP(MTFM,'EQ',MUFM) + CALL FMI2M(0,MTFM) + CALL ZMIMAG(MA%MZM,MUFM) + L2 = FMCOMP(MTFM,'EQ',MUFM) + FMLEQ_DZM = L1.AND.L2 + END FUNCTION + + FUNCTION FMLEQ_ZFM(Z,MA) + LOGICAL FMLEQ_ZFM,FMCOMP,L1,L2 + TYPE ( FM ) MA + COMPLEX Z + INTENT (IN) :: Z,MA + CALL FMSP2M(REAL(Z),MTFM) + L1 = FMCOMP(MTFM,'EQ',MA%MFM) + L2 = .TRUE. + IF (AIMAG(Z) /= 0.0) L2 = .FALSE. + FMLEQ_ZFM = L1.AND.L2 + END FUNCTION + + FUNCTION FMLEQ_ZIM(Z,MA) + USE FMVALS + LOGICAL FMLEQ_ZIM,FMCOMP,L1,L2 + TYPE ( IM ) MA + COMPLEX Z + INTEGER KA,NDSAVE + INTENT (IN) :: Z,MA + NDSAVE = NDIG + KA = MA%MIM(1) + NDIG = MAX(KA+NGRD52,NDIG) + CALL FMSP2M(REAL(Z),MTFM) + CALL IMI2FM(MA%MIM,MUFM) + L1 = FMCOMP(MTFM,'EQ',MUFM) + NDIG = NDSAVE + L2 = .TRUE. + IF (AIMAG(Z) /= 0.0) L2 = .FALSE. + FMLEQ_ZIM = L1.AND.L2 + END FUNCTION + + FUNCTION FMLEQ_ZZM(Z,MA) + LOGICAL FMLEQ_ZZM,FMCOMP,L1,L2 + TYPE ( ZM ) MA + COMPLEX Z + INTENT (IN) :: Z,MA + CALL ZMZ2M(Z,MTZM) + CALL ZMREAL(MTZM,MTFM) + CALL ZMREAL(MA%MZM,MUFM) + L1 = FMCOMP(MTFM,'EQ',MUFM) + CALL ZMIMAG(MTZM,MTFM) + CALL ZMIMAG(MA%MZM,MUFM) + L2 = FMCOMP(MTFM,'EQ',MUFM) + FMLEQ_ZZM = L1.AND.L2 + END FUNCTION + + FUNCTION FMLEQ_CFM(C,MA) + LOGICAL FMLEQ_CFM,FMCOMP,L1,L2 + TYPE ( FM ) MA + COMPLEX (KIND(0.0D0)) :: C + INTENT (IN) :: C,MA + CALL FMDP2M(REAL(C,KIND(0.0D0)),MTFM) + L1 = FMCOMP(MTFM,'EQ',MA%MFM) + L2 = .TRUE. + IF (AIMAG(C) /= 0.0) L2 = .FALSE. + FMLEQ_CFM = L1.AND.L2 + END FUNCTION + + FUNCTION FMLEQ_CIM(C,MA) + USE FMVALS + LOGICAL FMLEQ_CIM,FMCOMP,L1,L2 + TYPE ( IM ) MA + COMPLEX (KIND(0.0D0)) :: C + INTEGER KA,NDSAVE + INTENT (IN) :: C,MA + NDSAVE = NDIG + KA = MA%MIM(1) + NDIG = MAX(KA+NGRD52,NDIG) + CALL FMDP2M(REAL(C,KIND(0.0D0)),MTFM) + CALL IMI2FM(MA%MIM,MUFM) + L1 = FMCOMP(MTFM,'EQ',MUFM) + NDIG = NDSAVE + L2 = .TRUE. + IF (AIMAG(C) /= 0.0) L2 = .FALSE. + FMLEQ_CIM = L1.AND.L2 + END FUNCTION + + FUNCTION FMLEQ_CZM(C,MA) + LOGICAL FMLEQ_CZM,FMCOMP,L1,L2 + TYPE ( ZM ) MA + COMPLEX (KIND(0.0D0)) :: C + INTENT (IN) :: C,MA + CALL FMDP2M(REAL(C,KIND(0.0D0)),MTFM) + CALL ZMREAL(MA%MZM,MUFM) + L1 = FMCOMP(MTFM,'EQ',MUFM) + CALL FMDP2M(AIMAG(C),MTFM) + CALL ZMIMAG(MA%MZM,MUFM) + L2 = FMCOMP(MTFM,'EQ',MUFM) + FMLEQ_CZM = L1.AND.L2 + END FUNCTION + + FUNCTION FMLEQ_FMI(MA,IVAL) + LOGICAL FMLEQ_FMI,FMCOMP + TYPE ( FM ) MA + INTEGER IVAL + INTENT (IN) :: MA,IVAL + CALL FMI2M(IVAL,MTFM) + FMLEQ_FMI = FMCOMP(MA%MFM,'EQ',MTFM) + END FUNCTION + + FUNCTION FMLEQ_FMR(MA,R) + LOGICAL FMLEQ_FMR,FMCOMP + TYPE ( FM ) MA + REAL R + INTENT (IN) :: MA,R + CALL FMSP2M(R,MTFM) + FMLEQ_FMR = FMCOMP(MA%MFM,'EQ',MTFM) + END FUNCTION + + FUNCTION FMLEQ_FMD(MA,D) + LOGICAL FMLEQ_FMD,FMCOMP + TYPE ( FM ) MA + DOUBLE PRECISION D + INTENT (IN) :: MA,D + CALL FMDP2M(D,MTFM) + FMLEQ_FMD = FMCOMP(MA%MFM,'EQ',MTFM) + END FUNCTION + + FUNCTION FMLEQ_FMZ(MA,Z) + LOGICAL FMLEQ_FMZ,FMCOMP,L1,L2 + TYPE ( FM ) MA + COMPLEX Z + INTENT (IN) :: MA,Z + CALL FMSP2M(REAL(Z),MTFM) + L1 = FMCOMP(MA%MFM,'EQ',MTFM) + L2 = .TRUE. + IF (AIMAG(Z) /= 0.0) L2 = .FALSE. + FMLEQ_FMZ = L1.AND.L2 + END FUNCTION + + FUNCTION FMLEQ_FMC(MA,C) + LOGICAL FMLEQ_FMC,FMCOMP,L1,L2 + TYPE ( FM ) MA + COMPLEX (KIND(0.0D0)) :: C + INTENT (IN) :: MA,C + CALL FMDP2M(REAL(C,KIND(0.0D0)),MTFM) + L1 = FMCOMP(MA%MFM,'EQ',MTFM) + L2 = .TRUE. + IF (AIMAG(C) /= 0.0) L2 = .FALSE. + FMLEQ_FMC = L1.AND.L2 + END FUNCTION + + FUNCTION FMLEQ_FMFM(MA,MB) + LOGICAL FMLEQ_FMFM,FMCOMP + TYPE ( FM ) MA,MB + INTENT (IN) :: MA,MB + FMLEQ_FMFM = FMCOMP(MA%MFM,'EQ',MB%MFM) + END FUNCTION + + FUNCTION FMLEQ_FMIM(MA,MB) + LOGICAL FMLEQ_FMIM,FMCOMP + TYPE ( FM ) MA + TYPE ( IM ) MB + INTENT (IN) :: MA,MB + CALL FMINT(MA%MFM,MTFM) + IF (FMCOMP(MA%MFM,'EQ',MTFM)) THEN + CALL IMI2FM(MB%MIM,MTFM) + FMLEQ_FMIM = FMCOMP(MA%MFM,'EQ',MTFM) + ELSE + FMLEQ_FMIM = .FALSE. + ENDIF + END FUNCTION + + FUNCTION FMLEQ_FMZM(MA,MB) + USE FMVALS + LOGICAL FMLEQ_FMZM,FMCOMP,L1,L2 + TYPE ( FM ) MA + TYPE ( ZM ) MB + INTENT (IN) :: MA,MB + CALL ZMREAL(MB%MZM,MTFM) + L1 = FMCOMP(MA%MFM,'EQ',MTFM) + L2 = .TRUE. + IF (MB%MZM(KPTIMU+2) /= 0) L2 = .FALSE. + FMLEQ_FMZM = L1.AND.L2 + END FUNCTION + + FUNCTION FMLEQ_IMI(MA,IVAL) + LOGICAL FMLEQ_IMI,IMCOMP + TYPE ( IM ) MA + INTEGER IVAL + INTENT (IN) :: MA,IVAL + CALL IMI2M(IVAL,MTIM) + FMLEQ_IMI = IMCOMP(MA%MIM,'EQ',MTIM) + END FUNCTION + + FUNCTION FMLEQ_IMR(MA,R) + USE FMVALS + LOGICAL FMLEQ_IMR,FMCOMP + TYPE ( IM ) MA + INTEGER KA,NDSAVE + REAL R + INTENT (IN) :: MA,R + NDSAVE = NDIG + KA = MA%MIM(1) + NDIG = MAX(KA+NGRD52,NDIG) + CALL FMSP2M(R,MTFM) + CALL IMI2FM(MA%MIM,MUFM) + FMLEQ_IMR = FMCOMP(MUFM,'EQ',MTFM) + NDIG = NDSAVE + END FUNCTION + + FUNCTION FMLEQ_IMD(MA,D) + USE FMVALS + LOGICAL FMLEQ_IMD,FMCOMP + TYPE ( IM ) MA + DOUBLE PRECISION D + INTEGER KA,NDSAVE + INTENT (IN) :: MA,D + NDSAVE = NDIG + KA = MA%MIM(1) + NDIG = MAX(KA+NGRD52,NDIG) + CALL FMDP2M(D,MTFM) + CALL IMI2FM(MA%MIM,MUFM) + FMLEQ_IMD = FMCOMP(MUFM,'EQ',MTFM) + NDIG = NDSAVE + END FUNCTION + + FUNCTION FMLEQ_IMZ(MA,Z) + USE FMVALS + LOGICAL FMLEQ_IMZ,FMCOMP,L1,L2 + TYPE ( IM ) MA + COMPLEX Z + INTEGER KA,NDSAVE + INTENT (IN) :: MA,Z + NDSAVE = NDIG + KA = MA%MIM(1) + NDIG = MAX(KA+NGRD52,NDIG) + CALL FMSP2M(REAL(Z),MTFM) + CALL IMI2FM(MA%MIM,MUFM) + L1 = FMCOMP(MUFM,'EQ',MTFM) + NDIG = NDSAVE + L2 = .TRUE. + IF (AIMAG(Z) /= 0.0) L2 = .FALSE. + FMLEQ_IMZ = L1.AND.L2 + END FUNCTION + + FUNCTION FMLEQ_IMC(MA,C) + USE FMVALS + LOGICAL FMLEQ_IMC,FMCOMP,L1,L2 + TYPE ( IM ) MA + COMPLEX (KIND(0.0D0)) :: C + INTEGER KA,NDSAVE + INTENT (IN) :: MA,C + NDSAVE = NDIG + KA = MA%MIM(1) + NDIG = MAX(KA+NGRD52,NDIG) + CALL FMDP2M(REAL(C,KIND(0.0D0)),MTFM) + CALL IMI2FM(MA%MIM,MUFM) + L1 = FMCOMP(MUFM,'EQ',MTFM) + NDIG = NDSAVE + L2 = .TRUE. + IF (AIMAG(C) /= 0.0) L2 = .FALSE. + FMLEQ_IMC = L1.AND.L2 + END FUNCTION + + FUNCTION FMLEQ_IMFM(MA,MB) + LOGICAL FMLEQ_IMFM,FMCOMP + TYPE ( IM ) MA + TYPE ( FM ) MB + INTENT (IN) :: MA,MB + CALL FMINT(MB%MFM,MTFM) + IF (FMCOMP(MB%MFM,'EQ',MTFM)) THEN + CALL IMI2FM(MA%MIM,MTFM) + FMLEQ_IMFM = FMCOMP(MB%MFM,'EQ',MTFM) + ELSE + FMLEQ_IMFM = .FALSE. + ENDIF + END FUNCTION + + FUNCTION FMLEQ_IMIM(MA,MB) + LOGICAL FMLEQ_IMIM,IMCOMP + TYPE ( IM ) MA,MB + INTENT (IN) :: MA,MB + FMLEQ_IMIM = IMCOMP(MA%MIM,'EQ',MB%MIM) + END FUNCTION + + FUNCTION FMLEQ_IMZM(MA,MB) + USE FMVALS + LOGICAL FMLEQ_IMZM,FMCOMP + TYPE ( IM ) MA + TYPE ( ZM ) MB + INTENT (IN) :: MA,MB + CALL ZMREAL(MB%MZM,MTFM) + CALL FMINT(MTFM,MUFM) + IF (FMCOMP(MUFM,'EQ',MTFM).AND.MB%MZM(KPTIMU+2) == 0) THEN + CALL IMI2FM(MA%MIM,MUFM) + FMLEQ_IMZM = FMCOMP(MUFM,'EQ',MTFM) + ELSE + FMLEQ_IMZM = .FALSE. + ENDIF + END FUNCTION + + FUNCTION FMLEQ_ZMI(MA,IVAL) + USE FMVALS + LOGICAL FMLEQ_ZMI,FMCOMP + TYPE ( ZM ) MA + INTEGER IVAL + INTENT (IN) :: MA,IVAL + CALL ZMREAL(MA%MZM,MTFM) + CALL FMINT(MTFM,MUFM) + IF (FMCOMP(MUFM,'EQ',MTFM).AND.MA%MZM(KPTIMU+2) == 0) THEN + CALL FMI2M(IVAL,MUFM) + FMLEQ_ZMI = FMCOMP(MTFM,'EQ',MUFM) + ELSE + FMLEQ_ZMI = .FALSE. + ENDIF + END FUNCTION + + FUNCTION FMLEQ_ZMR(MA,R) + LOGICAL FMLEQ_ZMR,FMCOMP,L1,L2 + TYPE ( ZM ) MA + REAL R + INTENT (IN) :: MA,R + CALL FMSP2M(R,MTFM) + CALL ZMREAL(MA%MZM,MUFM) + L1 = FMCOMP(MTFM,'EQ',MUFM) + CALL FMI2M(0,MTFM) + CALL ZMIMAG(MA%MZM,MUFM) + L2 = FMCOMP(MTFM,'EQ',MUFM) + FMLEQ_ZMR = L1.AND.L2 + END FUNCTION + + FUNCTION FMLEQ_ZMD(MA,D) + LOGICAL FMLEQ_ZMD,FMCOMP,L1,L2 + TYPE ( ZM ) MA + DOUBLE PRECISION D + INTENT (IN) :: MA,D + CALL FMDP2M(D,MTFM) + CALL ZMREAL(MA%MZM,MUFM) + L1 = FMCOMP(MTFM,'EQ',MUFM) + CALL FMI2M(0,MTFM) + CALL ZMIMAG(MA%MZM,MUFM) + L2 = FMCOMP(MTFM,'EQ',MUFM) + FMLEQ_ZMD = L1.AND.L2 + END FUNCTION + + FUNCTION FMLEQ_ZMZ(MA,Z) + LOGICAL FMLEQ_ZMZ,FMCOMP,L1,L2 + TYPE ( ZM ) MA + COMPLEX Z + INTENT (IN) :: MA,Z + CALL ZMZ2M(Z,MTZM) + CALL ZMREAL(MTZM,MTFM) + CALL ZMREAL(MA%MZM,MUFM) + L1 = FMCOMP(MTFM,'EQ',MUFM) + CALL ZMIMAG(MTZM,MTFM) + CALL ZMIMAG(MA%MZM,MUFM) + L2 = FMCOMP(MTFM,'EQ',MUFM) + FMLEQ_ZMZ = L1.AND.L2 + END FUNCTION + + FUNCTION FMLEQ_ZMC(MA,C) + LOGICAL FMLEQ_ZMC,FMCOMP,L1,L2 + TYPE ( ZM ) MA + COMPLEX (KIND(0.0D0)) :: C + INTENT (IN) :: MA,C + CALL FMDP2M(REAL(C,KIND(0.0D0)),MTFM) + CALL ZMREAL(MA%MZM,MUFM) + L1 = FMCOMP(MTFM,'EQ',MUFM) + CALL FMDP2M(AIMAG(C),MTFM) + CALL ZMIMAG(MA%MZM,MUFM) + L2 = FMCOMP(MTFM,'EQ',MUFM) + FMLEQ_ZMC = L1.AND.L2 + END FUNCTION + + FUNCTION FMLEQ_ZMFM(MA,MB) + USE FMVALS + LOGICAL FMLEQ_ZMFM,FMCOMP,L1,L2 + TYPE ( FM ) MB + TYPE ( ZM ) MA + INTENT (IN) :: MA,MB + CALL ZMREAL(MA%MZM,MTFM) + L1 = FMCOMP(MB%MFM,'EQ',MTFM) + L2 = .TRUE. + IF (MA%MZM(KPTIMU+2) /= 0) L2 = .FALSE. + FMLEQ_ZMFM = L1.AND.L2 + END FUNCTION + + FUNCTION FMLEQ_ZMIM(MA,MB) + USE FMVALS + LOGICAL FMLEQ_ZMIM,FMCOMP + TYPE ( IM ) MB + TYPE ( ZM ) MA + INTENT (IN) :: MA,MB + CALL ZMREAL(MA%MZM,MTFM) + CALL FMINT(MTFM,MUFM) + IF (FMCOMP(MUFM,'EQ',MTFM).AND.MA%MZM(KPTIMU+2) == 0) THEN + CALL IMI2FM(MB%MIM,MUFM) + FMLEQ_ZMIM = FMCOMP(MUFM,'EQ',MTFM) + ELSE + FMLEQ_ZMIM = .FALSE. + ENDIF + END FUNCTION + + FUNCTION FMLEQ_ZMZM(MA,MB) + LOGICAL FMLEQ_ZMZM,FMCOMP,L1,L2 + TYPE ( ZM ) MA,MB + INTENT (IN) :: MA,MB + CALL ZMREAL(MA%MZM,MTFM) + CALL ZMREAL(MB%MZM,MUFM) + L1 = FMCOMP(MTFM,'EQ',MUFM) + CALL ZMIMAG(MA%MZM,MTFM) + CALL ZMIMAG(MB%MZM,MUFM) + L2 = FMCOMP(MTFM,'EQ',MUFM) + FMLEQ_ZMZM = L1.AND.L2 + END FUNCTION + + END MODULE FMZM_2 + + MODULE FMZM_3 + USE FMZM_1 + + INTERFACE OPERATOR ( /= ) + MODULE PROCEDURE FMLNE_IFM + MODULE PROCEDURE FMLNE_IIM + MODULE PROCEDURE FMLNE_IZM + MODULE PROCEDURE FMLNE_RFM + MODULE PROCEDURE FMLNE_RIM + MODULE PROCEDURE FMLNE_RZM + MODULE PROCEDURE FMLNE_DFM + MODULE PROCEDURE FMLNE_DIM + MODULE PROCEDURE FMLNE_DZM + MODULE PROCEDURE FMLNE_ZFM + MODULE PROCEDURE FMLNE_ZIM + MODULE PROCEDURE FMLNE_ZZM + MODULE PROCEDURE FMLNE_CFM + MODULE PROCEDURE FMLNE_CIM + MODULE PROCEDURE FMLNE_CZM + MODULE PROCEDURE FMLNE_FMI + MODULE PROCEDURE FMLNE_FMR + MODULE PROCEDURE FMLNE_FMD + MODULE PROCEDURE FMLNE_FMZ + MODULE PROCEDURE FMLNE_FMC + MODULE PROCEDURE FMLNE_FMFM + MODULE PROCEDURE FMLNE_FMIM + MODULE PROCEDURE FMLNE_FMZM + MODULE PROCEDURE FMLNE_IMI + MODULE PROCEDURE FMLNE_IMR + MODULE PROCEDURE FMLNE_IMD + MODULE PROCEDURE FMLNE_IMZ + MODULE PROCEDURE FMLNE_IMC + MODULE PROCEDURE FMLNE_IMFM + MODULE PROCEDURE FMLNE_IMIM + MODULE PROCEDURE FMLNE_IMZM + MODULE PROCEDURE FMLNE_ZMI + MODULE PROCEDURE FMLNE_ZMR + MODULE PROCEDURE FMLNE_ZMD + MODULE PROCEDURE FMLNE_ZMZ + MODULE PROCEDURE FMLNE_ZMC + MODULE PROCEDURE FMLNE_ZMFM + MODULE PROCEDURE FMLNE_ZMIM + MODULE PROCEDURE FMLNE_ZMZM + END INTERFACE + + INTERFACE OPERATOR ( > ) + MODULE PROCEDURE FMLGT_IFM + MODULE PROCEDURE FMLGT_IIM + MODULE PROCEDURE FMLGT_RFM + MODULE PROCEDURE FMLGT_RIM + MODULE PROCEDURE FMLGT_DFM + MODULE PROCEDURE FMLGT_DIM + MODULE PROCEDURE FMLGT_FMI + MODULE PROCEDURE FMLGT_FMR + MODULE PROCEDURE FMLGT_FMD + MODULE PROCEDURE FMLGT_FMFM + MODULE PROCEDURE FMLGT_FMIM + MODULE PROCEDURE FMLGT_IMI + MODULE PROCEDURE FMLGT_IMR + MODULE PROCEDURE FMLGT_IMD + MODULE PROCEDURE FMLGT_IMFM + MODULE PROCEDURE FMLGT_IMIM + END INTERFACE + + CONTAINS + +! /= + + FUNCTION FMLNE_IFM(IVAL,MA) + LOGICAL FMLNE_IFM,FMCOMP + TYPE ( FM ) MA + INTEGER IVAL + INTENT (IN) :: IVAL,MA + CALL FMI2M(IVAL,MTFM) + FMLNE_IFM = FMCOMP(MTFM,'NE',MA%MFM) + END FUNCTION + + FUNCTION FMLNE_IIM(IVAL,MA) + LOGICAL FMLNE_IIM,IMCOMP + TYPE ( IM ) MA + INTEGER IVAL + INTENT (IN) :: IVAL,MA + CALL IMI2M(IVAL,MTIM) + FMLNE_IIM = IMCOMP(MTIM,'NE',MA%MIM) + END FUNCTION + + FUNCTION FMLNE_IZM(IVAL,MA) + LOGICAL FMLNE_IZM,FMCOMP,L1,L2 + TYPE ( ZM ) MA + INTEGER IVAL + INTENT (IN) :: IVAL,MA + CALL FMI2M(IVAL,MTFM) + CALL ZMREAL(MA%MZM,MUFM) + L1 = FMCOMP(MTFM,'NE',MUFM) + CALL FMI2M(0,MTFM) + CALL ZMIMAG(MA%MZM,MUFM) + L2 = FMCOMP(MTFM,'NE',MUFM) + FMLNE_IZM = L1.OR.L2 + END FUNCTION + + FUNCTION FMLNE_RFM(R,MA) + LOGICAL FMLNE_RFM,FMCOMP + TYPE ( FM ) MA + REAL R + INTENT (IN) :: R,MA + CALL FMSP2M(R,MTFM) + FMLNE_RFM = FMCOMP(MTFM,'NE',MA%MFM) + END FUNCTION + + FUNCTION FMLNE_RIM(R,MA) + USE FMVALS + LOGICAL FMLNE_RIM,FMCOMP + TYPE ( IM ) MA + REAL R + INTEGER KA,NDSAVE + INTENT (IN) :: R,MA + NDSAVE = NDIG + KA = MA%MIM(1) + NDIG = MAX(KA+NGRD52,NDIG) + CALL FMSP2M(R,MTFM) + CALL IMI2FM(MA%MIM,MUFM) + FMLNE_RIM = FMCOMP(MTFM,'NE',MUFM) + NDIG = NDSAVE + END FUNCTION + + FUNCTION FMLNE_RZM(R,MA) + LOGICAL FMLNE_RZM,FMCOMP,L1,L2 + TYPE ( ZM ) MA + REAL R + INTENT (IN) :: R,MA + CALL FMSP2M(R,MTFM) + CALL ZMREAL(MA%MZM,MUFM) + L1 = FMCOMP(MTFM,'NE',MUFM) + CALL FMI2M(0,MTFM) + CALL ZMIMAG(MA%MZM,MUFM) + L2 = FMCOMP(MTFM,'NE',MUFM) + FMLNE_RZM = L1.OR.L2 + END FUNCTION + + FUNCTION FMLNE_DFM(D,MA) + LOGICAL FMLNE_DFM,FMCOMP + TYPE ( FM ) MA + DOUBLE PRECISION D + INTENT (IN) :: D,MA + CALL FMDP2M(D,MTFM) + FMLNE_DFM = FMCOMP(MTFM,'NE',MA%MFM) + END FUNCTION + + FUNCTION FMLNE_DIM(D,MA) + USE FMVALS + LOGICAL FMLNE_DIM,FMCOMP + TYPE ( IM ) MA + DOUBLE PRECISION D + INTEGER KA,NDSAVE + INTENT (IN) :: D,MA + NDSAVE = NDIG + KA = MA%MIM(1) + NDIG = MAX(KA+NGRD52,NDIG) + CALL FMDP2M(D,MTFM) + CALL IMI2FM(MA%MIM,MUFM) + FMLNE_DIM = FMCOMP(MTFM,'NE',MUFM) + NDIG = NDSAVE + END FUNCTION + + FUNCTION FMLNE_DZM(D,MA) + LOGICAL FMLNE_DZM,FMCOMP,L1,L2 + TYPE ( ZM ) MA + DOUBLE PRECISION D + INTENT (IN) :: D,MA + CALL FMDP2M(D,MTFM) + CALL ZMREAL(MA%MZM,MUFM) + L1 = FMCOMP(MTFM,'NE',MUFM) + CALL FMI2M(0,MTFM) + CALL ZMIMAG(MA%MZM,MUFM) + L2 = FMCOMP(MTFM,'NE',MUFM) + FMLNE_DZM = L1.OR.L2 + END FUNCTION + + FUNCTION FMLNE_ZFM(Z,MA) + LOGICAL FMLNE_ZFM,FMCOMP,L1,L2 + TYPE ( FM ) MA + COMPLEX Z + INTENT (IN) :: Z,MA + CALL FMSP2M(REAL(Z),MTFM) + L1 = FMCOMP(MTFM,'NE',MA%MFM) + L2 = .FALSE. + IF (AIMAG(Z) /= 0.0) L2 = .TRUE. + FMLNE_ZFM = L1.OR.L2 + END FUNCTION + + FUNCTION FMLNE_ZIM(Z,MA) + USE FMVALS + LOGICAL FMLNE_ZIM,FMCOMP,L1,L2 + TYPE ( IM ) MA + INTEGER KA,NDSAVE + COMPLEX Z + INTENT (IN) :: Z,MA + NDSAVE = NDIG + KA = MA%MIM(1) + NDIG = MAX(KA+NGRD52,NDIG) + CALL FMSP2M(REAL(Z),MTFM) + CALL IMI2FM(MA%MIM,MUFM) + L1 = FMCOMP(MTFM,'NE',MUFM) + NDIG = NDSAVE + L2 = .FALSE. + IF (AIMAG(Z) /= 0.0) L2 = .TRUE. + FMLNE_ZIM = L1.OR.L2 + END FUNCTION + + FUNCTION FMLNE_ZZM(Z,MA) + LOGICAL FMLNE_ZZM,FMCOMP,L1,L2 + TYPE ( ZM ) MA + COMPLEX Z + INTENT (IN) :: Z,MA + CALL ZMZ2M(Z,MTZM) + CALL ZMREAL(MTZM,MTFM) + CALL ZMREAL(MA%MZM,MUFM) + L1 = FMCOMP(MTFM,'NE',MUFM) + CALL ZMIMAG(MTZM,MTFM) + CALL ZMIMAG(MA%MZM,MUFM) + L2 = FMCOMP(MTFM,'NE',MUFM) + FMLNE_ZZM = L1.OR.L2 + END FUNCTION + + FUNCTION FMLNE_CFM(C,MA) + LOGICAL FMLNE_CFM,FMCOMP,L1,L2 + TYPE ( FM ) MA + COMPLEX (KIND(0.0D0)) :: C + INTENT (IN) :: C,MA + CALL FMDP2M(REAL(C,KIND(0.0D0)),MTFM) + L1 = FMCOMP(MTFM,'NE',MA%MFM) + L2 = .FALSE. + IF (AIMAG(C) /= 0.0) L2 = .TRUE. + FMLNE_CFM = L1.OR.L2 + END FUNCTION + + FUNCTION FMLNE_CIM(C,MA) + USE FMVALS + LOGICAL FMLNE_CIM,FMCOMP,L1,L2 + TYPE ( IM ) MA + COMPLEX (KIND(0.0D0)) :: C + INTEGER KA,NDSAVE + INTENT (IN) :: C,MA + NDSAVE = NDIG + KA = MA%MIM(1) + NDIG = MAX(KA+NGRD52,NDIG) + CALL FMDP2M(REAL(C,KIND(0.0D0)),MTFM) + CALL IMI2FM(MA%MIM,MUFM) + L1 = FMCOMP(MTFM,'NE',MUFM) + NDIG = NDSAVE + L2 = .FALSE. + IF (AIMAG(C) /= 0.0) L2 = .TRUE. + FMLNE_CIM = L1.OR.L2 + END FUNCTION + + FUNCTION FMLNE_CZM(C,MA) + LOGICAL FMLNE_CZM,FMCOMP,L1,L2 + TYPE ( ZM ) MA + COMPLEX (KIND(0.0D0)) :: C + INTENT (IN) :: C,MA + CALL FMDP2M(REAL(C,KIND(0.0D0)),MTFM) + CALL ZMREAL(MA%MZM,MUFM) + L1 = FMCOMP(MTFM,'NE',MUFM) + CALL FMDP2M(AIMAG(C),MTFM) + CALL ZMIMAG(MA%MZM,MUFM) + L2 = FMCOMP(MTFM,'NE',MUFM) + FMLNE_CZM = L1.OR.L2 + END FUNCTION + + FUNCTION FMLNE_FMI(MA,IVAL) + LOGICAL FMLNE_FMI,FMCOMP + TYPE ( FM ) MA + INTEGER IVAL + INTENT (IN) :: MA,IVAL + CALL FMI2M(IVAL,MTFM) + FMLNE_FMI = FMCOMP(MA%MFM,'NE',MTFM) + END FUNCTION + + FUNCTION FMLNE_FMR(MA,R) + LOGICAL FMLNE_FMR,FMCOMP + TYPE ( FM ) MA + REAL R + INTENT (IN) :: MA,R + CALL FMSP2M(R,MTFM) + FMLNE_FMR = FMCOMP(MA%MFM,'NE',MTFM) + END FUNCTION + + FUNCTION FMLNE_FMD(MA,D) + LOGICAL FMLNE_FMD,FMCOMP + TYPE ( FM ) MA + DOUBLE PRECISION D + INTENT (IN) :: MA,D + CALL FMDP2M(D,MTFM) + FMLNE_FMD = FMCOMP(MA%MFM,'NE',MTFM) + END FUNCTION + + FUNCTION FMLNE_FMZ(MA,Z) + LOGICAL FMLNE_FMZ,FMCOMP,L1,L2 + TYPE ( FM ) MA + COMPLEX Z + INTENT (IN) :: MA,Z + CALL FMSP2M(REAL(Z),MTFM) + L1 = FMCOMP(MA%MFM,'NE',MTFM) + L2 = .FALSE. + IF (AIMAG(Z) /= 0.0) L2 = .TRUE. + FMLNE_FMZ = L1.OR.L2 + END FUNCTION + + FUNCTION FMLNE_FMC(MA,C) + LOGICAL FMLNE_FMC,FMCOMP,L1,L2 + TYPE ( FM ) MA + COMPLEX (KIND(0.0D0)) :: C + INTENT (IN) :: MA,C + CALL FMDP2M(REAL(C,KIND(0.0D0)),MTFM) + L1 = FMCOMP(MA%MFM,'NE',MTFM) + L2 = .FALSE. + IF (AIMAG(C) /= 0.0) L2 = .TRUE. + FMLNE_FMC = L1.OR.L2 + END FUNCTION + + FUNCTION FMLNE_FMFM(MA,MB) + LOGICAL FMLNE_FMFM,FMCOMP + TYPE ( FM ) MA,MB + INTENT (IN) :: MA,MB + FMLNE_FMFM = FMCOMP(MA%MFM,'NE',MB%MFM) + END FUNCTION + + FUNCTION FMLNE_FMIM(MA,MB) + LOGICAL FMLNE_FMIM,FMCOMP + TYPE ( FM ) MA + TYPE ( IM ) MB + INTENT (IN) :: MA,MB + CALL FMINT(MA%MFM,MTFM) + IF (FMCOMP(MA%MFM,'EQ',MTFM)) THEN + CALL IMI2FM(MB%MIM,MTFM) + FMLNE_FMIM = FMCOMP(MA%MFM,'NE',MTFM) + ELSE + FMLNE_FMIM = .TRUE. + ENDIF + END FUNCTION + + FUNCTION FMLNE_FMZM(MA,MB) + USE FMVALS + LOGICAL FMLNE_FMZM,FMCOMP,L1,L2 + TYPE ( FM ) MA + TYPE ( ZM ) MB + INTENT (IN) :: MA,MB + CALL ZMREAL(MB%MZM,MTFM) + L1 = FMCOMP(MA%MFM,'NE',MTFM) + L2 = .FALSE. + IF (MB%MZM(KPTIMU+2) /= 0) L2 = .TRUE. + FMLNE_FMZM = L1.OR.L2 + END FUNCTION + + FUNCTION FMLNE_IMI(MA,IVAL) + LOGICAL FMLNE_IMI,IMCOMP + TYPE ( IM ) MA + INTEGER IVAL + INTENT (IN) :: MA,IVAL + CALL IMI2M(IVAL,MTIM) + FMLNE_IMI = IMCOMP(MA%MIM,'NE',MTIM) + END FUNCTION + + FUNCTION FMLNE_IMR(MA,R) + USE FMVALS + LOGICAL FMLNE_IMR,FMCOMP + TYPE ( IM ) MA + INTEGER KA,NDSAVE + REAL R + INTENT (IN) :: MA,R + NDSAVE = NDIG + KA = MA%MIM(1) + NDIG = MAX(KA+NGRD52,NDIG) + CALL FMSP2M(R,MTFM) + CALL IMI2FM(MA%MIM,MUFM) + FMLNE_IMR = FMCOMP(MUFM,'NE',MTFM) + NDIG = NDSAVE + END FUNCTION + + FUNCTION FMLNE_IMD(MA,D) + USE FMVALS + LOGICAL FMLNE_IMD,FMCOMP + TYPE ( IM ) MA + DOUBLE PRECISION D + INTEGER KA,NDSAVE + INTENT (IN) :: MA,D + NDSAVE = NDIG + KA = MA%MIM(1) + NDIG = MAX(KA+NGRD52,NDIG) + CALL FMDP2M(D,MTFM) + CALL IMI2FM(MA%MIM,MUFM) + FMLNE_IMD = FMCOMP(MUFM,'NE',MTFM) + NDIG = NDSAVE + END FUNCTION + + FUNCTION FMLNE_IMZ(MA,Z) + USE FMVALS + LOGICAL FMLNE_IMZ,FMCOMP,L1,L2 + TYPE ( IM ) MA + INTEGER KA,NDSAVE + COMPLEX Z + INTENT (IN) :: MA,Z + NDSAVE = NDIG + KA = MA%MIM(1) + NDIG = MAX(KA+NGRD52,NDIG) + CALL FMSP2M(REAL(Z),MTFM) + CALL IMI2FM(MA%MIM,MUFM) + L1 = FMCOMP(MUFM,'NE',MTFM) + NDIG = NDSAVE + L2 = .FALSE. + IF (AIMAG(Z) /= 0.0) L2 = .TRUE. + FMLNE_IMZ = L1.OR.L2 + END FUNCTION + + FUNCTION FMLNE_IMC(MA,C) + USE FMVALS + LOGICAL FMLNE_IMC,FMCOMP,L1,L2 + TYPE ( IM ) MA + COMPLEX (KIND(0.0D0)) :: C + INTEGER KA,NDSAVE + INTENT (IN) :: MA,C + NDSAVE = NDIG + KA = MA%MIM(1) + NDIG = MAX(KA+NGRD52,NDIG) + CALL FMDP2M(REAL(C,KIND(0.0D0)),MTFM) + CALL IMI2FM(MA%MIM,MUFM) + L1 = FMCOMP(MUFM,'NE',MTFM) + NDIG = NDSAVE + L2 = .FALSE. + IF (AIMAG(C) /= 0.0) L2 = .TRUE. + FMLNE_IMC = L1.OR.L2 + END FUNCTION + + FUNCTION FMLNE_IMFM(MA,MB) + LOGICAL FMLNE_IMFM,FMCOMP + TYPE ( IM ) MA + TYPE ( FM ) MB + INTENT (IN) :: MA,MB + CALL FMINT(MB%MFM,MTFM) + IF (FMCOMP(MB%MFM,'EQ',MTFM)) THEN + CALL IMI2FM(MA%MIM,MTFM) + FMLNE_IMFM = FMCOMP(MB%MFM,'NE',MTFM) + ELSE + FMLNE_IMFM = .TRUE. + ENDIF + END FUNCTION + + FUNCTION FMLNE_IMIM(MA,MB) + LOGICAL FMLNE_IMIM,IMCOMP + TYPE ( IM ) MA,MB + INTENT (IN) :: MA,MB + FMLNE_IMIM = IMCOMP(MA%MIM,'NE',MB%MIM) + END FUNCTION + + FUNCTION FMLNE_IMZM(MA,MB) + USE FMVALS + LOGICAL FMLNE_IMZM,FMCOMP + TYPE ( IM ) MA + TYPE ( ZM ) MB + INTENT (IN) :: MA,MB + CALL ZMREAL(MB%MZM,MTFM) + CALL FMINT(MTFM,MUFM) + IF (FMCOMP(MUFM,'EQ',MTFM).AND.MB%MZM(KPTIMU+2) == 0) THEN + CALL IMI2FM(MA%MIM,MUFM) + FMLNE_IMZM = FMCOMP(MUFM,'NE',MTFM) + ELSE + FMLNE_IMZM = .TRUE. + ENDIF + END FUNCTION + + FUNCTION FMLNE_ZMI(MA,IVAL) + USE FMVALS + LOGICAL FMLNE_ZMI,FMCOMP + TYPE ( ZM ) MA + INTEGER IVAL + INTENT (IN) :: MA,IVAL + CALL ZMREAL(MA%MZM,MTFM) + CALL FMINT(MTFM,MUFM) + IF (FMCOMP(MUFM,'EQ',MTFM).AND.MA%MZM(KPTIMU+2) == 0) THEN + CALL FMI2M(IVAL,MUFM) + FMLNE_ZMI = FMCOMP(MTFM,'NE',MUFM) + ELSE + FMLNE_ZMI = .TRUE. + ENDIF + END FUNCTION + + FUNCTION FMLNE_ZMR(MA,R) + LOGICAL FMLNE_ZMR,FMCOMP,L1,L2 + TYPE ( ZM ) MA + REAL R + INTENT (IN) :: MA,R + CALL FMSP2M(R,MTFM) + CALL ZMREAL(MA%MZM,MUFM) + L1 = FMCOMP(MTFM,'NE',MUFM) + CALL FMI2M(0,MTFM) + CALL ZMIMAG(MA%MZM,MUFM) + L2 = FMCOMP(MTFM,'NE',MUFM) + FMLNE_ZMR = L1.OR.L2 + END FUNCTION + + FUNCTION FMLNE_ZMD(MA,D) + LOGICAL FMLNE_ZMD,FMCOMP,L1,L2 + TYPE ( ZM ) MA + DOUBLE PRECISION D + INTENT (IN) :: MA,D + CALL FMDP2M(D,MTFM) + CALL ZMREAL(MA%MZM,MUFM) + L1 = FMCOMP(MTFM,'NE',MUFM) + CALL FMI2M(0,MTFM) + CALL ZMIMAG(MA%MZM,MUFM) + L2 = FMCOMP(MTFM,'NE',MUFM) + FMLNE_ZMD = L1.OR.L2 + END FUNCTION + + FUNCTION FMLNE_ZMZ(MA,Z) + LOGICAL FMLNE_ZMZ,FMCOMP,L1,L2 + TYPE ( ZM ) MA + COMPLEX Z + INTENT (IN) :: MA,Z + CALL ZMZ2M(Z,MTZM) + CALL ZMREAL(MTZM,MTFM) + CALL ZMREAL(MA%MZM,MUFM) + L1 = FMCOMP(MTFM,'NE',MUFM) + CALL ZMIMAG(MTZM,MTFM) + CALL ZMIMAG(MA%MZM,MUFM) + L2 = FMCOMP(MTFM,'NE',MUFM) + FMLNE_ZMZ = L1.OR.L2 + END FUNCTION + + FUNCTION FMLNE_ZMC(MA,C) + LOGICAL FMLNE_ZMC,FMCOMP,L1,L2 + TYPE ( ZM ) MA + COMPLEX (KIND(0.0D0)) :: C + INTENT (IN) :: MA,C + CALL FMDP2M(REAL(C,KIND(0.0D0)),MTFM) + CALL ZMREAL(MA%MZM,MUFM) + L1 = FMCOMP(MTFM,'NE',MUFM) + CALL FMDP2M(AIMAG(C),MTFM) + CALL ZMIMAG(MA%MZM,MUFM) + L2 = FMCOMP(MTFM,'NE',MUFM) + FMLNE_ZMC = L1.OR.L2 + END FUNCTION + + FUNCTION FMLNE_ZMFM(MA,MB) + USE FMVALS + LOGICAL FMLNE_ZMFM,FMCOMP,L1,L2 + TYPE ( FM ) MB + TYPE ( ZM ) MA + INTENT (IN) :: MA,MB + CALL ZMREAL(MA%MZM,MTFM) + L1 = FMCOMP(MB%MFM,'NE',MTFM) + L2 = .FALSE. + IF (MA%MZM(KPTIMU+2) /= 0) L2 = .TRUE. + FMLNE_ZMFM = L1.OR.L2 + END FUNCTION + + FUNCTION FMLNE_ZMIM(MA,MB) + USE FMVALS + LOGICAL FMLNE_ZMIM,FMCOMP + TYPE ( IM ) MB + TYPE ( ZM ) MA + INTENT (IN) :: MA,MB + CALL ZMREAL(MA%MZM,MTFM) + CALL FMINT(MTFM,MUFM) + IF (FMCOMP(MUFM,'EQ',MTFM).AND.MA%MZM(KPTIMU+2) == 0) THEN + CALL IMI2FM(MB%MIM,MUFM) + FMLNE_ZMIM = FMCOMP(MUFM,'NE',MTFM) + ELSE + FMLNE_ZMIM = .TRUE. + ENDIF + END FUNCTION + + FUNCTION FMLNE_ZMZM(MA,MB) + LOGICAL FMLNE_ZMZM,FMCOMP,L1,L2 + TYPE ( ZM ) MA,MB + INTENT (IN) :: MA,MB + CALL ZMREAL(MA%MZM,MTFM) + CALL ZMREAL(MB%MZM,MUFM) + L1 = FMCOMP(MTFM,'NE',MUFM) + CALL ZMIMAG(MA%MZM,MTFM) + CALL ZMIMAG(MB%MZM,MUFM) + L2 = FMCOMP(MTFM,'NE',MUFM) + FMLNE_ZMZM = L1.OR.L2 + END FUNCTION + +! > + + FUNCTION FMLGT_IFM(IVAL,MA) + LOGICAL FMLGT_IFM,FMCOMP + TYPE ( FM ) MA + INTEGER IVAL + INTENT (IN) :: IVAL,MA + CALL FMI2M(IVAL,MTFM) + FMLGT_IFM = FMCOMP(MTFM,'GT',MA%MFM) + END FUNCTION + + FUNCTION FMLGT_IIM(IVAL,MA) + LOGICAL FMLGT_IIM,IMCOMP + TYPE ( IM ) MA + INTEGER IVAL + INTENT (IN) :: IVAL,MA + CALL IMI2M(IVAL,MTIM) + FMLGT_IIM = IMCOMP(MTIM,'GT',MA%MIM) + END FUNCTION + + FUNCTION FMLGT_RFM(R,MA) + LOGICAL FMLGT_RFM,FMCOMP + TYPE ( FM ) MA + REAL R + INTENT (IN) :: R,MA + CALL FMSP2M(R,MTFM) + FMLGT_RFM = FMCOMP(MTFM,'GT',MA%MFM) + END FUNCTION + + FUNCTION FMLGT_RIM(R,MA) + USE FMVALS + LOGICAL FMLGT_RIM,FMCOMP + TYPE ( IM ) MA + INTEGER KA,NDSAVE + REAL R + INTENT (IN) :: R,MA + NDSAVE = NDIG + KA = MA%MIM(1) + NDIG = MAX(KA+NGRD52,NDIG) + CALL FMSP2M(R,MTFM) + CALL IMI2FM(MA%MIM,MUFM) + FMLGT_RIM = FMCOMP(MTFM,'GT',MUFM) + NDIG = NDSAVE + END FUNCTION + + FUNCTION FMLGT_DFM(D,MA) + LOGICAL FMLGT_DFM,FMCOMP + TYPE ( FM ) MA + DOUBLE PRECISION D + INTENT (IN) :: D,MA + CALL FMDP2M(D,MTFM) + FMLGT_DFM = FMCOMP(MTFM,'GT',MA%MFM) + END FUNCTION + + FUNCTION FMLGT_DIM(D,MA) + USE FMVALS + LOGICAL FMLGT_DIM,FMCOMP + TYPE ( IM ) MA + DOUBLE PRECISION D + INTEGER KA,NDSAVE + INTENT (IN) :: D,MA + NDSAVE = NDIG + KA = MA%MIM(1) + NDIG = MAX(KA+NGRD52,NDIG) + CALL FMDP2M(D,MTFM) + CALL IMI2FM(MA%MIM,MUFM) + FMLGT_DIM = FMCOMP(MTFM,'GT',MUFM) + NDIG = NDSAVE + END FUNCTION + + FUNCTION FMLGT_FMI(MA,IVAL) + LOGICAL FMLGT_FMI,FMCOMP + TYPE ( FM ) MA + INTEGER IVAL + INTENT (IN) :: MA,IVAL + CALL FMI2M(IVAL,MTFM) + FMLGT_FMI = FMCOMP(MA%MFM,'GT',MTFM) + END FUNCTION + + FUNCTION FMLGT_FMR(MA,R) + LOGICAL FMLGT_FMR,FMCOMP + TYPE ( FM ) MA + REAL R + INTENT (IN) :: MA,R + CALL FMSP2M(R,MTFM) + FMLGT_FMR = FMCOMP(MA%MFM,'GT',MTFM) + END FUNCTION + + FUNCTION FMLGT_FMD(MA,D) + LOGICAL FMLGT_FMD,FMCOMP + TYPE ( FM ) MA + DOUBLE PRECISION D + INTENT (IN) :: MA,D + CALL FMDP2M(D,MTFM) + FMLGT_FMD = FMCOMP(MA%MFM,'GT',MTFM) + END FUNCTION + + FUNCTION FMLGT_FMFM(MA,MB) + LOGICAL FMLGT_FMFM,FMCOMP + TYPE ( FM ) MA,MB + INTENT (IN) :: MA,MB + FMLGT_FMFM = FMCOMP(MA%MFM,'GT',MB%MFM) + END FUNCTION + + FUNCTION FMLGT_FMIM(MA,MB) + USE FMVALS + LOGICAL FMLGT_FMIM,FMCOMP + TYPE ( FM ) MA + TYPE ( IM ) MB + INTEGER KA,NDSAVE + INTENT (IN) :: MA,MB + NDSAVE = NDIG + KA = MB%MIM(1) + NDIG = MAX(KA+NGRD52,NDIG) + CALL IMI2FM(MB%MIM,MTFM) + FMLGT_FMIM = FMCOMP(MA%MFM,'GT',MTFM) + NDIG = NDSAVE + END FUNCTION + + FUNCTION FMLGT_IMI(MA,IVAL) + LOGICAL FMLGT_IMI,IMCOMP + TYPE ( IM ) MA + INTEGER IVAL + INTENT (IN) :: MA,IVAL + CALL IMI2M(IVAL,MTIM) + FMLGT_IMI = IMCOMP(MA%MIM,'GT',MTIM) + END FUNCTION + + FUNCTION FMLGT_IMR(MA,R) + USE FMVALS + LOGICAL FMLGT_IMR,FMCOMP + TYPE ( IM ) MA + INTEGER KA,NDSAVE + REAL R + INTENT (IN) :: MA,R + NDSAVE = NDIG + KA = MA%MIM(1) + NDIG = MAX(KA+NGRD52,NDIG) + CALL FMSP2M(R,MTFM) + CALL IMI2FM(MA%MIM,MUFM) + FMLGT_IMR = FMCOMP(MUFM,'GT',MTFM) + NDIG = NDSAVE + END FUNCTION + + FUNCTION FMLGT_IMD(MA,D) + USE FMVALS + LOGICAL FMLGT_IMD,FMCOMP + TYPE ( IM ) MA + DOUBLE PRECISION D + INTEGER KA,NDSAVE + INTENT (IN) :: MA,D + NDSAVE = NDIG + KA = MA%MIM(1) + NDIG = MAX(KA+NGRD52,NDIG) + CALL FMDP2M(D,MTFM) + CALL IMI2FM(MA%MIM,MUFM) + FMLGT_IMD = FMCOMP(MUFM,'GT',MTFM) + NDIG = NDSAVE + END FUNCTION + + FUNCTION FMLGT_IMFM(MA,MB) + USE FMVALS + LOGICAL FMLGT_IMFM,FMCOMP + TYPE ( IM ) MA + TYPE ( FM ) MB + INTEGER KA,NDSAVE + INTENT (IN) :: MA,MB + NDSAVE = NDIG + KA = MA%MIM(1) + NDIG = MAX(KA+NGRD52,NDIG) + CALL IMI2FM(MA%MIM,MTFM) + FMLGT_IMFM = FMCOMP(MTFM,'GT',MB%MFM) + NDIG = NDSAVE + END FUNCTION + + FUNCTION FMLGT_IMIM(MA,MB) + LOGICAL FMLGT_IMIM,IMCOMP + TYPE ( IM ) MA,MB + INTENT (IN) :: MA,MB + FMLGT_IMIM = IMCOMP(MA%MIM,'GT',MB%MIM) + END FUNCTION + + END MODULE FMZM_3 + + MODULE FMZM_4 + USE FMZM_1 + + INTERFACE OPERATOR ( >= ) + MODULE PROCEDURE FMLGE_IFM + MODULE PROCEDURE FMLGE_IIM + MODULE PROCEDURE FMLGE_RFM + MODULE PROCEDURE FMLGE_RIM + MODULE PROCEDURE FMLGE_DFM + MODULE PROCEDURE FMLGE_DIM + MODULE PROCEDURE FMLGE_FMI + MODULE PROCEDURE FMLGE_FMR + MODULE PROCEDURE FMLGE_FMD + MODULE PROCEDURE FMLGE_FMFM + MODULE PROCEDURE FMLGE_FMIM + MODULE PROCEDURE FMLGE_IMI + MODULE PROCEDURE FMLGE_IMR + MODULE PROCEDURE FMLGE_IMD + MODULE PROCEDURE FMLGE_IMFM + MODULE PROCEDURE FMLGE_IMIM + END INTERFACE + + INTERFACE OPERATOR ( < ) + MODULE PROCEDURE FMLLT_IFM + MODULE PROCEDURE FMLLT_IIM + MODULE PROCEDURE FMLLT_RFM + MODULE PROCEDURE FMLLT_RIM + MODULE PROCEDURE FMLLT_DFM + MODULE PROCEDURE FMLLT_DIM + MODULE PROCEDURE FMLLT_FMI + MODULE PROCEDURE FMLLT_FMR + MODULE PROCEDURE FMLLT_FMD + MODULE PROCEDURE FMLLT_FMFM + MODULE PROCEDURE FMLLT_FMIM + MODULE PROCEDURE FMLLT_IMI + MODULE PROCEDURE FMLLT_IMR + MODULE PROCEDURE FMLLT_IMD + MODULE PROCEDURE FMLLT_IMFM + MODULE PROCEDURE FMLLT_IMIM + END INTERFACE + + INTERFACE OPERATOR ( <= ) + MODULE PROCEDURE FMLLE_IFM + MODULE PROCEDURE FMLLE_IIM + MODULE PROCEDURE FMLLE_RFM + MODULE PROCEDURE FMLLE_RIM + MODULE PROCEDURE FMLLE_DFM + MODULE PROCEDURE FMLLE_DIM + MODULE PROCEDURE FMLLE_FMI + MODULE PROCEDURE FMLLE_FMR + MODULE PROCEDURE FMLLE_FMD + MODULE PROCEDURE FMLLE_FMFM + MODULE PROCEDURE FMLLE_FMIM + MODULE PROCEDURE FMLLE_IMI + MODULE PROCEDURE FMLLE_IMR + MODULE PROCEDURE FMLLE_IMD + MODULE PROCEDURE FMLLE_IMFM + MODULE PROCEDURE FMLLE_IMIM + END INTERFACE + + CONTAINS + +! >= + + FUNCTION FMLGE_IFM(IVAL,MA) + LOGICAL FMLGE_IFM,FMCOMP + TYPE ( FM ) MA + INTEGER IVAL + INTENT (IN) :: IVAL,MA + CALL FMI2M(IVAL,MTFM) + FMLGE_IFM = FMCOMP(MTFM,'GE',MA%MFM) + END FUNCTION + + FUNCTION FMLGE_IIM(IVAL,MA) + LOGICAL FMLGE_IIM,IMCOMP + TYPE ( IM ) MA + INTEGER IVAL + INTENT (IN) :: IVAL,MA + CALL IMI2M(IVAL,MTIM) + FMLGE_IIM = IMCOMP(MTIM,'GE',MA%MIM) + END FUNCTION + + FUNCTION FMLGE_RFM(R,MA) + LOGICAL FMLGE_RFM,FMCOMP + TYPE ( FM ) MA + REAL R + INTENT (IN) :: R,MA + CALL FMSP2M(R,MTFM) + FMLGE_RFM = FMCOMP(MTFM,'GE',MA%MFM) + END FUNCTION + + FUNCTION FMLGE_RIM(R,MA) + USE FMVALS + LOGICAL FMLGE_RIM,FMCOMP + TYPE ( IM ) MA + INTEGER KA,NDSAVE + REAL R + INTENT (IN) :: R,MA + NDSAVE = NDIG + KA = MA%MIM(1) + NDIG = MAX(KA+NGRD52,NDIG) + CALL FMSP2M(R,MTFM) + CALL IMI2FM(MA%MIM,MUFM) + FMLGE_RIM = FMCOMP(MTFM,'GE',MUFM) + NDIG = NDSAVE + END FUNCTION + + FUNCTION FMLGE_DFM(D,MA) + LOGICAL FMLGE_DFM,FMCOMP + TYPE ( FM ) MA + DOUBLE PRECISION D + INTENT (IN) :: D,MA + CALL FMDP2M(D,MTFM) + FMLGE_DFM = FMCOMP(MTFM,'GE',MA%MFM) + END FUNCTION + + FUNCTION FMLGE_DIM(D,MA) + USE FMVALS + LOGICAL FMLGE_DIM,FMCOMP + TYPE ( IM ) MA + DOUBLE PRECISION D + INTEGER KA,NDSAVE + INTENT (IN) :: D,MA + NDSAVE = NDIG + KA = MA%MIM(1) + NDIG = MAX(KA+NGRD52,NDIG) + CALL FMDP2M(D,MTFM) + CALL IMI2FM(MA%MIM,MUFM) + FMLGE_DIM = FMCOMP(MTFM,'GE',MUFM) + NDIG = NDSAVE + END FUNCTION + + FUNCTION FMLGE_FMI(MA,IVAL) + LOGICAL FMLGE_FMI,FMCOMP + TYPE ( FM ) MA + INTEGER IVAL + INTENT (IN) :: MA,IVAL + CALL FMI2M(IVAL,MTFM) + FMLGE_FMI = FMCOMP(MA%MFM,'GE',MTFM) + END FUNCTION + + FUNCTION FMLGE_FMR(MA,R) + LOGICAL FMLGE_FMR,FMCOMP + TYPE ( FM ) MA + REAL R + INTENT (IN) :: MA,R + CALL FMSP2M(R,MTFM) + FMLGE_FMR = FMCOMP(MA%MFM,'GE',MTFM) + END FUNCTION + + FUNCTION FMLGE_FMD(MA,D) + LOGICAL FMLGE_FMD,FMCOMP + TYPE ( FM ) MA + DOUBLE PRECISION D + INTENT (IN) :: MA,D + CALL FMDP2M(D,MTFM) + FMLGE_FMD = FMCOMP(MA%MFM,'GE',MTFM) + END FUNCTION + + FUNCTION FMLGE_FMFM(MA,MB) + LOGICAL FMLGE_FMFM,FMCOMP + TYPE ( FM ) MA,MB + INTENT (IN) :: MA,MB + FMLGE_FMFM = FMCOMP(MA%MFM,'GE',MB%MFM) + END FUNCTION + + FUNCTION FMLGE_FMIM(MA,MB) + USE FMVALS + LOGICAL FMLGE_FMIM,FMCOMP + TYPE ( FM ) MA + TYPE ( IM ) MB + INTEGER KA,NDSAVE + INTENT (IN) :: MA,MB + NDSAVE = NDIG + KA = MB%MIM(1) + NDIG = MAX(KA+NGRD52,NDIG) + CALL IMI2FM(MB%MIM,MTFM) + FMLGE_FMIM = FMCOMP(MA%MFM,'GE',MTFM) + NDIG = NDSAVE + END FUNCTION + + FUNCTION FMLGE_IMI(MA,IVAL) + LOGICAL FMLGE_IMI,IMCOMP + TYPE ( IM ) MA + INTEGER IVAL + INTENT (IN) :: MA,IVAL + CALL IMI2M(IVAL,MTIM) + FMLGE_IMI = IMCOMP(MA%MIM,'GE',MTIM) + END FUNCTION + + FUNCTION FMLGE_IMR(MA,R) + USE FMVALS + LOGICAL FMLGE_IMR,FMCOMP + TYPE ( IM ) MA + INTEGER KA,NDSAVE + REAL R + INTENT (IN) :: MA,R + NDSAVE = NDIG + KA = MA%MIM(1) + NDIG = MAX(KA+NGRD52,NDIG) + CALL FMSP2M(R,MTFM) + CALL IMI2FM(MA%MIM,MUFM) + FMLGE_IMR = FMCOMP(MUFM,'GE',MTFM) + NDIG = NDSAVE + END FUNCTION + + FUNCTION FMLGE_IMD(MA,D) + USE FMVALS + LOGICAL FMLGE_IMD,FMCOMP + TYPE ( IM ) MA + DOUBLE PRECISION D + INTEGER KA,NDSAVE + INTENT (IN) :: MA,D + NDSAVE = NDIG + KA = MA%MIM(1) + NDIG = MAX(KA+NGRD52,NDIG) + CALL FMDP2M(D,MTFM) + CALL IMI2FM(MA%MIM,MUFM) + FMLGE_IMD = FMCOMP(MUFM,'GE',MTFM) + NDIG = NDSAVE + END FUNCTION + + FUNCTION FMLGE_IMFM(MA,MB) + USE FMVALS + LOGICAL FMLGE_IMFM,FMCOMP + TYPE ( IM ) MA + TYPE ( FM ) MB + INTEGER KA,NDSAVE + INTENT (IN) :: MA,MB + NDSAVE = NDIG + KA = MA%MIM(1) + NDIG = MAX(KA+NGRD52,NDIG) + CALL IMI2FM(MA%MIM,MTFM) + FMLGE_IMFM = FMCOMP(MTFM,'GE',MB%MFM) + NDIG = NDSAVE + END FUNCTION + + FUNCTION FMLGE_IMIM(MA,MB) + LOGICAL FMLGE_IMIM,IMCOMP + TYPE ( IM ) MA,MB + INTENT (IN) :: MA,MB + FMLGE_IMIM = IMCOMP(MA%MIM,'GE',MB%MIM) + END FUNCTION + +! < + + FUNCTION FMLLT_IFM(IVAL,MA) + LOGICAL FMLLT_IFM,FMCOMP + TYPE ( FM ) MA + INTEGER IVAL + INTENT (IN) :: IVAL,MA + CALL FMI2M(IVAL,MTFM) + FMLLT_IFM = FMCOMP(MTFM,'LT',MA%MFM) + END FUNCTION + + FUNCTION FMLLT_IIM(IVAL,MA) + LOGICAL FMLLT_IIM,IMCOMP + TYPE ( IM ) MA + INTEGER IVAL + INTENT (IN) :: IVAL,MA + CALL IMI2M(IVAL,MTIM) + FMLLT_IIM = IMCOMP(MTIM,'LT',MA%MIM) + END FUNCTION + + FUNCTION FMLLT_RFM(R,MA) + LOGICAL FMLLT_RFM,FMCOMP + TYPE ( FM ) MA + REAL R + INTENT (IN) :: R,MA + CALL FMSP2M(R,MTFM) + FMLLT_RFM = FMCOMP(MTFM,'LT',MA%MFM) + END FUNCTION + + FUNCTION FMLLT_RIM(R,MA) + USE FMVALS + LOGICAL FMLLT_RIM,FMCOMP + TYPE ( IM ) MA + INTEGER KA,NDSAVE + REAL R + INTENT (IN) :: R,MA + NDSAVE = NDIG + KA = MA%MIM(1) + NDIG = MAX(KA+NGRD52,NDIG) + CALL FMSP2M(R,MTFM) + CALL IMI2FM(MA%MIM,MUFM) + FMLLT_RIM = FMCOMP(MTFM,'LT',MUFM) + NDIG = NDSAVE + END FUNCTION + + FUNCTION FMLLT_DFM(D,MA) + LOGICAL FMLLT_DFM,FMCOMP + TYPE ( FM ) MA + DOUBLE PRECISION D + INTENT (IN) :: D,MA + CALL FMDP2M(D,MTFM) + FMLLT_DFM = FMCOMP(MTFM,'LT',MA%MFM) + END FUNCTION + + FUNCTION FMLLT_DIM(D,MA) + USE FMVALS + LOGICAL FMLLT_DIM,FMCOMP + TYPE ( IM ) MA + DOUBLE PRECISION D + INTEGER KA,NDSAVE + INTENT (IN) :: D,MA + NDSAVE = NDIG + KA = MA%MIM(1) + NDIG = MAX(KA+NGRD52,NDIG) + CALL FMDP2M(D,MTFM) + CALL IMI2FM(MA%MIM,MUFM) + FMLLT_DIM = FMCOMP(MTFM,'LT',MUFM) + NDIG = NDSAVE + END FUNCTION + + FUNCTION FMLLT_FMI(MA,IVAL) + LOGICAL FMLLT_FMI,FMCOMP + TYPE ( FM ) MA + INTEGER IVAL + INTENT (IN) :: MA,IVAL + CALL FMI2M(IVAL,MTFM) + FMLLT_FMI = FMCOMP(MA%MFM,'LT',MTFM) + END FUNCTION + + FUNCTION FMLLT_FMR(MA,R) + LOGICAL FMLLT_FMR,FMCOMP + TYPE ( FM ) MA + REAL R + INTENT (IN) :: MA,R + CALL FMSP2M(R,MTFM) + FMLLT_FMR = FMCOMP(MA%MFM,'LT',MTFM) + END FUNCTION + + FUNCTION FMLLT_FMD(MA,D) + LOGICAL FMLLT_FMD,FMCOMP + TYPE ( FM ) MA + DOUBLE PRECISION D + INTENT (IN) :: MA,D + CALL FMDP2M(D,MTFM) + FMLLT_FMD = FMCOMP(MA%MFM,'LT',MTFM) + END FUNCTION + + FUNCTION FMLLT_FMFM(MA,MB) + LOGICAL FMLLT_FMFM,FMCOMP + TYPE ( FM ) MA,MB + INTENT (IN) :: MA,MB + FMLLT_FMFM = FMCOMP(MA%MFM,'LT',MB%MFM) + END FUNCTION + + FUNCTION FMLLT_FMIM(MA,MB) + USE FMVALS + LOGICAL FMLLT_FMIM,FMCOMP + TYPE ( FM ) MA + TYPE ( IM ) MB + INTEGER KA,NDSAVE + INTENT (IN) :: MA,MB + NDSAVE = NDIG + KA = MB%MIM(1) + NDIG = MAX(KA+NGRD52,NDIG) + CALL IMI2FM(MB%MIM,MTFM) + FMLLT_FMIM = FMCOMP(MA%MFM,'LT',MTFM) + NDIG = NDSAVE + END FUNCTION + + FUNCTION FMLLT_IMI(MA,IVAL) + LOGICAL FMLLT_IMI,IMCOMP + TYPE ( IM ) MA + INTEGER IVAL + INTENT (IN) :: MA,IVAL + CALL IMI2M(IVAL,MTIM) + FMLLT_IMI = IMCOMP(MA%MIM,'LT',MTIM) + END FUNCTION + + FUNCTION FMLLT_IMR(MA,R) + USE FMVALS + LOGICAL FMLLT_IMR,FMCOMP + TYPE ( IM ) MA + INTEGER KA,NDSAVE + REAL R + INTENT (IN) :: MA,R + NDSAVE = NDIG + KA = MA%MIM(1) + NDIG = MAX(KA+NGRD52,NDIG) + CALL FMSP2M(R,MTFM) + CALL IMI2FM(MA%MIM,MUFM) + FMLLT_IMR = FMCOMP(MUFM,'LT',MTFM) + NDIG = NDSAVE + END FUNCTION + + FUNCTION FMLLT_IMD(MA,D) + USE FMVALS + LOGICAL FMLLT_IMD,FMCOMP + TYPE ( IM ) MA + DOUBLE PRECISION D + INTEGER KA,NDSAVE + INTENT (IN) :: MA,D + NDSAVE = NDIG + KA = MA%MIM(1) + NDIG = MAX(KA+NGRD52,NDIG) + CALL FMDP2M(D,MTFM) + CALL IMI2FM(MA%MIM,MUFM) + FMLLT_IMD = FMCOMP(MUFM,'LT',MTFM) + NDIG = NDSAVE + END FUNCTION + + FUNCTION FMLLT_IMFM(MA,MB) + USE FMVALS + LOGICAL FMLLT_IMFM,FMCOMP + TYPE ( IM ) MA + TYPE ( FM ) MB + INTEGER KA,NDSAVE + INTENT (IN) :: MA,MB + NDSAVE = NDIG + KA = MA%MIM(1) + NDIG = MAX(KA+NGRD52,NDIG) + CALL IMI2FM(MA%MIM,MTFM) + FMLLT_IMFM = FMCOMP(MTFM,'LT',MB%MFM) + NDIG = NDSAVE + END FUNCTION + + FUNCTION FMLLT_IMIM(MA,MB) + LOGICAL FMLLT_IMIM,IMCOMP + TYPE ( IM ) MA,MB + INTENT (IN) :: MA,MB + FMLLT_IMIM = IMCOMP(MA%MIM,'LT',MB%MIM) + END FUNCTION + +! <= + + FUNCTION FMLLE_IFM(IVAL,MA) + LOGICAL FMLLE_IFM,FMCOMP + TYPE ( FM ) MA + INTEGER IVAL + INTENT (IN) :: IVAL,MA + CALL FMI2M(IVAL,MTFM) + FMLLE_IFM = FMCOMP(MTFM,'LE',MA%MFM) + END FUNCTION + + FUNCTION FMLLE_IIM(IVAL,MA) + LOGICAL FMLLE_IIM,IMCOMP + TYPE ( IM ) MA + INTEGER IVAL + INTENT (IN) :: IVAL,MA + CALL IMI2M(IVAL,MTIM) + FMLLE_IIM = IMCOMP(MTIM,'LE',MA%MIM) + END FUNCTION + + FUNCTION FMLLE_RFM(R,MA) + LOGICAL FMLLE_RFM,FMCOMP + TYPE ( FM ) MA + REAL R + INTENT (IN) :: R,MA + CALL FMSP2M(R,MTFM) + FMLLE_RFM = FMCOMP(MTFM,'LE',MA%MFM) + END FUNCTION + + FUNCTION FMLLE_RIM(R,MA) + USE FMVALS + LOGICAL FMLLE_RIM,FMCOMP + TYPE ( IM ) MA + INTEGER KA,NDSAVE + REAL R + INTENT (IN) :: R,MA + NDSAVE = NDIG + KA = MA%MIM(1) + NDIG = MAX(KA+NGRD52,NDIG) + CALL FMSP2M(R,MTFM) + CALL IMI2FM(MA%MIM,MUFM) + FMLLE_RIM = FMCOMP(MTFM,'LE',MUFM) + NDIG = NDSAVE + END FUNCTION + + FUNCTION FMLLE_DFM(D,MA) + LOGICAL FMLLE_DFM,FMCOMP + TYPE ( FM ) MA + DOUBLE PRECISION D + INTENT (IN) :: D,MA + CALL FMDP2M(D,MTFM) + FMLLE_DFM = FMCOMP(MTFM,'LE',MA%MFM) + END FUNCTION + + FUNCTION FMLLE_DIM(D,MA) + USE FMVALS + LOGICAL FMLLE_DIM,FMCOMP + TYPE ( IM ) MA + DOUBLE PRECISION D + INTEGER KA,NDSAVE + INTENT (IN) :: D,MA + NDSAVE = NDIG + KA = MA%MIM(1) + NDIG = MAX(KA+NGRD52,NDIG) + CALL FMDP2M(D,MTFM) + CALL IMI2FM(MA%MIM,MUFM) + FMLLE_DIM = FMCOMP(MTFM,'LE',MUFM) + NDIG = NDSAVE + END FUNCTION + + FUNCTION FMLLE_FMI(MA,IVAL) + LOGICAL FMLLE_FMI,FMCOMP + TYPE ( FM ) MA + INTEGER IVAL + INTENT (IN) :: MA,IVAL + CALL FMI2M(IVAL,MTFM) + FMLLE_FMI = FMCOMP(MA%MFM,'LE',MTFM) + END FUNCTION + + FUNCTION FMLLE_FMR(MA,R) + LOGICAL FMLLE_FMR,FMCOMP + TYPE ( FM ) MA + REAL R + INTENT (IN) :: MA,R + CALL FMSP2M(R,MTFM) + FMLLE_FMR = FMCOMP(MA%MFM,'LE',MTFM) + END FUNCTION + + FUNCTION FMLLE_FMD(MA,D) + LOGICAL FMLLE_FMD,FMCOMP + TYPE ( FM ) MA + DOUBLE PRECISION D + INTENT (IN) :: MA,D + CALL FMDP2M(D,MTFM) + FMLLE_FMD = FMCOMP(MA%MFM,'LE',MTFM) + END FUNCTION + + FUNCTION FMLLE_FMFM(MA,MB) + LOGICAL FMLLE_FMFM,FMCOMP + TYPE ( FM ) MA,MB + INTENT (IN) :: MA,MB + FMLLE_FMFM = FMCOMP(MA%MFM,'LE',MB%MFM) + END FUNCTION + + FUNCTION FMLLE_FMIM(MA,MB) + USE FMVALS + LOGICAL FMLLE_FMIM,FMCOMP + TYPE ( FM ) MA + TYPE ( IM ) MB + INTEGER KA,NDSAVE + INTENT (IN) :: MA,MB + NDSAVE = NDIG + KA = MB%MIM(1) + NDIG = MAX(KA+NGRD52,NDIG) + CALL IMI2FM(MB%MIM,MTFM) + FMLLE_FMIM = FMCOMP(MA%MFM,'LE',MTFM) + NDIG = NDSAVE + END FUNCTION + + FUNCTION FMLLE_IMI(MA,IVAL) + LOGICAL FMLLE_IMI,IMCOMP + TYPE ( IM ) MA + INTEGER IVAL + INTENT (IN) :: MA,IVAL + CALL IMI2M(IVAL,MTIM) + FMLLE_IMI = IMCOMP(MA%MIM,'LE',MTIM) + END FUNCTION + + FUNCTION FMLLE_IMR(MA,R) + USE FMVALS + LOGICAL FMLLE_IMR,FMCOMP + TYPE ( IM ) MA + INTEGER KA,NDSAVE + REAL R + INTENT (IN) :: MA,R + NDSAVE = NDIG + KA = MA%MIM(1) + NDIG = MAX(KA+NGRD52,NDIG) + CALL FMSP2M(R,MTFM) + CALL IMI2FM(MA%MIM,MUFM) + FMLLE_IMR = FMCOMP(MUFM,'LE',MTFM) + NDIG = NDSAVE + END FUNCTION + + FUNCTION FMLLE_IMD(MA,D) + USE FMVALS + LOGICAL FMLLE_IMD,FMCOMP + TYPE ( IM ) MA + DOUBLE PRECISION D + INTEGER KA,NDSAVE + INTENT (IN) :: MA,D + NDSAVE = NDIG + KA = MA%MIM(1) + NDIG = MAX(KA+NGRD52,NDIG) + CALL FMDP2M(D,MTFM) + CALL IMI2FM(MA%MIM,MUFM) + FMLLE_IMD = FMCOMP(MUFM,'LE',MTFM) + NDIG = NDSAVE + END FUNCTION + + FUNCTION FMLLE_IMFM(MA,MB) + USE FMVALS + LOGICAL FMLLE_IMFM,FMCOMP + TYPE ( IM ) MA + TYPE ( FM ) MB + INTEGER KA,NDSAVE + INTENT (IN) :: MA,MB + NDSAVE = NDIG + KA = MA%MIM(1) + NDIG = MAX(KA+NGRD52,NDIG) + CALL IMI2FM(MA%MIM,MTFM) + FMLLE_IMFM = FMCOMP(MTFM,'LE',MB%MFM) + NDIG = NDSAVE + END FUNCTION + + FUNCTION FMLLE_IMIM(MA,MB) + LOGICAL FMLLE_IMIM,IMCOMP + TYPE ( IM ) MA,MB + INTENT (IN) :: MA,MB + FMLLE_IMIM = IMCOMP(MA%MIM,'LE',MB%MIM) + END FUNCTION + + END MODULE FMZM_4 + + MODULE FMZM_5 + USE FMZM_1 + + INTERFACE OPERATOR (+) + MODULE PROCEDURE FMADD_IFM + MODULE PROCEDURE FMADD_IIM + MODULE PROCEDURE FMADD_IZM + MODULE PROCEDURE FMADD_RFM + MODULE PROCEDURE FMADD_RIM + MODULE PROCEDURE FMADD_RZM + MODULE PROCEDURE FMADD_DFM + MODULE PROCEDURE FMADD_DIM + MODULE PROCEDURE FMADD_DZM + MODULE PROCEDURE FMADD_ZFM + MODULE PROCEDURE FMADD_ZIM + MODULE PROCEDURE FMADD_ZZM + MODULE PROCEDURE FMADD_CFM + MODULE PROCEDURE FMADD_CIM + MODULE PROCEDURE FMADD_CZM + MODULE PROCEDURE FMADD_FMI + MODULE PROCEDURE FMADD_FMR + MODULE PROCEDURE FMADD_FMD + MODULE PROCEDURE FMADD_FMZ + MODULE PROCEDURE FMADD_FMC + MODULE PROCEDURE FMADD_FMFM + MODULE PROCEDURE FMADD_FMIM + MODULE PROCEDURE FMADD_FMZM + MODULE PROCEDURE FMADD_IMI + MODULE PROCEDURE FMADD_IMR + MODULE PROCEDURE FMADD_IMD + MODULE PROCEDURE FMADD_IMZ + MODULE PROCEDURE FMADD_IMC + MODULE PROCEDURE FMADD_IMFM + MODULE PROCEDURE FMADD_IMIM + MODULE PROCEDURE FMADD_IMZM + MODULE PROCEDURE FMADD_ZMI + MODULE PROCEDURE FMADD_ZMR + MODULE PROCEDURE FMADD_ZMD + MODULE PROCEDURE FMADD_ZMZ + MODULE PROCEDURE FMADD_ZMC + MODULE PROCEDURE FMADD_ZMFM + MODULE PROCEDURE FMADD_ZMIM + MODULE PROCEDURE FMADD_ZMZM + MODULE PROCEDURE FMADD_FM + MODULE PROCEDURE FMADD_IM + MODULE PROCEDURE FMADD_ZM + END INTERFACE + + INTERFACE OPERATOR (-) + MODULE PROCEDURE FMSUB_IFM + MODULE PROCEDURE FMSUB_IIM + MODULE PROCEDURE FMSUB_IZM + MODULE PROCEDURE FMSUB_RFM + MODULE PROCEDURE FMSUB_RIM + MODULE PROCEDURE FMSUB_RZM + MODULE PROCEDURE FMSUB_DFM + MODULE PROCEDURE FMSUB_DIM + MODULE PROCEDURE FMSUB_DZM + MODULE PROCEDURE FMSUB_ZFM + MODULE PROCEDURE FMSUB_ZIM + MODULE PROCEDURE FMSUB_ZZM + MODULE PROCEDURE FMSUB_CFM + MODULE PROCEDURE FMSUB_CIM + MODULE PROCEDURE FMSUB_CZM + MODULE PROCEDURE FMSUB_FMI + MODULE PROCEDURE FMSUB_FMR + MODULE PROCEDURE FMSUB_FMD + MODULE PROCEDURE FMSUB_FMZ + MODULE PROCEDURE FMSUB_FMC + MODULE PROCEDURE FMSUB_FMFM + MODULE PROCEDURE FMSUB_FMIM + MODULE PROCEDURE FMSUB_FMZM + MODULE PROCEDURE FMSUB_IMI + MODULE PROCEDURE FMSUB_IMR + MODULE PROCEDURE FMSUB_IMD + MODULE PROCEDURE FMSUB_IMZ + MODULE PROCEDURE FMSUB_IMC + MODULE PROCEDURE FMSUB_IMFM + MODULE PROCEDURE FMSUB_IMIM + MODULE PROCEDURE FMSUB_IMZM + MODULE PROCEDURE FMSUB_ZMI + MODULE PROCEDURE FMSUB_ZMR + MODULE PROCEDURE FMSUB_ZMD + MODULE PROCEDURE FMSUB_ZMZ + MODULE PROCEDURE FMSUB_ZMC + MODULE PROCEDURE FMSUB_ZMFM + MODULE PROCEDURE FMSUB_ZMIM + MODULE PROCEDURE FMSUB_ZMZM + MODULE PROCEDURE FMSUB_FM + MODULE PROCEDURE FMSUB_IM + MODULE PROCEDURE FMSUB_ZM + END INTERFACE + + CONTAINS + +! + + + FUNCTION FMADD_IFM(IVAL,MA) + USE FMVALS + TYPE ( FM ) MA,FMADD_IFM + INTEGER IVAL + INTENT (IN) :: IVAL,MA + CALL FMI2M(IVAL,MTFM) + CALL FMADD(MTFM,MA%MFM,FMADD_IFM%MFM) + END FUNCTION + + FUNCTION FMADD_IIM(IVAL,MA) + USE FMVALS + TYPE ( IM ) MA,FMADD_IIM + INTEGER IVAL + INTENT (IN) :: IVAL,MA + CALL IMI2M(IVAL,MTIM) + CALL IMADD(MTIM,MA%MIM,FMADD_IIM%MIM) + END FUNCTION + + FUNCTION FMADD_IZM(IVAL,MA) + USE FMVALS + TYPE ( ZM ) MA,FMADD_IZM + INTEGER IVAL + INTENT (IN) :: IVAL,MA + CALL FMI2M(IVAL,MTFM) + CALL FMI2M(0,MUFM) + CALL ZMCMPX(MTFM,MUFM,MTZM) + CALL ZMADD(MTZM,MA%MZM,FMADD_IZM%MZM) + END FUNCTION + + FUNCTION FMADD_RFM(R,MA) + USE FMVALS + TYPE ( FM ) MA,FMADD_RFM + REAL R + INTENT (IN) :: R,MA + CALL FMSP2M(R,MTFM) + CALL FMADD(MTFM,MA%MFM,FMADD_RFM%MFM) + END FUNCTION + + FUNCTION FMADD_RIM(R,MA) + USE FMVALS + TYPE ( FM ) FMADD_RIM + TYPE ( IM ) MA + REAL R + INTENT (IN) :: R,MA + CALL FMSP2M(R,MTFM) + CALL IMI2FM(MA%MIM,MUFM) + CALL FMADD(MTFM,MUFM,FMADD_RIM%MFM) + END FUNCTION + + FUNCTION FMADD_RZM(R,MA) + USE FMVALS + TYPE ( ZM ) MA,FMADD_RZM + REAL R + INTENT (IN) :: R,MA + CALL FMSP2M(R,MTFM) + CALL FMI2M(0,MUFM) + CALL ZMCMPX(MTFM,MUFM,MTZM) + CALL ZMADD(MTZM,MA%MZM,FMADD_RZM%MZM) + END FUNCTION + + FUNCTION FMADD_DFM(D,MA) + USE FMVALS + TYPE ( FM ) MA,FMADD_DFM + DOUBLE PRECISION D + INTENT (IN) :: D,MA + CALL FMDP2M(D,MTFM) + CALL FMADD(MTFM,MA%MFM,FMADD_DFM%MFM) + END FUNCTION + + FUNCTION FMADD_DIM(D,MA) + USE FMVALS + TYPE ( FM ) FMADD_DIM + TYPE ( IM ) MA + DOUBLE PRECISION D + INTENT (IN) :: D,MA + CALL FMDP2M(D,MTFM) + CALL IMI2FM(MA%MIM,MUFM) + CALL FMADD(MTFM,MUFM,FMADD_DIM%MFM) + END FUNCTION + + FUNCTION FMADD_DZM(D,MA) + USE FMVALS + TYPE ( ZM ) MA,FMADD_DZM + DOUBLE PRECISION D + INTENT (IN) :: D,MA + CALL FMDP2M(D,MTFM) + CALL FMI2M(0,MUFM) + CALL ZMCMPX(MTFM,MUFM,MTZM) + CALL ZMADD(MTZM,MA%MZM,FMADD_DZM%MZM) + END FUNCTION + + FUNCTION FMADD_ZFM(Z,MA) + USE FMVALS + TYPE ( ZM ) FMADD_ZFM + TYPE ( FM ) MA + COMPLEX Z + INTENT (IN) :: Z,MA + CALL ZMZ2M(Z,MTZM) + CALL FMI2M(0,MUFM) + CALL ZMCMPX(MA%MFM,MUFM,MUZM) + CALL ZMADD(MTZM,MUZM,FMADD_ZFM%MZM) + END FUNCTION + + FUNCTION FMADD_ZIM(Z,MA) + USE FMVALS + TYPE ( ZM ) FMADD_ZIM + TYPE ( IM ) MA + COMPLEX Z + INTENT (IN) :: Z,MA + CALL ZMZ2M(Z,MTZM) + CALL IMI2FM(MA%MIM,MTFM) + CALL FMI2M(0,MUFM) + CALL ZMCMPX(MTFM,MUFM,MUZM) + CALL ZMADD(MTZM,MUZM,FMADD_ZIM%MZM) + END FUNCTION + + FUNCTION FMADD_ZZM(Z,MA) + USE FMVALS + TYPE ( ZM ) MA,FMADD_ZZM + COMPLEX Z + INTENT (IN) :: Z,MA + CALL ZMZ2M(Z,MTZM) + CALL ZMADD(MTZM,MA%MZM,FMADD_ZZM%MZM) + END FUNCTION + + FUNCTION FMADD_CFM(C,MA) + USE FMVALS + TYPE ( ZM ) FMADD_CFM + TYPE ( FM ) MA + COMPLEX (KIND(0.0D0)) :: C + INTENT (IN) :: C,MA + CALL FMDP2M(REAL(C,KIND(0.0D0)),MTFM) + CALL FMDP2M(AIMAG(C),MUFM) + CALL ZMCMPX(MTFM,MUFM,MTZM) + CALL FMI2M(0,MUFM) + CALL ZMCMPX(MA%MFM,MUFM,MUZM) + CALL ZMADD(MTZM,MUZM,FMADD_CFM%MZM) + END FUNCTION + + FUNCTION FMADD_CIM(C,MA) + USE FMVALS + TYPE ( ZM ) FMADD_CIM + TYPE ( IM ) MA + COMPLEX (KIND(0.0D0)) :: C + INTENT (IN) :: C,MA + CALL FMDP2M(REAL(C,KIND(0.0D0)),MTFM) + CALL FMDP2M(AIMAG(C),MUFM) + CALL ZMCMPX(MTFM,MUFM,MTZM) + CALL IMI2FM(MA%MIM,MTFM) + CALL FMI2M(0,MUFM) + CALL ZMCMPX(MTFM,MUFM,MUZM) + CALL ZMADD(MTZM,MUZM,FMADD_CIM%MZM) + END FUNCTION + + FUNCTION FMADD_CZM(C,MA) + USE FMVALS + TYPE ( ZM ) MA,FMADD_CZM + COMPLEX (KIND(0.0D0)) :: C + INTENT (IN) :: C,MA + CALL FMDP2M(REAL(C,KIND(0.0D0)),MTFM) + CALL FMDP2M(AIMAG(C),MUFM) + CALL ZMCMPX(MTFM,MUFM,MTZM) + CALL ZMADD(MTZM,MA%MZM,FMADD_CZM%MZM) + END FUNCTION + + FUNCTION FMADD_FMI(MA,IVAL) + USE FMVALS + TYPE ( FM ) MA,FMADD_FMI + INTEGER IVAL + INTENT (IN) :: MA,IVAL + CALL FMI2M(IVAL,MTFM) + CALL FMADD(MA%MFM,MTFM,FMADD_FMI%MFM) + END FUNCTION + + FUNCTION FMADD_FMR(MA,R) + USE FMVALS + TYPE ( FM ) MA,FMADD_FMR + REAL R + INTENT (IN) :: MA,R + CALL FMSP2M(R,MTFM) + CALL FMADD(MA%MFM,MTFM,FMADD_FMR%MFM) + END FUNCTION + + FUNCTION FMADD_FMD(MA,D) + USE FMVALS + TYPE ( FM ) MA,FMADD_FMD + DOUBLE PRECISION D + INTENT (IN) :: MA,D + CALL FMDP2M(D,MTFM) + CALL FMADD(MA%MFM,MTFM,FMADD_FMD%MFM) + END FUNCTION + + FUNCTION FMADD_FMZ(MA,Z) + USE FMVALS + TYPE ( ZM ) FMADD_FMZ + TYPE ( FM ) MA + COMPLEX Z + INTENT (IN) :: MA,Z + CALL ZMZ2M(Z,MTZM) + CALL FMI2M(0,MUFM) + CALL ZMCMPX(MA%MFM,MUFM,MUZM) + CALL ZMADD(MUZM,MTZM,FMADD_FMZ%MZM) + END FUNCTION + + FUNCTION FMADD_FMC(MA,C) + USE FMVALS + TYPE ( ZM ) FMADD_FMC + TYPE ( FM ) MA + COMPLEX (KIND(0.0D0)) :: C + INTENT (IN) :: MA,C + CALL FMDP2M(REAL(C,KIND(0.0D0)),MTFM) + CALL FMDP2M(AIMAG(C),MUFM) + CALL ZMCMPX(MTFM,MUFM,MTZM) + CALL FMI2M(0,MUFM) + CALL ZMCMPX(MA%MFM,MUFM,MUZM) + CALL ZMADD(MUZM,MTZM,FMADD_FMC%MZM) + END FUNCTION + + FUNCTION FMADD_FMFM(MA,MB) + USE FMVALS + TYPE ( FM ) MA,MB,FMADD_FMFM + INTENT (IN) :: MA,MB + CALL FMADD(MA%MFM,MB%MFM,FMADD_FMFM%MFM) + END FUNCTION + + FUNCTION FMADD_FMIM(MA,MB) + USE FMVALS + TYPE ( FM ) MA,FMADD_FMIM + TYPE ( IM ) MB + INTENT (IN) :: MA,MB + CALL IMI2FM(MB%MIM,MTFM) + CALL FMADD(MA%MFM,MTFM,FMADD_FMIM%MFM) + END FUNCTION + + FUNCTION FMADD_FMZM(MA,MB) + USE FMVALS + TYPE ( FM ) MA + TYPE ( ZM ) MB,FMADD_FMZM + INTENT (IN) :: MA,MB + CALL FMI2M(0,MTFM) + CALL ZMCMPX(MA%MFM,MTFM,MTZM) + CALL ZMADD(MTZM,MB%MZM,FMADD_FMZM%MZM) + END FUNCTION + + FUNCTION FMADD_IMI(MA,IVAL) + USE FMVALS + TYPE ( IM ) MA,FMADD_IMI + INTEGER IVAL + INTENT (IN) :: MA,IVAL + CALL IMI2M(IVAL,MTIM) + CALL IMADD(MA%MIM,MTIM,FMADD_IMI%MIM) + END FUNCTION + + FUNCTION FMADD_IMR(MA,R) + USE FMVALS + TYPE ( FM ) FMADD_IMR + TYPE ( IM ) MA + REAL R + INTENT (IN) :: MA,R + CALL FMSP2M(R,MTFM) + CALL IMI2FM(MA%MIM,MUFM) + CALL FMADD(MUFM,MTFM,FMADD_IMR%MFM) + END FUNCTION + + FUNCTION FMADD_IMD(MA,D) + USE FMVALS + TYPE ( FM ) FMADD_IMD + TYPE ( IM ) MA + DOUBLE PRECISION D + INTENT (IN) :: MA,D + CALL FMDP2M(D,MTFM) + CALL IMI2FM(MA%MIM,MUFM) + CALL FMADD(MUFM,MTFM,FMADD_IMD%MFM) + END FUNCTION + + FUNCTION FMADD_IMZ(MA,Z) + USE FMVALS + TYPE ( ZM ) FMADD_IMZ + TYPE ( IM ) MA + COMPLEX Z + INTENT (IN) :: MA,Z + CALL ZMZ2M(Z,MTZM) + CALL IMI2FM(MA%MIM,MTFM) + CALL FMI2M(0,MUFM) + CALL ZMCMPX(MTFM,MUFM,MUZM) + CALL ZMADD(MUZM,MTZM,FMADD_IMZ%MZM) + END FUNCTION + + FUNCTION FMADD_IMC(MA,C) + USE FMVALS + TYPE ( ZM ) FMADD_IMC + TYPE ( IM ) MA + COMPLEX (KIND(0.0D0)) :: C + INTENT (IN) :: MA,C + CALL FMDP2M(REAL(C,KIND(0.0D0)),MTFM) + CALL FMDP2M(AIMAG(C),MUFM) + CALL ZMCMPX(MTFM,MUFM,MTZM) + CALL IMI2FM(MA%MIM,MTFM) + CALL FMI2M(0,MUFM) + CALL ZMCMPX(MTFM,MUFM,MUZM) + CALL ZMADD(MUZM,MTZM,FMADD_IMC%MZM) + END FUNCTION + + FUNCTION FMADD_IMFM(MA,MB) + USE FMVALS + TYPE ( IM ) MA + TYPE ( FM ) MB,FMADD_IMFM + INTENT (IN) :: MA,MB + CALL IMI2FM(MA%MIM,MTFM) + CALL FMADD(MTFM,MB%MFM,FMADD_IMFM%MFM) + END FUNCTION + + FUNCTION FMADD_IMIM(MA,MB) + USE FMVALS + TYPE ( IM ) MA,MB,FMADD_IMIM + INTENT (IN) :: MA,MB + CALL IMADD(MA%MIM,MB%MIM,FMADD_IMIM%MIM) + END FUNCTION + + FUNCTION FMADD_IMZM(MA,MB) + USE FMVALS + TYPE ( IM ) MA + TYPE ( ZM ) MB,FMADD_IMZM + INTENT (IN) :: MA,MB + CALL IMI2FM(MA%MIM,MTFM) + CALL FMI2M(0,MUFM) + CALL ZMCMPX(MTFM,MUFM,MUZM) + CALL ZMADD(MUZM,MB%MZM,FMADD_IMZM%MZM) + END FUNCTION + + FUNCTION FMADD_ZMI(MA,IVAL) + USE FMVALS + TYPE ( ZM ) MA,FMADD_ZMI + INTEGER IVAL + INTENT (IN) :: MA,IVAL + CALL FMI2M(IVAL,MTFM) + CALL FMI2M(0,MUFM) + CALL ZMCMPX(MTFM,MUFM,MTZM) + CALL ZMADD(MA%MZM,MTZM,FMADD_ZMI%MZM) + END FUNCTION + + FUNCTION FMADD_ZMR(MA,R) + USE FMVALS + TYPE ( ZM ) MA,FMADD_ZMR + REAL R + INTENT (IN) :: MA,R + CALL FMSP2M(R,MTFM) + CALL FMI2M(0,MUFM) + CALL ZMCMPX(MTFM,MUFM,MTZM) + CALL ZMADD(MA%MZM,MTZM,FMADD_ZMR%MZM) + END FUNCTION + + FUNCTION FMADD_ZMD(MA,D) + USE FMVALS + TYPE ( ZM ) MA,FMADD_ZMD + DOUBLE PRECISION D + INTENT (IN) :: MA,D + CALL FMDP2M(D,MTFM) + CALL FMI2M(0,MUFM) + CALL ZMCMPX(MTFM,MUFM,MTZM) + CALL ZMADD(MA%MZM,MTZM,FMADD_ZMD%MZM) + END FUNCTION + + FUNCTION FMADD_ZMZ(MA,Z) + USE FMVALS + TYPE ( ZM ) MA,FMADD_ZMZ + COMPLEX Z + INTENT (IN) :: MA,Z + CALL ZMZ2M(Z,MTZM) + CALL ZMADD(MA%MZM,MTZM,FMADD_ZMZ%MZM) + END FUNCTION + + FUNCTION FMADD_ZMC(MA,C) + USE FMVALS + TYPE ( ZM ) MA,FMADD_ZMC + COMPLEX (KIND(0.0D0)) :: C + INTENT (IN) :: MA,C + CALL FMDP2M(REAL(C,KIND(0.0D0)),MTFM) + CALL FMDP2M(AIMAG(C),MUFM) + CALL ZMCMPX(MTFM,MUFM,MTZM) + CALL ZMADD(MA%MZM,MTZM,FMADD_ZMC%MZM) + END FUNCTION + + FUNCTION FMADD_ZMFM(MA,MB) + USE FMVALS + TYPE ( FM ) MB + TYPE ( ZM ) MA,FMADD_ZMFM + INTENT (IN) :: MA,MB + CALL FMI2M(0,MTFM) + CALL ZMCMPX(MB%MFM,MTFM,MTZM) + CALL ZMADD(MA%MZM,MTZM,FMADD_ZMFM%MZM) + END FUNCTION + + FUNCTION FMADD_ZMIM(MA,MB) + USE FMVALS + TYPE ( IM ) MB + TYPE ( ZM ) MA,FMADD_ZMIM + INTENT (IN) :: MA,MB + CALL IMI2FM(MB%MIM,MTFM) + CALL FMI2M(0,MUFM) + CALL ZMCMPX(MTFM,MUFM,MUZM) + CALL ZMADD(MA%MZM,MUZM,FMADD_ZMIM%MZM) + END FUNCTION + + FUNCTION FMADD_ZMZM(MA,MB) + USE FMVALS + TYPE ( ZM ) MA,MB,FMADD_ZMZM + INTENT (IN) :: MA,MB + CALL ZMADD(MA%MZM,MB%MZM,FMADD_ZMZM%MZM) + END FUNCTION + + FUNCTION FMADD_FM(MA) + USE FMVALS + TYPE ( FM ) MA,FMADD_FM + INTENT (IN) :: MA + CALL FMEQ(MA%MFM,FMADD_FM%MFM) + END FUNCTION + + FUNCTION FMADD_IM(MA) + USE FMVALS + TYPE ( IM ) MA,FMADD_IM + INTENT (IN) :: MA + CALL IMEQ(MA%MIM,FMADD_IM%MIM) + END FUNCTION + + FUNCTION FMADD_ZM(MA) + USE FMVALS + TYPE ( ZM ) MA,FMADD_ZM + INTENT (IN) :: MA + CALL ZMEQ(MA%MZM,FMADD_ZM%MZM) + END FUNCTION + +! - + + FUNCTION FMSUB_IFM(IVAL,MA) + USE FMVALS + TYPE ( FM ) MA,FMSUB_IFM + INTEGER IVAL + INTENT (IN) :: IVAL,MA + CALL FMI2M(IVAL,MTFM) + CALL FMSUB(MTFM,MA%MFM,FMSUB_IFM%MFM) + END FUNCTION + + FUNCTION FMSUB_IIM(IVAL,MA) + USE FMVALS + TYPE ( IM ) MA,FMSUB_IIM + INTEGER IVAL + INTENT (IN) :: IVAL,MA + CALL IMI2M(IVAL,MTIM) + CALL IMSUB(MTIM,MA%MIM,FMSUB_IIM%MIM) + END FUNCTION + + FUNCTION FMSUB_IZM(IVAL,MA) + USE FMVALS + TYPE ( ZM ) MA,FMSUB_IZM + INTEGER IVAL + INTENT (IN) :: IVAL,MA + CALL FMI2M(IVAL,MTFM) + CALL FMI2M(0,MUFM) + CALL ZMCMPX(MTFM,MUFM,MTZM) + CALL ZMSUB(MTZM,MA%MZM,FMSUB_IZM%MZM) + END FUNCTION + + FUNCTION FMSUB_RFM(R,MA) + USE FMVALS + TYPE ( FM ) MA,FMSUB_RFM + REAL R + INTENT (IN) :: R,MA + CALL FMSP2M(R,MTFM) + CALL FMSUB(MTFM,MA%MFM,FMSUB_RFM%MFM) + END FUNCTION + + FUNCTION FMSUB_RIM(R,MA) + USE FMVALS + TYPE ( FM ) FMSUB_RIM + TYPE ( IM ) MA + REAL R + INTENT (IN) :: R,MA + CALL FMSP2M(R,MTFM) + CALL IMI2FM(MA%MIM,MUFM) + CALL FMSUB(MTFM,MUFM,FMSUB_RIM%MFM) + END FUNCTION + + FUNCTION FMSUB_RZM(R,MA) + USE FMVALS + TYPE ( ZM ) MA,FMSUB_RZM + REAL R + INTENT (IN) :: R,MA + CALL FMSP2M(R,MTFM) + CALL FMI2M(0,MUFM) + CALL ZMCMPX(MTFM,MUFM,MTZM) + CALL ZMSUB(MTZM,MA%MZM,FMSUB_RZM%MZM) + END FUNCTION + + FUNCTION FMSUB_DFM(D,MA) + USE FMVALS + TYPE ( FM ) MA,FMSUB_DFM + DOUBLE PRECISION D + INTENT (IN) :: D,MA + CALL FMDP2M(D,MTFM) + CALL FMSUB(MTFM,MA%MFM,FMSUB_DFM%MFM) + END FUNCTION + + FUNCTION FMSUB_DIM(D,MA) + USE FMVALS + TYPE ( FM ) FMSUB_DIM + TYPE ( IM ) MA + DOUBLE PRECISION D + INTENT (IN) :: D,MA + CALL FMDP2M(D,MTFM) + CALL IMI2FM(MA%MIM,MUFM) + CALL FMSUB(MTFM,MUFM,FMSUB_DIM%MFM) + END FUNCTION + + FUNCTION FMSUB_DZM(D,MA) + USE FMVALS + TYPE ( ZM ) MA,FMSUB_DZM + DOUBLE PRECISION D + INTENT (IN) :: D,MA + CALL FMDP2M(D,MTFM) + CALL FMI2M(0,MUFM) + CALL ZMCMPX(MTFM,MUFM,MTZM) + CALL ZMSUB(MTZM,MA%MZM,FMSUB_DZM%MZM) + END FUNCTION + + FUNCTION FMSUB_ZFM(Z,MA) + USE FMVALS + TYPE ( ZM ) FMSUB_ZFM + TYPE ( FM ) MA + COMPLEX Z + INTENT (IN) :: Z,MA + CALL ZMZ2M(Z,MTZM) + CALL FMI2M(0,MUFM) + CALL ZMCMPX(MA%MFM,MUFM,MUZM) + CALL ZMSUB(MTZM,MUZM,FMSUB_ZFM%MZM) + END FUNCTION + + FUNCTION FMSUB_ZIM(Z,MA) + USE FMVALS + TYPE ( ZM ) FMSUB_ZIM + TYPE ( IM ) MA + COMPLEX Z + INTENT (IN) :: Z,MA + CALL ZMZ2M(Z,MTZM) + CALL IMI2FM(MA%MIM,MTFM) + CALL FMI2M(0,MUFM) + CALL ZMCMPX(MTFM,MUFM,MUZM) + CALL ZMSUB(MTZM,MUZM,FMSUB_ZIM%MZM) + END FUNCTION + + FUNCTION FMSUB_ZZM(Z,MA) + USE FMVALS + TYPE ( ZM ) MA,FMSUB_ZZM + COMPLEX Z + INTENT (IN) :: Z,MA + CALL ZMZ2M(Z,MTZM) + CALL ZMSUB(MTZM,MA%MZM,FMSUB_ZZM%MZM) + END FUNCTION + + FUNCTION FMSUB_CFM(C,MA) + USE FMVALS + TYPE ( ZM ) FMSUB_CFM + TYPE ( FM ) MA + COMPLEX (KIND(0.0D0)) :: C + INTENT (IN) :: C,MA + CALL FMDP2M(REAL(C,KIND(0.0D0)),MTFM) + CALL FMDP2M(AIMAG(C),MUFM) + CALL ZMCMPX(MTFM,MUFM,MTZM) + CALL FMI2M(0,MUFM) + CALL ZMCMPX(MA%MFM,MUFM,MUZM) + CALL ZMSUB(MTZM,MUZM,FMSUB_CFM%MZM) + END FUNCTION + + FUNCTION FMSUB_CIM(C,MA) + USE FMVALS + TYPE ( ZM ) FMSUB_CIM + TYPE ( IM ) MA + COMPLEX (KIND(0.0D0)) :: C + INTENT (IN) :: C,MA + CALL FMDP2M(REAL(C,KIND(0.0D0)),MTFM) + CALL FMDP2M(AIMAG(C),MUFM) + CALL ZMCMPX(MTFM,MUFM,MTZM) + CALL IMI2FM(MA%MIM,MTFM) + CALL FMI2M(0,MUFM) + CALL ZMCMPX(MTFM,MUFM,MUZM) + CALL ZMSUB(MTZM,MUZM,FMSUB_CIM%MZM) + END FUNCTION + + FUNCTION FMSUB_CZM(C,MA) + USE FMVALS + TYPE ( ZM ) MA,FMSUB_CZM + COMPLEX (KIND(0.0D0)) :: C + INTENT (IN) :: C,MA + CALL FMDP2M(REAL(C,KIND(0.0D0)),MTFM) + CALL FMDP2M(AIMAG(C),MUFM) + CALL ZMCMPX(MTFM,MUFM,MTZM) + CALL ZMSUB(MTZM,MA%MZM,FMSUB_CZM%MZM) + END FUNCTION + + FUNCTION FMSUB_FMI(MA,IVAL) + USE FMVALS + TYPE ( FM ) MA,FMSUB_FMI + INTEGER IVAL + INTENT (IN) :: MA,IVAL + CALL FMI2M(IVAL,MTFM) + CALL FMSUB(MA%MFM,MTFM,FMSUB_FMI%MFM) + END FUNCTION + + FUNCTION FMSUB_FMR(MA,R) + USE FMVALS + TYPE ( FM ) MA,FMSUB_FMR + REAL R + INTENT (IN) :: MA,R + CALL FMSP2M(R,MTFM) + CALL FMSUB(MA%MFM,MTFM,FMSUB_FMR%MFM) + END FUNCTION + + FUNCTION FMSUB_FMD(MA,D) + USE FMVALS + TYPE ( FM ) MA,FMSUB_FMD + DOUBLE PRECISION D + INTENT (IN) :: MA,D + CALL FMDP2M(D,MTFM) + CALL FMSUB(MA%MFM,MTFM,FMSUB_FMD%MFM) + END FUNCTION + + FUNCTION FMSUB_FMZ(MA,Z) + USE FMVALS + TYPE ( ZM ) FMSUB_FMZ + TYPE ( FM ) MA + COMPLEX Z + INTENT (IN) :: MA,Z + CALL ZMZ2M(Z,MTZM) + CALL FMI2M(0,MUFM) + CALL ZMCMPX(MA%MFM,MUFM,MUZM) + CALL ZMSUB(MUZM,MTZM,FMSUB_FMZ%MZM) + END FUNCTION + + FUNCTION FMSUB_FMC(MA,C) + USE FMVALS + TYPE ( ZM ) FMSUB_FMC + TYPE ( FM ) MA + COMPLEX (KIND(0.0D0)) :: C + INTENT (IN) :: MA,C + CALL FMDP2M(REAL(C,KIND(0.0D0)),MTFM) + CALL FMDP2M(AIMAG(C),MUFM) + CALL ZMCMPX(MTFM,MUFM,MTZM) + CALL FMI2M(0,MUFM) + CALL ZMCMPX(MA%MFM,MUFM,MUZM) + CALL ZMSUB(MUZM,MTZM,FMSUB_FMC%MZM) + END FUNCTION + + FUNCTION FMSUB_FMFM(MA,MB) + USE FMVALS + TYPE ( FM ) MA,MB,FMSUB_FMFM + INTENT (IN) :: MA,MB + CALL FMSUB(MA%MFM,MB%MFM,FMSUB_FMFM%MFM) + END FUNCTION + + FUNCTION FMSUB_FMIM(MA,MB) + USE FMVALS + TYPE ( FM ) MA,FMSUB_FMIM + TYPE ( IM ) MB + INTENT (IN) :: MA,MB + CALL IMI2FM(MB%MIM,MTFM) + CALL FMSUB(MA%MFM,MTFM,FMSUB_FMIM%MFM) + END FUNCTION + + FUNCTION FMSUB_FMZM(MA,MB) + USE FMVALS + TYPE ( FM ) MA + TYPE ( ZM ) MB,FMSUB_FMZM + INTENT (IN) :: MA,MB + CALL FMI2M(0,MTFM) + CALL ZMCMPX(MA%MFM,MTFM,MTZM) + CALL ZMSUB(MTZM,MB%MZM,FMSUB_FMZM%MZM) + END FUNCTION + + FUNCTION FMSUB_IMI(MA,IVAL) + USE FMVALS + TYPE ( IM ) MA,FMSUB_IMI + INTEGER IVAL + INTENT (IN) :: MA,IVAL + CALL IMI2M(IVAL,MTIM) + CALL IMSUB(MA%MIM,MTIM,FMSUB_IMI%MIM) + END FUNCTION + + FUNCTION FMSUB_IMR(MA,R) + USE FMVALS + TYPE ( FM ) FMSUB_IMR + TYPE ( IM ) MA + REAL R + INTENT (IN) :: MA,R + CALL FMSP2M(R,MTFM) + CALL IMI2FM(MA%MIM,MUFM) + CALL FMSUB(MUFM,MTFM,FMSUB_IMR%MFM) + END FUNCTION + + FUNCTION FMSUB_IMD(MA,D) + USE FMVALS + TYPE ( FM ) FMSUB_IMD + TYPE ( IM ) MA + DOUBLE PRECISION D + INTENT (IN) :: MA,D + CALL FMDP2M(D,MTFM) + CALL IMI2FM(MA%MIM,MUFM) + CALL FMSUB(MUFM,MTFM,FMSUB_IMD%MFM) + END FUNCTION + + FUNCTION FMSUB_IMZ(MA,Z) + USE FMVALS + TYPE ( ZM ) FMSUB_IMZ + TYPE ( IM ) MA + COMPLEX Z + INTENT (IN) :: MA,Z + CALL ZMZ2M(Z,MTZM) + CALL IMI2FM(MA%MIM,MTFM) + CALL FMI2M(0,MUFM) + CALL ZMCMPX(MTFM,MUFM,MUZM) + CALL ZMSUB(MUZM,MTZM,FMSUB_IMZ%MZM) + END FUNCTION + + FUNCTION FMSUB_IMC(MA,C) + USE FMVALS + TYPE ( ZM ) FMSUB_IMC + TYPE ( IM ) MA + COMPLEX (KIND(0.0D0)) :: C + INTENT (IN) :: MA,C + CALL FMDP2M(REAL(C,KIND(0.0D0)),MTFM) + CALL FMDP2M(AIMAG(C),MUFM) + CALL ZMCMPX(MTFM,MUFM,MTZM) + CALL IMI2FM(MA%MIM,MTFM) + CALL FMI2M(0,MUFM) + CALL ZMCMPX(MTFM,MUFM,MUZM) + CALL ZMSUB(MUZM,MTZM,FMSUB_IMC%MZM) + END FUNCTION + + FUNCTION FMSUB_IMFM(MA,MB) + USE FMVALS + TYPE ( IM ) MA + TYPE ( FM ) MB,FMSUB_IMFM + INTENT (IN) :: MA,MB + CALL IMI2FM(MA%MIM,MTFM) + CALL FMSUB(MTFM,MB%MFM,FMSUB_IMFM%MFM) + END FUNCTION + + FUNCTION FMSUB_IMIM(MA,MB) + USE FMVALS + TYPE ( IM ) MA,MB,FMSUB_IMIM + INTENT (IN) :: MA,MB + CALL IMSUB(MA%MIM,MB%MIM,FMSUB_IMIM%MIM) + END FUNCTION + + FUNCTION FMSUB_IMZM(MA,MB) + USE FMVALS + TYPE ( IM ) MA + TYPE ( ZM ) MB,FMSUB_IMZM + INTENT (IN) :: MA,MB + CALL IMI2FM(MA%MIM,MTFM) + CALL FMI2M(0,MUFM) + CALL ZMCMPX(MTFM,MUFM,MUZM) + CALL ZMSUB(MUZM,MB%MZM,FMSUB_IMZM%MZM) + END FUNCTION + + FUNCTION FMSUB_ZMI(MA,IVAL) + USE FMVALS + TYPE ( ZM ) MA,FMSUB_ZMI + INTEGER IVAL + INTENT (IN) :: MA,IVAL + CALL FMI2M(IVAL,MTFM) + CALL FMI2M(0,MUFM) + CALL ZMCMPX(MTFM,MUFM,MTZM) + CALL ZMSUB(MA%MZM,MTZM,FMSUB_ZMI%MZM) + END FUNCTION + + FUNCTION FMSUB_ZMR(MA,R) + USE FMVALS + TYPE ( ZM ) MA,FMSUB_ZMR + REAL R + INTENT (IN) :: MA,R + CALL FMSP2M(R,MTFM) + CALL FMI2M(0,MUFM) + CALL ZMCMPX(MTFM,MUFM,MTZM) + CALL ZMSUB(MA%MZM,MTZM,FMSUB_ZMR%MZM) + END FUNCTION + + FUNCTION FMSUB_ZMD(MA,D) + USE FMVALS + TYPE ( ZM ) MA,FMSUB_ZMD + DOUBLE PRECISION D + INTENT (IN) :: MA,D + CALL FMDP2M(D,MTFM) + CALL FMI2M(0,MUFM) + CALL ZMCMPX(MTFM,MUFM,MTZM) + CALL ZMSUB(MA%MZM,MTZM,FMSUB_ZMD%MZM) + END FUNCTION + + FUNCTION FMSUB_ZMZ(MA,Z) + USE FMVALS + TYPE ( ZM ) MA,FMSUB_ZMZ + COMPLEX Z + INTENT (IN) :: MA,Z + CALL ZMZ2M(Z,MTZM) + CALL ZMSUB(MA%MZM,MTZM,FMSUB_ZMZ%MZM) + END FUNCTION + + FUNCTION FMSUB_ZMC(MA,C) + USE FMVALS + TYPE ( ZM ) MA,FMSUB_ZMC + COMPLEX (KIND(0.0D0)) :: C + INTENT (IN) :: MA,C + CALL FMDP2M(REAL(C,KIND(0.0D0)),MTFM) + CALL FMDP2M(AIMAG(C),MUFM) + CALL ZMCMPX(MTFM,MUFM,MTZM) + CALL ZMSUB(MA%MZM,MTZM,FMSUB_ZMC%MZM) + END FUNCTION + + FUNCTION FMSUB_ZMFM(MA,MB) + USE FMVALS + TYPE ( FM ) MB + TYPE ( ZM ) MA,FMSUB_ZMFM + INTENT (IN) :: MA,MB + CALL FMI2M(0,MTFM) + CALL ZMCMPX(MB%MFM,MTFM,MTZM) + CALL ZMSUB(MA%MZM,MTZM,FMSUB_ZMFM%MZM) + END FUNCTION + + FUNCTION FMSUB_ZMIM(MA,MB) + USE FMVALS + TYPE ( IM ) MB + TYPE ( ZM ) MA,FMSUB_ZMIM + INTENT (IN) :: MA,MB + CALL IMI2FM(MB%MIM,MTFM) + CALL FMI2M(0,MUFM) + CALL ZMCMPX(MTFM,MUFM,MUZM) + CALL ZMSUB(MA%MZM,MUZM,FMSUB_ZMIM%MZM) + END FUNCTION + + FUNCTION FMSUB_ZMZM(MA,MB) + USE FMVALS + TYPE ( ZM ) MA,MB,FMSUB_ZMZM + INTENT (IN) :: MA,MB + CALL ZMSUB(MA%MZM,MB%MZM,FMSUB_ZMZM%MZM) + END FUNCTION + + FUNCTION FMSUB_FM(MA) + USE FMVALS + TYPE ( FM ) MA,FMSUB_FM + INTENT (IN) :: MA + CALL FMEQ(MA%MFM,MTFM) + IF (MTFM(1) /= MUNKNO .AND. MTFM(2) /= 0) & + MTFM(-1) = -MTFM(-1) + CALL FMEQ(MTFM,FMSUB_FM%MFM) + END FUNCTION + + FUNCTION FMSUB_IM(MA) + USE FMVALS + TYPE ( IM ) MA,FMSUB_IM + INTENT (IN) :: MA + CALL IMEQ(MA%MIM,MTIM) + IF (MTIM(1) /= MUNKNO .AND. MTIM(2) /= 0) & + MTIM(-1) = -MTIM(-1) + CALL IMEQ(MTIM,FMSUB_IM%MIM) + END FUNCTION + + FUNCTION FMSUB_ZM(MA) + USE FMVALS + TYPE ( ZM ) MA,FMSUB_ZM + INTENT (IN) :: MA + CALL ZMEQ(MA%MZM,MTZM) + IF (MTZM(1) /= MUNKNO .AND. MTZM(2) /= 0) & + MTZM(-1) = -MTZM(-1) + IF (MTZM(KPTIMU+1) /= MUNKNO .AND. MTZM(KPTIMU+2) /= 0) THEN + MTZM(KPTIMU-1) = -MTZM(KPTIMU-1) + ENDIF + CALL ZMEQ(MTZM,FMSUB_ZM%MZM) + END FUNCTION + + END MODULE FMZM_5 + + MODULE FMZM_6 + USE FMZM_1 + + INTERFACE OPERATOR (*) + MODULE PROCEDURE FMMPY_IFM + MODULE PROCEDURE FMMPY_IIM + MODULE PROCEDURE FMMPY_IZM + MODULE PROCEDURE FMMPY_RFM + MODULE PROCEDURE FMMPY_RIM + MODULE PROCEDURE FMMPY_RZM + MODULE PROCEDURE FMMPY_DFM + MODULE PROCEDURE FMMPY_DIM + MODULE PROCEDURE FMMPY_DZM + MODULE PROCEDURE FMMPY_ZFM + MODULE PROCEDURE FMMPY_ZIM + MODULE PROCEDURE FMMPY_ZZM + MODULE PROCEDURE FMMPY_CFM + MODULE PROCEDURE FMMPY_CIM + MODULE PROCEDURE FMMPY_CZM + MODULE PROCEDURE FMMPY_FMI + MODULE PROCEDURE FMMPY_FMR + MODULE PROCEDURE FMMPY_FMD + MODULE PROCEDURE FMMPY_FMZ + MODULE PROCEDURE FMMPY_FMC + MODULE PROCEDURE FMMPY_FMFM + MODULE PROCEDURE FMMPY_FMIM + MODULE PROCEDURE FMMPY_FMZM + MODULE PROCEDURE FMMPY_IMI + MODULE PROCEDURE FMMPY_IMR + MODULE PROCEDURE FMMPY_IMD + MODULE PROCEDURE FMMPY_IMZ + MODULE PROCEDURE FMMPY_IMC + MODULE PROCEDURE FMMPY_IMFM + MODULE PROCEDURE FMMPY_IMIM + MODULE PROCEDURE FMMPY_IMZM + MODULE PROCEDURE FMMPY_ZMI + MODULE PROCEDURE FMMPY_ZMR + MODULE PROCEDURE FMMPY_ZMD + MODULE PROCEDURE FMMPY_ZMZ + MODULE PROCEDURE FMMPY_ZMC + MODULE PROCEDURE FMMPY_ZMFM + MODULE PROCEDURE FMMPY_ZMIM + MODULE PROCEDURE FMMPY_ZMZM + END INTERFACE + + INTERFACE OPERATOR (/) + MODULE PROCEDURE FMDIV_IFM + MODULE PROCEDURE FMDIV_IIM + MODULE PROCEDURE FMDIV_IZM + MODULE PROCEDURE FMDIV_RFM + MODULE PROCEDURE FMDIV_RIM + MODULE PROCEDURE FMDIV_RZM + MODULE PROCEDURE FMDIV_DFM + MODULE PROCEDURE FMDIV_DIM + MODULE PROCEDURE FMDIV_DZM + MODULE PROCEDURE FMDIV_ZFM + MODULE PROCEDURE FMDIV_ZIM + MODULE PROCEDURE FMDIV_ZZM + MODULE PROCEDURE FMDIV_CFM + MODULE PROCEDURE FMDIV_CIM + MODULE PROCEDURE FMDIV_CZM + MODULE PROCEDURE FMDIV_FMI + MODULE PROCEDURE FMDIV_FMR + MODULE PROCEDURE FMDIV_FMD + MODULE PROCEDURE FMDIV_FMZ + MODULE PROCEDURE FMDIV_FMC + MODULE PROCEDURE FMDIV_FMFM + MODULE PROCEDURE FMDIV_FMIM + MODULE PROCEDURE FMDIV_FMZM + MODULE PROCEDURE FMDIV_IMI + MODULE PROCEDURE FMDIV_IMR + MODULE PROCEDURE FMDIV_IMD + MODULE PROCEDURE FMDIV_IMZ + MODULE PROCEDURE FMDIV_IMC + MODULE PROCEDURE FMDIV_IMFM + MODULE PROCEDURE FMDIV_IMIM + MODULE PROCEDURE FMDIV_IMZM + MODULE PROCEDURE FMDIV_ZMI + MODULE PROCEDURE FMDIV_ZMR + MODULE PROCEDURE FMDIV_ZMD + MODULE PROCEDURE FMDIV_ZMZ + MODULE PROCEDURE FMDIV_ZMC + MODULE PROCEDURE FMDIV_ZMFM + MODULE PROCEDURE FMDIV_ZMIM + MODULE PROCEDURE FMDIV_ZMZM + END INTERFACE + + CONTAINS + +! * + + FUNCTION FMMPY_IFM(IVAL,MA) + USE FMVALS + TYPE ( FM ) MA,FMMPY_IFM + INTEGER IVAL + INTENT (IN) :: IVAL,MA + CALL FMMPYI(MA%MFM,IVAL,FMMPY_IFM%MFM) + END FUNCTION + + FUNCTION FMMPY_IIM(IVAL,MA) + USE FMVALS + TYPE ( IM ) MA,FMMPY_IIM + INTEGER IVAL + INTENT (IN) :: IVAL,MA + CALL IMMPYI(MA%MIM,IVAL,FMMPY_IIM%MIM) + END FUNCTION + + FUNCTION FMMPY_IZM(IVAL,MA) + USE FMVALS + TYPE ( ZM ) MA,FMMPY_IZM + INTEGER IVAL + INTENT (IN) :: IVAL,MA + CALL ZMMPYI(MA%MZM,IVAL,FMMPY_IZM%MZM) + END FUNCTION + + FUNCTION FMMPY_RFM(R,MA) + USE FMVALS + TYPE ( FM ) MA,FMMPY_RFM + REAL R + INTENT (IN) :: R,MA + CALL FMSP2M(R,MTFM) + CALL FMMPY(MTFM,MA%MFM,FMMPY_RFM%MFM) + END FUNCTION + + FUNCTION FMMPY_RIM(R,MA) + USE FMVALS + TYPE ( FM ) FMMPY_RIM + TYPE ( IM ) MA + REAL R + INTENT (IN) :: R,MA + CALL FMSP2M(R,MTFM) + CALL IMI2FM(MA%MIM,MUFM) + CALL FMMPY(MTFM,MUFM,FMMPY_RIM%MFM) + END FUNCTION + + FUNCTION FMMPY_RZM(R,MA) + USE FMVALS + TYPE ( ZM ) MA,FMMPY_RZM + REAL R + INTENT (IN) :: R,MA + CALL FMSP2M(R,MTFM) + CALL FMI2M(0,MUFM) + CALL ZMCMPX(MTFM,MUFM,MTZM) + CALL ZMMPY(MTZM,MA%MZM,FMMPY_RZM%MZM) + END FUNCTION + + FUNCTION FMMPY_DFM(D,MA) + USE FMVALS + TYPE ( FM ) MA,FMMPY_DFM + DOUBLE PRECISION D + INTENT (IN) :: D,MA + CALL FMDP2M(D,MTFM) + CALL FMMPY(MTFM,MA%MFM,FMMPY_DFM%MFM) + END FUNCTION + + FUNCTION FMMPY_DIM(D,MA) + USE FMVALS + TYPE ( FM ) FMMPY_DIM + TYPE ( IM ) MA + DOUBLE PRECISION D + INTENT (IN) :: D,MA + CALL FMDP2M(D,MTFM) + CALL IMI2FM(MA%MIM,MUFM) + CALL FMMPY(MTFM,MUFM,FMMPY_DIM%MFM) + END FUNCTION + + FUNCTION FMMPY_DZM(D,MA) + USE FMVALS + TYPE ( ZM ) MA,FMMPY_DZM + DOUBLE PRECISION D + INTENT (IN) :: D,MA + CALL FMDP2M(D,MTFM) + CALL FMI2M(0,MUFM) + CALL ZMCMPX(MTFM,MUFM,MTZM) + CALL ZMMPY(MTZM,MA%MZM,FMMPY_DZM%MZM) + END FUNCTION + + FUNCTION FMMPY_ZFM(Z,MA) + USE FMVALS + TYPE ( ZM ) FMMPY_ZFM + TYPE ( FM ) MA + COMPLEX Z + INTENT (IN) :: Z,MA + CALL ZMZ2M(Z,MTZM) + CALL FMI2M(0,MUFM) + CALL ZMCMPX(MA%MFM,MUFM,MUZM) + CALL ZMMPY(MTZM,MUZM,FMMPY_ZFM%MZM) + END FUNCTION + + FUNCTION FMMPY_ZIM(Z,MA) + USE FMVALS + TYPE ( ZM ) FMMPY_ZIM + TYPE ( IM ) MA + COMPLEX Z + INTENT (IN) :: Z,MA + CALL ZMZ2M(Z,MTZM) + CALL IMI2FM(MA%MIM,MTFM) + CALL FMI2M(0,MUFM) + CALL ZMCMPX(MTFM,MUFM,MUZM) + CALL ZMMPY(MTZM,MUZM,FMMPY_ZIM%MZM) + END FUNCTION + + FUNCTION FMMPY_ZZM(Z,MA) + USE FMVALS + TYPE ( ZM ) MA,FMMPY_ZZM + COMPLEX Z + INTENT (IN) :: Z,MA + CALL ZMZ2M(Z,MTZM) + CALL ZMMPY(MTZM,MA%MZM,FMMPY_ZZM%MZM) + END FUNCTION + + FUNCTION FMMPY_CFM(C,MA) + USE FMVALS + TYPE ( ZM ) FMMPY_CFM + TYPE ( FM ) MA + COMPLEX (KIND(0.0D0)) :: C + INTENT (IN) :: C,MA + CALL FMDP2M(REAL(C,KIND(0.0D0)),MTFM) + CALL FMDP2M(AIMAG(C),MUFM) + CALL ZMCMPX(MTFM,MUFM,MTZM) + CALL FMI2M(0,MUFM) + CALL ZMCMPX(MA%MFM,MUFM,MUZM) + CALL ZMMPY(MTZM,MUZM,FMMPY_CFM%MZM) + END FUNCTION + + FUNCTION FMMPY_CIM(C,MA) + USE FMVALS + TYPE ( ZM ) FMMPY_CIM + TYPE ( IM ) MA + COMPLEX (KIND(0.0D0)) :: C + INTENT (IN) :: C,MA + CALL FMDP2M(REAL(C,KIND(0.0D0)),MTFM) + CALL FMDP2M(AIMAG(C),MUFM) + CALL ZMCMPX(MTFM,MUFM,MTZM) + CALL IMI2FM(MA%MIM,MTFM) + CALL FMI2M(0,MUFM) + CALL ZMCMPX(MTFM,MUFM,MUZM) + CALL ZMMPY(MTZM,MUZM,FMMPY_CIM%MZM) + END FUNCTION + + FUNCTION FMMPY_CZM(C,MA) + USE FMVALS + TYPE ( ZM ) MA,FMMPY_CZM + COMPLEX (KIND(0.0D0)) :: C + INTENT (IN) :: C,MA + CALL FMDP2M(REAL(C,KIND(0.0D0)),MTFM) + CALL FMDP2M(AIMAG(C),MUFM) + CALL ZMCMPX(MTFM,MUFM,MTZM) + CALL ZMMPY(MTZM,MA%MZM,FMMPY_CZM%MZM) + END FUNCTION + + FUNCTION FMMPY_FMI(MA,IVAL) + USE FMVALS + TYPE ( FM ) MA,FMMPY_FMI + INTEGER IVAL + INTENT (IN) :: MA,IVAL + CALL FMMPYI(MA%MFM,IVAL,FMMPY_FMI%MFM) + END FUNCTION + + FUNCTION FMMPY_FMR(MA,R) + USE FMVALS + TYPE ( FM ) MA,FMMPY_FMR + REAL R + INTENT (IN) :: MA,R + CALL FMSP2M(R,MTFM) + CALL FMMPY(MA%MFM,MTFM,FMMPY_FMR%MFM) + END FUNCTION + + FUNCTION FMMPY_FMD(MA,D) + USE FMVALS + TYPE ( FM ) MA,FMMPY_FMD + DOUBLE PRECISION D + INTENT (IN) :: MA,D + CALL FMDP2M(D,MTFM) + CALL FMMPY(MA%MFM,MTFM,FMMPY_FMD%MFM) + END FUNCTION + + FUNCTION FMMPY_FMZ(MA,Z) + USE FMVALS + TYPE ( ZM ) FMMPY_FMZ + TYPE ( FM ) MA + COMPLEX Z + INTENT (IN) :: MA,Z + CALL ZMZ2M(Z,MTZM) + CALL FMI2M(0,MUFM) + CALL ZMCMPX(MA%MFM,MUFM,MUZM) + CALL ZMMPY(MUZM,MTZM,FMMPY_FMZ%MZM) + END FUNCTION + + FUNCTION FMMPY_FMC(MA,C) + USE FMVALS + TYPE ( ZM ) FMMPY_FMC + TYPE ( FM ) MA + COMPLEX (KIND(0.0D0)) :: C + INTENT (IN) :: MA,C + CALL FMDP2M(REAL(C,KIND(0.0D0)),MTFM) + CALL FMDP2M(AIMAG(C),MUFM) + CALL ZMCMPX(MTFM,MUFM,MTZM) + CALL FMI2M(0,MUFM) + CALL ZMCMPX(MA%MFM,MUFM,MUZM) + CALL ZMMPY(MUZM,MTZM,FMMPY_FMC%MZM) + END FUNCTION + + FUNCTION FMMPY_FMFM(MA,MB) + USE FMVALS + TYPE ( FM ) MA,MB,FMMPY_FMFM + INTENT (IN) :: MA,MB + CALL FMMPY(MA%MFM,MB%MFM,FMMPY_FMFM%MFM) + END FUNCTION + + FUNCTION FMMPY_FMIM(MA,MB) + USE FMVALS + TYPE ( FM ) MA,FMMPY_FMIM + TYPE ( IM ) MB + INTENT (IN) :: MA,MB + CALL IMI2FM(MB%MIM,MTFM) + CALL FMMPY(MA%MFM,MTFM,FMMPY_FMIM%MFM) + END FUNCTION + + FUNCTION FMMPY_FMZM(MA,MB) + USE FMVALS + TYPE ( FM ) MA + TYPE ( ZM ) MB,FMMPY_FMZM + INTENT (IN) :: MA,MB + CALL FMI2M(0,MTFM) + CALL ZMCMPX(MA%MFM,MTFM,MTZM) + CALL ZMMPY(MTZM,MB%MZM,FMMPY_FMZM%MZM) + END FUNCTION + + FUNCTION FMMPY_IMI(MA,IVAL) + USE FMVALS + TYPE ( IM ) MA,FMMPY_IMI + INTEGER IVAL + INTENT (IN) :: MA,IVAL + CALL IMMPYI(MA%MIM,IVAL,FMMPY_IMI%MIM) + END FUNCTION + + FUNCTION FMMPY_IMR(MA,R) + USE FMVALS + TYPE ( FM ) FMMPY_IMR + TYPE ( IM ) MA + REAL R + INTENT (IN) :: MA,R + CALL FMSP2M(R,MTFM) + CALL IMI2FM(MA%MIM,MUFM) + CALL FMMPY(MUFM,MTFM,FMMPY_IMR%MFM) + END FUNCTION + + FUNCTION FMMPY_IMD(MA,D) + USE FMVALS + TYPE ( FM ) FMMPY_IMD + TYPE ( IM ) MA + DOUBLE PRECISION D + INTENT (IN) :: MA,D + CALL FMDP2M(D,MTFM) + CALL IMI2FM(MA%MIM,MUFM) + CALL FMMPY(MUFM,MTFM,FMMPY_IMD%MFM) + END FUNCTION + + FUNCTION FMMPY_IMZ(MA,Z) + USE FMVALS + TYPE ( ZM ) FMMPY_IMZ + TYPE ( IM ) MA + COMPLEX Z + INTENT (IN) :: MA,Z + CALL ZMZ2M(Z,MTZM) + CALL IMI2FM(MA%MIM,MTFM) + CALL FMI2M(0,MUFM) + CALL ZMCMPX(MTFM,MUFM,MUZM) + CALL ZMMPY(MUZM,MTZM,FMMPY_IMZ%MZM) + END FUNCTION + + FUNCTION FMMPY_IMC(MA,C) + USE FMVALS + TYPE ( ZM ) FMMPY_IMC + TYPE ( IM ) MA + COMPLEX (KIND(0.0D0)) :: C + INTENT (IN) :: MA,C + CALL FMDP2M(REAL(C,KIND(0.0D0)),MTFM) + CALL FMDP2M(AIMAG(C),MUFM) + CALL ZMCMPX(MTFM,MUFM,MTZM) + CALL IMI2FM(MA%MIM,MTFM) + CALL FMI2M(0,MUFM) + CALL ZMCMPX(MTFM,MUFM,MUZM) + CALL ZMMPY(MUZM,MTZM,FMMPY_IMC%MZM) + END FUNCTION + + FUNCTION FMMPY_IMFM(MA,MB) + USE FMVALS + TYPE ( IM ) MA + TYPE ( FM ) MB,FMMPY_IMFM + INTENT (IN) :: MA,MB + CALL IMI2FM(MA%MIM,MTFM) + CALL FMMPY(MTFM,MB%MFM,FMMPY_IMFM%MFM) + END FUNCTION + + FUNCTION FMMPY_IMIM(MA,MB) + USE FMVALS + TYPE ( IM ) MA,MB,FMMPY_IMIM + INTENT (IN) :: MA,MB + CALL IMMPY(MA%MIM,MB%MIM,FMMPY_IMIM%MIM) + END FUNCTION + + FUNCTION FMMPY_IMZM(MA,MB) + USE FMVALS + TYPE ( IM ) MA + TYPE ( ZM ) MB,FMMPY_IMZM + INTENT (IN) :: MA,MB + CALL IMI2FM(MA%MIM,MTFM) + CALL FMI2M(0,MUFM) + CALL ZMCMPX(MTFM,MUFM,MUZM) + CALL ZMMPY(MUZM,MB%MZM,FMMPY_IMZM%MZM) + END FUNCTION + + FUNCTION FMMPY_ZMI(MA,IVAL) + USE FMVALS + TYPE ( ZM ) MA,FMMPY_ZMI + INTEGER IVAL + INTENT (IN) :: MA,IVAL + CALL ZMMPYI(MA%MZM,IVAL,FMMPY_ZMI%MZM) + END FUNCTION + + FUNCTION FMMPY_ZMR(MA,R) + USE FMVALS + TYPE ( ZM ) MA,FMMPY_ZMR + REAL R + INTENT (IN) :: MA,R + CALL FMSP2M(R,MTFM) + CALL FMI2M(0,MUFM) + CALL ZMCMPX(MTFM,MUFM,MTZM) + CALL ZMMPY(MA%MZM,MTZM,FMMPY_ZMR%MZM) + END FUNCTION + + FUNCTION FMMPY_ZMD(MA,D) + USE FMVALS + TYPE ( ZM ) MA,FMMPY_ZMD + DOUBLE PRECISION D + INTENT (IN) :: MA,D + CALL FMDP2M(D,MTFM) + CALL FMI2M(0,MUFM) + CALL ZMCMPX(MTFM,MUFM,MTZM) + CALL ZMMPY(MA%MZM,MTZM,FMMPY_ZMD%MZM) + END FUNCTION + + FUNCTION FMMPY_ZMZ(MA,Z) + USE FMVALS + TYPE ( ZM ) MA,FMMPY_ZMZ + COMPLEX Z + INTENT (IN) :: MA,Z + CALL ZMZ2M(Z,MTZM) + CALL ZMMPY(MA%MZM,MTZM,FMMPY_ZMZ%MZM) + END FUNCTION + + FUNCTION FMMPY_ZMC(MA,C) + USE FMVALS + TYPE ( ZM ) MA,FMMPY_ZMC + COMPLEX (KIND(0.0D0)) :: C + INTENT (IN) :: MA,C + CALL FMDP2M(REAL(C,KIND(0.0D0)),MTFM) + CALL FMDP2M(AIMAG(C),MUFM) + CALL ZMCMPX(MTFM,MUFM,MTZM) + CALL ZMMPY(MA%MZM,MTZM,FMMPY_ZMC%MZM) + END FUNCTION + + FUNCTION FMMPY_ZMFM(MA,MB) + USE FMVALS + TYPE ( FM ) MB + TYPE ( ZM ) MA,FMMPY_ZMFM + INTENT (IN) :: MA,MB + CALL FMI2M(0,MTFM) + CALL ZMCMPX(MB%MFM,MTFM,MTZM) + CALL ZMMPY(MA%MZM,MTZM,FMMPY_ZMFM%MZM) + END FUNCTION + + FUNCTION FMMPY_ZMIM(MA,MB) + USE FMVALS + TYPE ( IM ) MB + TYPE ( ZM ) MA,FMMPY_ZMIM + INTENT (IN) :: MA,MB + CALL IMI2FM(MB%MIM,MTFM) + CALL FMI2M(0,MUFM) + CALL ZMCMPX(MTFM,MUFM,MUZM) + CALL ZMMPY(MA%MZM,MUZM,FMMPY_ZMIM%MZM) + END FUNCTION + + FUNCTION FMMPY_ZMZM(MA,MB) + USE FMVALS + TYPE ( ZM ) MA,MB,FMMPY_ZMZM + INTENT (IN) :: MA,MB + CALL ZMMPY(MA%MZM,MB%MZM,FMMPY_ZMZM%MZM) + END FUNCTION + +! / + + FUNCTION FMDIV_IFM(IVAL,MA) + USE FMVALS + TYPE ( FM ) MA,FMDIV_IFM + INTEGER IVAL + INTENT (IN) :: IVAL,MA + CALL FMI2M(IVAL,MTFM) + CALL FMDIV(MTFM,MA%MFM,FMDIV_IFM%MFM) + END FUNCTION + + FUNCTION FMDIV_IIM(IVAL,MA) + USE FMVALS + TYPE ( IM ) MA,FMDIV_IIM + INTEGER IVAL + INTENT (IN) :: IVAL,MA + CALL IMI2M(IVAL,MTIM) + CALL IMDIV(MTIM,MA%MIM,FMDIV_IIM%MIM) + END FUNCTION + + FUNCTION FMDIV_IZM(IVAL,MA) + USE FMVALS + TYPE ( ZM ) MA,FMDIV_IZM + INTEGER IVAL + INTENT (IN) :: IVAL,MA + CALL FMI2M(IVAL,MTFM) + CALL FMI2M(0,MUFM) + CALL ZMCMPX(MTFM,MUFM,MTZM) + CALL ZMDIV(MTZM,MA%MZM,FMDIV_IZM%MZM) + END FUNCTION + + FUNCTION FMDIV_RFM(R,MA) + USE FMVALS + TYPE ( FM ) MA,FMDIV_RFM + REAL R + INTENT (IN) :: R,MA + CALL FMSP2M(R,MTFM) + CALL FMDIV(MTFM,MA%MFM,FMDIV_RFM%MFM) + END FUNCTION + + FUNCTION FMDIV_RIM(R,MA) + USE FMVALS + TYPE ( FM ) FMDIV_RIM + TYPE ( IM ) MA + REAL R + INTENT (IN) :: R,MA + CALL FMSP2M(R,MTFM) + CALL IMI2FM(MA%MIM,MUFM) + CALL FMDIV(MTFM,MUFM,FMDIV_RIM%MFM) + END FUNCTION + + FUNCTION FMDIV_RZM(R,MA) + USE FMVALS + TYPE ( ZM ) MA,FMDIV_RZM + REAL R + INTENT (IN) :: R,MA + CALL FMSP2M(R,MTFM) + CALL FMI2M(0,MUFM) + CALL ZMCMPX(MTFM,MUFM,MTZM) + CALL ZMDIV(MTZM,MA%MZM,FMDIV_RZM%MZM) + END FUNCTION + + FUNCTION FMDIV_DFM(D,MA) + USE FMVALS + TYPE ( FM ) MA,FMDIV_DFM + DOUBLE PRECISION D + INTENT (IN) :: D,MA + CALL FMDP2M(D,MTFM) + CALL FMDIV(MTFM,MA%MFM,FMDIV_DFM%MFM) + END FUNCTION + + FUNCTION FMDIV_DIM(D,MA) + USE FMVALS + TYPE ( FM ) FMDIV_DIM + TYPE ( IM ) MA + DOUBLE PRECISION D + INTENT (IN) :: D,MA + CALL FMDP2M(D,MTFM) + CALL IMI2FM(MA%MIM,MUFM) + CALL FMDIV(MTFM,MUFM,FMDIV_DIM%MFM) + END FUNCTION + + FUNCTION FMDIV_DZM(D,MA) + USE FMVALS + TYPE ( ZM ) MA,FMDIV_DZM + DOUBLE PRECISION D + INTENT (IN) :: D,MA + CALL FMDP2M(D,MTFM) + CALL FMI2M(0,MUFM) + CALL ZMCMPX(MTFM,MUFM,MTZM) + CALL ZMDIV(MTZM,MA%MZM,FMDIV_DZM%MZM) + END FUNCTION + + FUNCTION FMDIV_ZFM(Z,MA) + USE FMVALS + TYPE ( ZM ) FMDIV_ZFM + TYPE ( FM ) MA + COMPLEX Z + INTENT (IN) :: Z,MA + CALL ZMZ2M(Z,MTZM) + CALL FMI2M(0,MUFM) + CALL ZMCMPX(MA%MFM,MUFM,MUZM) + CALL ZMDIV(MTZM,MUZM,FMDIV_ZFM%MZM) + END FUNCTION + + FUNCTION FMDIV_ZIM(Z,MA) + USE FMVALS + TYPE ( ZM ) FMDIV_ZIM + TYPE ( IM ) MA + COMPLEX Z + INTENT (IN) :: Z,MA + CALL ZMZ2M(Z,MTZM) + CALL IMI2FM(MA%MIM,MTFM) + CALL FMI2M(0,MUFM) + CALL ZMCMPX(MTFM,MUFM,MUZM) + CALL ZMDIV(MTZM,MUZM,FMDIV_ZIM%MZM) + END FUNCTION + + FUNCTION FMDIV_ZZM(Z,MA) + USE FMVALS + TYPE ( ZM ) MA,FMDIV_ZZM + COMPLEX Z + INTENT (IN) :: Z,MA + CALL ZMZ2M(Z,MTZM) + CALL ZMDIV(MTZM,MA%MZM,FMDIV_ZZM%MZM) + END FUNCTION + + FUNCTION FMDIV_CFM(C,MA) + USE FMVALS + TYPE ( ZM ) FMDIV_CFM + TYPE ( FM ) MA + COMPLEX (KIND(0.0D0)) :: C + INTENT (IN) :: C,MA + CALL FMDP2M(REAL(C,KIND(0.0D0)),MTFM) + CALL FMDP2M(AIMAG(C),MUFM) + CALL ZMCMPX(MTFM,MUFM,MTZM) + CALL FMI2M(0,MUFM) + CALL ZMCMPX(MA%MFM,MUFM,MUZM) + CALL ZMDIV(MTZM,MUZM,FMDIV_CFM%MZM) + END FUNCTION + + FUNCTION FMDIV_CIM(C,MA) + USE FMVALS + TYPE ( ZM ) FMDIV_CIM + TYPE ( IM ) MA + COMPLEX (KIND(0.0D0)) :: C + INTENT (IN) :: C,MA + CALL FMDP2M(REAL(C,KIND(0.0D0)),MTFM) + CALL FMDP2M(AIMAG(C),MUFM) + CALL ZMCMPX(MTFM,MUFM,MTZM) + CALL IMI2FM(MA%MIM,MTFM) + CALL FMI2M(0,MUFM) + CALL ZMCMPX(MTFM,MUFM,MUZM) + CALL ZMDIV(MTZM,MUZM,FMDIV_CIM%MZM) + END FUNCTION + + FUNCTION FMDIV_CZM(C,MA) + USE FMVALS + TYPE ( ZM ) MA,FMDIV_CZM + COMPLEX (KIND(0.0D0)) :: C + INTENT (IN) :: C,MA + CALL FMDP2M(REAL(C,KIND(0.0D0)),MTFM) + CALL FMDP2M(AIMAG(C),MUFM) + CALL ZMCMPX(MTFM,MUFM,MTZM) + CALL ZMDIV(MTZM,MA%MZM,FMDIV_CZM%MZM) + END FUNCTION + + FUNCTION FMDIV_FMI(MA,IVAL) + USE FMVALS + TYPE ( FM ) MA,FMDIV_FMI + INTEGER IVAL + INTENT (IN) :: MA,IVAL + CALL FMDIVI(MA%MFM,IVAL,FMDIV_FMI%MFM) + END FUNCTION + + FUNCTION FMDIV_FMR(MA,R) + USE FMVALS + TYPE ( FM ) MA,FMDIV_FMR + REAL R + INTENT (IN) :: MA,R + CALL FMSP2M(R,MTFM) + CALL FMDIV(MA%MFM,MTFM,FMDIV_FMR%MFM) + END FUNCTION + + FUNCTION FMDIV_FMD(MA,D) + USE FMVALS + TYPE ( FM ) MA,FMDIV_FMD + DOUBLE PRECISION D + INTENT (IN) :: MA,D + CALL FMDP2M(D,MTFM) + CALL FMDIV(MA%MFM,MTFM,FMDIV_FMD%MFM) + END FUNCTION + + FUNCTION FMDIV_FMZ(MA,Z) + USE FMVALS + TYPE ( ZM ) FMDIV_FMZ + TYPE ( FM ) MA + COMPLEX Z + INTENT (IN) :: MA,Z + CALL ZMZ2M(Z,MTZM) + CALL FMI2M(0,MUFM) + CALL ZMCMPX(MA%MFM,MUFM,MUZM) + CALL ZMDIV(MUZM,MTZM,FMDIV_FMZ%MZM) + END FUNCTION + + FUNCTION FMDIV_FMC(MA,C) + USE FMVALS + TYPE ( ZM ) FMDIV_FMC + TYPE ( FM ) MA + COMPLEX (KIND(0.0D0)) :: C + INTENT (IN) :: MA,C + CALL FMDP2M(REAL(C,KIND(0.0D0)),MTFM) + CALL FMDP2M(AIMAG(C),MUFM) + CALL ZMCMPX(MTFM,MUFM,MTZM) + CALL FMI2M(0,MUFM) + CALL ZMCMPX(MA%MFM,MUFM,MUZM) + CALL ZMDIV(MUZM,MTZM,FMDIV_FMC%MZM) + END FUNCTION + + FUNCTION FMDIV_FMFM(MA,MB) + USE FMVALS + TYPE ( FM ) MA,MB,FMDIV_FMFM + INTENT (IN) :: MA,MB + CALL FMDIV(MA%MFM,MB%MFM,FMDIV_FMFM%MFM) + END FUNCTION + + FUNCTION FMDIV_FMIM(MA,MB) + USE FMVALS + TYPE ( FM ) MA,FMDIV_FMIM + TYPE ( IM ) MB + INTENT (IN) :: MA,MB + CALL IMI2FM(MB%MIM,MTFM) + CALL FMDIV(MA%MFM,MTFM,FMDIV_FMIM%MFM) + END FUNCTION + + FUNCTION FMDIV_FMZM(MA,MB) + USE FMVALS + TYPE ( FM ) MA + TYPE ( ZM ) MB,FMDIV_FMZM + INTENT (IN) :: MA,MB + CALL FMI2M(0,MTFM) + CALL ZMCMPX(MA%MFM,MTFM,MTZM) + CALL ZMDIV(MTZM,MB%MZM,FMDIV_FMZM%MZM) + END FUNCTION + + FUNCTION FMDIV_IMI(MA,IVAL) + USE FMVALS + TYPE ( IM ) MA,FMDIV_IMI + INTEGER IVAL + INTENT (IN) :: MA,IVAL + CALL IMDIVI(MA%MIM,IVAL,FMDIV_IMI%MIM) + END FUNCTION + + FUNCTION FMDIV_IMR(MA,R) + USE FMVALS + TYPE ( FM ) FMDIV_IMR + TYPE ( IM ) MA + REAL R + INTENT (IN) :: MA,R + CALL FMSP2M(R,MTFM) + CALL IMI2FM(MA%MIM,MUFM) + CALL FMDIV(MUFM,MTFM,FMDIV_IMR%MFM) + END FUNCTION + + FUNCTION FMDIV_IMD(MA,D) + USE FMVALS + TYPE ( FM ) FMDIV_IMD + TYPE ( IM ) MA + DOUBLE PRECISION D + INTENT (IN) :: MA,D + CALL FMDP2M(D,MTFM) + CALL IMI2FM(MA%MIM,MUFM) + CALL FMDIV(MUFM,MTFM,FMDIV_IMD%MFM) + END FUNCTION + + FUNCTION FMDIV_IMZ(MA,Z) + USE FMVALS + TYPE ( ZM ) FMDIV_IMZ + TYPE ( IM ) MA + COMPLEX Z + INTENT (IN) :: MA,Z + CALL ZMZ2M(Z,MTZM) + CALL IMI2FM(MA%MIM,MTFM) + CALL FMI2M(0,MUFM) + CALL ZMCMPX(MTFM,MUFM,MUZM) + CALL ZMDIV(MUZM,MTZM,FMDIV_IMZ%MZM) + END FUNCTION + + FUNCTION FMDIV_IMC(MA,C) + USE FMVALS + TYPE ( ZM ) FMDIV_IMC + TYPE ( IM ) MA + COMPLEX (KIND(0.0D0)) :: C + INTENT (IN) :: MA,C + CALL FMDP2M(REAL(C,KIND(0.0D0)),MTFM) + CALL FMDP2M(AIMAG(C),MUFM) + CALL ZMCMPX(MTFM,MUFM,MTZM) + CALL IMI2FM(MA%MIM,MTFM) + CALL FMI2M(0,MUFM) + CALL ZMCMPX(MTFM,MUFM,MUZM) + CALL ZMDIV(MUZM,MTZM,FMDIV_IMC%MZM) + END FUNCTION + + FUNCTION FMDIV_IMFM(MA,MB) + USE FMVALS + TYPE ( IM ) MA + TYPE ( FM ) MB,FMDIV_IMFM + INTENT (IN) :: MA,MB + CALL IMI2FM(MA%MIM,MTFM) + CALL FMDIV(MTFM,MB%MFM,FMDIV_IMFM%MFM) + END FUNCTION + + FUNCTION FMDIV_IMIM(MA,MB) + USE FMVALS + TYPE ( IM ) MA,MB,FMDIV_IMIM + INTENT (IN) :: MA,MB + CALL IMDIV(MA%MIM,MB%MIM,FMDIV_IMIM%MIM) + END FUNCTION + + FUNCTION FMDIV_IMZM(MA,MB) + USE FMVALS + TYPE ( IM ) MA + TYPE ( ZM ) MB,FMDIV_IMZM + INTENT (IN) :: MA,MB + CALL IMI2FM(MA%MIM,MTFM) + CALL FMI2M(0,MUFM) + CALL ZMCMPX(MTFM,MUFM,MUZM) + CALL ZMDIV(MUZM,MB%MZM,FMDIV_IMZM%MZM) + END FUNCTION + + FUNCTION FMDIV_ZMI(MA,IVAL) + USE FMVALS + TYPE ( ZM ) MA,FMDIV_ZMI + INTEGER IVAL + INTENT (IN) :: MA,IVAL + CALL ZMDIVI(MA%MZM,IVAL,FMDIV_ZMI%MZM) + END FUNCTION + + FUNCTION FMDIV_ZMR(MA,R) + USE FMVALS + TYPE ( ZM ) MA,FMDIV_ZMR + REAL R + INTENT (IN) :: MA,R + CALL FMSP2M(R,MTFM) + CALL FMI2M(0,MUFM) + CALL ZMCMPX(MTFM,MUFM,MTZM) + CALL ZMDIV(MA%MZM,MTZM,FMDIV_ZMR%MZM) + END FUNCTION + + FUNCTION FMDIV_ZMD(MA,D) + USE FMVALS + TYPE ( ZM ) MA,FMDIV_ZMD + DOUBLE PRECISION D + INTENT (IN) :: MA,D + CALL FMDP2M(D,MTFM) + CALL FMI2M(0,MUFM) + CALL ZMCMPX(MTFM,MUFM,MTZM) + CALL ZMDIV(MA%MZM,MTZM,FMDIV_ZMD%MZM) + END FUNCTION + + FUNCTION FMDIV_ZMZ(MA,Z) + USE FMVALS + TYPE ( ZM ) MA,FMDIV_ZMZ + COMPLEX Z + INTENT (IN) :: MA,Z + CALL ZMZ2M(Z,MTZM) + CALL ZMDIV(MA%MZM,MTZM,FMDIV_ZMZ%MZM) + END FUNCTION + + FUNCTION FMDIV_ZMC(MA,C) + USE FMVALS + TYPE ( ZM ) MA,FMDIV_ZMC + COMPLEX (KIND(0.0D0)) :: C + INTENT (IN) :: MA,C + CALL FMDP2M(REAL(C,KIND(0.0D0)),MTFM) + CALL FMDP2M(AIMAG(C),MUFM) + CALL ZMCMPX(MTFM,MUFM,MTZM) + CALL ZMDIV(MA%MZM,MTZM,FMDIV_ZMC%MZM) + END FUNCTION + + FUNCTION FMDIV_ZMFM(MA,MB) + USE FMVALS + TYPE ( FM ) MB + TYPE ( ZM ) MA,FMDIV_ZMFM + INTENT (IN) :: MA,MB + CALL FMI2M(0,MTFM) + CALL ZMCMPX(MB%MFM,MTFM,MTZM) + CALL ZMDIV(MA%MZM,MTZM,FMDIV_ZMFM%MZM) + END FUNCTION + + FUNCTION FMDIV_ZMIM(MA,MB) + USE FMVALS + TYPE ( IM ) MB + TYPE ( ZM ) MA,FMDIV_ZMIM + INTENT (IN) :: MA,MB + CALL IMI2FM(MB%MIM,MTFM) + CALL FMI2M(0,MUFM) + CALL ZMCMPX(MTFM,MUFM,MUZM) + CALL ZMDIV(MA%MZM,MUZM,FMDIV_ZMIM%MZM) + END FUNCTION + + FUNCTION FMDIV_ZMZM(MA,MB) + USE FMVALS + TYPE ( ZM ) MA,MB,FMDIV_ZMZM + INTENT (IN) :: MA,MB + CALL ZMDIV(MA%MZM,MB%MZM,FMDIV_ZMZM%MZM) + END FUNCTION + + END MODULE FMZM_6 + + MODULE FMZM_7 + USE FMZM_1 + + INTERFACE OPERATOR (**) + MODULE PROCEDURE FMPWR_IFM + MODULE PROCEDURE FMPWR_IIM + MODULE PROCEDURE FMPWR_IZM + MODULE PROCEDURE FMPWR_RFM + MODULE PROCEDURE FMPWR_RIM + MODULE PROCEDURE FMPWR_RZM + MODULE PROCEDURE FMPWR_DFM + MODULE PROCEDURE FMPWR_DIM + MODULE PROCEDURE FMPWR_DZM + MODULE PROCEDURE FMPWR_ZFM + MODULE PROCEDURE FMPWR_ZIM + MODULE PROCEDURE FMPWR_ZZM + MODULE PROCEDURE FMPWR_CFM + MODULE PROCEDURE FMPWR_CIM + MODULE PROCEDURE FMPWR_CZM + MODULE PROCEDURE FMPWR_FMI + MODULE PROCEDURE FMPWR_FMR + MODULE PROCEDURE FMPWR_FMD + MODULE PROCEDURE FMPWR_FMZ + MODULE PROCEDURE FMPWR_FMC + MODULE PROCEDURE FMPWR_FMFM + MODULE PROCEDURE FMPWR_FMIM + MODULE PROCEDURE FMPWR_FMZM + MODULE PROCEDURE FMPWR_IMI + MODULE PROCEDURE FMPWR_IMR + MODULE PROCEDURE FMPWR_IMD + MODULE PROCEDURE FMPWR_IMZ + MODULE PROCEDURE FMPWR_IMC + MODULE PROCEDURE FMPWR_IMFM + MODULE PROCEDURE FMPWR_IMIM + MODULE PROCEDURE FMPWR_IMZM + MODULE PROCEDURE FMPWR_ZMI + MODULE PROCEDURE FMPWR_ZMR + MODULE PROCEDURE FMPWR_ZMD + MODULE PROCEDURE FMPWR_ZMZ + MODULE PROCEDURE FMPWR_ZMC + MODULE PROCEDURE FMPWR_ZMFM + MODULE PROCEDURE FMPWR_ZMIM + MODULE PROCEDURE FMPWR_ZMZM + END INTERFACE + + INTERFACE ABS + MODULE PROCEDURE FMABS_FM + MODULE PROCEDURE FMABS_IM + MODULE PROCEDURE FMABS_ZM + END INTERFACE + + INTERFACE ACOS + MODULE PROCEDURE FMACOS_FM + MODULE PROCEDURE FMACOS_ZM + END INTERFACE + + INTERFACE AIMAG + MODULE PROCEDURE FMAIMAG_ZM + END INTERFACE + + INTERFACE AINT + MODULE PROCEDURE FMAINT_FM + MODULE PROCEDURE FMAINT_ZM + END INTERFACE + + INTERFACE ANINT + MODULE PROCEDURE FMANINT_FM + MODULE PROCEDURE FMANINT_ZM + END INTERFACE + + INTERFACE ASIN + MODULE PROCEDURE FMASIN_FM + MODULE PROCEDURE FMASIN_ZM + END INTERFACE + + INTERFACE ATAN + MODULE PROCEDURE FMATAN_FM + MODULE PROCEDURE FMATAN_ZM + END INTERFACE + + INTERFACE ATAN2 + MODULE PROCEDURE FMATAN2_FM + END INTERFACE + + INTERFACE BTEST + MODULE PROCEDURE FMBTEST_IM + END INTERFACE + + INTERFACE CEILING + MODULE PROCEDURE FMCEILING_FM + MODULE PROCEDURE FMCEILING_ZM + END INTERFACE + + INTERFACE CMPLX + MODULE PROCEDURE FMCMPLX_FM + MODULE PROCEDURE FMCMPLX_IM + END INTERFACE + + INTERFACE CONJG + MODULE PROCEDURE FMCONJG_ZM + END INTERFACE + + INTERFACE COS + MODULE PROCEDURE FMCOS_FM + MODULE PROCEDURE FMCOS_ZM + END INTERFACE + + INTERFACE COSH + MODULE PROCEDURE FMCOSH_FM + MODULE PROCEDURE FMCOSH_ZM + END INTERFACE + + INTERFACE DBLE + MODULE PROCEDURE FMDBLE_FM + MODULE PROCEDURE FMDBLE_IM + MODULE PROCEDURE FMDBLE_ZM + END INTERFACE + + INTERFACE DIGITS + MODULE PROCEDURE FMDIGITS_FM + MODULE PROCEDURE FMDIGITS_IM + MODULE PROCEDURE FMDIGITS_ZM + END INTERFACE + + INTERFACE DIM + MODULE PROCEDURE FMDIM_FM + MODULE PROCEDURE FMDIM_IM + END INTERFACE + + INTERFACE DINT + MODULE PROCEDURE FMDINT_FM + MODULE PROCEDURE FMDINT_ZM + END INTERFACE + + INTERFACE DOTPRODUCT + MODULE PROCEDURE FMDOTPRODUCT_FM + MODULE PROCEDURE FMDOTPRODUCT_IM + MODULE PROCEDURE FMDOTPRODUCT_ZM + END INTERFACE + + CONTAINS + +! ** + + FUNCTION FMPWR_IFM(IVAL,MA) + USE FMVALS + TYPE ( FM ) MA,FMPWR_IFM + INTEGER IVAL + INTENT (IN) :: IVAL,MA + CALL FMI2M(IVAL,MTFM) + CALL FMPWR(MTFM,MA%MFM,FMPWR_IFM%MFM) + END FUNCTION + + FUNCTION FMPWR_IIM(IVAL,MA) + USE FMVALS + TYPE ( IM ) MA,FMPWR_IIM + INTEGER IVAL + INTENT (IN) :: IVAL,MA + CALL IMI2M(IVAL,MTIM) + CALL IMPWR(MTIM,MA%MIM,FMPWR_IIM%MIM) + END FUNCTION + + FUNCTION FMPWR_IZM(IVAL,MA) + USE FMVALS + TYPE ( ZM ) MA,FMPWR_IZM + INTEGER IVAL + INTENT (IN) :: IVAL,MA + CALL FMI2M(IVAL,MTFM) + CALL FMI2M(0,MUFM) + CALL ZMCMPX(MTFM,MUFM,MTZM) + CALL ZMPWR(MTZM,MA%MZM,FMPWR_IZM%MZM) + END FUNCTION + + FUNCTION FMPWR_RFM(R,MA) + USE FMVALS + TYPE ( FM ) MA,FMPWR_RFM + REAL R + INTENT (IN) :: R,MA + CALL FMSP2M(R,MTFM) + CALL FMPWR(MTFM,MA%MFM,FMPWR_RFM%MFM) + END FUNCTION + + FUNCTION FMPWR_RIM(R,MA) + USE FMVALS + TYPE ( FM ) FMPWR_RIM + TYPE ( IM ) MA + REAL R + INTENT (IN) :: R,MA + CALL FMSP2M(R,MTFM) + CALL IMI2FM(MA%MIM,MUFM) + CALL FMPWR(MTFM,MUFM,FMPWR_RIM%MFM) + END FUNCTION + + FUNCTION FMPWR_RZM(R,MA) + USE FMVALS + TYPE ( ZM ) MA,FMPWR_RZM + REAL R + INTENT (IN) :: R,MA + CALL FMSP2M(R,MTFM) + CALL FMI2M(0,MUFM) + CALL ZMCMPX(MTFM,MUFM,MTZM) + CALL ZMPWR(MTZM,MA%MZM,FMPWR_RZM%MZM) + END FUNCTION + + FUNCTION FMPWR_DFM(D,MA) + USE FMVALS + TYPE ( FM ) MA,FMPWR_DFM + DOUBLE PRECISION D + INTENT (IN) :: D,MA + CALL FMDP2M(D,MTFM) + CALL FMPWR(MTFM,MA%MFM,FMPWR_DFM%MFM) + END FUNCTION + + FUNCTION FMPWR_DIM(D,MA) + USE FMVALS + TYPE ( FM ) FMPWR_DIM + TYPE ( IM ) MA + DOUBLE PRECISION D + INTENT (IN) :: D,MA + CALL FMDP2M(D,MTFM) + CALL IMI2FM(MA%MIM,MUFM) + CALL FMPWR(MTFM,MUFM,FMPWR_DIM%MFM) + END FUNCTION + + FUNCTION FMPWR_DZM(D,MA) + USE FMVALS + TYPE ( ZM ) MA,FMPWR_DZM + DOUBLE PRECISION D + INTENT (IN) :: D,MA + CALL FMDP2M(D,MTFM) + CALL FMI2M(0,MUFM) + CALL ZMCMPX(MTFM,MUFM,MTZM) + CALL ZMPWR(MTZM,MA%MZM,FMPWR_DZM%MZM) + END FUNCTION + + FUNCTION FMPWR_ZFM(Z,MA) + USE FMVALS + TYPE ( ZM ) FMPWR_ZFM + TYPE ( FM ) MA + COMPLEX Z + INTENT (IN) :: Z,MA + CALL ZMZ2M(Z,MTZM) + CALL FMI2M(0,MUFM) + CALL ZMCMPX(MA%MFM,MUFM,MUZM) + CALL ZMPWR(MTZM,MUZM,FMPWR_ZFM%MZM) + END FUNCTION + + FUNCTION FMPWR_ZIM(Z,MA) + USE FMVALS + TYPE ( ZM ) FMPWR_ZIM + TYPE ( IM ) MA + COMPLEX Z + INTENT (IN) :: Z,MA + CALL ZMZ2M(Z,MTZM) + CALL IMI2FM(MA%MIM,MTFM) + CALL FMI2M(0,MUFM) + CALL ZMCMPX(MTFM,MUFM,MUZM) + CALL ZMPWR(MTZM,MUZM,FMPWR_ZIM%MZM) + END FUNCTION + + FUNCTION FMPWR_ZZM(Z,MA) + USE FMVALS + TYPE ( ZM ) MA,FMPWR_ZZM + COMPLEX Z + INTENT (IN) :: Z,MA + CALL ZMZ2M(Z,MTZM) + CALL ZMPWR(MTZM,MA%MZM,FMPWR_ZZM%MZM) + END FUNCTION + + FUNCTION FMPWR_CFM(C,MA) + USE FMVALS + TYPE ( ZM ) FMPWR_CFM + TYPE ( FM ) MA + COMPLEX (KIND(0.0D0)) :: C + INTENT (IN) :: C,MA + CALL FMDP2M(REAL(C,KIND(0.0D0)),MTFM) + CALL FMDP2M(AIMAG(C),MUFM) + CALL ZMCMPX(MTFM,MUFM,MTZM) + CALL FMI2M(0,MUFM) + CALL ZMCMPX(MA%MFM,MUFM,MUZM) + CALL ZMPWR(MTZM,MUZM,FMPWR_CFM%MZM) + END FUNCTION + + FUNCTION FMPWR_CIM(C,MA) + USE FMVALS + TYPE ( ZM ) FMPWR_CIM + TYPE ( IM ) MA + COMPLEX (KIND(0.0D0)) :: C + INTENT (IN) :: C,MA + CALL FMDP2M(REAL(C,KIND(0.0D0)),MTFM) + CALL FMDP2M(AIMAG(C),MUFM) + CALL ZMCMPX(MTFM,MUFM,MTZM) + CALL IMI2FM(MA%MIM,MTFM) + CALL FMI2M(0,MUFM) + CALL ZMCMPX(MTFM,MUFM,MUZM) + CALL ZMPWR(MTZM,MUZM,FMPWR_CIM%MZM) + END FUNCTION + + FUNCTION FMPWR_CZM(C,MA) + USE FMVALS + TYPE ( ZM ) MA,FMPWR_CZM + COMPLEX (KIND(0.0D0)) :: C + INTENT (IN) :: C,MA + CALL FMDP2M(REAL(C,KIND(0.0D0)),MTFM) + CALL FMDP2M(AIMAG(C),MUFM) + CALL ZMCMPX(MTFM,MUFM,MTZM) + CALL ZMPWR(MTZM,MA%MZM,FMPWR_CZM%MZM) + END FUNCTION + + FUNCTION FMPWR_FMI(MA,IVAL) + USE FMVALS + TYPE ( FM ) MA,FMPWR_FMI + INTEGER IVAL + INTENT (IN) :: MA,IVAL + CALL FMIPWR(MA%MFM,IVAL,FMPWR_FMI%MFM) + END FUNCTION + + FUNCTION FMPWR_FMR(MA,R) + USE FMVALS + TYPE ( FM ) MA,FMPWR_FMR + REAL R + INTENT (IN) :: MA,R + CALL FMSP2M(R,MTFM) + CALL FMPWR(MA%MFM,MTFM,FMPWR_FMR%MFM) + END FUNCTION + + FUNCTION FMPWR_FMD(MA,D) + USE FMVALS + TYPE ( FM ) MA,FMPWR_FMD + DOUBLE PRECISION D + INTENT (IN) :: MA,D + CALL FMDP2M(D,MTFM) + CALL FMPWR(MA%MFM,MTFM,FMPWR_FMD%MFM) + END FUNCTION + + FUNCTION FMPWR_FMZ(MA,Z) + USE FMVALS + TYPE ( ZM ) FMPWR_FMZ + TYPE ( FM ) MA + COMPLEX Z + INTENT (IN) :: MA,Z + CALL ZMZ2M(Z,MTZM) + CALL FMI2M(0,MUFM) + CALL ZMCMPX(MA%MFM,MUFM,MUZM) + CALL ZMPWR(MUZM,MTZM,FMPWR_FMZ%MZM) + END FUNCTION + + FUNCTION FMPWR_FMC(MA,C) + USE FMVALS + TYPE ( ZM ) FMPWR_FMC + TYPE ( FM ) MA + COMPLEX (KIND(0.0D0)) :: C + INTENT (IN) :: MA,C + CALL FMDP2M(REAL(C,KIND(0.0D0)),MTFM) + CALL FMDP2M(AIMAG(C),MUFM) + CALL ZMCMPX(MTFM,MUFM,MTZM) + CALL FMI2M(0,MUFM) + CALL ZMCMPX(MA%MFM,MUFM,MUZM) + CALL ZMPWR(MUZM,MTZM,FMPWR_FMC%MZM) + END FUNCTION + + FUNCTION FMPWR_FMFM(MA,MB) + USE FMVALS + TYPE ( FM ) MA,MB,FMPWR_FMFM + INTENT (IN) :: MA,MB + CALL FMPWR(MA%MFM,MB%MFM,FMPWR_FMFM%MFM) + END FUNCTION + + FUNCTION FMPWR_FMIM(MA,MB) + USE FMVALS + TYPE ( FM ) MA,FMPWR_FMIM + TYPE ( IM ) MB + INTENT (IN) :: MA,MB + CALL IMI2FM(MB%MIM,MTFM) + CALL FMPWR(MA%MFM,MTFM,FMPWR_FMIM%MFM) + END FUNCTION + + FUNCTION FMPWR_FMZM(MA,MB) + USE FMVALS + TYPE ( FM ) MA + TYPE ( ZM ) MB,FMPWR_FMZM + INTENT (IN) :: MA,MB + CALL FMI2M(0,MTFM) + CALL ZMCMPX(MA%MFM,MTFM,MTZM) + CALL ZMPWR(MTZM,MB%MZM,FMPWR_FMZM%MZM) + END FUNCTION + + FUNCTION FMPWR_IMI(MA,IVAL) + USE FMVALS + TYPE ( IM ) MA,FMPWR_IMI + INTEGER IVAL + INTENT (IN) :: MA,IVAL + CALL IMI2M(IVAL,MTIM) + CALL IMPWR(MA%MIM,MTIM,FMPWR_IMI%MIM) + END FUNCTION + + FUNCTION FMPWR_IMR(MA,R) + USE FMVALS + TYPE ( FM ) FMPWR_IMR + TYPE ( IM ) MA + REAL R + INTENT (IN) :: MA,R + CALL FMSP2M(R,MTFM) + CALL IMI2FM(MA%MIM,MUFM) + CALL FMPWR(MUFM,MTFM,FMPWR_IMR%MFM) + END FUNCTION + + FUNCTION FMPWR_IMD(MA,D) + USE FMVALS + TYPE ( FM ) FMPWR_IMD + TYPE ( IM ) MA + DOUBLE PRECISION D + INTENT (IN) :: MA,D + CALL FMDP2M(D,MTFM) + CALL IMI2FM(MA%MIM,MUFM) + CALL FMPWR(MUFM,MTFM,FMPWR_IMD%MFM) + END FUNCTION + + FUNCTION FMPWR_IMZ(MA,Z) + USE FMVALS + TYPE ( ZM ) FMPWR_IMZ + TYPE ( IM ) MA + COMPLEX Z + INTENT (IN) :: MA,Z + CALL ZMZ2M(Z,MTZM) + CALL IMI2FM(MA%MIM,MTFM) + CALL FMI2M(0,MUFM) + CALL ZMCMPX(MTFM,MUFM,MUZM) + CALL ZMPWR(MUZM,MTZM,FMPWR_IMZ%MZM) + END FUNCTION + + FUNCTION FMPWR_IMC(MA,C) + USE FMVALS + TYPE ( ZM ) FMPWR_IMC + TYPE ( IM ) MA + COMPLEX (KIND(0.0D0)) :: C + INTENT (IN) :: MA,C + CALL FMDP2M(REAL(C,KIND(0.0D0)),MTFM) + CALL FMDP2M(AIMAG(C),MUFM) + CALL ZMCMPX(MTFM,MUFM,MTZM) + CALL IMI2FM(MA%MIM,MTFM) + CALL FMI2M(0,MUFM) + CALL ZMCMPX(MTFM,MUFM,MUZM) + CALL ZMPWR(MUZM,MTZM,FMPWR_IMC%MZM) + END FUNCTION + + FUNCTION FMPWR_IMFM(MA,MB) + USE FMVALS + TYPE ( IM ) MA + TYPE ( FM ) MB,FMPWR_IMFM + INTENT (IN) :: MA,MB + CALL IMI2FM(MA%MIM,MTFM) + CALL FMPWR(MTFM,MB%MFM,FMPWR_IMFM%MFM) + END FUNCTION + + FUNCTION FMPWR_IMIM(MA,MB) + USE FMVALS + TYPE ( IM ) MA,MB,FMPWR_IMIM + INTENT (IN) :: MA,MB + CALL IMPWR(MA%MIM,MB%MIM,FMPWR_IMIM%MIM) + END FUNCTION + + FUNCTION FMPWR_IMZM(MA,MB) + USE FMVALS + TYPE ( IM ) MA + TYPE ( ZM ) MB,FMPWR_IMZM + INTENT (IN) :: MA,MB + CALL IMI2FM(MA%MIM,MTFM) + CALL FMI2M(0,MUFM) + CALL ZMCMPX(MTFM,MUFM,MUZM) + CALL ZMPWR(MUZM,MB%MZM,FMPWR_IMZM%MZM) + END FUNCTION + + FUNCTION FMPWR_ZMI(MA,IVAL) + USE FMVALS + TYPE ( ZM ) MA,FMPWR_ZMI + INTEGER IVAL + INTENT (IN) :: MA,IVAL + CALL ZMIPWR(MA%MZM,IVAL,FMPWR_ZMI%MZM) + END FUNCTION + + FUNCTION FMPWR_ZMR(MA,R) + USE FMVALS + TYPE ( ZM ) MA,FMPWR_ZMR + REAL R + INTENT (IN) :: MA,R + CALL FMSP2M(R,MTFM) + CALL FMI2M(0,MUFM) + CALL ZMCMPX(MTFM,MUFM,MTZM) + CALL ZMPWR(MA%MZM,MTZM,FMPWR_ZMR%MZM) + END FUNCTION + + FUNCTION FMPWR_ZMD(MA,D) + USE FMVALS + TYPE ( ZM ) MA,FMPWR_ZMD + DOUBLE PRECISION D + INTENT (IN) :: MA,D + CALL FMDP2M(D,MTFM) + CALL FMI2M(0,MUFM) + CALL ZMCMPX(MTFM,MUFM,MTZM) + CALL ZMPWR(MA%MZM,MTZM,FMPWR_ZMD%MZM) + END FUNCTION + + FUNCTION FMPWR_ZMZ(MA,Z) + USE FMVALS + TYPE ( ZM ) MA,FMPWR_ZMZ + COMPLEX Z + INTENT (IN) :: MA,Z + CALL ZMZ2M(Z,MTZM) + CALL ZMPWR(MA%MZM,MTZM,FMPWR_ZMZ%MZM) + END FUNCTION + + FUNCTION FMPWR_ZMC(MA,C) + USE FMVALS + TYPE ( ZM ) MA,FMPWR_ZMC + COMPLEX (KIND(0.0D0)) :: C + INTENT (IN) :: MA,C + CALL FMDP2M(REAL(C,KIND(0.0D0)),MTFM) + CALL FMDP2M(AIMAG(C),MUFM) + CALL ZMCMPX(MTFM,MUFM,MTZM) + CALL ZMPWR(MA%MZM,MTZM,FMPWR_ZMC%MZM) + END FUNCTION + + FUNCTION FMPWR_ZMFM(MA,MB) + USE FMVALS + TYPE ( FM ) MB + TYPE ( ZM ) MA,FMPWR_ZMFM + INTENT (IN) :: MA,MB + CALL FMI2M(0,MTFM) + CALL ZMCMPX(MB%MFM,MTFM,MTZM) + CALL ZMPWR(MA%MZM,MTZM,FMPWR_ZMFM%MZM) + END FUNCTION + + FUNCTION FMPWR_ZMIM(MA,MB) + USE FMVALS + TYPE ( IM ) MB + TYPE ( ZM ) MA,FMPWR_ZMIM + INTENT (IN) :: MA,MB + CALL IMI2FM(MB%MIM,MTFM) + CALL FMI2M(0,MUFM) + CALL ZMCMPX(MTFM,MUFM,MUZM) + CALL ZMPWR(MA%MZM,MUZM,FMPWR_ZMIM%MZM) + END FUNCTION + + FUNCTION FMPWR_ZMZM(MA,MB) + USE FMVALS + TYPE ( ZM ) MA,MB,FMPWR_ZMZM + INTENT (IN) :: MA,MB + CALL ZMPWR(MA%MZM,MB%MZM,FMPWR_ZMZM%MZM) + END FUNCTION + +! ABS + + FUNCTION FMABS_FM(MA) + USE FMVALS + TYPE ( FM ) MA,FMABS_FM + INTENT (IN) :: MA + CALL FMABS(MA%MFM,FMABS_FM%MFM) + END FUNCTION + + FUNCTION FMABS_IM(MA) + USE FMVALS + TYPE ( IM ) MA,FMABS_IM + INTENT (IN) :: MA + CALL IMABS(MA%MIM,FMABS_IM%MIM) + END FUNCTION + + FUNCTION FMABS_ZM(MA) + USE FMVALS + TYPE ( FM ) FMABS_ZM + TYPE ( ZM ) MA + INTENT (IN) :: MA + CALL ZMABS(MA%MZM,FMABS_ZM%MFM) + END FUNCTION + +! ACOS + + FUNCTION FMACOS_FM(MA) + USE FMVALS + TYPE ( FM ) MA,FMACOS_FM + INTENT (IN) :: MA + CALL FMACOS(MA%MFM,FMACOS_FM%MFM) + END FUNCTION + + FUNCTION FMACOS_ZM(MA) + USE FMVALS + TYPE ( ZM ) MA,FMACOS_ZM + INTENT (IN) :: MA + CALL ZMACOS(MA%MZM,FMACOS_ZM%MZM) + END FUNCTION + +! AIMAG + + FUNCTION FMAIMAG_ZM(MA) + USE FMVALS + TYPE ( FM ) FMAIMAG_ZM + TYPE ( ZM ) MA + INTENT (IN) :: MA + CALL ZMIMAG(MA%MZM,FMAIMAG_ZM%MFM) + END FUNCTION + +! AINT + + FUNCTION FMAINT_FM(MA) + USE FMVALS + TYPE ( FM ) MA,FMAINT_FM + INTENT (IN) :: MA + CALL FMINT(MA%MFM,FMAINT_FM%MFM) + END FUNCTION + + FUNCTION FMAINT_ZM(MA) + USE FMVALS + TYPE ( ZM ) MA,FMAINT_ZM + INTENT (IN) :: MA + CALL ZMINT(MA%MZM,FMAINT_ZM%MZM) + END FUNCTION + +! ANINT + + FUNCTION FMANINT_FM(MA) + USE FMVALS + TYPE ( FM ) MA,FMANINT_FM + INTENT (IN) :: MA + CALL FMNINT(MA%MFM,FMANINT_FM%MFM) + END FUNCTION + + FUNCTION FMANINT_ZM(MA) + USE FMVALS + TYPE ( ZM ) MA,FMANINT_ZM + INTENT (IN) :: MA + CALL ZMNINT(MA%MZM,FMANINT_ZM%MZM) + END FUNCTION + +! ASIN + + FUNCTION FMASIN_FM(MA) + USE FMVALS + TYPE ( FM ) MA,FMASIN_FM + INTENT (IN) :: MA + CALL FMASIN(MA%MFM,FMASIN_FM%MFM) + END FUNCTION + + FUNCTION FMASIN_ZM(MA) + USE FMVALS + TYPE ( ZM ) MA,FMASIN_ZM + INTENT (IN) :: MA + CALL ZMASIN(MA%MZM,FMASIN_ZM%MZM) + END FUNCTION + +! ATAN + + FUNCTION FMATAN_FM(MA) + USE FMVALS + TYPE ( FM ) MA,FMATAN_FM + INTENT (IN) :: MA + CALL FMATAN(MA%MFM,FMATAN_FM%MFM) + END FUNCTION + + FUNCTION FMATAN_ZM(MA) + USE FMVALS + TYPE ( ZM ) MA,FMATAN_ZM + INTENT (IN) :: MA + CALL ZMATAN(MA%MZM,FMATAN_ZM%MZM) + END FUNCTION + +! ATAN2 + + FUNCTION FMATAN2_FM(MA,MB) + USE FMVALS + TYPE ( FM ) MA,MB,FMATAN2_FM + INTENT (IN) :: MA,MB + CALL FMATN2(MA%MFM,MB%MFM,FMATAN2_FM%MFM) + END FUNCTION + +! BTEST + + FUNCTION FMBTEST_IM(MA,POS) + TYPE ( IM ) MA + INTEGER POS + LOGICAL FMBTEST_IM + INTENT (IN) :: MA,POS + CALL IMI2M(2,MTIM) + CALL IMI2M(POS,MUIM) + CALL IMPWR(MTIM,MUIM,MVIM) + CALL IMDIV(MA%MIM,MVIM,MUIM) + MUIM(-1) = 1 + CALL IMMOD(MUIM,MTIM,MVIM) + IF (MVIM(2) == 0) THEN + FMBTEST_IM = .FALSE. + ELSE + FMBTEST_IM = .TRUE. + ENDIF + END FUNCTION + +! CEILING + + FUNCTION FMCEILING_FM(MA) + USE FMVALS + TYPE ( FM ) MA,FMCEILING_FM + INTENT (IN) :: MA + CALL FMINT(MA%MFM,MTFM) + CALL FMSUB(MA%MFM,MTFM,MUFM) + IF (MUFM(2) == 0) THEN + CALL FMEQ(MA%MFM,FMCEILING_FM%MFM) + ELSE IF (MA%MFM(-1) > 0) THEN + CALL FMADDI(MTFM,1) + CALL FMEQ(MTFM,FMCEILING_FM%MFM) + ELSE + CALL FMEQ(MTFM,FMCEILING_FM%MFM) + ENDIF + END FUNCTION + + FUNCTION FMCEILING_ZM(MA) + USE FMVALS + TYPE ( ZM ) MA,FMCEILING_ZM + INTENT (IN) :: MA + CALL FMINT(MA%MZM,MTFM) + CALL FMSUB(MA%MZM,MTFM,MUFM) + IF (MUFM(2) == 0) THEN + CALL FMEQ(MA%MZM,MVFM) + ELSE IF (MA%MZM(-1) > 0) THEN + CALL FMADDI(MTFM,1) + CALL FMEQ(MTFM,MVFM) + ELSE + CALL FMEQ(MTFM,MVFM) + ENDIF + CALL FMINT(MA%MZM(KPTIMU-1),MTFM) + CALL FMSUB(MA%MZM(KPTIMU-1),MTFM,MUFM) + IF (MUFM(2) == 0) THEN + CALL FMEQ(MA%MZM(KPTIMU-1),MUFM) + ELSE IF (MA%MZM(KPTIMU-1) > 0) THEN + CALL FMADDI(MTFM,1) + CALL FMEQ(MTFM,MUFM) + ELSE + CALL FMEQ(MTFM,MUFM) + ENDIF + CALL ZMCMPX(MVFM,MUFM,FMCEILING_ZM%MZM) + END FUNCTION + +! CMPLX + + FUNCTION FMCMPLX_FM(MA,MB) + USE FMVALS + TYPE ( ZM ) FMCMPLX_FM + TYPE ( FM ) MA + TYPE ( FM ), OPTIONAL :: MB + INTENT (IN) :: MA,MB + IF (PRESENT(MB)) THEN + CALL ZMCMPX(MA%MFM,MB%MFM,FMCMPLX_FM%MZM) + ELSE + CALL FMI2M(0,MTFM) + CALL ZMCMPX(MA%MFM,MTFM,FMCMPLX_FM%MZM) + ENDIF + END FUNCTION + + FUNCTION FMCMPLX_IM(MA,MB) + USE FMVALS + TYPE ( ZM ) FMCMPLX_IM + TYPE ( IM ) MA + TYPE ( IM ), OPTIONAL :: MB + INTENT (IN) :: MA,MB + IF (PRESENT(MB)) THEN + CALL IMI2FM(MA%MIM,MTFM) + CALL IMI2FM(MB%MIM,MUFM) + CALL ZMCMPX(MTFM,MUFM,FMCMPLX_IM%MZM) + ELSE + CALL IMI2FM(MA%MIM,MTFM) + CALL FMI2M(0,MUFM) + CALL ZMCMPX(MTFM,MUFM,FMCMPLX_IM%MZM) + ENDIF + END FUNCTION + +! CONJG + + FUNCTION FMCONJG_ZM(MA) + USE FMVALS + TYPE ( ZM ) FMCONJG_ZM,MA + INTENT (IN) :: MA + CALL ZMCONJ(MA%MZM,FMCONJG_ZM%MZM) + END FUNCTION + +! COS + + FUNCTION FMCOS_FM(MA) + USE FMVALS + TYPE ( FM ) MA,FMCOS_FM + INTENT (IN) :: MA + CALL FMCOS(MA%MFM,FMCOS_FM%MFM) + END FUNCTION + + FUNCTION FMCOS_ZM(MA) + USE FMVALS + TYPE ( ZM ) MA,FMCOS_ZM + INTENT (IN) :: MA + CALL ZMCOS(MA%MZM,FMCOS_ZM%MZM) + END FUNCTION + +! COSH + + FUNCTION FMCOSH_FM(MA) + USE FMVALS + TYPE ( FM ) MA,FMCOSH_FM + INTENT (IN) :: MA + CALL FMCOSH(MA%MFM,FMCOSH_FM%MFM) + END FUNCTION + + FUNCTION FMCOSH_ZM(MA) + USE FMVALS + TYPE ( ZM ) MA,FMCOSH_ZM + INTENT (IN) :: MA + CALL ZMCOSH(MA%MZM,FMCOSH_ZM%MZM) + END FUNCTION + +! DBLE + + FUNCTION FMDBLE_FM(MA) + USE FMVALS + TYPE ( FM ) MA,FMDBLE_FM + INTENT (IN) :: MA + CALL FMEQ(MA%MFM,FMDBLE_FM%MFM) + END FUNCTION + + FUNCTION FMDBLE_IM(MA) + USE FMVALS + TYPE ( FM ) FMDBLE_IM + TYPE ( IM ) MA + INTENT (IN) :: MA + CALL IMI2FM(MA%MIM,FMDBLE_IM%MFM) + END FUNCTION + + FUNCTION FMDBLE_ZM(MA) + USE FMVALS + TYPE ( FM ) FMDBLE_ZM + TYPE ( ZM ) MA + INTENT (IN) :: MA + CALL ZMREAL(MA%MZM,FMDBLE_ZM%MFM) + END FUNCTION + +! DIGITS + + FUNCTION FMDIGITS_FM(MA) + USE FMVALS + TYPE ( FM ) MA + INTEGER FMDIGITS_FM + INTENT (IN) :: MA + FMDIGITS_FM = NDIG + END FUNCTION + + FUNCTION FMDIGITS_IM(MA) + USE FMVALS + TYPE ( IM ) MA + INTEGER FMDIGITS_IM + INTENT (IN) :: MA + FMDIGITS_IM = NDIGMX + END FUNCTION + + FUNCTION FMDIGITS_ZM(MA) + USE FMVALS + INTEGER FMDIGITS_ZM + TYPE ( ZM ) MA + INTENT (IN) :: MA + FMDIGITS_ZM = NDIG + END FUNCTION + +! DIM + + FUNCTION FMDIM_FM(MA,MB) + USE FMVALS + TYPE ( FM ) MA,MB,FMDIM_FM + INTENT (IN) :: MA,MB + CALL FMDIM(MA%MFM,MB%MFM,FMDIM_FM%MFM) + END FUNCTION + + FUNCTION FMDIM_IM(MA,MB) + USE FMVALS + TYPE ( IM ) MA,MB,FMDIM_IM + INTENT (IN) :: MA,MB + CALL IMDIM(MA%MIM,MB%MIM,FMDIM_IM%MIM) + END FUNCTION + +! DINT + + FUNCTION FMDINT_FM(MA) + USE FMVALS + TYPE ( FM ) MA,FMDINT_FM + INTENT (IN) :: MA + CALL FMINT(MA%MFM,FMDINT_FM%MFM) + END FUNCTION + + FUNCTION FMDINT_ZM(MA) + USE FMVALS + TYPE ( ZM ) MA,FMDINT_ZM + INTENT (IN) :: MA + CALL ZMINT(MA%MZM,FMDINT_ZM%MZM) + END FUNCTION + +! DOTPRODUCT + + FUNCTION FMDOTPRODUCT_FM(MA,MB) + USE FMVALS + TYPE ( FM ) MA(:),MB(:),FMDOTPRODUCT_FM + INTEGER J,JA,JB,NDSAVE + INTENT (IN) :: MA,MB + IF (SIZE(MA) == SIZE(MB)) THEN + NDSAVE = NDIG + J = MAX(NGRD52,2) + NDIG = MIN(MAX(NDIG+J,2),NDG2MX) + CALL FMI2M(0,FMDOTPRODUCT_FM%MFM) + DO J = 1, SIZE(MA) + JA = LBOUND(MA,DIM=1) + J - 1 + JB = LBOUND(MB,DIM=1) + J - 1 + CALL FMEQ2(MA(JA)%MFM,MUFM,NDSAVE,NDIG) + CALL FMEQ2(MB(JB)%MFM,MVFM,NDSAVE,NDIG) + CALL FMMPY(MUFM,MVFM,MTFM) + CALL FMADD_R1(FMDOTPRODUCT_FM%MFM,MTFM) + ENDDO + CALL FMEQ2(FMDOTPRODUCT_FM%MFM,MTFM,NDIG,NDSAVE) + CALL FMEQ(MTFM,FMDOTPRODUCT_FM%MFM) + NDIG = NDSAVE + ELSE + CALL FMI2M(1,MTFM) + CALL FMI2M(0,MUFM) + CALL FMDIV(MTFM,MUFM,FMDOTPRODUCT_FM%MFM) + ENDIF + END FUNCTION + + FUNCTION FMDOTPRODUCT_IM(MA,MB) + USE FMVALS + TYPE ( IM ) MA(:),MB(:),FMDOTPRODUCT_IM + INTEGER J,JA,JB + INTENT (IN) :: MA,MB + IF (SIZE(MA) == SIZE(MB)) THEN + CALL IMI2M(0,FMDOTPRODUCT_IM%MIM) + DO J = 1, SIZE(MA) + JA = LBOUND(MA,DIM=1) + J - 1 + JB = LBOUND(MB,DIM=1) + J - 1 + CALL IMMPY(MA(JA)%MIM,MB(JB)%MIM,MTIM) + CALL IMADD(FMDOTPRODUCT_IM%MIM,MTIM,MUIM) + CALL IMEQ(MUIM,FMDOTPRODUCT_IM%MIM) + ENDDO + ELSE + CALL IMI2M(1,MTIM) + CALL IMI2M(0,MUIM) + CALL IMDIV(MTIM,MUIM,FMDOTPRODUCT_IM%MIM) + ENDIF + END FUNCTION + + FUNCTION FMDOTPRODUCT_ZM(MA,MB) + USE FMVALS + TYPE ( ZM ) MA(:),MB(:),FMDOTPRODUCT_ZM + INTEGER J,JA,JB,NDSAVE + INTENT (IN) :: MA,MB + IF (SIZE(MA) == SIZE(MB)) THEN + NDSAVE = NDIG + J = MAX(NGRD52,2) + NDIG = MIN(MAX(NDIG+J,2),NDG2MX) + CALL ZMI2M(0,FMDOTPRODUCT_ZM%MZM) + DO J = 1, SIZE(MA) + JA = LBOUND(MA,DIM=1) + J - 1 + JB = LBOUND(MB,DIM=1) + J - 1 + CALL ZMEQ2(MA(JA)%MZM,MUZM,NDSAVE,NDIG) + CALL ZMEQ2(MB(JB)%MZM,MVZM,NDSAVE,NDIG) + CALL ZMMPY(MUZM,MVZM,MTZM) + CALL ZMADD(FMDOTPRODUCT_ZM%MZM,MTZM,MUZM) + CALL ZMEQ(MUZM,FMDOTPRODUCT_ZM%MZM) + ENDDO + CALL ZMEQ2(FMDOTPRODUCT_ZM%MZM,MTZM,NDIG,NDSAVE) + CALL ZMEQ(MTZM,FMDOTPRODUCT_ZM%MZM) + NDIG = NDSAVE + ELSE + CALL ZMI2M(1,MTZM) + CALL ZMI2M(0,MUZM) + CALL ZMDIV(MTZM,MUZM,FMDOTPRODUCT_ZM%MZM) + ENDIF + END FUNCTION + + END MODULE FMZM_7 + + MODULE FMZM_8 + USE FMZM_1 + + INTERFACE EPSILON + MODULE PROCEDURE FMEPSILON_FM + END INTERFACE + + INTERFACE EXP + MODULE PROCEDURE FMEXP_FM + MODULE PROCEDURE FMEXP_ZM + END INTERFACE + + INTERFACE EXPONENT + MODULE PROCEDURE FMEXPONENT_FM + END INTERFACE + + INTERFACE FLOOR + MODULE PROCEDURE FMFLOOR_FM + MODULE PROCEDURE FMFLOOR_IM + MODULE PROCEDURE FMFLOOR_ZM + END INTERFACE + + INTERFACE FRACTION + MODULE PROCEDURE FMFRACTION_FM + MODULE PROCEDURE FMFRACTION_ZM + END INTERFACE + + INTERFACE HUGE + MODULE PROCEDURE FMHUGE_FM + MODULE PROCEDURE FMHUGE_IM + MODULE PROCEDURE FMHUGE_ZM + END INTERFACE + + INTERFACE INT + MODULE PROCEDURE FMINT_FM + MODULE PROCEDURE FMINT_IM + MODULE PROCEDURE FMINT_ZM + END INTERFACE + + INTERFACE LOG + MODULE PROCEDURE FMLOG_FM + MODULE PROCEDURE FMLOG_ZM + END INTERFACE + + INTERFACE LOG10 + MODULE PROCEDURE FMLOG10_FM + MODULE PROCEDURE FMLOG10_ZM + END INTERFACE + + INTERFACE MATMUL + MODULE PROCEDURE FMMATMUL_FM + MODULE PROCEDURE FMMATMUL_IM + MODULE PROCEDURE FMMATMUL_ZM + END INTERFACE + + INTERFACE MAX + MODULE PROCEDURE FMMAX_FM + MODULE PROCEDURE FMMAX_IM + END INTERFACE + + INTERFACE MAXEXPONENT + MODULE PROCEDURE FMMAXEXPONENT_FM + END INTERFACE + + INTERFACE MIN + MODULE PROCEDURE FMMIN_FM + MODULE PROCEDURE FMMIN_IM + END INTERFACE + + INTERFACE MINEXPONENT + MODULE PROCEDURE FMMINEXPONENT_FM + END INTERFACE + + INTERFACE MOD + MODULE PROCEDURE FMMOD_FM + MODULE PROCEDURE FMMOD_IM + END INTERFACE + + INTERFACE MODULO + MODULE PROCEDURE FMMODULO_FM + MODULE PROCEDURE FMMODULO_IM + END INTERFACE + + INTERFACE NEAREST + MODULE PROCEDURE FMNEAREST_FM + END INTERFACE + + INTERFACE NINT + MODULE PROCEDURE FMNINT_FM + MODULE PROCEDURE FMNINT_IM + MODULE PROCEDURE FMNINT_ZM + END INTERFACE + + INTERFACE PRECISION + MODULE PROCEDURE FMPRECISION_FM + MODULE PROCEDURE FMPRECISION_ZM + END INTERFACE + + INTERFACE RADIX + MODULE PROCEDURE FMRADIX_FM + MODULE PROCEDURE FMRADIX_IM + MODULE PROCEDURE FMRADIX_ZM + END INTERFACE + + INTERFACE RANGE + MODULE PROCEDURE FMRANGE_FM + MODULE PROCEDURE FMRANGE_IM + MODULE PROCEDURE FMRANGE_ZM + END INTERFACE + + INTERFACE REAL + MODULE PROCEDURE FMREAL_FM + MODULE PROCEDURE FMREAL_IM + MODULE PROCEDURE FMREAL_ZM + END INTERFACE + + INTERFACE RRSPACING + MODULE PROCEDURE FMRRSPACING_FM + END INTERFACE + + INTERFACE SCALE + MODULE PROCEDURE FMSCALE_FM + MODULE PROCEDURE FMSCALE_ZM + END INTERFACE + + INTERFACE SETEXPONENT + MODULE PROCEDURE FMSETEXPONENT_FM + END INTERFACE + + INTERFACE SIGN + MODULE PROCEDURE FMSIGN_FM + MODULE PROCEDURE FMSIGN_IM + END INTERFACE + + CONTAINS + +! EPSILON + + FUNCTION FMEPSILON_FM(MA) + USE FMVALS + TYPE ( FM ) MA,FMEPSILON_FM + INTENT (IN) :: MA + CALL FMI2M(1,MTFM) + CALL FMULP(MTFM,FMEPSILON_FM%MFM) + END FUNCTION + +! EXP + + FUNCTION FMEXP_FM(MA) + USE FMVALS + TYPE ( FM ) MA,FMEXP_FM + INTENT (IN) :: MA + CALL FMEXP(MA%MFM,FMEXP_FM%MFM) + END FUNCTION + + FUNCTION FMEXP_ZM(MA) + USE FMVALS + TYPE ( ZM ) MA,FMEXP_ZM + INTENT (IN) :: MA + CALL ZMEXP(MA%MZM,FMEXP_ZM%MZM) + END FUNCTION + +! EXPONENT + + FUNCTION FMEXPONENT_FM(MA) + TYPE ( FM ) MA + INTEGER FMEXPONENT_FM + INTENT (IN) :: MA + FMEXPONENT_FM = INT(MA%MFM(1)) + END FUNCTION + +! FLOOR + + FUNCTION FMFLOOR_FM(MA) + USE FMVALS + TYPE ( FM ) MA,FMFLOOR_FM + INTENT (IN) :: MA + CALL FMINT(MA%MFM,MTFM) + CALL FMSUB(MA%MFM,MTFM,MUFM) + IF (MUFM(2) == 0) THEN + CALL FMEQ(MA%MFM,FMFLOOR_FM%MFM) + ELSE IF (MA%MFM(-1) < 0) THEN + CALL FMADDI(MTFM,-1) + CALL FMEQ(MTFM,FMFLOOR_FM%MFM) + ELSE + CALL FMEQ(MTFM,FMFLOOR_FM%MFM) + ENDIF + END FUNCTION + + FUNCTION FMFLOOR_IM(MA) + USE FMVALS + TYPE ( IM ) MA,FMFLOOR_IM + INTENT (IN) :: MA + CALL IMEQ(MA%MIM,FMFLOOR_IM%MIM) + END FUNCTION + + FUNCTION FMFLOOR_ZM(MA) + USE FMVALS + TYPE ( ZM ) MA,FMFLOOR_ZM + INTENT (IN) :: MA + CALL FMINT(MA%MZM,MTFM) + CALL FMSUB(MA%MZM,MTFM,MUFM) + IF (MUFM(2) == 0) THEN + CALL FMEQ(MA%MZM,MVFM) + ELSE IF (MA%MZM(-1) < 0) THEN + CALL FMADDI(MTFM,-1) + CALL FMEQ(MTFM,MVFM) + ELSE + CALL FMEQ(MTFM,MVFM) + ENDIF + CALL FMINT(MA%MZM(KPTIMU-1),MTFM) + CALL FMSUB(MA%MZM(KPTIMU-1),MTFM,MUFM) + IF (MUFM(2) == 0) THEN + CALL FMEQ(MA%MZM(KPTIMU-1),MUFM) + ELSE IF (MA%MZM(KPTIMU-1) < 0) THEN + CALL FMADDI(MTFM,-1) + CALL FMEQ(MTFM,MUFM) + ELSE + CALL FMEQ(MTFM,MUFM) + ENDIF + CALL ZMCMPX(MVFM,MUFM,FMFLOOR_ZM%MZM) + END FUNCTION + +! FRACTION + + FUNCTION FMFRACTION_FM(MA) + USE FMVALS + TYPE ( FM ) MA,FMFRACTION_FM + INTENT (IN) :: MA + CALL FMEQ(MA%MFM,MTFM) + MTFM(1) = 0 + CALL FMEQ(MTFM,FMFRACTION_FM%MFM) + END FUNCTION + + FUNCTION FMFRACTION_ZM(MA) + USE FMVALS + TYPE ( ZM ) MA,FMFRACTION_ZM + INTENT (IN) :: MA + CALL ZMEQ(MA%MZM,MTZM) + MTZM(1) = 0 + MTZM(KPTIMU+1) = 0 + CALL ZMEQ(MTZM,FMFRACTION_ZM%MZM) + END FUNCTION + +! HUGE + + FUNCTION FMHUGE_FM(MA) + USE FMVALS + TYPE ( FM ) MA,FMHUGE_FM + INTENT (IN) :: MA + CALL FMBIG(FMHUGE_FM%MFM) + END FUNCTION + + FUNCTION FMHUGE_IM(MA) + USE FMVALS + TYPE ( IM ) MA,FMHUGE_IM + INTENT (IN) :: MA + CALL IMBIG(FMHUGE_IM%MIM) + END FUNCTION + + FUNCTION FMHUGE_ZM(MA) + USE FMVALS + TYPE ( ZM ) MA,FMHUGE_ZM + INTENT (IN) :: MA + CALL FMBIG(MTFM) + CALL ZMCMPX(MTFM,MTFM,FMHUGE_ZM%MZM) + END FUNCTION + +! INT + + FUNCTION FMINT_FM(MA) + USE FMVALS + TYPE ( FM ) MA + TYPE ( IM ) FMINT_FM + INTENT (IN) :: MA + CALL FMINT(MA%MFM,MTFM) + CALL IMFM2I(MTFM,FMINT_FM%MIM) + END FUNCTION + + FUNCTION FMINT_IM(MA) + USE FMVALS + TYPE ( IM ) MA,FMINT_IM + INTENT (IN) :: MA + CALL IMEQ(MA%MIM,FMINT_IM%MIM) + END FUNCTION + + FUNCTION FMINT_ZM(MA) + USE FMVALS + TYPE ( ZM ) MA + TYPE ( IM ) FMINT_ZM + INTENT (IN) :: MA + CALL ZMREAL(MA%MZM,MTFM) + CALL FMINT(MTFM,MUFM) + CALL IMFM2I(MUFM,FMINT_ZM%MIM) + END FUNCTION + +! LOG + + FUNCTION FMLOG_FM(MA) + USE FMVALS + TYPE ( FM ) MA,FMLOG_FM + INTENT (IN) :: MA + CALL FMLN(MA%MFM,FMLOG_FM%MFM) + END FUNCTION + + FUNCTION FMLOG_ZM(MA) + USE FMVALS + TYPE ( ZM ) MA,FMLOG_ZM + INTENT (IN) :: MA + CALL ZMLN(MA%MZM,FMLOG_ZM%MZM) + END FUNCTION + +! LOG10 + + FUNCTION FMLOG10_FM(MA) + USE FMVALS + TYPE ( FM ) MA,FMLOG10_FM + INTENT (IN) :: MA + CALL FMLG10(MA%MFM,FMLOG10_FM%MFM) + END FUNCTION + + FUNCTION FMLOG10_ZM(MA) + USE FMVALS + TYPE ( ZM ) MA,FMLOG10_ZM + INTENT (IN) :: MA + CALL ZMLG10(MA%MZM,FMLOG10_ZM%MZM) + END FUNCTION + +! MATMUL + + FUNCTION FMMATMUL_FM(MA,MB) RESULT(MC) + USE FMVALS + TYPE ( FM ) MA(:,:),MB(:,:) + TYPE ( FM ), DIMENSION(SIZE(MA,DIM=1),SIZE(MB,DIM=2)) :: MC + INTEGER I,J,K,NDSAVE + INTENT (IN) :: MA,MB + DO J = 1, SIZE(MA,DIM=1) + DO K = 1, SIZE(MB,DIM=2) + ENDDO + ENDDO + IF (SIZE(MA,DIM=2) == SIZE(MB,DIM=1)) THEN + NDSAVE = NDIG + J = MAX(NGRD52,2) + NDIG = MIN(MAX(NDIG+J,2),NDG2MX) + DO I = LBOUND(MA,DIM=1), UBOUND(MA,DIM=1) + DO J = LBOUND(MB,DIM=2), UBOUND(MB,DIM=2) + CALL FMI2M(0,MTFM) + DO K = LBOUND(MA,DIM=2), UBOUND(MA,DIM=2) + CALL FMEQ2(MA(I,K)%MFM,MUFM,NDSAVE,NDIG) + CALL FMEQ2(MB(K,J)%MFM,MVFM,NDSAVE,NDIG) + CALL FMMPY(MUFM,MVFM,M01) + CALL FMADD_R1(MTFM,M01) + ENDDO + CALL FMEQ2_R1(MTFM,NDIG,NDSAVE) + CALL FMEQ(MTFM,MC(I,J)%MFM) + ENDDO + ENDDO + NDIG = NDSAVE + ELSE + CALL FMI2M(1,MTFM) + CALL FMI2M(0,MUFM) + CALL FMDIV(MTFM,MUFM,MVFM) + DO I = 1, SIZE(MA,DIM=1) + DO J = 1, SIZE(MB,DIM=2) + CALL FMEQ(MVFM,MC(I,J)%MFM) + ENDDO + ENDDO + ENDIF + END FUNCTION + + FUNCTION FMMATMUL_IM(MA,MB) RESULT(MC) + USE FMVALS + TYPE ( IM ) MA(:,:),MB(:,:) + TYPE ( IM ), DIMENSION(SIZE(MA,DIM=1),SIZE(MB,DIM=2)) :: MC + INTEGER I,J,K + INTENT (IN) :: MA,MB + DO J = 1, SIZE(MA,DIM=1) + DO K = 1, SIZE(MB,DIM=2) + ENDDO + ENDDO + IF (SIZE(MA,DIM=2) == SIZE(MB,DIM=1)) THEN + DO I = LBOUND(MA,DIM=1), UBOUND(MA,DIM=1) + DO J = LBOUND(MB,DIM=2), UBOUND(MB,DIM=2) + CALL IMI2M(0,MTIM) + DO K = LBOUND(MA,DIM=2), UBOUND(MA,DIM=2) + CALL IMMPY(MA(I,K)%MIM,MB(K,J)%MIM,M01) + CALL IMADD(MTIM,M01,MUIM) + CALL IMEQ(MUIM,MTIM) + ENDDO + CALL IMEQ(MTIM,MC(I,J)%MIM) + ENDDO + ENDDO + ELSE + CALL IMI2M(1,MTIM) + CALL IMI2M(0,MUIM) + CALL IMDIV(MTIM,MUIM,MC(1,1)%MIM) + DO I = 1, SIZE(MA,DIM=1) + DO J = 1, SIZE(MB,DIM=2) + IF (I > 1 .OR. J > 1) CALL IMEQ(MC(1,1)%MIM,MC(I,J)%MIM) + ENDDO + ENDDO + ENDIF + END FUNCTION + + FUNCTION FMMATMUL_ZM(MA,MB) RESULT(MC) + USE FMVALS + TYPE ( ZM ) MA(:,:),MB(:,:) + TYPE ( ZM ), DIMENSION(SIZE(MA,DIM=1),SIZE(MB,DIM=2)) :: MC + INTEGER I,J,K,NDSAVE + INTENT (IN) :: MA,MB + DO J = 1, SIZE(MA,DIM=1) + DO K = 1, SIZE(MB,DIM=2) + ENDDO + ENDDO + IF (SIZE(MA,DIM=2) == SIZE(MB,DIM=1)) THEN + NDSAVE = NDIG + J = MAX(NGRD52,2) + NDIG = MIN(MAX(NDIG+J,2),NDG2MX) + DO I = LBOUND(MA,DIM=1), UBOUND(MA,DIM=1) + DO J = LBOUND(MB,DIM=2), UBOUND(MB,DIM=2) + CALL ZMI2M(0,MTZM) + DO K = LBOUND(MA,DIM=2), UBOUND(MA,DIM=2) + CALL ZMEQ2(MA(I,K)%MZM,MUZM,NDSAVE,NDIG) + CALL ZMEQ2(MB(K,J)%MZM,MVZM,NDSAVE,NDIG) + CALL ZMMPY(MUZM,MVZM,MZ02) + CALL ZMADD(MTZM,MZ02,MUZM) + CALL ZMEQ(MUZM,MTZM) + ENDDO + CALL ZMEQ2_R1(MTZM,NDIG,NDSAVE) + CALL ZMEQ(MTZM,MC(I,J)%MZM) + ENDDO + ENDDO + NDIG = NDSAVE + ELSE + CALL ZMI2M(1,MTZM) + CALL ZMI2M(0,MUZM) + CALL ZMDIV(MTZM,MUZM,MC(1,1)%MZM) + DO I = 1, SIZE(MA,DIM=1) + DO J = 1, SIZE(MB,DIM=2) + IF (I > 1 .OR. J > 1) CALL ZMEQ(MC(1,1)%MZM,MC(I,J)%MZM) + ENDDO + ENDDO + ENDIF + END FUNCTION + +! MAX + + FUNCTION FMMAX_FM(MA,MB,MC,MD,ME,MF,MG,MH,MI,MJ) + USE FMVALS + TYPE ( FM ) MA,MB,FMMAX_FM + TYPE ( FM ), OPTIONAL :: MC,MD,ME,MF,MG,MH,MI,MJ + INTENT (IN) :: MA,MB,MC,MD,ME,MF,MG,MH,MI,MJ + CALL FMMAX(MA%MFM,MB%MFM,MTFM) + IF (PRESENT(MC)) THEN + CALL FMMAX(MTFM,MC%MFM,MUFM) + CALL FMEQ(MUFM,MTFM) + ENDIF + IF (PRESENT(MD)) THEN + CALL FMMAX(MTFM,MD%MFM,MUFM) + CALL FMEQ(MUFM,MTFM) + ENDIF + IF (PRESENT(ME)) THEN + CALL FMMAX(MTFM,ME%MFM,MUFM) + CALL FMEQ(MUFM,MTFM) + ENDIF + IF (PRESENT(MF)) THEN + CALL FMMAX(MTFM,MF%MFM,MUFM) + CALL FMEQ(MUFM,MTFM) + ENDIF + IF (PRESENT(MG)) THEN + CALL FMMAX(MTFM,MG%MFM,MUFM) + CALL FMEQ(MUFM,MTFM) + ENDIF + IF (PRESENT(MH)) THEN + CALL FMMAX(MTFM,MH%MFM,MUFM) + CALL FMEQ(MUFM,MTFM) + ENDIF + IF (PRESENT(MI)) THEN + CALL FMMAX(MTFM,MI%MFM,MUFM) + CALL FMEQ(MUFM,MTFM) + ENDIF + IF (PRESENT(MJ)) THEN + CALL FMMAX(MTFM,MJ%MFM,MUFM) + CALL FMEQ(MUFM,MTFM) + ENDIF + CALL FMEQ(MTFM,FMMAX_FM%MFM) + END FUNCTION + + FUNCTION FMMAX_IM(MA,MB,MC,MD,ME,MF,MG,MH,MI,MJ) + USE FMVALS + TYPE ( IM ) MA,MB,FMMAX_IM + TYPE ( IM ), OPTIONAL :: MC,MD,ME,MF,MG,MH,MI,MJ + INTENT (IN) :: MA,MB,MC,MD,ME,MF,MG,MH,MI,MJ + CALL IMMAX(MA%MIM,MB%MIM,MTIM) + IF (PRESENT(MC)) THEN + CALL IMMAX(MTIM,MC%MIM,MUIM) + CALL IMEQ(MUIM,MTIM) + ENDIF + IF (PRESENT(MD)) THEN + CALL IMMAX(MTIM,MD%MIM,MUIM) + CALL IMEQ(MUIM,MTIM) + ENDIF + IF (PRESENT(ME)) THEN + CALL IMMAX(MTIM,ME%MIM,MUIM) + CALL IMEQ(MUIM,MTIM) + ENDIF + IF (PRESENT(MF)) THEN + CALL IMMAX(MTIM,MF%MIM,MUIM) + CALL IMEQ(MUIM,MTIM) + ENDIF + IF (PRESENT(MG)) THEN + CALL IMMAX(MTIM,MG%MIM,MUIM) + CALL IMEQ(MUIM,MTIM) + ENDIF + IF (PRESENT(MH)) THEN + CALL IMMAX(MTIM,MH%MIM,MUIM) + CALL IMEQ(MUIM,MTIM) + ENDIF + IF (PRESENT(MI)) THEN + CALL IMMAX(MTIM,MI%MIM,MUIM) + CALL IMEQ(MUIM,MTIM) + ENDIF + IF (PRESENT(MJ)) THEN + CALL IMMAX(MTIM,MJ%MIM,MUIM) + CALL IMEQ(MUIM,MTIM) + ENDIF + CALL IMEQ(MTIM,FMMAX_IM%MIM) + END FUNCTION + +! MAXEXPONENT + + FUNCTION FMMAXEXPONENT_FM(MA) + USE FMVALS + TYPE ( FM ) MA + INTEGER FMMAXEXPONENT_FM + INTENT (IN) :: MA + FMMAXEXPONENT_FM = INT(MXEXP) + 1 + END FUNCTION + +! MIN + + FUNCTION FMMIN_FM(MA,MB,MC,MD,ME,MF,MG,MH,MI,MJ) + USE FMVALS + TYPE ( FM ) MA,MB,FMMIN_FM + TYPE ( FM ), OPTIONAL :: MC,MD,ME,MF,MG,MH,MI,MJ + INTENT (IN) :: MA,MB,MC,MD,ME,MF,MG,MH,MI,MJ + CALL FMMIN(MA%MFM,MB%MFM,MTFM) + IF (PRESENT(MC)) THEN + CALL FMMIN(MTFM,MC%MFM,MUFM) + CALL FMEQ(MUFM,MTFM) + ENDIF + IF (PRESENT(MD)) THEN + CALL FMMIN(MTFM,MD%MFM,MUFM) + CALL FMEQ(MUFM,MTFM) + ENDIF + IF (PRESENT(ME)) THEN + CALL FMMIN(MTFM,ME%MFM,MUFM) + CALL FMEQ(MUFM,MTFM) + ENDIF + IF (PRESENT(MF)) THEN + CALL FMMIN(MTFM,MF%MFM,MUFM) + CALL FMEQ(MUFM,MTFM) + ENDIF + IF (PRESENT(MG)) THEN + CALL FMMIN(MTFM,MG%MFM,MUFM) + CALL FMEQ(MUFM,MTFM) + ENDIF + IF (PRESENT(MH)) THEN + CALL FMMIN(MTFM,MH%MFM,MUFM) + CALL FMEQ(MUFM,MTFM) + ENDIF + IF (PRESENT(MI)) THEN + CALL FMMIN(MTFM,MI%MFM,MUFM) + CALL FMEQ(MUFM,MTFM) + ENDIF + IF (PRESENT(MJ)) THEN + CALL FMMIN(MTFM,MJ%MFM,MUFM) + CALL FMEQ(MUFM,MTFM) + ENDIF + CALL FMEQ(MTFM,FMMIN_FM%MFM) + END FUNCTION + + FUNCTION FMMIN_IM(MA,MB,MC,MD,ME,MF,MG,MH,MI,MJ) + USE FMVALS + TYPE ( IM ) MA,MB,FMMIN_IM + TYPE ( IM ), OPTIONAL :: MC,MD,ME,MF,MG,MH,MI,MJ + INTENT (IN) :: MA,MB,MC,MD,ME,MF,MG,MH,MI,MJ + CALL IMMIN(MA%MIM,MB%MIM,MTIM) + IF (PRESENT(MC)) THEN + CALL IMMIN(MTIM,MC%MIM,MUIM) + CALL IMEQ(MUIM,MTIM) + ENDIF + IF (PRESENT(MD)) THEN + CALL IMMIN(MTIM,MD%MIM,MUIM) + CALL IMEQ(MUIM,MTIM) + ENDIF + IF (PRESENT(ME)) THEN + CALL IMMIN(MTIM,ME%MIM,MUIM) + CALL IMEQ(MUIM,MTIM) + ENDIF + IF (PRESENT(MF)) THEN + CALL IMMIN(MTIM,MF%MIM,MUIM) + CALL IMEQ(MUIM,MTIM) + ENDIF + IF (PRESENT(MG)) THEN + CALL IMMIN(MTIM,MG%MIM,MUIM) + CALL IMEQ(MUIM,MTIM) + ENDIF + IF (PRESENT(MH)) THEN + CALL IMMIN(MTIM,MH%MIM,MUIM) + CALL IMEQ(MUIM,MTIM) + ENDIF + IF (PRESENT(MI)) THEN + CALL IMMIN(MTIM,MI%MIM,MUIM) + CALL IMEQ(MUIM,MTIM) + ENDIF + IF (PRESENT(MJ)) THEN + CALL IMMIN(MTIM,MJ%MIM,MUIM) + CALL IMEQ(MUIM,MTIM) + ENDIF + CALL IMEQ(MTIM,FMMIN_IM%MIM) + END FUNCTION + +! MINEXPONENT + + FUNCTION FMMINEXPONENT_FM(MA) + USE FMVALS + TYPE ( FM ) MA + INTEGER FMMINEXPONENT_FM + INTENT (IN) :: MA + FMMINEXPONENT_FM = -INT(MXEXP) + END FUNCTION + +! MOD + + FUNCTION FMMOD_FM(MA,MB) + USE FMVALS + TYPE ( FM ) MA,MB,FMMOD_FM + INTENT (IN) :: MA,MB + CALL FMMOD(MA%MFM,MB%MFM,FMMOD_FM%MFM) + END FUNCTION + + FUNCTION FMMOD_IM(MA,MB) + USE FMVALS + TYPE ( IM ) MA,MB,FMMOD_IM + INTENT (IN) :: MA,MB + CALL IMMOD(MA%MIM,MB%MIM,FMMOD_IM%MIM) + END FUNCTION + +! MODULO + + FUNCTION FMMODULO_FM(MA,MB) + USE FMVALS + TYPE ( FM ) MA,MB,FMMODULO_FM + INTENT (IN) :: MA,MB + CALL FMMOD(MA%MFM,MB%MFM,MTFM) + IF (MTFM(2) /= 0) THEN + IF ((MA%MFM(2) > 0 .AND. MA%MFM(-1) > 0 .AND. & + MB%MFM(2) > 0 .AND. MB%MFM(-1) < 0) .OR. & + (MA%MFM(2) > 0 .AND. MA%MFM(-1) < 0 .AND. & + MB%MFM(2) > 0 .AND. MB%MFM(-1) > 0)) THEN + CALL FMADD_R1(MTFM,MB%MFM) + ENDIF + ENDIF + CALL FMEQ(MTFM,FMMODULO_FM%MFM) + END FUNCTION + + FUNCTION FMMODULO_IM(MA,MB) + USE FMVALS + TYPE ( IM ) MA,MB,FMMODULO_IM + INTENT (IN) :: MA,MB + CALL IMMOD(MA%MIM,MB%MIM,MTIM) + IF (MTIM(2) /= 0) THEN + IF ((MA%MIM(2) > 0 .AND. MA%MIM(-1) > 0 .AND. & + MB%MIM(2) > 0 .AND. MB%MIM(-1) < 0) .OR. & + (MA%MIM(2) > 0 .AND. MA%MIM(-1) < 0 .AND. & + MB%MIM(2) > 0 .AND. MB%MIM(-1) > 0)) THEN + CALL IMADD(MTIM,MB%MIM,MUIM) + CALL IMEQ(MUIM,MTIM) + ENDIF + ENDIF + CALL IMEQ(MTIM,FMMODULO_IM%MIM) + END FUNCTION + +! NEAREST + + FUNCTION FMNEAREST_FM(MA,MB) + USE FMVALS + TYPE ( FM ) MA,MB,FMNEAREST_FM + LOGICAL FMCOMP + INTENT (IN) :: MA,MB + IF (MA%MFM(2) == 0) THEN + IF (MB%MFM(-1) > 0) THEN + CALL FMBIG(MTFM) + CALL FMI2M(1,MUFM) + CALL FMDIV(MUFM,MTFM,FMNEAREST_FM%MFM) + ELSE + CALL FMBIG(MTFM) + CALL FMI2M(-1,MUFM) + CALL FMDIV(MUFM,MTFM,FMNEAREST_FM%MFM) + ENDIF + ELSE + IF (MB%MFM(-1) > 0) THEN + CALL FMULP(MA%MFM,MTFM) + MTFM(-1) = 1 + CALL FMADD(MA%MFM,MTFM,MUFM) + CALL FMULP(MUFM,MVFM) + CALL FMABS(MVFM,MUFM) + IF (FMCOMP(MTFM,'LE',MUFM)) THEN + CALL FMADD(MA%MFM,MTFM,FMNEAREST_FM%MFM) + ELSE + CALL FMADD(MA%MFM,MUFM,FMNEAREST_FM%MFM) + ENDIF + ELSE + CALL FMULP(MA%MFM,MTFM) + MTFM(-1) = 1 + CALL FMSUB(MA%MFM,MTFM,MUFM) + CALL FMULP(MUFM,MVFM) + CALL FMABS(MVFM,MUFM) + IF (FMCOMP(MTFM,'LE',MUFM)) THEN + CALL FMSUB(MA%MFM,MTFM,FMNEAREST_FM%MFM) + ELSE + CALL FMSUB(MA%MFM,MUFM,FMNEAREST_FM%MFM) + ENDIF + ENDIF + ENDIF + END FUNCTION + +! NINT + + FUNCTION FMNINT_FM(MA) + USE FMVALS + TYPE ( FM ) MA + TYPE ( IM ) FMNINT_FM + INTENT (IN) :: MA + CALL FMNINT(MA%MFM,MTFM) + CALL IMFM2I(MTFM,FMNINT_FM%MIM) + END FUNCTION + + FUNCTION FMNINT_IM(MA) + USE FMVALS + TYPE ( IM ) MA,FMNINT_IM + INTENT (IN) :: MA + CALL IMEQ(MA%MIM,FMNINT_IM%MIM) + END FUNCTION + + FUNCTION FMNINT_ZM(MA) + USE FMVALS + TYPE ( ZM ) MA + TYPE ( IM ) FMNINT_ZM + INTENT (IN) :: MA + CALL ZMREAL(MA%MZM,MTFM) + CALL FMNINT(MTFM,MUFM) + CALL IMFM2I(MUFM,FMNINT_ZM%MIM) + END FUNCTION + +! PRECISION + + FUNCTION FMPRECISION_FM(MA) + USE FMVALS + TYPE ( FM ) MA + INTEGER FMPRECISION_FM + INTENT (IN) :: MA + FMPRECISION_FM = INT(LOG10(REAL(MBASE))*(NDIG-1) + 1) + END FUNCTION + + FUNCTION FMPRECISION_ZM(MA) + USE FMVALS + TYPE ( ZM ) MA + INTEGER FMPRECISION_ZM + INTENT (IN) :: MA + FMPRECISION_ZM = INT(LOG10(REAL(MBASE))*(NDIG-1) + 1) + END FUNCTION + +! RADIX + + FUNCTION FMRADIX_FM(MA) + USE FMVALS + TYPE ( FM ) MA + INTEGER FMRADIX_FM + INTENT (IN) :: MA + FMRADIX_FM = INT(MBASE) + END FUNCTION + + FUNCTION FMRADIX_IM(MA) + USE FMVALS + TYPE ( IM ) MA + INTEGER FMRADIX_IM + INTENT (IN) :: MA + FMRADIX_IM = INT(MBASE) + END FUNCTION + + FUNCTION FMRADIX_ZM(MA) + USE FMVALS + TYPE ( ZM ) MA + INTEGER FMRADIX_ZM + INTENT (IN) :: MA + FMRADIX_ZM = INT(MBASE) + END FUNCTION + +! RANGE + + FUNCTION FMRANGE_FM(MA) + USE FMVALS + TYPE ( FM ) MA + INTEGER FMRANGE_FM + INTENT (IN) :: MA + FMRANGE_FM = INT(MXEXP*LOG10(REAL(MBASE))) + END FUNCTION + + FUNCTION FMRANGE_IM(MA) + USE FMVALS + TYPE ( IM ) MA + INTEGER FMRANGE_IM + INTENT (IN) :: MA + FMRANGE_IM = INT(NDIGMX*LOG10(REAL(MBASE))) + END FUNCTION + + FUNCTION FMRANGE_ZM(MA) + USE FMVALS + TYPE ( ZM ) MA + INTEGER FMRANGE_ZM + INTENT (IN) :: MA + FMRANGE_ZM = INT(MXEXP*LOG10(REAL(MBASE))) + END FUNCTION + +! REAL + + FUNCTION FMREAL_FM(MA) + USE FMVALS + TYPE ( FM ) MA,FMREAL_FM + INTENT (IN) :: MA + CALL FMEQ(MA%MFM,FMREAL_FM%MFM) + END FUNCTION + + FUNCTION FMREAL_IM(MA) + USE FMVALS + TYPE ( FM ) FMREAL_IM + TYPE ( IM ) MA + INTENT (IN) :: MA + CALL IMI2FM(MA%MIM,FMREAL_IM%MFM) + END FUNCTION + + FUNCTION FMREAL_ZM(MA) + USE FMVALS + TYPE ( FM ) FMREAL_ZM + TYPE ( ZM ) MA + INTENT (IN) :: MA + CALL ZMREAL(MA%MZM,FMREAL_ZM%MFM) + END FUNCTION + +! RRSPACING + + FUNCTION FMRRSPACING_FM(MA) + USE FMVALS + TYPE ( FM ) MA,FMRRSPACING_FM + INTENT (IN) :: MA + CALL FMABS(MA%MFM,MTFM) + MTFM(1) = NDIG + CALL FMEQ(MTFM,FMRRSPACING_FM%MFM) + END FUNCTION + +! SCALE + + FUNCTION FMSCALE_FM(MA,L) + USE FMVALS + TYPE ( FM ) MA,FMSCALE_FM + INTEGER L + INTENT (IN) :: MA,L + CALL FMEQ(MA%MFM,MTFM) + IF (ABS(MTFM(1)+L) < MXEXP) THEN + MTFM(1) = MTFM(1) + L + CALL FMEQ(MTFM,FMSCALE_FM%MFM) + ELSE + CALL FMI2M(INT(MBASE),MUFM) + CALL FMIPWR(MUFM,L,MVFM) + CALL FMMPY(MA%MFM,MVFM,FMSCALE_FM%MFM) + ENDIF + END FUNCTION + + FUNCTION FMSCALE_ZM(MA,L) + USE FMVALS + INTEGER L + TYPE ( ZM ) MA,FMSCALE_ZM + INTENT (IN) :: MA,L + CALL ZMEQ(MA%MZM,MTZM) + IF (ABS(MTZM(1)+L) < MXEXP .AND. & + ABS(MTZM(KPTIMU+1)+L) < MXEXP) THEN + MTZM(1) = MTZM(1) + L + MTZM(KPTIMU+1) = MTZM(KPTIMU+1) + L + CALL ZMEQ(MTZM,FMSCALE_ZM%MZM) + ELSE + CALL ZMI2M(INT(MBASE),MUZM) + CALL ZMIPWR(MUZM,L,MVZM) + CALL ZMMPY(MA%MZM,MVZM,FMSCALE_ZM%MZM) + ENDIF + END FUNCTION + +! SETEXPONENT + + FUNCTION FMSETEXPONENT_FM(MA,L) + USE FMVALS + TYPE ( FM ) MA,FMSETEXPONENT_FM + INTEGER L + INTENT (IN) :: MA,L + CALL FMEQ(MA%MFM,MTFM) + MTFM(1) = L + CALL FMEQ(MTFM,FMSETEXPONENT_FM%MFM) + END FUNCTION + +! SIGN + + FUNCTION FMSIGN_FM(MA,MB) + USE FMVALS + TYPE ( FM ) MA,MB,FMSIGN_FM + INTENT (IN) :: MA,MB + CALL FMSIGN(MA%MFM,MB%MFM,FMSIGN_FM%MFM) + END FUNCTION + + FUNCTION FMSIGN_IM(MA,MB) + USE FMVALS + TYPE ( IM ) MA,MB,FMSIGN_IM + INTENT (IN) :: MA,MB + CALL IMSIGN(MA%MIM,MB%MIM,FMSIGN_IM%MIM) + END FUNCTION + + END MODULE FMZM_8 + + MODULE FMZM_9 + USE FMZM_1 + + INTERFACE SIN + MODULE PROCEDURE FMSIN_FM + MODULE PROCEDURE FMSIN_ZM + END INTERFACE + + INTERFACE SINH + MODULE PROCEDURE FMSINH_FM + MODULE PROCEDURE FMSINH_ZM + END INTERFACE + + INTERFACE SPACING + MODULE PROCEDURE FMSPACING_FM + END INTERFACE + + INTERFACE SQRT + MODULE PROCEDURE FMSQRT_FM + MODULE PROCEDURE FMSQRT_ZM + END INTERFACE + + INTERFACE TAN + MODULE PROCEDURE FMTAN_FM + MODULE PROCEDURE FMTAN_ZM + END INTERFACE + + INTERFACE TANH + MODULE PROCEDURE FMTANH_FM + MODULE PROCEDURE FMTANH_ZM + END INTERFACE + + INTERFACE TINY + MODULE PROCEDURE FMTINY_FM + MODULE PROCEDURE FMTINY_IM + MODULE PROCEDURE FMTINY_ZM + END INTERFACE + + INTERFACE TO_FM + MODULE PROCEDURE FM_I + MODULE PROCEDURE FM_R + MODULE PROCEDURE FM_D + MODULE PROCEDURE FM_Z + MODULE PROCEDURE FM_C + MODULE PROCEDURE FM_FM + MODULE PROCEDURE FM_IM + MODULE PROCEDURE FM_ZM + MODULE PROCEDURE FM_ST + END INTERFACE + + INTERFACE TO_IM + MODULE PROCEDURE IM_I + MODULE PROCEDURE IM_R + MODULE PROCEDURE IM_D + MODULE PROCEDURE IM_Z + MODULE PROCEDURE IM_C + MODULE PROCEDURE IM_FM + MODULE PROCEDURE IM_IM + MODULE PROCEDURE IM_ZM + MODULE PROCEDURE IM_ST + END INTERFACE + + INTERFACE TO_ZM + MODULE PROCEDURE ZM_I + MODULE PROCEDURE ZM_R + MODULE PROCEDURE ZM_D + MODULE PROCEDURE ZM_Z + MODULE PROCEDURE ZM_C + MODULE PROCEDURE ZM_FM + MODULE PROCEDURE ZM_IM + MODULE PROCEDURE ZM_ZM + MODULE PROCEDURE ZM_ST + END INTERFACE + + INTERFACE TO_INT + MODULE PROCEDURE FM_2INT + MODULE PROCEDURE IM_2INT + MODULE PROCEDURE ZM_2INT + END INTERFACE + + INTERFACE TO_SP + MODULE PROCEDURE FM_2SP + MODULE PROCEDURE IM_2SP + MODULE PROCEDURE ZM_2SP + END INTERFACE + + INTERFACE TO_DP + MODULE PROCEDURE FM_2DP + MODULE PROCEDURE IM_2DP + MODULE PROCEDURE ZM_2DP + END INTERFACE + + INTERFACE TO_SPZ + MODULE PROCEDURE FM_2SPZ + MODULE PROCEDURE IM_2SPZ + MODULE PROCEDURE ZM_2SPZ + END INTERFACE + + INTERFACE TO_DPZ + MODULE PROCEDURE FM_2DPZ + MODULE PROCEDURE IM_2DPZ + MODULE PROCEDURE ZM_2DPZ + END INTERFACE + + + INTERFACE FM_FORMAT + MODULE PROCEDURE FMFORMAT_FM + END INTERFACE + + INTERFACE IM_FORMAT + MODULE PROCEDURE IMFORMAT_IM + END INTERFACE + + INTERFACE ZM_FORMAT + MODULE PROCEDURE ZMFORMAT_ZM + END INTERFACE + + INTERFACE GCD + MODULE PROCEDURE GCD_IM + END INTERFACE + + INTERFACE MULTIPLY_MOD + MODULE PROCEDURE MULTIPLYMOD_IM + END INTERFACE + + INTERFACE POWER_MOD + MODULE PROCEDURE POWERMOD_IM + END INTERFACE + + INTERFACE FM_RANDOM_SEED + MODULE PROCEDURE FM_SEED + END INTERFACE + + INTERFACE BERNOULLI + MODULE PROCEDURE FMBERNOULLI_FM + END INTERFACE + + INTERFACE BETA + MODULE PROCEDURE FMBETA_FM + END INTERFACE + + INTERFACE BINOMIAL + MODULE PROCEDURE FMBINOMIAL_FM + END INTERFACE + + INTERFACE FACTORIAL + MODULE PROCEDURE FMFACTORIAL_FM + END INTERFACE + + INTERFACE GAMMA + MODULE PROCEDURE FMGAMMA_FM + END INTERFACE + + INTERFACE INCOMPLETE_BETA + MODULE PROCEDURE FMINCOMPLETE_BETA_FM + END INTERFACE + + INTERFACE INCOMPLETE_GAMMA1 + MODULE PROCEDURE FMINCOMPLETE_GAMMA1_FM + END INTERFACE + + INTERFACE INCOMPLETE_GAMMA2 + MODULE PROCEDURE FMINCOMPLETE_GAMMA2_FM + END INTERFACE + + INTERFACE LOG_GAMMA + MODULE PROCEDURE FMLOG_GAMMA_FM + END INTERFACE + + INTERFACE POLYGAMMA + MODULE PROCEDURE FMPOLYGAMMA_FM + END INTERFACE + + INTERFACE POCHHAMMER + MODULE PROCEDURE FMPOCHHAMMER_FM + END INTERFACE + + INTERFACE PSI + MODULE PROCEDURE FMPSI_FM + END INTERFACE + + CONTAINS + +! SIN + + FUNCTION FMSIN_FM(MA) + USE FMVALS + TYPE ( FM ) MA,FMSIN_FM + INTENT (IN) :: MA + CALL FMSIN(MA%MFM,FMSIN_FM%MFM) + END FUNCTION + + FUNCTION FMSIN_ZM(MA) + USE FMVALS + TYPE ( ZM ) MA,FMSIN_ZM + INTENT (IN) :: MA + CALL ZMSIN(MA%MZM,FMSIN_ZM%MZM) + END FUNCTION + +! SINH + + FUNCTION FMSINH_FM(MA) + USE FMVALS + TYPE ( FM ) MA,FMSINH_FM + INTENT (IN) :: MA + CALL FMSINH(MA%MFM,FMSINH_FM%MFM) + END FUNCTION + + FUNCTION FMSINH_ZM(MA) + USE FMVALS + TYPE ( ZM ) MA,FMSINH_ZM + INTENT (IN) :: MA + CALL ZMSINH(MA%MZM,FMSINH_ZM%MZM) + END FUNCTION + +! SPACING + + FUNCTION FMSPACING_FM(MA) + USE FMVALS + TYPE ( FM ) MA,FMSPACING_FM + INTENT (IN) :: MA + CALL FMABS(MA%MFM,MTFM) + CALL FMULP(MTFM,FMSPACING_FM%MFM) + END FUNCTION + +! SQRT + + FUNCTION FMSQRT_FM(MA) + USE FMVALS + TYPE ( FM ) MA,FMSQRT_FM + INTENT (IN) :: MA + CALL FMSQRT(MA%MFM,FMSQRT_FM%MFM) + END FUNCTION + + FUNCTION FMSQRT_ZM(MA) + USE FMVALS + TYPE ( ZM ) MA,FMSQRT_ZM + INTENT (IN) :: MA + CALL ZMSQRT(MA%MZM,FMSQRT_ZM%MZM) + END FUNCTION + +! TAN + + FUNCTION FMTAN_FM(MA) + USE FMVALS + TYPE ( FM ) MA,FMTAN_FM + INTENT (IN) :: MA + CALL FMTAN(MA%MFM,FMTAN_FM%MFM) + END FUNCTION + + FUNCTION FMTAN_ZM(MA) + USE FMVALS + TYPE ( ZM ) MA,FMTAN_ZM + INTENT (IN) :: MA + CALL ZMTAN(MA%MZM,FMTAN_ZM%MZM) + END FUNCTION + +! TANH + + FUNCTION FMTANH_FM(MA) + USE FMVALS + TYPE ( FM ) MA,FMTANH_FM + INTENT (IN) :: MA + CALL FMTANH(MA%MFM,FMTANH_FM%MFM) + END FUNCTION + + FUNCTION FMTANH_ZM(MA) + USE FMVALS + TYPE ( ZM ) MA,FMTANH_ZM + INTENT (IN) :: MA + CALL ZMTANH(MA%MZM,FMTANH_ZM%MZM) + END FUNCTION + +! TINY + + FUNCTION FMTINY_FM(MA) + USE FMVALS + TYPE ( FM ) MA,FMTINY_FM + INTEGER J + INTENT (IN) :: MA + FMTINY_FM%MFM(-1) = 1 + FMTINY_FM%MFM(0) = NINT(NDIG*ALOGM2) + FMTINY_FM%MFM(1) = -MXEXP + FMTINY_FM%MFM(2) = 1 + DO J = 3, NDIG+1 + FMTINY_FM%MFM(J) = 0 + ENDDO + END FUNCTION + + FUNCTION FMTINY_IM(MA) + USE FMVALS + TYPE ( IM ) MA,FMTINY_IM + INTENT (IN) :: MA + CALL IMI2M(1,FMTINY_IM%MIM) + END FUNCTION + + FUNCTION FMTINY_ZM(MA) + USE FMVALS + TYPE ( ZM ) MA,FMTINY_ZM + INTEGER J + INTENT (IN) :: MA + MTFM(-1) = 1 + MTFM(0) = NINT(NDIG*ALOGM2) + MTFM(1) = -MXEXP + MTFM(2) = 1 + DO J = 3, NDIG+1 + MTFM(J) = 0 + ENDDO + CALL ZMCMPX(MTFM,MTFM,FMTINY_ZM%MZM) + END FUNCTION + +! TO_FM + + FUNCTION FM_I(IVAL) + USE FMVALS + TYPE ( FM ) FM_I + INTEGER IVAL + INTENT (IN) :: IVAL + CALL FMI2M(IVAL,FM_I%MFM) + END FUNCTION + + FUNCTION FM_R(R) + USE FMVALS + TYPE ( FM ) FM_R + REAL R + INTENT (IN) :: R + CALL FMSP2M(R,FM_R%MFM) + END FUNCTION + + FUNCTION FM_D(D) + USE FMVALS + TYPE ( FM ) FM_D + DOUBLE PRECISION D + INTENT (IN) :: D + CALL FMDP2M(D,FM_D%MFM) + END FUNCTION + + FUNCTION FM_Z(Z) + USE FMVALS + TYPE ( FM ) FM_Z + COMPLEX Z + INTENT (IN) :: Z + CALL FMSP2M(REAL(Z),FM_Z%MFM) + END FUNCTION + + FUNCTION FM_C(C) + USE FMVALS + TYPE ( FM ) FM_C + COMPLEX (KIND(0.0D0)) :: C + INTENT (IN) :: C + CALL FMDP2M(REAL(C,KIND(0.0D0)),FM_C%MFM) + END FUNCTION + + FUNCTION FM_FM(MA) + USE FMVALS + TYPE ( FM ) FM_FM,MA + INTENT (IN) :: MA + CALL FMEQ(MA%MFM,FM_FM%MFM) + END FUNCTION + + FUNCTION FM_IM(MA) + USE FMVALS + TYPE ( FM ) FM_IM + TYPE ( IM ) MA + INTENT (IN) :: MA + CALL IMI2FM(MA%MIM,FM_IM%MFM) + END FUNCTION + + FUNCTION FM_ST(ST) + USE FMVALS + TYPE ( FM ) FM_ST + CHARACTER(*) :: ST + INTENT (IN) :: ST + CALL FMST2M(ST,FM_ST%MFM) + END FUNCTION + + FUNCTION FM_ZM(MA) + USE FMVALS + TYPE ( FM ) FM_ZM + TYPE ( ZM ) MA + INTENT (IN) :: MA + CALL ZMREAL(MA%MZM,FM_ZM%MFM) + END FUNCTION + +! TO_IM + + FUNCTION IM_I(IVAL) + USE FMVALS + TYPE ( IM ) IM_I + INTEGER IVAL + INTENT (IN) :: IVAL + CALL IMI2M(IVAL,IM_I%MIM) + END FUNCTION + + FUNCTION IM_R(R) + USE FMVALS + TYPE ( IM ) IM_R + REAL R + CHARACTER(25) :: ST + INTENT (IN) :: R + IF (ABS(R) < HUGE(1)) THEN + IVAL = INT(R) + CALL IMI2M(IVAL,IM_R%MIM) + ELSE + WRITE (ST,'(E25.16)') R + CALL IMST2M(ST,IM_R%MIM) + ENDIF + END FUNCTION + + FUNCTION IM_D(D) + USE FMVALS + TYPE ( IM ) IM_D + DOUBLE PRECISION D + CHARACTER(25) :: ST + INTENT (IN) :: D + IF (ABS(D) < HUGE(1)) THEN + IVAL = INT(D) + CALL IMI2M(IVAL,IM_D%MIM) + ELSE + WRITE (ST,'(E25.16)') D + CALL IMST2M(ST,IM_D%MIM) + ENDIF + END FUNCTION + + FUNCTION IM_Z(Z) + USE FMVALS + TYPE ( IM ) IM_Z + COMPLEX Z + REAL R + CHARACTER(25) :: ST + INTENT (IN) :: Z + R = REAL(Z) + IF (ABS(R) < HUGE(1)) THEN + IVAL = INT(R) + CALL IMI2M(IVAL,IM_Z%MIM) + ELSE + WRITE (ST,'(E25.16)') R + CALL IMST2M(ST,IM_Z%MIM) + ENDIF + END FUNCTION + + FUNCTION IM_C(C) + USE FMVALS + TYPE ( IM ) IM_C + COMPLEX (KIND(0.0D0)) :: C + DOUBLE PRECISION D + CHARACTER(25) :: ST + INTENT (IN) :: C + D = REAL(C) + IF (ABS(D) < HUGE(1)) THEN + IVAL = INT(D) + CALL IMI2M(IVAL,IM_C%MIM) + ELSE + WRITE (ST,'(E25.16)') D + CALL IMST2M(ST,IM_C%MIM) + ENDIF + END FUNCTION + + FUNCTION IM_FM(MA) + USE FMVALS + TYPE ( IM ) IM_FM + TYPE ( FM ) MA + INTENT (IN) :: MA + CALL IMFM2I(MA%MFM,IM_FM%MIM) + END FUNCTION + + FUNCTION IM_IM(MA) + USE FMVALS + TYPE ( IM ) IM_IM,MA + INTENT (IN) :: MA + CALL IMEQ(MA%MIM,IM_IM%MIM) + END FUNCTION + + FUNCTION IM_ST(ST) + USE FMVALS + TYPE ( IM ) IM_ST + CHARACTER(*) :: ST + INTENT (IN) :: ST + CALL IMST2M(ST,IM_ST%MIM) + END FUNCTION + + FUNCTION IM_ZM(MA) + USE FMVALS + TYPE ( IM ) IM_ZM + TYPE ( ZM ) MA + INTENT (IN) :: MA + CALL ZMREAL(MA%MZM,MTFM) + CALL IMFM2I(MTFM,IM_ZM%MIM) + END FUNCTION + +! TO_ZM + + FUNCTION ZM_I(IVAL) + USE FMVALS + TYPE ( ZM ) ZM_I + INTEGER IVAL + INTENT (IN) :: IVAL + CALL ZMI2M(IVAL,ZM_I%MZM) + END FUNCTION + + FUNCTION ZM_R(R) + USE FMVALS + TYPE ( ZM ) ZM_R + REAL R + INTENT (IN) :: R + CALL FMSP2M(R,MTFM) + CALL FMI2M(0,MUFM) + CALL ZMCMPX(MTFM,MUFM,ZM_R%MZM) + END FUNCTION + + FUNCTION ZM_D(D) + USE FMVALS + TYPE ( ZM ) ZM_D + DOUBLE PRECISION D + INTENT (IN) :: D + CALL FMDP2M(D,MTFM) + CALL FMI2M(0,MUFM) + CALL ZMCMPX(MTFM,MUFM,ZM_D%MZM) + END FUNCTION + + FUNCTION ZM_Z(Z) + USE FMVALS + TYPE ( ZM ) ZM_Z + COMPLEX Z + INTENT (IN) :: Z + CALL ZMZ2M(Z,ZM_Z%MZM) + END FUNCTION + + FUNCTION ZM_C(C) + USE FMVALS + TYPE ( ZM ) ZM_C + COMPLEX (KIND(0.0D0)) :: C + INTENT (IN) :: C + CALL FMDP2M(REAL(C,KIND(0.0D0)),MTFM) + CALL FMDP2M(AIMAG(C),MUFM) + CALL ZMCMPX(MTFM,MUFM,ZM_C%MZM) + END FUNCTION + + FUNCTION ZM_FM(MA) + USE FMVALS + TYPE ( ZM ) ZM_FM + TYPE ( FM ) MA + INTENT (IN) :: MA + CALL FMI2M(0,MUFM) + CALL ZMCMPX(MA%MFM,MUFM,ZM_FM%MZM) + END FUNCTION + + FUNCTION ZM_IM(MA) + USE FMVALS + TYPE ( ZM ) ZM_IM + TYPE ( IM ) MA + INTENT (IN) :: MA + CALL IMI2FM(MA%MIM,MTFM) + CALL FMI2M(0,MUFM) + CALL ZMCMPX(MTFM,MUFM,ZM_IM%MZM) + END FUNCTION + + FUNCTION ZM_ST(ST) + USE FMVALS + TYPE ( ZM ) ZM_ST + CHARACTER(*) :: ST + INTENT (IN) :: ST + CALL ZMST2M(ST,ZM_ST%MZM) + END FUNCTION + + FUNCTION ZM_ZM(MA) + USE FMVALS + TYPE ( ZM ) ZM_ZM,MA + INTENT (IN) :: MA + CALL ZMEQ(MA%MZM,ZM_ZM%MZM) + END FUNCTION + +! TO_INT + + FUNCTION FM_2INT(MA) + TYPE ( FM ) MA + INTEGER FM_2INT + INTENT (IN) :: MA + CALL FMM2I(MA%MFM,FM_2INT) + END FUNCTION + + FUNCTION IM_2INT(MA) + TYPE ( IM ) MA + INTEGER IM_2INT + INTENT (IN) :: MA + CALL IMM2I(MA%MIM,IM_2INT) + END FUNCTION + + FUNCTION ZM_2INT(MA) + TYPE ( ZM ) MA + INTEGER ZM_2INT + INTENT (IN) :: MA + CALL ZMM2I(MA%MZM,ZM_2INT) + END FUNCTION + +! TO_SP + + FUNCTION FM_2SP(MA) + TYPE ( FM ) MA + REAL FM_2SP + INTENT (IN) :: MA + CALL FMM2SP(MA%MFM,FM_2SP) + END FUNCTION + + FUNCTION IM_2SP(MA) + TYPE ( IM ) MA + REAL IM_2SP + INTENT (IN) :: MA + CALL IMI2FM(MA%MIM,MTFM) + CALL FMM2SP(MTFM,IM_2SP) + END FUNCTION + + FUNCTION ZM_2SP(MA) + TYPE ( ZM ) MA + REAL ZM_2SP + INTENT (IN) :: MA + CALL ZMREAL(MA%MZM,MTFM) + CALL FMM2SP(MTFM,ZM_2SP) + END FUNCTION + +! TO_DP + + FUNCTION FM_2DP(MA) + TYPE ( FM ) MA + DOUBLE PRECISION FM_2DP + INTENT (IN) :: MA + CALL FMM2DP(MA%MFM,FM_2DP) + END FUNCTION + + FUNCTION IM_2DP(MA) + TYPE ( IM ) MA + DOUBLE PRECISION IM_2DP + INTENT (IN) :: MA + CALL IMI2FM(MA%MIM,MTFM) + CALL FMM2DP(MTFM,IM_2DP) + END FUNCTION + + FUNCTION ZM_2DP(MA) + TYPE ( ZM ) MA + DOUBLE PRECISION ZM_2DP + INTENT (IN) :: MA + CALL ZMREAL(MA%MZM,MTFM) + CALL FMM2DP(MTFM,ZM_2DP) + END FUNCTION + +! TO_SPZ + + FUNCTION FM_2SPZ(MA) + TYPE ( FM ) MA + COMPLEX FM_2SPZ + REAL R + INTENT (IN) :: MA + CALL FMM2SP(MA%MFM,R) + FM_2SPZ = CMPLX( R , 0.0 ) + END FUNCTION + + FUNCTION IM_2SPZ(MA) + TYPE ( IM ) MA + COMPLEX IM_2SPZ + REAL R + INTENT (IN) :: MA + CALL IMI2FM(MA%MIM,MTFM) + CALL FMM2SP(MTFM,R) + IM_2SPZ = CMPLX( R , 0.0 ) + END FUNCTION + + FUNCTION ZM_2SPZ(MA) + TYPE ( ZM ) MA + COMPLEX ZM_2SPZ + INTENT (IN) :: MA + CALL ZMM2Z(MA%MZM,ZM_2SPZ) + END FUNCTION + +! TO_DPZ + + FUNCTION FM_2DPZ(MA) + TYPE ( FM ) MA + COMPLEX (KIND(0.0D0)) :: FM_2DPZ + DOUBLE PRECISION D + INTENT (IN) :: MA + CALL FMM2DP(MA%MFM,D) + FM_2DPZ = CMPLX( D , 0.0D0 , KIND(0.0D0) ) + END FUNCTION + + FUNCTION IM_2DPZ(MA) + TYPE ( IM ) MA + COMPLEX (KIND(0.0D0)) :: IM_2DPZ + DOUBLE PRECISION D + INTENT (IN) :: MA + CALL IMM2DP(MA%MIM,D) + IM_2DPZ = CMPLX( D , 0.0D0 , KIND(0.0D0) ) + END FUNCTION + + FUNCTION ZM_2DPZ(MA) + TYPE ( ZM ) MA + COMPLEX (KIND(0.0D0)) :: ZM_2DPZ + DOUBLE PRECISION D1,D2 + INTENT (IN) :: MA + CALL ZMREAL(MA%MZM,MTFM) + CALL FMM2DP(MTFM,D1) + CALL ZMIMAG(MA%MZM,MTFM) + CALL FMM2DP(MTFM,D2) + ZM_2DPZ = CMPLX( D1 , D2 , KIND(0.0D0) ) + END FUNCTION + +! FM_RANDOM_SEED + + SUBROUTINE FM_SEED(PUT,GET,SIZE) + +! Interface routine for FM_RANDOM_SEED, used to initialize the random sequence +! from FM_RANDOM_NUMBER. + +! Like the Fortran intrinsic function RANDOM_SEED, exactly one of the three +! arguments must be present, and the call should be with an argument keyword. + +! CALL FM_RANDOM_SEED(SIZE=J) returns J=7 to the calling program, indicating +! that the seed array has length 7. + +! CALL FM_RANDOM_SEED(GET=SEED) returns SEED(1) through SEED(7) as the current +! seed for the generator, but see the comments in routine FM_RANDOM_NUMBER. + +! CALL FM_RANDOM_SEED(PUT=SEED) initializes the FM_RANDOM_NUMBER generator. + +! The typical usage is to call FM_RANDOM_SEED once with PUT defined as an +! integer array of length 7 containing seven seed values used to initialize +! the generator. This initializes the table used by the mixed congruential +! generator. Then each call to FM_RANDOM_NUMBER gets the next random value. + +! This example seeds the generator and then fills the double precision array R +! with random values between 0 and 1. + +! SEED = (/ 314159,265358,979323,846264,338327,950288,419716 /) +! CALL FM_RANDOM_SEED(PUT=SEED) +! DO J = 1, N +! CALL FM_RANDOM_NUMBER(R(J)) +! ENDDO + + USE FMVALS + + IMPLICIT NONE + + INTEGER, OPTIONAL, INTENT(IN) :: PUT(7) + INTEGER, OPTIONAL, INTENT(OUT) :: GET(7) + INTEGER, OPTIONAL, INTENT(OUT) :: SIZE + + REAL (KIND(1.0D0)) :: MSAVE + INTEGER J,K + + + IF (PRESENT(SIZE)) THEN + SIZE = 7 + RETURN + ENDIF + MSAVE = MBASE + MBASE = MBRAND + IF (PRESENT(PUT)) THEN + K = 10**7 + CALL IMI2M(ABS(PUT(1)),MRNX) + DO J = 2, 7 + CALL IMMPYI(MRNX,K,MTIM) + CALL IMI2M(ABS(PUT(J)),M04) + CALL IMADD(MTIM,M04,MRNX) + ENDDO + CALL IMST2M('2070613773952029032014000773560846464373793273739',M04) + CALL IMMOD(MRNX,M04,MTIM) + CALL IMEQ(MTIM,MRNX) + START_RANDOM_SEQUENCE = 1 + MBASE = MSAVE + RETURN + ENDIF + IF (PRESENT(GET)) THEN + K = 10**7 + CALL IMI2M(K,M05) + CALL IMEQ(MRNX,M04) + DO J = 7, 1, -1 + CALL IMMOD(M04,M05,M06) + CALL IMM2I(M06,GET(J)) + CALL IMDIVI(M04,K,MTIM) + CALL IMEQ(MTIM,M04) + ENDDO + MBASE = MSAVE + RETURN + ENDIF + END SUBROUTINE + +! FM_FORMAT + + FUNCTION FMFORMAT_FM(FMT,MA) + USE FMVALS + CHARACTER(*) :: FMT + TYPE ( FM ) MA + CHARACTER(200) :: FMFORMAT_FM + INTENT (IN) :: FMT,MA + CALL FMFORM(FMT,MA%MFM,FMFORMAT_FM) + END FUNCTION + +! IM_FORMAT + + FUNCTION IMFORMAT_IM(FMT,MA) + USE FMVALS + CHARACTER(*) :: FMT + CHARACTER(200) :: IMFORMAT_IM + TYPE ( IM ) MA + INTENT (IN) :: FMT,MA + CALL IMFORM(FMT,MA%MIM,IMFORMAT_IM) + END FUNCTION + +! ZM_FORMAT + + FUNCTION ZMFORMAT_ZM(FMTR,FMTI,MA) + USE FMVALS + CHARACTER(*) :: FMTR,FMTI + CHARACTER(200) :: ZMFORMAT_ZM + TYPE ( ZM ) MA + INTENT (IN) :: FMTR,FMTI,MA + CALL ZMFORM(FMTR,FMTI,MA%MZM,ZMFORMAT_ZM) + END FUNCTION + +! GCD + + FUNCTION GCD_IM(MA,MB) + USE FMVALS + TYPE ( IM ) MA,MB,GCD_IM + INTENT (IN) :: MA,MB + CALL IMGCD(MA%MIM,MB%MIM,GCD_IM%MIM) + END FUNCTION + +! MULTIPLY_MOD + + FUNCTION MULTIPLYMOD_IM(MA,MB,MC) + USE FMVALS + TYPE ( IM ) MA,MB,MC,MULTIPLYMOD_IM + INTENT (IN) :: MA,MB,MC + CALL IMMPYM(MA%MIM,MB%MIM,MC%MIM,MULTIPLYMOD_IM%MIM) + END FUNCTION + +! POWER_MOD + + FUNCTION POWERMOD_IM(MA,MB,MC) + USE FMVALS + TYPE ( IM ) MA,MB,MC,POWERMOD_IM + INTENT (IN) :: MA,MB,MC + CALL IMPMOD(MA%MIM,MB%MIM,MC%MIM,POWERMOD_IM%MIM) + END FUNCTION + +! BERNOULLI + + FUNCTION FMBERNOULLI_FM(N) + USE FMVALS + TYPE ( FM ) FMBERNOULLI_FM + INTEGER N + INTENT (IN) :: N + CALL FMI2M(1,MTFM) + CALL FMBERN(N,MTFM,FMBERNOULLI_FM%MFM) + END FUNCTION + +! BETA + + FUNCTION FMBETA_FM(MA,MB) + USE FMVALS + TYPE ( FM ) MA,MB,FMBETA_FM + INTENT (IN) :: MA,MB + CALL FMBETA(MA%MFM,MB%MFM,FMBETA_FM%MFM) + END FUNCTION + +! BINOMIAL + + FUNCTION FMBINOMIAL_FM(MA,MB) + USE FMVALS + TYPE ( FM ) MA,MB,FMBINOMIAL_FM + INTENT (IN) :: MA,MB + CALL FMCOMB(MA%MFM,MB%MFM,FMBINOMIAL_FM%MFM) + END FUNCTION + +! FACTORIAL + + FUNCTION FMFACTORIAL_FM(MA) + USE FMVALS + TYPE ( FM ) MA,FMFACTORIAL_FM + INTENT (IN) :: MA + CALL FMFACT(MA%MFM,FMFACTORIAL_FM%MFM) + END FUNCTION + +! GAMMA + + FUNCTION FMGAMMA_FM(MA) + USE FMVALS + TYPE ( FM ) MA,FMGAMMA_FM + INTENT (IN) :: MA + CALL FMGAM(MA%MFM,FMGAMMA_FM%MFM) + END FUNCTION + +! INCOMPLETE_BETA + + FUNCTION FMINCOMPLETE_BETA_FM(MX,MA,MB) + USE FMVALS + TYPE ( FM ) MX,MA,MB,FMINCOMPLETE_BETA_FM + INTENT (IN) :: MX,MA,MB + CALL FMIBTA(MX%MFM,MA%MFM,MB%MFM,FMINCOMPLETE_BETA_FM%MFM) + END FUNCTION + +! INCOMPLETE_GAMMA1 + + FUNCTION FMINCOMPLETE_GAMMA1_FM(MA,MB) + USE FMVALS + TYPE ( FM ) MA,MB,FMINCOMPLETE_GAMMA1_FM + INTENT (IN) :: MA,MB + CALL FMIGM1(MA%MFM,MB%MFM,FMINCOMPLETE_GAMMA1_FM%MFM) + END FUNCTION + +! INCOMPLETE_GAMMA2 + + FUNCTION FMINCOMPLETE_GAMMA2_FM(MA,MB) + USE FMVALS + TYPE ( FM ) MA,MB,FMINCOMPLETE_GAMMA2_FM + INTENT (IN) :: MA,MB + CALL FMIGM2(MA%MFM,MB%MFM,FMINCOMPLETE_GAMMA2_FM%MFM) + END FUNCTION + +! LOG_GAMMA + + FUNCTION FMLOG_GAMMA_FM(MA) + USE FMVALS + TYPE ( FM ) MA,FMLOG_GAMMA_FM + INTENT (IN) :: MA + CALL FMLNGM(MA%MFM,FMLOG_GAMMA_FM%MFM) + END FUNCTION + +! POLYGAMMA + + FUNCTION FMPOLYGAMMA_FM(N,MA) + USE FMVALS + TYPE ( FM ) MA,FMPOLYGAMMA_FM + INTEGER N + INTENT (IN) :: N,MA + CALL FMPGAM(N,MA%MFM,FMPOLYGAMMA_FM%MFM) + END FUNCTION + +! POCHHAMMER + + FUNCTION FMPOCHHAMMER_FM(MA,N) + USE FMVALS + TYPE ( FM ) MA,FMPOCHHAMMER_FM + INTEGER N + INTENT (IN) :: N,MA + CALL FMPOCH(MA%MFM,N,FMPOCHHAMMER_FM%MFM) + END FUNCTION + +! PSI + + FUNCTION FMPSI_FM(MA) + USE FMVALS + TYPE ( FM ) MA,FMPSI_FM + INTENT (IN) :: MA + CALL FMPSI(MA%MFM,FMPSI_FM%MFM) + END FUNCTION + + END MODULE FMZM_9 + + MODULE FMZM + + USE FMZM_1 + USE FMZM_2 + USE FMZM_3 + USE FMZM_4 + USE FMZM_5 + USE FMZM_6 + USE FMZM_7 + USE FMZM_8 + USE FMZM_9 + + END MODULE FMZM diff --git a/src/fmlib/Makefile b/src/fmlib/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1c1612e0f8f7627a5994f1a8278a3b57e5e1c138 --- /dev/null +++ b/src/fmlib/Makefile @@ -0,0 +1,73 @@ +#=============================================================================== +# +# Makefile for FMLIB +# +#------------------------------------------------------------------------------- +# +# Copyright (C) 2011 Yoshifumi Nakamura +# +# This file is part of BQCD -- Berlin Quantum ChromoDynamics program +# +# BQCD 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 Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BQCD is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BQCD. If not, see <http://www.gnu.org/licenses/>. +# +#=============================================================================== +DIR = ../ +include $(DIR)Makefile.in +MODULES_DIR = $(DIR)modules + + +FAST_MAKE = make -j 1 + +ifdef FPP2 + fpp = $(FPP2) +else + fpp = $(FPP) +endif + +.SUFFIXES: +.SUFFIXES: .a .o .F90 + +.F90.o: + $(fpp) -I../include $(MYFLAGS) $< > $*.f90 + $(F90) -c $(FFLAGS) $*.f90 + +OBJS = \ + FMSAVE.o \ + FMZM90.o \ + FM.o +# SampleFM.o \ +# TestFM.o + +fast: +ifdef FMLIB + $(FAST_MAKE) lib_FM.a +endif + +lib_FM.a: $(OBJS) + $(AR) $(ARFLAGS) rv $@ $(OBJS) + +TestFM: $(OBJS) TestFM.o + $(F90) -o $@ TestFM.o $(OBJS) + +SampleFM: $(OBJS) SampleFM.o + $(F90) -o $@ SampleFM.o $(OBJS) + +test: TestFM SampleFM + ./TestFM | tee TestFM.log + ./SampleFM | tee SampleFM.log + +clobber: + rm -f *.[Tiod] *.f90 *.mod *.log *.LOG + rm -f lib_FM.a + rm -f TestFM SampleFM diff --git a/src/fmlib/ReadMe b/src/fmlib/ReadMe new file mode 100644 index 0000000000000000000000000000000000000000..fa13ca65e4c66b6965459a5cd19471c9098379c5 --- /dev/null +++ b/src/fmlib/ReadMe @@ -0,0 +1,1626 @@ + +This is a list of the files for version 1.2 of FMLIB. + +1. FMSAVE.f90 Module for FM internal global variables + +2. FMZM90.f90 Modules for interfaces and definitions of derived-types + +3. FM.f90 Subroutine library for multiple-precision operations + +4. TestFM.f90 Test program for most of the FM routines + +5. SampleFM.f90 Small sample program using FM + +6. SAMPLE.CHK Expected output file SAMPLE.LOG from SampleFM.f90 + + +Here is an example set of compiler/linker commands for building +the programs. For lines on which there is no *.f90 file listed, +the f90 script skips the compiler and calls the linker. +Options: + -c compile to object code -- don't make executable + -O optimization on + -f free Fortran-90 free source form + -o output file name + + +f90 FMSAVE.f90 -c -f free -o FMSAVE.o + + +f90 FMZM90.f90 -c -f free -o FMZM90.o + + +f90 FM.f90 -O -c -f free -o FM.o + + +f90 TestFM.f90 -c -f free -o TestFM.o + +f90 TestFM.o FMSAVE.o FMZM90.o FM.o -o TestFM + + +f90 SampleFM.f90 -c -f free -o SampleFM.o + +f90 SampleFM.o FMSAVE.o FMZM90.o FM.o -o SampleFM + + +Basically the first three files are compiled as object code libraries, and +then a program using FM is compiled and linked to those three libraries. + +Most compilers also produce files FMVALS.mod, FMZM.mod, etc., containing +module information from the first two files. + + +Troubleshooting + +1. After downloading the files, if the compiler gives many error messages or + it appears to see no code in the file at all, check that the lines in the + file have the proper end-of-line characters for your system. + + For a PC, this means each line should end with both a carriage return <cr> + character (ascii 13) and a line feed <lf> character (ascii 10). If the + file appears to be one huge line when viewed in an editor, one of these + two characters is probably missing and should be added to each line. + + To use FM on a Unix system, lines end with <lf>, and for a Mac system they + end with <cr>. On these systems, failing to fix the end-of-line characters + might mean the file seems to have twice the expected number of lines, with + a blank line between each line of code when viewed in an editor. + + Many good editors will recognize a foreign end-of-line format and + automatically fix each file the first time it is opened. + +2. Compiler gives an "out of memory" error message or crashes during compile + of FM.f90 or FMZM90.f90. + + It might be necessary to break the file into smaller pieces or split it + into separate files for each routine or module. This could be caused by + lack of system memory, lack of virtual memory, or a bug (memory leak) in + the compiler. + + Some compilers have an option (-split) to do this automatically. + +3. Most of the routines compile, but a few fail with error messages like + "symbol 120 is not the label of a branch target statement". + However, looking at the code shows there is a label 120 in that routine. + + This might happen in the larger routines. Some compilers may require + additional options be enabled (e.g., to force 32-bit branches or addresses + to be used). Check in the compiler manual and try turning on any options + that mention "long branches", "32-bit addresses", etc. + +4. All files compile, but the TestFM program reports a few errors when it runs. + There are other possibilities, but one thing to check is whether the + compiler has any options controlling arithmetic precision of intermediate + results. + + Because the FM numbers are stored as integer values in double precision + arrays, any sloppy rounding can cause problems. In one case, a compiler + optimized an expression by leaving the result of a division in an 80-bit + register and then used that result later in the calculation. Rounding + the division back to double precision would have fixed the error, but + using the inaccurate extended precision value caused the final result to + be off by one when it was returned to an integer value. + + This compiler had an option (-ap) to force intermediate results to not be + left in registers, and that fixed the problem. + + Another way to check to see if this is the problem is to create a version + of FM that uses integer arrays instead of double precision. See the section + titled "EFFICIENCY" below to see how to make this change. On most machines, + there is little if any speed penalty for using integer arrays as long as the + precision is under 100 significant digits (i.e., NDIG < 15 or so with MBASE + = 10**7). + +5. Several messages like this appear: + C:\t\FMZM90.f90(6563) : Info: This variable has not been used. [MA] + FUNCTION FMTINY_ZM(MA) + + This and the other messages of the same type are not errors. The argument + for functions like TINY is not used for anything except telling the + compiler which routine to call by checking the argument's type. The same + is true of the Fortran intrinsic function TINY. If we say TINY(1.0) or + TINY(2.0), the input argument is not used, other than to indicate that we + want the single precision value of TINY. + + + +================================================================================ +================================================================================ + + + USER'S GUIDE FOR THE FM PACKAGE + + +The various lists of available multiple precision operations and +routines have been collected here, along with some general advice +on using the package. + +See the program SampleFM.f90 for some examples of initializing and +using the package. + + +INITIALIZATION: The default precision for the multiple-precision numbers + is about 50 significant digits. + + To set precision to a different value, put + CALL FMSET(N) + in the main program before any multiple precision + operations are done, with N replaced by the number + of decimal digits of accuracy to be used. + +ROUTINE NAMES: For each multiple precision operation there are + several routines with related names that perform + variations of that operation. For example, the + addition operation has these forms: + + Using the Fortran-90 interface module, to perform + real (floating-point) multiple precision addition, + declare the variables as FM derived types with + + USE FMZM + TYPE ( FM ) A,B,C + + and then add using + + C = A + B + + Normally, using the interface module avoids the need + to know the name of the FM routine being called. For + some operations, usually those that are not Fortran-90 + functions (such as formatting a number), a direct call + may be needed. The addition above can be done as + + CALL FM_ADD(A,B,C) + + It is rare for a program to bypass the derived types + and work directly with the arrays that define the + multiple-precision numbers. The only real drawback + to using the derived types is a small performance + penalty (that varies from one compiler to another). + If FM.f90 is used without the interface module, then + the multiple precision numbers are declared as arrays + + DOUBLE PRECISION A(-1:LUNPCK),B(-1:LUNPCK),C(-1:LUNPCK) + + where LUNPCK is defined in FMSAVE.f90. The numbers are + then added by calling the FM routine where the arguments + are assumed to be arrays, not TYPE (FM) derived types: + + CALL FMADD(A,B,C) + + For each of the routines listed below (like FMADD), + there is a version that assumes the arguments have + the appropriate derived type. These have the same + names, except "_" has been inserted after the first + two letters of the name (like FM_ADD). + + If direct calls are done instead of using the + interface module, there is another form for these + routine names that is used when the arrays have been + declared in a packed format that takes roughly half + as much space: + + DOUBLE PRECISION A(-1:LPACK),B(-1:LPACK),C(-1:LPACK) + + The routines that work with packed arrays have names + where the second letter has been changed from M to P: + + CALL FPADD(A,B,C) + + The packed versions are slower. + + For multiple precision integer (IM) or complex (ZM) + operations there are similar Fortran-90 derived types + and the various routines: + + USE FMZM + ... + TYPE ( IM ) A,B,C + TYPE ( ZM ) X,Y,Z + ... + C = A + B + ... + Z = X + Y + + with explicit calls of the form + + CALL IM_ADD(A,B,C) + CALL ZM_ADD(X,Y,Z) + + Without using the interface module: + + DOUBLE PRECISION A(-1:LUNPCK),B(-1:LUNPCK),C(-1:LUNPCK) + DOUBLE PRECISION X(-1:LUNPKZ),Y(-1:LUNPKZ),Z(-1:LUNPKZ) + ... + CALL IMADD(A,B,C) + ... + CALL ZMADD(X,Y,Z) + + Packed format without the interface module: + + DOUBLE PRECISION A(-1:LPACK),B(-1:LPACK),C(-1:LPACK) + DOUBLE PRECISION X(-1:LPACKZ),Y(-1:LPACKZ),Z(-1:LPACKZ) + ... + CALL IPADD(A,B,C) + ... + CALL ZPADD(X,Y,Z) + + + +-------------------------------------------------------------------------------- +----------------------- Fortran-90 Interface Notes ------------------------- + + + + +There are three multiple precision data types: + FM (multiple precision real) + IM (multiple precision integer) + ZM (multiple precision complex) + +Some of the interface routines assume that the precision chosen in the +calling program (using FMSET) represents more significant digits than does +the machine's double precision. + +Most of the functions defined in this module are multiple precision versions +of standard Fortran-90 functions. In addition, there are functions for +direct conversion, formatting, and some mathematical special functions. + +TO_FM is a function for converting other types of numbers to type FM. Note +that TO_FM(3.12) converts the REAL constant to FM, but it is accurate only +to single precision. TO_FM(3.12D0) agrees with 3.12 to double precision +accuracy, and TO_FM('3.12') or TO_FM(312)/TO_FM(100) agrees to full FM +accuracy. + +TO_IM converts to type IM, and TO_ZM converts to type ZM. + +Functions are also supplied for converting the three multiple precision types +to the other numeric data types: + TO_INT converts to machine precision integer + TO_SP converts to single precision + TO_DP converts to double precision + TO_SPZ converts to single precision complex + TO_DPZ converts to double precision complex + +WARNING: When multiple precision type declarations are inserted in an + existing program, take care in converting functions like DBLE(X), + where X has been declared as a multiple precision type. If X + was single precision in the original program, then replacing + the DBLE(X) by TO_DP(X) in the new version could lose accuracy. + For this reason, the Fortran type-conversion functions defined + in this module assume that results should be multiple precision + whenever inputs are. Examples: + DBLE(TO_FM('1.23E+123456')) is type FM + REAL(TO_FM('1.23E+123456')) is type FM + REAL(TO_ZM('3.12+4.56i')) is type FM = TO_FM('3.12') + INT(TO_FM('1.23')) is type IM = TO_IM(1) + INT(TO_IM('1E+23')) is type IM + CMPLX(TO_FM('1.23'),TO_FM('4.56')) is type ZM + +Programs using this module may sometimes need to call FM, IM, or ZM routines +directly. This is normally the case when routines are needed that are not +Fortran-90 intrinsics, such as the formatting subroutine FMFORM. In a +program using this module, suppose MAFM has been declared with +TYPE ( FM ) MAFM. To use the routine FMFORM, which expects the second +argument to be an array and not a derived type, the call would have to be +CALL FMFORM('F65.60',MAFM%MFM,ST1) so that the array contained in MAFM is +passed. + +As an alternative so the user can refer directly to the FM-, IM-, and ZM-type +variables and avoid the cumbersome "%MFM" suffixes, the FM package provides a +collection of interface routines to supply any needed argument conversions. +For each FM, IM, and ZM routine that is designed to be called by the user, +there is also a version that assumes any multiple-precision arguments are +derived types instead of arrays. Each interface routine has the same name as +the original with an underscore after the first two letters of the routine +name. To convert the number to a character string with F65.60 format, use +CALL FM_FORM('F65.60',MAFM,ST1) if MAFM is of TYPE ( FM ), or use +CALL FMFORM('F65.60',MA,ST1) if MA is declared as an array. All the routines +shown below may be used this way. + +For each of the operations =, == , /= , < , <= , > , >= , +, -, *, /, +and **, the interface module defines all mixed mode variations involving one +of the three multiple precision derived types and another argument having one +of the types: { integer, real, double, complex, complex double, FM, IM, ZM }. +So mixed mode expressions such as + MAFM = 12 + MAFM = MAFM + 1 + IF (ABS(MAFM) > 1.0D-23) THEN +are handled correctly. + +Not all the named functions are defined for all three multiple precision +derived types, so the list below shows which can be used. The labels "real", +"integer", and "complex" refer to types FM, IM, and ZM respectively, "string" +means the function accepts character strings (e.g., TO_FM('3.45')), and +"other" means the function can accept any of the machine precision data types +integer, real, double, complex, or complex double. For functions that accept +two or more arguments, like ATAN2 or MAX, all the arguments must be of the +same type. + + +AVAILABLE OPERATIONS: + + = + + + - + * + / + ** + == + /= + < + <= + > + >= + ABS real integer complex + ACOS real complex + AIMAG complex + AINT real complex + ANINT real complex + ASIN real complex + ATAN real complex + ATAN2 real + BTEST integer + CEILING real complex + CMPLX real integer + CONJ complex + COS real complex + COSH real complex + DBLE real integer complex + DIGITS real integer complex + DIM real integer + DINT real complex + DOTPRODUCT real integer complex + EPSILON real + EXP real complex + EXPONENT real + FLOOR real integer complex + FRACTION real complex + HUGE real integer complex + INT real integer complex + LOG real complex + LOG10 real complex + MATMUL real integer complex + MAX real integer + MAXEXPONENT real + MIN real integer + MINEXPONENT real + MOD real integer + MODULO real integer + NEAREST real + NINT real integer complex + PRECISION real complex + RADIX real integer complex + RANGE real integer complex + REAL real integer complex + RRSPACING real + SCALE real complex + SETEXPONENT real + SIGN real integer + SIN real complex + SINH real complex + SPACING real + SQRT real complex + TAN real complex + TANH real complex + TINY real integer complex + TO_FM real integer complex string other + TO_IM real integer complex string other + TO_ZM real integer complex string other + TO_INT real integer complex + TO_SP real integer complex + TO_DP real integer complex + TO_SPZ real integer complex + TO_DPZ real integer complex + +Some other functions are defined that do not correspond to machine precision +intrinsic functions. These include formatting functions, integer modular +functions and GCD, and the Gamma function and its related functions. +N below is a machine precision integer, J1, J2, J3 are TYPE (IM), FMT, FMTR, +FMTI are character strings, A,B,X are TYPE (FM), and Z is TYPE (ZM). +The three formatting functions return a character string containing the +formatted number, the three TYPE (IM) functions return a TYPE (IM) result, +and the 12 special functions return TYPE (FM) results. + +Formatting functions: + + FM_FORMAT(FMT,A) Put A into FMT (real) format + IM_FORMAT(FMT,J1) Put J1 into FMT (integer) format + ZM_FORMAT(FMTR,FMTI,Z) Put Z into (complex) format, FMTR for the real + part and FMTI for the imaginary part + + Examples: + ST = FM_FORMAT('F65.60',A) + WRITE (*,*) ' A = ',TRIM(ST) + ST = FM_FORMAT('E75.60',B) + WRITE (*,*) ' B = ',ST(1:75) + ST = IM_FORMAT('I50',J1) + WRITE (*,*) ' J1 = ',ST(1:50) + ST = ZM_FORMAT('F35.30','F30.25',Z) + WRITE (*,*) ' Z = ',ST(1:70) + + These functions are used for one-line output. The returned character + strings are of length 200. Avoid using the formatting function in the + write list, as in + WRITE (*,*) ' J1 = ',IM_FORMAT('I50',J1)(1:50) + since the formatting functions may themselves execute an internal WRITE + and that would cause a recursive write reference. + + For higher precision numbers, the output can be broken onto multiple + lines automatically by calling subroutines FM_PRNT, IM_PRNT, ZM_PRNT, + or the line breaks can be done by hand after calling one of the + subroutines FM_FORM, IM_FORM, ZM_FORM. + + For ZM_FORMAT the length of the output is 5 more than the sum of the + two field widths. + +Integer functions: + + GCD(J1,J2) Greatest Common Divisor of J1 and J2. + MULTIPLY_MOD(J1,J2,J3) J1 * J2 mod J3 + POWER_MOD(J1,J2,J3) J1 ** J2 mod J3 + +Special functions: + + BERNOULLI(N) Nth Bernoulli number + BETA(A,B) Integral (0 to 1) t**(A-1) * (1-t)**(B-1) dt + BINOMIAL(A,B) Binomial Coefficient A! / ( B! (A-B)! ) + FACTORIAL(A) A! + GAMMA(A) Integral (0 to infinity) t**(A-1) * exp(-t) dt + INCOMPLETE_BETA(X,A,B) Integral (0 to X) t**(A-1) * (1-t)**(B-1) dt + INCOMPLETE_GAMMA1(A,X) Integral (0 to X) t**(A-1) * exp(-t) dt + INCOMPLETE_GAMMA2(A,X) Integral (X to infinity) t**(A-1) * exp(-t) dt + LOG_GAMMA(A) Ln( GAMMA(A) ) + POLYGAMMA(N,A) Nth derivative of Psi(x), evaluated at A + POCHHAMMER(A,N) A*(A+1)*(A+2)*...*(A+N-1) + PSI(A) Derivative of Ln(Gamma(x)), evaluated at A + + + +-------------------------------------------------------------------------------- +------------------------------ FM.f90 Notes -------------------------------- + + + +The routines in this package perform multiple precision arithmetic and +functions on three kinds of numbers. +FM routines handle floating-point real multiple precision numbers, +IM routines handle integer multiple precision numbers, and +ZM routines handle floating-point complex multiple precision numbers. + + +1. INITIALIZING THE PACKAGE + +The variables that contain values to be shared among the different routines +are located in module FMVALS in file FMSAVE.f90. Variables that are described +below for controlling various features of the FM package are found in this +module. They are initialized to default values assuming 32-bit integers and +64-bit double precision representation of the arrays holding multiple +precision numbers. The base and number of digits to be used are initialized +to give slightly more than 50 decimal digits. Subroutine FMVARS can be used +to get a list of these variables and their values. + +The intent of module FMVALS is to hide the FM internal variables from the +user's program, so that no name conflicts can occur. Subroutine FMSETVAR can +be used to change the variables listed below to new values. It is not always +safe to try to change these variables directly by putting USE FMVALS into the +calling program and then changing them by hand. Some of the saved constants +depend upon others, so that changing one variable may cause errors if others +depending on that one are not also changed. FMSETVAR automatically updates +any others that depend upon the one being changed. + +Subroutine FMSET also initializes these variables. It tries to compute the +best value for each, and it checks several of the values set in FMVALS to see +that they are reasonable for a given machine. FMSET can also be called to +set or change the current precision level for the multiple precision numbers. + +Calling FMSET is optional in version 1.2 of the FM package. In previous +versions one call was required before any other routine in the package could +be used. + +The routine ZMSET from version 1.1 is no longer needed, and the complex +operations are automatically initialized in FMVALS. It has been left in the +package for compatibility with version 1.1. + + +2. REPRESENTATION OF FM NUMBERS + +MBASE is the base in which the arithmetic is done. MBASE must be + bigger than one, and less than or equal to the square root of + the largest representable integer. For best efficiency MBASE + should be large, but no more than about 1/4 of the square root + of the largest representable integer. Input and output + conversions are much faster when MBASE is a power of ten. + +NDIG is the number of base MBASE digits that are carried in the + multiple precision numbers. NDIG must be at least two. The + upper limit for NDIG is defined in FMVALS and is restricted + only by the amount of memory available. + +Sometimes it is useful to dynamically vary NDIG during the program. Routine +FMEQU should be used to round numbers to lower precision or zero-pad them to +higher precision when changing NDIG. + +The default value of MBASE is a large power of ten. FMSET also sets MBASE to +a large power of ten. For an application where another base is used, such as +simulating a given machine's base two arithmetic, use subroutine FMSETVAR to +change MBASE, so that the other internal values depending on MBASE will be +changed accordingly. + +There are two representations for a floating point multiple precision number. +The unpacked representation used by the routines while doing the computations +is base MBASE and is stored in NDIG+2 words. A packed representation is +available to store the numbers in the user's program in compressed form. In +this format, the NDIG (base MBASE) digits of the mantissa are packed two per +word to conserve storage. Thus the external, packed form of a number +requires (NDIG+1)/2+2 words. + +This version uses double precision arrays to hold the numbers. Version 1.0 +of FM used integer arrays, which are faster on some machines. The package +can be changed to use integer arrays --- see section 11 on EFFICIENCY below. + +The unpacked format of a floating multiple precision number is as follows. +A number MA is kept in an array with MA(1) containing the exponent, and +MA(2) through MA(NDIG+1) each containing one digit of the mantissa, expressed +in base MBASE. The array is dimensioned to start at MA(-1), with the +sign of the number (+1 or -1) held in MA(-1), and the approximate number +of bits of precision stored in MA(0). This precision value is intended to +be used by FM functions that need to monitor cancellation error in addition +and subtraction. The cancellation monitor code is usually disabled for user +calls, and FM functions only check for cancellation when they must. Tracking +cancellation causes most routines to run slower, with addition and +subtraction being affected the most. The exponent is a power of MBASE and +the implied radix point is immediately before the first digit of the +mantissa. Every nonzero number is normalized so that the second array +element (the first digit of the mantissa) is nonzero. + +In both representations the sign of the number is carried on the second array +element only. Elements 3,4,... are always nonnegative. The exponent is a +signed integer and may be as large in magnitude as MXEXP. + +For MBASE = 10,000 and NDIG = 4, the number -pi would have these +representations: + Word 1 2 3 4 5 + + Unpacked: 1 -3 1415 9265 3590 + Packed: 1 -31415 92653590 + +In both formats MA(0) would be 42, indicating that the mantissa has about 42 +bits of precision, and MA(-1) = -1 since the number is negative. + +Because of normalization in a large base, the equivalent number of base 10 +significant digits for an FM number may be as small as +LOG10(MBASE)*(NDIG-1) + 1. + +The integer routines use the FM format to represent numbers, without the +number of digits (NDIG) being fixed. Integers in IM format are essentially +variable precision, using the minimum number of words to represent each +value. + +For programs using both FM and IM numbers, FM routines should not be called +with IM numbers, and IM routines should not be called with FM numbers, since +the implied value of NDIG used for an IM number may not match the explicit +NDIG expected by an FM routine. Use the conversion routines IMFM2I and +IMI2FM to change between the FM and IM formats. + +The format for complex FM numbers (called ZM numbers below) is very similar +to that for real FM numbers. Each ZM array holds two FM numbers to represent +the real and imaginary parts of a complex number. Each ZM array is twice as +long as a corresponding FM array, with the imaginary part starting at the +midpoint of the array. As with FM, there are packed and unpacked formats for +the numbers. + + +3. INPUT/OUTPUT ROUTINES + +All versions of the input routines perform free-format conversion from +characters to FM numbers. + +a. Conversion to or from a character array + + FMINP converts from a character*1 array to an FM number. + + FMOUT converts an FM number to base 10 and formats it for output as an + array of type character*1. The output is left justified in the + array, and the format is defined by two variables in module FMVALS, + so that a separate format definition does not have to be provided + for each output call. + + JFORM1 and JFORM2 define a default output format. + + JFORM1 = 0 E format ( .314159M+6 ) + = 1 1PE format ( 3.14159M+5 ) + = 2 F format ( 314159.000 ) + + JFORM2 is the number of significant digits to display (if JFORM1 = + 0 or 1). If JFORM2 = 0 then a default number of digits is chosen. + The default is roughly the full precision of the number. + JFORM2 is the number of digits after the decimal point (if JFORM1 = 2). + See the FMOUT documentation for more details. + +b. Conversion to or from a character string + + FMST2M converts from a character string to an FM number. + + FMFORM converts an FM number to a character string according to a format + provided in each call. The format description is more like that of + a Fortran FORMAT statement, and integer or fixed-point output is + right justified. + +c. Direct read or write + + FMPRNT uses FMOUT to print one FM number. + + FMFPRT uses FMFORM to print one FM number. + + FMWRIT writes FM numbers for later input using FMREAD. + + FMREAD reads FM numbers written by FMWRIT. + +The values given to JFORM1 and JFORM2 can be used to define a default output +format when FMOUT or FMPRNT are called. The explicit format used in a call +to FMFORM or FMFPRT overrides the settings of JFORM1 and JFORM2. + +KW is the unit number to be used for standard output from the package, + including error and warning messages, and trace output. + +For multiple precision integers, the corresponding routines IMINP, IMOUT, +IMST2M, IMFORM, IMPRNT, IMFPRT, IMWRIT, and IMREAD provide similar input and +output conversions. For output of IM numbers, JFORM1 and JFORM2 are ignored +and integer format (JFORM1=2, JFORM2=0) is used. + +For ZM numbers, the corresponding routines ZMINP, ZMOUT, ZMST2M, ZMFORM, +ZMPRNT, ZMFPRT, ZMWRIT, and ZMREAD provide similar input and output +conversions. + +For the output format of ZM numbers, JFORM1 and JFORM2 determine the default +format for the individual parts of a complex number as with FM numbers. + + JFORMZ determines the combined output format of the real and + imaginary parts. + + JFORMZ = 1 normal setting : 1.23 - 4.56 i + = 2 use capital I : 1.23 - 4.56 I + = 3 parenthesis format: ( 1.23 , -4.56 ) + + JPRNTZ controls whether to print real and imaginary parts + on one line whenever possible. + + JPRNTZ = 1 print both parts as a single string : + 1.23456789M+321 - 9.87654321M-123 i + = 2 print on separate lines without the 'i' : + 1.23456789M+321 + -9.87654321M-123 + +For further description of these routines, see sections 9 and 10 below. + + +4. ARITHMETIC TRACING + +NTRACE and LVLTRC control trace printout from the package. + +NTRACE = 0 No output except warnings and errors. (Default) + = 1 The result of each call to one of the routines + is printed in base 10, using FMOUT. + = -1 The result of each call to one of the routines + is printed in internal base MBASE format. + = 2 The input arguments and result of each call to one + of the routines is printed in base 10, using FMOUT. + = -2 The input arguments and result of each call to one + of the routines is printed in base MBASE format. + +LVLTRC defines the call level to which the trace is done. LVLTRC = 1 + means only FM routines called directly by the user are traced, + LVLTRC = 2 also prints traces for FM routines called by other + FM routines called directly by the user, etc. Default is 1. + +In the above description, internal MBASE format means the number is +printed as it appears in the array --- an exponent followed by NDIG +base MBASE digits. + + +5. ERROR CONDITIONS + +KFLAG is a condition value returned by the package after each call to one of + the routines. Negative values indicate conditions for which a warning + message will be printed unless KWARN = 0. + Positive values indicate conditions that may be of interest but are not + errors. No warning message is printed if KFLAG is nonnegative. + +Subroutine FMFLAG is provided to give the user access to the current +condition code. For example, to set the user's local variable LFLAG +to FM's internal KFLAG value: CALL FMFLAG(LFLAG) + + KFLAG = 0 Normal operation. + + = 1 One of the operands in FMADD or FMSUB was insignificant with + respect to the other, so that the result was equal to + the argument of larger magnitude. + = 2 In converting an FM number to a one word integer in FMM2I, + the FM number was not exactly an integer. The next + integer toward zero was returned. + + = -1 NDIG was less than 2 or more than NDIGMX. + = -2 MBASE was less than 2 or more than MXBASE. + = -3 An exponent was out of range. + = -4 Invalid input argument(s) to an FM routine. + UNKNOWN was returned. + = -5 + or - OVERFLOW was generated as a result from an + FM routine. + = -6 + or - UNDERFLOW was generated as a result from an + FM routine. + = -7 The input string (array) to FMINP was not legal. + = -8 The character array was not large enough in an + input or output routine. + = -9 Precision could not be raised enough to provide all + requested guard digits. Increasing the value + of NDIGMX in file FMSAVE.f90 may fix this. + UNKNOWN was returned. + = -10 An FM input argument was too small in magnitude to + convert to the machine's single or double + precision in FMM2SP or FMM2DP. Check that the + definitions of SPMAX and DPMAX in file FMSAVE.f90 + are correct for the current machine. + Zero was returned. + = -11 Array MBERN is not dimensioned large enough for the + requested number of Bernoulli numbers. + = -12 Array MJSUMS is not dimensioned large enough for + the number of coefficients needed in the + reflection formula in FMPGAM. + +When a negative KFLAG condition is encountered, the value of KWARN +determines the action to be taken. + +KWARN = 0 Execution continues and no message is printed. + = 1 A warning message is printed and execution continues. + = 2 A warning message is printed and execution stops. + +The default setting is KWARN = 1. + +When an overflow or underflow is generated for an operation in which an input +argument was already an overflow or underflow, no additional message is +printed. When an unknown result is generated and an input argument was +already unknown, no additional message is printed. In these cases the +negative KFLAG value is still returned. + +IM routines handle exceptions like OVERFLOW or UNKNOWN in the same way as FM +routines. When using IMMPY, the product of two large positive integers will +return +OVERFLOW. The routines IMMPYM and IMPMOD can be used to obtain a +modular result without overflow. The largest representable IM integer is +MBASE**NDIGMX - 1. For example, if MBASE is 10**7 and NDIGMX is set to 256, +integers less than 10**1792 can be used. + + +6. OTHER OPTIONS + +KRAD = 0 All angles in the trigonometric functions and inverse functions + are measured in degrees. + = 1 All angles are measured in radians. (Default) + +KROUND = -1 All results are rounded toward minus infinity. + = 0 All results are rounded toward zero (chopped). + = 1 All results are rounded to the nearest FM number, or to the + value with an even last digit if the result is halfway + between two FM numbers. (Default) + = 2 All results are rounded toward plus infinity. + + In all cases, while a function is being computed all intermediate + results are rounded to nearest, with only the final result being + rounded according to KROUND. + +KRPERF = 0 A smaller number of guard digits used, to give nearly perfect + rounding. This number is chosen so that the last intermediate + result should have error less than 0.001 unit in the last place + of the final rounded result. (Default) + = 1 Causes more guard digits to be used, to get perfect rounding in + the mode set by KROUND. This slows execution speed. + + If a small base is used for the arithmetic, like MBASE = 2, 10, or 16, + FM assumes that the arithmetic hardware for some machine is being + simulated, so perfect rounding is done without regard for the value + of KRPERF. + If KROUND = 1, then KRPERF = 1 means returned results are no more than + 0.500 units in the last place from the exact mathematical result, + versus 0.501 for KRPERF = 0. + If KROUND is not 1, then KRPERF = 1 means returned results are no more + than 1.000 units in the last place from the exact mathematical result, + versus 1.001 for KRPERF = 0. + +KSWIDE defines the maximum screen width to be used for all unit KW output. + Default is 80. + +KESWCH controls the action taken in FMINP and other input routines for + strings like 'E7' that have no digits before the exponent field. + This is sometimes a convenient abbreviation when doing interactive + keyboard input. + KESWCH = 1 causes 'E7' to translate like '1.0E+7'. (Default) + KESWCH = 0 causes 'E7' to translate like '0.0E+7' and give 0. + +CMCHAR defines the exponent letter to be used for FM variable output. + Default is 'M', as in 1.2345M+678. + Change it to 'E' for output to be read by a non-FM program. + +KDEBUG = 0 No error checking is done to see if input arguments are valid + and parameters like NDIG and MBASE are correct upon entry to + each routine. (Default) + = 1 Some error checking is done. (Slower speed) + +See module FMVALS in file FMSAVE.f90 for additional description of these and +other variables defining various FM conditions. + + +7. ARRAY DIMENSIONS + +The dimensions of the arrays in the FM package are defined using parameters +NDIGMX and NBITS. +NDIGMX is the maximum value the user may set for NDIG. +NBITS is the number of bits used to represent integers for a given machine. + See the EFFICIENCY discussion below. + +The standard version of FM sets NDIGMX = 55, so on a 32-bit machine using +MBASE = 10**7 the maximum precision is about 7*54+1 = 379 significant +digits. Previous versions of FM set NDIGMX = 256. Two reasons for making +this change are: +(a) Almost all applications using FM use only 30 to 50 significant digits + for checking double or quadruple precision results, and the larger + arrays are wasted space. +(b) Most FM applications use the derived type interface so that the number + of changes to existing code is minimized. Many compilers implement the + FM interface by doing copy in / copy out argument passing of the derived + types. Copying the entire large array when only a small part of it is + being used causes the derived type arithmetic to be slow compared to + making direct calls to the subroutines. Setting NDIGMX to be only + slightly higher than a program actually uses minimizes any performance + penalty for the derived type arithmetic. + +To change dimensions so that 10,000 significant digit calculation can be +done, NDIGMX needs to be at least 10**4/7 + 5 = 1434. This allows for a +few user guard digits to be defined when the precision is changed using +CALL FMSET(10000). Changing 'NDIGMX = 55' to 'NDIGMX = 1434' in FMSAVE.f90 +will define all the new array sizes. + +If NDIG much greater than 256 is to be used and elementary functions will +be needed, they will be faster if array MJSUMS is larger. The parameter +defining the size of MJSUMS is set in the standard version by + LJSUMS = 8*(LUNPCK+2) +The 8 means that up to eight concurrent sums can be used by the elementary +functions. The approximate number needed for best speed is given by + 0.051*Log(MBASE)*NDIG**0.333 + 1.85 +For example, with MBASE=10**7 and NDIG=1434 this gives 11. Changing +'LJSUMS = 8*(LUNPCK+2)' to 'LJSUMS = 11*(LUNPCK+2)' in FMSAVE.f90 will give +slightly better speed. + +FM numbers in packed format have dimension -1:LPACK, and those in unpacked +format have dimension -1:LUNPCK. + +The parameters LPACKZ and LUNPKZ define the size of the packed and unpacked +ZM arrays. The real part starts at the beginning of the array, and the +imaginary part starts at word KPTIMP for packed format or at word KPTIMU for +unpacked format. + + +8. PORTABILITY + +In FMSET several variables are set to machine-dependent values, and many of +the variables initialized in module FMVALS in file FMSAVE.f90 are checked to +see that they have reasonable values. FMSET will print warning messages on +unit KW for any of the FMVALS variables that seem to be poorly initialized. + +If an FM run fails, call FMVARS to get a list of all the FMVALS variables +printed on unit KW. Setting KDEBUG = 1 at the start may also identify some +errors. + +Some compilers object to a function like FMCOMP with side effects such as +changing KFLAG or other module variables. Blocks of code in FMCOMP and +IMCOMP that modify these variables are identified so they may be removed or +commented out to produce a function without side effects. This disables +trace printing in FMCOMP and IMCOMP, and error codes are not returned in +KFLAG. See FMCOMP and IMCOMP for further details. + +In FMBER2 and FMPGAM several constants are used that require the machine's +integer word size to be at least 32 bits. + + +9. LIST OF ROUTINES - Shown after section 11 below. + + +10. NEW FOR VERSION 1.2 + +Version 1.2 is written in Fortran-90 free source format. + +The routines for the Gamma function and related mathematical special +functions are new in version 1.2. + +Several new derived-type function interfaces are included in module FMZM in +file FMZM90.f90, such as integer multiple precision operations GCD, modular +multiplication, and modular powers. There are also formatting functions and +function interfaces for the Gamma and related special functions. + +Two new rounding modes have been added, round toward -infinity and round +toward +infinity. See the description of KROUND above. +An option has been added to force more guard digits to be used, so that basic +arithmetic operations will always round perfectly. See the description of +KRPERF above. +These options are included for applications that use FM to check IEEE +hardware arithmetic. They are not normally useful for most multiple +precision calculations. + +The random number routine FM_RANDOM_NUMBER uses 49-digit prime numbers in a +shuffled multiplicative congruential generator. Historically, some popular +random number routines tried so hard for maximum speed that they were later +found to fail some tests for randomness. FM_RANDOM_NUMBER tries to return +high-quality random values. It is much slower than other generators, but can +return about 60,000 numbers per second on a 400 MHz single-processor machine. +This is usually fast enough to be used as a check for suspicious monte carlo +results from other generators. +For more details, see the comments in the routine. + +The arrays for multiple precision numbers were dimensioned starting at 0 in +version 1.1, and now begin at -1. Array(-1) now holds the sign of the number +instead of combining the sign with Array(2) as before. The reason for moving +the sign bit is that many of the original routines, written before Fortran-90 +existed, simplified the logic by temporarily making input arguments positive, +working with positive values, then restoring the signs to the input arguments +upon return. This became illegal under Fortran-90 when used with the derived +type interface, which demands the inputs to functions for arithmetic operator +overloading be declared with INTENT(IN). + +The common blocks of earlier versions have been replaced by module FMVALS. +This makes it easier to hide the FM internal variable names from the calling +program, and these variables can be initialized in the module so the +initializing call to FMSET is no longer mandatory. Several new routines are +provided to set or return the values for some of these variables. See the +descriptions for FMSETVAR, FMFLAG, and FMVARS above. + +Version 1.0 used integer arrays and integer arithmetic internally to perform +the multiple precision operations. Later versions use double precision +arithmetic and arrays internally. This is usually faster at higher +precisions, and on many machines it is also faster at lower precisions. +Version 1.2 is written so that the arithmetic used can easily be changed from +double precision to integer, or any other available arithmetic type. This +permits the user to make the best use of a given machine's arithmetic +hardware. See the EFFICIENCY discussion below. + + +11. EFFICIENCY + +When the derived type interface is used to access the FM routines, there may +be a loss of speed if the arrays used to define the multiple precision data +types are larger than necessary. See comment (b) in the section above on +array dimensions. + +To take advantage of hardware architecture on different machines, the package +has been designed so that the arithmetic used to perform the multiple +precision operations can easily be changed. All variables that must be +changed to get a different arithmetic have names beginning with 'M' and are +declared using REAL (KIND(1.0D0)) ... + +For example, to change the package to use integer arithmetic internally, make +these two changes everywhere in the FM.f90 file. +Change 'REAL (KIND(1.0D0))' to 'INTEGER'. +Change 'AINT (' to 'INT('. Note the blank between AINT and (. +On some systems, changing 'AINT (' to '(' may give better speed. + +In most places in FM, an AINT function is not supposed to be changed. These +are written 'AINT(', with no embedded blank, so they will not be changed by +the global change above. + +The first of these changes must also be made throughout the files FMZM90.f90 +and FMSAVE.f90. +Change 'REAL (KIND(1.0D0))' to 'INTEGER'. + +Many of the variables in FMSAVE.f90 are initialized when they are declared, +so the initialization values should be changed to integer values. +Find the lines beginning '! Integer initialization' in file FMSAVE.f90 and +change the values. The values needed for 32-bit integer arithmetic are next +to the double precision values, but commented out. In every case, the line +before the '! Integer initialization' should have '!' inserted in column 1 +and the line after should have the '!' removed from column 1. If a different +wordsize is used, the first call to FMSET will check the values defined in +file FMSAVE.f90 and write messages (on unit KW) if any need to be changed. + +When changing to a different type of arithmetic, any FM arrays in the user's +program must be changed to agree. If derived types are used instead of +direct calls, no changes should be needed in the calling program. + +For example, in the test program TestFM.f90, change all +'REAL (KIND(1.0D0))' to 'INTEGER', as with the other files. + +This version of FM restricts the base used to be also representable in +integer variables, so using precision above double usually does not save much +time unless integers can also be declared at a higher precision. Using IEEE +Extended would allow a base of around 10**9 to be chosen, but the delayed +digit-normalization method used for multiplication and division means that a +slightly smaller base like 10**8 would probably run faster. This would +usually not be much faster than using the usual base 10**7 with double +precision. + +The value of NBITS defined as a parameter in FMVALS refers to the number of +bits used to represent integers in an M-variable word. Typical values for +NBITS are: 24 for IEEE single precision, 32 for integer, 53 for IEEE double +precision. NBITS controls only array size, so setting it too high is ok, but +then the program will use slightly more memory than necessary. + +For cases where special compiler directives or minor re-writing of the code +may improve speed, several of the most important loops in FM are identified +by comments containing the string '(Inner Loop)'. + + + +-------------------------------------------------------------------------------- +--------------- Routines for Real Floating-Point Operations ---------------- + + + +These are the FM routines that are designed to be called by the user. +All are subroutines except logical function FMCOMP. +MA, MB, MC refer to FM format numbers. + +In Fortran-90 and later versions of the Fortran standard, it is potentially +unsafe to use the same array more than once in the calling sequence. The +operation MA = MA + MB should not be written as + CALL FMADD(MA,MB,MA) +since the compiler is allowed to pass the three arguments with a copy in / +copy out mechanism. This means the third argument, containing the result, +might not be copied out last, and then a later copy out of the original +input MA could destroy the computed result. + +One solution is to use a third array and then put the result back in MA: + CALL FMADD(MA,MB,MC) + CALL FMEQ(MC,MA) + +When the first call is doing one of the "fast" operations like addition, +the extra call to move the result back to MA can cause a noticeable loss +in efficiency. To avoid this, separate routines are provided for the basic +arithmetic operations when the result is to be returned in the same array +as one of the inputs. + +A routine name with a suffix of "_R1" returns the result in the first input +array, and a suffix of "_R2" returns the result in the second input array. +The example above would then be: + CALL FMADD_R1(MA,MB) + +These routines each have one less argument than the original version, since +the output is re-directed to one of the inputs. The result array should not +be the same as any input array when the original version of the routine is +used. + +The routines that can be used this way are listed below. For others, like + CALL FMEXP(MA,MA) +the relative cost of doing an extra copy is small. This one should become + CALL FMEXP(MA,MB) + CALL FMEQ(MB,MA) + +If the derived-type interface is used, as in + TYPE (FM) A,B + ... + A = A + B +there is no problem putting the result back into A, since the interface routine +creates a temporary scratch array for the result of A + B, allowing copy in / +copy out to work. + +For each of these routines there is also a version available for which the +argument list is the same but all FM numbers are in packed format. The +routines using packed numbers have the same names except 'FM' is replaced by +'FP' at the start of each name. + + +FMABS(MA,MB) MB = ABS(MA) + +FMACOS(MA,MB) MB = ACOS(MA) + +FMADD(MA,MB,MC) MC = MA + MB + +FMADD_R1(MA,MB) MA = MA + MB + +FMADD_R2(MA,MB) MB = MA + MB + +FMADDI(MA,IVAL) MA = MA + IVAL Increment an FM number by a one word + integer. Note this call does not have + an "MB" result like FMDIVI and FMMPYI. + +FMASIN(MA,MB) MB = ASIN(MA) + +FMATAN(MA,MB) MB = ATAN(MA) + +FMATN2(MA,MB,MC) MC = ATAN2(MA,MB) + +FMBIG(MA) MA = Biggest FM number less than overflow. + +FMCHSH(MA,MB,MC) MB = COSH(MA), MC = SINH(MA). + Faster than making two separate calls. + +FMCOMP(MA,LREL,MB) Logical comparison of MA and MB. + LREL is a CHARACTER*2 value identifying + which of the six comparisons is to be made. + Example: IF (FMCOMP(MA,'GE',MB)) ... + Also can be: IF (FMCOMP(MA,'>=',MB)) ... + CHARACTER*1 is ok: IF (FMCOMP(MA,'>',MB)) ... + +FMCONS Set several saved constants that depend on MBASE, + the base being used. FMCONS should be called + immediately after changing MBASE. + +FMCOS(MA,MB) MB = COS(MA) + +FMCOSH(MA,MB) MB = COSH(MA) + +FMCSSN(MA,MB,MC) MB = COS(MA), MC = SIN(MA). + Faster than making two separate calls. + +FMDIG(NSTACK,KST) Find a set of precisions to use during Newton + iteration for finding a simple root starting with + about double precision accuracy. + +FMDIM(MA,MB,MC) MC = DIM(MA,MB) + +FMDIV(MA,MB,MC) MC = MA / MB + +FMDIV_R1(MA,MB) MA = MA / MB + +FMDIV_R2(MA,MB) MB = MA / MB + +FMDIVI(MA,IVAL,MB) MB = MA/IVAL IVAL is a one word integer. + +FMDIVI_R1(MA,IVAL) MA = MA/IVAL + +FMDP2M(X,MA) MA = X Convert from double precision to FM. + +FMDPM(X,MA) MA = X Convert from double precision to FM. + Faster than FMDP2M, but MA agrees with X only + to D.P. accuracy. See the comments in the + two routines. + +FMEQ(MA,MB) MB = MA Both have precision NDIG. + This is the version to use for standard + B = A statements. + +FMEQU(MA,MB,NA,NB) MB = MA Version for changing precision. + MA has NA digits (i.e., MA was computed + using NDIG = NA), and MB will be defined + having NB digits. + MB is rounded if NB < NA + MB is zero-padded if NB > NA + +FMEXP(MA,MB) MB = EXP(MA) + +FMFLAG(K) K = KFLAG get the value of the FM condition + flag -- stored in the internal FM + variable KFLAG in module FMVALS. + +FMFORM(FORM,MA,STRING) MA is converted to a character string using format + FORM and returned in STRING. FORM can represent + I, F, E, or 1PE formats. Example: + CALL FMFORM('F60.40',MA,STRING) + +FMFPRT(FORM,MA) Print MA on unit KW using FORM format. + +FMI2M(IVAL,MA) MA = IVAL Convert from one word integer to FM. + +FMINP(LINE,MA,LA,LB) MA = LINE Input conversion. + Convert LINE(LA) through LINE(LB) + from characters to FM. + +FMINT(MA,MB) MB = INT(MA) Integer part of MA. + +FMIPWR(MA,IVAL,MB) MB = MA**IVAL Raise an FM number to a one word + integer power. + +FMLG10(MA,MB) MB = LOG10(MA) + +FMLN(MA,MB) MB = LOG(MA) + +FMLNI(IVAL,MA) MA = LOG(IVAL) Natural log of a one word integer. + +FMM2DP(MA,X) X = MA Convert from FM to double precision. + +FMM2I(MA,IVAL) IVAL = MA Convert from FM to integer. + +FMM2SP(MA,X) X = MA Convert from FM to single precision. + +FMMAX(MA,MB,MC) MC = MAX(MA,MB) + +FMMIN(MA,MB,MC) MC = MIN(MA,MB) + +FMMOD(MA,MB,MC) MC = MA mod MB + +FMMPY(MA,MB,MC) MC = MA * MB + +FMMPY_R1(MA,MB) MA = MA * MB + +FMMPY_R2(MA,MB) MB = MA * MB + +FMMPYI(MA,IVAL,MB) MB = MA*IVAL Multiply by a one word integer. + +FMMPYI_R1(MA,IVAL) MA = MA*IVAL + +FMNINT(MA,MB) MB = NINT(MA) Nearest FM integer. + +FMOUT(MA,LINE,LB) LINE = MA Convert from FM to character. + LINE is a character array of length LB. + +FMPI(MA) MA = pi + +FMPRNT(MA) Print MA on unit KW using current format. + +FMPWR(MA,MB,MC) MC = MA**MB + +FM_RANDOM_NUMBER(X) X is returned as a double precision random number, + uniform on (0,1). High-quality, long-period + generator. + Note that X is double precision, unlike the similar + Fortran intrinsic random number routine, which + returns a single-precision result. + See the comments in section 10 below and also those + in the routine for more details. + +FMREAD(KREAD,MA) MA is returned after reading one (possibly multi-line) + FM number on unit KREAD. This routine reads + numbers written by FMWRIT. + +FMRPWR(MA,K,J,MB) MB = MA**(K/J) Rational power. + Faster than FMPWR for functions like the cube root. + +FMSET(NPREC) Set the internal FM variables so that the precision + is at least NPREC base 10 digits plus three base 10 + guard digits. + +FMSETVAR(STRING) Define a new value for one of the internal FM + variables in module FMVALS that controls one of the + FM options. STRING has the form variable = value. + Example: To change the screen width for FM output: + CALL FMSETVAR(' KSWIDE = 120 ') + The variables that can be changed and the options + they control are listed in sections 2 through 6 + above. Only one variable can be set per call. + The variable name in STRING must have no embedded + blanks. The value part of STRING can be in any + numerical format, except in the case of variable + CMCHAR, which is character type. To set CMCHAR to + 'E', don't use any quotes in STRING: + CALL FMSETVAR(' CMCHAR = E ') + +FMSIGN(MA,MB,MC) MC = SIGN(MA,MB) Sign transfer. + +FMSIN(MA,MB) MB = SIN(MA) + +FMSINH(MA,MB) MB = SINH(MA) + +FMSP2M(X,MA) MA = X Convert from single precision to FM. + +FMSQR(MA,MB) MB = MA * MA Faster than FMMPY. + +FMSQR_R1(MA) MA = MA * MA + +FMSQRT(MA,MB) MB = SQRT(MA) + +FMSQRT_R1(MA) MA = SQRT(MA) + +FMST2M(STRING,MA) MA = STRING + Convert from character string to FM. + STRING may be in any numerical format. + Often more convenient than FMINP, which converts + an array of CHARACTER*1 values. Example: + CALL FMST2M('123.4',MA) + +FMSUB(MA,MB,MC) MC = MA - MB + +FMSUB_R1(MA,MB) MA = MA - MB + +FMSUB_R2(MA,MB) MB = MA - MB + +FMTAN(MA,MB) MB = TAN(MA) + +FMTANH(MA,MB) MB = TANH(MA) + +FMULP(MA,MB) MB = One Unit in the Last Place of MA. + +FMVARS Write the current values of the internal FM + variables on unit KW. + +FMWRIT(KWRITE,MA) Write MA on unit KWRITE. + Multi-line numbers will have '&' as the last + nonblank character on all but the last line. These + numbers can then be read easily using FMREAD. + + + +These are the Gamma and Related Functions. + +FMBERN(N,MA,MB) MB = MA*B(N) Multiply by Nth Bernoulli number + +FMBETA(MA,MB,MC) MC = Beta(MA,MB) + +FMCOMB(MA,MB,MC) MC = Combination MA choose MB (Binomial coeff.) + +FMEULR(MA) MA = Euler's constant ( 0.5772156649... ) + +FMFACT(MA,MB) MB = MA Factorial (Gamma(MA+1)) + +FMGAM(MA,MB) MB = Gamma(MA) + +FMIBTA(MX,MA,MB,MC) MC = Incomplete Beta(MX,MA,MB) + +FMIGM1(MA,MB,MC) MC = Incomplete Gamma(MA,MB). Lower case Gamma(a,x) + +FMIGM2(MA,MB,MC) MC = Incomplete Gamma(MA,MB). Upper case Gamma(a,x) + +FMLNGM(MA,MB) MB = Ln(Gamma(MA)) + +FMPGAM(N,MA,MB) MB = Polygamma(N,MA) (Nth derivative of Psi) + +FMPOCH(MA,N,MB) MB = MA*(MA+1)*(MA+2)*...*(MA+N-1) (Pochhammer) + +FMPSI(MA,MB) MB = Psi(MA) (Derivative of Ln(Gamma(MA)) + + + + +-------------------------------------------------------------------------------- +--------------------- Routines for Integer Operations ---------------------- + + + +These are the integer routines that are designed to be called by the user. +All are subroutines except logical function IMCOMP. MA, MB, MC refer to IM +format numbers. In each case the version of the routine to handle packed IM +numbers has the same name, with 'IM' replaced by 'IP'. + +IMABS(MA,MB) MB = ABS(MA) + +IMADD(MA,MB,MC) MC = MA + MB + +IMBIG(MA) MA = Biggest IM number less than overflow. + +IMCOMP(MA,LREL,MB) Logical comparison of MA and MB. + LREL is a CHARACTER*2 value identifying which of + the six comparisons is to be made. + Example: IF (IMCOMP(MA,'GE',MB)) ... + Also can be: IF (IMCOMP(MA,'>=',MB)) + CHARACTER*1 is ok: IF (IMCOMP(MA,'>',MB)) ... + +IMDIM(MA,MB,MC) MC = DIM(MA,MB) + +IMDIV(MA,MB,MC) MC = int(MA/MB) + Use IMDIVR if the remainder is also needed. + +IMDIVI(MA,IVAL,MB) MB = int(MA/IVAL) + IVAL is a one word integer. + Use IMDVIR to get the remainder also. + +IMDIVR(MA,MB,MC,MD) MC = int(MA/MB), MD = MA mod MB + When both the quotient and remainder are needed, + this routine is twice as fast as calling both + IMDIV and IMMOD. + +IMDVIR(MA,IVAL,MB,IREM) MB = int(MA/IVAL), IREM = MA mod IVAL + IVAL and IREM are one word integers. + +IMEQ(MA,MB) MB = MA + +IMFM2I(MAFM,MB) MB = MAFM Convert from real (FM) format to + integer (IM) format. + +IMFORM(FORM,MA,STRING) MA is converted to a character string using format + FORM and returned in STRING. FORM can represent + I, F, E, or 1PE formats. Example: + CALL IMFORM('I70',MA,STRING) + +IMFPRT(FORM,MA) Print MA on unit KW using FORM format. + +IMGCD(MA,MB,MC) MC = greatest common divisor of MA and MB. + +IMI2FM(MA,MBFM) MBFM = MA Convert from integer (IM) format to + real (FM) format. + +IMI2M(IVAL,MA) MA = IVAL Convert from one word integer to IM. + +IMINP(LINE,MA,LA,LB) MA = LINE Input conversion. + Convert LINE(LA) through LINE(LB) + from characters to IM. + +IMM2DP(MA,X) X = MA Convert from IM to double precision. + +IMM2I(MA,IVAL) IVAL = MA Convert from IM to one word integer. + +IMMAX(MA,MB,MC) MC = MAX(MA,MB) + +IMMIN(MA,MB,MC) MC = MIN(MA,MB) + +IMMOD(MA,MB,MC) MC = MA mod MB + +IMMPY(MA,MB,MC) MC = MA*MB + +IMMPYI(MA,IVAL,MB) MB = MA*IVAL Multiply by a one word integer. + +IMMPYM(MA,MB,MC,MD) MD = MA*MB mod MC + Slightly faster than calling IMMPY and IMMOD + separately, and it works for cases where IMMPY + would return OVERFLOW. + +IMOUT(MA,LINE,LB) LINE = MA Convert from IM to character. + LINE is a character array of length LB. + +IMPMOD(MA,MB,MC,MD) MD = MA**MB mod MC + +IMPRNT(MA) Print MA on unit KW. + +IMPWR(MA,MB,MC) MC = MA**MB + +IMREAD(KREAD,MA) MA is returned after reading one (possibly multi-line) + IM number on unit KREAD. + This routine reads numbers written by IMWRIT. + +IMSIGN(MA,MB,MC) MC = SIGN(MA,MB) Sign transfer. + +IMSQR(MA,MB) MB = MA*MA Faster than IMMPY. + +IMST2M(STRING,MA) MA = STRING + Convert from character string to IM. + Often more convenient than IMINP, which converts an + array of CHARACTER*1 values. Example: + CALL IMST2M('12345678901',MA) + +IMSUB(MA,MB,MC) MC = MA - MB + +IMWRIT(KWRITE,MA) Write MA on unit KWRITE. + Multi-line numbers will have '&' as the last nonblank + character on all but the last line. + These numbers can then be read easily using IMREAD. + + + + +-------------------------------------------------------------------------------- +-------------- Routines for Complex Floating-Point Operations -------------- + + + +These are the complex routines that are designed to be called by the user. +All are subroutines, and in each case the version of the routine to handle +packed ZM numbers has the same name, with 'ZM' replaced by 'ZP'. + +MA, MB, MC refer to ZM format complex numbers. +MAFM, MBFM, MCFM refer to FM format real numbers. +INTEG is a Fortran INTEGER variable. +ZVAL is a Fortran COMPLEX variable. + +ZMABS(MA,MBFM) MBFM = ABS(MA) Result is real. + +ZMACOS(MA,MB) MB = ACOS(MA) + +ZMADD(MA,MB,MC) MC = MA + MB + +ZMADDI(MA,INTEG) MA = MA + INTEG Increment an ZM number by a one word + integer. Note this call does not have + an "MB" result like ZMDIVI and ZMMPYI. + +ZMARG(MA,MBFM) MBFM = Argument(MA) Result is real. + +ZMASIN(MA,MB) MB = ASIN(MA) + +ZMATAN(MA,MB) MB = ATAN(MA) + +ZMCHSH(MA,MB,MC) MB = COSH(MA), MC = SINH(MA). + Faster than 2 calls. + +ZMCMPX(MAFM,MBFM,MC) MC = CMPLX(MAFM,MBFM) + +ZMCONJ(MA,MB) MB = CONJG(MA) + +ZMCOS(MA,MB) MB = COS(MA) + +ZMCOSH(MA,MB) MB = COSH(MA) + +ZMCSSN(MA,MB,MC) MB = COS(MA), MC = SIN(MA). + Faster than 2 calls. + +ZMDIV(MA,MB,MC) MC = MA / MB + +ZMDIVI(MA,INTEG,MB) MB = MA / INTEG + +ZMEQ(MA,MB) MB = MA + +ZMEQU(MA,MB,NDA,NDB) MB = MA Version for changing precision. + (NDA and NDB are as in FMEQU) + +ZMEXP(MA,MB) MB = EXP(MA) + +ZMFORM(FORM1,FORM2,MA,STRING) STRING = MA + MA is converted to a character string using format + FORM1 for the real part and FORM2 for the imaginary + part. The result is returned in STRING. FORM1 and + FORM2 can represent I, F, E, or 1PE formats. Example: + CALL ZMFORM('F20.10','F15.10',MA,STRING) + A 1PE in the first format does not carry over to the + other format descriptor, as it would in an ordinary + FORMAT statement. + +ZMFPRT(FORM1,FORM2,MA) Print MA on unit KW using formats FORM1 and FORM2. + +ZMI2M(INTEG,MA) MA = CMPLX(INTEG,0) + +ZM2I2M(INTEG1,INTEG2,MA) MA = CMPLX(INTEG1,INTEG2) + +ZMIMAG(MA,MBFM) MBFM = IMAG(MA) Imaginary part. + +ZMINP(LINE,MA,LA,LB) MA = LINE Input conversion. + Convert LINE(LA) through LINE(LB) from + characters to ZM. LINE is a character array + of length at least LB. + +ZMINT(MA,MB) MB = INT(MA) Integer part of both Real + and Imaginary parts of MA. + +ZMIPWR(MA,INTEG,MB) MB = MA ** INTEG Integer power function. + +ZMLG10(MA,MB) MB = LOG10(MA) + +ZMLN(MA,MB) MB = LOG(MA) + +ZMM2I(MA,INTEG) INTEG = INT(REAL(MA)) + +ZMM2Z(MA,ZVAL) ZVAL = MA + +ZMMPY(MA,MB,MC) MC = MA * MB + +ZMMPYI(MA,INTEG,MB) MB = MA * INTEG + +ZMNINT(MA,MB) MB = NINT(MA) Nearest integer of both Real + and Imaginary. + +ZMOUT(MA,LINE,LB,LAST1,LAST2) LINE = MA + Convert from FM to character. + LINE is the returned character*1 array. + LB is the dimensioned size of LINE. + LAST1 is returned as the position in LINE of + the last character of REAL(MA). + LAST2 is returned as the position in LINE + of the last character of AIMAG(MA). + +ZMPRNT(MA) Print MA on unit KW using current format. + +ZMPWR(MA,MB,MC) MC = MA ** MB + +ZMREAD(KREAD,MA) MA is returned after reading one (possibly multi-line) + ZM number on unit KREAD. + This routine reads numbers written by ZMWRIT. + +ZMREAL(MA,MBFM) MBFM = REAL(MA) Real part. + +ZMRPWR(MA,IVAL,JVAL,MB) MB = MA ** (IVAL/JVAL) + +ZMSET(NPREC) Set precision to the equivalent of a few more than NPREC + base 10 digits. This is now the same as FMSET, but is + retained for compatibility with earlier versions of the + package. + +ZMSIN(MA,MB) MB = SIN(MA) + +ZMSINH(MA,MB) MB = SINH(MA) + +ZMSQR(MA,MB) MB = MA*MA Faster than ZMMPY. + +ZMSQRT(MA,MB) MB = SQRT(MA) + +ZMST2M(STRING,MA) MA = STRING + Convert from character string to ZM. + Often more convenient than ZMINP, which + converts an array of CHARACTER*1 values. + Example: CALL ZMST2M('123.4+5.67i',MA). + +ZMSUB(MA,MB,MC) MC = MA - MB + +ZMTAN(MA,MB) MB = TAN(MA) + +ZMTANH(MA,MB) MB = TANH(MA) + +ZMWRIT(KWRITE,MA) Write MA on unit KWRITE. Multi-line numbers are + formatted for automatic reading with ZMREAD. + +ZMZ2M(ZVAL,MA) MA = ZVAL + + + +================================================================================ +================================================================================ diff --git a/src/fmlib/SAMPLE.CHK b/src/fmlib/SAMPLE.CHK new file mode 100644 index 0000000000000000000000000000000000000000..bd84e0610eda4fe06e51ab45d985c3ad5a438d95 --- /dev/null +++ b/src/fmlib/SAMPLE.CHK @@ -0,0 +1,107 @@ + + + Sample 1. Real root of f(x) = x**5 - 3x**4 + x**3 - 4x**2 + x - 6 = 0. + + + Iteration Newton Approximation + + 0 3.120000000000000000000000000000000000000000000000000000000000 + + 1 3.120656718532108533919391265947916793506741449899073468862023 + + 2 3.120656215327022122238354686569835883519704471397219749798884 + + 3 3.120656215326726500470956115551705969611230193197937042123082 + + 4 3.120656215326726500470956013523797484654623935599078168006617 + + 5 3.120656215326726500470956013523797484654623935599066014988828 + + 6 3.120656215326726500470956013523797484654623935599066014988828 + + + + Sample 2. Find the root above to 300 decimal places. + + 3.12065621532672650047095601352379748465462393559906601498882843581902649995179546 + 89783257450017151095811923431332682839420040840535954560118152245371792881305271951 + 01711893889821240366205830730398354737691328200011005827350420283867070989561927541 + 348452154928259189115694520078941581838752951201099960 + + + + Sample 3. 109 terms were added in the Zeta sum + + Zeta(3) = 1.202056903159594285399738161511449990764986292340498881792272 + + + + Sample 4. 57 values were checked before finding a prime p. + + p = 5468317884572019103692012212053793153845065543480825746529998049913561 + + + + Sample 5. Check that Gamma(1/2) = Sqrt(pi) + + Gamma(1/2) = 1.772453850905516027298167483341145182797549456122387128213808 + + + + Sample 6. Psi and Polygamma functions. + + Sum (n=1 to infinity) 1/(n**2 * (8n+1)**2) = + .013499486145413024755107829105035147950644978635837270816327 + + + + Sample 7. Incomplete gamma and Gamma functions. + + Probability = .19373313011487144632751025918250599953472318607121386973066 + + + + Sample 8. Complex root of f(x) = x**5 - 3x**4 + x**3 - 4x**2 + x - 6 = 0. + + + Iteration Newton Approximation + + 0 .560000000000000000000000000000 + 1.060000000000000000000000000000 i + + 1 .561964780980333719745880263787 + 1.061135231152741154895778904059 i + + 2 .561958308372772219534516409947 + 1.061134679566247415769456345141 i + + 3 .561958308335403235495113920123 + 1.061134679604332556981397796290 i + + 4 .561958308335403235498111195347 + 1.061134679604332556983391239059 i + + 5 .561958308335403235498111195347 + 1.061134679604332556983391239059 i + + + + Sample 9. 44 terms were added to get Exp(1.23-2.34i) + + Result= -2.379681796854777515745457977697 - 2.458032970832342652397461908326 i + + + + Sample 10. Exception handling. + + Iterate Exp(x) starting at 1.0 until overflow occurs. + + + Iteration 1 2.718281828459045235360287471352662497757M+0 + + Iteration 2 1.515426224147926418976043027262991190553M+1 + + Iteration 3 3.814279104760220592209219594098203571024M+6 + + Iteration 4 2.331504399007195462289689911012137666332M+1656520 + + Iteration 5 + OVERFLOW + + Overflow was correctly detected. + + + All results were ok. diff --git a/src/fmlib/SampleFM.F90 b/src/fmlib/SampleFM.F90 new file mode 100644 index 0000000000000000000000000000000000000000..4753d33cc058921cbe81f0f98fa71360ebde6762 --- /dev/null +++ b/src/fmlib/SampleFM.F90 @@ -0,0 +1,639 @@ + PROGRAM SAMPLE + +! David M. Smith + +! This is a sample program using the FM Fortran-90 modules for +! doing arithmetic using the FM, IM, and ZM derived types. + +! The output is saved in file SAMPLE.LOG. A comparison file, +! SAMPLE.CHK, is provided showing the expected output from 32-bit +! (IEEE arithmetic) machines. When run on other computers, all the +! numerical results should still be the same, but the number of terms +! needed for some of the results might be slightly different. The +! program checks all the results and the last line of the log file +! should be "All results were ok." + +! In a few places, an explicit call is made to an FM or ZM routine. +! For a call like CALL FM_FORM('F65.60',MAFM,ST1), note that the +! "FM_" form is used since MAFM is a TYPE (FM) variable and not just +! an array. See the discussion in FMZM90.f. + + + USE FMZM + + IMPLICIT NONE + + TYPE ( FM ) MAFM,MBFM,MCFM,MDFM + TYPE ( IM ) MAIM,MBIM,MCIM + TYPE ( ZM ) MAZM,MBZM,MCZM,MDZM + + CHARACTER(80) :: ST1 + CHARACTER(175) :: FMT + INTEGER ITER,J,K,KLOG,LFLAG,NERROR + INTEGER SEED(7) + DOUBLE PRECISION VALUE + +! Write output to the screen (unit *), and also to the +! file SAMPLE.LOG. + + KLOG = 18 + OPEN (KLOG,FILE='SAMPLE.LOG') + + NERROR = 0 + + +! 1. Find a root of the equation +! f(x) = x**5 - 3x**4 + x**3 - 4x**2 + x - 6 = 0. + +! Set precision to give at least 60 significant digits. + + CALL FM_SET(60) + +! Use Newton's method with initial guess x = 3.12. +! This version is not tuned for speed. See the FMSQRT +! routine for possible ways to increase speed. +! Horner's rule is used to evaluate the function. + +! MAFM is the previous iterate. +! MBFM is the current iterate. + +! TO_FM is a function for converting other types of numbers +! to type FM. Note that TO_FM(3.12) converts the REAL +! constant to FM, but it is accurate only to single +! precision. TO_FM(3.12D0) agrees with 3.12 to double +! precision accuracy, and TO_FM('3.12') or +! TO_FM(312)/TO_FM(100) agrees to full FM accuracy. +! Here, TO_FM(3.12) would be ok, since Newton iteration +! will correct the error coming from single precision, +! but it is a good habit to use the more accurate form. + + MAFM = TO_FM('3.12') + +! Print the first iteration. + + FMT = "(//' Sample 1. Real root of f(x) = x**5 - 3x**4 + ',"// & + "'x**3 - 4x**2 + x - 6 = 0.'///" // & + "' Iteration Newton Approximation')" + WRITE (*,FMT) + WRITE (KLOG,FMT) + +! FM_FORMAT is a formatting function that returns a +! character string (of length 200). +! Avoid using FM_FORMAT in the write list, since this +! function itself does internal WRITE operations, and +! some compilers object to recursive WRITE references. + + ST1 = FM_FORMAT('F65.60',MAFM) + WRITE (* ,"(/I10,4X,A)") 0,TRIM(ST1) + WRITE (KLOG,"(/I10,4X,A)") 0,TRIM(ST1) + + DO ITER = 1, 10 + +! MCFM is f(MAFM). + + MCFM = ((((MAFM-3)*MAFM+1)*MAFM-4)*MAFM+1)*MAFM-6 + +! MDFM is f'(MAFM). + + MDFM = (((5*MAFM-12)*MAFM+3)*MAFM-8)*MAFM+1 + + MBFM = MAFM - MCFM/MDFM + +! Print each iteration. + +! FM_FORM is a formatting subroutine. FM_FORM can +! handle output strings longer that 200 characters. + + CALL FM_FORM('F65.60',MBFM,ST1) + WRITE (* ,"(/I10,4X,A)") ITER,TRIM(ST1) + WRITE (KLOG,"(/I10,4X,A)") ITER,TRIM(ST1) + +! Stop iterating if MAFM and MBFM agree to over 60 places. + + MDFM = ABS(MAFM-MBFM) + IF (MDFM < 1.0D-61) EXIT + +! Set MAFM = MBFM for the next iteration. + + MAFM = MBFM + ENDDO + +! Check the answer. + + MCFM = TO_FM('3.120656215326726500470956013523797484654623'// & + '9355990660149888284358') + +! It is slightly safer to do this test with .NOT. instead of +! IF (ABS(MCFM-MBFM) >= 1.0D-61) THEN +! because if the result of ABS(MCFM-MBFM) is FM's UNKNOWN value, +! the comparison returns false for all comparisons. + + IF (.NOT.(ABS(MCFM-MBFM) < 1.0D-61)) THEN + NERROR = NERROR + 1 + WRITE (* ,"(/' Error in sample case number 1.'/)") + WRITE (KLOG,"(/' Error in sample case number 1.'/)") + ENDIF + + +! 2. Higher Precision. Compute the root above to 300 decimal places. + + CALL FM_SET(300) + +! It is tempting to just say MAFM = MCFM here to initialize the +! start of the higher precision iterations to be the check value +! defined above. That will not work, because precision has +! changed. Most of the digits of MCFM may be undefined at the +! new precision. +! The usual way to pad a lower precision value with zeros when +! raising precision is to use subroutine FM_EQU, but here it is +! easier to define MAFM from scratch at the new precision. + + MAFM = TO_FM('3.120656215326726500470956013523797484654623'// & + '9355990660149888284358') + + DO ITER = 1, 10 + +! MCFM is f(MAFM). + + MCFM = ((((MAFM-3)*MAFM+1)*MAFM-4)*MAFM+1)*MAFM-6 + +! MDFM is f'(MAFM). + + MDFM = (((5*MAFM-12)*MAFM+3)*MAFM-8)*MAFM+1 + + MBFM = MAFM - MCFM/MDFM + +! Stop iterating if MAFM and MBFM agree to over 300 places. + + MDFM = ABS(MAFM-MBFM) + IF (MDFM < TO_FM('1.0E-301')) EXIT + +! Set MAFM = MBFM for the next iteration. + + MAFM = MBFM + ENDDO + +! For very high precision output, it is sometimes more +! convenient to use FM_PRNT to format and print the numbers, +! since the line breaks are handled automatically. +! The unit number for the output, KW, and the format codes +! to be used, JFORM1 and JFORM2, are internal FM variables. +! Subroutine FMSETVAR is used to re-define these, and the +! new values will remain in effect for any further calls +! to FM_PRNT. + +! Other variables that can be changed and the options they +! control are listed in the documentation at the top of file +! FM.f. + +! Set the format to F305.300 + + CALL FMSETVAR(' JFORM1 = 2 ') + CALL FMSETVAR(' JFORM2 = 300 ') + +! Set the output screen width to 90 columns. + + CALL FMSETVAR(' KSWIDE = 90 ') + + WRITE (* ,"(///' Sample 2. Find the root above to 300 decimal places.'/)") + WRITE (KLOG,"(///' Sample 2. Find the root above to 300 decimal places.'/)") + +! Write to the log file. + + CALL FMSETVAR(' KW = 18 ') + CALL FM_PRNT(MBFM) + +! Write to the screen (unit 6). + + CALL FMSETVAR(' KW = 6 ') + CALL FM_PRNT(MBFM) + +! Check the answer. + + MCFM = TO_FM('3.12065621532672650047095601352379748465462393559906601'// & + '4988828435819026499951795468978325745001715109581192343'// & + '1332682839420040840535954560118152245371792881305271951'// & + '0171189388982124036620583073039835473769132820001100582'// & + '7350420283867070989561927541348452154928259189115694520'// & + '0789415818387529512010999602155131321076797099026664236') + + IF (.NOT.(ABS(MCFM-MBFM) < TO_FM('1.0E-301'))) THEN + NERROR = NERROR + 1 + WRITE (* ,"(/' Error in sample case number 2.'/)") + WRITE (KLOG,"(/' Error in sample case number 2.'/)") + ENDIF + + +! 3. Compute the Riemann Zeta function for s=3. + +! Use Gosper's formula: Zeta(3) = +! (5/4)*Sum[ (-1)**k * (k!)**2 / ((k+1)**2 * (2k+1)!) ] +! while k = 0, 1, .... + +! MAFM is the current partial sum. +! MBFM is the current term. +! MCFM is k! +! MDFM is (2k+1)! + + CALL FM_SET(60) + MAFM = 1 + MCFM = 1 + MDFM = 1 + DO K = 1, 200 + MCFM = K*MCFM + J = 2*K*(2*K+1) + MDFM = J*MDFM + MBFM = MCFM**2 + J = (K+1)*(K+1) + MBFM = (MBFM/J)/MDFM + IF (MOD(K,2) == 0) THEN + MAFM = MAFM + MBFM + ELSE + MAFM = MAFM - MBFM + ENDIF + +! Test for convergence. + + IF (MAFM-MBFM == MAFM) THEN + WRITE (* , & + "(///' Sample 3.',8X,I5,' terms were added in the Zeta sum'/)") K + WRITE (KLOG, & + "(///' Sample 3.',8X,I5,' terms were added in the Zeta sum'/)") K + EXIT + ENDIF + ENDDO + +! Print the result. + + MAFM = (5*MAFM)/4 + CALL FM_FORM('F62.60',MAFM,ST1) + WRITE (* ,"(' Zeta(3) = ',A)") TRIM(ST1) + WRITE (KLOG,"(' Zeta(3) = ',A)") TRIM(ST1) + +! Check the answer. + + MCFM = TO_FM('1.20205690315959428539973816151144999076498'// & + '6292340498881792271555') + IF (.NOT.(ABS(MAFM-MCFM) < 1.0D-61)) THEN + NERROR = NERROR + 1 + WRITE (* ,"(/' Error in sample case number 3.'/)") + WRITE (KLOG,"(/' Error in sample case number 3.'/)") + ENDIF + + +! 4. Integer multiple precision calculations. + +! Fermat's theorem says x**(p-1) mod p = 1 +! when p is prime and x is not a multiple of p. +! If x**(p-1) mod p gives 1 for some p with +! several different x's, then it is very likely +! that p is prime (but it is not certain until +! further tests are done). + +! Find a 70-digit number p that is "probably" prime. + +! Use FM_RANDOM_NUMBER to generate a random 70-digit +! starting value and search for a prime from that point. +! Initialize the generator. +! Note that VALUE is double precision, unlike the similar +! Fortran intrinsic random number routine, which returns +! a single-precision result. + + CALL FM_SET(80) + SEED = (/ 2718281,8284590,4523536,0287471,3526624,9775724,7093699 /) + CALL FM_RANDOM_SEED(PUT=SEED) + +! MAIM is the value p being tested. + + MAIM = 0 + MCIM = TO_IM(10)**13 + DO J = 1, 6 + CALL FM_RANDOM_NUMBER(VALUE) + MBIM = 1.0D+13*VALUE + MAIM = MAIM*MCIM + MBIM + ENDDO + MCIM = TO_IM(10)**70 + MAIM = MOD(MAIM,MCIM) + +! To speed up the search, test only values that are +! not multiples of 2, 3, 5, 7, 11, 13. + + K = 2*3*5*7*11*13 + MAIM = (MAIM/K)*K + K + 1 + MCIM = 3 + + DO J = 1, 100 + MBIM = MAIM - 1 + +! Compute 3**(p-1) mod p + + MCIM = POWER_MOD(MCIM,MBIM,MAIM) + IF (MCIM == 1) THEN + +! Check that 7**(p-1) mod p is also 1. + + MCIM = 7 + MCIM = POWER_MOD(MCIM,MBIM,MAIM) + IF (MCIM == 1) THEN + FMT = "(///' Sample 4.',8X,I5,' values were"// & + " checked before finding a prime p.'/)" + WRITE (* ,FMT) J + WRITE (KLOG,FMT) J + EXIT + ENDIF + ENDIF + + MCIM = 3 + MAIM = MAIM + K + ENDDO + +! Print the result. + + CALL IM_FORM('I72',MAIM,ST1) + WRITE (* ,"(' p =',A)") TRIM(ST1) + WRITE (KLOG,"(' p =',A)") TRIM(ST1) + +! Check the answer. + + MCIM = TO_IM('546831788457201910369201221205379315384'// & + '5065543480825746529998049913561') + IF (.NOT.(MAIM == MCIM)) THEN + NERROR = NERROR + 1 + WRITE (* ,"(/' Error in sample case number 4.'/)") + WRITE (KLOG,"(/' Error in sample case number 4.'/)") + ENDIF + + +! 5. Gamma function. + +! Check that Gamma(1/2) is Sqrt(pi) + + CALL FM_SET(60) + WRITE (* ,"(///' Sample 5. Check that Gamma(1/2) = Sqrt(pi)'/)") + WRITE (KLOG,"(///' Sample 5. Check that Gamma(1/2) = Sqrt(pi)'/)") + + MBFM = GAMMA(TO_FM('0.5')) + +! Print the result. + + CALL FM_FORM('F62.60',MBFM,ST1) + WRITE (* ,"(' Gamma(1/2) = ',A)") TRIM(ST1) + WRITE (KLOG,"(' Gamma(1/2) = ',A)") TRIM(ST1) + +! Check the answer. + + MCFM = SQRT(4*ATAN(TO_FM(1))) + IF (.NOT.(ABS(MCFM-MBFM) < 1.0D-61)) THEN + NERROR = NERROR + 1 + WRITE (* ,"(/' Error in sample case number 5.'/)") + WRITE (KLOG,"(/' Error in sample case number 5.'/)") + ENDIF + + +! 6. Psi and Polygamma functions. + +! Rational series can often be summed using these functions. +! Sum (n=1 to infinity) 1/(n**2 * (8n+1)**2) = +! 16*(Psi(1) - Psi(9/8)) + Polygamma(1,1) + Polygamma(1,9/8) +! Ref: Abramowitz & Stegun, Handbook of Mathematical Functions, +! chapter 6, Example 10. + + WRITE (* ,"(///' Sample 6. Psi and Polygamma functions.'/)") + WRITE (KLOG,"(///' Sample 6. Psi and Polygamma functions.'/)") + + MBFM = 16*(PSI(TO_FM(1)) - PSI(TO_FM(9)/8)) + & + POLYGAMMA(1,TO_FM(1)) + POLYGAMMA(1,TO_FM(9)/8) + +! Print the result. + + CALL FM_FORM('F65.60',MBFM,ST1) + WRITE (* ,"(' Sum (n=1 to infinity) 1/(n**2 * (8n+1)**2) = '/9X,A)") TRIM(ST1) + WRITE (KLOG,"(' Sum (n=1 to infinity) 1/(n**2 * (8n+1)**2) = '/9X,A)") TRIM(ST1) + +! Check the answer. + + MCFM = TO_FM('1.34994861454130247551078291050351479506449786'// & + '35837270816327396M-2') + IF (.NOT.(ABS(MCFM-MBFM) < 1.0D-61)) THEN + NERROR = NERROR + 1 + WRITE (* ,"(/' Error in sample case number 6.'/)") + WRITE (KLOG,"(/' Error in sample case number 6.'/)") + ENDIF + + +! 7. Incomplete gamma and Gamma functions. + +! Find the probability that an observed chi-square for a correct +! model should be less that 2.3 when the number of degrees of +! freedom is 5. +! Ref: Knuth, Volume 2, 3rd ed., Page 56, and Press, Flannery, +! Teukolsky, Vetterling, Numerical Recipes, 1st ed., Page 165. + + WRITE (* ,"(///' Sample 7. Incomplete gamma and Gamma functions.'/)") + WRITE (KLOG,"(///' Sample 7. Incomplete gamma and Gamma functions.'/)") + + MAFM = TO_FM(5)/2 + MBFM = INCOMPLETE_GAMMA1(MAFM,TO_FM('2.3')/2) / GAMMA(MAFM) + +! Print the result. + + CALL FM_FORM('F61.60',MBFM,ST1) + WRITE (* ,"(' Probability = ',A)") TRIM(ST1) + WRITE (KLOG,"(' Probability = ',A)") TRIM(ST1) + +! Check the answer. + + MCFM = TO_FM('0.193733130114871446327510259182505999534723186'// & + '07121386973066283739') + IF (.NOT.(ABS(MCFM-MBFM) < 1.0D-61)) THEN + NERROR = NERROR + 1 + WRITE (* ,"(/' Error in sample case number 7.'/)") + WRITE (KLOG,"(/' Error in sample case number 7.'/)") + ENDIF + + +! Complex arithmetic. + +! Set precision to give at least 30 significant digits. + + CALL FM_SET(30) + + +! 8. Find a complex root of the equation +! f(x) = x**5 - 3x**4 + x**3 - 4x**2 + x - 6 = 0. + +! Newton's method with initial guess x = .56 + 1.06 i. +! This version is not tuned for speed. See the ZMSQRT +! routine for possible ways to increase speed. +! Horner's rule is used to evaluate the function. + +! MAZM is the previous iterate. +! MBZM is the current iterate. + + MAZM = TO_ZM('.56 + 1.06 i') + +! Print the first iteration. + + FMT = "(///' Sample 8. Complex root of f(x) = x**5 - 3x**4 + ',"// & + "'x**3 - 4x**2 + x - 6 = 0.'///" // & + "' Iteration Newton Approximation')" + WRITE (*,FMT) + WRITE (KLOG,FMT) + CALL ZM_FORM('F32.30','F32.30',MAZM,ST1) + WRITE (* ,"(/I6,4X,A)") 0,TRIM(ST1) + WRITE (KLOG,"(/I6,4X,A)") 0,TRIM(ST1) + + DO ITER = 1, 10 + +! MCZM is f(MAZM). + + MCZM = ((((MAZM-3)*MAZM+1)*MAZM-4)*MAZM+1)*MAZM-6 + +! MDZM is f'(MAZM). + + MDZM = (((5*MAZM-12)*MAZM+3)*MAZM-8)*MAZM+1 + + MBZM = MAZM - MCZM/MDZM + +! Print each iteration. + + CALL ZM_FORM('F32.30','F32.30',MBZM,ST1) + WRITE (* ,"(/I6,4X,A)") ITER,TRIM(ST1) + WRITE (KLOG,"(/I6,4X,A)") ITER,TRIM(ST1) + +! Stop iterating if MAZM and MBZM agree to over 30 places. + + IF (ABS(MAZM-MBZM) < 1.0D-31) EXIT + +! Set MAZM = MBZM for the next iteration. + + MAZM = MBZM + ENDDO + +! Check the answer. + + MCZM = TO_ZM('0.561958308335403235498111195347453 +'// & + '1.061134679604332556983391239058885 i') + IF (.NOT.(ABS(MCZM-MBZM) < 1.0D-31)) THEN + NERROR = NERROR + 1 + WRITE (* ,"(/' Error in sample case number 8.'/)") + WRITE (KLOG,"(/' Error in sample case number 8.'/)") + ENDIF + + +! 9. Compute Exp(1.23-2.34i). + +! Use the direct Taylor series. See the ZMEXP routine +! for a faster way to get Exp(x). + +! MAZM is x. +! MBZM is the current term, x**n/n!. +! MCZM is the current partial sum. + + MAZM = TO_ZM('1.23-2.34i') + MBZM = 1 + MCZM = 1 + DO K = 1, 100 + MBZM = MBZM*MAZM/K + MDZM = MCZM + MBZM + +! Test for convergence. + + IF (MDZM == MCZM) THEN + FMT = "(///' Sample 9.',8X,I5,' terms were added ',"// & + "'to get Exp(1.23-2.34i)'/)" + WRITE (* ,FMT) K + WRITE (KLOG,FMT) K + EXIT + ENDIF + MCZM = MDZM + ENDDO + +! Print the result. + + CALL ZM_FORM('F33.30','F32.30',MCZM,ST1) + WRITE (* ,"(' Result= ',A)") TRIM(ST1) + WRITE (KLOG,"(' Result= ',A)") TRIM(ST1) + +! Check the answer. + + MDZM = TO_ZM('-2.379681796854777515745457977696745 -'// & + ' 2.458032970832342652397461908326042 i') + IF (.NOT.(ABS(MDZM-MCZM) < 1.0D-31)) THEN + NERROR = NERROR + 1 + WRITE (* ,"(/' Error in sample case number 9.'/)") + WRITE (KLOG,"(/' Error in sample case number 9.'/)") + ENDIF + + +! 10. Exception handling. +! Iterate (real) Exp(x) starting at 1.0 until overflow occurs. +! +! Testing type FM numbers directly using an IF can +! be tricky. When MAFM is +overflow, the statement +! IF (MAFM == TO_FM(' +OVERFLOW ')) THEN +! will return false, since the comparison routine cannot be +! sure that two different overflowed results would have been +! equal if the overflow threshold had been higher. +! +! In this case, calling subroutine FMFLAG will tell when +! an exception has happened. +! +! However, for a complicated expression that generates several +! FM calls using the derived type numbers, note that the FM +! result flag may be zero at the end of the expression even if +! an exception occurred. For example, if EXP(A) overflows in +! X = (3 + 1/EXP(A))*2 +! then the result is 6 with a flag of zero, since the exception +! caused no loss of accuracy in the final result. A warning +! message will still appear because of the overflow. +! +! The FM warning message is written on unit KW, so in this test +! it appears on the screen and not in the log file. +! +! The final result is checked by formatting the result and finding +! that the output string is '+ OVERFLOW'. + + CALL FM_SET(60) + + MAFM = TO_FM(1) + + FMT = "(///' Sample 10. Exception handling.'//" // & + "12X,' Iterate Exp(x) starting at 1.0 until overflow occurs.'//" // & + "12X,' An FM warning message will be printed before the last iteration.'/)" + WRITE (*,FMT) + FMT = "(///' Sample 10. Exception handling.'//" // & + "12X,' Iterate Exp(x) starting at 1.0 until overflow occurs.'/)" + WRITE (KLOG,FMT) + + DO J = 1, 10 + MAFM = EXP(MAFM) + CALL FMFLAG(LFLAG) + CALL FM_FORM('1PE60.40',MAFM,ST1) + WRITE (* ,"(/' Iteration',I3,5X,A)") J,TRIM(ST1) + WRITE (KLOG,"(/' Iteration',I3,5X,A)") J,TRIM(ST1) + IF (LFLAG < 0) EXIT + ENDDO + +! Check that the last result was +overflow. + + IF (FM_FORMAT('E60.40',MAFM) == FM_FORMAT('E60.40',TO_FM('+OVERFLOW'))) THEN + WRITE (* ,"(/' Overflow was correctly detected.')") + WRITE (KLOG,"(/' Overflow was correctly detected.')") + ELSE + NERROR = NERROR + 1 + WRITE (* ,"(/' Error in sample case number 10.'/)") + WRITE (* ,"(/' Overflow was not correctly detected.')") + WRITE (KLOG ,"(/' Error in sample case number 10.'/)") + WRITE (KLOG ,"(/' Overflow was not correctly detected.')") + ENDIF + + IF (NERROR == 0) THEN + WRITE (* ,"(//A/)") ' All results were ok.' + WRITE (KLOG,"(//A/)") ' All results were ok.' + ELSE + WRITE (* ,"(//I3,A/)") NERROR,' error(s) found.' + WRITE (KLOG,"(//I3,A/)") NERROR,' error(s) found.' + ENDIF + + END PROGRAM SAMPLE diff --git a/src/fmlib/TestFM.F90 b/src/fmlib/TestFM.F90 new file mode 100644 index 0000000000000000000000000000000000000000..79dda01ab9c0838847bf591f2490f56c31eefb3f --- /dev/null +++ b/src/fmlib/TestFM.F90 @@ -0,0 +1,10944 @@ + +! David M. Smith + +! This is a test program for FMLIB 1.2, a multiple-precision +! arithmetic package. Most of the FM (floating-point real) +! and ZM (floating-point complex) routines are tested. +! Precision is set to 50 significant digits and the results +! are checked to that accuracy. +! Most of the IM (integer) routines are tested, with exact +! results required to pass the tests. +! Most of the USE FMZM derived type interface routines are +! tested in the same manner as those described above. + +! If all tests are completed successfully, this line is printed: + +! 935 cases tested. No errors were found. + + MODULE TEST_VARS + + USE FMVALS + USE FMZM + +! Declare arrays for FM variables. + + REAL (KIND(1.0D0)) :: MA(-1:LUNPCK),MB(-1:LUNPCK),MC(-1:LUNPCK), & + MD(-1:LUNPCK),ME(-1:LUNPCK),MP1(-1:LPACK), & + MP2(-1:LPACK),MP3(-1:LPACK) + REAL (KIND(1.0D0)) :: ZA(-1:LUNPKZ),ZB(-1:LUNPKZ),ZC(-1:LUNPKZ), & + ZD(-1:LUNPKZ),ZE(-1:LUNPKZ) + REAL (KIND(1.0D0)) :: MLNSV2(-1:LUNPCK),MLNSV3(-1:LUNPCK), & + MLNSV5(-1:LUNPCK),MLNSV7(-1:LUNPCK) + +! Declare derived type variables. + + TYPE (FM), SAVE :: M_A,M_B,M_C,M_D,MFM1,MFM2,MFM3,MFM4,MFM5,MFM6, & + MSMALL,MFMV1(3),MFMV2(3),MFMA(3,3),MFMB(3,3),MFMC(3,3) + TYPE (IM), SAVE :: M_J,M_K,M_L,MIM1,MIM2,MIM3,MIM4,MIM5,MIMV1(3), & + MIMV2(3),MIMA(2,2),MIMB(2,2),MIMC(2,2) + TYPE (ZM), SAVE :: M_X,M_Y,M_Z,MZM1,MZM2,MZM3,MZM4,MZM5,MZMV1(3), & + MZMV2(3),MZMA(2,3),MZMB(3,4),MZMC(2,4) + + INTEGER, SAVE :: J1,J2,J3,J4,J5 + REAL, SAVE :: R1,R2,R3,R4,R5,RSMALL + DOUBLE PRECISION, SAVE :: D1,D2,D3,D4,D5,DSMALL + COMPLEX, SAVE :: C1,C2,C3,C4,C5 + COMPLEX (KIND(0.0D0)), SAVE :: CD1,CD2,CD3,CD4 + + END MODULE TEST_VARS + + PROGRAM TEST + + USE FMVALS + USE FMZM + USE TEST_VARS + + IMPLICIT NONE + +! Character strings used for input and output. + + CHARACTER(80) :: ST1,ST2 + CHARACTER(160) :: STZ1,STZ2 + + INTEGER KLOG,KWSAVE,NCASE,NERROR + REAL TIME1,TIME2 + +! Write output to the standard FM output (unit KW, defined +! in subroutine FMSET), and also to the file TESTFM.LOG. + + KLOG = 18 + OPEN (KLOG,FILE='TESTFM.LOG') + KWSAVE = KW + KW = KLOG + +! Set precision to give at least 50 significant digits +! and initialize the FM package. +! This call also checks many of the initialization values +! used in module FMVALS (file FMSAVE.f90). Set KW = KLOG for +! this call so that any messages concerning these values will +! appear in file TESTFM.LOG. + + CALL FMSET(50) + KW = KWSAVE + + CALL TIMEIT(TIME1) + + J2 = 131 + R2 = 241.21 + D2 = 391.61D0 + C2 = ( 411.11D0 , 421.21D0 ) + CD2 = ( 431.11D0 , 441.21D0 ) + CALL FM_ST2M('581.21',MFM1) + CALL FM_ST2M('-572.42',MFM2) + CALL IM_ST2M('661',MIM1) + CALL IM_ST2M('-602',MIM2) + CALL ZM_ST2M('731.51 + 711.41 i',MZM1) + CALL ZM_ST2M('-762.12 - 792.42 i',MZM2) + +! NERROR is the number of errors found. +! NCASE is the number of cases tested. + + NERROR = 0 + +! Test input and output conversion. + + CALL TEST1(ST1,ST2,NCASE,NERROR,KLOG) + +! Test add and subtract. + + CALL TEST2(ST1,ST2,NCASE,NERROR,KLOG) + +! Test multiply, divide and square root. + + CALL TEST3(ST1,ST2,NCASE,NERROR,KLOG) + +! Test stored constants. + + CALL TEST4(NCASE,NERROR,KLOG) + +! Test exponentials. + + CALL TEST5(ST1,ST2,NCASE,NERROR,KLOG) + +! Test logarithms. + + CALL TEST6(ST1,ST2,NCASE,NERROR,KLOG) + +! Test trigonometric functions. + + CALL TEST7(ST1,ST2,NCASE,NERROR,KLOG) + +! Test inverse trigonometric functions. + + CALL TEST8(ST1,ST2,NCASE,NERROR,KLOG) + +! Test hyperbolic functions. + + CALL TEST9(ST1,ST2,NCASE,NERROR,KLOG) + +! Test integer input and output conversion. + + CALL TEST10(ST1,ST2,NCASE,NERROR,KLOG) + +! Test integer add and subtract. + + CALL TEST11(ST1,ST2,NCASE,NERROR,KLOG) + +! Test integer multiply and divide. + + CALL TEST12(ST1,ST2,NCASE,NERROR,KLOG) + +! Test conversions between FM and IM format. + + CALL TEST13(NCASE,NERROR,KLOG) + +! Test integer power and GCD functions. + + CALL TEST14(ST1,ST2,NCASE,NERROR,KLOG) + +! Test integer modular functions. + + CALL TEST15(ST1,ST2,NCASE,NERROR,KLOG) + +! Test complex input and output conversion. + + CALL TEST16(STZ1,STZ2,NCASE,NERROR,KLOG) + +! Test complex add and subtract. + + CALL TEST17(STZ1,STZ2,NCASE,NERROR,KLOG) + +! Test complex multiply, divide and square root. + + CALL TEST18(STZ1,STZ2,NCASE,NERROR,KLOG) + +! Test complex exponentials. + + CALL TEST19(STZ1,STZ2,NCASE,NERROR,KLOG) + +! Test complex logarithms. + + CALL TEST20(STZ1,STZ2,NCASE,NERROR,KLOG) + +! Test complex trigonometric functions. + + CALL TEST21(STZ1,STZ2,NCASE,NERROR,KLOG) + +! Test complex inverse trigonometric functions. + + CALL TEST22(STZ1,STZ2,NCASE,NERROR,KLOG) + +! Test complex hyperbolic functions. + + CALL TEST23(STZ1,STZ2,NCASE,NERROR,KLOG) + +! Test the derived type = interface. + + CALL TEST24(NCASE,NERROR,KLOG) + +! Test the derived type == interface. + + CALL TEST25(NCASE,NERROR,KLOG) + +! Test the derived type /= interface. + + CALL TEST26(NCASE,NERROR,KLOG) + +! Test the derived type > interface. + + CALL TEST27(NCASE,NERROR,KLOG) + +! Test the derived type >= interface. + + CALL TEST28(NCASE,NERROR,KLOG) + +! Test the derived type < interface. + + CALL TEST29(NCASE,NERROR,KLOG) + +! Test the derived type <= interface. + + CALL TEST30(NCASE,NERROR,KLOG) + +! Test the derived type + interface. + + CALL TEST31(NCASE,NERROR,KLOG) + +! Test the derived type - interface. + + CALL TEST32(NCASE,NERROR,KLOG) + +! Test the derived type * interface. + + CALL TEST33(NCASE,NERROR,KLOG) + +! Test the derived type / interface. + + CALL TEST34(NCASE,NERROR,KLOG) + +! Test the derived type ** interface. + + CALL TEST35(NCASE,NERROR,KLOG) + +! Test the derived type functions ABS, ..., CEILING interface. + + CALL TEST36(NCASE,NERROR,KLOG) + +! Test the derived type functions CMPLX, ..., EXPONENT interface. + + CALL TEST37(NCASE,NERROR,KLOG) + +! Test the derived type functions FLOOR, ..., MIN interface. + + CALL TEST38(NCASE,NERROR,KLOG) + +! Test the derived type functions MINEXPONENT, ..., RRSPACING interface. + + CALL TEST39(NCASE,NERROR,KLOG) + +! Test the derived type functions SCALE, ..., TINY interface. + + CALL TEST40(NCASE,NERROR,KLOG) + +! Test the derived type functions TO_FM, TO_IM, TO_ZM, ..., TO_DPZ interface. + + CALL TEST41(NCASE,NERROR,KLOG) + +! Test the derived type functions ADDI, ..., Z2M interface. + + CALL TEST42(NCASE,NERROR,KLOG) + +! Test Bernoulli numbers, Pochhammer's function, Euler's constant. + + CALL TEST43(NCASE,NERROR,KLOG) + +! Test Gamma, Factorial, Log(Gamma), Beta, Binomial. + + CALL TEST44(NCASE,NERROR,KLOG) + +! Test Incomplete Gamma, Incomplete Beta. + + CALL TEST45(NCASE,NERROR,KLOG) + +! Test Polygamma, Psi. + + CALL TEST46(NCASE,NERROR,KLOG) + +! Test the different rounding modes. + + CALL TEST47(NCASE,NERROR,KLOG) + +! End of tests. + + CALL TIMEIT(TIME2) + + IF (NERROR == 0) THEN + WRITE (KW, & + "(///1X,I5,' cases tested. No errors were found.'/)" & + ) NCASE + WRITE (KLOG, & + "(///1X,I5,' cases tested. No errors were found.'/)" & + ) NCASE + ELSE IF (NERROR == 1) THEN + WRITE (KW, & + "(///1X,I5,' cases tested. 1 error was found.'/)" & + ) NCASE + WRITE (KLOG, & + "(///1X,I5,' cases tested. 1 error was found.'/)" & + ) NCASE + ELSE + WRITE (KW, & + "(///1X,I5,' cases tested.',I4,' errors were found.'/)" & + ) NCASE,NERROR + WRITE (KLOG, & + "(///1X,I5,' cases tested.',I4,' errors were found.'/)" & + ) NCASE,NERROR + ENDIF + + IF (NERROR >= 1) THEN + KWSAVE = KW + KW = KLOG + +! Write some of the initialized values in common. + + CALL FMVARS + KW = KWSAVE + ENDIF + + WRITE (KW,*) ' ' + WRITE (KW,"(F10.2,A)") TIME2-TIME1,' Seconds for TestFM.' + WRITE (KW,*) ' ' + WRITE (KLOG,*) ' ' + WRITE (KLOG,"(F10.2,A)") TIME2-TIME1,' Seconds for TestFM.' + WRITE (KLOG,*) ' ' + + WRITE (KW,*)' End of run.' + + STOP + END PROGRAM TEST + + SUBROUTINE TEST1(ST1,ST2,NCASE,NERROR,KLOG) + +! Input and output testing. + + USE FMVALS + USE FMZM + USE TEST_VARS + + IMPLICIT NONE + +! Logical function for comparing FM numbers. + + LOGICAL FMCOMP + + CHARACTER(80) :: ST1,ST2 + INTEGER KLOG,NCASE,NERROR + + WRITE (KW,"(/' Testing input and output routines.')") + + NCASE = 1 + CALL FMST2M('123',MA) + CALL FMI2M(123,MC) + CALL FMSUB(MA,MC,MD) + CALL FMABS(MD,ME) + CALL FMEQ(ME,MD) + CALL FMI2M(10,MB) + CALL FMIPWR(MB,-48,ME) + CALL FMEQ(ME,MB) + +! Use the .NOT. because FMCOMP returns FALSE for special +! cases like MD = UNKNOWN, and these should be treated +! as errors for these tests. + + IF (.NOT.FMCOMP(MD,'LE',MB)) THEN + CALL ERRPRTFM('FMST2M',MA,'MA',MC,'MC',MD,'MD', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 2 + ST1 = '1.3505154639175257731958762886597938144329896907216495' + CALL FMST2M(ST1,MA) + CALL FMI2M(131,MB) + CALL FMI2M(97,MC) + CALL FMDIV(MB,MC,ME) + CALL FMEQ(ME,MC) + CALL FMSUB(MA,MC,MD) + CALL FMABS(MD,ME) + CALL FMEQ(ME,MD) + CALL FMST2M('1.0E-50',MB) + IF (.NOT.FMCOMP(MD,'LE',MB)) THEN + CALL ERRPRTFM('FMST2M',MA,'MA',MC,'MC',MD,'MD', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 3 + ST1 = '1.3505154639175257731958762886597938144329896907216495E-2' + CALL FMST2M(ST1,MA) + CALL FMI2M(131,MB) + CALL FMI2M(9700,MC) + CALL FMDIV(MB,MC,ME) + CALL FMEQ(ME,MC) + CALL FMSUB(MA,MC,MD) + CALL FMABS(MD,ME) + CALL FMEQ(ME,MD) + CALL FMST2M('1.0E-52',MB) + IF (.NOT.FMCOMP(MD,'LE',MB)) THEN + CALL ERRPRTFM('FMST2M',MA,'MA',MC,'MC',MD,'MD', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 4 + ST1 = '1.3505154639175257731958762886597938144329896907216495E-2' + CALL FMST2M(ST1,MA) + CALL FMFORM('F40.30',MA,ST2) + CALL FMST2M(ST2,MA) + ST1 = ' .013505154639175257731958762887' + CALL FMST2M(ST2,MC) + CALL FMSUB(MA,MC,MD) + CALL FMABS(MD,ME) + CALL FMEQ(ME,MD) + CALL FMST2M('0',MB) + IF ((.NOT.FMCOMP(MD,'LE',MB)) .OR. ST1 /= ST2) THEN + CALL ERRPRTFM('FMFORM',MA,'MA',MC,'MC',MD,'MD', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 5 + ST1 = '1.3505154639175257731958762886597938144329896907216495E+16' + CALL FMST2M(ST1,MA) + CALL FMFORM('F53.33',MA,ST2) + CALL FMST2M(ST2,MA) + ST1 = '13505154639175257.731958762886597938144329896907216' + CALL FMST2M(ST1,MC) + CALL FMSUB(MA,MC,MD) + CALL FMABS(MD,ME) + CALL FMEQ(ME,MD) + CALL FMST2M('0',MB) + IF (.NOT.FMCOMP(MD,'LE',MB)) THEN + CALL ERRPRTFM('FMFORM',MA,'MA',MC,'MC',MD,'MD', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 6 + ST1 = '1.3505154639175257731958762886597938144329896907216495E+16' + CALL FMST2M(ST1,MA) + CALL FMFORM('I24',MA,ST2) + CALL FMST2M(ST2,MA) + ST1 = '13505154639175258' + CALL FMST2M(ST1,MC) + CALL FMSUB(MA,MC,MD) + CALL FMABS(MD,ME) + CALL FMEQ(ME,MD) + CALL FMST2M('0',MB) + IF (.NOT.FMCOMP(MD,'LE',MB)) THEN + CALL ERRPRTFM('FMFORM',MA,'MA',MC,'MC',MD,'MD', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 7 + ST1 ='-1.3505154639175257731958762886597938144329896907216495E+16' + CALL FMST2M(ST1,MA) + CALL FMFORM('E55.49',MA,ST2) + CALL FMST2M(ST2,MA) + ST1 = '-1.350515463917525773195876288659793814432989690722D16' + CALL FMST2M(ST1,MC) + CALL FMSUB(MA,MC,MD) + CALL FMABS(MD,ME) + CALL FMEQ(ME,MD) + CALL FMST2M('0',MB) + IF (.NOT.FMCOMP(MD,'LE',MB)) THEN + CALL ERRPRTFM('FMFORM',MA,'MA',MC,'MC',MD,'MD', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 8 + ST1 ='-1.3505154639175257731958762886597938144329896907216495E+16' + CALL FMST2M(ST1,MA) + CALL FMFORM('1PE54.46',MA,ST2) + CALL FMST2M(ST2,MA) + ST1 = '-1.350515463917525773195876288659793814432989691M+16' + CALL FMST2M(ST1,MC) + CALL FMSUB(MA,MC,MD) + CALL FMABS(MD,ME) + CALL FMEQ(ME,MD) + CALL FMST2M('0',MB) + IF (.NOT.FMCOMP(MD,'LE',MB)) THEN + CALL ERRPRTFM('FMFORM',MA,'MA',MC,'MC',MD,'MD', & + NCASE,NERROR,KLOG) + ENDIF + + RETURN + END SUBROUTINE TEST1 + + SUBROUTINE TEST2(ST1,ST2,NCASE,NERROR,KLOG) + +! Test add and subtract. + + USE FMVALS + USE FMZM + USE TEST_VARS + + IMPLICIT NONE + + LOGICAL FMCOMP + + CHARACTER(80) :: ST1,ST2 + INTEGER KLOG,NCASE,NERROR + + WRITE (KW,"(/' Testing add and subtract routines.')") + + NCASE = 9 + CALL FMST2M('123',MA) + CALL FMST2M('789',MB) + CALL FMADD(MA,MB,ME) + CALL FMEQ(ME,MA) + CALL FMI2M(912,MC) + CALL FMSUB(MA,MC,MD) + CALL FMABS(MD,ME) + CALL FMEQ(ME,MD) + CALL FMST2M('0',MB) + IF (.NOT.FMCOMP(MD,'LE',MB)) THEN + CALL ERRPRTFM('FMADD ',MA,'MA',MC,'MC',MD,'MD', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 10 + ST1 = '0.3505154639175257731958762886597938144329896907216495' + CALL FMST2M(ST1,MA) + ST1 = '0.7319587628865979381443298969072164948453608247422680' + CALL FMST2M(ST1,MB) + CALL FMADD(MA,MB,ME) + CALL FMEQ(ME,MA) + ST2 = '1.0824742268041237113402061855670103092783505154639175' + CALL FMST2M(ST2,MC) + CALL FMSUB(MA,MC,MD) + CALL FMABS(MD,ME) + CALL FMEQ(ME,MD) + CALL FMST2M('1.0E-50',MB) + IF (.NOT.FMCOMP(MD,'LE',MB)) THEN + CALL ERRPRTFM('FMADD ',MA,'MA',MC,'MC',MD,'MD', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 11 + ST1 = '0.3505154639175257731958762886597938144329896907216495' + CALL FMST2M(ST1,MA) + ST1 = '0.7319587628865979381443298969072164948453608247422680' + CALL FMST2M(ST1,MB) + CALL FMSUB(MA,MB,ME) + CALL FMEQ(ME,MA) + ST2 = '-.3814432989690721649484536082474226804123711340206185' + CALL FMST2M(ST2,MC) + CALL FMSUB(MA,MC,MD) + CALL FMABS(MD,ME) + CALL FMEQ(ME,MD) + CALL FMST2M('1.0E-50',MB) + IF (.NOT.FMCOMP(MD,'LE',MB)) THEN + CALL ERRPRTFM('FMSUB ',MA,'MA',MC,'MC',MD,'MD', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 12 + ST1 = '0.3505154639175257731958762886597938144329896907216495' + CALL FMST2M(ST1,MA) + ST1 = '0.3505154639175257731443298969072164948453608247422680' + CALL FMST2M(ST1,MB) + CALL FMSUB(MA,MB,ME) + CALL FMEQ(ME,MA) + ST2 = '5.15463917525773195876288659793815M-20' + CALL FMST2M(ST2,MC) + CALL FMSUB(MA,MC,MD) + CALL FMABS(MD,ME) + CALL FMEQ(ME,MD) + CALL FMST2M('1.0E-50',MB) + IF (.NOT.FMCOMP(MD,'LE',MB)) THEN + CALL ERRPRTFM('FMSUB ',MA,'MA',MC,'MC',MD,'MD', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 13 + ST1 = '0.3505154639175257731958762886597938144329896907216495' + CALL FMST2M(ST1,MA) + CALL FMADDI(MA,1) + ST2 = '1.3505154639175257731958762886597938144329896907216495' + CALL FMST2M(ST2,MC) + CALL FMSUB(MA,MC,MD) + CALL FMABS(MD,ME) + CALL FMEQ(ME,MD) + CALL FMST2M('1.0E-50',MB) + IF (.NOT.FMCOMP(MD,'LE',MB)) THEN + CALL ERRPRTFM('FMADDI',MA,'MA',MC,'MC',MD,'MD', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 14 + ST1 = '4.3505154639175257731958762886597938144329896907216495' + CALL FMST2M(ST1,MA) + CALL FMADDI(MA,5) + ST2 = '9.3505154639175257731958762886597938144329896907216495' + CALL FMST2M(ST2,MC) + CALL FMSUB(MA,MC,MD) + CALL FMABS(MD,ME) + CALL FMEQ(ME,MD) + CALL FMST2M('1.0E-50',MB) + IF (.NOT.FMCOMP(MD,'LE',MB)) THEN + CALL ERRPRTFM('FMADDI',MA,'MA',MC,'MC',MD,'MD', & + NCASE,NERROR,KLOG) + ENDIF + + RETURN + END SUBROUTINE TEST2 + + SUBROUTINE TEST3(ST1,ST2,NCASE,NERROR,KLOG) + +! Test multiply, divide and square root. + + USE FMVALS + USE FMZM + USE TEST_VARS + + IMPLICIT NONE + + LOGICAL FMCOMP + + CHARACTER(80) :: ST1,ST2 + INTEGER KLOG,NCASE,NERROR + + WRITE (KW,"(/' Testing multiply, divide and square root routines.')") + + NCASE = 15 + CALL FMST2M('123',MA) + CALL FMST2M('789',MB) + CALL FMMPY(MA,MB,ME) + CALL FMEQ(ME,MA) + CALL FMI2M(97047,MC) + CALL FMSUB(MA,MC,MD) + CALL FMABS(MD,ME) + CALL FMEQ(ME,MD) + CALL FMST2M('0',MB) + IF (.NOT.FMCOMP(MD,'LE',MB)) THEN + CALL ERRPRTFM('FMMPY ',MA,'MA',MC,'MC',MD,'MD', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 16 + ST1 = '0.3505154639175257731958762886597938144329896907216495' + CALL FMST2M(ST1,MA) + ST1 = '0.7319587628865979381443298969072164948453608247422680' + CALL FMST2M(ST1,MB) + CALL FMMPY(MA,MB,ME) + CALL FMEQ(ME,MA) + ST2 = '0.2565628653416941226485280051014985652035285365075991' + CALL FMST2M(ST2,MC) + CALL FMSUB(MA,MC,MD) + CALL FMABS(MD,ME) + CALL FMEQ(ME,MD) + CALL FMST2M('1.0E-50',MB) + IF (.NOT.FMCOMP(MD,'LE',MB)) THEN + CALL ERRPRTFM('FMMPY ',MA,'MA',MC,'MC',MD,'MD', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 17 + ST1 = '0.3505154639175257731958762886597938144329896907216495' + CALL FMST2M(ST1,MA) + ST1 = '0.7319587628865979381443298969072164948453608247422680' + CALL FMST2M(ST1,MB) + CALL FMDIV(MA,MB,ME) + CALL FMEQ(ME,MA) + ST2 = '0.4788732394366197183098591549295774647887323943661972' + CALL FMST2M(ST2,MC) + CALL FMSUB(MA,MC,MD) + CALL FMABS(MD,ME) + CALL FMEQ(ME,MD) + CALL FMST2M('1.0E-50',MB) + IF (.NOT.FMCOMP(MD,'LE',MB)) THEN + CALL ERRPRTFM('FMDIV ',MA,'MA',MC,'MC',MD,'MD', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 18 + ST1 = '0.7319587628865979381443298969072164948453608247422680' + CALL FMST2M(ST1,MA) + CALL FMMPYI(MA,14,ME) + CALL FMEQ(ME,MA) + ST2 = '10.2474226804123711340206185567010309278350515463917526' + CALL FMST2M(ST2,MC) + CALL FMSUB(MA,MC,MD) + CALL FMABS(MD,ME) + CALL FMEQ(ME,MD) + CALL FMST2M('1.0E-50',MB) + IF (.NOT.FMCOMP(MD,'LE',MB)) THEN + CALL ERRPRTFM('FMMPYI',MA,'MA',MC,'MC',MD,'MD', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 19 + ST1 = '0.7319587628865979381443298969072164948453608247422680' + CALL FMST2M(ST1,MA) + CALL FMDIVI(MA,24,ME) + CALL FMEQ(ME,MA) + ST2 = '0.0304982817869415807560137457044673539518900343642612' + CALL FMST2M(ST2,MC) + CALL FMSUB(MA,MC,MD) + CALL FMABS(MD,ME) + CALL FMEQ(ME,MD) + CALL FMST2M('1.0E-50',MB) + IF (.NOT.FMCOMP(MD,'LE',MB)) THEN + CALL ERRPRTFM('FMDIVI',MA,'MA',MC,'MC',MD,'MD', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 20 + ST1 = '-0.3505154639175257731958762886597938144329896907216495' + CALL FMST2M(ST1,MA) + CALL FMSQR(MA,ME) + CALL FMEQ(ME,MA) + ST2 = '0.1228610904453183122542246784993091720692953555106813' + CALL FMST2M(ST2,MC) + CALL FMSUB(MA,MC,MD) + CALL FMABS(MD,ME) + CALL FMEQ(ME,MD) + CALL FMST2M('1.0E-50',MB) + IF (.NOT.FMCOMP(MD,'LE',MB)) THEN + CALL ERRPRTFM('FMSQR ',MA,'MA',MC,'MC',MD,'MD', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 21 + ST1 = '0.3505154639175257731958762886597938144329896907216495' + CALL FMST2M(ST1,MA) + CALL FMSQRT(MA,ME) + CALL FMEQ(ME,MA) + ST2 = '0.5920434645509785316136003710368759268547372945659987' + CALL FMST2M(ST2,MC) + CALL FMSUB(MA,MC,MD) + CALL FMABS(MD,ME) + CALL FMEQ(ME,MD) + CALL FMST2M('1.0E-50',MB) + IF (.NOT.FMCOMP(MD,'LE',MB)) THEN + CALL ERRPRTFM('FMSQRT',MA,'MA',MC,'MC',MD,'MD', & + NCASE,NERROR,KLOG) + ENDIF + + RETURN + END SUBROUTINE TEST3 + + SUBROUTINE TEST4(NCASE,NERROR,KLOG) + +! Test stored constants. + + USE FMVALS + USE FMZM + USE TEST_VARS + + IMPLICIT NONE + + LOGICAL FMCOMP + + REAL (KIND(1.0D0)) :: MBSAVE + INTEGER J,JEXP,KLOG,NCASE,NDGSAV,NERROR + + WRITE (KW,"(/' Testing stored constants.'//' Check e.'/)") + +! Switch to base 10 and check the stored digits. + + IF (NDIGMX < 55) THEN + WRITE (KLOG,*) ' ' + WRITE (KLOG,*) & + ' To test these constants at their stored precision requires' + WRITE (KLOG,*) & + ' setting NDIG=55 (number of digits). The current maximum' + WRITE (KLOG,*) ' for NDIG is NDIGMX = ',NDIGMX + WRITE (KLOG,*) ' Skip the tests for stored constants.' + RETURN + ENDIF + + MBSAVE = MBASE + NDGSAV = NDIG + NCASE = 22 + CALL FMSETVAR(' MBASE = 1000 ') + CALL FMSETVAR(' NDIG = 55 ') + CALL FMCONS + CALL FMI2M(1,MB) + CALL FMEXP(MB,MC) + DO J = 49, 51 + NDIG = J + NDIGE = 0 + CALL FMI2M(1,MB) + CALL FMEXP(MB,MA) + CALL FMSUB(MA,MC,MD) + CALL FMABS(MD,ME) + CALL FMEQ(ME,MD) + CALL FMI2M(1000,MB) + JEXP = -J + 1 + CALL FMIPWR(MB,JEXP,ME) + CALL FMEQ(ME,MB) + IF (.NOT.FMCOMP(MD,'LE',MB)) THEN + CALL ERRPRTFM(' e ',MA,'MA',MC,'MC',MD,'MD', & + NCASE,NERROR,KLOG) + EXIT + ENDIF + ENDDO + + NCASE = 23 + CALL FMSETVAR(' MBASE = 1000 ') + CALL FMSETVAR(' NDIG = 55 ') + CALL FMI2M(2,MB) + CALL FMLN(MB,MC) + CALL FMEQ(MLN1,MLNSV2) + CALL FMEQ(MLN2,MLNSV3) + CALL FMEQ(MLN3,MLNSV5) + CALL FMEQ(MLN4,MLNSV7) + WRITE (KW,"(' Check ln(2).'/)") + DO J = 49, 51 + NDIG = J + NDIGLI = 0 + CALL FMI2M(2,MB) + CALL FMLN(MB,MA) + CALL FMSUB(MA,MC,MD) + CALL FMABS(MD,ME) + CALL FMEQ(ME,MD) + CALL FMI2M(1000,MB) + JEXP = -J + CALL FMIPWR(MB,JEXP,ME) + CALL FMEQ(ME,MB) + IF (.NOT.FMCOMP(MD,'LE',MB)) THEN + CALL ERRPRTFM(' ln(2)',MA,'MA',MC,'MC',MD,'MD', & + NCASE,NERROR,KLOG) + EXIT + ENDIF + ENDDO + + NCASE = 24 + CALL FMSETVAR(' MBASE = 1000 ') + CALL FMSETVAR(' NDIG = 55 ') + WRITE (KW,"(' Check ln(3).'/)") + CALL FMEQ(MLNSV3,MC) + DO J = 49, 51 + NDIG = J + NDIGLI = 0 + CALL FMI2M(3,MB) + CALL FMLN(MB,MA) + CALL FMSUB(MA,MC,MD) + CALL FMABS(MD,ME) + CALL FMEQ(ME,MD) + CALL FMI2M(1000,MB) + JEXP = -J + 1 + CALL FMIPWR(MB,JEXP,ME) + CALL FMEQ(ME,MB) + IF (.NOT.FMCOMP(MD,'LE',MB)) THEN + CALL ERRPRTFM(' ln(3)',MA,'MA',MC,'MC',MD,'MD', & + NCASE,NERROR,KLOG) + EXIT + ENDIF + ENDDO + + NCASE = 25 + CALL FMSETVAR(' MBASE = 1000 ') + CALL FMSETVAR(' NDIG = 55 ') + WRITE (KW,"(' Check ln(5).'/)") + CALL FMEQ(MLNSV5,MC) + DO J = 49, 51 + NDIG = J + NDIGLI = 0 + CALL FMI2M(5,MB) + CALL FMLN(MB,MA) + CALL FMSUB(MA,MC,MD) + CALL FMABS(MD,ME) + CALL FMEQ(ME,MD) + CALL FMI2M(1000,MB) + JEXP = -J + 1 + CALL FMIPWR(MB,JEXP,ME) + CALL FMEQ(ME,MB) + IF (.NOT.FMCOMP(MD,'LE',MB)) THEN + CALL ERRPRTFM(' ln(5)',MA,'MA',MC,'MC',MD,'MD', & + NCASE,NERROR,KLOG) + EXIT + ENDIF + ENDDO + + NCASE = 26 + CALL FMSETVAR(' MBASE = 1000 ') + CALL FMSETVAR(' NDIG = 55 ') + WRITE (KW,"(' Check ln(7).'/)") + CALL FMEQ(MLNSV7,MC) + DO J = 49, 51 + NDIG = J + NDIGLI = 0 + CALL FMI2M(7,MB) + CALL FMLN(MB,MA) + CALL FMSUB(MA,MC,MD) + CALL FMABS(MD,ME) + CALL FMEQ(ME,MD) + CALL FMI2M(1000,MB) + JEXP = -J + 1 + CALL FMIPWR(MB,JEXP,ME) + CALL FMEQ(ME,MB) + IF (.NOT.FMCOMP(MD,'LE',MB)) THEN + CALL ERRPRTFM(' ln(7)',MA,'MA',MC,'MC',MD,'MD', & + NCASE,NERROR,KLOG) + EXIT + ENDIF + ENDDO + + NCASE = 27 + CALL FMSETVAR(' MBASE = 1000 ') + CALL FMSETVAR(' NDIG = 55 ') + WRITE (KW,"(' Check pi.')") + CALL FMPI(MC) + DO J = 49, 51 + NDIG = J + NDIGPI = 0 + CALL FMPI(MA) + CALL FMSUB(MA,MC,MD) + CALL FMABS(MD,ME) + CALL FMEQ(ME,MD) + CALL FMI2M(1000,MB) + JEXP = -J + 1 + CALL FMIPWR(MB,JEXP,ME) + CALL FMEQ(ME,MB) + IF (.NOT.FMCOMP(MD,'LE',MB)) THEN + CALL ERRPRTFM(' pi ',MA,'MA',MC,'MC',MD,'MD', & + NCASE,NERROR,KLOG) + EXIT + ENDIF + ENDDO + +! Restore base and precision. + + MBASE = MBSAVE + NDIG = NDGSAV + CALL FMCONS + RETURN + END SUBROUTINE TEST4 + + SUBROUTINE TEST5(ST1,ST2,NCASE,NERROR,KLOG) + +! Test exponentials. + + USE FMVALS + USE FMZM + USE TEST_VARS + + IMPLICIT NONE + + LOGICAL FMCOMP + + CHARACTER(80) :: ST1,ST2 + INTEGER KLOG,NCASE,NERROR + + WRITE (KW,"(/' Testing exponential routines.')") + + NCASE = 28 + ST1 = '-0.3505154639175257731958762886597938144329896907216495' + CALL FMST2M(ST1,MA) + CALL FMEXP(MA,ME) + CALL FMEQ(ME,MA) + ST2 = '0.7043249420381570899426746185150096342459216636010743' + CALL FMST2M(ST2,MC) + CALL FMSUB(MA,MC,MD) + CALL FMABS(MD,ME) + CALL FMEQ(ME,MD) + CALL FMST2M('1.0E-50',MB) + IF (.NOT.FMCOMP(MD,'LE',MB)) THEN + CALL ERRPRTFM('FMEXP ',MA,'MA',MC,'MC',MD,'MD', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 29 + ST1 = '5.3505154639175257731958762886597938144329896907216495' + CALL FMST2M(ST1,MA) + CALL FMEXP(MA,ME) + CALL FMEQ(ME,MA) + ST2 = '210.7168868293979289717186453717687341395104929999527672' + CALL FMST2M(ST2,MC) + CALL FMSUB(MA,MC,MD) + CALL FMABS(MD,ME) + CALL FMEQ(ME,MD) + CALL FMST2M('1.0E-48',MB) + IF (.NOT.FMCOMP(MD,'LE',MB)) THEN + CALL ERRPRTFM('FMEXP ',MA,'MA',MC,'MC',MD,'MD', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 30 + ST1 = '0.3505154639175257731958762886597938144329896907216495' + CALL FMST2M(ST1,MA) + CALL FMIPWR(MA,13,ME) + CALL FMEQ(ME,MA) + ST2 = '1.205572620050170403854527299272882946980306577287581E-6' + CALL FMST2M(ST2,MC) + CALL FMSUB(MA,MC,MD) + CALL FMABS(MD,ME) + CALL FMEQ(ME,MD) + CALL FMST2M('1.0E-56',MB) + IF (.NOT.FMCOMP(MD,'LE',MB)) THEN + CALL ERRPRTFM('FMIPWR',MA,'MA',MC,'MC',MD,'MD', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 31 + ST1 = '0.7319587628865979381443298969072164948453608247422680' + CALL FMST2M(ST1,MA) + CALL FMIPWR(MA,-1234,ME) + CALL FMEQ(ME,MA) + ST2 = '1.673084074011006302103793189789209370839697748745938E167' + CALL FMST2M(ST2,MC) + CALL FMSUB(MA,MC,MD) + CALL FMABS(MD,ME) + CALL FMEQ(ME,MD) + CALL FMST2M('1.0E+120',MB) + IF (.NOT.FMCOMP(MD,'LE',MB)) THEN + CALL ERRPRTFM('FMIPWR',MA,'MA',MC,'MC',MD,'MD', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 32 + ST1 = '0.3505154639175257731958762886597938144329896907216495' + CALL FMST2M(ST1,MA) + ST1 = '0.7319587628865979381443298969072164948453608247422680' + CALL FMST2M(ST1,MB) + CALL FMPWR(MA,MB,ME) + CALL FMEQ(ME,MA) + ST2 = '0.4642420045002127676457665673753493595170650613692580' + CALL FMST2M(ST2,MC) + CALL FMSUB(MA,MC,MD) + CALL FMABS(MD,ME) + CALL FMEQ(ME,MD) + CALL FMST2M('1.0E-50',MB) + IF (.NOT.FMCOMP(MD,'LE',MB)) THEN + CALL ERRPRTFM('FMPWR ',MA,'MA',MC,'MC',MD,'MD', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 33 + ST1 = '0.3505154639175257731958762886597938144329896907216495' + CALL FMST2M(ST1,MA) + ST1 = '-34.7319587628865979381443298969072164948453608247422680' + CALL FMST2M(ST1,MB) + CALL FMPWR(MA,MB,ME) + CALL FMEQ(ME,MA) + ST2 = '6.504461581246879800523526109766882955934341922848773E15' + CALL FMST2M(ST2,MC) + CALL FMSUB(MA,MC,MD) + CALL FMABS(MD,ME) + CALL FMEQ(ME,MD) + CALL FMST2M('1.0E-34',MB) + IF (.NOT.FMCOMP(MD,'LE',MB)) THEN + CALL ERRPRTFM('FMPWR ',MA,'MA',MC,'MC',MD,'MD', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 34 + ST1 = '0.3505154639175257731958762886597938144329896907216495' + CALL FMST2M(ST1,MA) + CALL FMRPWR(MA,1,3,ME) + CALL FMEQ(ME,MA) + ST2 = '0.7050756680967220302067310420367584779561732592049823' + CALL FMST2M(ST2,MC) + CALL FMSUB(MA,MC,MD) + CALL FMABS(MD,ME) + CALL FMEQ(ME,MD) + CALL FMST2M('1.0E-50',MB) + IF (.NOT.FMCOMP(MD,'LE',MB)) THEN + CALL ERRPRTFM('FMRPWR',MA,'MA',MC,'MC',MD,'MD', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 35 + ST1 = '0.7319587628865979381443298969072164948453608247422680' + CALL FMST2M(ST1,MA) + CALL FMRPWR(MA,-17,5,ME) + CALL FMEQ(ME,MA) + ST2 = '2.8889864895853344043562747681699203201333872009477318' + CALL FMST2M(ST2,MC) + CALL FMSUB(MA,MC,MD) + CALL FMABS(MD,ME) + CALL FMEQ(ME,MD) + CALL FMST2M('1.0E-50',MB) + IF (.NOT.FMCOMP(MD,'LE',MB)) THEN + CALL ERRPRTFM('FMRPWR',MA,'MA',MC,'MC',MD,'MD', & + NCASE,NERROR,KLOG) + ENDIF + + RETURN + END SUBROUTINE TEST5 + + SUBROUTINE TEST6(ST1,ST2,NCASE,NERROR,KLOG) + +! Test logarithms. + + USE FMVALS + USE FMZM + USE TEST_VARS + + IMPLICIT NONE + + LOGICAL FMCOMP + + CHARACTER(80) :: ST1,ST2 + INTEGER KLOG,NCASE,NERROR + + WRITE (KW,"(/' Testing logarithm routines.')") + + NCASE = 36 + ST1 = '0.3505154639175257731958762886597938144329896907216495' + CALL FMST2M(ST1,MA) + CALL FMLN(MA,ME) + CALL FMEQ(ME,MA) + ST2 = '-1.0483504538872214324499548823726586101452117557127813' + CALL FMST2M(ST2,MC) + CALL FMSUB(MA,MC,MD) + CALL FMABS(MD,ME) + CALL FMEQ(ME,MD) + CALL FMST2M('1.0E-49',MB) + IF (.NOT.FMCOMP(MD,'LE',MB)) THEN + CALL ERRPRTFM('FMLN ',MA,'MA',MC,'MC',MD,'MD', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 37 + ST1 = '0.3505154639175257731958762886597938144329896907216495E123' + CALL FMST2M(ST1,MA) + CALL FMLN(MA,ME) + CALL FMEQ(ME,MA) + ST2 = '282.1696159843803977017629940438041389247902713456262947' + CALL FMST2M(ST2,MC) + CALL FMSUB(MA,MC,MD) + CALL FMABS(MD,ME) + CALL FMEQ(ME,MD) + CALL FMST2M('1.0E-47',MB) + IF (.NOT.FMCOMP(MD,'LE',MB)) THEN + CALL ERRPRTFM('FMLN ',MA,'MA',MC,'MC',MD,'MD', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 38 + ST1 = '0.3505154639175257731958762886597938144329896907216495' + CALL FMST2M(ST1,MA) + CALL FMLG10(MA,ME) + CALL FMEQ(ME,MA) + ST2 = '-0.4552928172239897280304530226127473926500843247517120' + CALL FMST2M(ST2,MC) + CALL FMSUB(MA,MC,MD) + CALL FMABS(MD,ME) + CALL FMEQ(ME,MD) + CALL FMST2M('1.0E-49',MB) + IF (.NOT.FMCOMP(MD,'LE',MB)) THEN + CALL ERRPRTFM('FMLG10',MA,'MA',MC,'MC',MD,'MD', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 39 + CALL FMLNI(210,MA) + ST2 = '5.3471075307174686805185894350500696418856767760333836' + CALL FMST2M(ST2,MC) + CALL FMSUB(MA,MC,MD) + CALL FMABS(MD,ME) + CALL FMEQ(ME,MD) + CALL FMST2M('1.0E-49',MB) + IF (.NOT.FMCOMP(MD,'LE',MB)) THEN + CALL ERRPRTFM('FMIPWR',MA,'MA',MC,'MC',MD,'MD', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 40 + CALL FMLNI(211,MA) + ST2 = '5.3518581334760664957419562654542801180411581735816684' + CALL FMST2M(ST2,MC) + CALL FMSUB(MA,MC,MD) + CALL FMABS(MD,ME) + CALL FMEQ(ME,MD) + CALL FMST2M('1.0E-49',MB) + IF (.NOT.FMCOMP(MD,'LE',MB)) THEN + CALL ERRPRTFM('FMPWR ',MA,'MA',MC,'MC',MD,'MD', & + NCASE,NERROR,KLOG) + ENDIF + + RETURN + END SUBROUTINE TEST6 + + SUBROUTINE TEST7(ST1,ST2,NCASE,NERROR,KLOG) + +! Test trigonometric functions. + + USE FMVALS + USE FMZM + USE TEST_VARS + + IMPLICIT NONE + + LOGICAL FMCOMP + + CHARACTER(80) :: ST1,ST2 + INTEGER KLOG,NCASE,NERROR + + WRITE (KW,"(/' Testing trigonometric routines.')") + + NCASE = 41 + ST1 = '0.3505154639175257731958762886597938144329896907216495' + CALL FMST2M(ST1,MA) + CALL FMCOS(MA,ME) + CALL FMEQ(ME,MA) + ST2 = '0.9391958366109693586000906984500978377093121163061328' + CALL FMST2M(ST2,MC) + CALL FMSUB(MA,MC,MD) + CALL FMABS(MD,ME) + CALL FMEQ(ME,MD) + CALL FMST2M('1.0E-50',MB) + IF (.NOT.FMCOMP(MD,'LE',MB)) THEN + CALL ERRPRTFM('FMCOS ',MA,'MA',MC,'MC',MD,'MD', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 42 + ST1 = '-43.3505154639175257731958762886597938144329896907216495' + CALL FMST2M(ST1,MA) + CALL FMCOS(MA,ME) + CALL FMEQ(ME,MA) + ST2 = '0.8069765551968063243992244125871029909816207609700968' + CALL FMST2M(ST2,MC) + CALL FMSUB(MA,MC,MD) + CALL FMABS(MD,ME) + CALL FMEQ(ME,MD) + CALL FMST2M('1.0E-50',MB) + IF (.NOT.FMCOMP(MD,'LE',MB)) THEN + CALL ERRPRTFM('FMCOS ',MA,'MA',MC,'MC',MD,'MD', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 43 + ST1 = '-0.3505154639175257731958762886597938144329896907216495' + CALL FMST2M(ST1,MA) + CALL FMSIN(MA,ME) + CALL FMEQ(ME,MA) + ST2 = '-0.3433819746180939949443652360333010581867042625893927' + CALL FMST2M(ST2,MC) + CALL FMSUB(MA,MC,MD) + CALL FMABS(MD,ME) + CALL FMEQ(ME,MD) + CALL FMST2M('1.0E-50',MB) + IF (.NOT.FMCOMP(MD,'LE',MB)) THEN + CALL ERRPRTFM('FMSIN ',MA,'MA',MC,'MC',MD,'MD', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 44 + ST1 = '43.3505154639175257731958762886597938144329896907216495' + CALL FMST2M(ST1,MA) + CALL FMSIN(MA,ME) + CALL FMEQ(ME,MA) + ST2 = '-0.5905834736620182429243173169772978155668602154136946' + CALL FMST2M(ST2,MC) + CALL FMSUB(MA,MC,MD) + CALL FMABS(MD,ME) + CALL FMEQ(ME,MD) + CALL FMST2M('1.0E-50',MB) + IF (.NOT.FMCOMP(MD,'LE',MB)) THEN + CALL ERRPRTFM('FMSIN ',MA,'MA',MC,'MC',MD,'MD', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 45 + ST1 = '0.3505154639175257731958762886597938144329896907216495' + CALL FMST2M(ST1,MA) + CALL FMTAN(MA,ME) + CALL FMEQ(ME,MA) + ST2 = '0.3656127521360899712035823015565426347554405301360773' + CALL FMST2M(ST2,MC) + CALL FMSUB(MA,MC,MD) + CALL FMABS(MD,ME) + CALL FMEQ(ME,MD) + CALL FMST2M('1.0E-50',MB) + IF (.NOT.FMCOMP(MD,'LE',MB)) THEN + CALL ERRPRTFM('FMTAN ',MA,'MA',MC,'MC',MD,'MD', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 46 + ST1 = '43.3505154639175257731958762886597938144329896907216495' + CALL FMST2M(ST1,MA) + CALL FMTAN(MA,ME) + CALL FMEQ(ME,MA) + ST2 = '-0.7318471272291003544610122296764031536071117330470298' + CALL FMST2M(ST2,MC) + CALL FMSUB(MA,MC,MD) + CALL FMABS(MD,ME) + CALL FMEQ(ME,MD) + CALL FMST2M('1.0E-50',MB) + IF (.NOT.FMCOMP(MD,'LE',MB)) THEN + CALL ERRPRTFM('FMTAN ',MA,'MA',MC,'MC',MD,'MD', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 47 + ST1 = '0.3505154639175257731958762886597938144329896907216495' + CALL FMST2M(ST1,MA) + CALL FMCSSN(MA,ME,MC) + CALL FMEQ(ME,MA) + ST2 = '0.9391958366109693586000906984500978377093121163061328' + CALL FMST2M(ST2,MC) + CALL FMSUB(MA,MC,MD) + CALL FMABS(MD,ME) + CALL FMEQ(ME,MD) + CALL FMST2M('1.0E-50',MB) + IF (.NOT.FMCOMP(MD,'LE',MB)) THEN + CALL ERRPRTFM('FMCSSN',MA,'MA',MC,'MC',MD,'MD', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 48 + ST1 = '-43.3505154639175257731958762886597938144329896907216495' + CALL FMST2M(ST1,MA) + CALL FMCSSN(MA,ME,MC) + CALL FMEQ(ME,MA) + ST2 = '0.8069765551968063243992244125871029909816207609700968' + CALL FMST2M(ST2,MC) + CALL FMSUB(MA,MC,MD) + CALL FMABS(MD,ME) + CALL FMEQ(ME,MD) + CALL FMST2M('1.0E-50',MB) + IF (.NOT.FMCOMP(MD,'LE',MB)) THEN + CALL ERRPRTFM('FMCSSN',MA,'MA',MC,'MC',MD,'MD', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 49 + ST1 = '-0.3505154639175257731958762886597938144329896907216495' + CALL FMST2M(ST1,MA) + CALL FMCSSN(MA,MC,ME) + CALL FMEQ(ME,MA) + ST2 = '-0.3433819746180939949443652360333010581867042625893927' + CALL FMST2M(ST2,MC) + CALL FMSUB(MA,MC,MD) + CALL FMABS(MD,ME) + CALL FMEQ(ME,MD) + CALL FMST2M('1.0E-50',MB) + IF (.NOT.FMCOMP(MD,'LE',MB)) THEN + CALL ERRPRTFM('FMCSSN',MA,'MA',MC,'MC',MD,'MD', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 50 + ST1 = '43.3505154639175257731958762886597938144329896907216495' + CALL FMST2M(ST1,MA) + CALL FMCSSN(MA,MC,ME) + CALL FMEQ(ME,MA) + ST2 = '-0.5905834736620182429243173169772978155668602154136946' + CALL FMST2M(ST2,MC) + CALL FMSUB(MA,MC,MD) + CALL FMABS(MD,ME) + CALL FMEQ(ME,MD) + CALL FMST2M('1.0E-50',MB) + IF (.NOT.FMCOMP(MD,'LE',MB)) THEN + CALL ERRPRTFM('FMCSSN',MA,'MA',MC,'MC',MD,'MD', & + NCASE,NERROR,KLOG) + ENDIF + + RETURN + END SUBROUTINE TEST7 + + SUBROUTINE TEST8(ST1,ST2,NCASE,NERROR,KLOG) + +! Test inverse trigonometric functions. + + USE FMVALS + USE FMZM + USE TEST_VARS + + IMPLICIT NONE + + LOGICAL FMCOMP + + CHARACTER(80) :: ST1,ST2 + INTEGER KLOG,NCASE,NERROR + + WRITE (KW,"(/' Testing inverse trigonometric routines.')") + + NCASE = 51 + ST1 = '0.3505154639175257731958762886597938144329896907216495' + CALL FMST2M(ST1,MA) + CALL FMACOS(MA,ME) + CALL FMEQ(ME,MA) + ST2 = '1.2126748979730954046873545995574544481988102502510807' + CALL FMST2M(ST2,MC) + CALL FMSUB(MA,MC,MD) + CALL FMABS(MD,ME) + CALL FMEQ(ME,MD) + CALL FMST2M('1.0E-50',MB) + IF (.NOT.FMCOMP(MD,'LE',MB)) THEN + CALL ERRPRTFM('FMACOS',MA,'MA',MC,'MC',MD,'MD', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 52 + ST1 = '-0.3505154639175257731958762886597938144329896907216495' + CALL FMST2M(ST1,MA) + CALL FMACOS(MA,ME) + CALL FMEQ(ME,MA) + ST2 = '1.9289177556166978337752887837220484359983591491240252' + CALL FMST2M(ST2,MC) + CALL FMSUB(MA,MC,MD) + CALL FMABS(MD,ME) + CALL FMEQ(ME,MD) + CALL FMST2M('1.0E-50',MB) + IF (.NOT.FMCOMP(MD,'LE',MB)) THEN + CALL ERRPRTFM('FMACOS',MA,'MA',MC,'MC',MD,'MD', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 53 + ST1 = '0.3505154639175257731958762886597938144329896907216495' + CALL FMST2M(ST1,MA) + CALL FMASIN(MA,ME) + CALL FMEQ(ME,MA) + ST2 = '0.3581214288218012145439670920822969938997744494364723' + CALL FMST2M(ST2,MC) + CALL FMSUB(MA,MC,MD) + CALL FMABS(MD,ME) + CALL FMEQ(ME,MD) + CALL FMST2M('1.0E-50',MB) + IF (.NOT.FMCOMP(MD,'LE',MB)) THEN + CALL ERRPRTFM('FMASIN',MA,'MA',MC,'MC',MD,'MD', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 54 + ST1 = '-0.3505154639175257731958762886597938144329896907216495' + CALL FMST2M(ST1,MA) + CALL FMASIN(MA,ME) + CALL FMEQ(ME,MA) + ST2 = '-0.3581214288218012145439670920822969938997744494364723' + CALL FMST2M(ST2,MC) + CALL FMSUB(MA,MC,MD) + CALL FMABS(MD,ME) + CALL FMEQ(ME,MD) + CALL FMST2M('1.0E-50',MB) + IF (.NOT.FMCOMP(MD,'LE',MB)) THEN + CALL ERRPRTFM('FMASIN',MA,'MA',MC,'MC',MD,'MD', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 55 + ST1 = '0.3505154639175257731958762886597938144329896907216495' + CALL FMST2M(ST1,MA) + CALL FMATAN(MA,ME) + CALL FMEQ(ME,MA) + ST2 = '0.3371339561772373443347761845672381725353758541616570' + CALL FMST2M(ST2,MC) + CALL FMSUB(MA,MC,MD) + CALL FMABS(MD,ME) + CALL FMEQ(ME,MD) + CALL FMST2M('1.0E-50',MB) + IF (.NOT.FMCOMP(MD,'LE',MB)) THEN + CALL ERRPRTFM('FMATAN',MA,'MA',MC,'MC',MD,'MD', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 56 + ST1 = '43.3505154639175257731958762886597938144329896907216495' + CALL FMST2M(ST1,MA) + CALL FMATAN(MA,ME) + CALL FMEQ(ME,MA) + ST2 = '1.5477326406586162039457549832092678908202994134569781' + CALL FMST2M(ST2,MC) + CALL FMSUB(MA,MC,MD) + CALL FMABS(MD,ME) + CALL FMEQ(ME,MD) + CALL FMST2M('1.0E-50',MB) + IF (.NOT.FMCOMP(MD,'LE',MB)) THEN + CALL ERRPRTFM('FMATAN',MA,'MA',MC,'MC',MD,'MD', & + NCASE,NERROR,KLOG) + ENDIF + + RETURN + END SUBROUTINE TEST8 + + SUBROUTINE TEST9(ST1,ST2,NCASE,NERROR,KLOG) + +! Test hyperbolic functions. + + USE FMVALS + USE FMZM + USE TEST_VARS + + IMPLICIT NONE + + LOGICAL FMCOMP + + CHARACTER(80) :: ST1,ST2 + INTEGER KLOG,NCASE,NERROR + + WRITE (KW,"(/' Testing hyperbolic routines.')") + + NCASE = 57 + ST1 = '0.3505154639175257731958762886597938144329896907216495' + CALL FMST2M(ST1,MA) + CALL FMCOSH(MA,ME) + CALL FMEQ(ME,MA) + ST2 = '1.0620620786534654254819884264931372964608741056397718' + CALL FMST2M(ST2,MC) + CALL FMSUB(MA,MC,MD) + CALL FMABS(MD,ME) + CALL FMEQ(ME,MD) + CALL FMST2M('1.0E-49',MB) + IF (.NOT.FMCOMP(MD,'LE',MB)) THEN + CALL ERRPRTFM('FMCOSH',MA,'MA',MC,'MC',MD,'MD', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 58 + ST1 = '-43.3505154639175257731958762886597938144329896907216495' + CALL FMST2M(ST1,MA) + CALL FMCOSH(MA,ME) + CALL FMEQ(ME,MA) + ST2 = '3.356291383454381441662669560464886179346554730604556E+18' + CALL FMST2M(ST2,MC) + CALL FMSUB(MA,MC,MD) + CALL FMABS(MD,ME) + CALL FMEQ(ME,MD) + CALL FMST2M('1.0E-31',MB) + IF (.NOT.FMCOMP(MD,'LE',MB)) THEN + CALL ERRPRTFM('FMCOSH',MA,'MA',MC,'MC',MD,'MD', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 59 + ST1 = '-0.3505154639175257731958762886597938144329896907216495' + CALL FMST2M(ST1,MA) + CALL FMSINH(MA,ME) + CALL FMEQ(ME,MA) + ST2 = '-0.3577371366153083355393138079781276622149524420386975' + CALL FMST2M(ST2,MC) + CALL FMSUB(MA,MC,MD) + CALL FMABS(MD,ME) + CALL FMEQ(ME,MD) + CALL FMST2M('1.0E-50',MB) + IF (.NOT.FMCOMP(MD,'LE',MB)) THEN + CALL ERRPRTFM('FMSINH',MA,'MA',MC,'MC',MD,'MD', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 60 + ST1 = '43.3505154639175257731958762886597938144329896907216495' + CALL FMST2M(ST1,MA) + CALL FMSINH(MA,ME) + CALL FMEQ(ME,MA) + ST2 = '3.356291383454381441662669560464886179197580776059111E+18' + CALL FMST2M(ST2,MC) + CALL FMSUB(MA,MC,MD) + CALL FMABS(MD,ME) + CALL FMEQ(ME,MD) + CALL FMST2M('1.0E-31',MB) + IF (.NOT.FMCOMP(MD,'LE',MB)) THEN + CALL ERRPRTFM('FMSINH',MA,'MA',MC,'MC',MD,'MD', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 61 + ST1 = '0.3505154639175257731958762886597938144329896907216495' + CALL FMST2M(ST1,MA) + CALL FMTANH(MA,ME) + CALL FMEQ(ME,MA) + ST2 = '0.3368326049912874057089491946232983472275659538703038' + CALL FMST2M(ST2,MC) + CALL FMSUB(MA,MC,MD) + CALL FMABS(MD,ME) + CALL FMEQ(ME,MD) + CALL FMST2M('1.0E-50',MB) + IF (.NOT.FMCOMP(MD,'LE',MB)) THEN + CALL ERRPRTFM('FMTANH',MA,'MA',MC,'MC',MD,'MD', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 62 + ST1 = '43.3505154639175257731958762886597938144329896907216495' + CALL FMST2M(ST1,MA) + CALL FMTANH(MA,ME) + CALL FMEQ(ME,MA) + ST2 = '0.9999999999999999999999999999999999999556135217341837' + CALL FMST2M(ST2,MC) + CALL FMSUB(MA,MC,MD) + CALL FMABS(MD,ME) + CALL FMEQ(ME,MD) + CALL FMST2M('1.0E-50',MB) + IF (.NOT.FMCOMP(MD,'LE',MB)) THEN + CALL ERRPRTFM('FMTANH',MA,'MA',MC,'MC',MD,'MD', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 63 + ST1 = '0.3505154639175257731958762886597938144329896907216495' + CALL FMST2M(ST1,MA) + CALL FMCHSH(MA,ME,MC) + CALL FMEQ(ME,MA) + ST2 = '1.0620620786534654254819884264931372964608741056397718' + CALL FMST2M(ST2,MC) + CALL FMSUB(MA,MC,MD) + CALL FMABS(MD,ME) + CALL FMEQ(ME,MD) + CALL FMST2M('1.0E-49',MB) + IF (.NOT.FMCOMP(MD,'LE',MB)) THEN + CALL ERRPRTFM('FMCHSH',MA,'MA',MC,'MC',MD,'MD', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 64 + ST1 = '-43.3505154639175257731958762886597938144329896907216495' + CALL FMST2M(ST1,MA) + CALL FMCHSH(MA,ME,MC) + CALL FMEQ(ME,MA) + ST2 = '3.356291383454381441662669560464886179346554730604556E+18' + CALL FMST2M(ST2,MC) + CALL FMSUB(MA,MC,MD) + CALL FMABS(MD,ME) + CALL FMEQ(ME,MD) + CALL FMST2M('1.0E-31',MB) + IF (.NOT.FMCOMP(MD,'LE',MB)) THEN + CALL ERRPRTFM('FMCHSH',MA,'MA',MC,'MC',MD,'MD', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 65 + ST1 = '-0.3505154639175257731958762886597938144329896907216495' + CALL FMST2M(ST1,MA) + CALL FMCHSH(MA,MC,ME) + CALL FMEQ(ME,MA) + ST2 = '-0.3577371366153083355393138079781276622149524420386975' + CALL FMST2M(ST2,MC) + CALL FMSUB(MA,MC,MD) + CALL FMABS(MD,ME) + CALL FMEQ(ME,MD) + CALL FMST2M('1.0E-50',MB) + IF (.NOT.FMCOMP(MD,'LE',MB)) THEN + CALL ERRPRTFM('FMCHSH',MA,'MA',MC,'MC',MD,'MD', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 66 + ST1 = '43.3505154639175257731958762886597938144329896907216495' + CALL FMST2M(ST1,MA) + CALL FMCHSH(MA,MC,ME) + CALL FMEQ(ME,MA) + ST2 = '3.356291383454381441662669560464886179197580776059111E+18' + CALL FMST2M(ST2,MC) + CALL FMSUB(MA,MC,MD) + CALL FMABS(MD,ME) + CALL FMEQ(ME,MD) + CALL FMST2M('1.0E-31',MB) + IF (.NOT.FMCOMP(MD,'LE',MB)) THEN + CALL ERRPRTFM('FMCHSH',MA,'MA',MC,'MC',MD,'MD', & + NCASE,NERROR,KLOG) + ENDIF + + RETURN + END SUBROUTINE TEST9 + + SUBROUTINE TEST10(ST1,ST2,NCASE,NERROR,KLOG) + +! Input and output testing for IM routines. + + USE FMVALS + USE FMZM + USE TEST_VARS + + IMPLICIT NONE + +! Logical function for comparing IM numbers. + + LOGICAL IMCOMP + + CHARACTER(80) :: ST1,ST2 + INTEGER KLOG,NCASE,NERROR + + WRITE (KW,"(/' Testing integer input and output routines.')") + + NCASE = 67 + CALL IMST2M('123',MA) + CALL IMI2M(123,MC) + IF (.NOT.IMCOMP(MA,'EQ',MC)) THEN + CALL ERRPRTIM('IMST2M',MA,'MA',MC,'MC',NCASE,NERROR,KLOG) + ENDIF + + NCASE = 68 + ST1 = '-350515' + CALL IMST2M(ST1,MA) + CALL IMI2M(-350515,MC) + IF (.NOT.IMCOMP(MA,'EQ',MC)) THEN + CALL ERRPRTIM('IMST2M',MA,'MA',MC,'MC',NCASE,NERROR,KLOG) + ENDIF + + NCASE = 69 + ST1 = '19895113660064588580108197261066338165074766609' + CALL IMST2M(ST1,MA) + CALL IMI2M(23,MB) + CALL IMI2M(34,MC) + CALL IMPWR(MB,MC,ME) + CALL IMEQ(ME,MC) + IF (.NOT.IMCOMP(MA,'EQ',MC)) THEN + CALL ERRPRTIM('IMPWR ',MA,'MA',MC,'MC',NCASE,NERROR,KLOG) + ENDIF + + NCASE = 70 + ST1 = '-20800708073664542533904165663516279809808659679033703' + CALL IMST2M(ST1,MA) + CALL IMI2M(-567,MB) + CALL IMI2M(19,MC) + CALL IMPWR(MB,MC,ME) + CALL IMEQ(ME,MC) + IF (.NOT.IMCOMP(MA,'EQ',MC)) THEN + CALL ERRPRTIM('IMPWR ',MA,'MA',MC,'MC',NCASE,NERROR,KLOG) + ENDIF + + NCASE = 71 + ST1 = '19895113660064588580108197261066338165074766609' + CALL IMST2M(ST1,MA) + CALL IMFORM('I53',MA,ST2) + CALL IMST2M(ST2,MC) + IF (.NOT.IMCOMP(MA,'EQ',MC)) THEN + CALL ERRPRTIM('IMFORM',MA,'MA',MC,'MC',NCASE,NERROR,KLOG) + ENDIF + + NCASE = 72 + ST1 = '-20800708073664542533904165663516279809808659679033703' + CALL IMST2M(ST1,MA) + CALL IMFORM('I73',MA,ST2) + CALL IMST2M(ST2,MC) + IF (.NOT.IMCOMP(MA,'EQ',MC)) THEN + CALL ERRPRTIM('IMFORM',MA,'MA',MC,'MC',NCASE,NERROR,KLOG) + ENDIF + + RETURN + END SUBROUTINE TEST10 + + SUBROUTINE TEST11(ST1,ST2,NCASE,NERROR,KLOG) + +! Test add and subtract for IM routines. + + USE FMVALS + USE FMZM + USE TEST_VARS + + IMPLICIT NONE + + LOGICAL IMCOMP + + CHARACTER(80) :: ST1,ST2 + INTEGER KLOG,NCASE,NERROR + + WRITE (KW,"(/' Testing integer add and subtract routines.')") + + NCASE = 73 + CALL IMST2M('123',MA) + CALL IMST2M('789',MB) + CALL IMADD(MA,MB,ME) + CALL IMEQ(ME,MA) + CALL IMI2M(912,MC) + IF (.NOT.IMCOMP(MA,'EQ',MC)) THEN + CALL ERRPRTIM('IMADD ',MA,'MA',MC,'MC',NCASE,NERROR,KLOG) + ENDIF + + NCASE = 74 + ST1 = '3505154639175257731958762886597938144329896907216495' + CALL IMST2M(ST1,MA) + ST1 = '7319587628865979381443298969072164948453608247422680' + CALL IMST2M(ST1,MB) + CALL IMADD(MA,MB,ME) + CALL IMEQ(ME,MA) + ST2 = '10824742268041237113402061855670103092783505154639175' + CALL IMST2M(ST2,MC) + IF (.NOT.IMCOMP(MA,'EQ',MC)) THEN + CALL ERRPRTIM('IMADD ',MA,'MA',MC,'MC',NCASE,NERROR,KLOG) + ENDIF + + NCASE = 75 + ST1 = '3505154639175257731958762886597938144329896907216495' + CALL IMST2M(ST1,MA) + ST1 = '7319587628865979381443298969072164948453608247422680' + CALL IMST2M(ST1,MB) + CALL IMSUB(MA,MB,ME) + CALL IMEQ(ME,MA) + ST2 = '-3814432989690721649484536082474226804123711340206185' + CALL IMST2M(ST2,MC) + IF (.NOT.IMCOMP(MA,'EQ',MC)) THEN + CALL ERRPRTIM('IMSUB ',MA,'MA',MC,'MC',NCASE,NERROR,KLOG) + ENDIF + + NCASE = 76 + ST1 = '3505154639175257731958762886597938144329896907216495' + CALL IMST2M(ST1,MA) + ST1 = '3505154639175257731443298969072164948453608247422680' + CALL IMST2M(ST1,MB) + CALL IMSUB(MA,MB,ME) + CALL IMEQ(ME,MA) + ST2 = '515463917525773195876288659793815' + CALL IMST2M(ST2,MC) + IF (.NOT.IMCOMP(MA,'EQ',MC)) THEN + CALL ERRPRTIM('IMSUB ',MA,'MA',MC,'MC',NCASE,NERROR,KLOG) + ENDIF + + RETURN + END SUBROUTINE TEST11 + + SUBROUTINE TEST12(ST1,ST2,NCASE,NERROR,KLOG) + +! Test integer multiply and divide. + + USE FMVALS + USE FMZM + USE TEST_VARS + + IMPLICIT NONE + + LOGICAL IMCOMP + + CHARACTER(80) :: ST1,ST2 + INTEGER IREM,KLOG,NCASE,NERROR + + WRITE (KW,"(/' Testing integer multiply, divide and square routines.')") + + NCASE = 77 + CALL IMST2M('123',MA) + CALL IMST2M('789',MB) + CALL IMMPY(MA,MB,ME) + CALL IMEQ(ME,MA) + CALL IMI2M(97047,MC) + IF (.NOT.IMCOMP(MA,'EQ',MC)) THEN + CALL ERRPRTIM('IMMPY ',MA,'MA',MC,'MC',NCASE,NERROR,KLOG) + ENDIF + + NCASE = 78 + ST1 = '10430738374625018354698' + CALL IMST2M(ST1,MA) + ST1 = '2879494424799214514791045985' + CALL IMST2M(ST1,MB) + CALL IMMPY(MA,MB,ME) + CALL IMEQ(ME,MA) + ST2 = '30035252996271960952238822892375588336807158787530' + CALL IMST2M(ST2,MC) + IF (.NOT.IMCOMP(MA,'EQ',MC)) THEN + CALL ERRPRTIM('IMMPY ',MA,'MA',MC,'MC',NCASE,NERROR,KLOG) + ENDIF + + NCASE = 79 + CALL IMST2M('12347',MA) + CALL IMST2M('47',MB) + CALL IMDIV(MA,MB,ME) + CALL IMEQ(ME,MA) + CALL IMST2M('262',MC) + IF (.NOT.IMCOMP(MA,'EQ',MC)) THEN + CALL ERRPRTIM('IMDIV ',MA,'MA',MC,'MC',NCASE,NERROR,KLOG) + ENDIF + + NCASE = 80 + ST1 = '2701314697583086005158008013691015597308949443159762' + CALL IMST2M(ST1,MA) + ST1 = '-978132616472842669976589722394' + CALL IMST2M(ST1,MB) + CALL IMDIV(MA,MB,ME) + CALL IMEQ(ME,MA) + CALL IMST2M('-2761705981469115610382',MC) + IF (.NOT.IMCOMP(MA,'EQ',MC)) THEN + CALL ERRPRTIM('IMDIV ',MA,'MA',MC,'MC',NCASE,NERROR,KLOG) + ENDIF + + NCASE = 81 + CALL IMST2M('12368',MA) + CALL IMST2M('67',MB) + CALL IMMOD(MA,MB,ME) + CALL IMEQ(ME,MB) + CALL IMST2M('40',MC) + IF (.NOT.IMCOMP(MB,'EQ',MC)) THEN + CALL ERRPRTIM('IMMOD ',MB,'MB',MC,'MC',NCASE,NERROR,KLOG) + ENDIF + + NCASE = 82 + ST1 = '2701314697583086005158008013691015597308949443159762' + CALL IMST2M(ST1,MA) + ST1 = '-978132616472842669976589722394' + CALL IMST2M(ST1,MB) + CALL IMMOD(MA,MB,ME) + CALL IMEQ(ME,MB) + CALL IMST2M('450750319653685523300198865254',MC) + IF (.NOT.IMCOMP(MB,'EQ',MC)) THEN + CALL ERRPRTIM('IMMOD ',MB,'MB',MC,'MC',NCASE,NERROR,KLOG) + ENDIF + + NCASE = 83 + CALL IMST2M('1234',MA) + CALL IMST2M('17',MB) + CALL IMDIVR(MA,MB,MC,MD) + CALL IMEQ(MC,MA) + CALL IMEQ(MD,MB) + CALL IMST2M('72',MC) + IF (.NOT.IMCOMP(MA,'EQ',MC)) THEN + CALL ERRPRTIM('IMDIVR',MA,'MA',MC,'MC',NCASE,NERROR,KLOG) + ENDIF + CALL IMST2M('10',MC) + IF (.NOT.IMCOMP(MB,'EQ',MC)) THEN + CALL ERRPRTIM('IMDIVR',MB,'MB',MC,'MC',NCASE,NERROR,KLOG) + ENDIF + + NCASE = 84 + ST1 = '34274652243817531418235301715935108945364446765801943' + CALL IMST2M(ST1,MA) + ST1 = '-54708769795848731641842224621693' + CALL IMST2M(ST1,MB) + CALL IMDIVR(MA,MB,MC,MD) + CALL IMEQ(MC,MA) + CALL IMEQ(MD,MB) + CALL IMST2M('-626492834178447772323',MC) + IF (.NOT.IMCOMP(MA,'EQ',MC)) THEN + CALL ERRPRTIM('IMDIVR',MA,'MA',MC,'MC',NCASE,NERROR,KLOG) + ENDIF + CALL IMST2M('31059777254296217822749494999104',MC) + IF (.NOT.IMCOMP(MB,'EQ',MC)) THEN + CALL ERRPRTIM('IMDIVR',MB,'MB',MC,'MC',NCASE,NERROR,KLOG) + ENDIF + + NCASE = 85 + CALL IMST2M('4866',MA) + CALL IMMPYI(MA,14,ME) + CALL IMEQ(ME,MA) + CALL IMST2M('68124',MC) + IF (.NOT.IMCOMP(MA,'EQ',MC)) THEN + CALL ERRPRTIM('IMMPYI',MA,'MA',MC,'MC',NCASE,NERROR,KLOG) + ENDIF + + NCASE = 86 + CALL IMST2M('270131469758308600515800801369101559730894',MA) + CALL IMMPYI(MA,-2895,ME) + CALL IMEQ(ME,MA) + CALL IMST2M('-782030604950303398493243319963549015420938130',MC) + IF (.NOT.IMCOMP(MA,'EQ',MC)) THEN + CALL ERRPRTIM('IMMPYI ',MA,'MA',MC,'MC',NCASE,NERROR,KLOG) + ENDIF + + NCASE = 87 + CALL IMST2M('-37179',MA) + CALL IMDIVI(MA,129,ME) + CALL IMEQ(ME,MA) + CALL IMST2M('-288',MC) + IF (.NOT.IMCOMP(MA,'EQ',MC)) THEN + CALL ERRPRTIM('IMDIVI',MA,'MA',MC,'MC',NCASE,NERROR,KLOG) + ENDIF + + NCASE = 88 + ST1 = '8267538919383255454483790743961990401918726073065738' + CALL IMST2M(ST1,MA) + CALL IMDIVI(MA,1729,ME) + CALL IMEQ(ME,MA) + ST2 = '4781688212483085861471249707323302719444028960708' + CALL IMST2M(ST2,MC) + IF (.NOT.IMCOMP(MA,'EQ',MC)) THEN + CALL ERRPRTIM('IMDIVI',MA,'MA',MC,'MC',NCASE,NERROR,KLOG) + ENDIF + + NCASE = 89 + CALL IMST2M('-71792',MA) + CALL IMDVIR(MA,65,MC,IREM) + CALL IMEQ(MC,MA) + CALL IMST2M('-1104',MC) + IF (.NOT.IMCOMP(MA,'EQ',MC)) THEN + CALL ERRPRTIM('IMDVIR',MA,'MA',MC,'MC',NCASE,NERROR,KLOG) + ENDIF + CALL IMI2M(IREM,MB) + CALL IMI2M(-32,MC) + IF (.NOT.IMCOMP(MB,'EQ',MC)) THEN + CALL ERRPRTIM('IMDVIR',MB,'MB',MC,'MC',NCASE,NERROR,KLOG) + ENDIF + + NCASE = 90 + ST1 = '97813261647284266997658972239417958580120170263408655' + CALL IMST2M(ST1,MA) + CALL IMDVIR(MA,826,MC,IREM) + CALL IMEQ(MC,MA) + ST2 = '118417992309060855929369215786220288837917881674828' + CALL IMST2M(ST2,MC) + IF (.NOT.IMCOMP(MA,'EQ',MC)) THEN + CALL ERRPRTIM('IMDVIR',MA,'MA',MC,'MC',NCASE,NERROR,KLOG) + ENDIF + CALL IMI2M(IREM,MB) + CALL IMI2M(727,MC) + IF (.NOT.IMCOMP(MB,'EQ',MC)) THEN + CALL ERRPRTIM('IMDVIR',MB,'MB',MC,'MC',NCASE,NERROR,KLOG) + ENDIF + + NCASE = 91 + CALL IMST2M('538',MA) + CALL IMSQR(MA,ME) + CALL IMEQ(ME,MA) + CALL IMST2M('289444',MC) + IF (.NOT.IMCOMP(MA,'EQ',MC)) THEN + CALL ERRPRTIM('IMSQR ',MA,'MA',MC,'MC',NCASE,NERROR,KLOG) + ENDIF + + NCASE = 92 + CALL IMST2M('-47818191879814587168242632',MA) + CALL IMSQR(MA,ME) + CALL IMEQ(ME,MA) + ST2 = '2286579474654765721668058416662636606051551222287424' + CALL IMST2M(ST2,MC) + IF (.NOT.IMCOMP(MA,'EQ',MC)) THEN + CALL ERRPRTIM('IMSQR ',MA,'MA',MC,'MC',NCASE,NERROR,KLOG) + ENDIF + + RETURN + END SUBROUTINE TEST12 + + SUBROUTINE TEST13(NCASE,NERROR,KLOG) + +! Test conversions between FM and IM format. + + USE FMVALS + USE FMZM + USE TEST_VARS + + IMPLICIT NONE + + LOGICAL FMCOMP,IMCOMP + + INTEGER KLOG,NCASE,NERROR + + WRITE (KW,"(/' Testing conversions between FM and IM format.')") + + NCASE = 93 + CALL IMST2M('123',MA) + CALL IMI2FM(MA,MB) + CALL FMI2M(123,MC) + CALL FMSUB(MA,MC,MD) + CALL FMABS(MD,ME) + CALL FMEQ(ME,MD) + CALL FMST2M('0',MB) + IF (.NOT.FMCOMP(MD,'LE',MB)) THEN + CALL ERRPRTFM('IMI2FM',MA,'MA',MC,'MC',MD,'MD', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 94 + CALL IMST2M('979282999076598337488362000995916',MA) + CALL IMI2FM(MA,MB) + CALL FMST2M('979282999076598337488362000995916',MC) + CALL FMSUB(MA,MC,MD) + CALL FMABS(MD,ME) + CALL FMEQ(ME,MD) + CALL FMST2M('0',MB) + IF (.NOT.FMCOMP(MD,'LE',MB)) THEN + CALL ERRPRTFM('IMI2FM',MA,'MA',MC,'MC',MD,'MD', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 95 + CALL FMST2M('123.4',MA) + CALL IMFM2I(MA,MB) + CALL IMI2M(123,MC) + IF (.NOT.IMCOMP(MB,'EQ',MC)) THEN + CALL ERRPRTIM('IMFM2I',MB,'MB',MC,'MC',NCASE,NERROR,KLOG) + ENDIF + + NCASE = 96 + CALL FMST2M('979282999076598337488362000995916',MA) + CALL IMFM2I(MA,MB) + CALL IMST2M('979282999076598337488362000995916',MC) + IF (.NOT.IMCOMP(MB,'EQ',MC)) THEN + CALL ERRPRTIM('IMFM2I',MB,'MB',MC,'MC',NCASE,NERROR,KLOG) + ENDIF + + RETURN + END SUBROUTINE TEST13 + + SUBROUTINE TEST14(ST1,ST2,NCASE,NERROR,KLOG) + +! Test integer power and GCD functions. + + USE FMVALS + USE FMZM + USE TEST_VARS + + IMPLICIT NONE + + LOGICAL IMCOMP + + CHARACTER(80) :: ST1,ST2 + INTEGER KLOG,NCASE,NERROR + + WRITE (KW,"(/' Testing integer GCD and power routines.')") + + NCASE = 97 + CALL IMST2M('123',MA) + CALL IMST2M('789',MB) + CALL IMGCD(MA,MB,ME) + CALL IMEQ(ME,MA) + CALL IMI2M(3,MC) + IF (.NOT.IMCOMP(MA,'EQ',MC)) THEN + CALL ERRPRTIM('IMGCD ',MA,'MA',MC,'MC',NCASE,NERROR,KLOG) + ENDIF + + NCASE = 98 + ST1 = '431134020618556701030927835051546391752577319587628885' + CALL IMST2M(ST1,MA) + ST1 = '900309278350515463917525773195876288659793814432989640' + CALL IMST2M(ST1,MB) + CALL IMGCD(MA,MB,ME) + CALL IMEQ(ME,MA) + CALL IMST2M('615',MC) + IF (.NOT.IMCOMP(MA,'EQ',MC)) THEN + CALL ERRPRTIM('IMGCD ',MA,'MA',MC,'MC',NCASE,NERROR,KLOG) + ENDIF + + NCASE = 99 + ST1 = '5877631675869176172956662762822298812326084745145447940' + CALL IMST2M(ST1,MA) + ST1 = '10379997509886032090765062511740075746391432253007667' + CALL IMST2M(ST1,MB) + CALL IMGCD(MA,MB,ME) + CALL IMEQ(ME,MA) + CALL IMST2M('1',MC) + IF (.NOT.IMCOMP(MA,'EQ',MC)) THEN + CALL ERRPRTIM('IMGCD ',MA,'MA',MC,'MC',NCASE,NERROR,KLOG) + ENDIF + + NCASE = 100 + CALL IMST2M('47',MA) + CALL IMST2M('34',MB) + CALL IMPWR(MA,MB,ME) + CALL IMEQ(ME,MA) + ST2 = '710112520079088427392020925014421733344154169313556279969' + CALL IMST2M(ST2,MC) + IF (.NOT.IMCOMP(MA,'EQ',MC)) THEN + CALL ERRPRTIM('IMPWR ',MA,'MA',MC,'MC',NCASE,NERROR,KLOG) + ENDIF + + NCASE = 101 + CALL IMST2M('2',MA) + CALL IMST2M('187',MB) + CALL IMPWR(MA,MB,ME) + CALL IMEQ(ME,MA) + ST2 = '196159429230833773869868419475239575503198607639501078528' + CALL IMST2M(ST2,MC) + IF (.NOT.IMCOMP(MA,'EQ',MC)) THEN + CALL ERRPRTIM('IMPWR ',MA,'MA',MC,'MC',NCASE,NERROR,KLOG) + ENDIF + + NCASE = 102 + CALL IMST2M('-3',MA) + CALL IMST2M('101',MB) + CALL IMPWR(MA,MB,ME) + CALL IMEQ(ME,MA) + ST2 = '-1546132562196033993109383389296863818106322566003' + CALL IMST2M(ST2,MC) + IF (.NOT.IMCOMP(MA,'EQ',MC)) THEN + CALL ERRPRTIM('IMPWR ',MA,'MA',MC,'MC',NCASE,NERROR,KLOG) + ENDIF + + RETURN + END SUBROUTINE TEST14 + + SUBROUTINE TEST15(ST1,ST2,NCASE,NERROR,KLOG) + +! Test integer modular functions. + + USE FMVALS + USE FMZM + USE TEST_VARS + + IMPLICIT NONE + + LOGICAL IMCOMP + + CHARACTER(80) :: ST1,ST2 + INTEGER KLOG,NCASE,NERROR + + WRITE (KW,"(/' Testing integer modular routines.')") + + NCASE = 103 + CALL IMST2M('123',MA) + CALL IMST2M('789',MB) + CALL IMST2M('997',MC) + CALL IMMPYM(MA,MB,MC,ME) + CALL IMEQ(ME,MA) + CALL IMI2M(338,MC) + IF (.NOT.IMCOMP(MA,'EQ',MC)) THEN + CALL ERRPRTIM('IMMPYM',MA,'MA',MC,'MC',NCASE,NERROR,KLOG) + ENDIF + + NCASE = 104 + ST1 = '431134020618556701030927835051546391752577319587628885' + CALL IMST2M(ST1,MA) + ST1 = '36346366019557973241042306587666640486264616086971724' + CALL IMST2M(ST1,MB) + ST1 = '900309278350515463917525773195876288659793814432989640' + CALL IMST2M(ST1,MC) + CALL IMMPYM(MA,MB,MC,ME) + CALL IMEQ(ME,MA) + ST2 = '458279704440780378752997531208983184411293504187816380' + CALL IMST2M(ST2,MC) + IF (.NOT.IMCOMP(MA,'EQ',MC)) THEN + CALL ERRPRTIM('IMMPYM',MA,'MA',MC,'MC',NCASE,NERROR,KLOG) + ENDIF + + NCASE = 105 + ST1 = '914726194238000125985765939883182' + CALL IMST2M(ST1,MA) + ST1 = '-75505764717193044779376979508186553225192' + CALL IMST2M(ST1,MB) + ST1 = '18678872625055834600521936' + CALL IMST2M(ST1,MC) + CALL IMMPYM(MA,MB,MC,ME) + CALL IMEQ(ME,MA) + ST2 = '-7769745969769966093344960' + CALL IMST2M(ST2,MC) + IF (.NOT.IMCOMP(MA,'EQ',MC)) THEN + CALL ERRPRTIM('IMMPYM',MA,'MA',MC,'MC',NCASE,NERROR,KLOG) + ENDIF + + NCASE = 106 + CALL IMST2M('123',MA) + CALL IMST2M('789',MB) + CALL IMST2M('997',MC) + CALL IMPMOD(MA,MB,MC,ME) + CALL IMEQ(ME,MA) + CALL IMI2M(240,MC) + IF (.NOT.IMCOMP(MA,'EQ',MC)) THEN + CALL ERRPRTIM('IMPMOD',MA,'MA',MC,'MC',NCASE,NERROR,KLOG) + ENDIF + + NCASE = 107 + ST1 = '431134020618556701030927835051546391752577319587628885' + CALL IMST2M(ST1,MA) + ST1 = '36346366019557973241042306587666640486264616086971724' + CALL IMST2M(ST1,MB) + ST1 = '900309278350515463917525773195876288659793814432989640' + CALL IMST2M(ST1,MC) + CALL IMPMOD(MA,MB,MC,ME) + CALL IMEQ(ME,MA) + ST2 = '755107893576299697276281907390144058060594744720442385' + CALL IMST2M(ST2,MC) + IF (.NOT.IMCOMP(MA,'EQ',MC)) THEN + CALL ERRPRTIM('IMPMOD',MA,'MA',MC,'MC',NCASE,NERROR,KLOG) + ENDIF + + NCASE = 108 + CALL IMST2M('314159',MA) + CALL IMST2M('1411695892374393248272691827763664225585897550',MB) + CALL IMST2M('1411695892374393248272691827763664225585897551',MC) + CALL IMPMOD(MA,MB,MC,ME) + CALL IMEQ(ME,MA) + CALL IMST2M('1',MC) + IF (.NOT.IMCOMP(MA,'EQ',MC)) THEN + CALL ERRPRTIM('IMPMOD',MA,'MA',MC,'MC',NCASE,NERROR,KLOG) + ENDIF + + RETURN + END SUBROUTINE TEST15 + + SUBROUTINE TEST16(STZ1,STZ2,NCASE,NERROR,KLOG) + +! Complex input and output testing. + + USE FMVALS + USE FMZM + USE TEST_VARS + + IMPLICIT NONE + +! Logical function for comparing FM numbers. + + LOGICAL FMCOMP + + CHARACTER(160) :: STZ1,STZ2 + INTEGER KLOG,NCASE,NERROR + + WRITE (KW,"(/' Testing complex input and output routines.')") + + NCASE = 109 + CALL ZMST2M('123 + 456 i',ZA) + CALL ZM2I2M(123,456,ZC) + CALL ZMSUB(ZA,ZC,ZD) + CALL ZMABS(ZD,MA) + CALL FMI2M(10,MB) + CALL FMIPWR(MB,-48,ME) + CALL FMEQ(ME,MB) + +! Use the .NOT. because FMCOMP returns FALSE for special +! cases like ZD = UNKNOWN, and these should be treated +! as errors for these tests. + + IF (.NOT.FMCOMP(MA,'LE',MB)) THEN + CALL ERRPRTZM('ZMST2M',ZA,'ZA',ZC,'ZC',ZD,'ZD', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 110 + STZ1 = '0.3505154639175257731958762886597938144329896907216495 + ' & + // '0.7319587628865979381443298969072164948453608247422680 i' + CALL ZMST2M(STZ1,ZA) + CALL ZM2I2M(34,71,ZC) + CALL ZMDIVI(ZC,97,ZE) + CALL ZMEQ(ZE,ZC) + CALL ZMSUB(ZA,ZC,ZD) + CALL ZMABS(ZD,MA) + CALL FMI2M(10,MB) + CALL FMIPWR(MB,-50,ME) + CALL FMEQ(ME,MB) + IF (.NOT.FMCOMP(MA,'LE',MB)) THEN + CALL ERRPRTZM('ZMST2M',ZA,'ZA',ZC,'ZC',ZD,'ZD', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 111 + STZ1 = '0.3505154639175257731958762886597938144329896907216495E-5 ' & + //'+ 0.7319587628865979381443298969072164948453608247422680D-5 i' + CALL ZMST2M(STZ1,ZA) + CALL ZM2I2M(34,71,ZC) + CALL ZMDIVI(ZC,9700000,ZE) + CALL ZMEQ(ZE,ZC) + CALL ZMSUB(ZA,ZC,ZD) + CALL ZMABS(ZD,MA) + CALL FMI2M(10,MB) + CALL FMIPWR(MB,-55,ME) + CALL FMEQ(ME,MB) + IF (.NOT.FMCOMP(MA,'LE',MB)) THEN + CALL ERRPRTZM('ZMST2M',ZA,'ZA',ZC,'ZC',ZD,'ZD', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 112 + STZ1 = '7.699115044247787610619469026548672566371681415929204e 03 ' & + //'- 5.221238938053097345132743362831858407079646017699115M 03 I' + CALL ZMST2M(STZ1,ZA) + CALL ZM2I2M(87,-59,ZC) + CALL ZMDIVI(ZC,113,ZE) + CALL ZMEQ(ZE,ZC) + CALL ZMMPYI(ZC,10000,ZE) + CALL ZMEQ(ZE,ZC) + CALL ZMSUB(ZA,ZC,ZD) + CALL ZMABS(ZD,MA) + CALL FMI2M(10,MB) + CALL FMIPWR(MB,-47,ME) + CALL FMEQ(ME,MB) + IF (.NOT.FMCOMP(MA,'LE',MB)) THEN + CALL ERRPRTZM('ZMST2M',ZA,'ZA',ZC,'ZC',ZD,'ZD', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 113 + STZ1 = '7.699115044247787610619469026548672566371681415929204e+3 ' & + //'- 5.221238938053097345132743362831858407079646017699115M+3 i' + CALL ZMST2M(STZ1,ZA) + CALL ZMFORM('F53.33','F50.30',ZA,STZ2) + CALL ZMST2M(STZ2,ZA) + STZ1 = '7699.115044247787610619469026548673 ' & + // '-5221.238938053097345132743362831858 i' + CALL ZMST2M(STZ1,ZC) + CALL ZMSUB(ZA,ZC,ZD) + CALL ZMABS(ZD,MA) + CALL FMI2M(10,MB) + CALL FMIPWR(MB,-30,ME) + CALL FMEQ(ME,MB) + IF (.NOT.FMCOMP(MA,'LE',MB)) THEN + CALL ERRPRTZM('ZMFORM',ZA,'ZA',ZC,'ZC',ZD,'ZD', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 114 + STZ1 = '7.699115044247787610619469026548672566371681415929204e+3 ' & + //'- 5.221238938053097345132743362831858407079646017699115M+3 i' + CALL ZMST2M(STZ1,ZA) + CALL ZMFORM('I9','I7',ZA,STZ2) + CALL ZMST2M(STZ2,ZA) + STZ1 = '7699 -5221 i' + CALL ZMST2M(STZ1,ZC) + CALL ZMSUB(ZA,ZC,ZD) + CALL ZMABS(ZD,MA) + CALL FMI2M(0,MB) + IF (.NOT.FMCOMP(MA,'LE',MB)) THEN + CALL ERRPRTZM('ZMFORM',ZA,'ZA',ZC,'ZC',ZD,'ZD', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 115 + STZ1 = '7.699115044247787610619469026548672566371681415929204e+3 ' & + //'- 5.221238938053097345132743362831858407079646017699115M+3 i' + CALL ZMST2M(STZ1,ZA) + CALL ZMFORM('E59.50','E58.49',ZA,STZ2) + CALL ZMST2M(STZ2,ZA) + STZ1 = '7.6991150442477876106194690265486725663716814159292E3' & + //'- 5.221238938053097345132743362831858407079646017699E3 i' + CALL ZMST2M(STZ1,ZC) + CALL ZMSUB(ZA,ZC,ZD) + CALL ZMABS(ZD,MA) + CALL FMI2M(10,MB) + CALL FMIPWR(MB,-48,ME) + CALL FMEQ(ME,MB) + IF (.NOT.FMCOMP(MA,'LE',MB)) THEN + CALL ERRPRTZM('ZMFORM',ZA,'ZA',ZC,'ZC',ZD,'ZD', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 116 + STZ1 = '7.699115044247787610619469026548672566371681415929204e+3 ' & + //'- 5.221238938053097345132743362831858407079646017699115M+3 i' + CALL ZMST2M(STZ1,ZA) + CALL ZMFORM('1PE59.50','1PE58.49',ZA,STZ2) + CALL ZMST2M(STZ2,ZA) + CALL ZMST2M(STZ1,ZC) + CALL ZMSUB(ZA,ZC,ZD) + CALL ZMABS(ZD,MA) + CALL FMI2M(10,MB) + CALL FMIPWR(MB,-44,ME) + CALL FMEQ(ME,MB) + IF (.NOT.FMCOMP(MA,'LE',MB)) THEN + CALL ERRPRTZM('ZMFORM',ZA,'ZA',ZC,'ZC',ZD,'ZD', & + NCASE,NERROR,KLOG) + ENDIF + + RETURN + END SUBROUTINE TEST16 + + SUBROUTINE TEST17(STZ1,STZ2,NCASE,NERROR,KLOG) + +! Test complex add and subtract. + + USE FMVALS + USE FMZM + USE TEST_VARS + + IMPLICIT NONE + + LOGICAL FMCOMP + + CHARACTER(160) :: STZ1,STZ2 + INTEGER KLOG,NCASE,NERROR + + WRITE (KW,"(/' Testing complex add and subtract routines.')") + + NCASE = 117 + CALL ZMST2M('123 + 456 i',ZA) + CALL ZMST2M('789 - 543 i',ZB) + CALL ZMADD(ZA,ZB,ZE) + CALL ZMEQ(ZE,ZA) + CALL ZM2I2M(912,-87,ZC) + CALL ZMSUB(ZA,ZC,ZD) + CALL ZMABS(ZD,MA) + CALL FMI2M(0,MB) + IF (.NOT.FMCOMP(MA,'LE',MB)) THEN + CALL ERRPRTZM('ZMADD ',ZA,'ZA',ZC,'ZC',ZD,'ZD', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 118 + STZ1 = '.7699115044247787610619469026548672566371681415929204 ' & + //'- .5221238938053097345132743362831858407079646017699115 i' + CALL ZMST2M(STZ1,ZA) + STZ1 = '.3505154639175257731958762886597938144329896907216495 ' & + //'+ .7319587628865979381443298969072164948453608247422680 i' + CALL ZMST2M(STZ1,ZB) + CALL ZMADD(ZA,ZB,ZE) + CALL ZMEQ(ZE,ZA) + STZ2 = '1.1204269683423045342578231913146610710701578323145698 ' & + //'+ 0.2098348690812882036310555606240306541373962229723565 i' + CALL ZMST2M(STZ2,ZC) + CALL ZMSUB(ZA,ZC,ZD) + CALL ZMABS(ZD,MA) + CALL FMI2M(10,MB) + CALL FMIPWR(MB,-49,ME) + CALL FMEQ(ME,MB) + IF (.NOT.FMCOMP(MA,'LE',MB)) THEN + CALL ERRPRTZM('ZMADD ',ZA,'ZA',ZC,'ZC',ZD,'ZD', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 119 + STZ1 = '.7699115044247787610619469026548672566371681415929204 ' & + //'- .5221238938053097345132743362831858407079646017699115 i' + CALL ZMST2M(STZ1,ZA) + STZ1 = '.3505154639175257731958762886597938144329896907216495 ' & + //'+ .7319587628865979381443298969072164948453608247422680 i' + CALL ZMST2M(STZ1,ZB) + CALL ZMSUB(ZA,ZB,ZE) + CALL ZMEQ(ZE,ZA) + STZ2 = '0.4193960405072529878660706139950734422041784508712709 ' & + //'- 1.2540826566919076726576042331904023355533254265121795 i' + CALL ZMST2M(STZ2,ZC) + CALL ZMSUB(ZA,ZC,ZD) + CALL ZMABS(ZD,MA) + CALL FMI2M(10,MB) + CALL FMIPWR(MB,-49,ME) + CALL FMEQ(ME,MB) + IF (.NOT.FMCOMP(MA,'LE',MB)) THEN + CALL ERRPRTZM('ZMSUB ',ZA,'ZA',ZC,'ZC',ZD,'ZD', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 120 + STZ1 = '.7699115044247787610619469026548672566371681415929204E3 ' & + //'- .5221238938053097345132743362831858407079646017699115E3 i' + CALL ZMST2M(STZ1,ZA) + STZ1 = '.3505154639175257731958762886597938144329896907216495 ' & + //'+ .7319587628865979381443298969072164948453608247422680 i' + CALL ZMST2M(STZ1,ZB) + CALL ZMSUB(ZA,ZB,ZE) + CALL ZMEQ(ZE,ZA) + STZ2 = '769.5609889608612352887510263662074628227351519021987045 ' & + //'- 522.8558525681963324514186661800930572028099625946537725 i' + CALL ZMST2M(STZ2,ZC) + CALL ZMSUB(ZA,ZC,ZD) + CALL ZMABS(ZD,MA) + CALL FMI2M(10,MB) + CALL FMIPWR(MB,-47,ME) + CALL FMEQ(ME,MB) + IF (.NOT.FMCOMP(MA,'LE',MB)) THEN + CALL ERRPRTZM('ZMSUB ',ZA,'ZA',ZC,'ZC',ZD,'ZD', & + NCASE,NERROR,KLOG) + ENDIF + + RETURN + END SUBROUTINE TEST17 + + SUBROUTINE TEST18(STZ1,STZ2,NCASE,NERROR,KLOG) + +! Test complex multiply, divide and square root. + + USE FMVALS + USE FMZM + USE TEST_VARS + + IMPLICIT NONE + + LOGICAL FMCOMP + + CHARACTER(160) :: STZ1,STZ2 + INTEGER KLOG,NCASE,NERROR + + WRITE (KW, & + "(/' Testing complex multiply, divide and square root routines.')") + + NCASE = 121 + CALL ZMST2M('123 + 456 i',ZA) + CALL ZMST2M('789 - 543 i',ZB) + CALL ZMMPY(ZA,ZB,ZE) + CALL ZMEQ(ZE,ZA) + CALL ZM2I2M(344655,292995,ZC) + CALL ZMSUB(ZA,ZC,ZD) + CALL ZMABS(ZD,MA) + CALL FMI2M(0,MB) + IF (.NOT.FMCOMP(MA,'LE',MB)) THEN + CALL ERRPRTZM('ZMMPY ',ZA,'ZA',ZC,'ZC',ZD,'ZD', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 122 + STZ1 = '.7699115044247787610619469026548672566371681415929204 ' & + //'- .5221238938053097345132743362831858407079646017699115 i' + CALL ZMST2M(STZ1,ZA) + STZ1 = '.3505154639175257731958762886597938144329896907216495 ' & + //'+ .7319587628865979381443298969072164948453608247422680 i' + CALL ZMST2M(STZ1,ZB) + CALL ZMMPY(ZA,ZB,ZE) + CALL ZMEQ(ZE,ZA) + STZ2 = '0.6520390475321594745005017790347596022260742632971444 ' & + //'+ 0.3805309734513274336283185840707964601769911504424779 i' + CALL ZMST2M(STZ2,ZC) + CALL ZMSUB(ZA,ZC,ZD) + CALL ZMABS(ZD,MA) + CALL FMI2M(10,MB) + CALL FMIPWR(MB,-50,ME) + CALL FMEQ(ME,MB) + IF (.NOT.FMCOMP(MA,'LE',MB)) THEN + CALL ERRPRTZM('ZMMPY ',ZA,'ZA',ZC,'ZC',ZD,'ZD', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 123 + STZ1 = '.7699115044247787610619469026548672566371681415929204 ' & + //'- .5221238938053097345132743362831858407079646017699115 i' + CALL ZMST2M(STZ1,ZA) + STZ1 = '.3505154639175257731958762886597938144329896907216495 ' & + //'+ .7319587628865979381443298969072164948453608247422680 i' + CALL ZMST2M(STZ1,ZB) + CALL ZMDIV(ZA,ZB,ZE) + CALL ZMEQ(ZE,ZA) + STZ2 = '-.1705178497731560089737969128653459210208765017614861 ' & + //'- 1.1335073636829696356072949942949842987114804337239972 i' + CALL ZMST2M(STZ2,ZC) + CALL ZMSUB(ZA,ZC,ZD) + CALL ZMABS(ZD,MA) + CALL FMI2M(10,MB) + CALL FMIPWR(MB,-49,ME) + CALL FMEQ(ME,MB) + IF (.NOT.FMCOMP(MA,'LE',MB)) THEN + CALL ERRPRTZM('ZMDIV ',ZA,'ZA',ZC,'ZC',ZD,'ZD', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 124 + STZ1 = '.7699115044247787610619469026548672566371681415929204 ' & + //'- .5221238938053097345132743362831858407079646017699115 i' + CALL ZMST2M(STZ1,ZA) + CALL ZMMPYI(ZA,36,ZE) + CALL ZMEQ(ZE,ZA) + STZ2 = '27.7168141592920353982300884955752212389380530973451327 ' & + //'- 18.7964601769911504424778761061946902654867256637168142 i' + CALL ZMST2M(STZ2,ZC) + CALL ZMSUB(ZA,ZC,ZD) + CALL ZMABS(ZD,MA) + CALL FMI2M(10,MB) + CALL FMIPWR(MB,-48,ME) + CALL FMEQ(ME,MB) + IF (.NOT.FMCOMP(MA,'LE',MB)) THEN + CALL ERRPRTZM('ZMMPYI',ZA,'ZA',ZC,'ZC',ZD,'ZD', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 125 + STZ1 = '.7699115044247787610619469026548672566371681415929204 ' & + //'- .5221238938053097345132743362831858407079646017699115 i' + CALL ZMST2M(STZ1,ZA) + CALL ZMDIVI(ZA,37,ZE) + CALL ZMEQ(ZE,ZA) + STZ2 = '2.080841903850753408275532169337479071992346328629514E-2 ' & + //'- 1.411145658933269552738579287251853623535039464243004E-2 i' + CALL ZMST2M(STZ2,ZC) + CALL ZMSUB(ZA,ZC,ZD) + CALL ZMABS(ZD,MA) + CALL FMI2M(10,MB) + CALL FMIPWR(MB,-52,ME) + CALL FMEQ(ME,MB) + IF (.NOT.FMCOMP(MA,'LE',MB)) THEN + CALL ERRPRTZM('ZMDIVI',ZA,'ZA',ZC,'ZC',ZD,'ZD', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 126 + STZ1 = '.7699115044247787610619469026548672566371681415929204 ' & + //'- .5221238938053097345132743362831858407079646017699115 i' + CALL ZMST2M(STZ1,ZA) + CALL ZMSQR(ZA,ZE) + CALL ZMEQ(ZE,ZA) + STZ2 = '0.3201503641632077688150990680554467851828647505677813 ' & + //'- 0.8039783851515388832328295089670295246299631921058814 i' + CALL ZMST2M(STZ2,ZC) + CALL ZMSUB(ZA,ZC,ZD) + CALL ZMABS(ZD,MA) + CALL FMI2M(10,MB) + CALL FMIPWR(MB,-50,ME) + CALL FMEQ(ME,MB) + IF (.NOT.FMCOMP(MA,'LE',MB)) THEN + CALL ERRPRTZM('ZMSQR ',ZA,'ZA',ZC,'ZC',ZD,'ZD', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 127 + STZ1 = '.7699115044247787610619469026548672566371681415929204 ' & + //'- .5221238938053097345132743362831858407079646017699115 i' + CALL ZMST2M(STZ1,ZA) + CALL ZMSQRT(ZA,ZE) + CALL ZMEQ(ZE,ZA) + STZ2 = '0.9219999909012323458336720551458583330580388434229845 ' & + //'- 0.2831474506279259570386845864488094697732718981999941 i' + CALL ZMST2M(STZ2,ZC) + CALL ZMSUB(ZA,ZC,ZD) + CALL ZMABS(ZD,MA) + CALL FMI2M(10,MB) + CALL FMIPWR(MB,-50,ME) + CALL FMEQ(ME,MB) + IF (.NOT.FMCOMP(MA,'LE',MB)) THEN + CALL ERRPRTZM('ZMSQRT',ZA,'ZA',ZC,'ZC',ZD,'ZD', & + NCASE,NERROR,KLOG) + ENDIF + + RETURN + END SUBROUTINE TEST18 + + SUBROUTINE TEST19(STZ1,STZ2,NCASE,NERROR,KLOG) + +! Test complex exponentials. + + USE FMVALS + USE FMZM + USE TEST_VARS + + IMPLICIT NONE + + LOGICAL FMCOMP + + CHARACTER(160) :: STZ1,STZ2 + INTEGER KLOG,NCASE,NERROR + + WRITE (KW,"(/' Testing complex exponential routines.')") + + NCASE = 128 + STZ1 = '.7699115044247787610619469026548672566371681415929204 ' & + //'- .5221238938053097345132743362831858407079646017699115 i' + CALL ZMST2M(STZ1,ZA) + CALL ZMEXP(ZA,ZE) + CALL ZMEQ(ZE,ZA) + STZ2 = '1.8718374504057787925867989348073888855260008469310002 ' & + //'- 1.0770279996847678711699041910427261417963102075889234 i' + CALL ZMST2M(STZ2,ZC) + CALL ZMSUB(ZA,ZC,ZD) + CALL ZMABS(ZD,MA) + CALL FMI2M(10,MB) + CALL FMIPWR(MB,-49,ME) + CALL FMEQ(ME,MB) + IF (.NOT.FMCOMP(MA,'LE',MB)) THEN + CALL ERRPRTZM('ZMEXP ',ZA,'ZA',ZC,'ZC',ZD,'ZD', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 129 + STZ1 = '5.7699115044247787610619469026548672566371681415929204 ' & + //'- 4.5221238938053097345132743362831858407079646017699115 i' + CALL ZMST2M(STZ1,ZA) + CALL ZMEXP(ZA,ZE) + CALL ZMEQ(ZE,ZA) + STZ2 = '-60.6144766542152809520229386164396710991242264070603612 ' & + //'+ 314.7254994809539691403004121118801578835669635535466592 i' + CALL ZMST2M(STZ2,ZC) + CALL ZMSUB(ZA,ZC,ZD) + CALL ZMABS(ZD,MA) + CALL FMI2M(10,MB) + CALL FMIPWR(MB,-47,ME) + CALL FMEQ(ME,MB) + IF (.NOT.FMCOMP(MA,'LE',MB)) THEN + CALL ERRPRTZM('ZMEXP ',ZA,'ZA',ZC,'ZC',ZD,'ZD', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 130 + STZ1 = '1.7699115044247787610619469026548672566371681415929204 ' & + //'- 1.5221238938053097345132743362831858407079646017699115 i' + CALL ZMST2M(STZ1,ZA) + CALL ZMIPWR(ZA,45,ZE) + CALL ZMEQ(ZE,ZA) + STZ2 = '31595668743300099.70429472191424818167262151605608585179 ' & + //'- 19209634448276799.67717448173630165852744930837930753788 i' + CALL ZMST2M(STZ2,ZC) + CALL ZMSUB(ZA,ZC,ZD) + CALL ZMABS(ZD,MA) + CALL FMI2M(10,MB) + CALL FMIPWR(MB,-33,ME) + CALL FMEQ(ME,MB) + IF (.NOT.FMCOMP(MA,'LE',MB)) THEN + CALL ERRPRTZM('ZMIPWR',ZA,'ZA',ZC,'ZC',ZD,'ZD', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 131 + STZ1 = '1.7699115044247787610619469026548672566371681415929204 ' & + //'- 1.5221238938053097345132743362831858407079646017699115 i' + CALL ZMST2M(STZ1,ZA) + CALL ZMIPWR(ZA,-122,ZE) + CALL ZMEQ(ZE,ZA) + STZ2 = '3.1000215641022021714480000129414241564868699479432E-46 ' & + //'- 1.1687846789859477815450163510927243367234863123667E-45 i' + CALL ZMST2M(STZ2,ZC) + CALL ZMSUB(ZA,ZC,ZD) + CALL ZMABS(ZD,MA) + CALL FMI2M(10,MB) + CALL FMIPWR(MB,-93,ME) + CALL FMEQ(ME,MB) + IF (.NOT.FMCOMP(MA,'LE',MB)) THEN + CALL ERRPRTZM('ZMIPWR',ZA,'ZA',ZC,'ZC',ZD,'ZD', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 132 + STZ1 = '.7699115044247787610619469026548672566371681415929204 ' & + //'- .5221238938053097345132743362831858407079646017699115 i' + CALL ZMST2M(STZ1,ZA) + STZ1 = '.3505154639175257731958762886597938144329896907216495 ' & + //'+ .7319587628865979381443298969072164948453608247422680 i' + CALL ZMST2M(STZ1,ZB) + CALL ZMPWR(ZA,ZB,ZE) + CALL ZMEQ(ZE,ZA) + STZ2 = '1.4567089343012352449621841355636496276866203747888724 ' & + //'- 0.3903177712261966292764255714390622205129978923650749 i' + CALL ZMST2M(STZ2,ZC) + CALL ZMSUB(ZA,ZC,ZD) + CALL ZMABS(ZD,MA) + CALL FMI2M(10,MB) + CALL FMIPWR(MB,-49,ME) + CALL FMEQ(ME,MB) + IF (.NOT.FMCOMP(MA,'LE',MB)) THEN + CALL ERRPRTZM('ZMPWR ',ZA,'ZA',ZC,'ZC',ZD,'ZD', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 133 + STZ1 = '.3505154639175257731958762886597938144329896907216495 ' & + //'+ .7319587628865979381443298969072164948453608247422680 i' + CALL ZMST2M(STZ1,ZA) + STZ1 = '2.7699115044247787610619469026548672566371681415929204 ' & + //'- 0.5221238938053097345132743362831858407079646017699115 i' + CALL ZMST2M(STZ1,ZB) + CALL ZMPWR(ZA,ZB,ZE) + CALL ZMEQ(ZE,ZA) + STZ2 = '-1.0053105716678380336247948739245187868180079734997482 ' & + // '- 0.0819537653234704467729051473979237153087038930127116 i' + CALL ZMST2M(STZ2,ZC) + CALL ZMSUB(ZA,ZC,ZD) + CALL ZMABS(ZD,MA) + CALL FMI2M(10,MB) + CALL FMIPWR(MB,-49,ME) + CALL FMEQ(ME,MB) + IF (.NOT.FMCOMP(MA,'LE',MB)) THEN + CALL ERRPRTZM('ZMPWR ',ZA,'ZA',ZC,'ZC',ZD,'ZD', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 134 + STZ1 = '0.7699115044247787610619469026548672566371681415929204 ' & + //'- 0.5221238938053097345132743362831858407079646017699115 i' + CALL ZMST2M(STZ1,ZA) + CALL ZMRPWR(ZA,2,7,ZE) + CALL ZMEQ(ZE,ZA) + STZ2 = '0.9653921326136512316639621651337975772631340364271270 ' & + //'- 0.1659768285667051396562270035411852432430188906482848 i' + CALL ZMST2M(STZ2,ZC) + CALL ZMSUB(ZA,ZC,ZD) + CALL ZMABS(ZD,MA) + CALL FMI2M(10,MB) + CALL FMIPWR(MB,-50,ME) + CALL FMEQ(ME,MB) + IF (.NOT.FMCOMP(MA,'LE',MB)) THEN + CALL ERRPRTZM('ZMRPWR',ZA,'ZA',ZC,'ZC',ZD,'ZD', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 135 + STZ1 = '0.7699115044247787610619469026548672566371681415929204 ' & + //'- 0.5221238938053097345132743362831858407079646017699115 i' + CALL ZMST2M(STZ1,ZA) + CALL ZMRPWR(ZA,-19,7,ZE) + CALL ZMEQ(ZE,ZA) + STZ2 = '-0.0567985880053556315170006800325686036902111276420647 ' & + // '+ 1.2154793972711356706410882510363594270389067962568571 i' + CALL ZMST2M(STZ2,ZC) + CALL ZMSUB(ZA,ZC,ZD) + CALL ZMABS(ZD,MA) + CALL FMI2M(10,MB) + CALL FMIPWR(MB,-49,ME) + CALL FMEQ(ME,MB) + IF (.NOT.FMCOMP(MA,'LE',MB)) THEN + CALL ERRPRTZM('ZMRPWR',ZA,'ZA',ZC,'ZC',ZD,'ZD', & + NCASE,NERROR,KLOG) + ENDIF + + RETURN + END SUBROUTINE TEST19 + + SUBROUTINE TEST20(STZ1,STZ2,NCASE,NERROR,KLOG) + +! Test complex logarithms. + + USE FMVALS + USE FMZM + USE TEST_VARS + + IMPLICIT NONE + + LOGICAL FMCOMP + + CHARACTER(160) :: STZ1,STZ2 + INTEGER KLOG,NCASE,NERROR + + WRITE (KW,"(/' Testing complex logarithm routines.')") + + NCASE = 136 + STZ1 = '.7699115044247787610619469026548672566371681415929204 ' & + //'- .5221238938053097345132743362831858407079646017699115 i' + CALL ZMST2M(STZ1,ZA) + CALL ZMLN(ZA,ZE) + CALL ZMEQ(ZE,ZA) + STZ2 = '-0.0722949652393911311212450699415231782692434885813725 ' & + //'- 0.5959180055163009910007765127008371205749515965219804 i' + CALL ZMST2M(STZ2,ZC) + CALL ZMSUB(ZA,ZC,ZD) + CALL ZMABS(ZD,MA) + CALL FMI2M(10,MB) + CALL FMIPWR(MB,-50,ME) + CALL FMEQ(ME,MB) + IF (.NOT.FMCOMP(MA,'LE',MB)) THEN + CALL ERRPRTZM('ZMLN ',ZA,'ZA',ZC,'ZC',ZD,'ZD', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 137 + STZ1 = '.7699115044247787610619469026548672566371681415929204E28 ' & + //'- .5221238938053097345132743362831858407079646017699115E28 i' + CALL ZMST2M(STZ1,ZA) + CALL ZMLN(ZA,ZE) + CALL ZMEQ(ZE,ZA) + STZ2 = '64.4000876385938880213825156612206746345615981930242708 ' & + //'- 0.5959180055163009910007765127008371205749515965219804 i' + CALL ZMST2M(STZ2,ZC) + CALL ZMSUB(ZA,ZC,ZD) + CALL ZMABS(ZD,MA) + CALL FMI2M(10,MB) + CALL FMIPWR(MB,-48,ME) + CALL FMEQ(ME,MB) + IF (.NOT.FMCOMP(MA,'LE',MB)) THEN + CALL ERRPRTZM('ZMLN ',ZA,'ZA',ZC,'ZC',ZD,'ZD', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 138 + STZ1 = '.7699115044247787610619469026548672566371681415929204 ' & + //'- .5221238938053097345132743362831858407079646017699115 i' + CALL ZMST2M(STZ1,ZA) + CALL ZMLG10(ZA,ZE) + CALL ZMEQ(ZE,ZA) + STZ2 = '-0.0313973044728549715287589498363619677438302809470943 ' & + //'- 0.2588039014625211035392823012785304771809982053965284 i' + CALL ZMST2M(STZ2,ZC) + CALL ZMSUB(ZA,ZC,ZD) + CALL ZMABS(ZD,MA) + CALL FMI2M(10,MB) + CALL FMIPWR(MB,-50,ME) + CALL FMEQ(ME,MB) + IF (.NOT.FMCOMP(MA,'LE',MB)) THEN + CALL ERRPRTZM('ZMLG10',ZA,'ZA',ZC,'ZC',ZD,'ZD', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 139 + STZ1 = '.7699115044247787610619469026548672566371681415929204E82 ' & + //'- .5221238938053097345132743362831858407079646017699115E82 i' + CALL ZMST2M(STZ1,ZA) + CALL ZMLG10(ZA,ZE) + CALL ZMEQ(ZE,ZA) + STZ2 = '81.9686026955271450284712410501636380322561697190529057 ' & + //'- 0.2588039014625211035392823012785304771809982053965284 i' + CALL ZMST2M(STZ2,ZC) + CALL ZMSUB(ZA,ZC,ZD) + CALL ZMABS(ZD,MA) + CALL FMI2M(10,MB) + CALL FMIPWR(MB,-48,ME) + CALL FMEQ(ME,MB) + IF (.NOT.FMCOMP(MA,'LE',MB)) THEN + CALL ERRPRTZM('ZMLG10',ZA,'ZA',ZC,'ZC',ZD,'ZD', & + NCASE,NERROR,KLOG) + ENDIF + + RETURN + END SUBROUTINE TEST20 + + SUBROUTINE TEST21(STZ1,STZ2,NCASE,NERROR,KLOG) + +! Test complex trigonometric functions. + + USE FMVALS + USE FMZM + USE TEST_VARS + + IMPLICIT NONE + + LOGICAL FMCOMP + + CHARACTER(160) :: STZ1,STZ2 + INTEGER KLOG,NCASE,NERROR + + WRITE (KW,"(/' Testing complex trigonometric routines.')") + + NCASE = 140 + STZ1 = '.7699115044247787610619469026548672566371681415929204 ' & + //'- .5221238938053097345132743362831858407079646017699115 i' + CALL ZMST2M(STZ1,ZA) + CALL ZMCOS(ZA,ZE) + CALL ZMEQ(ZE,ZA) + STZ2 = '0.8180802525254482451348613286211514555816444253416895 ' & + //'+ 0.3801751200076938035500853542125525088505055292851393 i' + CALL ZMST2M(STZ2,ZC) + CALL ZMSUB(ZA,ZC,ZD) + CALL ZMABS(ZD,MA) + CALL FMI2M(10,MB) + CALL FMIPWR(MB,-50,ME) + CALL FMEQ(ME,MB) + IF (.NOT.FMCOMP(MA,'LE',MB)) THEN + CALL ERRPRTZM('ZMCOS ',ZA,'ZA',ZC,'ZC',ZD,'ZD', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 141 + STZ1 = '34.7699115044247787610619469026548672566371681415929204 ' & + //'- 42.5221238938053097345132743362831858407079646017699115 i' + CALL ZMST2M(STZ1,ZA) + CALL ZMCOS(ZA,ZE) + CALL ZMEQ(ZE,ZA) + STZ2 = '-1432925478410268113.5816466154230974355002592549420099 ' & + //'- 309002816679456015.00151246245263842483282458519462258 i' + CALL ZMST2M(STZ2,ZC) + CALL ZMSUB(ZA,ZC,ZD) + CALL ZMABS(ZD,MA) + CALL FMI2M(10,MB) + CALL FMIPWR(MB,-31,ME) + CALL FMEQ(ME,MB) + IF (.NOT.FMCOMP(MA,'LE',MB)) THEN + CALL ERRPRTZM('ZMCOS ',ZA,'ZA',ZC,'ZC',ZD,'ZD', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 142 + STZ1 = '.7699115044247787610619469026548672566371681415929204 ' & + //'- .5221238938053097345132743362831858407079646017699115 i' + CALL ZMST2M(STZ1,ZA) + CALL ZMSIN(ZA,ZE) + CALL ZMEQ(ZE,ZA) + STZ2 = '0.7931260548991613428648822413402447097755865697557818 ' & + //'- 0.3921366045897070762848927655743167937790944353110710 i' + CALL ZMST2M(STZ2,ZC) + CALL ZMSUB(ZA,ZC,ZD) + CALL ZMABS(ZD,MA) + CALL FMI2M(10,MB) + CALL FMIPWR(MB,-50,ME) + CALL FMEQ(ME,MB) + IF (.NOT.FMCOMP(MA,'LE',MB)) THEN + CALL ERRPRTZM('ZMSIN ',ZA,'ZA',ZC,'ZC',ZD,'ZD', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 143 + STZ1 = '34.7699115044247787610619469026548672566371681415929204 ' & + //'- 42.5221238938053097345132743362831858407079646017699115 i' + CALL ZMST2M(STZ1,ZA) + CALL ZMSIN(ZA,ZE) + CALL ZMEQ(ZE,ZA) + STZ2 = '-3.090028166794560150015124624526384249047272360765358E17 ' & + //'+ 1.432925478410268113581646615423097435166828182950161E18 i' + CALL ZMST2M(STZ2,ZC) + CALL ZMSUB(ZA,ZC,ZD) + CALL ZMABS(ZD,MA) + CALL FMI2M(10,MB) + CALL FMIPWR(MB,-31,ME) + CALL FMEQ(ME,MB) + IF (.NOT.FMCOMP(MA,'LE',MB)) THEN + CALL ERRPRTZM('ZMSIN ',ZA,'ZA',ZC,'ZC',ZD,'ZD', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 144 + STZ1 = '.7699115044247787610619469026548672566371681415929204 ' & + //'- .5221238938053097345132743362831858407079646017699115 i' + CALL ZMST2M(STZ1,ZA) + CALL ZMTAN(ZA,ZE) + CALL ZMEQ(ZE,ZA) + STZ2 = '0.6141156219447569167198437040270236055089243090199979 ' & + //'- 0.7647270337230070156308196055474639461102792169274526 i' + CALL ZMST2M(STZ2,ZC) + CALL ZMSUB(ZA,ZC,ZD) + CALL ZMABS(ZD,MA) + CALL FMI2M(10,MB) + CALL FMIPWR(MB,-50,ME) + CALL FMEQ(ME,MB) + IF (.NOT.FMCOMP(MA,'LE',MB)) THEN + CALL ERRPRTZM('ZMTAN ',ZA,'ZA',ZC,'ZC',ZD,'ZD', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 145 + STZ1 = '35.7699115044247787610619469026548672566371681415929204 ' & + //'- 43.5221238938053097345132743362831858407079646017699115 i' + CALL ZMST2M(STZ1,ZA) + CALL ZMTAN(ZA,ZE) + CALL ZMEQ(ZE,ZA) + STZ2 = '2.068934241218867332441292427642153175237611151321340E-38 ' & + //'- 1.000000000000000000000000000000000000023741659169354 i' + CALL ZMST2M(STZ2,ZC) + CALL ZMSUB(ZA,ZC,ZD) + CALL ZMABS(ZD,MA) + CALL FMI2M(10,MB) + CALL FMIPWR(MB,-49,ME) + CALL FMEQ(ME,MB) + IF (.NOT.FMCOMP(MA,'LE',MB)) THEN + CALL ERRPRTZM('ZMTAN ',ZA,'ZA',ZC,'ZC',ZD,'ZD', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 146 + STZ1 = '0.3505154639175257731958762886597938144329896907216495 ' & + //'+ 0.7319587628865979381443298969072164948453608247422680 i' + CALL ZMST2M(STZ1,ZA) + CALL ZMCSSN(ZA,ZE,ZC) + CALL ZMEQ(ZE,ZA) + STZ2 = '1.2022247452809115256533054407001508718694617802593324 ' & + //'- 0.2743936538120352873902095801531325075994392065668943 i' + CALL ZMST2M(STZ2,ZC) + CALL ZMSUB(ZA,ZC,ZD) + CALL ZMABS(ZD,MA) + CALL FMI2M(10,MB) + CALL FMIPWR(MB,-49,ME) + CALL FMEQ(ME,MB) + IF (.NOT.FMCOMP(MA,'LE',MB)) THEN + CALL ERRPRTZM('ZMCSSN',ZA,'ZA',ZC,'ZC',ZD,'ZD', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 147 + STZ1 = '0.3505154639175257731958762886597938144329896907216495 ' & + //'+ 0.7319587628865979381443298969072164948453608247422680 i' + CALL ZMST2M(STZ1,ZA) + CALL ZMCSSN(ZA,ZC,ZE) + CALL ZMEQ(ZE,ZA) + STZ2 = '0.4395486978082638069281369170831952476351663772871008 ' & + //'+ 0.7505035100906417134864779281080728222900154610025883 i' + CALL ZMST2M(STZ2,ZC) + CALL ZMSUB(ZA,ZC,ZD) + CALL ZMABS(ZD,MA) + CALL FMI2M(10,MB) + CALL FMIPWR(MB,-50,ME) + CALL FMEQ(ME,MB) + IF (.NOT.FMCOMP(MA,'LE',MB)) THEN + CALL ERRPRTZM('ZMCSSN',ZA,'ZA',ZC,'ZC',ZD,'ZD', & + NCASE,NERROR,KLOG) + ENDIF + + RETURN + END SUBROUTINE TEST21 + + SUBROUTINE TEST22(STZ1,STZ2,NCASE,NERROR,KLOG) + +! Test complex inverse trigonometric functions. + + USE FMVALS + USE FMZM + USE TEST_VARS + + IMPLICIT NONE + + LOGICAL FMCOMP + + CHARACTER(160) :: STZ1,STZ2 + INTEGER KLOG,NCASE,NERROR + + WRITE (KW,"(/' Testing complex inverse trigonometric routines.')") + + NCASE = 148 + STZ1 = '.7699115044247787610619469026548672566371681415929204 ' & + //'- .5221238938053097345132743362831858407079646017699115 i' + CALL ZMST2M(STZ1,ZA) + CALL ZMACOS(ZA,ZE) + CALL ZMEQ(ZE,ZA) + STZ2 = '0.8797127900868121872960714368309657795959216549012347 ' & + //'+ 0.6342141347945396859119941874681961111936156338608130 i' + CALL ZMST2M(STZ2,ZC) + CALL ZMSUB(ZA,ZC,ZD) + CALL ZMABS(ZD,MA) + CALL FMI2M(10,MB) + CALL FMIPWR(MB,-50,ME) + CALL FMEQ(ME,MB) + IF (.NOT.FMCOMP(MA,'LE',MB)) THEN + CALL ERRPRTZM('ZMACOS',ZA,'ZA',ZC,'ZC',ZD,'ZD', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 149 + STZ1 = '.7699115044247787610619469026548672566371681415929204E12 ' & + //'- .5221238938053097345132743362831858407079646017699115E12 i' + CALL ZMST2M(STZ1,ZA) + CALL ZMACOS(ZA,ZE) + CALL ZMEQ(ZE,ZA) + STZ2 = '0.5959180055163009910007767810953294528367807973983794 ' & + //'+28.2518733312491023865118844008522768856672089946951468 i' + CALL ZMST2M(STZ2,ZC) + CALL ZMSUB(ZA,ZC,ZD) + CALL ZMABS(ZD,MA) + CALL FMI2M(10,MB) + CALL FMIPWR(MB,-48,ME) + CALL FMEQ(ME,MB) + IF (.NOT.FMCOMP(MA,'LE',MB)) THEN + CALL ERRPRTZM('ZMACOS',ZA,'ZA',ZC,'ZC',ZD,'ZD', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 150 + STZ1 = '.7699115044247787610619469026548672566371681415929204 ' & + //'- .5221238938053097345132743362831858407079646017699115 i' + CALL ZMST2M(STZ1,ZA) + CALL ZMASIN(ZA,ZE) + CALL ZMEQ(ZE,ZA) + STZ2 = '0.6910835367080844319352502548087856625026630447863182 ' & + //'- 0.6342141347945396859119941874681961111936156338608130 i' + CALL ZMST2M(STZ2,ZC) + CALL ZMSUB(ZA,ZC,ZD) + CALL ZMABS(ZD,MA) + CALL FMI2M(10,MB) + CALL FMIPWR(MB,-50,ME) + CALL FMEQ(ME,MB) + IF (.NOT.FMCOMP(MA,'LE',MB)) THEN + CALL ERRPRTZM('ZMASIN',ZA,'ZA',ZC,'ZC',ZD,'ZD', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 151 + STZ1 = '.7699115044247787610619469026548672566371681415929204E13 ' & + //'- .5221238938053097345132743362831858407079646017699115E13 i' + CALL ZMST2M(STZ1,ZA) + CALL ZMASIN(ZA,ZE) + CALL ZMEQ(ZE,ZA) + STZ2 = '0.9748783212785956282305451762549693982010148111568094 ' & + //'-30.5544584242431480705298759613446206186670533428066404 i' + CALL ZMST2M(STZ2,ZC) + CALL ZMSUB(ZA,ZC,ZD) + CALL ZMABS(ZD,MA) + CALL FMI2M(10,MB) + CALL FMIPWR(MB,-48,ME) + CALL FMEQ(ME,MB) + IF (.NOT.FMCOMP(MA,'LE',MB)) THEN + CALL ERRPRTZM('ZMASIN',ZA,'ZA',ZC,'ZC',ZD,'ZD', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 152 + STZ1 = '.7699115044247787610619469026548672566371681415929204 ' & + //'- .5221238938053097345132743362831858407079646017699115 i' + CALL ZMST2M(STZ1,ZA) + CALL ZMATAN(ZA,ZE) + CALL ZMEQ(ZE,ZA) + STZ2 = '0.7417952692265900376512911713942700568648670953521258 ' & + //'- 0.3162747143126729004878357203292329539837025170484857 i' + CALL ZMST2M(STZ2,ZC) + CALL ZMSUB(ZA,ZC,ZD) + CALL ZMABS(ZD,MA) + CALL FMI2M(10,MB) + CALL FMIPWR(MB,-50,ME) + CALL FMEQ(ME,MB) + IF (.NOT.FMCOMP(MA,'LE',MB)) THEN + CALL ERRPRTZM('ZMATAN',ZA,'ZA',ZC,'ZC',ZD,'ZD', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 153 + STZ1 = '.7699115044247787610619469026548672566371681415929204E13 ' & + //'- .5221238938053097345132743362831858407079646017699115E13 i' + CALL ZMST2M(STZ1,ZA) + CALL ZMATAN(ZA,ZE) + CALL ZMEQ(ZE,ZA) + STZ2 = ' 1.570796326794807650905529836436131532596233124329403 ' & + //'-6.033484162895927601809954710695221401671437742867605E-14 i' + CALL ZMST2M(STZ2,ZC) + CALL ZMSUB(ZA,ZC,ZD) + CALL ZMABS(ZD,MA) + CALL FMI2M(10,MB) + CALL FMIPWR(MB,-49,ME) + CALL FMEQ(ME,MB) + IF (.NOT.FMCOMP(MA,'LE',MB)) THEN + CALL ERRPRTZM('ZMATAN',ZA,'ZA',ZC,'ZC',ZD,'ZD', & + NCASE,NERROR,KLOG) + ENDIF + + RETURN + END SUBROUTINE TEST22 + + SUBROUTINE TEST23(STZ1,STZ2,NCASE,NERROR,KLOG) + +! Test complex hyperbolic functions. + + USE FMVALS + USE FMZM + USE TEST_VARS + + IMPLICIT NONE + + LOGICAL FMCOMP + + CHARACTER(160) :: STZ1,STZ2 + INTEGER KLOG,NCASE,NERROR + + WRITE (KW,"(/' Testing complex hyperbolic routines.')") + + NCASE = 154 + STZ1 = '.7699115044247787610619469026548672566371681415929204 ' & + //'- .5221238938053097345132743362831858407079646017699115 i' + CALL ZMST2M(STZ1,ZA) + CALL ZMCOSH(ZA,ZE) + CALL ZMEQ(ZE,ZA) + STZ2 = '1.1365975275870879962259716562608779977957563621412079 ' & + //'- 0.4230463404769118342540441830446134405410543954181579 i' + CALL ZMST2M(STZ2,ZC) + CALL ZMSUB(ZA,ZC,ZD) + CALL ZMABS(ZD,MA) + CALL FMI2M(10,MB) + CALL FMIPWR(MB,-49,ME) + CALL FMEQ(ME,MB) + IF (.NOT.FMCOMP(MA,'LE',MB)) THEN + CALL ERRPRTZM('ZMCOSH',ZA,'ZA',ZC,'ZC',ZD,'ZD', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 155 + STZ1 = '34.7699115044247787610619469026548672566371681415929204 ' & + //'- 42.5221238938053097345132743362831858407079646017699115 i' + CALL ZMST2M(STZ1,ZA) + CALL ZMCOSH(ZA,ZE) + CALL ZMEQ(ZE,ZA) + STZ2 = '69552104658681.7558589320148420094288419217262200765435 ' & + //'+ 626163773308016.884007302915197616300902876551542156676 i' + CALL ZMST2M(STZ2,ZC) + CALL ZMSUB(ZA,ZC,ZD) + CALL ZMABS(ZD,MA) + CALL FMI2M(10,MB) + CALL FMIPWR(MB,-35,ME) + CALL FMEQ(ME,MB) + IF (.NOT.FMCOMP(MA,'LE',MB)) THEN + CALL ERRPRTZM('ZMCOSH',ZA,'ZA',ZC,'ZC',ZD,'ZD', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 156 + STZ1 = '.7699115044247787610619469026548672566371681415929204 ' & + //'- .5221238938053097345132743362831858407079646017699115 i' + CALL ZMST2M(STZ1,ZA) + CALL ZMSINH(ZA,ZE) + CALL ZMEQ(ZE,ZA) + STZ2 = '0.7352399228186907963608272785465108877302444847897922 ' & + //'- 0.6539816592078560369158600079981127012552558121707655 i' + CALL ZMST2M(STZ2,ZC) + CALL ZMSUB(ZA,ZC,ZD) + CALL ZMABS(ZD,MA) + CALL FMI2M(10,MB) + CALL FMIPWR(MB,-50,ME) + CALL FMEQ(ME,MB) + IF (.NOT.FMCOMP(MA,'LE',MB)) THEN + CALL ERRPRTZM('ZMSINH',ZA,'ZA',ZC,'ZC',ZD,'ZD', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 157 + STZ1 = '34.7699115044247787610619469026548672566371681415929204 ' & + //'- 42.5221238938053097345132743362831858407079646017699115 i' + CALL ZMST2M(STZ1,ZA) + CALL ZMSINH(ZA,ZE) + CALL ZMEQ(ZE,ZA) + STZ2 = '6.955210465868175585893201484192181376093291191637290E 13 ' & + //'+ 6.261637733080168840073029151984050820616907795167046E 14 i' + CALL ZMST2M(STZ2,ZC) + CALL ZMSUB(ZA,ZC,ZD) + CALL ZMABS(ZD,MA) + CALL FMI2M(10,MB) + CALL FMIPWR(MB,-35,ME) + CALL FMEQ(ME,MB) + IF (.NOT.FMCOMP(MA,'LE',MB)) THEN + CALL ERRPRTZM('ZMSINH',ZA,'ZA',ZC,'ZC',ZD,'ZD', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 158 + STZ1 = '.7699115044247787610619469026548672566371681415929204 ' & + //'- .5221238938053097345132743362831858407079646017699115 i' + CALL ZMST2M(STZ1,ZA) + CALL ZMTANH(ZA,ZE) + CALL ZMEQ(ZE,ZA) + STZ2 = '0.7562684782933185240709480231996041186654551038993505 ' & + //'- 0.2938991498221693198532255749292372853685311106820169 i' + CALL ZMST2M(STZ2,ZC) + CALL ZMSUB(ZA,ZC,ZD) + CALL ZMABS(ZD,MA) + CALL FMI2M(10,MB) + CALL FMIPWR(MB,-50,ME) + CALL FMEQ(ME,MB) + IF (.NOT.FMCOMP(MA,'LE',MB)) THEN + CALL ERRPRTZM('ZMTANH',ZA,'ZA',ZC,'ZC',ZD,'ZD', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 159 + STZ1 = '35.7699115044247787610619469026548672566371681415929204 ' & + //'- 43.5221238938053097345132743362831858407079646017699115 i' + CALL ZMST2M(STZ1,ZA) + CALL ZMTANH(ZA,ZE) + CALL ZMEQ(ZE,ZA) + STZ2 = '9.999999999999999999999999999998967653135180689424497E-01 ' & + //'+ 1.356718776492102400812550018433337461876455254467192E-31 i' + CALL ZMST2M(STZ2,ZC) + CALL ZMSUB(ZA,ZC,ZD) + CALL ZMABS(ZD,MA) + CALL FMI2M(10,MB) + CALL FMIPWR(MB,-50,ME) + CALL FMEQ(ME,MB) + IF (.NOT.FMCOMP(MA,'LE',MB)) THEN + CALL ERRPRTZM('ZMTANH',ZA,'ZA',ZC,'ZC',ZD,'ZD', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 160 + STZ1 = '0.3505154639175257731958762886597938144329896907216495 ' & + //'+ 0.7319587628865979381443298969072164948453608247422680 i' + CALL ZMST2M(STZ1,ZA) + CALL ZMCHSH(ZA,ZE,ZC) + CALL ZMEQ(ZE,ZA) + STZ2 = '0.7900326499280864816444807620997665088044412803737969 ' & + //'+ 0.2390857359988804105051429301542214823277594407302781 i' + CALL ZMST2M(STZ2,ZC) + CALL ZMSUB(ZA,ZC,ZD) + CALL ZMABS(ZD,MA) + CALL FMI2M(10,MB) + CALL FMIPWR(MB,-50,ME) + CALL FMEQ(ME,MB) + IF (.NOT.FMCOMP(MA,'LE',MB)) THEN + CALL ERRPRTZM('ZMCHSH',ZA,'ZA',ZC,'ZC',ZD,'ZD', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 161 + STZ1 = '0.3505154639175257731958762886597938144329896907216495 ' & + //'+ 0.7319587628865979381443298969072164948453608247422680 i' + CALL ZMST2M(STZ1,ZA) + CALL ZMCHSH(ZA,ZC,ZE) + CALL ZMEQ(ZE,ZA) + STZ2 = '0.2661087555034471983220879532235334422670297141428191 ' & + //'+ 0.7098057980612199357870532628105009808447460332437714 i' + CALL ZMST2M(STZ2,ZC) + CALL ZMSUB(ZA,ZC,ZD) + CALL ZMABS(ZD,MA) + CALL FMI2M(10,MB) + CALL FMIPWR(MB,-50,ME) + CALL FMEQ(ME,MB) + IF (.NOT.FMCOMP(MA,'LE',MB)) THEN + CALL ERRPRTZM('ZMCHSH',ZA,'ZA',ZC,'ZC',ZD,'ZD', & + NCASE,NERROR,KLOG) + ENDIF + + RETURN + END SUBROUTINE TEST23 + + SUBROUTINE TEST24(NCASE,NERROR,KLOG) + +! Test the = assignment interface. + + USE FMVALS + USE FMZM + USE TEST_VARS + IMPLICIT NONE + + INTEGER NERROR,NCASE,KLOG + LOGICAL FM_COMP,IM_COMP + + WRITE (KW,"(/' Testing the derived type = interface.')") + + RSMALL = EPSILON(1.0)*100.0 + DSMALL = EPSILON(1.0D0)*100.0 + MSMALL = EPSILON(TO_FM(1))*10000.0 + NCASE = 162 + J4 = MFM1 + IF (J4 /= 581) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 163 + J4 = MIM1 + IF (J4 /= 661) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 164 + J4 = MZM1 + IF (J4 /= 731) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 165 + R4 = MFM1 + IF (ABS((R4-581.21)/581.21) > RSMALL) & + CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 166 + R4 = MIM1 + IF (ABS((R4-661.0)/661.0) > RSMALL) & + CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 167 + R4 = MZM1 + IF (ABS((R4-731.51)/731.51) > RSMALL) & + CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 168 + D4 = MFM1 + IF (ABS((D4-581.21D0)/581.21D0) > DSMALL) & + CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 169 + D4 = MIM1 + IF (ABS((D4-661.0D0)/661.0D0) > DSMALL) & + CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 170 + D4 = MZM1 + IF (ABS((D4-731.51D0)/731.51D0) > DSMALL) & + CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 171 + C4 = MFM1 + IF (ABS((C4-581.21)/581.21) > RSMALL) & + CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 172 + C4 = MIM1 + IF (ABS((C4-661.0)/661.0) > RSMALL) & + CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 173 + C4 = MZM1 + IF (ABS((C4-(731.51,711.41))/(731.51,711.41)) > RSMALL) & + CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 174 + CD4 = MFM1 + IF (ABS((CD4-581.21D0)/581.21D0) > DSMALL) & + CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 175 + CD4 = MIM1 + IF (ABS((CD4-661.0D0)/661.0D0) > DSMALL) & + CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 176 + CD4 = MZM1 + IF (ABS((CD4-(731.51D0,711.41D0))/(731.51D0,711.41D0)) > DSMALL) & + CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 177 + MFM3 = J2 + CALL FM_I2M(131,MFM4) + CALL FM_SUB(MFM3,MFM4,MFM6) + CALL FM_EQ(MFM6,MFM4) + CALL FM_ABS(MFM4,MFM6) + CALL FM_EQ(MFM6,MFM4) + CALL FM_ST2M('0',MFM3) + IF (FM_COMP(MFM4,'GT',MFM3)) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 178 + MFM3 = R2 + CALL FM_ST2M('241.21',MFM4) + CALL FM_SUB(MFM3,MFM4,MFM6) + CALL FM_EQ(MFM6,MFM4) + CALL FM_DIV(MFM4,MFM3,MFM6) + CALL FM_EQ(MFM6,MFM4) + CALL FM_ABS(MFM4,MFM6) + CALL FM_EQ(MFM6,MFM4) + MFM3 = RSMALL + IF (FM_COMP(MFM4,'GT',MFM3)) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 179 + MFM3 = D2 + CALL FM_ST2M('391.61',MFM4) + CALL FM_SUB(MFM3,MFM4,MFM6) + CALL FM_EQ(MFM6,MFM4) + CALL FM_DIV(MFM4,MFM3,MFM6) + CALL FM_EQ(MFM6,MFM4) + CALL FM_ABS(MFM4,MFM6) + CALL FM_EQ(MFM6,MFM4) + MFM3 = DSMALL + IF (FM_COMP(MFM4,'GT',MFM3)) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 180 + MFM3 = C2 + CALL FM_ST2M('411.11',MFM4) + CALL FM_SUB(MFM3,MFM4,MFM6) + CALL FM_EQ(MFM6,MFM4) + CALL FM_DIV(MFM4,MFM3,MFM6) + CALL FM_EQ(MFM6,MFM4) + CALL FM_ABS(MFM4,MFM6) + CALL FM_EQ(MFM6,MFM4) + MFM3 = RSMALL + IF (FM_COMP(MFM4,'GT',MFM3)) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 181 + MFM3 = CD2 + CALL FM_ST2M('431.11',MFM4) + CALL FM_SUB(MFM3,MFM4,MFM6) + CALL FM_EQ(MFM6,MFM4) + CALL FM_DIV(MFM4,MFM3,MFM6) + CALL FM_EQ(MFM6,MFM4) + CALL FM_ABS(MFM4,MFM6) + CALL FM_EQ(MFM6,MFM4) + MFM3 = DSMALL + IF (FM_COMP(MFM4,'GT',MFM3)) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 182 + MFM3 = MFM1 + CALL FM_ST2M('581.21',MFM4) + CALL FM_SUB(MFM3,MFM4,MFM6) + CALL FM_EQ(MFM6,MFM4) + CALL FM_DIV(MFM4,MFM3,MFM6) + CALL FM_EQ(MFM6,MFM4) + CALL FM_ABS(MFM4,MFM6) + CALL FM_EQ(MFM6,MFM4) + CALL FM_EQ(MSMALL,MFM3) + IF (FM_COMP(MFM4,'GT',MFM3)) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 183 + MFM3 = MIM1 + CALL FM_ST2M('661',MFM4) + CALL FM_SUB(MFM3,MFM4,MFM6) + CALL FM_EQ(MFM6,MFM4) + CALL FM_ABS(MFM4,MFM6) + CALL FM_EQ(MFM6,MFM4) + CALL FM_ST2M('0',MFM3) + IF (FM_COMP(MFM4,'GT',MFM3)) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 184 + MFM3 = MZM1 + CALL FM_ST2M('731.51',MFM4) + CALL FM_SUB(MFM3,MFM4,MFM6) + CALL FM_EQ(MFM6,MFM4) + CALL FM_DIV(MFM4,MFM3,MFM6) + CALL FM_EQ(MFM6,MFM4) + CALL FM_ABS(MFM4,MFM6) + CALL FM_EQ(MFM6,MFM4) + MFM3 = MSMALL + IF (FM_COMP(MFM4,'GT',MFM3)) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 185 + MIM3 = J2 + CALL IM_I2M(131,MIM4) + CALL IM_SUB(MIM3,MIM4,MIM5) + CALL IM_EQ(MIM5,MIM4) + CALL IM_ST2M('0',MIM3) + IF (IM_COMP(MIM4,'GT',MIM3)) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 186 + MIM3 = R2 + CALL IM_ST2M('241',MIM4) + CALL IM_SUB(MIM3,MIM4,MIM5) + CALL IM_EQ(MIM5,MIM4) + CALL IM_ST2M('0',MIM3) + IF (IM_COMP(MIM4,'GT',MIM3)) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 187 + MIM3 = D2 + CALL IM_ST2M('391',MIM4) + CALL IM_SUB(MIM3,MIM4,MIM5) + CALL IM_EQ(MIM5,MIM4) + CALL IM_ST2M('0',MIM3) + IF (IM_COMP(MIM4,'GT',MIM3)) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 188 + MIM3 = C2 + CALL IM_ST2M('411',MIM4) + CALL IM_SUB(MIM3,MIM4,MIM5) + CALL IM_EQ(MIM5,MIM4) + CALL IM_ST2M('0',MIM3) + IF (IM_COMP(MIM4,'GT',MIM3)) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 189 + MIM3 = CD2 + CALL IM_ST2M('431',MIM4) + CALL IM_SUB(MIM3,MIM4,MIM5) + CALL IM_EQ(MIM5,MIM4) + CALL IM_ST2M('0',MIM3) + IF (IM_COMP(MIM4,'GT',MIM3)) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 190 + MIM3 = MFM1 + CALL IM_ST2M('581',MIM4) + CALL IM_SUB(MIM3,MIM4,MIM5) + CALL IM_EQ(MIM5,MIM4) + CALL IM_ST2M('0',MIM3) + IF (IM_COMP(MIM4,'GT',MIM3)) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 191 + MIM3 = MIM1 + CALL IM_ST2M('661',MIM4) + CALL IM_SUB(MIM3,MIM4,MIM5) + CALL IM_EQ(MIM5,MIM4) + CALL IM_ST2M('0',MIM3) + IF (IM_COMP(MIM4,'GT',MIM3)) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 192 + MIM3 = MZM1 + CALL IM_ST2M('731',MIM4) + CALL IM_SUB(MIM3,MIM4,MIM5) + CALL IM_EQ(MIM5,MIM4) + CALL IM_ST2M('0',MIM3) + IF (IM_COMP(MIM4,'GT',MIM3)) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 193 + MZM3 = J2 + CALL ZM_I2M(131,MZM4) + CALL ZM_SUB(MZM3,MZM4,MZM5) + CALL ZM_EQ(MZM5,MZM4) + CALL ZM_ABS(MZM4,MFM4) + CALL FM_ST2M('0',MFM3) + IF (FM_COMP(MFM4,'GT',MFM3)) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 194 + MZM3 = R2 + CALL ZM_ST2M('241.21',MZM4) + CALL ZM_SUB(MZM3,MZM4,MZM5) + CALL ZM_EQ(MZM5,MZM4) + CALL ZM_DIV(MZM4,MZM3,MZM5) + CALL ZM_EQ(MZM5,MZM4) + CALL ZM_ABS(MZM4,MFM4) + MFM3 = RSMALL + IF (FM_COMP(MFM4,'GT',MFM3)) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 195 + MZM3 = D2 + CALL ZM_ST2M('391.61',MZM4) + CALL ZM_SUB(MZM3,MZM4,MZM5) + CALL ZM_EQ(MZM5,MZM4) + CALL ZM_DIV(MZM4,MZM3,MZM5) + CALL ZM_EQ(MZM5,MZM4) + CALL ZM_ABS(MZM4,MFM4) + MFM3 = DSMALL + IF (FM_COMP(MFM4,'GT',MFM3)) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 196 + MZM3 = C2 + CALL ZM_ST2M('411.11 + 421.21 i',MZM4) + CALL ZM_SUB(MZM3,MZM4,MZM5) + CALL ZM_EQ(MZM5,MZM4) + CALL ZM_DIV(MZM4,MZM3,MZM5) + CALL ZM_EQ(MZM5,MZM4) + CALL ZM_ABS(MZM4,MFM4) + MFM3 = RSMALL + IF (FM_COMP(MFM4,'GT',MFM3)) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 197 + MZM3 = CD2 + CALL ZM_ST2M('431.11 + 441.21 i',MZM4) + CALL ZM_SUB(MZM3,MZM4,MZM5) + CALL ZM_EQ(MZM5,MZM4) + CALL ZM_DIV(MZM4,MZM3,MZM5) + CALL ZM_EQ(MZM5,MZM4) + CALL ZM_ABS(MZM4,MFM4) + MFM3 = DSMALL + IF (FM_COMP(MFM4,'GT',MFM3)) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 198 + MZM3 = MFM1 + CALL ZM_ST2M('581.21',MZM4) + CALL ZM_SUB(MZM3,MZM4,MZM5) + CALL ZM_EQ(MZM5,MZM4) + CALL ZM_DIV(MZM4,MZM3,MZM5) + CALL ZM_EQ(MZM5,MZM4) + CALL ZM_ABS(MZM4,MFM4) + MFM3 = MSMALL + IF (FM_COMP(MFM4,'GT',MFM3)) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 199 + MZM3 = MIM1 + CALL ZM_ST2M('661',MZM4) + CALL ZM_SUB(MZM3,MZM4,MZM5) + CALL ZM_EQ(MZM5,MZM4) + CALL ZM_ABS(MZM4,MFM4) + CALL FM_ST2M('0',MFM3) + IF (FM_COMP(MFM4,'GT',MFM3)) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 200 + MZM3 = MZM1 + CALL ZM_ST2M('731.51 + 711.41 i',MZM4) + CALL ZM_SUB(MZM3,MZM4,MZM5) + CALL ZM_EQ(MZM5,MZM4) + CALL ZM_DIV(MZM4,MZM3,MZM5) + CALL ZM_EQ(MZM5,MZM4) + CALL ZM_ABS(MZM4,MFM4) + MFM3 = MSMALL + IF (FM_COMP(MFM4,'GT',MFM3)) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + END SUBROUTINE TEST24 + + SUBROUTINE TEST25(NCASE,NERROR,KLOG) + +! Test the derived type == interface. + + USE FMVALS + USE FMZM + USE TEST_VARS + + IMPLICIT NONE + + INTEGER KLOG,NCASE,NERROR + LOGICAL FM_COMP + + WRITE (KW,"(/' Testing the derived type == interface.')") + + NCASE = 201 + M_A = 123 + M_B = M_A + IF (.NOT.FM_COMP(M_A,'==',M_B)) THEN + CALL ERRPRT_FM(' == ',M_A,'M_A',M_B,'M_B',M_B,'M_B', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 202 + M_A = 123 + M_B = M_A + IF (.NOT.FM_COMP(M_A,'EQ',M_B)) THEN + CALL ERRPRT_FM(' == ',M_A,'M_A',M_B,'M_B',M_B,'M_B', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 203 + J1 = 123 + M_A = J1 + IF (.NOT.(M_A == J1)) THEN + CALL ERRPRT_FM(' == ',M_A,'M_A',M_A,'M_A',M_A,'M_A', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 204 + J1 = 123 + M_A = J1 + IF (.NOT.(J1 == M_A)) THEN + CALL ERRPRT_FM(' == ',M_A,'M_A',M_A,'M_A',M_A,'M_A', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 205 + J1 = 123 + M_J = J1 + IF (.NOT.(M_J == J1)) THEN + CALL ERRPRT_IM(' == ',M_J,'M_J',M_J,'M_J', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 206 + J1 = 123 + M_J = J1 + IF (.NOT.(J1 == M_J)) THEN + CALL ERRPRT_IM(' == ',M_J,'M_J',M_J,'M_J', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 207 + J1 = 123 + M_Z = J1 + IF (.NOT.(M_Z == J1)) THEN + CALL ERRPRT_ZM(' == ',M_Z,'M_Z',M_Z,'M_Z',M_Z,'M_Z', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 208 + J1 = 123 + M_Z = J1 + IF (.NOT.(J1 == M_Z)) THEN + CALL ERRPRT_ZM(' == ',M_Z,'M_Z',M_Z,'M_Z',M_Z,'M_Z', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 209 + R1 = 12.3 + M_A = R1 + IF (.NOT.(M_A == R1)) THEN + CALL ERRPRT_FM(' == ',M_A,'M_A',M_A,'M_A',M_A,'M_A', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 210 + R1 = 12.3 + M_A = R1 + IF (.NOT.(R1 == M_A)) THEN + CALL ERRPRT_FM(' == ',M_A,'M_A',M_A,'M_A',M_A,'M_A', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 211 + R1 = 123 + M_J = R1 + IF (.NOT.(M_J == R1)) THEN + CALL ERRPRT_IM(' == ',M_J,'M_J',M_J,'M_J', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 212 + R1 = 123 + M_J = R1 + IF (.NOT.(R1 == M_J)) THEN + CALL ERRPRT_IM(' == ',M_J,'M_J',M_J,'M_J', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 213 + R1 = 12.3 + M_Z = R1 + IF (.NOT.(M_Z == R1)) THEN + CALL ERRPRT_ZM(' == ',M_Z,'M_Z',M_Z,'M_Z',M_Z,'M_Z', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 214 + R1 = 12.3 + M_Z = R1 + IF (.NOT.(R1 == M_Z)) THEN + CALL ERRPRT_ZM(' == ',M_Z,'M_Z',M_Z,'M_Z',M_Z,'M_Z', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 215 + D1 = 12.3 + M_A = D1 + IF (.NOT.(M_A == D1)) THEN + CALL ERRPRT_FM(' == ',M_A,'M_A',M_A,'M_A',M_A,'M_A', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 216 + D1 = 12.3 + M_A = D1 + IF (.NOT.(D1 == M_A)) THEN + CALL ERRPRT_FM(' == ',M_A,'M_A',M_A,'M_A',M_A,'M_A', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 217 + D1 = 123 + M_J = D1 + IF (.NOT.(M_J == D1)) THEN + CALL ERRPRT_IM(' == ',M_J,'M_J',M_J,'M_J', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 218 + D1 = 123 + M_J = D1 + IF (.NOT.(D1 == M_J)) THEN + CALL ERRPRT_IM(' == ',M_J,'M_J',M_J,'M_J', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 219 + D1 = 12.3 + M_Z = D1 + IF (.NOT.(M_Z == D1)) THEN + CALL ERRPRT_ZM(' == ',M_Z,'M_Z',M_Z,'M_Z',M_Z,'M_Z', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 220 + D1 = 12.3 + M_Z = D1 + IF (.NOT.(D1 == M_Z)) THEN + CALL ERRPRT_ZM(' == ',M_Z,'M_Z',M_Z,'M_Z',M_Z,'M_Z', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 221 + C1 = 12.3 + M_A = C1 + IF (.NOT.(M_A == C1)) THEN + CALL ERRPRT_FM(' == ',M_A,'M_A',M_A,'M_A',M_A,'M_A', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 222 + C1 = 12.3 + M_A = C1 + IF (.NOT.(C1 == M_A)) THEN + CALL ERRPRT_FM(' == ',M_A,'M_A',M_A,'M_A',M_A,'M_A', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 223 + C1 = 123 + M_J = C1 + IF (.NOT.(M_J == C1)) THEN + CALL ERRPRT_IM(' == ',M_J,'M_J',M_J,'M_J', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 224 + C1 = 123 + M_J = C1 + IF (.NOT.(C1 == M_J)) THEN + CALL ERRPRT_IM(' == ',M_J,'M_J',M_J,'M_J', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 225 + C1 = (12.3 , 45.6) + M_Z = C1 + IF (.NOT.(M_Z == C1)) THEN + CALL ERRPRT_ZM(' == ',M_Z,'M_Z',M_Z,'M_Z',M_Z,'M_Z', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 226 + C1 = (12.3 , 45.6) + M_Z = C1 + IF (.NOT.(C1 == M_Z)) THEN + CALL ERRPRT_ZM(' == ',M_Z,'M_Z',M_Z,'M_Z',M_Z,'M_Z', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 227 + CD1 = 12.3 + M_A = CD1 + IF (.NOT.(M_A == CD1)) THEN + CALL ERRPRT_FM(' == ',M_A,'M_A',M_A,'M_A',M_A,'M_A', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 228 + CD1 = 12.3 + M_A = CD1 + IF (.NOT.(CD1 == M_A)) THEN + CALL ERRPRT_FM(' == ',M_A,'M_A',M_A,'M_A',M_A,'M_A', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 229 + CD1 = 123 + M_J = CD1 + IF (.NOT.(M_J == CD1)) THEN + CALL ERRPRT_IM(' == ',M_J,'M_J',M_J,'M_J', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 230 + CD1 = 123 + M_J = CD1 + IF (.NOT.(CD1 == M_J)) THEN + CALL ERRPRT_IM(' == ',M_J,'M_J',M_J,'M_J', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 231 + CD1 = (12.3 , 45.6) + M_Z = CD1 + IF (.NOT.(M_Z == CD1)) THEN + CALL ERRPRT_ZM(' == ',M_Z,'M_Z',M_Z,'M_Z',M_Z,'M_Z', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 232 + CD1 = (12.3 , 45.6) + M_Z = CD1 + IF (.NOT.(CD1 == M_Z)) THEN + CALL ERRPRT_ZM(' == ',M_Z,'M_Z',M_Z,'M_Z',M_Z,'M_Z', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 233 + M_B = 12.3 + M_A = M_B + IF (.NOT.(M_A == M_B)) THEN + CALL ERRPRT_FM(' == ',M_A,'M_A',M_A,'M_A',M_A,'M_A', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 234 + M_B = 123 + M_J = M_B + IF (.NOT.(M_J == M_B)) THEN + CALL ERRPRT_IM(' == ',M_J,'M_J',M_J,'M_J', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 235 + M_B = 123 + M_J = M_B + IF (.NOT.(M_B == M_J)) THEN + CALL ERRPRT_IM(' == ',M_J,'M_J',M_J,'M_J', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 236 + M_B = (12.3 , 45.6) + M_Z = M_B + IF (.NOT.(M_Z == M_B)) THEN + CALL ERRPRT_ZM(' == ',M_Z,'M_Z',M_Z,'M_Z',M_Z,'M_Z', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 237 + M_B = (12.3 , 45.6) + M_Z = M_B + IF (.NOT.(M_B == M_Z)) THEN + CALL ERRPRT_ZM(' == ',M_Z,'M_Z',M_Z,'M_Z',M_Z,'M_Z', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 238 + M_K = 123 + M_J = M_K + IF (.NOT.(M_J == M_K)) THEN + CALL ERRPRT_IM(' == ',M_J,'M_J',M_J,'M_J', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 239 + M_K = (12.3 , 45.6) + M_Z = M_K + IF (.NOT.(M_Z == M_K)) THEN + CALL ERRPRT_ZM(' == ',M_Z,'M_Z',M_Z,'M_Z',M_Z,'M_Z', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 240 + M_K = (12.3 , 45.6) + M_Z = M_K + IF (.NOT.(M_K == M_Z)) THEN + CALL ERRPRT_ZM(' == ',M_Z,'M_Z',M_Z,'M_Z',M_Z,'M_Z', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 241 + M_Y = (12.3 , 45.6) + M_Z = M_Y + IF (.NOT.(M_Y == M_Z)) THEN + CALL ERRPRT_ZM(' == ',M_Z,'M_Z',M_Z,'M_Z',M_Z,'M_Z', & + NCASE,NERROR,KLOG) + ENDIF + + RETURN + END SUBROUTINE TEST25 + + SUBROUTINE TEST26(NCASE,NERROR,KLOG) + +! Test the derived type /= interface. + + USE FMVALS + USE FMZM + USE TEST_VARS + + IMPLICIT NONE + + INTEGER KLOG,NCASE,NERROR + LOGICAL FM_COMP + + WRITE (KW,"(/' Testing the derived type /= interface.')") + + NCASE = 242 + M_A = 123 + M_B = 124 + IF (.NOT.FM_COMP(M_A,'/=',M_B)) THEN + CALL ERRPRT_FM(' == ',M_A,'M_A',M_B,'M_B',M_B,'M_B', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 243 + M_A = 123 + M_B = 124 + IF (.NOT.FM_COMP(M_A,'NE',M_B)) THEN + CALL ERRPRT_FM(' == ',M_A,'M_A',M_B,'M_B',M_B,'M_B', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 244 + J1 = 123 + M_A = 1 + J1 + IF (.NOT.(M_A /= J1)) THEN + CALL ERRPRT_FM(' /= ',M_A,'M_A',M_A,'M_A',M_A,'M_A', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 245 + J1 = 123 + M_A = 1 + J1 + IF (.NOT.(J1 /= M_A)) THEN + CALL ERRPRT_FM(' /= ',M_A,'M_A',M_A,'M_A',M_A,'M_A', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 246 + J1 = 123 + M_J = 1 + J1 + IF (.NOT.(M_J /= J1)) THEN + CALL ERRPRT_IM(' /= ',M_J,'M_J',M_J,'M_J', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 247 + J1 = 123 + M_J = 1 + J1 + IF (.NOT.(J1 /= M_J)) THEN + CALL ERRPRT_IM(' /= ',M_J,'M_J',M_J,'M_J', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 248 + J1 = 123 + M_Z = 1 + J1 + IF (.NOT.(M_Z /= J1)) THEN + CALL ERRPRT_ZM(' /= ',M_Z,'M_Z',M_Z,'M_Z',M_Z,'M_Z', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 249 + J1 = 123 + M_Z = 1 + J1 + IF (.NOT.(J1 /= M_Z)) THEN + CALL ERRPRT_ZM(' /= ',M_Z,'M_Z',M_Z,'M_Z',M_Z,'M_Z', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 250 + R1 = 12.3 + M_A = 1 + R1 + IF (.NOT.(M_A /= R1)) THEN + CALL ERRPRT_FM(' /= ',M_A,'M_A',M_A,'M_A',M_A,'M_A', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 251 + R1 = 12.3 + M_A = 1 + R1 + IF (.NOT.(R1 /= M_A)) THEN + CALL ERRPRT_FM(' /= ',M_A,'M_A',M_A,'M_A',M_A,'M_A', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 252 + R1 = 123 + M_J = 1 + R1 + IF (.NOT.(M_J /= R1)) THEN + CALL ERRPRT_IM(' /= ',M_J,'M_J',M_J,'M_J', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 253 + R1 = 123 + M_J = 1 + R1 + IF (.NOT.(R1 /= M_J)) THEN + CALL ERRPRT_IM(' /= ',M_J,'M_J',M_J,'M_J', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 254 + R1 = 12.3 + M_Z = 1 + R1 + IF (.NOT.(M_Z /= R1)) THEN + CALL ERRPRT_ZM(' /= ',M_Z,'M_Z',M_Z,'M_Z',M_Z,'M_Z', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 255 + R1 = 12.3 + M_Z = 1 + R1 + IF (.NOT.(R1 /= M_Z)) THEN + CALL ERRPRT_ZM(' /= ',M_Z,'M_Z',M_Z,'M_Z',M_Z,'M_Z', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 256 + D1 = 12.3 + M_A = 1 + D1 + IF (.NOT.(M_A /= D1)) THEN + CALL ERRPRT_FM(' /= ',M_A,'M_A',M_A,'M_A',M_A,'M_A', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 257 + D1 = 12.3 + M_A = 1 + D1 + IF (.NOT.(D1 /= M_A)) THEN + CALL ERRPRT_FM(' /= ',M_A,'M_A',M_A,'M_A',M_A,'M_A', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 258 + D1 = 123 + M_J = 1 + D1 + IF (.NOT.(M_J /= D1)) THEN + CALL ERRPRT_IM(' /= ',M_J,'M_J',M_J,'M_J', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 259 + D1 = 123 + M_J = 1 + D1 + IF (.NOT.(D1 /= M_J)) THEN + CALL ERRPRT_IM(' /= ',M_J,'M_J',M_J,'M_J', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 260 + D1 = 12.3 + M_Z = 1 + D1 + IF (.NOT.(M_Z /= D1)) THEN + CALL ERRPRT_ZM(' /= ',M_Z,'M_Z',M_Z,'M_Z',M_Z,'M_Z', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 261 + D1 = 12.3 + M_Z = 1 + D1 + IF (.NOT.(D1 /= M_Z)) THEN + CALL ERRPRT_ZM(' /= ',M_Z,'M_Z',M_Z,'M_Z',M_Z,'M_Z', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 262 + C1 = 12.3 + M_A = 1 + C1 + IF (.NOT.(M_A /= C1)) THEN + CALL ERRPRT_FM(' /= ',M_A,'M_A',M_A,'M_A',M_A,'M_A', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 263 + C1 = 12.3 + M_A = 1 + C1 + IF (.NOT.(C1 /= M_A)) THEN + CALL ERRPRT_FM(' /= ',M_A,'M_A',M_A,'M_A',M_A,'M_A', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 264 + C1 = 123 + M_J = 1 + C1 + IF (.NOT.(M_J /= C1)) THEN + CALL ERRPRT_IM(' /= ',M_J,'M_J',M_J,'M_J', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 265 + C1 = 123 + M_J = 1 + C1 + IF (.NOT.(C1 /= M_J)) THEN + CALL ERRPRT_IM(' /= ',M_J,'M_J',M_J,'M_J', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 266 + C1 = (12.3 , 45.6) + M_Z = 1 + C1 + IF (.NOT.(M_Z /= C1)) THEN + CALL ERRPRT_ZM(' /= ',M_Z,'M_Z',M_Z,'M_Z',M_Z,'M_Z', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 267 + C1 = (12.3 , 45.6) + M_Z = 1 + C1 + IF (.NOT.(C1 /= M_Z)) THEN + CALL ERRPRT_ZM(' /= ',M_Z,'M_Z',M_Z,'M_Z',M_Z,'M_Z', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 268 + CD1 = 12.3 + M_A = 1 + CD1 + IF (.NOT.(M_A /= CD1)) THEN + CALL ERRPRT_FM(' /= ',M_A,'M_A',M_A,'M_A',M_A,'M_A', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 269 + CD1 = 12.3 + M_A = 1 + CD1 + IF (.NOT.(CD1 /= M_A)) THEN + CALL ERRPRT_FM(' /= ',M_A,'M_A',M_A,'M_A',M_A,'M_A', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 270 + CD1 = 123 + M_J = 1 + CD1 + IF (.NOT.(M_J /= CD1)) THEN + CALL ERRPRT_IM(' /= ',M_J,'M_J',M_J,'M_J', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 271 + CD1 = 123 + M_J = 1 + CD1 + IF (.NOT.(CD1 /= M_J)) THEN + CALL ERRPRT_IM(' /= ',M_J,'M_J',M_J,'M_J', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 272 + CD1 = (12.3 , 45.6) + M_Z = 1 + CD1 + IF (.NOT.(M_Z /= CD1)) THEN + CALL ERRPRT_ZM(' /= ',M_Z,'M_Z',M_Z,'M_Z',M_Z,'M_Z', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 273 + CD1 = (12.3 , 45.6) + M_Z = 1 + CD1 + IF (.NOT.(CD1 /= M_Z)) THEN + CALL ERRPRT_ZM(' /= ',M_Z,'M_Z',M_Z,'M_Z',M_Z,'M_Z', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 274 + M_B = 12.3 + M_A = 1 + M_B + IF (.NOT.(M_A /= M_B)) THEN + CALL ERRPRT_FM(' /= ',M_A,'M_A',M_A,'M_A',M_A,'M_A', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 275 + M_B = 123 + M_J = 1 + M_B + IF (.NOT.(M_J /= M_B)) THEN + CALL ERRPRT_IM(' /= ',M_J,'M_J',M_J,'M_J', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 276 + M_B = 123 + M_J = 1 + M_B + IF (.NOT.(M_B /= M_J)) THEN + CALL ERRPRT_IM(' /= ',M_J,'M_J',M_J,'M_J', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 277 + M_B = (12.3 , 45.6) + M_Z = 1 + M_B + IF (.NOT.(M_Z /= M_B)) THEN + CALL ERRPRT_ZM(' /= ',M_Z,'M_Z',M_Z,'M_Z',M_Z,'M_Z', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 278 + M_B = (12.3 , 45.6) + M_Z = 1 + M_B + IF (.NOT.(M_B /= M_Z)) THEN + CALL ERRPRT_ZM(' /= ',M_Z,'M_Z',M_Z,'M_Z',M_Z,'M_Z', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 279 + M_K = 123 + M_J = 1 + M_K + IF (.NOT.(M_J /= M_K)) THEN + CALL ERRPRT_IM(' /= ',M_J,'M_J',M_J,'M_J', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 280 + M_K = (12.3 , 45.6) + M_Z = 1 + M_K + IF (.NOT.(M_Z /= M_K)) THEN + CALL ERRPRT_ZM(' /= ',M_Z,'M_Z',M_Z,'M_Z',M_Z,'M_Z', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 281 + M_K = (12.3 , 45.6) + M_Z = 1 + M_K + IF (.NOT.(M_K /= M_Z)) THEN + CALL ERRPRT_ZM(' /= ',M_Z,'M_Z',M_Z,'M_Z',M_Z,'M_Z', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 282 + M_Y = (12.3 , 45.6) + M_Z = 1 + M_Y + IF (.NOT.(M_Y /= M_Z)) THEN + CALL ERRPRT_ZM(' /= ',M_Z,'M_Z',M_Z,'M_Z',M_Z,'M_Z', & + NCASE,NERROR,KLOG) + ENDIF + + RETURN + END SUBROUTINE TEST26 + + SUBROUTINE TEST27(NCASE,NERROR,KLOG) + +! Test the derived type > interface. + + USE FMVALS + USE FMZM + USE TEST_VARS + + IMPLICIT NONE + + INTEGER KLOG,NCASE,NERROR + LOGICAL FM_COMP + + WRITE (KW,"(/' Testing the derived type > interface.')") + + NCASE = 283 + M_A = 125 + M_B = 124 + IF (.NOT.FM_COMP(M_A,'>',M_B)) THEN + CALL ERRPRT_FM(' > ',M_A,'M_A',M_B,'M_B',M_B,'M_B', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 284 + M_A = 125 + M_B = 124 + IF (.NOT.FM_COMP(M_A,'GT',M_B)) THEN + CALL ERRPRT_FM(' > ',M_A,'M_A',M_B,'M_B',M_B,'M_B', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 285 + J1 = 123 + M_A = J1 + 1 + IF (.NOT.(M_A > J1)) THEN + CALL ERRPRT_FM(' > ',M_A,'M_A',M_A,'M_A',M_A,'M_A', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 286 + J1 = 123 + M_A = J1 - 1 + IF (.NOT.(J1 > M_A)) THEN + CALL ERRPRT_FM(' > ',M_A,'M_A',M_A,'M_A',M_A,'M_A', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 287 + J1 = 123 + M_J = J1 + 1 + IF (.NOT.(M_J > J1)) THEN + CALL ERRPRT_IM(' > ',M_J,'M_J',M_J,'M_J', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 288 + J1 = 123 + M_J = J1 - 1 + IF (.NOT.(J1 > M_J)) THEN + CALL ERRPRT_IM(' > ',M_J,'M_J',M_J,'M_J', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 289 + R1 = 12.3 + M_A = R1 + 1 + IF (.NOT.(M_A > R1)) THEN + CALL ERRPRT_FM(' > ',M_A,'M_A',M_A,'M_A',M_A,'M_A', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 290 + R1 = 12.3 + M_A = R1 - 1 + IF (.NOT.(R1 > M_A)) THEN + CALL ERRPRT_FM(' > ',M_A,'M_A',M_A,'M_A',M_A,'M_A', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 291 + R1 = 123 + M_J = R1 + 1 + IF (.NOT.(M_J > R1)) THEN + CALL ERRPRT_IM(' > ',M_J,'M_J',M_J,'M_J', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 292 + R1 = 123 + M_J = R1 - 1 + IF (.NOT.(R1 > M_J)) THEN + CALL ERRPRT_IM(' > ',M_J,'M_J',M_J,'M_J', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 293 + D1 = 12.3 + M_A = D1 + 1 + IF (.NOT.(M_A > D1)) THEN + CALL ERRPRT_FM(' > ',M_A,'M_A',M_A,'M_A',M_A,'M_A', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 294 + D1 = 12.3 + M_A = D1 - 1 + IF (.NOT.(D1 > M_A)) THEN + CALL ERRPRT_FM(' > ',M_A,'M_A',M_A,'M_A',M_A,'M_A', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 295 + D1 = 123 + M_J = D1 + 1 + IF (.NOT.(M_J > D1)) THEN + CALL ERRPRT_IM(' > ',M_J,'M_J',M_J,'M_J', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 296 + D1 = 123 + M_J = D1 - 1 + IF (.NOT.(D1 > M_J)) THEN + CALL ERRPRT_IM(' > ',M_J,'M_J',M_J,'M_J', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 297 + M_B = 12.3 + M_A = M_B + 1 + IF (.NOT.(M_A > M_B)) THEN + CALL ERRPRT_FM(' > ',M_A,'M_A',M_A,'M_A',M_A,'M_A', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 298 + M_B = 123 + M_J = M_B + 1 + IF (.NOT.(M_J > M_B)) THEN + CALL ERRPRT_IM(' > ',M_J,'M_J',M_J,'M_J', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 299 + M_B = 123 + M_J = M_B - 1 + IF (.NOT.(M_B > M_J)) THEN + CALL ERRPRT_IM(' > ',M_J,'M_J',M_J,'M_J', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 300 + M_K = 123 + M_J = M_K + 1 + IF (.NOT.(M_J > M_K)) THEN + CALL ERRPRT_IM(' > ',M_J,'M_J',M_J,'M_J', & + NCASE,NERROR,KLOG) + ENDIF + + RETURN + END SUBROUTINE TEST27 + + SUBROUTINE TEST28(NCASE,NERROR,KLOG) + +! Test the derived type >= interface. + + USE FMVALS + USE FMZM + USE TEST_VARS + + IMPLICIT NONE + + INTEGER KLOG,NCASE,NERROR + LOGICAL FM_COMP + + WRITE (KW,"(/' Testing the derived type >= interface.')") + + NCASE = 301 + M_A = 125 + M_B = 124 + IF (.NOT.FM_COMP(M_A,'>=',M_B)) THEN + CALL ERRPRT_FM(' >= ',M_A,'M_A',M_B,'M_B',M_B,'M_B', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 302 + M_A = 125 + M_B = 124 + IF (.NOT.FM_COMP(M_A,'GE',M_B)) THEN + CALL ERRPRT_FM(' >= ',M_A,'M_A',M_B,'M_B',M_B,'M_B', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 303 + J1 = 123 + M_A = J1 + 1 + IF (.NOT.(M_A >= J1)) THEN + CALL ERRPRT_FM(' >= ',M_A,'M_A',M_A,'M_A',M_A,'M_A', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 304 + J1 = 123 + M_A = J1 - 1 + IF (.NOT.(J1 >= M_A)) THEN + CALL ERRPRT_FM(' >= ',M_A,'M_A',M_A,'M_A',M_A,'M_A', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 305 + J1 = 123 + M_J = J1 + 1 + IF (.NOT.(M_J >= J1)) THEN + CALL ERRPRT_IM(' >= ',M_J,'M_J',M_J,'M_J', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 306 + J1 = 123 + M_J = J1 - 1 + IF (.NOT.(J1 >= M_J)) THEN + CALL ERRPRT_IM(' >= ',M_J,'M_J',M_J,'M_J', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 307 + R1 = 12.3 + M_A = R1 + 1 + IF (.NOT.(M_A >= R1)) THEN + CALL ERRPRT_FM(' >= ',M_A,'M_A',M_A,'M_A',M_A,'M_A', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 308 + R1 = 12.3 + M_A = R1 - 1 + IF (.NOT.(R1 >= M_A)) THEN + CALL ERRPRT_FM(' >= ',M_A,'M_A',M_A,'M_A',M_A,'M_A', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 309 + R1 = 123 + M_J = R1 + 1 + IF (.NOT.(M_J >= R1)) THEN + CALL ERRPRT_IM(' >= ',M_J,'M_J',M_J,'M_J', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 310 + R1 = 123 + M_J = R1 - 1 + IF (.NOT.(R1 >= M_J)) THEN + CALL ERRPRT_IM(' >= ',M_J,'M_J',M_J,'M_J', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 311 + D1 = 12.3 + M_A = D1 + 1 + IF (.NOT.(M_A >= D1)) THEN + CALL ERRPRT_FM(' >= ',M_A,'M_A',M_A,'M_A',M_A,'M_A', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 312 + D1 = 12.3 + M_A = D1 - 1 + IF (.NOT.(D1 >= M_A)) THEN + CALL ERRPRT_FM(' >= ',M_A,'M_A',M_A,'M_A',M_A,'M_A', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 313 + D1 = 123 + M_J = D1 + 1 + IF (.NOT.(M_J >= D1)) THEN + CALL ERRPRT_IM(' >= ',M_J,'M_J',M_J,'M_J', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 314 + D1 = 123 + M_J = D1 - 1 + IF (.NOT.(D1 >= M_J)) THEN + CALL ERRPRT_IM(' >= ',M_J,'M_J',M_J,'M_J', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 315 + M_B = 12.3 + M_A = M_B + 1 + IF (.NOT.(M_A >= M_B)) THEN + CALL ERRPRT_FM(' >= ',M_A,'M_A',M_A,'M_A',M_A,'M_A', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 316 + M_B = 123 + M_J = M_B + 1 + IF (.NOT.(M_J >= M_B)) THEN + CALL ERRPRT_IM(' >= ',M_J,'M_J',M_J,'M_J', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 317 + M_B = 123 + M_J = M_B - 1 + IF (.NOT.(M_B >= M_J)) THEN + CALL ERRPRT_IM(' >= ',M_J,'M_J',M_J,'M_J', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 318 + M_K = 123 + M_J = M_K + 1 + IF (.NOT.(M_J >= M_K)) THEN + CALL ERRPRT_IM(' >= ',M_J,'M_J',M_J,'M_J', & + NCASE,NERROR,KLOG) + ENDIF + + RETURN + END SUBROUTINE TEST28 + + SUBROUTINE TEST29(NCASE,NERROR,KLOG) + +! Test the derived type < interface. + + USE FMVALS + USE FMZM + USE TEST_VARS + + IMPLICIT NONE + + INTEGER KLOG,NCASE,NERROR + LOGICAL FM_COMP + + WRITE (KW,"(/' Testing the derived type < interface.')") + + NCASE = 319 + M_A = 123 + M_B = 124 + IF (.NOT.FM_COMP(M_A,'<',M_B)) THEN + CALL ERRPRT_FM(' < ',M_A,'M_A',M_B,'M_B',M_B,'M_B', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 320 + M_A = 123 + M_B = 124 + IF (.NOT.FM_COMP(M_A,'LT',M_B)) THEN + CALL ERRPRT_FM(' < ',M_A,'M_A',M_B,'M_B',M_B,'M_B', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 321 + J1 = 123 + M_A = J1 - 2 + IF (.NOT.(M_A < J1)) THEN + CALL ERRPRT_FM(' < ',M_A,'M_A',M_A,'M_A',M_A,'M_A', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 322 + J1 = 123 + M_A = J1 + 2 + IF (.NOT.(J1 < M_A)) THEN + CALL ERRPRT_FM(' < ',M_A,'M_A',M_A,'M_A',M_A,'M_A', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 323 + J1 = 123 + M_J = J1 - 2 + IF (.NOT.(M_J < J1)) THEN + CALL ERRPRT_IM(' < ',M_J,'M_J',M_J,'M_J', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 324 + J1 = 123 + M_J = J1 + 2 + IF (.NOT.(J1 < M_J)) THEN + CALL ERRPRT_IM(' < ',M_J,'M_J',M_J,'M_J', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 325 + R1 = 12.3 + M_A = R1 - 2 + IF (.NOT.(M_A < R1)) THEN + CALL ERRPRT_FM(' < ',M_A,'M_A',M_A,'M_A',M_A,'M_A', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 326 + R1 = 12.3 + M_A = R1 + 2 + IF (.NOT.(R1 < M_A)) THEN + CALL ERRPRT_FM(' < ',M_A,'M_A',M_A,'M_A',M_A,'M_A', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 327 + R1 = 123 + M_J = R1 - 2 + IF (.NOT.(M_J < R1)) THEN + CALL ERRPRT_IM(' < ',M_J,'M_J',M_J,'M_J', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 328 + R1 = 123 + M_J = R1 + 2 + IF (.NOT.(R1 < M_J)) THEN + CALL ERRPRT_IM(' < ',M_J,'M_J',M_J,'M_J', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 329 + D1 = 12.3 + M_A = D1 - 2 + IF (.NOT.(M_A < D1)) THEN + CALL ERRPRT_FM(' < ',M_A,'M_A',M_A,'M_A',M_A,'M_A', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 330 + D1 = 12.3 + M_A = D1 + 2 + IF (.NOT.(D1 < M_A)) THEN + CALL ERRPRT_FM(' < ',M_A,'M_A',M_A,'M_A',M_A,'M_A', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 331 + D1 = 123 + M_J = D1 - 2 + IF (.NOT.(M_J < D1)) THEN + CALL ERRPRT_IM(' < ',M_J,'M_J',M_J,'M_J', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 332 + D1 = 123 + M_J = D1 + 2 + IF (.NOT.(D1 < M_J)) THEN + CALL ERRPRT_IM(' < ',M_J,'M_J',M_J,'M_J', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 333 + M_B = 12.3 + M_A = M_B - 2 + IF (.NOT.(M_A < M_B)) THEN + CALL ERRPRT_FM(' < ',M_A,'M_A',M_A,'M_A',M_A,'M_A', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 334 + M_B = 123 + M_J = M_B - 2 + IF (.NOT.(M_J < M_B)) THEN + CALL ERRPRT_IM(' < ',M_J,'M_J',M_J,'M_J', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 335 + M_B = 123 + M_J = M_B + 2 + IF (.NOT.(M_B < M_J)) THEN + CALL ERRPRT_IM(' < ',M_J,'M_J',M_J,'M_J', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 336 + M_K = 123 + M_J = M_K - 2 + IF (.NOT.(M_J < M_K)) THEN + CALL ERRPRT_IM(' < ',M_J,'M_J',M_J,'M_J', & + NCASE,NERROR,KLOG) + ENDIF + + RETURN + END SUBROUTINE TEST29 + + SUBROUTINE TEST30(NCASE,NERROR,KLOG) + +! Test the derived type <= interface. + + USE FMVALS + USE FMZM + USE TEST_VARS + + IMPLICIT NONE + + INTEGER KLOG,NCASE,NERROR + LOGICAL FM_COMP + + WRITE (KW,"(/' Testing the derived type <= interface.')") + + NCASE = 337 + M_A = 123 + M_B = 124 + IF (.NOT.FM_COMP(M_A,'<=',M_B)) THEN + CALL ERRPRT_FM(' <= ',M_A,'M_A',M_B,'M_B',M_B,'M_B', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 338 + M_A = 123 + M_B = 124 + IF (.NOT.FM_COMP(M_A,'LE',M_B)) THEN + CALL ERRPRT_FM(' <= ',M_A,'M_A',M_B,'M_B',M_B,'M_B', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 339 + J1 = 123 + M_A = J1 - 2 + IF (.NOT.(M_A <= J1)) THEN + CALL ERRPRT_FM(' <= ',M_A,'M_A',M_A,'M_A',M_A,'M_A', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 340 + J1 = 123 + M_A = J1 + 2 + IF (.NOT.(J1 <= M_A)) THEN + CALL ERRPRT_FM(' <= ',M_A,'M_A',M_A,'M_A',M_A,'M_A', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 341 + J1 = 123 + M_J = J1 - 2 + IF (.NOT.(M_J <= J1)) THEN + CALL ERRPRT_IM(' <= ',M_J,'M_J',M_J,'M_J', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 342 + J1 = 123 + M_J = J1 + 2 + IF (.NOT.(J1 <= M_J)) THEN + CALL ERRPRT_IM(' <= ',M_J,'M_J',M_J,'M_J', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 343 + R1 = 12.3 + M_A = R1 - 2 + IF (.NOT.(M_A <= R1)) THEN + CALL ERRPRT_FM(' <= ',M_A,'M_A',M_A,'M_A',M_A,'M_A', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 344 + R1 = 12.3 + M_A = R1 + 2 + IF (.NOT.(R1 <= M_A)) THEN + CALL ERRPRT_FM(' <= ',M_A,'M_A',M_A,'M_A',M_A,'M_A', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 345 + R1 = 123 + M_J = R1 - 2 + IF (.NOT.(M_J <= R1)) THEN + CALL ERRPRT_IM(' <= ',M_J,'M_J',M_J,'M_J', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 346 + R1 = 123 + M_J = R1 + 2 + IF (.NOT.(R1 <= M_J)) THEN + CALL ERRPRT_IM(' <= ',M_J,'M_J',M_J,'M_J', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 347 + D1 = 12.3 + M_A = D1 - 2 + IF (.NOT.(M_A <= D1)) THEN + CALL ERRPRT_FM(' <= ',M_A,'M_A',M_A,'M_A',M_A,'M_A', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 348 + D1 = 12.3 + M_A = D1 + 2 + IF (.NOT.(D1 <= M_A)) THEN + CALL ERRPRT_FM(' <= ',M_A,'M_A',M_A,'M_A',M_A,'M_A', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 349 + D1 = 123 + M_J = D1 - 2 + IF (.NOT.(M_J <= D1)) THEN + CALL ERRPRT_IM(' <= ',M_J,'M_J',M_J,'M_J', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 350 + D1 = 123 + M_J = D1 + 2 + IF (.NOT.(D1 <= M_J)) THEN + CALL ERRPRT_IM(' <= ',M_J,'M_J',M_J,'M_J', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 351 + M_B = 12.3 + M_A = M_B - 2 + IF (.NOT.(M_A <= M_B)) THEN + CALL ERRPRT_FM(' <= ',M_A,'M_A',M_A,'M_A',M_A,'M_A', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 352 + M_B = 123 + M_J = M_B - 2 + IF (.NOT.(M_J <= M_B)) THEN + CALL ERRPRT_IM(' <= ',M_J,'M_J',M_J,'M_J', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 353 + M_B = 123 + M_J = M_B + 2 + IF (.NOT.(M_B <= M_J)) THEN + CALL ERRPRT_IM(' <= ',M_J,'M_J',M_J,'M_J', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 354 + M_K = 123 + M_J = M_K - 2 + IF (.NOT.(M_J <= M_K)) THEN + CALL ERRPRT_IM(' <= ',M_J,'M_J',M_J,'M_J', & + NCASE,NERROR,KLOG) + ENDIF + + RETURN + END SUBROUTINE TEST30 + + SUBROUTINE TEST31(NCASE,NERROR,KLOG) + +! Test the '+' arithmetic operator. + + USE FMVALS + USE FMZM + USE TEST_VARS + IMPLICIT NONE + + INTEGER KLOG,NERROR,NCASE + + WRITE (KW,"(/' Testing the derived type + interface.')") + + RSMALL = EPSILON(1.0)*100.0 + DSMALL = EPSILON(1.0D0)*100.0 + + NCASE = 355 + MFM3 = J2 + MFM1 + CALL FM_ST2M('131',MFM4) + CALL FM_ADD(MFM4,MFM1,MFM6) + CALL FM_EQ(MFM6,MFM4) + IF (MFM3 /= MFM4) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 356 + MIM3 = J2 + MIM1 + CALL IM_ST2M('131',MIM4) + CALL IM_ADD(MIM4,MIM1,MIM5) + CALL IM_EQ(MIM5,MIM4) + IF (MIM3 /= MIM4) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 357 + MZM3 = J2 + MZM1 + CALL ZM_ST2M('131',MZM4) + CALL ZM_ADD(MZM4,MZM1,MZM5) + CALL ZM_EQ(MZM5,MZM4) + IF (MZM3 /= MZM4) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 358 + MFM3 = R2 + MFM1 + CALL FM_ST2M('241.21',MFM4) + CALL FM_ADD(MFM4,MFM1,MFM6) + CALL FM_EQ(MFM6,MFM4) + CALL FM_SUB(MFM3,MFM4,MFM6) + CALL FM_EQ(MFM6,MFM4) + CALL FM_DIV(MFM4,MFM3,MFM6) + CALL FM_EQ(MFM6,MFM4) + CALL FM_ABS(MFM4,MFM6) + CALL FM_EQ(MFM6,MFM4) + IF (MFM4 > RSMALL) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 359 + CALL FM_ST2M('241.21',MFM4) + CALL FM_ST2M('661',MFM3) + CALL FM_ADD(MFM4,MFM3,MFM6) + CALL FM_EQ(MFM6,MFM4) + MFM3 = R2 + MIM1 + CALL FM_SUB(MFM3,MFM4,MFM6) + CALL FM_EQ(MFM6,MFM4) + CALL FM_DIV(MFM4,MFM3,MFM6) + CALL FM_EQ(MFM6,MFM4) + CALL FM_ABS(MFM4,MFM6) + CALL FM_EQ(MFM6,MFM4) + IF (MFM4 > RSMALL) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 360 + MZM3 = R2 + MZM1 + CALL ZM_ST2M('241.21',MZM4) + CALL ZM_ADD(MZM4,MZM1,MZM5) + CALL ZM_EQ(MZM5,MZM4) + CALL ZM_SUB(MZM3,MZM4,MZM5) + CALL ZM_EQ(MZM5,MZM4) + CALL ZM_DIV(MZM4,MZM3,MZM5) + CALL ZM_EQ(MZM5,MZM4) + CALL ZM_ABS(MZM4,MFM4) + IF (MFM4 > RSMALL) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 361 + MFM3 = D2 + MFM1 + CALL FM_ST2M('391.61',MFM4) + CALL FM_ADD(MFM4,MFM1,MFM6) + CALL FM_EQ(MFM6,MFM4) + CALL FM_SUB(MFM3,MFM4,MFM6) + CALL FM_EQ(MFM6,MFM4) + CALL FM_DIV(MFM4,MFM3,MFM6) + CALL FM_EQ(MFM6,MFM4) + CALL FM_ABS(MFM4,MFM6) + CALL FM_EQ(MFM6,MFM4) + IF (MFM4 > DSMALL) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 362 + CALL FM_ST2M('391.61',MFM4) + CALL FM_ST2M('661',MFM3) + CALL FM_ADD(MFM4,MFM3,MFM6) + CALL FM_EQ(MFM6,MFM4) + MFM3 = D2 + MIM1 + CALL FM_SUB(MFM3,MFM4,MFM6) + CALL FM_EQ(MFM6,MFM4) + CALL FM_DIV(MFM4,MFM3,MFM6) + CALL FM_EQ(MFM6,MFM4) + CALL FM_ABS(MFM4,MFM6) + CALL FM_EQ(MFM6,MFM4) + IF (MFM4 > DSMALL) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 363 + MZM3 = D2 + MZM1 + CALL ZM_ST2M('391.61',MZM4) + CALL ZM_ADD(MZM4,MZM1,MZM5) + CALL ZM_EQ(MZM5,MZM4) + CALL ZM_SUB(MZM3,MZM4,MZM5) + CALL ZM_EQ(MZM5,MZM4) + CALL ZM_DIV(MZM4,MZM3,MZM5) + CALL ZM_EQ(MZM5,MZM4) + CALL ZM_ABS(MZM4,MFM4) + IF (MFM4 > DSMALL) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 364 + CALL ZM_ST2M('411.11 + 421.21 i',MZM4) + CALL ZM_ST2M('581.21',MZM3) + CALL ZM_ADD(MZM4,MZM3,MZM5) + CALL ZM_EQ(MZM5,MZM4) + MZM3 = C2 + MFM1 + CALL ZM_SUB(MZM3,MZM4,MZM5) + CALL ZM_EQ(MZM5,MZM4) + CALL ZM_DIV(MZM4,MZM3,MZM5) + CALL ZM_EQ(MZM5,MZM4) + CALL ZM_ABS(MZM4,MFM4) + IF (MFM4 > RSMALL) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 365 + CALL ZM_ST2M('411.11 + 421.21 i',MZM4) + CALL ZM_ST2M('661',MZM3) + CALL ZM_ADD(MZM4,MZM3,MZM5) + CALL ZM_EQ(MZM5,MZM4) + MZM3 = C2 + MIM1 + CALL ZM_SUB(MZM3,MZM4,MZM5) + CALL ZM_EQ(MZM5,MZM4) + CALL ZM_DIV(MZM4,MZM3,MZM5) + CALL ZM_EQ(MZM5,MZM4) + CALL ZM_ABS(MZM4,MFM4) + IF (MFM4 > RSMALL) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 366 + MZM3 = C2 + MZM1 + CALL ZM_ST2M('411.11 + 421.21 i',MZM4) + CALL ZM_ADD(MZM4,MZM1,MZM5) + CALL ZM_EQ(MZM5,MZM4) + CALL ZM_SUB(MZM3,MZM4,MZM5) + CALL ZM_EQ(MZM5,MZM4) + CALL ZM_DIV(MZM4,MZM3,MZM5) + CALL ZM_EQ(MZM5,MZM4) + CALL ZM_ABS(MZM4,MFM4) + IF (MFM4 > RSMALL) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 367 + CALL ZM_ST2M('431.11 + 441.21 i',MZM4) + CALL ZM_ST2M('581.21',MZM3) + CALL ZM_ADD(MZM4,MZM3,MZM5) + CALL ZM_EQ(MZM5,MZM4) + MZM3 = CD2 + MFM1 + CALL ZM_SUB(MZM3,MZM4,MZM5) + CALL ZM_EQ(MZM5,MZM4) + CALL ZM_DIV(MZM4,MZM3,MZM5) + CALL ZM_EQ(MZM5,MZM4) + CALL ZM_ABS(MZM4,MFM4) + IF (MFM4 > DSMALL) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 368 + CALL ZM_ST2M('431.11 + 441.21 i',MZM4) + CALL ZM_ST2M('661',MZM3) + CALL ZM_ADD(MZM4,MZM3,MZM5) + CALL ZM_EQ(MZM5,MZM4) + MZM3 = CD2 + MIM1 + CALL ZM_SUB(MZM3,MZM4,MZM5) + CALL ZM_EQ(MZM5,MZM4) + CALL ZM_DIV(MZM4,MZM3,MZM5) + CALL ZM_EQ(MZM5,MZM4) + CALL ZM_ABS(MZM4,MFM4) + IF (MFM4 > DSMALL) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 369 + MZM3 = CD2 + MZM1 + CALL ZM_ST2M('431.11 + 441.21 i',MZM4) + CALL ZM_ADD(MZM4,MZM1,MZM5) + CALL ZM_EQ(MZM5,MZM4) + CALL ZM_SUB(MZM3,MZM4,MZM5) + CALL ZM_EQ(MZM5,MZM4) + CALL ZM_DIV(MZM4,MZM3,MZM5) + CALL ZM_EQ(MZM5,MZM4) + CALL ZM_ABS(MZM4,MFM4) + IF (MFM4 > DSMALL) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 370 + MFM3 = MFM1 + J2 + CALL FM_ST2M('131',MFM4) + CALL FM_ADD(MFM1,MFM4,MFM6) + CALL FM_EQ(MFM6,MFM4) + IF (MFM3 /= MFM4) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 371 + MFM3 = MFM1 + R2 + CALL FM_ST2M('241.21',MFM4) + CALL FM_ADD(MFM1,MFM4,MFM6) + CALL FM_EQ(MFM6,MFM4) + CALL FM_SUB(MFM3,MFM4,MFM6) + CALL FM_EQ(MFM6,MFM4) + CALL FM_DIV(MFM4,MFM3,MFM6) + CALL FM_EQ(MFM6,MFM4) + CALL FM_ABS(MFM4,MFM6) + CALL FM_EQ(MFM6,MFM4) + IF (MFM4 > RSMALL) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 372 + MFM3 = MFM1 + D2 + CALL FM_ST2M('391.61',MFM4) + CALL FM_ADD(MFM1,MFM4,MFM6) + CALL FM_EQ(MFM6,MFM4) + CALL FM_SUB(MFM3,MFM4,MFM6) + CALL FM_EQ(MFM6,MFM4) + CALL FM_DIV(MFM4,MFM3,MFM6) + CALL FM_EQ(MFM6,MFM4) + CALL FM_ABS(MFM4,MFM6) + CALL FM_EQ(MFM6,MFM4) + IF (MFM4 > DSMALL) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 373 + CALL ZM_ST2M('581.21',MZM3) + CALL ZM_ST2M('411.11 + 421.21 i',MZM4) + CALL ZM_ADD(MZM3,MZM4,MZM5) + CALL ZM_EQ(MZM5,MZM4) + MZM3 = MFM1 + C2 + CALL ZM_SUB(MZM3,MZM4,MZM5) + CALL ZM_EQ(MZM5,MZM4) + CALL ZM_DIV(MZM4,MZM3,MZM5) + CALL ZM_EQ(MZM5,MZM4) + CALL ZM_ABS(MZM4,MFM4) + IF (MFM4 > RSMALL) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 374 + CALL ZM_ST2M('431.11 + 441.21 i',MZM3) + CALL ZM_ST2M('581.21',MZM4) + CALL ZM_ADD(MZM4,MZM3,MZM5) + CALL ZM_EQ(MZM5,MZM4) + MZM3 = MFM1 + CD2 + CALL ZM_SUB(MZM3,MZM4,MZM5) + CALL ZM_EQ(MZM5,MZM4) + CALL ZM_DIV(MZM4,MZM3,MZM5) + CALL ZM_EQ(MZM5,MZM4) + CALL ZM_ABS(MZM4,MFM4) + IF (MFM4 > DSMALL) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 375 + MFM3 = MFM1 + MFM2 + CALL FM_ADD(MFM1,MFM2,MFM4) + IF (MFM4 /= MFM3) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 376 + MFM3 = MFM1 + MIM1 + CALL FM_ST2M('661',MFM4) + CALL FM_ADD(MFM1,MFM4,MFM6) + CALL FM_EQ(MFM6,MFM4) + IF (MFM4 /= MFM3) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 377 + MZM3 = MFM1 + MZM1 + CALL ZM_ST2M('581.21',MZM4) + CALL ZM_ADD(MZM4,MZM1,MZM5) + CALL ZM_EQ(MZM5,MZM4) + IF (MFM4 /= MFM3) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 378 + MIM3 = MIM1 + J2 + CALL IM_ST2M('131',MIM4) + CALL IM_ADD(MIM1,MIM4,MIM5) + CALL IM_EQ(MIM5,MIM4) + IF (MIM3 /= MIM4) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 379 + CALL FM_ST2M('241.21',MFM3) + CALL FM_ST2M('661',MFM4) + CALL FM_ADD(MFM4,MFM3,MFM6) + CALL FM_EQ(MFM6,MFM4) + MFM3 = MIM1 + R2 + CALL FM_SUB(MFM3,MFM4,MFM6) + CALL FM_EQ(MFM6,MFM4) + CALL FM_DIV(MFM4,MFM3,MFM6) + CALL FM_EQ(MFM6,MFM4) + CALL FM_ABS(MFM4,MFM6) + CALL FM_EQ(MFM6,MFM4) + IF (MFM4 > RSMALL) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 380 + CALL FM_ST2M('391.61',MFM3) + CALL FM_ST2M('661',MFM4) + CALL FM_ADD(MFM4,MFM3,MFM6) + CALL FM_EQ(MFM6,MFM4) + MFM3 = MIM1 + D2 + CALL FM_SUB(MFM3,MFM4,MFM6) + CALL FM_EQ(MFM6,MFM4) + CALL FM_DIV(MFM4,MFM3,MFM6) + CALL FM_EQ(MFM6,MFM4) + CALL FM_ABS(MFM4,MFM6) + CALL FM_EQ(MFM6,MFM4) + IF (MFM4 > DSMALL) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 381 + CALL ZM_ST2M('411.11 + 421.21 i',MZM3) + CALL ZM_ST2M('661',MZM4) + CALL ZM_ADD(MZM4,MZM3,MZM5) + CALL ZM_EQ(MZM5,MZM4) + MZM3 = MIM1 + C2 + CALL ZM_SUB(MZM3,MZM4,MZM5) + CALL ZM_EQ(MZM5,MZM4) + CALL ZM_DIV(MZM4,MZM3,MZM5) + CALL ZM_EQ(MZM5,MZM4) + CALL ZM_ABS(MZM4,MFM4) + IF (MFM4 > RSMALL) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 382 + CALL ZM_ST2M('431.11 + 441.21 i',MZM3) + CALL ZM_ST2M('661',MZM4) + CALL ZM_ADD(MZM4,MZM3,MZM5) + CALL ZM_EQ(MZM5,MZM4) + MZM3 = MIM1 + CD2 + CALL ZM_SUB(MZM3,MZM4,MZM5) + CALL ZM_EQ(MZM5,MZM4) + CALL ZM_DIV(MZM4,MZM3,MZM5) + CALL ZM_EQ(MZM5,MZM4) + CALL ZM_ABS(MZM4,MFM4) + IF (MFM4 > DSMALL) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 383 + MFM3 = MIM1 + MFM1 + CALL FM_ST2M('661',MFM4) + CALL FM_ADD(MFM4,MFM1,MFM6) + CALL FM_EQ(MFM6,MFM4) + IF (MFM4 /= MFM3) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 384 + MIM3 = MIM1 + MIM2 + CALL IM_ADD(MIM1,MIM2,MIM4) + IF (MIM4 /= MIM3) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 385 + MZM3 = MIM1 + MZM1 + CALL ZM_ST2M('661',MZM4) + CALL ZM_ADD(MZM4,MZM1,MZM5) + CALL ZM_EQ(MZM5,MZM4) + IF (MZM4 /= MZM3) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 386 + MZM3 = MZM1 + J2 + CALL ZM_ST2M('131',MZM4) + CALL ZM_ADD(MZM1,MZM4,MZM5) + CALL ZM_EQ(MZM5,MZM4) + IF (MZM3 /= MZM4) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 387 + MZM3 = MZM1 + R2 + CALL ZM_ST2M('241.21',MZM4) + CALL ZM_ADD(MZM1,MZM4,MZM5) + CALL ZM_EQ(MZM5,MZM4) + CALL ZM_SUB(MZM3,MZM4,MZM5) + CALL ZM_EQ(MZM5,MZM4) + CALL ZM_DIV(MZM4,MZM3,MZM5) + CALL ZM_EQ(MZM5,MZM4) + CALL ZM_ABS(MZM4,MFM4) + IF (MFM4 > RSMALL) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 388 + MZM3 = MZM1 + D2 + CALL ZM_ST2M('391.61',MZM4) + CALL ZM_ADD(MZM1,MZM4,MZM5) + CALL ZM_EQ(MZM5,MZM4) + CALL ZM_SUB(MZM3,MZM4,MZM5) + CALL ZM_EQ(MZM5,MZM4) + CALL ZM_DIV(MZM4,MZM3,MZM5) + CALL ZM_EQ(MZM5,MZM4) + CALL ZM_ABS(MZM4,MFM4) + IF (MFM4 > DSMALL) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 389 + MZM3 = MZM1 + C2 + CALL ZM_ST2M('411.11 + 421.21 i',MZM4) + CALL ZM_ADD(MZM1,MZM4,MZM5) + CALL ZM_EQ(MZM5,MZM4) + CALL ZM_SUB(MZM3,MZM4,MZM5) + CALL ZM_EQ(MZM5,MZM4) + CALL ZM_DIV(MZM4,MZM3,MZM5) + CALL ZM_EQ(MZM5,MZM4) + CALL ZM_ABS(MZM4,MFM4) + IF (MFM4 > RSMALL) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 390 + MZM3 = MZM1 + CD2 + CALL ZM_ST2M('431.11 + 441.21 i',MZM4) + CALL ZM_ADD(MZM1,MZM4,MZM5) + CALL ZM_EQ(MZM5,MZM4) + CALL ZM_SUB(MZM3,MZM4,MZM5) + CALL ZM_EQ(MZM5,MZM4) + CALL ZM_DIV(MZM4,MZM3,MZM5) + CALL ZM_EQ(MZM5,MZM4) + CALL ZM_ABS(MZM4,MFM4) + IF (MFM4 > DSMALL) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 391 + MZM3 = MZM1 + MFM1 + CALL ZM_ST2M('581.21',MZM4) + CALL ZM_ADD(MZM1,MZM4,MZM5) + CALL ZM_EQ(MZM5,MZM4) + IF (MZM4 /= MZM3) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 392 + MZM3 = MZM1 + MIM1 + CALL ZM_ST2M('661',MZM4) + CALL ZM_ADD(MZM1,MZM4,MZM5) + CALL ZM_EQ(MZM5,MZM4) + IF (MZM4 /= MZM3) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 393 + MZM3 = MZM1 + MZM2 + CALL ZM_ADD(MZM1,MZM2,MZM5) + CALL ZM_EQ(MZM5,MZM4) + IF (MZM4 /= MZM3) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 394 + MFM3 = +MFM1 + CALL FM_EQ(MFM1,MFM4) + IF (MFM3 /= MFM4) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 395 + MIM3 = +MIM1 + CALL IM_EQ(MIM1,MIM4) + IF (MIM3 /= MIM4) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 396 + MZM3 = +MZM1 + CALL ZM_EQ(MZM1,MZM4) + IF (MZM3 /= MZM4) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + END SUBROUTINE TEST31 + + SUBROUTINE TEST32(NCASE,NERROR,KLOG) + +! Test the '-' arithmetic operator. + + USE FMVALS + USE FMZM + USE TEST_VARS + IMPLICIT NONE + + INTEGER KLOG,NERROR,NCASE + + WRITE (KW,"(/' Testing the derived type - interface.')") + + RSMALL = EPSILON(1.0)*100.0 + DSMALL = EPSILON(1.0D0)*100.0 + + NCASE = 397 + MFM3 = J2 - MFM1 + CALL FM_ST2M('131',MFM4) + CALL FM_SUB(MFM4,MFM1,MFM6) + CALL FM_EQ(MFM6,MFM4) + IF (MFM3 /= MFM4) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 398 + MIM3 = J2 - MIM1 + CALL IM_ST2M('131',MIM4) + CALL IM_SUB(MIM4,MIM1,MIM5) + CALL IM_EQ(MIM5,MIM4) + IF (MIM3 /= MIM4) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 399 + MZM3 = J2 - MZM1 + CALL ZM_ST2M('131',MZM4) + CALL ZM_SUB(MZM4,MZM1,MZM5) + CALL ZM_EQ(MZM5,MZM4) + IF (MZM3 /= MZM4) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 400 + MFM3 = R2 - MFM1 + CALL FM_ST2M('241.21',MFM4) + CALL FM_SUB(MFM4,MFM1,MFM6) + CALL FM_EQ(MFM6,MFM4) + CALL FM_SUB(MFM3,MFM4,MFM6) + CALL FM_EQ(MFM6,MFM4) + CALL FM_DIV(MFM4,MFM3,MFM6) + CALL FM_EQ(MFM6,MFM4) + CALL FM_ABS(MFM4,MFM6) + CALL FM_EQ(MFM6,MFM4) + IF (MFM4 > RSMALL) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 401 + CALL FM_ST2M('241.21',MFM4) + CALL FM_ST2M('661',MFM3) + CALL FM_SUB(MFM4,MFM3,MFM6) + CALL FM_EQ(MFM6,MFM4) + MFM3 = R2 - MIM1 + CALL FM_SUB(MFM3,MFM4,MFM6) + CALL FM_EQ(MFM6,MFM4) + CALL FM_DIV(MFM4,MFM3,MFM6) + CALL FM_EQ(MFM6,MFM4) + CALL FM_ABS(MFM4,MFM6) + CALL FM_EQ(MFM6,MFM4) + IF (MFM4 > RSMALL) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 402 + MZM3 = R2 - MZM1 + CALL ZM_ST2M('241.21',MZM4) + CALL ZM_SUB(MZM4,MZM1,MZM5) + CALL ZM_EQ(MZM5,MZM4) + CALL ZM_SUB(MZM3,MZM4,MZM5) + CALL ZM_EQ(MZM5,MZM4) + CALL ZM_DIV(MZM4,MZM3,MZM5) + CALL ZM_EQ(MZM5,MZM4) + CALL ZM_ABS(MZM4,MFM4) + IF (MFM4 > RSMALL) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 403 + MFM3 = D2 - MFM1 + CALL FM_ST2M('391.61',MFM4) + CALL FM_SUB(MFM4,MFM1,MFM6) + CALL FM_EQ(MFM6,MFM4) + CALL FM_SUB(MFM3,MFM4,MFM6) + CALL FM_EQ(MFM6,MFM4) + CALL FM_DIV(MFM4,MFM3,MFM6) + CALL FM_EQ(MFM6,MFM4) + CALL FM_ABS(MFM4,MFM6) + CALL FM_EQ(MFM6,MFM4) + IF (MFM4 > DSMALL) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 404 + CALL FM_ST2M('391.61',MFM4) + CALL FM_ST2M('661',MFM3) + CALL FM_SUB(MFM4,MFM3,MFM6) + CALL FM_EQ(MFM6,MFM4) + MFM3 = D2 - MIM1 + CALL FM_SUB(MFM3,MFM4,MFM6) + CALL FM_EQ(MFM6,MFM4) + CALL FM_DIV(MFM4,MFM3,MFM6) + CALL FM_EQ(MFM6,MFM4) + CALL FM_ABS(MFM4,MFM6) + CALL FM_EQ(MFM6,MFM4) + IF (MFM4 > DSMALL) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 405 + MZM3 = D2 - MZM1 + CALL ZM_ST2M('391.61',MZM4) + CALL ZM_SUB(MZM4,MZM1,MZM5) + CALL ZM_EQ(MZM5,MZM4) + CALL ZM_SUB(MZM3,MZM4,MZM5) + CALL ZM_EQ(MZM5,MZM4) + CALL ZM_DIV(MZM4,MZM3,MZM5) + CALL ZM_EQ(MZM5,MZM4) + CALL ZM_ABS(MZM4,MFM4) + IF (MFM4 > DSMALL) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 406 + CALL ZM_ST2M('411.11 + 421.21 i',MZM4) + CALL ZM_ST2M('581.21',MZM3) + CALL ZM_SUB(MZM4,MZM3,MZM5) + CALL ZM_EQ(MZM5,MZM4) + MZM3 = C2 - MFM1 + CALL ZM_SUB(MZM3,MZM4,MZM5) + CALL ZM_EQ(MZM5,MZM4) + CALL ZM_DIV(MZM4,MZM3,MZM5) + CALL ZM_EQ(MZM5,MZM4) + CALL ZM_ABS(MZM4,MFM4) + IF (MFM4 > RSMALL) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 407 + CALL ZM_ST2M('411.11 + 421.21 i',MZM4) + CALL ZM_ST2M('661',MZM3) + CALL ZM_SUB(MZM4,MZM3,MZM5) + CALL ZM_EQ(MZM5,MZM4) + MZM3 = C2 - MIM1 + CALL ZM_SUB(MZM3,MZM4,MZM5) + CALL ZM_EQ(MZM5,MZM4) + CALL ZM_DIV(MZM4,MZM3,MZM5) + CALL ZM_EQ(MZM5,MZM4) + CALL ZM_ABS(MZM4,MFM4) + IF (MFM4 > RSMALL) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 408 + MZM3 = C2 - MZM1 + CALL ZM_ST2M('411.11 + 421.21 i',MZM4) + CALL ZM_SUB(MZM4,MZM1,MZM5) + CALL ZM_EQ(MZM5,MZM4) + CALL ZM_SUB(MZM3,MZM4,MZM5) + CALL ZM_EQ(MZM5,MZM4) + CALL ZM_DIV(MZM4,MZM3,MZM5) + CALL ZM_EQ(MZM5,MZM4) + CALL ZM_ABS(MZM4,MFM4) + IF (MFM4 > RSMALL) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 409 + CALL ZM_ST2M('431.11 + 441.21 i',MZM4) + CALL ZM_ST2M('581.21',MZM3) + CALL ZM_SUB(MZM4,MZM3,MZM5) + CALL ZM_EQ(MZM5,MZM4) + MZM3 = CD2 - MFM1 + CALL ZM_SUB(MZM3,MZM4,MZM5) + CALL ZM_EQ(MZM5,MZM4) + CALL ZM_DIV(MZM4,MZM3,MZM5) + CALL ZM_EQ(MZM5,MZM4) + CALL ZM_ABS(MZM4,MFM4) + IF (MFM4 > DSMALL) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 410 + CALL ZM_ST2M('431.11 + 441.21 i',MZM4) + CALL ZM_ST2M('661',MZM3) + CALL ZM_SUB(MZM4,MZM3,MZM5) + CALL ZM_EQ(MZM5,MZM4) + MZM3 = CD2 - MIM1 + CALL ZM_SUB(MZM3,MZM4,MZM5) + CALL ZM_EQ(MZM5,MZM4) + CALL ZM_DIV(MZM4,MZM3,MZM5) + CALL ZM_EQ(MZM5,MZM4) + CALL ZM_ABS(MZM4,MFM4) + IF (MFM4 > DSMALL) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 411 + MZM3 = CD2 - MZM1 + CALL ZM_ST2M('431.11 + 441.21 i',MZM4) + CALL ZM_SUB(MZM4,MZM1,MZM5) + CALL ZM_EQ(MZM5,MZM4) + CALL ZM_SUB(MZM3,MZM4,MZM5) + CALL ZM_EQ(MZM5,MZM4) + CALL ZM_DIV(MZM4,MZM3,MZM5) + CALL ZM_EQ(MZM5,MZM4) + CALL ZM_ABS(MZM4,MFM4) + IF (MFM4 > DSMALL) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 412 + MFM3 = MFM1 - J2 + CALL FM_ST2M('131',MFM4) + CALL FM_SUB(MFM1,MFM4,MFM6) + CALL FM_EQ(MFM6,MFM4) + IF (MFM3 /= MFM4) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 413 + MFM3 = MFM1 - R2 + CALL FM_ST2M('241.21',MFM4) + CALL FM_SUB(MFM1,MFM4,MFM6) + CALL FM_EQ(MFM6,MFM4) + CALL FM_SUB(MFM3,MFM4,MFM6) + CALL FM_EQ(MFM6,MFM4) + CALL FM_DIV(MFM4,MFM3,MFM6) + CALL FM_EQ(MFM6,MFM4) + CALL FM_ABS(MFM4,MFM6) + CALL FM_EQ(MFM6,MFM4) + IF (MFM4 > RSMALL) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 414 + MFM3 = MFM1 - D2 + CALL FM_ST2M('391.61',MFM4) + CALL FM_SUB(MFM1,MFM4,MFM6) + CALL FM_EQ(MFM6,MFM4) + CALL FM_SUB(MFM3,MFM4,MFM6) + CALL FM_EQ(MFM6,MFM4) + CALL FM_DIV(MFM4,MFM3,MFM6) + CALL FM_EQ(MFM6,MFM4) + CALL FM_ABS(MFM4,MFM6) + CALL FM_EQ(MFM6,MFM4) + IF (MFM4 > DSMALL) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 415 + CALL ZM_ST2M('581.21',MZM3) + CALL ZM_ST2M('411.11 + 421.21 i',MZM4) + CALL ZM_SUB(MZM3,MZM4,MZM5) + CALL ZM_EQ(MZM5,MZM4) + MZM3 = MFM1 - C2 + CALL ZM_SUB(MZM3,MZM4,MZM5) + CALL ZM_EQ(MZM5,MZM4) + CALL ZM_DIV(MZM4,MZM3,MZM5) + CALL ZM_EQ(MZM5,MZM4) + CALL ZM_ABS(MZM4,MFM4) + IF (MFM4 > RSMALL) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 416 + CALL ZM_ST2M('431.11 + 441.21 i',MZM3) + CALL ZM_ST2M('581.21',MZM4) + CALL ZM_SUB(MZM4,MZM3,MZM5) + CALL ZM_EQ(MZM5,MZM4) + MZM3 = MFM1 - CD2 + CALL ZM_SUB(MZM3,MZM4,MZM5) + CALL ZM_EQ(MZM5,MZM4) + CALL ZM_DIV(MZM4,MZM3,MZM5) + CALL ZM_EQ(MZM5,MZM4) + CALL ZM_ABS(MZM4,MFM4) + IF (MFM4 > DSMALL) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 417 + MFM3 = MFM1 - MFM2 + CALL FM_SUB(MFM1,MFM2,MFM4) + IF (MFM4 /= MFM3) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 418 + MFM3 = MFM1 - MIM1 + CALL FM_ST2M('661',MFM4) + CALL FM_SUB(MFM1,MFM4,MFM6) + CALL FM_EQ(MFM6,MFM4) + IF (MFM4 /= MFM3) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 419 + MZM3 = MFM1 - MZM1 + CALL ZM_ST2M('581.21',MZM4) + CALL ZM_SUB(MZM4,MZM1,MZM5) + CALL ZM_EQ(MZM5,MZM4) + IF (MFM4 /= MFM3) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 420 + MIM3 = MIM1 - J2 + CALL IM_ST2M('131',MIM4) + CALL IM_SUB(MIM1,MIM4,MIM5) + CALL IM_EQ(MIM5,MIM4) + IF (MIM3 /= MIM4) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 421 + CALL FM_ST2M('241.21',MFM3) + CALL FM_ST2M('661',MFM4) + CALL FM_SUB(MFM4,MFM3,MFM6) + CALL FM_EQ(MFM6,MFM4) + MFM3 = MIM1 - R2 + CALL FM_SUB(MFM3,MFM4,MFM6) + CALL FM_EQ(MFM6,MFM4) + CALL FM_DIV(MFM4,MFM3,MFM6) + CALL FM_EQ(MFM6,MFM4) + CALL FM_ABS(MFM4,MFM6) + CALL FM_EQ(MFM6,MFM4) + IF (MFM4 > RSMALL) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 422 + CALL FM_ST2M('391.61',MFM3) + CALL FM_ST2M('661',MFM4) + CALL FM_SUB(MFM4,MFM3,MFM6) + CALL FM_EQ(MFM6,MFM4) + MFM3 = MIM1 - D2 + CALL FM_SUB(MFM3,MFM4,MFM6) + CALL FM_EQ(MFM6,MFM4) + CALL FM_DIV(MFM4,MFM3,MFM6) + CALL FM_EQ(MFM6,MFM4) + CALL FM_ABS(MFM4,MFM6) + CALL FM_EQ(MFM6,MFM4) + IF (MFM4 > DSMALL) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 423 + CALL ZM_ST2M('411.11 + 421.21 i',MZM3) + CALL ZM_ST2M('661',MZM4) + CALL ZM_SUB(MZM4,MZM3,MZM5) + CALL ZM_EQ(MZM5,MZM4) + MZM3 = MIM1 - C2 + CALL ZM_SUB(MZM3,MZM4,MZM5) + CALL ZM_EQ(MZM5,MZM4) + CALL ZM_DIV(MZM4,MZM3,MZM5) + CALL ZM_EQ(MZM5,MZM4) + CALL ZM_ABS(MZM4,MFM4) + IF (MFM4 > RSMALL) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 424 + CALL ZM_ST2M('431.11 + 441.21 i',MZM3) + CALL ZM_ST2M('661',MZM4) + CALL ZM_SUB(MZM4,MZM3,MZM5) + CALL ZM_EQ(MZM5,MZM4) + MZM3 = MIM1 - CD2 + CALL ZM_SUB(MZM3,MZM4,MZM5) + CALL ZM_EQ(MZM5,MZM4) + CALL ZM_DIV(MZM4,MZM3,MZM5) + CALL ZM_EQ(MZM5,MZM4) + CALL ZM_ABS(MZM4,MFM4) + IF (MFM4 > DSMALL) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 425 + MFM3 = MIM1 - MFM1 + CALL FM_ST2M('661',MFM4) + CALL FM_SUB(MFM4,MFM1,MFM6) + CALL FM_EQ(MFM6,MFM4) + IF (MFM4 /= MFM3) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 426 + MIM3 = MIM1 - MIM2 + CALL IM_SUB(MIM1,MIM2,MIM4) + IF (MIM4 /= MIM3) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 427 + MZM3 = MIM1 - MZM1 + CALL ZM_ST2M('661',MZM4) + CALL ZM_SUB(MZM4,MZM1,MZM5) + CALL ZM_EQ(MZM5,MZM4) + IF (MZM4 /= MZM3) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 428 + MZM3 = MZM1 - J2 + CALL ZM_ST2M('131',MZM4) + CALL ZM_SUB(MZM1,MZM4,MZM5) + CALL ZM_EQ(MZM5,MZM4) + IF (MZM3 /= MZM4) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 429 + MZM3 = MZM1 - R2 + CALL ZM_ST2M('241.21',MZM4) + CALL ZM_SUB(MZM1,MZM4,MZM5) + CALL ZM_EQ(MZM5,MZM4) + CALL ZM_SUB(MZM3,MZM4,MZM5) + CALL ZM_EQ(MZM5,MZM4) + CALL ZM_DIV(MZM4,MZM3,MZM5) + CALL ZM_EQ(MZM5,MZM4) + CALL ZM_ABS(MZM4,MFM4) + IF (MFM4 > RSMALL) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 430 + MZM3 = MZM1 - D2 + CALL ZM_ST2M('391.61',MZM4) + CALL ZM_SUB(MZM1,MZM4,MZM5) + CALL ZM_EQ(MZM5,MZM4) + CALL ZM_SUB(MZM3,MZM4,MZM5) + CALL ZM_EQ(MZM5,MZM4) + CALL ZM_DIV(MZM4,MZM3,MZM5) + CALL ZM_EQ(MZM5,MZM4) + CALL ZM_ABS(MZM4,MFM4) + IF (MFM4 > DSMALL) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 431 + MZM3 = MZM1 - C2 + CALL ZM_ST2M('411.11 + 421.21 i',MZM4) + CALL ZM_SUB(MZM1,MZM4,MZM5) + CALL ZM_EQ(MZM5,MZM4) + CALL ZM_SUB(MZM3,MZM4,MZM5) + CALL ZM_EQ(MZM5,MZM4) + CALL ZM_DIV(MZM4,MZM3,MZM5) + CALL ZM_EQ(MZM5,MZM4) + CALL ZM_ABS(MZM4,MFM4) + IF (MFM4 > RSMALL) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 432 + MZM3 = MZM1 - CD2 + CALL ZM_ST2M('431.11 + 441.21 i',MZM4) + CALL ZM_SUB(MZM1,MZM4,MZM5) + CALL ZM_EQ(MZM5,MZM4) + CALL ZM_SUB(MZM3,MZM4,MZM5) + CALL ZM_EQ(MZM5,MZM4) + CALL ZM_DIV(MZM4,MZM3,MZM5) + CALL ZM_EQ(MZM5,MZM4) + CALL ZM_ABS(MZM4,MFM4) + IF (MFM4 > DSMALL) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 433 + MZM3 = MZM1 - MFM1 + CALL ZM_ST2M('581.21',MZM4) + CALL ZM_SUB(MZM1,MZM4,MZM5) + CALL ZM_EQ(MZM5,MZM4) + IF (MZM4 /= MZM3) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 434 + MZM3 = MZM1 - MIM1 + CALL ZM_ST2M('661',MZM4) + CALL ZM_SUB(MZM1,MZM4,MZM5) + CALL ZM_EQ(MZM5,MZM4) + IF (MZM4 /= MZM3) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 435 + MZM3 = MZM1 - MZM2 + CALL ZM_SUB(MZM1,MZM2,MZM5) + CALL ZM_EQ(MZM5,MZM4) + IF (MZM4 /= MZM3) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 436 + MFM3 = -MFM1 + CALL FM_I2M(0,MFM4) + CALL FM_SUB(MFM4,MFM1,MFM6) + CALL FM_EQ(MFM6,MFM4) + IF (MFM3 /= MFM4) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 437 + MIM3 = -MIM1 + CALL IM_I2M(0,MIM4) + CALL IM_SUB(MIM4,MIM1,MIM5) + CALL IM_EQ(MIM5,MIM4) + IF (MIM3 /= MIM4) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 438 + MZM3 = -MZM1 + CALL ZM_I2M(0,MZM4) + CALL ZM_SUB(MZM4,MZM1,MZM5) + CALL ZM_EQ(MZM5,MZM4) + IF (MZM3 /= MZM4) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + END SUBROUTINE TEST32 + + SUBROUTINE TEST33(NCASE,NERROR,KLOG) + +! Test the '*' arithmetic operator. + + USE FMVALS + USE FMZM + USE TEST_VARS + IMPLICIT NONE + + INTEGER KLOG,NERROR,NCASE + + WRITE (KW,"(/' Testing the derived type * interface.')") + + RSMALL = EPSILON(1.0)*100.0 + DSMALL = EPSILON(1.0D0)*100.0 + + NCASE = 439 + MFM3 = J2 * MFM1 + CALL FM_ST2M('131',MFM4) + CALL FM_MPY(MFM4,MFM1,MFM6) + CALL FM_EQ(MFM6,MFM4) + IF (MFM3 /= MFM4) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 440 + MIM3 = J2 * MIM1 + CALL IM_ST2M('131',MIM4) + CALL IM_MPY(MIM4,MIM1,MIM5) + CALL IM_EQ(MIM5,MIM4) + IF (MIM3 /= MIM4) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 441 + MZM3 = J2 * MZM1 + CALL ZM_ST2M('131',MZM4) + CALL ZM_MPY(MZM4,MZM1,MZM5) + CALL ZM_EQ(MZM5,MZM4) + IF (MZM3 /= MZM4) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 442 + MFM3 = R2 * MFM1 + CALL FM_ST2M('241.21',MFM4) + CALL FM_MPY(MFM4,MFM1,MFM6) + CALL FM_EQ(MFM6,MFM4) + CALL FM_SUB(MFM3,MFM4,MFM6) + CALL FM_EQ(MFM6,MFM4) + CALL FM_DIV(MFM4,MFM3,MFM6) + CALL FM_EQ(MFM6,MFM4) + CALL FM_ABS(MFM4,MFM6) + CALL FM_EQ(MFM6,MFM4) + IF (MFM4 > RSMALL) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 443 + CALL FM_ST2M('241.21',MFM4) + CALL FM_ST2M('661',MFM3) + CALL FM_MPY(MFM4,MFM3,MFM6) + CALL FM_EQ(MFM6,MFM4) + MFM3 = R2 * MIM1 + CALL FM_SUB(MFM3,MFM4,MFM6) + CALL FM_EQ(MFM6,MFM4) + CALL FM_DIV(MFM4,MFM3,MFM6) + CALL FM_EQ(MFM6,MFM4) + CALL FM_ABS(MFM4,MFM6) + CALL FM_EQ(MFM6,MFM4) + IF (MFM4 > RSMALL) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 444 + MZM3 = R2 * MZM1 + CALL ZM_ST2M('241.21',MZM4) + CALL ZM_MPY(MZM4,MZM1,MZM5) + CALL ZM_EQ(MZM5,MZM4) + CALL ZM_SUB(MZM3,MZM4,MZM5) + CALL ZM_EQ(MZM5,MZM4) + CALL ZM_DIV(MZM4,MZM3,MZM5) + CALL ZM_EQ(MZM5,MZM4) + CALL ZM_ABS(MZM4,MFM4) + IF (MFM4 > RSMALL) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 445 + MFM3 = D2 * MFM1 + CALL FM_ST2M('391.61',MFM4) + CALL FM_MPY(MFM4,MFM1,MFM6) + CALL FM_EQ(MFM6,MFM4) + CALL FM_SUB(MFM3,MFM4,MFM6) + CALL FM_EQ(MFM6,MFM4) + CALL FM_DIV(MFM4,MFM3,MFM6) + CALL FM_EQ(MFM6,MFM4) + CALL FM_ABS(MFM4,MFM6) + CALL FM_EQ(MFM6,MFM4) + IF (MFM4 > DSMALL) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 446 + CALL FM_ST2M('391.61',MFM4) + CALL FM_ST2M('661',MFM3) + CALL FM_MPY(MFM4,MFM3,MFM6) + CALL FM_EQ(MFM6,MFM4) + MFM3 = D2 * MIM1 + CALL FM_SUB(MFM3,MFM4,MFM6) + CALL FM_EQ(MFM6,MFM4) + CALL FM_DIV(MFM4,MFM3,MFM6) + CALL FM_EQ(MFM6,MFM4) + CALL FM_ABS(MFM4,MFM6) + CALL FM_EQ(MFM6,MFM4) + IF (MFM4 > DSMALL) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 447 + MZM3 = D2 * MZM1 + CALL ZM_ST2M('391.61',MZM4) + CALL ZM_MPY(MZM4,MZM1,MZM5) + CALL ZM_EQ(MZM5,MZM4) + CALL ZM_SUB(MZM3,MZM4,MZM5) + CALL ZM_EQ(MZM5,MZM4) + CALL ZM_DIV(MZM4,MZM3,MZM5) + CALL ZM_EQ(MZM5,MZM4) + CALL ZM_ABS(MZM4,MFM4) + IF (MFM4 > DSMALL) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 448 + CALL ZM_ST2M('411.11 + 421.21 i',MZM4) + CALL ZM_ST2M('581.21',MZM3) + CALL ZM_MPY(MZM4,MZM3,MZM5) + CALL ZM_EQ(MZM5,MZM4) + MZM3 = C2 * MFM1 + CALL ZM_SUB(MZM3,MZM4,MZM5) + CALL ZM_EQ(MZM5,MZM4) + CALL ZM_DIV(MZM4,MZM3,MZM5) + CALL ZM_EQ(MZM5,MZM4) + CALL ZM_ABS(MZM4,MFM4) + IF (MFM4 > RSMALL) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 449 + CALL ZM_ST2M('411.11 + 421.21 i',MZM4) + CALL ZM_ST2M('661',MZM3) + CALL ZM_MPY(MZM4,MZM3,MZM5) + CALL ZM_EQ(MZM5,MZM4) + MZM3 = C2 * MIM1 + CALL ZM_SUB(MZM3,MZM4,MZM5) + CALL ZM_EQ(MZM5,MZM4) + CALL ZM_DIV(MZM4,MZM3,MZM5) + CALL ZM_EQ(MZM5,MZM4) + CALL ZM_ABS(MZM4,MFM4) + IF (MFM4 > RSMALL) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 450 + MZM3 = C2 * MZM1 + CALL ZM_ST2M('411.11 + 421.21 i',MZM4) + CALL ZM_MPY(MZM4,MZM1,MZM5) + CALL ZM_EQ(MZM5,MZM4) + CALL ZM_SUB(MZM3,MZM4,MZM5) + CALL ZM_EQ(MZM5,MZM4) + CALL ZM_DIV(MZM4,MZM3,MZM5) + CALL ZM_EQ(MZM5,MZM4) + CALL ZM_ABS(MZM4,MFM4) + IF (MFM4 > RSMALL) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 451 + CALL ZM_ST2M('431.11 + 441.21 i',MZM4) + CALL ZM_ST2M('581.21',MZM3) + CALL ZM_MPY(MZM4,MZM3,MZM5) + CALL ZM_EQ(MZM5,MZM4) + MZM3 = CD2 * MFM1 + CALL ZM_SUB(MZM3,MZM4,MZM5) + CALL ZM_EQ(MZM5,MZM4) + CALL ZM_DIV(MZM4,MZM3,MZM5) + CALL ZM_EQ(MZM5,MZM4) + CALL ZM_ABS(MZM4,MFM4) + IF (MFM4 > DSMALL) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 452 + CALL ZM_ST2M('431.11 + 441.21 i',MZM4) + CALL ZM_ST2M('661',MZM3) + CALL ZM_MPY(MZM4,MZM3,MZM5) + CALL ZM_EQ(MZM5,MZM4) + MZM3 = CD2 * MIM1 + CALL ZM_SUB(MZM3,MZM4,MZM5) + CALL ZM_EQ(MZM5,MZM4) + CALL ZM_DIV(MZM4,MZM3,MZM5) + CALL ZM_EQ(MZM5,MZM4) + CALL ZM_ABS(MZM4,MFM4) + IF (MFM4 > DSMALL) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 453 + MZM3 = CD2 * MZM1 + CALL ZM_ST2M('431.11 + 441.21 i',MZM4) + CALL ZM_MPY(MZM4,MZM1,MZM5) + CALL ZM_EQ(MZM5,MZM4) + CALL ZM_SUB(MZM3,MZM4,MZM5) + CALL ZM_EQ(MZM5,MZM4) + CALL ZM_DIV(MZM4,MZM3,MZM5) + CALL ZM_EQ(MZM5,MZM4) + CALL ZM_ABS(MZM4,MFM4) + IF (MFM4 > DSMALL) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 454 + MFM3 = MFM1 * J2 + CALL FM_ST2M('131',MFM4) + CALL FM_MPY(MFM1,MFM4,MFM6) + CALL FM_EQ(MFM6,MFM4) + IF (MFM3 /= MFM4) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 455 + MFM3 = MFM1 * R2 + CALL FM_ST2M('241.21',MFM4) + CALL FM_MPY(MFM1,MFM4,MFM6) + CALL FM_EQ(MFM6,MFM4) + CALL FM_SUB(MFM3,MFM4,MFM6) + CALL FM_EQ(MFM6,MFM4) + CALL FM_DIV(MFM4,MFM3,MFM6) + CALL FM_EQ(MFM6,MFM4) + CALL FM_ABS(MFM4,MFM6) + CALL FM_EQ(MFM6,MFM4) + IF (MFM4 > RSMALL) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 456 + MFM3 = MFM1 * D2 + CALL FM_ST2M('391.61',MFM4) + CALL FM_MPY(MFM1,MFM4,MFM6) + CALL FM_EQ(MFM6,MFM4) + CALL FM_SUB(MFM3,MFM4,MFM6) + CALL FM_EQ(MFM6,MFM4) + CALL FM_DIV(MFM4,MFM3,MFM6) + CALL FM_EQ(MFM6,MFM4) + CALL FM_ABS(MFM4,MFM6) + CALL FM_EQ(MFM6,MFM4) + IF (MFM4 > DSMALL) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 457 + CALL ZM_ST2M('581.21',MZM3) + CALL ZM_ST2M('411.11 + 421.21 i',MZM4) + CALL ZM_MPY(MZM3,MZM4,MZM5) + CALL ZM_EQ(MZM5,MZM4) + MZM3 = MFM1 * C2 + CALL ZM_SUB(MZM3,MZM4,MZM5) + CALL ZM_EQ(MZM5,MZM4) + CALL ZM_DIV(MZM4,MZM3,MZM5) + CALL ZM_EQ(MZM5,MZM4) + CALL ZM_ABS(MZM4,MFM4) + IF (MFM4 > RSMALL) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 458 + CALL ZM_ST2M('431.11 + 441.21 i',MZM3) + CALL ZM_ST2M('581.21',MZM4) + CALL ZM_MPY(MZM4,MZM3,MZM5) + CALL ZM_EQ(MZM5,MZM4) + MZM3 = MFM1 * CD2 + CALL ZM_SUB(MZM3,MZM4,MZM5) + CALL ZM_EQ(MZM5,MZM4) + CALL ZM_DIV(MZM4,MZM3,MZM5) + CALL ZM_EQ(MZM5,MZM4) + CALL ZM_ABS(MZM4,MFM4) + IF (MFM4 > DSMALL) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 459 + MFM3 = MFM1 * MFM2 + CALL FM_MPY(MFM1,MFM2,MFM4) + IF (MFM4 /= MFM3) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 460 + MFM3 = MFM1 * MIM1 + CALL FM_ST2M('661',MFM4) + CALL FM_MPY(MFM1,MFM4,MFM6) + CALL FM_EQ(MFM6,MFM4) + IF (MFM4 /= MFM3) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 461 + MZM3 = MFM1 * MZM1 + CALL ZM_ST2M('581.21',MZM4) + CALL ZM_MPY(MZM4,MZM1,MZM5) + CALL ZM_EQ(MZM5,MZM4) + IF (MFM4 /= MFM3) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 462 + MIM3 = MIM1 * J2 + CALL IM_ST2M('131',MIM4) + CALL IM_MPY(MIM1,MIM4,MIM5) + CALL IM_EQ(MIM5,MIM4) + IF (MIM3 /= MIM4) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 463 + CALL FM_ST2M('241.21',MFM3) + CALL FM_ST2M('661',MFM4) + CALL FM_MPY(MFM4,MFM3,MFM6) + CALL FM_EQ(MFM6,MFM4) + MFM3 = MIM1 * R2 + CALL FM_SUB(MFM3,MFM4,MFM6) + CALL FM_EQ(MFM6,MFM4) + CALL FM_DIV(MFM4,MFM3,MFM6) + CALL FM_EQ(MFM6,MFM4) + CALL FM_ABS(MFM4,MFM6) + CALL FM_EQ(MFM6,MFM4) + IF (MFM4 > RSMALL) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 464 + CALL FM_ST2M('391.61',MFM3) + CALL FM_ST2M('661',MFM4) + CALL FM_MPY(MFM4,MFM3,MFM6) + CALL FM_EQ(MFM6,MFM4) + MFM3 = MIM1 * D2 + CALL FM_SUB(MFM3,MFM4,MFM6) + CALL FM_EQ(MFM6,MFM4) + CALL FM_DIV(MFM4,MFM3,MFM6) + CALL FM_EQ(MFM6,MFM4) + CALL FM_ABS(MFM4,MFM6) + CALL FM_EQ(MFM6,MFM4) + IF (MFM4 > DSMALL) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 465 + CALL ZM_ST2M('411.11 + 421.21 i',MZM3) + CALL ZM_ST2M('661',MZM4) + CALL ZM_MPY(MZM4,MZM3,MZM5) + CALL ZM_EQ(MZM5,MZM4) + MZM3 = MIM1 * C2 + CALL ZM_SUB(MZM3,MZM4,MZM5) + CALL ZM_EQ(MZM5,MZM4) + CALL ZM_DIV(MZM4,MZM3,MZM5) + CALL ZM_EQ(MZM5,MZM4) + CALL ZM_ABS(MZM4,MFM4) + IF (MFM4 > RSMALL) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 466 + CALL ZM_ST2M('431.11 + 441.21 i',MZM3) + CALL ZM_ST2M('661',MZM4) + CALL ZM_MPY(MZM4,MZM3,MZM5) + CALL ZM_EQ(MZM5,MZM4) + MZM3 = MIM1 * CD2 + CALL ZM_SUB(MZM3,MZM4,MZM5) + CALL ZM_EQ(MZM5,MZM4) + CALL ZM_DIV(MZM4,MZM3,MZM5) + CALL ZM_EQ(MZM5,MZM4) + CALL ZM_ABS(MZM4,MFM4) + IF (MFM4 > DSMALL) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 467 + MFM3 = MIM1 * MFM1 + CALL FM_ST2M('661',MFM4) + CALL FM_MPY(MFM4,MFM1,MFM6) + CALL FM_EQ(MFM6,MFM4) + IF (MFM4 /= MFM3) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 468 + MIM3 = MIM1 * MIM2 + CALL IM_MPY(MIM1,MIM2,MIM4) + IF (MIM4 /= MIM3) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 469 + MZM3 = MIM1 * MZM1 + CALL ZM_ST2M('661',MZM4) + CALL ZM_MPY(MZM4,MZM1,MZM5) + CALL ZM_EQ(MZM5,MZM4) + IF (MZM4 /= MZM3) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 470 + MZM3 = MZM1 * J2 + CALL ZM_ST2M('131',MZM4) + CALL ZM_MPY(MZM1,MZM4,MZM5) + CALL ZM_EQ(MZM5,MZM4) + IF (MZM3 /= MZM4) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 471 + MZM3 = MZM1 * R2 + CALL ZM_ST2M('241.21',MZM4) + CALL ZM_MPY(MZM1,MZM4,MZM5) + CALL ZM_EQ(MZM5,MZM4) + CALL ZM_SUB(MZM3,MZM4,MZM5) + CALL ZM_EQ(MZM5,MZM4) + CALL ZM_DIV(MZM4,MZM3,MZM5) + CALL ZM_EQ(MZM5,MZM4) + CALL ZM_ABS(MZM4,MFM4) + IF (MFM4 > RSMALL) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 472 + MZM3 = MZM1 * D2 + CALL ZM_ST2M('391.61',MZM4) + CALL ZM_MPY(MZM1,MZM4,MZM5) + CALL ZM_EQ(MZM5,MZM4) + CALL ZM_SUB(MZM3,MZM4,MZM5) + CALL ZM_EQ(MZM5,MZM4) + CALL ZM_DIV(MZM4,MZM3,MZM5) + CALL ZM_EQ(MZM5,MZM4) + CALL ZM_ABS(MZM4,MFM4) + IF (MFM4 > DSMALL) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 473 + MZM3 = MZM1 * C2 + CALL ZM_ST2M('411.11 + 421.21 i',MZM4) + CALL ZM_MPY(MZM1,MZM4,MZM5) + CALL ZM_EQ(MZM5,MZM4) + CALL ZM_SUB(MZM3,MZM4,MZM5) + CALL ZM_EQ(MZM5,MZM4) + CALL ZM_DIV(MZM4,MZM3,MZM5) + CALL ZM_EQ(MZM5,MZM4) + CALL ZM_ABS(MZM4,MFM4) + IF (MFM4 > RSMALL) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 474 + MZM3 = MZM1 * CD2 + CALL ZM_ST2M('431.11 + 441.21 i',MZM4) + CALL ZM_MPY(MZM1,MZM4,MZM5) + CALL ZM_EQ(MZM5,MZM4) + CALL ZM_SUB(MZM3,MZM4,MZM5) + CALL ZM_EQ(MZM5,MZM4) + CALL ZM_DIV(MZM4,MZM3,MZM5) + CALL ZM_EQ(MZM5,MZM4) + CALL ZM_ABS(MZM4,MFM4) + IF (MFM4 > DSMALL) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 475 + MZM3 = MZM1 * MFM1 + CALL ZM_ST2M('581.21',MZM4) + CALL ZM_MPY(MZM1,MZM4,MZM5) + CALL ZM_EQ(MZM5,MZM4) + IF (MZM4 /= MZM3) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 476 + MZM3 = MZM1 * MIM1 + CALL ZM_ST2M('661',MZM4) + CALL ZM_MPY(MZM1,MZM4,MZM5) + CALL ZM_EQ(MZM5,MZM4) + IF (MZM4 /= MZM3) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 477 + MZM3 = MZM1 * MZM2 + CALL ZM_MPY(MZM1,MZM2,MZM5) + CALL ZM_EQ(MZM5,MZM4) + IF (MZM4 /= MZM3) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + END SUBROUTINE TEST33 + + SUBROUTINE TEST34(NCASE,NERROR,KLOG) + +! Test the '/' arithmetic operator. + + USE FMVALS + USE FMZM + USE TEST_VARS + IMPLICIT NONE + + INTEGER KLOG,NERROR,NCASE + + WRITE (KW,"(/' Testing the derived type / interface.')") + + RSMALL = EPSILON(1.0)*100.0 + DSMALL = EPSILON(1.0D0)*100.0 + + NCASE = 478 + MFM3 = J2 / MFM1 + CALL FM_ST2M('131',MFM4) + CALL FM_DIV(MFM4,MFM1,MFM6) + CALL FM_EQ(MFM6,MFM4) + IF (MFM3 /= MFM4) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 479 + MIM3 = J2 / MIM1 + CALL IM_ST2M('131',MIM4) + CALL IM_DIV(MIM4,MIM1,MIM5) + CALL IM_EQ(MIM5,MIM4) + IF (MIM3 /= MIM4) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 480 + MZM3 = J2 / MZM1 + CALL ZM_ST2M('131',MZM4) + CALL ZM_DIV(MZM4,MZM1,MZM5) + CALL ZM_EQ(MZM5,MZM4) + IF (MZM3 /= MZM4) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 481 + MFM3 = R2 / MFM1 + CALL FM_ST2M('241.21',MFM4) + CALL FM_DIV(MFM4,MFM1,MFM6) + CALL FM_EQ(MFM6,MFM4) + CALL FM_SUB(MFM3,MFM4,MFM6) + CALL FM_EQ(MFM6,MFM4) + CALL FM_DIV(MFM4,MFM3,MFM6) + CALL FM_EQ(MFM6,MFM4) + CALL FM_ABS(MFM4,MFM6) + CALL FM_EQ(MFM6,MFM4) + IF (MFM4 > RSMALL) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 482 + CALL FM_ST2M('241.21',MFM4) + CALL FM_ST2M('661',MFM3) + CALL FM_DIV(MFM4,MFM3,MFM6) + CALL FM_EQ(MFM6,MFM4) + MFM3 = R2 / MIM1 + CALL FM_SUB(MFM3,MFM4,MFM6) + CALL FM_EQ(MFM6,MFM4) + CALL FM_DIV(MFM4,MFM3,MFM6) + CALL FM_EQ(MFM6,MFM4) + CALL FM_ABS(MFM4,MFM6) + CALL FM_EQ(MFM6,MFM4) + IF (MFM4 > RSMALL) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 483 + MZM3 = R2 / MZM1 + CALL ZM_ST2M('241.21',MZM4) + CALL ZM_DIV(MZM4,MZM1,MZM5) + CALL ZM_EQ(MZM5,MZM4) + CALL ZM_SUB(MZM3,MZM4,MZM5) + CALL ZM_EQ(MZM5,MZM4) + CALL ZM_DIV(MZM4,MZM3,MZM5) + CALL ZM_EQ(MZM5,MZM4) + CALL ZM_ABS(MZM4,MFM4) + IF (MFM4 > RSMALL) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 484 + MFM3 = D2 / MFM1 + CALL FM_ST2M('391.61',MFM4) + CALL FM_DIV(MFM4,MFM1,MFM6) + CALL FM_EQ(MFM6,MFM4) + CALL FM_SUB(MFM3,MFM4,MFM6) + CALL FM_EQ(MFM6,MFM4) + CALL FM_DIV(MFM4,MFM3,MFM6) + CALL FM_EQ(MFM6,MFM4) + CALL FM_ABS(MFM4,MFM6) + CALL FM_EQ(MFM6,MFM4) + IF (MFM4 > DSMALL) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 485 + CALL FM_ST2M('391.61',MFM4) + CALL FM_ST2M('661',MFM3) + CALL FM_DIV(MFM4,MFM3,MFM6) + CALL FM_EQ(MFM6,MFM4) + MFM3 = D2 / MIM1 + CALL FM_SUB(MFM3,MFM4,MFM6) + CALL FM_EQ(MFM6,MFM4) + CALL FM_DIV(MFM4,MFM3,MFM6) + CALL FM_EQ(MFM6,MFM4) + CALL FM_ABS(MFM4,MFM6) + CALL FM_EQ(MFM6,MFM4) + IF (MFM4 > DSMALL) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 486 + MZM3 = D2 / MZM1 + CALL ZM_ST2M('391.61',MZM4) + CALL ZM_DIV(MZM4,MZM1,MZM5) + CALL ZM_EQ(MZM5,MZM4) + CALL ZM_SUB(MZM3,MZM4,MZM5) + CALL ZM_EQ(MZM5,MZM4) + CALL ZM_DIV(MZM4,MZM3,MZM5) + CALL ZM_EQ(MZM5,MZM4) + CALL ZM_ABS(MZM4,MFM4) + IF (MFM4 > DSMALL) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 487 + CALL ZM_ST2M('411.11 + 421.21 i',MZM4) + CALL ZM_ST2M('581.21',MZM3) + CALL ZM_DIV(MZM4,MZM3,MZM5) + CALL ZM_EQ(MZM5,MZM4) + MZM3 = C2 / MFM1 + CALL ZM_SUB(MZM3,MZM4,MZM5) + CALL ZM_EQ(MZM5,MZM4) + CALL ZM_DIV(MZM4,MZM3,MZM5) + CALL ZM_EQ(MZM5,MZM4) + CALL ZM_ABS(MZM4,MFM4) + IF (MFM4 > RSMALL) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 488 + CALL ZM_ST2M('411.11 + 421.21 i',MZM4) + CALL ZM_ST2M('661',MZM3) + CALL ZM_DIV(MZM4,MZM3,MZM5) + CALL ZM_EQ(MZM5,MZM4) + MZM3 = C2 / MIM1 + CALL ZM_SUB(MZM3,MZM4,MZM5) + CALL ZM_EQ(MZM5,MZM4) + CALL ZM_DIV(MZM4,MZM3,MZM5) + CALL ZM_EQ(MZM5,MZM4) + CALL ZM_ABS(MZM4,MFM4) + IF (MFM4 > RSMALL) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 489 + MZM3 = C2 / MZM1 + CALL ZM_ST2M('411.11 + 421.21 i',MZM4) + CALL ZM_DIV(MZM4,MZM1,MZM5) + CALL ZM_EQ(MZM5,MZM4) + CALL ZM_SUB(MZM3,MZM4,MZM5) + CALL ZM_EQ(MZM5,MZM4) + CALL ZM_DIV(MZM4,MZM3,MZM5) + CALL ZM_EQ(MZM5,MZM4) + CALL ZM_ABS(MZM4,MFM4) + IF (MFM4 > RSMALL) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 490 + CALL ZM_ST2M('431.11 + 441.21 i',MZM4) + CALL ZM_ST2M('581.21',MZM3) + CALL ZM_DIV(MZM4,MZM3,MZM5) + CALL ZM_EQ(MZM5,MZM4) + MZM3 = CD2 / MFM1 + CALL ZM_SUB(MZM3,MZM4,MZM5) + CALL ZM_EQ(MZM5,MZM4) + CALL ZM_DIV(MZM4,MZM3,MZM5) + CALL ZM_EQ(MZM5,MZM4) + CALL ZM_ABS(MZM4,MFM4) + IF (MFM4 > DSMALL) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 491 + CALL ZM_ST2M('431.11 + 441.21 i',MZM4) + CALL ZM_ST2M('661',MZM3) + CALL ZM_DIV(MZM4,MZM3,MZM5) + CALL ZM_EQ(MZM5,MZM4) + MZM3 = CD2 / MIM1 + CALL ZM_SUB(MZM3,MZM4,MZM5) + CALL ZM_EQ(MZM5,MZM4) + CALL ZM_DIV(MZM4,MZM3,MZM5) + CALL ZM_EQ(MZM5,MZM4) + CALL ZM_ABS(MZM4,MFM4) + IF (MFM4 > DSMALL) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 492 + MZM3 = CD2 / MZM1 + CALL ZM_ST2M('431.11 + 441.21 i',MZM4) + CALL ZM_DIV(MZM4,MZM1,MZM5) + CALL ZM_EQ(MZM5,MZM4) + CALL ZM_SUB(MZM3,MZM4,MZM5) + CALL ZM_EQ(MZM5,MZM4) + CALL ZM_DIV(MZM4,MZM3,MZM5) + CALL ZM_EQ(MZM5,MZM4) + CALL ZM_ABS(MZM4,MFM4) + IF (MFM4 > DSMALL) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 493 + MFM3 = MFM1 / J2 + CALL FM_ST2M('131',MFM4) + CALL FM_DIV(MFM1,MFM4,MFM6) + CALL FM_EQ(MFM6,MFM4) + IF (MFM3 /= MFM4) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 494 + MFM3 = MFM1 / R2 + CALL FM_ST2M('241.21',MFM4) + CALL FM_DIV(MFM1,MFM4,MFM6) + CALL FM_EQ(MFM6,MFM4) + CALL FM_SUB(MFM3,MFM4,MFM6) + CALL FM_EQ(MFM6,MFM4) + CALL FM_DIV(MFM4,MFM3,MFM6) + CALL FM_EQ(MFM6,MFM4) + CALL FM_ABS(MFM4,MFM6) + CALL FM_EQ(MFM6,MFM4) + IF (MFM4 > RSMALL) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 495 + MFM3 = MFM1 / D2 + CALL FM_ST2M('391.61',MFM4) + CALL FM_DIV(MFM1,MFM4,MFM6) + CALL FM_EQ(MFM6,MFM4) + CALL FM_SUB(MFM3,MFM4,MFM6) + CALL FM_EQ(MFM6,MFM4) + CALL FM_DIV(MFM4,MFM3,MFM6) + CALL FM_EQ(MFM6,MFM4) + CALL FM_ABS(MFM4,MFM6) + CALL FM_EQ(MFM6,MFM4) + IF (MFM4 > DSMALL) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 496 + CALL ZM_ST2M('581.21',MZM3) + CALL ZM_ST2M('411.11 + 421.21 i',MZM4) + CALL ZM_DIV(MZM3,MZM4,MZM5) + CALL ZM_EQ(MZM5,MZM4) + MZM3 = MFM1 / C2 + CALL ZM_SUB(MZM3,MZM4,MZM5) + CALL ZM_EQ(MZM5,MZM4) + CALL ZM_DIV(MZM4,MZM3,MZM5) + CALL ZM_EQ(MZM5,MZM4) + CALL ZM_ABS(MZM4,MFM4) + IF (MFM4 > RSMALL) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 497 + CALL ZM_ST2M('431.11 + 441.21 i',MZM3) + CALL ZM_ST2M('581.21',MZM4) + CALL ZM_DIV(MZM4,MZM3,MZM5) + CALL ZM_EQ(MZM5,MZM4) + MZM3 = MFM1 / CD2 + CALL ZM_SUB(MZM3,MZM4,MZM5) + CALL ZM_EQ(MZM5,MZM4) + CALL ZM_DIV(MZM4,MZM3,MZM5) + CALL ZM_EQ(MZM5,MZM4) + CALL ZM_ABS(MZM4,MFM4) + IF (MFM4 > DSMALL) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 498 + MFM3 = MFM1 / MFM2 + CALL FM_DIV(MFM1,MFM2,MFM4) + IF (MFM4 /= MFM3) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 499 + MFM3 = MFM1 / MIM1 + CALL FM_ST2M('661',MFM4) + CALL FM_DIV(MFM1,MFM4,MFM6) + CALL FM_EQ(MFM6,MFM4) + IF (MFM4 /= MFM3) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 500 + MZM3 = MFM1 / MZM1 + CALL ZM_ST2M('581.21',MZM4) + CALL ZM_DIV(MZM4,MZM1,MZM5) + CALL ZM_EQ(MZM5,MZM4) + IF (MFM4 /= MFM3) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 501 + MIM3 = MIM1 / J2 + CALL IM_ST2M('131',MIM4) + CALL IM_DIV(MIM1,MIM4,MIM5) + CALL IM_EQ(MIM5,MIM4) + IF (MIM3 /= MIM4) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 502 + CALL FM_ST2M('241.21',MFM3) + CALL FM_ST2M('661',MFM4) + CALL FM_DIV(MFM4,MFM3,MFM6) + CALL FM_EQ(MFM6,MFM4) + MFM3 = MIM1 / R2 + CALL FM_SUB(MFM3,MFM4,MFM6) + CALL FM_EQ(MFM6,MFM4) + CALL FM_DIV(MFM4,MFM3,MFM6) + CALL FM_EQ(MFM6,MFM4) + CALL FM_ABS(MFM4,MFM6) + CALL FM_EQ(MFM6,MFM4) + IF (MFM4 > RSMALL) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 503 + CALL FM_ST2M('391.61',MFM3) + CALL FM_ST2M('661',MFM4) + CALL FM_DIV(MFM4,MFM3,MFM6) + CALL FM_EQ(MFM6,MFM4) + MFM3 = MIM1 / D2 + CALL FM_SUB(MFM3,MFM4,MFM6) + CALL FM_EQ(MFM6,MFM4) + CALL FM_DIV(MFM4,MFM3,MFM6) + CALL FM_EQ(MFM6,MFM4) + CALL FM_ABS(MFM4,MFM6) + CALL FM_EQ(MFM6,MFM4) + IF (MFM4 > DSMALL) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 504 + CALL ZM_ST2M('411.11 + 421.21 i',MZM3) + CALL ZM_ST2M('661',MZM4) + CALL ZM_DIV(MZM4,MZM3,MZM5) + CALL ZM_EQ(MZM5,MZM4) + MZM3 = MIM1 / C2 + CALL ZM_SUB(MZM3,MZM4,MZM5) + CALL ZM_EQ(MZM5,MZM4) + CALL ZM_DIV(MZM4,MZM3,MZM5) + CALL ZM_EQ(MZM5,MZM4) + CALL ZM_ABS(MZM4,MFM4) + IF (MFM4 > RSMALL) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 505 + CALL ZM_ST2M('431.11 + 441.21 i',MZM3) + CALL ZM_ST2M('661',MZM4) + CALL ZM_DIV(MZM4,MZM3,MZM5) + CALL ZM_EQ(MZM5,MZM4) + MZM3 = MIM1 / CD2 + CALL ZM_SUB(MZM3,MZM4,MZM5) + CALL ZM_EQ(MZM5,MZM4) + CALL ZM_DIV(MZM4,MZM3,MZM5) + CALL ZM_EQ(MZM5,MZM4) + CALL ZM_ABS(MZM4,MFM4) + IF (MFM4 > DSMALL) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 506 + MFM3 = MIM1 / MFM1 + CALL FM_ST2M('661',MFM4) + CALL FM_DIV(MFM4,MFM1,MFM6) + CALL FM_EQ(MFM6,MFM4) + IF (MFM4 /= MFM3) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 507 + MIM3 = MIM1 / MIM2 + CALL IM_DIV(MIM1,MIM2,MIM4) + IF (MIM4 /= MIM3) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 508 + MZM3 = MIM1 / MZM1 + CALL ZM_ST2M('661',MZM4) + CALL ZM_DIV(MZM4,MZM1,MZM5) + CALL ZM_EQ(MZM5,MZM4) + IF (MZM4 /= MZM3) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 509 + MZM3 = MZM1 / J2 + CALL ZM_ST2M('131',MZM4) + CALL ZM_DIV(MZM1,MZM4,MZM5) + CALL ZM_EQ(MZM5,MZM4) + IF (MZM3 /= MZM4) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 510 + MZM3 = MZM1 / R2 + CALL ZM_ST2M('241.21',MZM4) + CALL ZM_DIV(MZM1,MZM4,MZM5) + CALL ZM_EQ(MZM5,MZM4) + CALL ZM_SUB(MZM3,MZM4,MZM5) + CALL ZM_EQ(MZM5,MZM4) + CALL ZM_DIV(MZM4,MZM3,MZM5) + CALL ZM_EQ(MZM5,MZM4) + CALL ZM_ABS(MZM4,MFM4) + IF (MFM4 > RSMALL) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 511 + MZM3 = MZM1 / D2 + CALL ZM_ST2M('391.61',MZM4) + CALL ZM_DIV(MZM1,MZM4,MZM5) + CALL ZM_EQ(MZM5,MZM4) + CALL ZM_SUB(MZM3,MZM4,MZM5) + CALL ZM_EQ(MZM5,MZM4) + CALL ZM_DIV(MZM4,MZM3,MZM5) + CALL ZM_EQ(MZM5,MZM4) + CALL ZM_ABS(MZM4,MFM4) + IF (MFM4 > DSMALL) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 512 + MZM3 = MZM1 / C2 + CALL ZM_ST2M('411.11 + 421.21 i',MZM4) + CALL ZM_DIV(MZM1,MZM4,MZM5) + CALL ZM_EQ(MZM5,MZM4) + CALL ZM_SUB(MZM3,MZM4,MZM5) + CALL ZM_EQ(MZM5,MZM4) + CALL ZM_DIV(MZM4,MZM3,MZM5) + CALL ZM_EQ(MZM5,MZM4) + CALL ZM_ABS(MZM4,MFM4) + IF (MFM4 > RSMALL) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 513 + MZM3 = MZM1 / CD2 + CALL ZM_ST2M('431.11 + 441.21 i',MZM4) + CALL ZM_DIV(MZM1,MZM4,MZM5) + CALL ZM_EQ(MZM5,MZM4) + CALL ZM_SUB(MZM3,MZM4,MZM5) + CALL ZM_EQ(MZM5,MZM4) + CALL ZM_DIV(MZM4,MZM3,MZM5) + CALL ZM_EQ(MZM5,MZM4) + CALL ZM_ABS(MZM4,MFM4) + IF (MFM4 > DSMALL) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 514 + MZM3 = MZM1 / MFM1 + CALL ZM_ST2M('581.21',MZM4) + CALL ZM_DIV(MZM1,MZM4,MZM5) + CALL ZM_EQ(MZM5,MZM4) + IF (MZM4 /= MZM3) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 515 + MZM3 = MZM1 / MIM1 + CALL ZM_ST2M('661',MZM4) + CALL ZM_DIV(MZM1,MZM4,MZM5) + CALL ZM_EQ(MZM5,MZM4) + IF (MZM4 /= MZM3) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 516 + MZM3 = MZM1 / MZM2 + CALL ZM_DIV(MZM1,MZM2,MZM5) + CALL ZM_EQ(MZM5,MZM4) + IF (MZM4 /= MZM3) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + END SUBROUTINE TEST34 + + SUBROUTINE TEST35(NCASE,NERROR,KLOG) + +! Test the '**' arithmetic operator. + + USE FMVALS + USE FMZM + USE TEST_VARS + IMPLICIT NONE + + INTEGER KLOG,NERROR,NCASE + + WRITE (KW,"(/' Testing the derived type ** interface.')") + +! Use a larger error tolerance for large exponents. + + RSMALL = EPSILON(1.0)*10000.0 + DSMALL = EPSILON(1.0D0)*10000.0 + + NCASE = 517 + MFM3 = J2 ** MFM1 + CALL FM_ST2M('131',MFM4) + CALL FM_PWR(MFM4,MFM1,MFM6) + CALL FM_EQ(MFM6,MFM4) + IF (MFM3 /= MFM4) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 518 + J4 = 2 + MIM3 = J4 ** MIM1 + CALL IM_ST2M('2',MIM4) + CALL IM_PWR(MIM4,MIM1,MIM5) + CALL IM_EQ(MIM5,MIM4) + IF (MIM3 /= MIM4) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 519 + MZM3 = J2 ** MZM1 + CALL ZM_ST2M('131',MZM4) + CALL ZM_PWR(MZM4,MZM1,MZM5) + CALL ZM_EQ(MZM5,MZM4) + IF (MZM3 /= MZM4) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 520 + MFM3 = R2 ** MFM1 + CALL FM_ST2M('241.21',MFM4) + CALL FM_PWR(MFM4,MFM1,MFM6) + CALL FM_EQ(MFM6,MFM4) + CALL FM_SUB(MFM3,MFM4,MFM6) + CALL FM_EQ(MFM6,MFM4) + CALL FM_DIV(MFM4,MFM3,MFM6) + CALL FM_EQ(MFM6,MFM4) + CALL FM_ABS(MFM4,MFM6) + CALL FM_EQ(MFM6,MFM4) + IF (MFM4 > RSMALL) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + + NCASE = 521 + CALL FM_ST2M('241.21',MFM4) + CALL FM_ST2M('661',MFM3) + CALL FM_PWR(MFM4,MFM3,MFM6) + CALL FM_EQ(MFM6,MFM4) + MFM3 = R2 ** MIM1 + CALL FM_SUB(MFM3,MFM4,MFM6) + CALL FM_EQ(MFM6,MFM4) + CALL FM_DIV(MFM4,MFM3,MFM6) + CALL FM_EQ(MFM6,MFM4) + CALL FM_ABS(MFM4,MFM6) + CALL FM_EQ(MFM6,MFM4) + IF (MFM4 > RSMALL) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 522 + MZM3 = R2 ** MZM1 + CALL ZM_ST2M('241.21',MZM4) + CALL ZM_PWR(MZM4,MZM1,MZM5) + CALL ZM_EQ(MZM5,MZM4) + CALL ZM_SUB(MZM3,MZM4,MZM5) + CALL ZM_EQ(MZM5,MZM4) + CALL ZM_DIV(MZM4,MZM3,MZM5) + CALL ZM_EQ(MZM5,MZM4) + CALL ZM_ABS(MZM4,MFM4) + IF (MFM4 > RSMALL) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 523 + MFM3 = D2 ** MFM1 + CALL FM_ST2M('391.61',MFM4) + CALL FM_PWR(MFM4,MFM1,MFM6) + CALL FM_EQ(MFM6,MFM4) + CALL FM_SUB(MFM3,MFM4,MFM6) + CALL FM_EQ(MFM6,MFM4) + CALL FM_DIV(MFM4,MFM3,MFM6) + CALL FM_EQ(MFM6,MFM4) + CALL FM_ABS(MFM4,MFM6) + CALL FM_EQ(MFM6,MFM4) + IF (MFM4 > DSMALL) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 524 + CALL FM_ST2M('391.61',MFM4) + CALL FM_ST2M('661',MFM3) + CALL FM_PWR(MFM4,MFM3,MFM6) + CALL FM_EQ(MFM6,MFM4) + MFM3 = D2 ** MIM1 + CALL FM_SUB(MFM3,MFM4,MFM6) + CALL FM_EQ(MFM6,MFM4) + CALL FM_DIV(MFM4,MFM3,MFM6) + CALL FM_EQ(MFM6,MFM4) + CALL FM_ABS(MFM4,MFM6) + CALL FM_EQ(MFM6,MFM4) + IF (MFM4 > DSMALL) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 525 + MZM3 = D2 ** MZM1 + CALL ZM_ST2M('391.61',MZM4) + CALL ZM_PWR(MZM4,MZM1,MZM5) + CALL ZM_EQ(MZM5,MZM4) + CALL ZM_SUB(MZM3,MZM4,MZM5) + CALL ZM_EQ(MZM5,MZM4) + CALL ZM_DIV(MZM4,MZM3,MZM5) + CALL ZM_EQ(MZM5,MZM4) + CALL ZM_ABS(MZM4,MFM4) + IF (MFM4 > DSMALL) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 526 + CALL ZM_ST2M('411.11 + 421.21 i',MZM4) + CALL ZM_ST2M('581.21',MZM3) + CALL ZM_PWR(MZM4,MZM3,MZM5) + CALL ZM_EQ(MZM5,MZM4) + MZM3 = C2 ** MFM1 + CALL ZM_SUB(MZM3,MZM4,MZM5) + CALL ZM_EQ(MZM5,MZM4) + CALL ZM_DIV(MZM4,MZM3,MZM5) + CALL ZM_EQ(MZM5,MZM4) + CALL ZM_ABS(MZM4,MFM4) + IF (MFM4 > RSMALL) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 527 + CALL ZM_ST2M('411.11 + 421.21 i',MZM4) + CALL ZM_ST2M('661',MZM3) + CALL ZM_PWR(MZM4,MZM3,MZM5) + CALL ZM_EQ(MZM5,MZM4) + MZM3 = C2 ** MIM1 + CALL ZM_SUB(MZM3,MZM4,MZM5) + CALL ZM_EQ(MZM5,MZM4) + CALL ZM_DIV(MZM4,MZM3,MZM5) + CALL ZM_EQ(MZM5,MZM4) + CALL ZM_ABS(MZM4,MFM4) + IF (MFM4 > RSMALL) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 528 + MZM3 = C2 ** MZM1 + CALL ZM_ST2M('411.11 + 421.21 i',MZM4) + CALL ZM_PWR(MZM4,MZM1,MZM5) + CALL ZM_EQ(MZM5,MZM4) + CALL ZM_SUB(MZM3,MZM4,MZM5) + CALL ZM_EQ(MZM5,MZM4) + CALL ZM_DIV(MZM4,MZM3,MZM5) + CALL ZM_EQ(MZM5,MZM4) + CALL ZM_ABS(MZM4,MFM4) + IF (MFM4 > RSMALL) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 529 + CALL ZM_ST2M('431.11 + 441.21 i',MZM4) + CALL ZM_ST2M('581.21',MZM3) + CALL ZM_PWR(MZM4,MZM3,MZM5) + CALL ZM_EQ(MZM5,MZM4) + MZM3 = CD2 ** MFM1 + CALL ZM_SUB(MZM3,MZM4,MZM5) + CALL ZM_EQ(MZM5,MZM4) + CALL ZM_DIV(MZM4,MZM3,MZM5) + CALL ZM_EQ(MZM5,MZM4) + CALL ZM_ABS(MZM4,MFM4) + IF (MFM4 > DSMALL) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 530 + CALL ZM_ST2M('431.11 + 441.21 i',MZM4) + CALL ZM_ST2M('661',MZM3) + CALL ZM_PWR(MZM4,MZM3,MZM5) + CALL ZM_EQ(MZM5,MZM4) + MZM3 = CD2 ** MIM1 + CALL ZM_SUB(MZM3,MZM4,MZM5) + CALL ZM_EQ(MZM5,MZM4) + CALL ZM_DIV(MZM4,MZM3,MZM5) + CALL ZM_EQ(MZM5,MZM4) + CALL ZM_ABS(MZM4,MFM4) + IF (MFM4 > DSMALL) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 531 + MZM3 = CD2 ** MZM1 + CALL ZM_ST2M('431.11 + 441.21 i',MZM4) + CALL ZM_PWR(MZM4,MZM1,MZM5) + CALL ZM_EQ(MZM5,MZM4) + CALL ZM_SUB(MZM3,MZM4,MZM5) + CALL ZM_EQ(MZM5,MZM4) + CALL ZM_DIV(MZM4,MZM3,MZM5) + CALL ZM_EQ(MZM5,MZM4) + CALL ZM_ABS(MZM4,MFM4) + IF (MFM4 > DSMALL) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 532 + MFM3 = MFM1 ** J2 + CALL FM_ST2M('131',MFM4) + CALL FM_PWR(MFM1,MFM4,MFM6) + CALL FM_EQ(MFM6,MFM4) + IF (MFM3 /= MFM4) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 533 + MFM3 = MFM1 ** R2 + CALL FM_ST2M('241.21',MFM4) + CALL FM_PWR(MFM1,MFM4,MFM6) + CALL FM_EQ(MFM6,MFM4) + CALL FM_SUB(MFM3,MFM4,MFM6) + CALL FM_EQ(MFM6,MFM4) + CALL FM_DIV(MFM4,MFM3,MFM6) + CALL FM_EQ(MFM6,MFM4) + CALL FM_ABS(MFM4,MFM6) + CALL FM_EQ(MFM6,MFM4) + IF (MFM4 > RSMALL) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 534 + MFM3 = MFM1 ** D2 + CALL FM_ST2M('391.61',MFM4) + CALL FM_PWR(MFM1,MFM4,MFM6) + CALL FM_EQ(MFM6,MFM4) + CALL FM_SUB(MFM3,MFM4,MFM6) + CALL FM_EQ(MFM6,MFM4) + CALL FM_DIV(MFM4,MFM3,MFM6) + CALL FM_EQ(MFM6,MFM4) + CALL FM_ABS(MFM4,MFM6) + CALL FM_EQ(MFM6,MFM4) + IF (MFM4 > DSMALL) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 535 + CALL ZM_ST2M('581.21',MZM3) + CALL ZM_ST2M('411.11 + 421.21 i',MZM4) + CALL ZM_PWR(MZM3,MZM4,MZM5) + CALL ZM_EQ(MZM5,MZM4) + MZM3 = MFM1 ** C2 + CALL ZM_SUB(MZM3,MZM4,MZM5) + CALL ZM_EQ(MZM5,MZM4) + CALL ZM_DIV(MZM4,MZM3,MZM5) + CALL ZM_EQ(MZM5,MZM4) + CALL ZM_ABS(MZM4,MFM4) + IF (MFM4 > RSMALL) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 536 + CALL ZM_ST2M('431.11 + 441.21 i',MZM3) + CALL ZM_ST2M('581.21',MZM4) + CALL ZM_PWR(MZM4,MZM3,MZM5) + CALL ZM_EQ(MZM5,MZM4) + MZM3 = MFM1 ** CD2 + CALL ZM_SUB(MZM3,MZM4,MZM5) + CALL ZM_EQ(MZM5,MZM4) + CALL ZM_DIV(MZM4,MZM3,MZM5) + CALL ZM_EQ(MZM5,MZM4) + CALL ZM_ABS(MZM4,MFM4) + IF (MFM4 > DSMALL) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 537 + MFM3 = MFM1 ** MFM2 + CALL FM_PWR(MFM1,MFM2,MFM4) + IF (MFM4 /= MFM3) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 538 + MFM3 = MFM1 ** MIM1 + CALL FM_ST2M('661',MFM4) + CALL FM_PWR(MFM1,MFM4,MFM6) + CALL FM_EQ(MFM6,MFM4) + IF (MFM4 /= MFM3) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 539 + MZM3 = MFM1 ** MZM1 + CALL ZM_ST2M('581.21',MZM4) + CALL ZM_PWR(MZM4,MZM1,MZM5) + CALL ZM_EQ(MZM5,MZM4) + IF (MFM4 /= MFM3) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 540 + J4 = 17 + MIM3 = MIM1 ** J4 + CALL IM_ST2M('17',MIM4) + CALL IM_PWR(MIM1,MIM4,MIM5) + CALL IM_EQ(MIM5,MIM4) + IF (MIM3 /= MIM4) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 541 + CALL FM_ST2M('241.21',MFM3) + CALL FM_ST2M('661',MFM4) + CALL FM_PWR(MFM4,MFM3,MFM6) + CALL FM_EQ(MFM6,MFM4) + MFM3 = MIM1 ** R2 + CALL FM_SUB(MFM3,MFM4,MFM6) + CALL FM_EQ(MFM6,MFM4) + CALL FM_DIV(MFM4,MFM3,MFM6) + CALL FM_EQ(MFM6,MFM4) + CALL FM_ABS(MFM4,MFM6) + CALL FM_EQ(MFM6,MFM4) + IF (MFM4 > RSMALL) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 542 + CALL FM_ST2M('391.61',MFM3) + CALL FM_ST2M('661',MFM4) + CALL FM_PWR(MFM4,MFM3,MFM6) + CALL FM_EQ(MFM6,MFM4) + MFM3 = MIM1 ** D2 + CALL FM_SUB(MFM3,MFM4,MFM6) + CALL FM_EQ(MFM6,MFM4) + CALL FM_DIV(MFM4,MFM3,MFM6) + CALL FM_EQ(MFM6,MFM4) + CALL FM_ABS(MFM4,MFM6) + CALL FM_EQ(MFM6,MFM4) + IF (MFM4 > DSMALL) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 543 + CALL ZM_ST2M('411.11 + 421.21 i',MZM3) + CALL ZM_ST2M('661',MZM4) + CALL ZM_PWR(MZM4,MZM3,MZM5) + CALL ZM_EQ(MZM5,MZM4) + MZM3 = MIM1 ** C2 + CALL ZM_SUB(MZM3,MZM4,MZM5) + CALL ZM_EQ(MZM5,MZM4) + CALL ZM_DIV(MZM4,MZM3,MZM5) + CALL ZM_EQ(MZM5,MZM4) + CALL ZM_ABS(MZM4,MFM4) + IF (MFM4 > RSMALL) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 544 + CALL ZM_ST2M('431.11 + 441.21 i',MZM3) + CALL ZM_ST2M('661',MZM4) + CALL ZM_PWR(MZM4,MZM3,MZM5) + CALL ZM_EQ(MZM5,MZM4) + MZM3 = MIM1 ** CD2 + CALL ZM_SUB(MZM3,MZM4,MZM5) + CALL ZM_EQ(MZM5,MZM4) + CALL ZM_DIV(MZM4,MZM3,MZM5) + CALL ZM_EQ(MZM5,MZM4) + CALL ZM_ABS(MZM4,MFM4) + IF (MFM4 > DSMALL) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 545 + MFM3 = MIM1 ** MFM1 + CALL FM_ST2M('661',MFM4) + CALL FM_PWR(MFM4,MFM1,MFM6) + CALL FM_EQ(MFM6,MFM4) + IF (MFM4 /= MFM3) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 546 + MIM4 = 19 + MIM3 = MIM1 ** MIM4 + CALL IM_PWR(MIM1,MIM4,MIM5) + CALL IM_EQ(MIM5,MIM4) + IF (MIM4 /= MIM3) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 547 + MZM3 = MIM1 ** MZM1 + CALL ZM_ST2M('661',MZM4) + CALL ZM_PWR(MZM4,MZM1,MZM5) + CALL ZM_EQ(MZM5,MZM4) + IF (MZM4 /= MZM3) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 548 + MZM3 = MZM1 ** J2 + CALL ZM_ST2M('131',MZM4) + CALL ZM_PWR(MZM1,MZM4,MZM5) + CALL ZM_EQ(MZM5,MZM4) + IF (MZM3 /= MZM4) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 549 + MZM3 = MZM1 ** R2 + CALL ZM_ST2M('241.21',MZM4) + CALL ZM_PWR(MZM1,MZM4,MZM5) + CALL ZM_EQ(MZM5,MZM4) + CALL ZM_SUB(MZM3,MZM4,MZM5) + CALL ZM_EQ(MZM5,MZM4) + CALL ZM_DIV(MZM4,MZM3,MZM5) + CALL ZM_EQ(MZM5,MZM4) + CALL ZM_ABS(MZM4,MFM4) + IF (MFM4 > RSMALL) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 550 + MZM3 = MZM1 ** D2 + CALL ZM_ST2M('391.61',MZM4) + CALL ZM_PWR(MZM1,MZM4,MZM5) + CALL ZM_EQ(MZM5,MZM4) + CALL ZM_SUB(MZM3,MZM4,MZM5) + CALL ZM_EQ(MZM5,MZM4) + CALL ZM_DIV(MZM4,MZM3,MZM5) + CALL ZM_EQ(MZM5,MZM4) + CALL ZM_ABS(MZM4,MFM4) + IF (MFM4 > DSMALL) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 551 + MZM3 = MZM1 ** C2 + CALL ZM_ST2M('411.11 + 421.21 i',MZM4) + CALL ZM_PWR(MZM1,MZM4,MZM5) + CALL ZM_EQ(MZM5,MZM4) + CALL ZM_SUB(MZM3,MZM4,MZM5) + CALL ZM_EQ(MZM5,MZM4) + CALL ZM_DIV(MZM4,MZM3,MZM5) + CALL ZM_EQ(MZM5,MZM4) + CALL ZM_ABS(MZM4,MFM4) + IF (MFM4 > RSMALL) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 552 + MZM3 = MZM1 ** CD2 + CALL ZM_ST2M('431.11 + 441.21 i',MZM4) + CALL ZM_PWR(MZM1,MZM4,MZM5) + CALL ZM_EQ(MZM5,MZM4) + CALL ZM_SUB(MZM3,MZM4,MZM5) + CALL ZM_EQ(MZM5,MZM4) + CALL ZM_DIV(MZM4,MZM3,MZM5) + CALL ZM_EQ(MZM5,MZM4) + CALL ZM_ABS(MZM4,MFM4) + IF (MFM4 > DSMALL) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 553 + MZM3 = MZM1 ** MFM1 + CALL ZM_ST2M('581.21',MZM4) + CALL ZM_PWR(MZM1,MZM4,MZM5) + CALL ZM_EQ(MZM5,MZM4) + IF (MZM4 /= MZM3) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 554 + MZM3 = MZM1 ** MIM1 + CALL ZM_ST2M('661',MZM4) + CALL ZM_PWR(MZM1,MZM4,MZM5) + CALL ZM_EQ(MZM5,MZM4) + IF (MZM4 /= MZM3) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 555 + MZM3 = MZM1 ** MZM2 + CALL ZM_PWR(MZM1,MZM2,MZM5) + CALL ZM_EQ(MZM5,MZM4) + IF (MZM4 /= MZM3) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + END SUBROUTINE TEST35 + + SUBROUTINE TEST36(NCASE,NERROR,KLOG) + +! Test functions ABS, ..., CEILING. + + USE FMVALS + USE FMZM + USE TEST_VARS + IMPLICIT NONE + + INTEGER J,JERR,KLOG,NERROR,NCASE + + WRITE (KW,"(/' Testing the derived type ABS, ..., CEILING interfaces.')") + + NCASE = 556 + MFM3 = ABS(MFM1) + CALL FM_ABS(MFM1,MFM4) + IF (MFM3 /= MFM4) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 557 + MIM3 = ABS(MIM1) + CALL IM_ABS(MIM1,MIM4) + IF (MIM3 /= MIM4) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 558 + MFM3 = ABS(MZM1) + CALL ZM_ABS(MZM1,MFM4) + IF (MFM3 /= MFM4) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 559 + CALL FM_ST2M('0.7654',MFM4) + MFM3 = ACOS(MFM4) + CALL FM_ACOS(MFM4,MFM6) + CALL FM_EQ(MFM6,MFM4) + IF (MFM3 /= MFM4) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 560 + CALL ZM_ST2M('0.7654 - 0.3456 i',MZM4) + MZM3 = ACOS(MZM4) + CALL ZM_ACOS(MZM4,MZM5) + CALL ZM_EQ(MZM5,MZM4) + IF (MZM3 /= MZM4) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 561 + CALL ZM_ST2M('0.7654 - 0.3456 i',MZM4) + MFM3 = AIMAG(MZM4) + CALL ZM_IMAG(MZM4,MFM4) + IF (MFM3 /= MFM4) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 562 + MFM3 = AINT(MFM1) + CALL FM_INT(MFM1,MFM4) + IF (MFM3 /= MFM4) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 563 + MZM3 = AINT(MZM1) + CALL ZM_INT(MZM1,MZM4) + IF (MZM3 /= MZM4) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 564 + MFM3 = ANINT(MFM1) + CALL FM_NINT(MFM1,MFM4) + IF (MFM3 /= MFM4) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 565 + MZM3 = ANINT(MZM1) + CALL ZM_NINT(MZM1,MZM4) + IF (MZM3 /= MZM4) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 566 + CALL FM_ST2M('0.7654',MFM4) + MFM3 = ASIN(MFM4) + CALL FM_ASIN(MFM4,MFM6) + CALL FM_EQ(MFM6,MFM4) + IF (MFM3 /= MFM4) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 567 + CALL ZM_ST2M('0.7654 - 0.3456 i',MZM4) + MZM3 = ASIN(MZM4) + CALL ZM_ASIN(MZM4,MZM5) + CALL ZM_EQ(MZM5,MZM4) + IF (MZM3 /= MZM4) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 568 + CALL FM_ST2M('0.7654',MFM4) + MFM3 = ATAN(MFM4) + CALL FM_ATAN(MFM4,MFM6) + CALL FM_EQ(MFM6,MFM4) + IF (MFM3 /= MFM4) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 569 + CALL ZM_ST2M('0.7654 - 0.3456 i',MZM4) + MZM3 = ATAN(MZM4) + CALL ZM_ATAN(MZM4,MZM5) + CALL ZM_EQ(MZM5,MZM4) + IF (MZM3 /= MZM4) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 570 + MFM3 = ATAN2(MFM1,MFM2) + CALL FM_ATN2(MFM1,MFM2,MFM4) + IF (MFM3 /= MFM4) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 571 + JERR = -1 + DO J = 0, 10 + IF (BTEST(661,J)) THEN + IF (.NOT.BTEST(MIM1,J)) JERR = J + ELSE + IF (BTEST(MIM1,J)) JERR = J + ENDIF + ENDDO + IF (JERR >= 0) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 572 + CALL FM_ST2M('12.37654',MFM4) + MFM3 = CEILING(MFM4) + CALL FM_ST2M('13',MFM4) + IF (MFM3 /= MFM4) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 573 + CALL FM_ST2M('-12.7654',MFM4) + MFM3 = CEILING(MFM4) + CALL FM_ST2M('-12',MFM4) + IF (MFM3 /= MFM4) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 574 + CALL ZM_ST2M('12.37654 - 22.54 i',MZM4) + MZM3 = CEILING(MZM4) + CALL ZM_ST2M('13 - 22 i',MZM4) + IF (MZM3 /= MZM4) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 575 + CALL ZM_ST2M('-12.7654 + 22.31 i',MZM4) + MZM3 = CEILING(MZM4) + CALL ZM_ST2M('-12 + 23 i',MZM4) + IF (MZM3 /= MZM4) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + END SUBROUTINE TEST36 + + SUBROUTINE TEST37(NCASE,NERROR,KLOG) + +! Test functions CMPLX, ..., EXPONENT. + + USE FMVALS + USE FMZM + USE TEST_VARS + IMPLICIT NONE + + INTEGER J,KLOG,NERROR,NCASE + + WRITE (KW,"(/"// & + "' Testing the derived type CMPLX, ..., EXPONENT interfaces.')") + + NCASE = 576 + MZM3 = CMPLX(MFM1,MFM2) + CALL ZM_CMPX(MFM1,MFM2,MZM5) + CALL ZM_EQ(MZM5,MZM4) + IF (MZM3 /= MZM4) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 577 + MZM3 = CMPLX(MIM1,MIM2) + CALL IM_I2FM(MIM1,MFM3) + CALL IM_I2FM(MIM2,MFM4) + CALL ZM_CMPX(MFM3,MFM4,MZM5) + CALL ZM_EQ(MZM5,MZM4) + IF (MZM3 /= MZM4) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 578 + MZM3 = CMPLX(MFM1) + CALL FM_I2M(0,MFM4) + CALL ZM_CMPX(MFM1,MFM4,MZM5) + CALL ZM_EQ(MZM5,MZM4) + IF (MZM3 /= MZM4) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 579 + MZM3 = CMPLX(MIM1) + CALL IM_I2FM(MIM1,MFM3) + CALL FM_I2M(0,MFM4) + CALL ZM_CMPX(MFM3,MFM4,MZM5) + CALL ZM_EQ(MZM5,MZM4) + IF (MZM3 /= MZM4) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 580 + MZM3 = CONJG(MZM1) + CALL ZM_CONJ(MZM1,MZM4) + IF (MZM3 /= MZM4) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 581 + CALL FM_ST2M('0.7654',MFM4) + MFM3 = COS(MFM4) + CALL FM_COS(MFM4,MFM6) + CALL FM_EQ(MFM6,MFM4) + IF (MFM3 /= MFM4) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 582 + CALL ZM_ST2M('0.7654 - 0.3456 i',MZM4) + MZM3 = COS(MZM4) + CALL ZM_COS(MZM4,MZM5) + CALL ZM_EQ(MZM5,MZM4) + IF (MZM3 /= MZM4) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 583 + CALL FM_ST2M('0.7654',MFM4) + MFM3 = COSH(MFM4) + CALL FM_COSH(MFM4,MFM6) + CALL FM_EQ(MFM6,MFM4) + IF (MFM3 /= MFM4) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 584 + CALL ZM_ST2M('0.7654 - 0.3456 i',MZM4) + MZM3 = COSH(MZM4) + CALL ZM_COSH(MZM4,MZM5) + CALL ZM_EQ(MZM5,MZM4) + IF (MZM3 /= MZM4) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 585 + MFM3 = DBLE(MFM1) + CALL FM_EQ(MFM1,MFM4) + IF (MFM3 /= MFM4) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 586 + MFM3 = DBLE(MIM1) + CALL IM_I2FM(MIM1,MFM4) + IF (MFM3 /= MFM4) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 587 + MFM3 = DBLE(MZM1) + CALL ZM_REAL(MZM1,MFM4) + IF (MFM3 /= MFM4) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 588 + J = DIGITS(MFM1) + IF (J /= NDIG) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 589 + J = DIGITS(MIM1) + IF (J /= NDIGMX) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 590 + J = DIGITS(MZM1) + IF (J /= NDIG) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 591 + MFM3 = DIM(MFM1,MFM2) + CALL FM_DIM(MFM1,MFM2,MFM4) + IF (MFM3 /= MFM4) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 592 + MIM3 = DIM(MIM1,MIM2) + CALL IM_DIM(MIM1,MIM2,MIM4) + IF (MIM3 /= MIM4) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 593 + MFM3 = DINT (MFM1) + CALL FM_INT(MFM1,MFM4) + IF (MFM3 /= MFM4) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 594 + MZM3 = DINT (MZM1) + CALL ZM_INT(MZM1,MZM4) + IF (MZM3 /= MZM4) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 595 + CALL FM_ST2M('1.23',MFMV1(1)) + CALL FM_ST2M('2.23',MFMV1(2)) + CALL FM_ST2M('3.23',MFMV1(3)) + CALL FM_ST2M('4.23',MFMV2(1)) + CALL FM_ST2M('5.23',MFMV2(2)) + CALL FM_ST2M('6.23',MFMV2(3)) + MFM3 = DOTPRODUCT(MFMV1,MFMV2) + MFM4 = 0 + DO J = 1, 3 + MFM4 = MFM4 + MFMV1(J)*MFMV2(J) + ENDDO + IF (MFM3 /= MFM4) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 596 + CALL IM_ST2M('12',MIMV1(1)) + CALL IM_ST2M('23',MIMV1(2)) + CALL IM_ST2M('34',MIMV1(3)) + CALL IM_ST2M('-14',MIMV2(1)) + CALL IM_ST2M('-5',MIMV2(2)) + CALL IM_ST2M('16',MIMV2(3)) + MIM3 = DOTPRODUCT(MIMV1,MIMV2) + MIM4 = 0 + DO J = 1, 3 + MIM4 = MIM4 + MIMV1(J)*MIMV2(J) + ENDDO + IF (MIM3 /= MIM4) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 597 + CALL ZM_ST2M('1.23 + 1.67 i',MZMV1(1)) + CALL ZM_ST2M('2.23 - 2.56 i',MZMV1(2)) + CALL ZM_ST2M('3.23 + 3.45 i',MZMV1(3)) + CALL ZM_ST2M('4.23 - 4.34 i',MZMV2(1)) + CALL ZM_ST2M('5.23 + 5.23 i',MZMV2(2)) + CALL ZM_ST2M('6.23 - 6.12 i',MZMV2(3)) + MZM3 = DOTPRODUCT(MZMV1,MZMV2) + MZM4 = 0 + DO J = 1, 3 + MZM4 = MZM4 + MZMV1(J)*MZMV2(J) + ENDDO + IF (MZM3 /= MZM4) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 598 + MFM3 = EPSILON(MFM1) + CALL FM_I2M(1,MFM4) + CALL FM_ULP(MFM4,MFM6) + CALL FM_EQ(MFM6,MFM4) + IF (MFM3 /= MFM4) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 599 + CALL FM_ST2M('0.7654',MFM4) + MFM3 = EXP(MFM4) + CALL FM_EXP(MFM4,MFM6) + CALL FM_EQ(MFM6,MFM4) + IF (MFM3 /= MFM4) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 600 + CALL ZM_ST2M('0.7654 - 0.3456 i',MZM4) + MZM3 = EXP(MZM4) + CALL ZM_EXP(MZM4,MZM5) + CALL ZM_EQ(MZM5,MZM4) + IF (MZM3 /= MZM4) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 601 + J = EXPONENT(MFM1) + IF (J /= INT(MFM1%MFM(1))) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + END SUBROUTINE TEST37 + + SUBROUTINE TEST38(NCASE,NERROR,KLOG) + +! Test functions FLOOR, ..., MIN. + + USE FMVALS + USE FMZM + USE TEST_VARS + IMPLICIT NONE + + INTEGER I,J,KLOG,NERROR,NCASE + + WRITE (KW,"(/"// & + "' Testing the derived type FLOOR, ..., MIN interfaces.')") + + NCASE = 602 + CALL FM_ST2M('12.37654',MFM4) + MFM3 = FLOOR(MFM4) + CALL FM_ST2M('12',MFM4) + IF (MFM3 /= MFM4) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 603 + CALL FM_ST2M('-12.7654',MFM4) + MFM3 = FLOOR(MFM4) + CALL FM_ST2M('-13',MFM4) + IF (MFM3 /= MFM4) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 604 + CALL IM_ST2M('12',MIM4) + MIM3 = FLOOR(MIM4) + CALL IM_ST2M('12',MIM4) + IF (MIM3 /= MIM4) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 605 + CALL IM_ST2M('-123',MIM4) + MIM3 = FLOOR(MIM4) + CALL IM_ST2M('-123',MIM4) + IF (MIM3 /= MIM4) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 606 + CALL ZM_ST2M('12.37654 - 22.54 i',MZM4) + MZM3 = FLOOR(MZM4) + CALL ZM_ST2M('12 - 23 i',MZM4) + IF (MZM3 /= MZM4) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 607 + CALL ZM_ST2M('-12.7654 + 22.31 i',MZM4) + MZM3 = FLOOR(MZM4) + CALL ZM_ST2M('-13 + 22 i',MZM4) + IF (MZM3 /= MZM4) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 608 + CALL FM_ST2M('12.37654',MFM4) + MFM3 = FRACTION(MFM4) + MFM4%MFM(1) = 0 + IF (MFM3 /= MFM4) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 609 + CALL ZM_ST2M('12.37654 - 22.54',MZM4) + MZM3 = FRACTION(MZM4) + MZM4%MZM(1) = 0 + MZM4%MZM(KPTIMU+01) = 0 + IF (MZM3 /= MZM4) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 610 + MFM3 = HUGE(MFM1) + CALL FM_BIG(MFM4) + IF (MFM3 /= MFM4) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 611 + MIM3 = HUGE(MIM1) + CALL IM_BIG(MIM4) + IF (MIM3 /= MIM4) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 612 + MZM3 = HUGE(MZM1) + CALL FM_BIG(MFM4) + CALL ZM_CMPX(MFM4,MFM4,MZM5) + CALL ZM_EQ(MZM5,MZM4) + IF (MZM3 /= MZM4) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 613 + MIM3 = INT(MFM1) + CALL FM_INT(MFM1,MFM4) + CALL IM_FM2I(MFM4,MIM4) + IF (MIM3 /= MIM4) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 614 + MIM3 = INT(MIM1) + CALL IM_EQ(MIM1,MIM4) + IF (MIM3 /= MIM4) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 615 + MIM3 = INT(MZM1) + CALL ZM_INT(MZM1,MZM4) + CALL ZM_REAL(MZM4,MFM4) + CALL IM_FM2I(MFM4,MIM4) + IF (MIM3 /= MIM4) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 616 + CALL FM_ST2M('0.7654',MFM4) + MFM3 = LOG(MFM4) + CALL FM_LN(MFM4,MFM6) + CALL FM_EQ(MFM6,MFM4) + IF (MFM3 /= MFM4) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 617 + CALL ZM_ST2M('0.7654 - 0.3456 i',MZM4) + MZM3 = LOG(MZM4) + CALL ZM_LN(MZM4,MZM5) + CALL ZM_EQ(MZM5,MZM4) + IF (MZM3 /= MZM4) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 618 + CALL FM_ST2M('0.7654',MFM4) + MFM3 = LOG10(MFM4) + CALL FM_LG10(MFM4,MFM6) + CALL FM_EQ(MFM6,MFM4) + IF (MFM3 /= MFM4) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 619 + CALL ZM_ST2M('0.7654 - 0.3456 i',MZM4) + MZM3 = LOG10(MZM4) + CALL ZM_LG10(MZM4,MZM5) + CALL ZM_EQ(MZM5,MZM4) + IF (MZM3 /= MZM4) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 620 + DO I = 1, 3 + DO J = 1, 3 + MFMA(I,J) = 3*(J-1) + I + MFMB(I,J) = 3*(I-1) + J + 10 + ENDDO + ENDDO + MFMC = MATMUL(MFMA,MFMB) + MFM3 = ABS(MFMC(1,1)-186)+ABS(MFMC(1,2)-198)+ABS(MFMC(1,3)-210)+ & + ABS(MFMC(2,1)-228)+ABS(MFMC(2,2)-243)+ABS(MFMC(2,3)-258)+ & + ABS(MFMC(3,1)-270)+ABS(MFMC(3,2)-288)+ABS(MFMC(3,3)-306) + IF (MFM3 /= 0) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 621 + DO I = 1, 2 + DO J = 1, 2 + MIMA(I,J) = 2*(J-1) + I + 20 + MIMB(I,J) = 2*(I-1) + J + 30 + ENDDO + ENDDO + MIMC = MATMUL(MIMA,MIMB) + MIM3 = ABS(MIMC(1,1)-1410) + ABS(MIMC(1,2)-1454) + & + ABS(MIMC(2,1)-1474) + ABS(MIMC(2,2)-1520) + IF (MIM3 /= 0) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 622 + DO I = 1, 2 + DO J = 1, 3 + MZMA(I,J) = CMPLX(TO_FM(2*(J-1)+I+10),TO_FM(2*(J-1)+I+20)) + ENDDO + ENDDO + DO I = 1, 3 + DO J = 1, 4 + MZMB(I,J) = CMPLX(TO_FM(4*(I-1)+J+50),TO_FM(4*(I-1)+J+30)) + ENDDO + ENDDO + MZMC = MATMUL(MZMA,MZMB) + MFM3 = ABS(MZMC(1,1)-TO_ZM('-270 + 5192 i')) + & + ABS(MZMC(1,2)-TO_ZM('-300 + 5300 i')) + & + ABS(MZMC(1,3)-TO_ZM('-330 + 5408 i')) + & + ABS(MZMC(1,4)-TO_ZM('-360 + 5516 i')) + & + ABS(MZMC(2,1)-TO_ZM('-210 + 5462 i')) + & + ABS(MZMC(2,2)-TO_ZM('-240 + 5576 i')) + & + ABS(MZMC(2,3)-TO_ZM('-270 + 5690 i')) + & + ABS(MZMC(2,4)-TO_ZM('-300 + 5804 i')) + IF (MFM3 /= 0) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 623 + MFM3 = MAX(MFM1,MFM2) + CALL FM_MAX(MFM1,MFM2,MFM4) + IF (MFM3 /= MFM4) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 624 + CALL FM_ST2M('0.7654',MFM4) + MFM3 = MAX(MFM2,MFM1,MFM4) + CALL FM_MAX(MFM1,MFM4,MFM6) + CALL FM_EQ(MFM6,MFM4) + CALL FM_MAX(MFM2,MFM4,MFM6) + CALL FM_EQ(MFM6,MFM4) + IF (MFM3 /= MFM4) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 625 + MIM3 = MAX(MIM1,MIM2) + CALL IM_MAX(MIM1,MIM2,MIM4) + IF (MIM3 /= MIM4) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 626 + CALL IM_ST2M('7654',MIM4) + CALL IM_ST2M('-1654',MIM3) + MIM3 = MAX(MIM2,MIM1,MIM3,MIM4) + CALL IM_ST2M('7654',MIM4) + IF (MIM3 /= MIM4) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 627 + J = MAXEXPONENT(MFM1) + IF (J /= INT(MXEXP)+1) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 628 + MFM3 = MIN(MFM1,MFM2) + CALL FM_MIN(MFM1,MFM2,MFM4) + IF (MFM3 /= MFM4) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 629 + CALL FM_ST2M('0.7654',MFM4) + MFM3 = MIN(MFM2,MFM1,MFM4) + CALL FM_MIN(MFM1,MFM4,MFM6) + CALL FM_EQ(MFM6,MFM4) + CALL FM_MIN(MFM2,MFM4,MFM6) + CALL FM_EQ(MFM6,MFM4) + IF (MFM3 /= MFM4) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 630 + MIM3 = MIN(MIM1,MIM2) + CALL IM_MIN(MIM1,MIM2,MIM4) + IF (MIM3 /= MIM4) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 631 + CALL IM_ST2M('7654',MIM4) + CALL IM_ST2M('-1654',MIM3) + MIM3 = MIN(MIM2,MIM1,MIM3,MIM4) + CALL IM_ST2M('-1654',MIM4) + IF (MIM3 /= MIM4) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + END SUBROUTINE TEST38 + + SUBROUTINE TEST39(NCASE,NERROR,KLOG) + +! Test functions MINEXPONENT, ..., RRSPACING. + + USE FMVALS + USE FMZM + USE TEST_VARS + IMPLICIT NONE + + INTEGER J,KLOG,NERROR,NCASE + + WRITE (KW,"(/"// & + "' Testing the derived type MINEXPONENT, ..., RRSPACING interfaces.')") + + NCASE = 632 + J = MINEXPONENT(MFM1) + IF (J /= -INT(MXEXP)) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 633 + CALL FM_ST2M('8',MFM3) + CALL FM_ST2M('5',MFM4) + MFM3 = MOD(MFM3,MFM4) + CALL FM_ST2M('3',MFM4) + IF (MFM3 /= MFM4) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 634 + CALL FM_ST2M('-8',MFM3) + CALL FM_ST2M('5',MFM4) + MFM3 = MOD(MFM3,MFM4) + CALL FM_ST2M('-3',MFM4) + IF (MFM3 /= MFM4) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 635 + CALL FM_ST2M('8',MFM3) + CALL FM_ST2M('-5',MFM4) + MFM3 = MOD(MFM3,MFM4) + CALL FM_ST2M('3',MFM4) + IF (MFM3 /= MFM4) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 636 + CALL FM_ST2M('-8',MFM3) + CALL FM_ST2M('-5',MFM4) + MFM3 = MOD(MFM3,MFM4) + CALL FM_ST2M('-3',MFM4) + IF (MFM3 /= MFM4) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 637 + CALL IM_ST2M('8',MIM3) + CALL IM_ST2M('5',MIM4) + MIM3 = MOD(MIM3,MIM4) + CALL IM_ST2M('3',MIM4) + IF (MIM3 /= MIM4) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 638 + CALL IM_ST2M('-8',MIM3) + CALL IM_ST2M('5',MIM4) + MIM3 = MOD(MIM3,MIM4) + CALL IM_ST2M('-3',MIM4) + IF (MIM3 /= MIM4) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 639 + CALL IM_ST2M('8',MIM3) + CALL IM_ST2M('-5',MIM4) + MIM3 = MOD(MIM3,MIM4) + CALL IM_ST2M('3',MIM4) + IF (MIM3 /= MIM4) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 640 + CALL IM_ST2M('-8',MIM3) + CALL IM_ST2M('-5',MIM4) + MIM3 = MOD(MIM3,MIM4) + CALL IM_ST2M('-3',MIM4) + IF (MIM3 /= MIM4) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 641 + CALL FM_ST2M('8',MFM3) + CALL FM_ST2M('5',MFM4) + MFM3 = MODULO(MFM3,MFM4) + CALL FM_ST2M('3',MFM4) + IF (MFM3 /= MFM4) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 642 + CALL FM_ST2M('-8',MFM3) + CALL FM_ST2M('5',MFM4) + MFM3 = MODULO(MFM3,MFM4) + CALL FM_ST2M('2',MFM4) + IF (MFM3 /= MFM4) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 643 + CALL FM_ST2M('8',MFM3) + CALL FM_ST2M('-5',MFM4) + MFM3 = MODULO(MFM3,MFM4) + CALL FM_ST2M('-2',MFM4) + IF (MFM3 /= MFM4) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 644 + CALL FM_ST2M('-8',MFM3) + CALL FM_ST2M('-5',MFM4) + MFM3 = MODULO(MFM3,MFM4) + CALL FM_ST2M('-3',MFM4) + IF (MFM3 /= MFM4) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 645 + CALL IM_ST2M('8',MIM3) + CALL IM_ST2M('5',MIM4) + MIM3 = MODULO(MIM3,MIM4) + CALL IM_ST2M('3',MIM4) + IF (MIM3 /= MIM4) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 646 + CALL IM_ST2M('-8',MIM3) + CALL IM_ST2M('5',MIM4) + MIM3 = MODULO(MIM3,MIM4) + CALL IM_ST2M('2',MIM4) + IF (MIM3 /= MIM4) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 647 + CALL IM_ST2M('8',MIM3) + CALL IM_ST2M('-5',MIM4) + MIM3 = MODULO(MIM3,MIM4) + CALL IM_ST2M('-2',MIM4) + IF (MIM3 /= MIM4) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 648 + CALL IM_ST2M('-8',MIM3) + CALL IM_ST2M('-5',MIM4) + MIM3 = MODULO(MIM3,MIM4) + CALL IM_ST2M('-3',MIM4) + IF (MIM3 /= MIM4) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 649 + CALL FM_ST2M('0',MFM4) + CALL FM_ST2M('1',MFM3) + CALL FM_BIG(MFM5) + CALL FM_DIV(MFM3,MFM5,MFM6) + CALL FM_EQ(MFM6,MFM5) + MFM3 = NEAREST(MFM4,MFM3) + IF (MFM3 /= MFM5) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 650 + CALL FM_ST2M('0',MFM4) + CALL FM_ST2M('-1',MFM3) + CALL FM_BIG(MFM5) + CALL FM_DIV(MFM3,MFM5,MFM6) + CALL FM_EQ(MFM6,MFM5) + MFM3 = NEAREST(MFM4,MFM3) + IF (MFM3 /= MFM5) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 651 + CALL FM_ST2M('2.345',MFM4) + CALL FM_ST2M('1',MFM3) + MFM3 = NEAREST(MFM4,MFM3) + CALL FM_ULP(MFM4,MFM5) + CALL FM_ADD(MFM4,MFM5,MFM6) + CALL FM_EQ(MFM6,MFM4) + IF (MFM3 /= MFM4) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 652 + CALL FM_ST2M('2.345',MFM4) + CALL FM_ST2M('-1',MFM3) + MFM3 = NEAREST(MFM4,MFM3) + CALL FM_ULP(MFM4,MFM5) + CALL FM_SUB(MFM4,MFM5,MFM6) + CALL FM_EQ(MFM6,MFM4) + IF (MFM3 /= MFM4) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 653 + CALL FM_ST2M('1',MFM4) + CALL FM_ST2M('-1',MFM3) + MFM3 = NEAREST(MFM4,MFM3) + CALL FM_ST2M('0.99',MFM5) + CALL FM_ULP(MFM5,MFM6) + CALL FM_EQ(MFM6,MFM5) + CALL FM_SUB(MFM4,MFM5,MFM6) + CALL FM_EQ(MFM6,MFM4) + IF (MFM3 /= MFM4) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 654 + CALL FM_ST2M('-1',MFM4) + CALL FM_ST2M('12',MFM3) + MFM3 = NEAREST(MFM4,MFM3) + CALL FM_ST2M('-0.99',MFM5) + CALL FM_ULP(MFM5,MFM6) + CALL FM_EQ(MFM6,MFM5) + CALL FM_SUB(MFM4,MFM5,MFM6) + CALL FM_EQ(MFM6,MFM4) + IF (MFM3 /= MFM4) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 655 + MIM3 = NINT(MFM1) + CALL FM_NINT(MFM1,MFM4) + CALL IM_FM2I(MFM4,MIM4) + IF (MIM3 /= MIM4) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 656 + MIM3 = NINT(MIM1) + CALL IM_EQ(MIM1,MIM4) + IF (MIM3 /= MIM4) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 657 + MIM3 = NINT(MZM1) + CALL ZM_NINT(MZM1,MZM4) + CALL ZM_REAL(MZM4,MFM4) + CALL IM_FM2I(MFM4,MIM4) + IF (MIM3 /= MIM4) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 658 + J = PRECISION(MFM1) + IF (J /= INT(LOG10(REAL(MBASE))*(NDIG-1) + 1)) & + CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 659 + J = PRECISION(MZM1) + IF (J /= INT(LOG10(REAL(MBASE))*(NDIG-1) + 1)) & + CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 660 + J = RADIX(MFM1) + IF (J /= INT(MBASE)) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 661 + J = RADIX(MIM1) + IF (J /= INT(MBASE)) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 662 + J = RADIX(MZM1) + IF (J /= INT(MBASE)) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 663 + J = RANGE(MFM1) + IF (J /= INT(MXEXP*LOG10(REAL(MBASE)))) & + CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 664 + J = RANGE(MIM1) + IF (J /= INT(NDIGMX*LOG10(REAL(MBASE)))) & + CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 665 + J = RANGE(MZM1) + IF (J /= INT(MXEXP*LOG10(REAL(MBASE)))) & + CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 666 + MFM3 = REAL(MFM1) + CALL FM_EQ(MFM1,MFM4) + IF (MFM3 /= MFM4) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 667 + MFM3 = REAL(MIM1) + CALL IM_I2FM(MIM1,MFM4) + IF (MFM3 /= MFM4) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 668 + MFM3 = REAL(MZM1) + CALL ZM_REAL(MZM1,MFM4) + IF (MFM3 /= MFM4) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 669 + MFM3 = RRSPACING(MFM1) + CALL FM_ABS(MFM1,MFM4) + MFM4%MFM(1) = NDIG + IF (MFM3 /= MFM4) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + END SUBROUTINE TEST39 + + SUBROUTINE TEST40(NCASE,NERROR,KLOG) + +! Test functions SCALE, ..., TINY. + + USE FMVALS + USE FMZM + USE TEST_VARS + IMPLICIT NONE + + INTEGER KLOG,NERROR,NCASE + + WRITE (KW,"(/"// & + "' Testing the derived type SCALE, ..., TINY interfaces.')") + + NCASE = 670 + CALL FM_ST2M('0.7654',MFM4) + MFM3 = SCALE(MFM4,1) + CALL FM_MPYI(MFM4,INT(MBASE),MFM6) + CALL FM_EQ(MFM6,MFM4) + IF (MFM3 /= MFM4) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 671 + CALL ZM_ST2M('0.7654 - 0.3456 i',MZM4) + MZM3 = SCALE(MZM4,-2) + CALL ZM_DIVI(MZM4,INT(MBASE),MZM5) + CALL ZM_EQ(MZM5,MZM4) + CALL ZM_DIVI(MZM4,INT(MBASE),MZM5) + CALL ZM_EQ(MZM5,MZM4) + IF (MZM3 /= MZM4) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 672 + CALL FM_ST2M('0.7654',MFM4) + MFM3 = SETEXPONENT(MFM4,1) + CALL FM_MPYI(MFM4,INT(MBASE),MFM6) + CALL FM_EQ(MFM6,MFM4) + IF (MFM3 /= MFM4) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 673 + CALL FM_ST2M('0.7654',MFM4) + MFM3 = SIGN(MFM4,MFM2) + CALL FM_SIGN(MFM4,MFM2,MFM6) + CALL FM_EQ(MFM6,MFM4) + IF (MFM3 /= MFM4) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 674 + CALL IM_ST2M('231',MIM4) + MIM3 = SIGN(MIM4,MIM2) + CALL IM_SIGN(MIM4,MIM2,MIM5) + CALL IM_EQ(MIM5,MIM4) + IF (MIM3 /= MIM4) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 675 + CALL FM_ST2M('0.7654',MFM4) + MFM3 = SIN(MFM4) + CALL FM_SIN(MFM4,MFM6) + CALL FM_EQ(MFM6,MFM4) + IF (MFM3 /= MFM4) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 676 + CALL ZM_ST2M('0.7654 - 0.3456 i',MZM4) + MZM3 = SIN(MZM4) + CALL ZM_SIN(MZM4,MZM5) + CALL ZM_EQ(MZM5,MZM4) + IF (MZM3 /= MZM4) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 677 + CALL FM_ST2M('0.7654',MFM4) + MFM3 = SINH(MFM4) + CALL FM_SINH(MFM4,MFM6) + CALL FM_EQ(MFM6,MFM4) + IF (MFM3 /= MFM4) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 678 + CALL ZM_ST2M('0.7654 - 0.3456 i',MZM4) + MZM3 = SINH(MZM4) + CALL ZM_SINH(MZM4,MZM5) + CALL ZM_EQ(MZM5,MZM4) + IF (MZM3 /= MZM4) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 679 + CALL FM_ST2M('-0.7654',MFM4) + MFM3 = SPACING(MFM4) + CALL FM_ULP(MFM4,MFM6) + CALL FM_EQ(MFM6,MFM4) + CALL FM_ABS(MFM4,MFM6) + CALL FM_EQ(MFM6,MFM4) + IF (MFM3 /= MFM4) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 680 + CALL FM_ST2M('0.7654',MFM4) + MFM3 = SQRT(MFM4) + CALL FM_SQRT(MFM4,MFM6) + CALL FM_EQ(MFM6,MFM4) + IF (MFM3 /= MFM4) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 681 + CALL ZM_ST2M('0.7654 - 0.3456 i',MZM4) + MZM3 = SQRT(MZM4) + CALL ZM_SQRT(MZM4,MZM5) + CALL ZM_EQ(MZM5,MZM4) + IF (MZM3 /= MZM4) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 682 + CALL FM_ST2M('0.7654',MFM4) + MFM3 = TAN(MFM4) + CALL FM_TAN(MFM4,MFM6) + CALL FM_EQ(MFM6,MFM4) + IF (MFM3 /= MFM4) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 683 + CALL ZM_ST2M('0.7654 - 0.3456 i',MZM4) + MZM3 = TAN(MZM4) + CALL ZM_TAN(MZM4,MZM5) + CALL ZM_EQ(MZM5,MZM4) + IF (MZM3 /= MZM4) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 684 + CALL FM_ST2M('0.7654',MFM4) + MFM3 = TANH(MFM4) + CALL FM_TANH(MFM4,MFM6) + CALL FM_EQ(MFM6,MFM4) + IF (MFM3 /= MFM4) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 685 + CALL ZM_ST2M('0.7654 - 0.3456 i',MZM4) + MZM3 = TANH(MZM4) + CALL ZM_TANH(MZM4,MZM5) + CALL ZM_EQ(MZM5,MZM4) + IF (MZM3 /= MZM4) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 686 + CALL FM_BIG(MFM4) + CALL FM_I2M(1,MFM3) + CALL FM_DIV(MFM3,MFM4,MFM6) + CALL FM_EQ(MFM6,MFM4) + MFM3 = TINY(MFM1) + IF (MFM3 /= MFM4) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 687 + MIM3 = TINY(MIM1) + CALL IM_I2M(1,MIM4) + IF (MIM3 /= MIM4) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 688 + CALL FM_BIG(MFM4) + CALL FM_I2M(1,MFM3) + CALL FM_DIV(MFM3,MFM4,MFM6) + CALL FM_EQ(MFM6,MFM4) + CALL ZM_CMPX(MFM4,MFM4,MZM4) + MZM3 = TINY(MZM1) + IF (MZM3 /= MZM4) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + END SUBROUTINE TEST40 + + SUBROUTINE TEST41(NCASE,NERROR,KLOG) + +! Test functions TO_FM, TO_IM, TO_ZM, ..., TO_DPZ. + + USE FMVALS + USE FMZM + USE TEST_VARS + IMPLICIT NONE + + INTEGER KLOG,NERROR,NCASE + LOGICAL FM_COMP + + WRITE (KW,"(/"// & + "' Testing the derived type TO_FM, ..., TO_DPZ interfaces.')") + + RSMALL = EPSILON(1.0)*100.0 + DSMALL = EPSILON(1.0D0)*100.0 + + NCASE = 689 + MFM3 = TO_FM(123) + CALL FM_I2M(123,MFM4) + IF (MFM3 /= MFM4) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 690 + MFM3 = TO_FM(123.4) + CALL FM_SP2M(123.4,MFM4) + CALL FM_SUB(MFM3,MFM4,MFM6) + CALL FM_EQ(MFM6,MFM4) + CALL FM_DIV(MFM4,MFM3,MFM6) + CALL FM_EQ(MFM6,MFM4) + CALL FM_ABS(MFM4,MFM6) + CALL FM_EQ(MFM6,MFM4) + MFM3 = RSMALL + IF (FM_COMP(MFM4,'GT',MFM3)) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 691 + MFM3 = TO_FM(123.45D0) + CALL FM_DP2M(123.45D0,MFM4) + CALL FM_SUB(MFM3,MFM4,MFM6) + CALL FM_EQ(MFM6,MFM4) + CALL FM_DIV(MFM4,MFM3,MFM6) + CALL FM_EQ(MFM6,MFM4) + CALL FM_ABS(MFM4,MFM6) + CALL FM_EQ(MFM6,MFM4) + MFM3 = DSMALL + IF (FM_COMP(MFM4,'GT',MFM3)) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + + NCASE = 692 + MFM3 = TO_FM(CMPLX(123.4,567.8)) + CALL FM_SP2M(123.4,MFM4) + CALL FM_SUB(MFM3,MFM4,MFM6) + CALL FM_EQ(MFM6,MFM4) + CALL FM_DIV(MFM4,MFM3,MFM6) + CALL FM_EQ(MFM6,MFM4) + CALL FM_ABS(MFM4,MFM6) + CALL FM_EQ(MFM6,MFM4) + MFM3 = RSMALL + IF (FM_COMP(MFM4,'GT',MFM3)) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 693 + MFM3 = TO_FM(CMPLX(123.4D0,567.8D0,KIND(1.0D0))) + CALL FM_DP2M(123.4D0,MFM4) + CALL FM_SUB(MFM3,MFM4,MFM6) + CALL FM_EQ(MFM6,MFM4) + CALL FM_DIV(MFM4,MFM3,MFM6) + CALL FM_EQ(MFM6,MFM4) + CALL FM_ABS(MFM4,MFM6) + CALL FM_EQ(MFM6,MFM4) + MFM3 = DSMALL + IF (FM_COMP(MFM4,'GT',MFM3)) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 694 + MFM3 = TO_FM(MFM1) + CALL FM_EQ(MFM1,MFM4) + IF (MFM3 /= MFM4) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 695 + MFM3 = TO_FM(MIM1) + CALL IM_I2FM(MIM1,MFM4) + IF (MFM3 /= MFM4) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 696 + MFM3 = TO_FM(MZM1) + CALL ZM_REAL(MZM1,MFM4) + IF (MFM3 /= MFM4) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 697 + MFM3 = TO_FM('-123.654') + CALL FM_ST2M('-123.654',MFM4) + IF (MFM3 /= MFM4) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 698 + MIM3 = TO_IM(123) + CALL IM_I2M(123,MIM4) + IF (MIM3 /= MIM4) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 699 + MIM3 = TO_IM(123.4) + CALL FM_SP2M(123.4,MFM4) + CALL IM_FM2I(MFM4,MIM4) + IF (MIM3 /= MIM4) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 700 + MIM3 = TO_IM(123.45D0) + CALL FM_DP2M(123.45D0,MFM4) + CALL IM_FM2I(MFM4,MIM4) + IF (MIM3 /= MIM4) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 701 + MIM3 = TO_IM(CMPLX(123.4,567.8)) + CALL FM_SP2M(123.4,MFM4) + CALL IM_FM2I(MFM4,MIM4) + IF (MIM3 /= MIM4) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 702 + MIM3 = TO_IM(CMPLX(123.4D0,567.8D0,KIND(1.0D0))) + CALL FM_DP2M(123.4D0,MFM4) + CALL IM_FM2I(MFM4,MIM4) + IF (MIM3 /= MIM4) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 703 + MIM3 = TO_IM(MFM1) + CALL FM_EQ(MFM1,MFM4) + CALL IM_FM2I(MFM4,MIM4) + IF (MIM3 /= MIM4) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 704 + MIM3 = TO_IM(MIM1) + CALL IM_I2FM(MIM1,MFM4) + CALL IM_FM2I(MFM4,MIM4) + IF (MIM3 /= MIM4) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 705 + MIM3 = TO_IM(MZM1) + CALL ZM_REAL(MZM1,MFM4) + CALL IM_FM2I(MFM4,MIM4) + IF (MIM3 /= MIM4) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 706 + MIM3 = TO_IM('-123654') + CALL IM_ST2M('-123654',MIM4) + IF (MIM3 /= MIM4) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 707 + MZM3 = TO_ZM(123) + CALL ZM_I2M(123,MZM4) + IF (MZM3 /= MZM4) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 708 + MZM3 = TO_ZM(123.4) + CALL FM_SP2M(123.4,MFM4) + CALL FM_I2M(0,MFM5) + CALL ZM_CMPX(MFM4,MFM5,MZM4) + CALL ZM_SUB(MZM3,MZM4,MZM5) + CALL ZM_EQ(MZM5,MZM4) + CALL ZM_DIV(MZM4,MZM3,MZM5) + CALL ZM_EQ(MZM5,MZM4) + CALL ZM_ABS(MZM4,MFM4) + MFM3 = RSMALL + IF (FM_COMP(MFM4,'GT',MFM3)) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 709 + MZM3 = TO_ZM(123.45D0) + CALL FM_DP2M(123.45D0,MFM4) + CALL FM_I2M(0,MFM5) + CALL ZM_CMPX(MFM4,MFM5,MZM4) + CALL ZM_SUB(MZM3,MZM4,MZM5) + CALL ZM_EQ(MZM5,MZM4) + CALL ZM_DIV(MZM4,MZM3,MZM5) + CALL ZM_EQ(MZM5,MZM4) + CALL ZM_ABS(MZM4,MFM4) + MFM3 = DSMALL + IF (FM_COMP(MFM4,'GT',MFM3)) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 710 + MZM3 = TO_ZM(CMPLX(123.4,567.8)) + CALL FM_SP2M(123.4,MFM4) + CALL FM_SP2M(567.8,MFM5) + CALL ZM_CMPX(MFM4,MFM5,MZM4) + CALL ZM_SUB(MZM3,MZM4,MZM5) + CALL ZM_EQ(MZM5,MZM4) + CALL ZM_DIV(MZM4,MZM3,MZM5) + CALL ZM_EQ(MZM5,MZM4) + CALL ZM_ABS(MZM4,MFM4) + MFM3 = RSMALL + IF (FM_COMP(MFM4,'GT',MFM3)) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 711 + MZM3 = TO_ZM(CMPLX(123.4D0,567.8D0,KIND(1.0D0))) + CALL FM_DP2M(123.4D0,MFM4) + CALL FM_DP2M(567.8D0,MFM5) + CALL ZM_CMPX(MFM4,MFM5,MZM4) + CALL ZM_SUB(MZM3,MZM4,MZM5) + CALL ZM_EQ(MZM5,MZM4) + CALL ZM_DIV(MZM4,MZM3,MZM5) + CALL ZM_EQ(MZM5,MZM4) + CALL ZM_ABS(MZM4,MFM4) + MFM3 = DSMALL + IF (FM_COMP(MFM4,'GT',MFM3)) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 712 + MZM3 = TO_ZM(MFM1) + CALL FM_EQ(MFM1,MFM4) + CALL FM_I2M(0,MFM5) + CALL ZM_CMPX(MFM4,MFM5,MZM4) + IF (MZM3 /= MZM4) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 713 + MZM3 = TO_ZM(MIM1) + CALL IM_I2FM(MIM1,MFM4) + CALL FM_I2M(0,MFM5) + CALL ZM_CMPX(MFM4,MFM5,MZM4) + IF (MZM3 /= MZM4) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 714 + MZM3 = TO_ZM(MZM1) + CALL ZM_EQ(MZM1,MZM4) + IF (MZM3 /= MZM4) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 715 + MZM3 = TO_ZM('-123.654 + 98.7 i') + CALL ZM_ST2M('-123.654 + 98.7 i',MZM4) + IF (MZM3 /= MZM4) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 716 + CALL FM_M2I(MFM1,J3) + IF (TO_INT(MFM1) /= J3) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 717 + CALL IM_M2I(MIM1,J3) + IF (TO_INT(MIM1) /= J3) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 718 + CALL ZM_M2I(MZM1,J3) + IF (TO_INT(MZM1) /= J3) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 719 + CALL FM_M2SP(MFM1,R3) + IF (ABS((TO_SP(MFM1)-R3)/R3) > RSMALL) THEN + CALL PRTERR(KW,KLOG,NCASE,NERROR) + ENDIF + + NCASE = 720 + CALL IM_M2DP(MIM1,D3) + R3 = D3 + IF (ABS((TO_SP(MIM1)-R3)/R3) > RSMALL) THEN + CALL PRTERR(KW,KLOG,NCASE,NERROR) + ENDIF + + NCASE = 721 + CALL ZM_REAL(MZM1,MFM4) + CALL FM_M2SP(MFM4,R3) + IF (ABS((TO_SP(MZM1)-R3)/R3) > RSMALL) THEN + CALL PRTERR(KW,KLOG,NCASE,NERROR) + ENDIF + + NCASE = 722 + CALL FM_M2DP(MFM1,D3) + IF (ABS((TO_DP(MFM1)-D3)/D3) > DSMALL) THEN + CALL PRTERR(KW,KLOG,NCASE,NERROR) + ENDIF + + NCASE = 723 + CALL IM_M2DP(MIM1,D3) + IF (ABS((TO_DP(MIM1)-D3)/D3) > DSMALL) THEN + CALL PRTERR(KW,KLOG,NCASE,NERROR) + ENDIF + + NCASE = 724 + CALL ZM_REAL(MZM1,MFM4) + CALL FM_M2DP(MFM4,D3) + IF (ABS((TO_DP(MZM1)-D3)/D3) > DSMALL) THEN + CALL PRTERR(KW,KLOG,NCASE,NERROR) + ENDIF + + NCASE = 725 + CALL FM_M2SP(MFM1,R3) + C3 = R3 + IF (ABS((TO_SPZ(MFM1)-C3)/C3) > RSMALL) THEN + CALL PRTERR(KW,KLOG,NCASE,NERROR) + ENDIF + + NCASE = 726 + CALL IM_M2DP(MIM1,D3) + C3 = D3 + IF (ABS((TO_SPZ(MIM1)-C3)/C3) > RSMALL) THEN + CALL PRTERR(KW,KLOG,NCASE,NERROR) + ENDIF + + NCASE = 727 + CALL ZM_M2Z(MZM1,C3) + IF (ABS((TO_SPZ(MZM1)-C3)/C3) > RSMALL) THEN + CALL PRTERR(KW,KLOG,NCASE,NERROR) + ENDIF + + NCASE = 728 + CALL FM_M2DP(MFM1,D3) + CD3 = D3 + IF (ABS((TO_DPZ(MFM1)-CD3)/CD3) > DSMALL) THEN + CALL PRTERR(KW,KLOG,NCASE,NERROR) + ENDIF + + NCASE = 729 + CALL IM_M2DP(MIM1,D3) + CD3 = D3 + IF (ABS((TO_DPZ(MIM1)-CD3)/CD3) > DSMALL) THEN + CALL PRTERR(KW,KLOG,NCASE,NERROR) + ENDIF + + NCASE = 730 + CALL ZM_REAL(MZM1,MFM4) + CALL FM_M2DP(MFM4,D3) + CALL ZM_IMAG(MZM1,MFM4) + CALL FM_M2DP(MFM4,D4) + CD3 = CMPLX( D3 , D4 , KIND(0.0D0) ) + IF (ABS((TO_DPZ(MZM1)-CD3)/CD3) > DSMALL) THEN + CALL PRTERR(KW,KLOG,NCASE,NERROR) + ENDIF + + END SUBROUTINE TEST41 + + SUBROUTINE TEST42(NCASE,NERROR,KLOG) + +! Test the derived-type interface routines that are not +! used elsewhere in this program. + + USE FMVALS + USE FMZM + USE TEST_VARS + IMPLICIT NONE + + CHARACTER(80) :: STRING + INTEGER KLOG,NERROR,NCASE + + WRITE (KW,"(/"// & + "' Testing the derived type ADDI, ..., Z2M interfaces.')") + + RSMALL = EPSILON(1.0)*100.0 + DSMALL = EPSILON(1.0D0)*100.0 + MSMALL = EPSILON(TO_FM(1))*10000.0 + + NCASE = 731 + MFM3 = MFM1 + 123 + MFM4 = MFM1 + CALL FM_ADDI(MFM4,123) + IF (MFM3 /= MFM4) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 732 + CALL FM_CHSH(MFM1,MFM4,MFM3) + MFM3 = COSH(MFM1) + IF (MFM3 /= MFM4) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 733 + CALL FM_CHSH(MFM1,MFM3,MFM4) + MFM3 = SINH(MFM1) + IF (MFM3 /= MFM4) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 734 + CALL FM_CSSN(MFM1,MFM4,MFM3) + MFM3 = COS(MFM1) + IF (MFM3 /= MFM4) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 735 + CALL FM_CSSN(MFM1,MFM3,MFM4) + MFM3 = SIN(MFM1) + IF (MFM3 /= MFM4) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 736 + MFM3 = MFM1 / 123 + CALL FM_DIVI(MFM1,123,MFM4) + IF (MFM3 /= MFM4) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 737 + MFM3 = 123.45D0 + CALL FM_DPM(123.45D0,MFM4) + IF (ABS((MFM3-MFM4)/MFM4) > DSMALL) & + CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 738 + CALL FM_FORM('F70.56',MFM1,STRING) + CALL FM_ST2M(STRING(1:70),MFM4) + IF (ABS((MFM1-MFM4)/MFM4) > MSMALL) & + CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 739 + STRING = FM_FORMAT('F70.56',MFM1) + CALL FM_ST2M(STRING(1:70),MFM4) + IF (ABS((MFM1-MFM4)/MFM4) > MSMALL) & + CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 740 + MFM3 = MFM1 ** 123 + CALL FM_IPWR(MFM1,123,MFM4) + IF (MFM3 /= MFM4) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 741 + MFM3 = LOG(TO_FM(123)) + CALL FM_LNI(123,MFM4) + IF (MFM3 /= MFM4) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 742 + D4 = MFM1 + CALL FM_M2DP(MFM1,D5) + IF (ABS((D4-D5)/D4) > DSMALL) & + CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 743 + J4 = MFM1 + CALL FM_M2I(MFM1,J5) + IF (J4 /= J5) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 744 + R4 = MFM1 + CALL FM_M2SP(MFM1,R5) + IF (ABS((R4-R5)/R4) > RSMALL) & + CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 745 + MFM3 = 2.67 + CALL FM_MOD(MFM1,MFM3,MFM4) + MFM3 = MOD(MFM1,MFM3) + IF (MFM3 /= MFM4) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 746 + CALL FM_PI(MFM4) + MFM3 = 4*ATAN(TO_FM(1)) + IF (ABS((MFM3-MFM4)/MFM4) > MSMALL) & + CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 747 + MFM3 = MFM1 ** (TO_FM(1)/TO_FM(3)) + CALL FM_RPWR(MFM1,1,3,MFM4) + IF (ABS((MFM3-MFM4)/MFM4) > MSMALL) & + CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 748 + CALL FM_SQR(MFM1,MFM4) + MFM3 = MFM1*MFM1 + IF (MFM3 /= MFM4) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 749 + MIM3 = MIM1 / 13 + CALL IM_DIVI(MIM1,13,MIM4) + IF (MIM3 /= MIM4) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 750 + MIM3 = 13 + CALL IM_DIVR(MIM1,MIM3,MIM5,MIM4) + MIM3 = MOD(MIM1,MIM3) + IF (MIM3 /= MIM4) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 751 + MIM3 = 13 + CALL IM_DIVR(MIM1,MIM3,MIM5,MIM4) + CALL IM_EQ(MIM5,MIM3) + MIM4 = MIM1 / 13 + IF (MIM3 /= MIM4) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 752 + MIM3 = MIM1 / 13 + CALL IM_DVIR(MIM1,13,MIM4,J5) + IF (MIM3 /= MIM4) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 753 + J4 = MOD(MIM1,TO_IM(13)) + CALL IM_DVIR(MIM1,13,MIM4,J5) + IF (J4 /= J5) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 754 + CALL IM_FORM('I70',MIM1,STRING) + CALL IM_ST2M(STRING(1:70),MIM4) + IF (MIM1 /= MIM4) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 755 + STRING = IM_FORMAT('I70',MIM1) + CALL IM_ST2M(STRING(1:70),MIM4) + IF (MIM1 /= MIM4) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 756 + MIM3 = 40833 + MIM4 = 16042 + CALL IM_GCD(MIM3,MIM4,MIM5) + CALL IM_EQ(MIM5,MIM4) + IF (MIM4 /= 13) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 757 + MIM3 = 40833 + MIM4 = 16042 + MIM4 = GCD(MIM3,MIM4) + IF (MIM4 /= 13) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 758 + D4 = MIM1 + CALL IM_M2DP(MIM1,D5) + IF (ABS((D4-D5)/D4) > DSMALL) & + CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 759 + J4 = MIM1 + CALL IM_M2I(MIM1,J5) + IF (J4 /= J5) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 760 + MIM3 = 6 + CALL IM_MOD(MIM1,MIM3,MIM4) + MIM3 = MOD(MIM1,MIM3) + IF (MIM3 /= MIM4) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 761 + MIM3 = MIM1 * 123 + CALL IM_MPYI(MIM1,123,MIM4) + IF (MIM3 /= MIM4) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 762 + MIM2 = 3141 + MIM3 = 133 + CALL IM_MPYM(MIM1,MIM2,MIM3,MIM4) + MIM3 = MOD(MIM1*MIM2,MIM3) + IF (MIM3 /= MIM4) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 763 + MIM2 = 3141 + MIM3 = 133 + MIM4 = MULTIPLY_MOD(MIM1,MIM2,MIM3) + MIM3 = MOD(MIM1*MIM2,MIM3) + IF (MIM3 /= MIM4) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 764 + MIM2 = 31 + MIM3 = 147 + CALL IM_PMOD(MIM1,MIM2,MIM3,MIM4) + MIM3 = MOD(MIM1**MIM2,MIM3) + IF (MIM3 /= MIM4) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 765 + MIM2 = 31 + MIM3 = 147 + MIM4 = POWER_MOD(MIM1,MIM2,MIM3) + MIM3 = MOD(MIM1**MIM2,MIM3) + IF (MIM3 /= MIM4) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 766 + CALL IM_SQR(MIM1,MIM4) + MIM3 = MIM1*MIM1 + IF (MIM3 /= MIM4) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 767 + MZM3 = MZM1 + 123 + MZM4 = MZM1 + CALL ZM_ADDI(MZM4,123) + IF (MZM3 /= MZM4) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 768 + MFM3 = ATAN2(AIMAG(MZM1),REAL(MZM1)) + CALL ZM_ARG(MZM1,MFM4) + IF (MFM3 /= MFM4) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 769 + CALL ZM_CHSH(MZM1,MZM4,MZM3) + MZM3 = COSH(MZM1) + IF (MZM3 /= MZM4) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 770 + CALL ZM_CHSH(MZM1,MZM3,MZM4) + MZM3 = SINH(MZM1) + IF (MZM3 /= MZM4) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 771 + CALL ZM_CSSN(MZM1,MZM4,MZM3) + MZM3 = COS(MZM1) + IF (MZM3 /= MZM4) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 772 + CALL ZM_CSSN(MZM1,MZM3,MZM4) + MZM3 = SIN(MZM1) + IF (MZM3 /= MZM4) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 773 + CALL ZM_FORM('F35.26','F35.26',MZM1,STRING) + CALL ZM_ST2M(STRING(1:75),MZM4) + IF (ABS((MZM1-MZM4)/MZM4) > MSMALL) & + CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 774 + STRING = ZM_FORMAT('F35.26','F35.26',MZM1) + CALL ZM_ST2M(STRING(1:75),MZM4) + IF (ABS((MZM1-MZM4)/MZM4) > MSMALL) & + CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 775 + MZM3 = TO_ZM('123-456i') + CALL ZM_2I2M(123,-456,MZM4) + IF (MZM3 /= MZM4) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 776 + MZM3 = MZM1 ** 123 + CALL ZM_IPWR(MZM1,123,MZM4) + IF (MZM3 /= MZM4) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 777 + J4 = MZM1 + CALL ZM_M2I(MZM1,J5) + IF (J4 /= J5) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 778 + C4 = MZM1 + CALL ZM_M2Z(MZM1,C5) + IF (ABS((C4-C5)/C4) > RSMALL) & + CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 779 + MZM3 = MZM1 * 123 + CALL ZM_MPYI(MZM1,123,MZM4) + IF (MZM3 /= MZM4) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 780 + MZM3 = MZM1 ** (TO_ZM(1)/TO_ZM(3)) + CALL ZM_RPWR(MZM1,1,3,MZM4) + IF (ABS((MZM3-MZM4)/MZM4) > MSMALL) & + CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 781 + CALL ZM_SQR(MZM1,MZM4) + MZM3 = MZM1*MZM1 + IF (MZM3 /= MZM4) CALL PRTERR(KW,KLOG,NCASE,NERROR) + + NCASE = 782 + MZM3 = C2 + CALL ZM_Z2M(C2,MZM4) + IF (ABS((MZM3-MZM4)/MZM3) > RSMALL) & + CALL PRTERR(KW,KLOG,NCASE,NERROR) + + END SUBROUTINE TEST42 + + SUBROUTINE TEST43(NCASE,NERROR,KLOG) + +! Test Bernoulli numbers, Pochhammer's function, Euler's constant. + + USE FMVALS + USE FMZM + USE TEST_VARS + + IMPLICIT NONE + + INTEGER KLOG,NCASE,NERROR,NDGSAV + + WRITE (KW,"(/' Testing Bernoulli, Pochhammer, Euler.')") + + NCASE = 783 + M_A = 1 + CALL FM_BERN(10,M_A,M_C) + M_D = TO_FM('7.5757575757575757575757575757575757575757575757575758M-2') + M_D = ABS((M_C - M_D)/M_D) + IF (.NOT.(M_D <= TO_FM('1.0E-49'))) THEN + CALL ERRPRT_FM(' BERN ',M_A,'M_A',M_C,'M_C',M_D,'M_D', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 784 + M_A = 1 + CALL FM_BERN(0,M_A,M_C) + M_D = TO_FM('1') + M_D = ABS((M_C - M_D)/M_D) + IF (.NOT.(M_D <= TO_FM('1.0E-49'))) THEN + CALL ERRPRT_FM(' BERN ',M_A,'M_A',M_C,'M_C',M_D,'M_D', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 785 + M_A = 1 + CALL FM_BERN(1,M_A,M_C) + M_D = TO_FM('-0.5') + M_D = ABS((M_C - M_D)/M_D) + IF (.NOT.(M_D <= TO_FM('1.0E-49'))) THEN + CALL ERRPRT_FM(' BERN ',M_A,'M_A',M_C,'M_C',M_D,'M_D', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 786 + M_A = 1 + CALL FM_BERN(41,M_A,M_C) + M_D = TO_FM('0') + M_D = ABS(M_C - M_D) + IF (.NOT.(M_D <= TO_FM('1.0E-49'))) THEN + CALL ERRPRT_FM(' BERN ',M_A,'M_A',M_C,'M_C',M_D,'M_D', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 787 + M_A = 0 + CALL FM_BERN(52,M_A,M_C) + M_D = TO_FM('0') + M_D = ABS(M_C - M_D) + IF (.NOT.(M_D <= TO_FM('1.0E-49'))) THEN + CALL ERRPRT_FM(' BERN ',M_A,'M_A',M_C,'M_C',M_D,'M_D', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 788 + M_A = TO_FM('.7699115044247787610619469026548672566371681415929204') + CALL FM_BERN(102,M_A,M_C) + M_D = TO_FM('5.7022917356035929245914353639470138260075545712953255M+80') + M_D = ABS((M_C - M_D)/M_D) + IF (.NOT.(M_D <= TO_FM('1.0E-49'))) THEN + CALL ERRPRT_FM(' BERN ',M_A,'M_A',M_C,'M_C',M_D,'M_D', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 789 + M_A = TO_FM('.7699115044247787610619469026548672566371681415929204') + CALL FM_BERN(76,M_A,M_C) + M_D = TO_FM('-6.3274121765674850311763600458139008604123253720098077M+50') + M_D = ABS((M_C - M_D)/M_D) + IF (.NOT.(M_D <= TO_FM('1.0E-49'))) THEN + CALL ERRPRT_FM(' BERN ',M_A,'M_A',M_C,'M_C',M_D,'M_D', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 790 + M_A = TO_FM('.7699115044247787610619469026548672566371681415929204') + M_C = BERNOULLI(76)*M_A + M_D = TO_FM('-6.3274121765674850311763600458139008604123253720098077M+50') + M_D = ABS((M_C - M_D)/M_D) + IF (.NOT.(M_D <= TO_FM('1.0E-49'))) THEN + CALL ERRPRT_FM(' BERN ',M_A,'M_A',M_C,'M_C',M_D,'M_D', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 791 + M_A = TO_FM('769.9115044247787610619469026548672566371681415929204') + CALL FM_POCH(M_A,10,M_C) + M_D = TO_FM('7.7568981408767238023000514593534249181767332686451635M+28') + M_D = ABS((M_C - M_D)/M_D) + IF (.NOT.(M_D <= TO_FM('1.0E-49'))) THEN + CALL ERRPRT_FM(' POCH ',M_A,'M_A',M_C,'M_C',M_D,'M_D', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 792 + M_A = TO_FM('7699.115044247787610619469026548672566371681415929204') + CALL FM_POCH(M_A,2222,M_C) + M_D = TO_FM('1.3306321985792900130409652455318897459921360351317942M+8763') + M_D = ABS((M_C - M_D)/M_D) + IF (.NOT.(M_D <= TO_FM('1.0E-49'))) THEN + CALL ERRPRT_FM(' POCH ',M_A,'M_A',M_C,'M_C',M_D,'M_D', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 793 + M_A = TO_FM('-7') + CALL FM_POCH(M_A,12,M_C) + M_D = TO_FM('0') + M_D = ABS(M_C - M_D) + IF (.NOT.(M_D <= TO_FM('1.0E-49'))) THEN + CALL ERRPRT_FM(' POCH ',M_A,'M_A',M_C,'M_C',M_D,'M_D', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 794 + M_A = TO_FM('7.7568981408767238023000514593534249181767332686451635M+281') + CALL FM_POCH(M_A,6,M_C) + M_D = TO_FM('2.1783543710019819738631136312604490177244818356538937M+1691') + M_D = ABS((M_C - M_D)/M_D) + IF (.NOT.(M_D <= TO_FM('1.0E-49'))) THEN + CALL ERRPRT_FM(' POCH ',M_A,'M_A',M_C,'M_C',M_D,'M_D', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 795 + M_A = TO_FM('7.7568981408767238023000514593534249181767332686451635M-281') + CALL FM_POCH(M_A,8,M_C) + M_D = TO_FM('3.9094766630018687963592259355141261587610735673971624M-277') + M_D = ABS((M_C - M_D)/M_D) + IF (.NOT.(M_D <= TO_FM('1.0E-49'))) THEN + CALL ERRPRT_FM(' POCH ',M_A,'M_A',M_C,'M_C',M_D,'M_D', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 796 + M_A = TO_FM('7.7568981408767238023000514593534249181767332686451635M-281') + CALL FM_POCH(M_A,1,M_C) + M_D = TO_FM('7.7568981408767238023000514593534249181767332686451635M-281') + M_D = ABS((M_C - M_D)/M_D) + IF (.NOT.(M_D <= TO_FM('1.0E-49'))) THEN + CALL ERRPRT_FM(' POCH ',M_A,'M_A',M_C,'M_C',M_D,'M_D', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 797 + M_A = TO_FM('7.7568981408767238023000514593534249181767332686451635M-281') + CALL FM_POCH(M_A,0,M_C) + M_D = TO_FM('1') + M_D = ABS((M_C - M_D)/M_D) + IF (.NOT.(M_D <= TO_FM('1.0E-49'))) THEN + CALL ERRPRT_FM(' POCH ',M_A,'M_A',M_C,'M_C',M_D,'M_D', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 798 + M_A = TO_FM('0') + CALL FM_POCH(M_A,8,M_C) + M_D = TO_FM('0') + M_D = ABS(M_C - M_D) + IF (.NOT.(M_D <= TO_FM('1.0E-49'))) THEN + CALL ERRPRT_FM(' POCH ',M_A,'M_A',M_C,'M_C',M_D,'M_D', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 799 + M_A = TO_FM('769.9115044247787610619469026548672566371681415929204') + M_C = POCHHAMMER(M_A,10) + M_D = TO_FM('7.7568981408767238023000514593534249181767332686451635M+28') + M_D = ABS((M_C - M_D)/M_D) + IF (.NOT.(M_D <= TO_FM('1.0E-49'))) THEN + CALL ERRPRT_FM(' POCH ',M_A,'M_A',M_C,'M_C',M_D,'M_D', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 800 + CALL FM_EULR(M_C) + M_D = TO_FM('.5772156649015328606065120900824024310421593359399236') + M_D = ABS((M_C - M_D)/M_D) + IF (.NOT.(M_D <= TO_FM('1.0E-49'))) THEN + CALL ERRPRT_FM(' EULR ',M_A,'M_A',M_C,'M_C',M_D,'M_D', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 801 + NDGSAV = NDIG + NDIG = MIN(NDIGMX,INT(1785*DLOGTN/DLOGMB)+2) + CALL FM_EULR(M_C) + M_D = TO_FM( & + ' .5772156649015328606065120900824024310421593359399235988057672348848677267'// & + '776646709369470632917467495146314472498070824809605040144865428362241739976'// & + '449235362535003337429373377376739427925952582470949160087352039481656708532'// & + '331517766115286211995015079847937450857057400299213547861466940296043254215'// & + '190587755352673313992540129674205137541395491116851028079842348775872050384'// & + '310939973613725530608893312676001724795378367592713515772261027349291394079'// & + '843010341777177808815495706610750101619166334015227893586796549725203621287'// & + '922655595366962817638879272680132431010476505963703947394957638906572967929'// & + '601009015125195950922243501409349871228247949747195646976318506676129063811'// & + '051824197444867836380861749455169892792301877391072945781554316005002182844'// & + '096053772434203285478367015177394398700302370339518328690001558193988042707'// & + '411542227819716523011073565833967348717650491941812300040654693142999297779'// & + '569303100503086303418569803231083691640025892970890985486825777364288253954'// & + '925873629596133298574739302373438847070370284412920166417850248733379080562'// & + '754998434590761643167103146710722370021810745044418664759134803669025532458'// & + '625442225345181387912434573501361297782278288148945909863846006293169471887'// & + '149587525492366493520473243641097268276160877595088095126208404544477992299'// & + '157248292516251278427659657083214610298214617951957959095922704208989627971'// & + '255363217948873764210660607065982561990102880756125199137511678217643619057'// & + '058440783573501580056077457934213144988500786415171615194565706170432450750'// & + '081687052307890937046143066848179164968425491504967243121837838753564894950'// & + '868454102340601622508515583867234944187880440940770106883795111307872023426'// & + '395226920971608856908382511378712836820491178925944784861991185293910293099'// & + '059255266917274468920443869711147174571574573203935209122316085086828') + M_D = ABS((M_C - M_D)/M_D) + IF (.NOT.(M_D <= MAX(TO_FM('1.0E-1785'),10*EPSILON(M_C)))) THEN + CALL ERRPRT_FM(' EULR ',M_A,'M_A',M_C,'M_C',M_D,'M_D', & + NCASE,NERROR,KLOG) + ENDIF + NDIG = NDGSAV + + RETURN + END SUBROUTINE TEST43 + + SUBROUTINE TEST44(NCASE,NERROR,KLOG) + +! Test Gamma, Factorial, Log(Gamma), Beta, Binomial. + + USE FMVALS + USE FMZM + USE TEST_VARS + + IMPLICIT NONE + + INTEGER KLOG,NCASE,NERROR + + WRITE (KW,"(/' Testing Gamma, Factorial, Log(Gamma), Beta, Binomial.')") + + NCASE = 802 + M_A = 19 + CALL FM_GAM(M_A,M_C) + M_D = TO_FM('6.402373705728M+15') + M_D = ABS((M_C - M_D)/M_D) + IF (.NOT.(M_D <= TO_FM('1.0E-49'))) THEN + CALL ERRPRT_FM(' GAM ',M_A,'M_A',M_C,'M_C',M_D,'M_D', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 803 + M_A = TO_FM('.7699115044247787610619469026548672566371681415929204') + CALL FM_GAM(M_A,M_C) + M_D = TO_FM('1.1998023858495967876496039855917100290498970370440326') + M_D = ABS((M_C - M_D)/M_D) + IF (.NOT.(M_D <= TO_FM('1.0E-49'))) THEN + CALL ERRPRT_FM(' GAM ',M_A,'M_A',M_C,'M_C',M_D,'M_D', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 804 + M_A = TO_FM('.7699115044247787610619469026548672566371681415929204') + CALL FM_GAM(M_A,M_C) + M_D = TO_FM('1.1998023858495967876496039855917100290498970370440326') + M_D = ABS((M_C - M_D)/M_D) + IF (.NOT.(M_D <= TO_FM('1.0E-49'))) THEN + CALL ERRPRT_FM(' GAM ',M_A,'M_A',M_C,'M_C',M_D,'M_D', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 805 + M_A = TO_FM('5.7699115044247787610619469026548672566371681415929204') + CALL FM_GAM(M_A,M_C) + M_D = TO_FM('8.1434691207877806133071511233406796488474685081500979M+1') + M_D = ABS((M_C - M_D)/M_D) + IF (.NOT.(M_D <= TO_FM('1.0E-49'))) THEN + CALL ERRPRT_FM(' GAM ',M_A,'M_A',M_C,'M_C',M_D,'M_D', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 806 + M_A = TO_FM('7.7568981408767238023000514593534249181767332686451635M-281') + CALL FM_GAM(M_A,M_C) + M_D = TO_FM('1.2891751081921193691625844770542239587773115818085396M+280') + M_D = ABS((M_C - M_D)/M_D) + IF (.NOT.(M_D <= TO_FM('1.0E-49'))) THEN + CALL ERRPRT_FM(' GAM ',M_A,'M_A',M_C,'M_C',M_D,'M_D', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 807 + M_A = TO_FM('2') + CALL FM_GAM(M_A,M_C) + M_D = TO_FM('1') + M_D = ABS((M_C - M_D)/M_D) + IF (.NOT.(M_D <= TO_FM('1.0E-49'))) THEN + CALL ERRPRT_FM(' GAM ',M_A,'M_A',M_C,'M_C',M_D,'M_D', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 808 + M_A = TO_FM('5.7699115044247787610619469026548672566371681415929204') + M_C = GAMMA(M_A) + M_D = TO_FM('8.1434691207877806133071511233406796488474685081500979M+1') + M_D = ABS((M_C - M_D)/M_D) + IF (.NOT.(M_D <= TO_FM('1.0E-49'))) THEN + CALL ERRPRT_FM(' GAM ',M_A,'M_A',M_C,'M_C',M_D,'M_D', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 809 + M_A = 33 + CALL FM_FACT(M_A,M_C) + M_D = TO_FM('8.68331761881188649551819440128M+36') + M_D = ABS((M_C - M_D)/M_D) + IF (.NOT.(M_D <= TO_FM('1.0E-49'))) THEN + CALL ERRPRT_FM(' FACT ',M_A,'M_A',M_C,'M_C',M_D,'M_D', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 810 + M_A = TO_FM('769.9115044247787610619469026548672566371681415929204') + CALL FM_FACT(M_A,M_C) + M_D = TO_FM('5.9982590033571347622193071279165294725603013413394492M+1889') + M_D = ABS((M_C - M_D)/M_D) + IF (.NOT.(M_D <= TO_FM('1.0E-49'))) THEN + CALL ERRPRT_FM(' FACT ',M_A,'M_A',M_C,'M_C',M_D,'M_D', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 811 + M_A = TO_FM('769.9115044247787610619469026548672566371681415929204') + M_C = FACTORIAL(M_A) + M_D = TO_FM('5.9982590033571347622193071279165294725603013413394492M+1889') + M_D = ABS((M_C - M_D)/M_D) + IF (.NOT.(M_D <= TO_FM('1.0E-49'))) THEN + CALL ERRPRT_FM(' FACT ',M_A,'M_A',M_C,'M_C',M_D,'M_D', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 812 + M_A = TO_FM('1.0M-222') + CALL FM_LNGM(M_A,M_C) + M_D = TO_FM('5.1117389064467814185199410293992885408744453047558760M+2') + M_D = ABS((M_C - M_D)/M_D) + IF (.NOT.(M_D <= TO_FM('1.0E-49'))) THEN + CALL ERRPRT_FM(' LNGM ',M_A,'M_A',M_C,'M_C',M_D,'M_D', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 813 + M_A = TO_FM('2') + CALL FM_LNGM(M_A,M_C) + M_D = TO_FM('0') + M_D = ABS(M_C - M_D) + IF (.NOT.(M_D <= TO_FM('1.0E-49'))) THEN + CALL ERRPRT_FM(' LNGM ',M_A,'M_A',M_C,'M_C',M_D,'M_D', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 814 + M_A = TO_FM('33') + CALL FM_LNGM(M_A,M_C) + M_D = TO_FM('8.1557959456115037178502968666011206687099284403417368M+1') + M_D = ABS((M_C - M_D)/M_D) + IF (.NOT.(M_D <= TO_FM('1.0E-49'))) THEN + CALL ERRPRT_FM(' LNGM ',M_A,'M_A',M_C,'M_C',M_D,'M_D', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 815 + M_A = TO_FM('2.00000000000000000001') + CALL FM_LNGM(M_A,M_C) + M_D = TO_FM('4.2278433509846713939671258025183870114019600466320121M-21') + M_D = ABS((M_C - M_D)/M_D) + IF (.NOT.(M_D <= TO_FM('1.0E-49'))) THEN + CALL ERRPRT_FM(' LNGM ',M_A,'M_A',M_C,'M_C',M_D,'M_D', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 816 + M_C = LOG_GAMMA(TO_FM('33')) + M_D = TO_FM('8.1557959456115037178502968666011206687099284403417368M+1') + M_D = ABS((M_C - M_D)/M_D) + IF (.NOT.(M_D <= TO_FM('1.0E-49'))) THEN + CALL ERRPRT_FM(' LNGM ',M_A,'M_A',M_C,'M_C',M_D,'M_D', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 817 + M_A = TO_FM('2.0706137739520290320140007735608464643737932737070189M-223') + M_B = TO_FM('.78') + CALL FM_BETA(M_A,M_B,M_C) + M_D = TO_FM('4.8294858876137637017880452468052846823385248996130407M+222') + M_D = ABS((M_C - M_D)/M_D) + IF (.NOT.(M_D <= TO_FM('1.0E-49'))) THEN + CALL ERRPRT_FM(' BETA ',M_A,'M_A',M_C,'M_C',M_D,'M_D', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 818 + M_A = TO_FM('.78') + M_B = TO_FM('2.0706137739520290320140007735608464643737932737070189M-223') + CALL FM_BETA(M_A,M_B,M_C) + M_D = TO_FM('4.8294858876137637017880452468052846823385248996130407M+222') + M_D = ABS((M_C - M_D)/M_D) + IF (.NOT.(M_D <= TO_FM('1.0E-49'))) THEN + CALL ERRPRT_FM(' BETA ',M_A,'M_A',M_C,'M_C',M_D,'M_D', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 819 + M_A = TO_FM('-4.5') + M_B = TO_FM('4.5') + CALL FM_BETA(M_A,M_B,M_C) + M_D = TO_FM('0') + M_D = ABS(M_C - M_D) + IF (.NOT.(M_D <= TO_FM('1.0E-49'))) THEN + CALL ERRPRT_FM(' BETA ',M_A,'M_A',M_C,'M_C',M_D,'M_D', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 820 + M_A = TO_FM('-5.5') + M_B = TO_FM('4.5') + CALL FM_BETA(M_A,M_B,M_C) + M_D = TO_FM('0') + M_D = ABS(M_C - M_D) + IF (.NOT.(M_D <= TO_FM('1.0E-49'))) THEN + CALL ERRPRT_FM(' BETA ',M_A,'M_A',M_C,'M_C',M_D,'M_D', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 821 + M_A = TO_FM('10') + M_B = TO_FM('4') + CALL FM_BETA(M_A,M_B,M_C) + M_D = TO_FM('3.4965034965034965034965034965034965034965034965034965M-4') + M_D = ABS((M_C - M_D)/M_D) + IF (.NOT.(M_D <= TO_FM('1.0E-49'))) THEN + CALL ERRPRT_FM(' BETA ',M_A,'M_A',M_C,'M_C',M_D,'M_D', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 822 + M_A = TO_FM('1.0M+1234') + M_B = TO_FM('2.2') + CALL FM_BETA(M_A,M_B,M_C) + M_D = TO_FM('1.7462392672319547876554292922652110015806932440139209M-2715') + M_D = ABS((M_C - M_D)/M_D) + IF (.NOT.(M_D <= TO_FM('1.0E-49'))) THEN + CALL ERRPRT_FM(' BETA ',M_A,'M_A',M_C,'M_C',M_D,'M_D', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 823 + M_A = TO_FM('10') + M_B = TO_FM('5.3') + CALL FM_BETA(M_A,M_B,M_C) + M_D = TO_FM('7.0836036771097107530120640698518155187687458162734679M-5') + M_D = ABS((M_C - M_D)/M_D) + IF (.NOT.(M_D <= TO_FM('1.0E-49'))) THEN + CALL ERRPRT_FM(' BETA ',M_A,'M_A',M_C,'M_C',M_D,'M_D', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 824 + M_A = TO_FM('10.3') + M_B = TO_FM('5') + CALL FM_BETA(M_A,M_B,M_C) + M_D = TO_FM('8.8146035423244390793072072569173028531206477712519934M-5') + M_D = ABS((M_C - M_D)/M_D) + IF (.NOT.(M_D <= TO_FM('1.0E-49'))) THEN + CALL ERRPRT_FM(' BETA ',M_A,'M_A',M_C,'M_C',M_D,'M_D', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 825 + M_A = TO_FM('10.3') + M_B = TO_FM('5') + M_C = BETA(M_A,M_B) + M_D = TO_FM('8.8146035423244390793072072569173028531206477712519934M-5') + M_D = ABS((M_C - M_D)/M_D) + IF (.NOT.(M_D <= TO_FM('1.0E-49'))) THEN + CALL ERRPRT_FM(' BETA ',M_A,'M_A',M_C,'M_C',M_D,'M_D', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 826 + M_A = TO_FM('12.5') + M_B = TO_FM('0') + CALL FM_COMB(M_A,M_B,M_C) + M_D = TO_FM('1') + M_D = ABS((M_C - M_D)/M_D) + IF (.NOT.(M_D <= TO_FM('1.0E-49'))) THEN + CALL ERRPRT_FM(' COMB ',M_A,'M_A',M_C,'M_C',M_D,'M_D', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 827 + M_A = TO_FM('5') + M_B = TO_FM('-2') + CALL FM_COMB(M_A,M_B,M_C) + M_D = TO_FM('0') + M_D = ABS(M_C - M_D) + IF (.NOT.(M_D <= TO_FM('1.0E-49'))) THEN + CALL ERRPRT_FM(' COMB ',M_A,'M_A',M_C,'M_C',M_D,'M_D', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 828 + M_A = TO_FM('12.5') + M_B = TO_FM('12.5') + CALL FM_COMB(M_A,M_B,M_C) + M_D = TO_FM('1') + M_D = ABS((M_C - M_D)/M_D) + IF (.NOT.(M_D <= TO_FM('1.0E-49'))) THEN + CALL ERRPRT_FM(' COMB ',M_A,'M_A',M_C,'M_C',M_D,'M_D', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 829 + M_A = TO_FM('-4.5') + M_B = TO_FM('4.5') + CALL FM_COMB(M_A,M_B,M_C) + M_D = TO_FM('0') + M_D = ABS(M_C - M_D) + IF (.NOT.(M_D <= TO_FM('1.0E-49'))) THEN + CALL ERRPRT_FM(' COMB ',M_A,'M_A',M_C,'M_C',M_D,'M_D', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 830 + M_A = TO_FM('-4.5') + M_B = TO_FM('4.5') + CALL FM_COMB(M_A,M_B,M_C) + M_D = TO_FM('0') + M_D = ABS(M_C - M_D) + IF (.NOT.(M_D <= TO_FM('1.0E-49'))) THEN + CALL ERRPRT_FM(' COMB ',M_A,'M_A',M_C,'M_C',M_D,'M_D', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 831 + M_A = TO_FM('-10') + M_B = TO_FM('3') + CALL FM_COMB(M_A,M_B,M_C) + M_D = TO_FM('-220') + M_D = ABS((M_C - M_D)/M_D) + IF (.NOT.(M_D <= TO_FM('1.0E-49'))) THEN + CALL ERRPRT_FM(' COMB ',M_A,'M_A',M_C,'M_C',M_D,'M_D', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 832 + M_A = TO_FM('52') + M_B = TO_FM('5') + CALL FM_COMB(M_A,M_B,M_C) + M_D = TO_FM('2.59896M+6') + M_D = ABS((M_C - M_D)/M_D) + IF (.NOT.(M_D <= TO_FM('1.0E-49'))) THEN + CALL ERRPRT_FM(' COMB ',M_A,'M_A',M_C,'M_C',M_D,'M_D', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 833 + M_A = TO_FM('1.0M+1234') + M_B = TO_FM('7') + CALL FM_COMB(M_A,M_B,M_C) + M_D = TO_FM('1.9841269841269841269841269841269841269841269841269841M+8634') + M_D = ABS((M_C - M_D)/M_D) + IF (.NOT.(M_D <= TO_FM('1.0E-49'))) THEN + CALL ERRPRT_FM(' COMB ',M_A,'M_A',M_C,'M_C',M_D,'M_D', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 834 + M_A = TO_FM('1.0M+123') + M_B = TO_FM('2.2') + CALL FM_COMB(M_A,M_B,M_C) + M_D = TO_FM('1.6423797032130683531106846289429264567307029528308099M+270') + M_D = ABS((M_C - M_D)/M_D) + IF (.NOT.(M_D <= TO_FM('1.0E-49'))) THEN + CALL ERRPRT_FM(' COMB ',M_A,'M_A',M_C,'M_C',M_D,'M_D', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 835 + M_A = TO_FM('1.0M-100') + M_B = TO_FM('4') + CALL FM_COMB(M_A,M_B,M_C) + M_D = TO_FM('-2.5M-101') + M_D = ABS((M_C - M_D)/M_D) + IF (.NOT.(M_D <= TO_FM('1.0E-49'))) THEN + CALL ERRPRT_FM(' COMB ',M_A,'M_A',M_C,'M_C',M_D,'M_D', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 836 + M_A = TO_FM('1.0M+123') + M_B = TO_FM('2.2') + M_C = BINOMIAL(M_A,M_B) + M_D = TO_FM('1.6423797032130683531106846289429264567307029528308099M+270') + M_D = ABS((M_C - M_D)/M_D) + IF (.NOT.(M_D <= TO_FM('1.0E-49'))) THEN + CALL ERRPRT_FM(' COMB ',M_A,'M_A',M_C,'M_C',M_D,'M_D', & + NCASE,NERROR,KLOG) + ENDIF + + RETURN + END SUBROUTINE TEST44 + + SUBROUTINE TEST45(NCASE,NERROR,KLOG) + +! Test Incomplete Gamma, Incomplete Beta. + + USE FMVALS + USE FMZM + USE TEST_VARS + + IMPLICIT NONE + + INTEGER KLOG,NCASE,NERROR + + WRITE (KW,"(/' Testing Incomplete Gamma, Incomplete Beta.')") + + NCASE = 837 + M_A = TO_FM('2.0706137739520290320140007735608464643737932737070189M-145') + M_B = TO_FM('.34') + CALL FM_IGM1(M_A,M_B,M_C) + M_D = TO_FM('4.8294858876137637017880452468052846823385248996130407M+144') + M_D = ABS((M_C - M_D)/M_D) + IF (.NOT.(M_D <= TO_FM('1.0E-49'))) THEN + CALL ERRPRT_FM(' IGM1 ',M_A,'M_A',M_C,'M_C',M_D,'M_D', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 838 + M_A = TO_FM('1.0E-50') + M_B = TO_FM('1.0E+555') + CALL FM_IGM1(M_A,M_B,M_C) + M_D = TO_FM('9.9999999999999999999999999999999999999999999999999423M+49') + M_D = ABS((M_C - M_D)/M_D) + IF (.NOT.(M_D <= TO_FM('1.0E-49'))) THEN + CALL ERRPRT_FM(' IGM1 ',M_A,'M_A',M_C,'M_C',M_D,'M_D', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 839 + M_A = TO_FM('1.2') + M_B = TO_FM('2.3') + CALL FM_IGM1(M_A,M_B,M_C) + M_D = TO_FM('7.9163089830797686672658085698101181778608009481363580M-1') + M_D = ABS((M_C - M_D)/M_D) + IF (.NOT.(M_D <= TO_FM('1.0E-49'))) THEN + CALL ERRPRT_FM(' IGM1 ',M_A,'M_A',M_C,'M_C',M_D,'M_D', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 840 + M_A = TO_FM('23.4') + M_B = TO_FM('456.7') + CALL FM_IGM1(M_A,M_B,M_C) + M_D = TO_FM('3.9191215305400046110416169991395759293572844563673750M+21') + M_D = ABS((M_C - M_D)/M_D) + IF (.NOT.(M_D <= TO_FM('1.0E-49'))) THEN + CALL ERRPRT_FM(' IGM1 ',M_A,'M_A',M_C,'M_C',M_D,'M_D', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 841 + M_A = TO_FM('1.2') + M_B = TO_FM('0') + CALL FM_IGM1(M_A,M_B,M_C) + M_D = TO_FM('0') + M_D = ABS(M_C - M_D) + IF (.NOT.(M_D <= TO_FM('1.0E-49'))) THEN + CALL ERRPRT_FM(' IGM1 ',M_A,'M_A',M_C,'M_C',M_D,'M_D', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 842 + M_A = TO_FM('-1234.5') + M_B = TO_FM('3.4') + CALL FM_IGM1(M_A,M_B,M_C) + M_D = TO_FM('-2.0892439131810030556730824779643382797767198269736235M-661') + M_D = ABS((M_C - M_D)/M_D) + IF (.NOT.(M_D <= TO_FM('1.0E-49'))) THEN + CALL ERRPRT_FM(' IGM1 ',M_A,'M_A',M_C,'M_C',M_D,'M_D', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 843 + M_A = TO_FM('10.3') + M_B = TO_FM('230.7') + CALL FM_IGM1(M_A,M_B,M_C) + M_D = TO_FM('7.1643068906237524454762965471616445342244699109269471M+5') + M_D = ABS((M_C - M_D)/M_D) + IF (.NOT.(M_D <= TO_FM('1.0E-49'))) THEN + CALL ERRPRT_FM(' IGM1 ',M_A,'M_A',M_C,'M_C',M_D,'M_D', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 844 + M_A = TO_FM('1.2') + M_B = TO_FM('2.3') + M_C = INCOMPLETE_GAMMA1(M_A,M_B) + M_D = TO_FM('7.9163089830797686672658085698101181778608009481363580M-1') + M_D = ABS((M_C - M_D)/M_D) + IF (.NOT.(M_D <= TO_FM('1.0E-49'))) THEN + CALL ERRPRT_FM(' IGM1 ',M_A,'M_A',M_C,'M_C',M_D,'M_D', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 845 + M_A = TO_FM('0') + M_B = TO_FM('4.5') + CALL FM_IGM2(M_A,M_B,M_C) + M_D = TO_FM('2.0734007547146144328855938695797884889319725701443004M-3') + M_D = ABS((M_C - M_D)/M_D) + IF (.NOT.(M_D <= TO_FM('1.0E-49'))) THEN + CALL ERRPRT_FM(' IGM2 ',M_A,'M_A',M_C,'M_C',M_D,'M_D', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 846 + M_A = TO_FM('4.5') + M_B = TO_FM('0') + CALL FM_IGM2(M_A,M_B,M_C) + M_D = TO_FM('1.1631728396567448929144224109426265262108918305803166M+1') + M_D = ABS((M_C - M_D)/M_D) + IF (.NOT.(M_D <= TO_FM('1.0E-49'))) THEN + CALL ERRPRT_FM(' IGM2 ',M_A,'M_A',M_C,'M_C',M_D,'M_D', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 847 + M_A = TO_FM('1.2') + M_B = TO_FM('2.3') + CALL FM_IGM2(M_A,M_B,M_C) + M_D = TO_FM('1.2653784409178374391437079820481858290074190484504480M-1') + M_D = ABS((M_C - M_D)/M_D) + IF (.NOT.(M_D <= TO_FM('1.0E-49'))) THEN + CALL ERRPRT_FM(' IGM2 ',M_A,'M_A',M_C,'M_C',M_D,'M_D', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 848 + M_A = TO_FM('3.4') + M_B = TO_FM('456.7') + CALL FM_IGM2(M_A,M_B,M_C) + M_D = TO_FM('1.1043526800164195407100289367720949121507981651704628M-192') + M_D = ABS((M_C - M_D)/M_D) + IF (.NOT.(M_D <= TO_FM('1.0E-49'))) THEN + CALL ERRPRT_FM(' IGM2 ',M_A,'M_A',M_C,'M_C',M_D,'M_D', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 849 + M_A = TO_FM('1.0E-30') + M_B = TO_FM('40.7') + CALL FM_IGM2(M_A,M_B,M_C) + M_D = TO_FM('5.0619447546123889551107110735110897294460083487536391M-20') + M_D = ABS((M_C - M_D)/M_D) + IF (.NOT.(M_D <= TO_FM('1.0E-49'))) THEN + CALL ERRPRT_FM(' IGM2 ',M_A,'M_A',M_C,'M_C',M_D,'M_D', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 850 + M_A = TO_FM('-8000.3') + M_B = TO_FM('1.0e-10') + CALL FM_IGM2(M_A,M_B,M_C) + M_D = TO_FM('1.2499531266327356460522174653022492899665091451890036M+79999') + M_D = ABS((M_C - M_D)/M_D) + IF (.NOT.(M_D <= TO_FM('1.0E-49'))) THEN + CALL ERRPRT_FM(' IGM2 ',M_A,'M_A',M_C,'M_C',M_D,'M_D', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 851 + M_A = TO_FM('1') + M_B = TO_FM('-10.7') + CALL FM_IGM2(M_A,M_B,M_C) + M_D = TO_FM('4.4355855130297866938628363428602120081387560278336788M+4') + M_D = ABS((M_C - M_D)/M_D) + IF (.NOT.(M_D <= TO_FM('1.0E-49'))) THEN + CALL ERRPRT_FM(' IGM2 ',M_A,'M_A',M_C,'M_C',M_D,'M_D', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 852 + M_A = TO_FM('1.2') + M_B = TO_FM('2.3') + M_C = INCOMPLETE_GAMMA2(M_A,M_B) + M_D = TO_FM('1.2653784409178374391437079820481858290074190484504480M-1') + M_D = ABS((M_C - M_D)/M_D) + IF (.NOT.(M_D <= TO_FM('1.0E-49'))) THEN + CALL ERRPRT_FM(' IGM2 ',M_A,'M_A',M_C,'M_C',M_D,'M_D', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 853 + M_A = TO_FM('0.1') + M_B = TO_FM('23.4') + M_C = TO_FM('34.5') + CALL FM_IBTA(M_A,M_B,M_C,MFM6) + CALL FM_EQ(MFM6,M_C) + M_D = TO_FM('5.8731980918960730463350151650813268739874201571164800M-27') + M_D = ABS((M_C - M_D)/M_D) + IF (.NOT.(M_D <= TO_FM('1.0E-49'))) THEN + CALL ERRPRT_FM(' IBTA ',M_A,'M_A',M_C,'M_C',M_D,'M_D', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 854 + M_A = TO_FM('8.115640517330775M-1') + M_B = TO_FM('2.00853601446773') + M_C = TO_FM('1.59735792202923') + CALL FM_IBTA(M_A,M_B,M_C,MFM6) + CALL FM_EQ(MFM6,M_C) + M_D = TO_FM('2.0112520048150164306467955877563719782378767062440103M-1') + M_D = ABS((M_C - M_D)/M_D) + IF (.NOT.(M_D <= TO_FM('1.0E-49'))) THEN + CALL ERRPRT_FM(' IBTA ',M_A,'M_A',M_C,'M_C',M_D,'M_D', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 855 + M_A = TO_FM('9.01737835258975M-1') + M_B = TO_FM('2.00853601446773') + M_C = TO_FM('1.59735792202923') + CALL FM_IBTA(M_A,M_B,M_C,MFM6) + CALL FM_EQ(MFM6,M_C) + M_D = TO_FM('2.2512248738228585976753517954889151150428002974819213M-1') + M_D = ABS((M_C - M_D)/M_D) + IF (.NOT.(M_D <= TO_FM('1.0E-49'))) THEN + CALL ERRPRT_FM(' IBTA ',M_A,'M_A',M_C,'M_C',M_D,'M_D', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 856 + M_A = TO_FM('9.6097615596216720E-01') + M_B = TO_FM('1.970425178583792') + M_C = TO_FM('5.5680052333367') + CALL FM_IBTA(M_A,M_B,M_C,MFM6) + CALL FM_EQ(MFM6,M_C) + M_D = TO_FM('2.8619456987740165364092968281459448023932520843535423M-2') + M_D = ABS((M_C - M_D)/M_D) + IF (.NOT.(M_D <= TO_FM('1.0E-49'))) THEN + CALL ERRPRT_FM(' IBTA ',M_A,'M_A',M_C,'M_C',M_D,'M_D', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 857 + M_A = TO_FM('4.764360371097952E-01') + M_B = TO_FM('1.161514683661584E+01') + M_C = TO_FM('2.937801562768354E-01') + CALL FM_IBTA(M_A,M_B,M_C,MFM6) + CALL FM_EQ(MFM6,M_C) + M_D = TO_FM('2.3604503996731113868791517339909092506365724801689105M-5') + M_D = ABS((M_C - M_D)/M_D) + IF (.NOT.(M_D <= TO_FM('1.0E-49'))) THEN + CALL ERRPRT_FM(' IBTA ',M_A,'M_A',M_C,'M_C',M_D,'M_D', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 858 + M_A = TO_FM('0.9') + M_B = TO_FM('23.4') + M_C = TO_FM('34.5') + CALL FM_IBTA(M_A,M_B,M_C,MFM6) + CALL FM_EQ(MFM6,M_C) + M_D = TO_FM('7.3148127865937299821246829407023943740949130742928268M-18') + M_D = ABS((M_C - M_D)/M_D) + IF (.NOT.(M_D <= TO_FM('1.0E-49'))) THEN + CALL ERRPRT_FM(' IBTA ',M_A,'M_A',M_C,'M_C',M_D,'M_D', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 859 + M_A = TO_FM('9.99496253868099M-1') + M_B = TO_FM('2.47067979368109M+6') + M_C = TO_FM('6.09475681774953M-100') + CALL FM_IBTA(M_A,M_B,M_C,MFM6) + CALL FM_EQ(MFM6,M_C) + M_D = TO_FM('1.7681753021411259894614747665450637683755190050365931M-544') + M_D = ABS((M_C - M_D)/M_D) + IF (.NOT.(M_D <= TO_FM('1.0E-49'))) THEN + CALL ERRPRT_FM(' IBTA ',M_A,'M_A',M_C,'M_C',M_D,'M_D', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 860 + M_A = TO_FM('6.213433771653724M-1') + M_B = TO_FM('8.854622686031200M-1') + M_C = TO_FM('5.00000854049816M-121') + CALL FM_IBTA(M_A,M_B,M_C,MFM6) + CALL FM_EQ(MFM6,M_C) + M_D = TO_FM('1.1281271573737080091147788530326864610276172049831497M+0') + M_D = ABS((M_C - M_D)/M_D) + IF (.NOT.(M_D <= TO_FM('1.0E-49'))) THEN + CALL ERRPRT_FM(' IBTA ',M_A,'M_A',M_C,'M_C',M_D,'M_D', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 861 + M_A = TO_FM('5.304391676698501M-15') + M_B = TO_FM('4.870186358377400M+2') + M_C = TO_FM('4.999955247889730M-98') + CALL FM_IBTA(M_A,M_B,M_C,MFM6) + CALL FM_EQ(MFM6,M_C) + M_D = TO_FM('8.7892314482956847896604128106803662527479433068750459M-6956') + M_D = ABS((M_C - M_D)/M_D) + IF (.NOT.(M_D <= TO_FM('1.0E-49'))) THEN + CALL ERRPRT_FM(' IBTA ',M_A,'M_A',M_C,'M_C',M_D,'M_D', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 862 + M_A = TO_FM('1.882803169800314M-7') + M_B = TO_FM('1.591547060066600M-169') + M_C = TO_FM('3.521822614438970M+6') + CALL FM_IBTA(M_A,M_B,M_C,MFM6) + CALL FM_EQ(MFM6,M_C) + M_D = TO_FM('6.2831946669434576663925763649227277100409122269443137M+168') + M_D = ABS((M_C - M_D)/M_D) + IF (.NOT.(M_D <= TO_FM('1.0E-49'))) THEN + CALL ERRPRT_FM(' IBTA ',M_A,'M_A',M_C,'M_C',M_D,'M_D', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 863 + M_A = TO_FM('.9999999999999') + M_B = TO_FM('8.591098092677430M+2') + M_C = TO_FM('1.863210949748253M+1') + CALL FM_IBTA(M_A,M_B,M_C,MFM6) + CALL FM_EQ(MFM6,M_C) + M_D = TO_FM('3.9062929191651064065641350979581425238442928803700306M-40') + M_D = ABS((M_C - M_D)/M_D) + IF (.NOT.(M_D <= TO_FM('1.0E-49'))) THEN + CALL ERRPRT_FM(' IBTA ',M_A,'M_A',M_C,'M_C',M_D,'M_D', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 864 + M_A = TO_FM('2.531772074701081M-99') + M_B = TO_FM('3.547571261801072M+2') + M_C = TO_FM('1.974896958876250M+6') + CALL FM_IBTA(M_A,M_B,M_C,MFM6) + CALL FM_EQ(MFM6,M_C) + M_D = TO_FM('4.0957237103166196693191012056689839835950377114705018M-34981') + M_D = ABS((M_C - M_D)/M_D) + IF (.NOT.(M_D <= TO_FM('1.0E-49'))) THEN + CALL ERRPRT_FM(' IBTA ',M_A,'M_A',M_C,'M_C',M_D,'M_D', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 865 + M_A = TO_FM('.99999999999999') + M_B = TO_FM('1.0E-123') + M_C = TO_FM('1.0E-134') + CALL FM_IBTA(M_A,M_B,M_C,MFM6) + CALL FM_EQ(MFM6,M_C) + M_D = TO_FM('1.0M+123') + M_D = ABS((M_C - M_D)/M_D) + IF (.NOT.(M_D <= TO_FM('1.0E-49'))) THEN + CALL ERRPRT_FM(' IBTA ',M_A,'M_A',M_C,'M_C',M_D,'M_D', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 866 + M_A = TO_FM('1') + M_B = TO_FM('2.65') + M_C = TO_FM('4.88') + CALL FM_IBTA(M_A,M_B,M_C,MFM6) + CALL FM_EQ(MFM6,M_C) + M_D = TO_FM('1.5020204575152306127604878970920601604169827852591720M-2') + M_D = ABS((M_C - M_D)/M_D) + IF (.NOT.(M_D <= TO_FM('1.0E-49'))) THEN + CALL ERRPRT_FM(' IBTA ',M_A,'M_A',M_C,'M_C',M_D,'M_D', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 867 + M_A = TO_FM('0') + M_B = TO_FM('2.65') + M_C = TO_FM('4.88') + CALL FM_IBTA(M_A,M_B,M_C,MFM6) + CALL FM_EQ(MFM6,M_C) + M_D = TO_FM('0') + M_D = ABS(M_C - M_D) + IF (.NOT.(M_D <= TO_FM('1.0E-49'))) THEN + CALL ERRPRT_FM(' IBTA ',M_A,'M_A',M_C,'M_C',M_D,'M_D', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 868 + M_A = TO_FM('.998') + M_B = TO_FM('759.6') + M_C = TO_FM('4.95e-57') + CALL FM_IBTA(M_A,M_B,M_C,MFM6) + CALL FM_EQ(MFM6,M_C) + M_D = TO_FM('9.7133692099062434492386763673434080317019087637060970M-2') + M_D = ABS((M_C - M_D)/M_D) + IF (.NOT.(M_D <= TO_FM('1.0E-49'))) THEN + CALL ERRPRT_FM(' IBTA ',M_A,'M_A',M_C,'M_C',M_D,'M_D', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 869 + M_A = TO_FM('4.764360371097952E-01') + M_B = TO_FM('1.161514683661584E+01') + M_C = TO_FM('2.937801562768354E-01') + M_C = INCOMPLETE_BETA(M_A,M_B,M_C) + M_D = TO_FM('2.3604503996731113868791517339909092506365724801689105M-5') + M_D = ABS((M_C - M_D)/M_D) + IF (.NOT.(M_D <= TO_FM('1.0E-49'))) THEN + CALL ERRPRT_FM(' IBTA ',M_A,'M_A',M_C,'M_C',M_D,'M_D', & + NCASE,NERROR,KLOG) + ENDIF + + RETURN + END SUBROUTINE TEST45 + + SUBROUTINE TEST46(NCASE,NERROR,KLOG) + +! Test the Polygamma, Psi functions. + + USE FMVALS + USE FMZM + USE TEST_VARS + + IMPLICIT NONE + + INTEGER KLOG,NCASE,NERROR + + WRITE (KW,"(/' Testing Polygamma, Psi.')") + + + NCASE = 870 + M_A = TO_FM('4.5') + CALL FM_PGAM(0,M_A,M_C) + M_D = TO_FM('1.3888709263595289015114046193821968137592213477205183M+0') + M_D = ABS((M_C - M_D)/M_D) + IF (.NOT.(M_D <= TO_FM('1.0E-49'))) THEN + CALL ERRPRT_FM(' PGAM ',M_A,'M_A',M_C,'M_C',M_D,'M_D', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 871 + M_A = TO_FM('1.0E-123') + CALL FM_PGAM(1,M_A,M_C) + M_D = TO_FM('1.0M+246') + M_D = ABS((M_C - M_D)/M_D) + IF (.NOT.(M_D <= TO_FM('1.0E-49'))) THEN + CALL ERRPRT_FM(' PGAM ',M_A,'M_A',M_C,'M_C',M_D,'M_D', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 872 + M_A = TO_FM('1.0E-123') + CALL FM_PGAM(2,M_A,M_C) + M_D = TO_FM('-2.0M+369') + M_D = ABS((M_C - M_D)/M_D) + IF (.NOT.(M_D <= TO_FM('1.0E-49'))) THEN + CALL ERRPRT_FM(' PGAM ',M_A,'M_A',M_C,'M_C',M_D,'M_D', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 873 + M_A = TO_FM('2.0706137739520290320140007735608464643737932737070189M-1') + CALL FM_PGAM(1,M_A,M_C) + M_D = TO_FM('2.4580954480899934124966756607870377560864828849100481M+1') + M_D = ABS((M_C - M_D)/M_D) + IF (.NOT.(M_D <= TO_FM('1.0E-49'))) THEN + CALL ERRPRT_FM(' PGAM ',M_A,'M_A',M_C,'M_C',M_D,'M_D', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 874 + M_A = TO_FM('2.0706137739520290320140007735608464643737932737070189M-1') + CALL FM_PGAM(6,M_A,M_C) + M_D = TO_FM('-4.4120531379423056741117517146346730469682094212273241M+7') + M_D = ABS((M_C - M_D)/M_D) + IF (.NOT.(M_D <= TO_FM('1.0E-49'))) THEN + CALL ERRPRT_FM(' PGAM ',M_A,'M_A',M_C,'M_C',M_D,'M_D', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 875 + M_A = TO_FM('2.0706137739520290320140007735608464643737932737070189M-1') + CALL FM_PGAM(23,M_A,M_C) + M_D = TO_FM('6.7006365293376930742991440911935017694098601683947073M+38') + M_D = ABS((M_C - M_D)/M_D) + IF (.NOT.(M_D <= TO_FM('1.0E-49'))) THEN + CALL ERRPRT_FM(' PGAM ',M_A,'M_A',M_C,'M_C',M_D,'M_D', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 876 + M_A = TO_FM('1.0E+123') + CALL FM_PGAM(4,M_A,M_C) + M_D = TO_FM('-6.0M-492') + M_D = ABS((M_C - M_D)/M_D) + IF (.NOT.(M_D <= TO_FM('1.0E-49'))) THEN + CALL ERRPRT_FM(' PGAM ',M_A,'M_A',M_C,'M_C',M_D,'M_D', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 877 + M_A = TO_FM('-6.499999840238790109') + CALL FM_PGAM(4,M_A,M_C) + M_D = TO_FM('1.0135142464863270830609416082237513111216512170936928M-16') + M_D = ABS((M_C - M_D)/M_D) + IF (.NOT.(M_D <= TO_FM('1.0E-49'))) THEN + CALL ERRPRT_FM(' PGAM ',M_A,'M_A',M_C,'M_C',M_D,'M_D', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 878 + M_C = POLYGAMMA(2,TO_FM('1.0E-123')) + M_D = TO_FM('-2.0M+369') + M_D = ABS((M_C - M_D)/M_D) + IF (.NOT.(M_D <= TO_FM('1.0E-49'))) THEN + CALL ERRPRT_FM(' PGAM ',M_A,'M_A',M_C,'M_C',M_D,'M_D', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 879 + M_A = TO_FM('1.0E-135') + CALL FM_PSI(M_A,M_C) + M_D = TO_FM('-1.0M+135') + M_D = ABS((M_C - M_D)/M_D) + IF (.NOT.(M_D <= TO_FM('1.0E-49'))) THEN + CALL ERRPRT_FM(' PSI ',M_A,'M_A',M_C,'M_C',M_D,'M_D', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 880 + M_A = TO_FM('1.2') + CALL FM_PSI(M_A,M_C) + M_D = TO_FM('-2.8903989659218829554720796244995210482558827420664281M-1') + M_D = ABS((M_C - M_D)/M_D) + IF (.NOT.(M_D <= TO_FM('1.0E-49'))) THEN + CALL ERRPRT_FM(' PSI ',M_A,'M_A',M_C,'M_C',M_D,'M_D', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 881 + M_A = TO_FM('-3.4') + CALL FM_PSI(M_A,M_C) + M_D = TO_FM('2.3844508141180140670320531380285019520468887144980679M+0') + M_D = ABS((M_C - M_D)/M_D) + IF (.NOT.(M_D <= TO_FM('1.0E-49'))) THEN + CALL ERRPRT_FM(' PSI ',M_A,'M_A',M_C,'M_C',M_D,'M_D', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 882 + M_A = TO_FM('57') + CALL FM_PSI(M_A,M_C) + M_D = TO_FM('4.0342536898816977739559850955847848905386809772893269M+0') + M_D = ABS((M_C - M_D)/M_D) + IF (.NOT.(M_D <= TO_FM('1.0E-49'))) THEN + CALL ERRPRT_FM(' PSI ',M_A,'M_A',M_C,'M_C',M_D,'M_D', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 883 + M_A = TO_FM('1.0E+56') + CALL FM_PSI(M_A,M_C) + M_D = TO_FM('1.2894476520766655830500752146232439562566168336321129M+2') + M_D = ABS((M_C - M_D)/M_D) + IF (.NOT.(M_D <= TO_FM('1.0E-49'))) THEN + CALL ERRPRT_FM(' PSI ',M_A,'M_A',M_C,'M_C',M_D,'M_D', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 884 + M_A = TO_FM('1.0') + CALL FM_PSI(M_A,M_C) + M_D = TO_FM('-5.7721566490153286060651209008240243104215933593992360M-1') + M_D = ABS((M_C - M_D)/M_D) + IF (.NOT.(M_D <= TO_FM('1.0E-49'))) THEN + CALL ERRPRT_FM(' PSI ',M_A,'M_A',M_C,'M_C',M_D,'M_D', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 885 + M_A = TO_FM('1.0E+23456') + CALL FM_PSI(M_A,M_C) + M_D = TO_FM('5.4009435941268335564326007561076446853491436517276499M+4') + M_D = ABS((M_C - M_D)/M_D) + IF (.NOT.(M_D <= TO_FM('1.0E-49'))) THEN + CALL ERRPRT_FM(' PSI ',M_A,'M_A',M_C,'M_C',M_D,'M_D', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 886 + M_A = TO_FM('1.46163214496836234126266') + CALL FM_PSI(M_A,M_C) + M_D = TO_FM('4.4287869692570149446165609601581442013784186419176534M-25') + M_D = ABS((M_C - M_D)/M_D) + IF (.NOT.(M_D <= TO_FM('1.0E-49'))) THEN + CALL ERRPRT_FM(' PSI ',M_A,'M_A',M_C,'M_C',M_D,'M_D', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 887 + M_C = PSI(TO_FM('1.2')) + M_D = TO_FM('-2.8903989659218829554720796244995210482558827420664281M-1') + M_D = ABS((M_C - M_D)/M_D) + IF (.NOT.(M_D <= TO_FM('1.0E-49'))) THEN + CALL ERRPRT_FM(' PSI ',M_A,'M_A',M_C,'M_C',M_D,'M_D', & + NCASE,NERROR,KLOG) + ENDIF + + RETURN + END SUBROUTINE TEST46 + + SUBROUTINE TEST47(NCASE,NERROR,KLOG) + +! Test the different rounding modes. + + USE FMVALS + USE FMZM + USE TEST_VARS + + IMPLICIT NONE + + INTEGER KLOG,NCASE,NERROR + INTEGER SEED(7) + + WRITE (KW,"(/' Testing the different rounding modes.')") + + + CALL FMSETVAR(' MBASE = 10 ') + CALL FMSETVAR(' NDIG = 20 ') + M_A = 0 + + NCASE = 888 + CALL FMSETVAR(' KROUND = 1 ') + M_C = TO_FM('2')/TO_FM('3') + M_D = TO_FM('.66666666666666666667') + IF (.NOT.(M_D == M_C)) THEN + CALL ERRPRT_FM(' Round',M_A,'M_A',M_C,'M_C',M_D,'M_D', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 889 + CALL FMSETVAR(' KROUND = -1 ') + M_C = TO_FM('2')/TO_FM('3') + M_D = TO_FM('.66666666666666666666') + IF (.NOT.(M_D == M_C)) THEN + CALL ERRPRT_FM(' Round',M_A,'M_A',M_C,'M_C',M_D,'M_D', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 890 + CALL FMSETVAR(' KROUND = 0 ') + M_C = TO_FM('2')/TO_FM('3') + M_D = TO_FM('.66666666666666666666') + IF (.NOT.(M_D == M_C)) THEN + CALL ERRPRT_FM(' Round',M_A,'M_A',M_C,'M_C',M_D,'M_D', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 891 + CALL FMSETVAR(' KROUND = 2 ') + M_C = TO_FM('2')/TO_FM('3') + M_D = TO_FM('.66666666666666666667') + IF (.NOT.(M_D == M_C)) THEN + CALL ERRPRT_FM(' Round',M_A,'M_A',M_C,'M_C',M_D,'M_D', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 892 + CALL FMSETVAR(' KROUND = 1 ') + M_C = TO_FM('1')/TO_FM('3') + M_D = TO_FM('.33333333333333333333') + IF (.NOT.(M_D == M_C)) THEN + CALL ERRPRT_FM(' Round',M_A,'M_A',M_C,'M_C',M_D,'M_D', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 893 + CALL FMSETVAR(' KROUND = -1 ') + M_C = TO_FM('1')/TO_FM('3') + M_D = TO_FM('.33333333333333333333') + IF (.NOT.(M_D == M_C)) THEN + CALL ERRPRT_FM(' Round',M_A,'M_A',M_C,'M_C',M_D,'M_D', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 894 + CALL FMSETVAR(' KROUND = 0 ') + M_C = TO_FM('1')/TO_FM('3') + M_D = TO_FM('.33333333333333333333') + IF (.NOT.(M_D == M_C)) THEN + CALL ERRPRT_FM(' Round',M_A,'M_A',M_C,'M_C',M_D,'M_D', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 895 + CALL FMSETVAR(' KROUND = 2 ') + M_C = TO_FM('1')/TO_FM('3') + M_D = TO_FM('.33333333333333333334') + IF (.NOT.(M_D == M_C)) THEN + CALL ERRPRT_FM(' Round',M_A,'M_A',M_C,'M_C',M_D,'M_D', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 896 + CALL FMSETVAR(' KROUND = 1 ') + M_C = TO_FM('-1')/TO_FM('3') + M_D = TO_FM('-.33333333333333333333') + IF (.NOT.(M_D == M_C)) THEN + CALL ERRPRT_FM(' Round',M_A,'M_A',M_C,'M_C',M_D,'M_D', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 897 + CALL FMSETVAR(' KROUND = -1 ') + M_C = TO_FM('-1')/TO_FM('3') + M_D = TO_FM('-.33333333333333333334') + IF (.NOT.(M_D == M_C)) THEN + CALL ERRPRT_FM(' Round',M_A,'M_A',M_C,'M_C',M_D,'M_D', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 898 + CALL FMSETVAR(' KROUND = 0 ') + M_C = TO_FM('-1')/TO_FM('3') + M_D = TO_FM('-.33333333333333333333') + IF (.NOT.(M_D == M_C)) THEN + CALL ERRPRT_FM(' Round',M_A,'M_A',M_C,'M_C',M_D,'M_D', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 899 + CALL FMSETVAR(' KROUND = 2 ') + M_C = TO_FM('-1')/TO_FM('3') + M_D = TO_FM('-.33333333333333333333') + IF (.NOT.(M_D == M_C)) THEN + CALL ERRPRT_FM(' Round',M_A,'M_A',M_C,'M_C',M_D,'M_D', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 900 + CALL FMSETVAR(' KROUND = 1 ') + M_C = TO_FM('-2')/TO_FM('3') + M_D = TO_FM('-.66666666666666666667') + IF (.NOT.(M_D == M_C)) THEN + CALL ERRPRT_FM(' Round',M_A,'M_A',M_C,'M_C',M_D,'M_D', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 901 + CALL FMSETVAR(' KROUND = -1 ') + M_C = TO_FM('-2')/TO_FM('3') + M_D = TO_FM('-.66666666666666666667') + IF (.NOT.(M_D == M_C)) THEN + CALL ERRPRT_FM(' Round',M_A,'M_A',M_C,'M_C',M_D,'M_D', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 902 + CALL FMSETVAR(' KROUND = 0 ') + M_C = TO_FM('-2')/TO_FM('3') + M_D = TO_FM('-.66666666666666666666') + IF (.NOT.(M_D == M_C)) THEN + CALL ERRPRT_FM(' Round',M_A,'M_A',M_C,'M_C',M_D,'M_D', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 903 + CALL FMSETVAR(' KROUND = 2 ') + M_C = TO_FM('-2')/TO_FM('3') + M_D = TO_FM('-.66666666666666666666') + IF (.NOT.(M_D == M_C)) THEN + CALL ERRPRT_FM(' Round',M_A,'M_A',M_C,'M_C',M_D,'M_D', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 904 + CALL FMSETVAR(' KROUND = 1 ') + M_C = TO_FM('1') + TO_FM('3E-555') + M_D = TO_FM('1.0000000000000000000') + IF (.NOT.(M_D == M_C)) THEN + CALL ERRPRT_FM(' Round',M_A,'M_A',M_C,'M_C',M_D,'M_D', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 905 + CALL FMSETVAR(' KROUND = -1 ') + M_C = TO_FM('1') + TO_FM('3E-555') + M_D = TO_FM('1.0000000000000000000') + IF (.NOT.(M_D == M_C)) THEN + CALL ERRPRT_FM(' Round',M_A,'M_A',M_C,'M_C',M_D,'M_D', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 906 + CALL FMSETVAR(' KROUND = 0 ') + M_C = TO_FM('1') + TO_FM('3E-555') + M_D = TO_FM('1.0000000000000000000') + IF (.NOT.(M_D == M_C)) THEN + CALL ERRPRT_FM(' Round',M_A,'M_A',M_C,'M_C',M_D,'M_D', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 907 + CALL FMSETVAR(' KROUND = 2 ') + M_C = TO_FM('1') + TO_FM('3E-555') + M_D = TO_FM('1.0000000000000000001') + IF (.NOT.(M_D == M_C)) THEN + CALL ERRPRT_FM(' Round',M_A,'M_A',M_C,'M_C',M_D,'M_D', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 908 + CALL FMSETVAR(' KROUND = 1 ') + M_C = TO_FM('1') - TO_FM('3E-555') + M_D = TO_FM('1.0000000000000000000') + IF (.NOT.(M_D == M_C)) THEN + CALL ERRPRT_FM(' Round',M_A,'M_A',M_C,'M_C',M_D,'M_D', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 909 + CALL FMSETVAR(' KROUND = -1 ') + M_C = TO_FM('1') - TO_FM('3E-555') + M_D = TO_FM('.99999999999999999999') + IF (.NOT.(M_D == M_C)) THEN + CALL ERRPRT_FM(' Round',M_A,'M_A',M_C,'M_C',M_D,'M_D', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 910 + CALL FMSETVAR(' KROUND = 0 ') + M_C = TO_FM('1') - TO_FM('3E-555') + M_D = TO_FM('.99999999999999999999') + IF (.NOT.(M_D == M_C)) THEN + CALL ERRPRT_FM(' Round',M_A,'M_A',M_C,'M_C',M_D,'M_D', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 911 + CALL FMSETVAR(' KROUND = 2 ') + M_C = TO_FM('1') - TO_FM('3E-555') + M_D = TO_FM('1.0000000000000000000') + IF (.NOT.(M_D == M_C)) THEN + CALL ERRPRT_FM(' Round',M_A,'M_A',M_C,'M_C',M_D,'M_D', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 912 + CALL FMSETVAR(' KROUND = 1 ') + M_C = TO_FM('-1') + TO_FM('3E-555') + M_D = TO_FM('-1.0000000000000000000') + IF (.NOT.(M_D == M_C)) THEN + CALL ERRPRT_FM(' Round',M_A,'M_A',M_C,'M_C',M_D,'M_D', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 913 + CALL FMSETVAR(' KROUND = -1 ') + M_C = TO_FM('-1') + TO_FM('3E-555') + M_D = TO_FM('-1.0000000000000000000') + IF (.NOT.(M_D == M_C)) THEN + CALL ERRPRT_FM(' Round',M_A,'M_A',M_C,'M_C',M_D,'M_D', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 914 + CALL FMSETVAR(' KROUND = 0 ') + M_C = TO_FM('-1') + TO_FM('3E-555') + M_D = TO_FM('-.99999999999999999999') + IF (.NOT.(M_D == M_C)) THEN + CALL ERRPRT_FM(' Round',M_A,'M_A',M_C,'M_C',M_D,'M_D', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 915 + CALL FMSETVAR(' KROUND = 2 ') + M_C = TO_FM('-1') + TO_FM('3E-555') + M_D = TO_FM('-.99999999999999999999') + IF (.NOT.(M_D == M_C)) THEN + CALL ERRPRT_FM(' Round',M_A,'M_A',M_C,'M_C',M_D,'M_D', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 916 + CALL FMSETVAR(' KROUND = 1 ') + M_C = TO_FM('-1') - TO_FM('3E-555') + M_D = TO_FM('-1.0000000000000000000') + IF (.NOT.(M_D == M_C)) THEN + CALL ERRPRT_FM(' Round',M_A,'M_A',M_C,'M_C',M_D,'M_D', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 917 + CALL FMSETVAR(' KROUND = -1 ') + M_C = TO_FM('-1') - TO_FM('3E-555') + M_D = TO_FM('-1.0000000000000000001') + IF (.NOT.(M_D == M_C)) THEN + CALL ERRPRT_FM(' Round',M_A,'M_A',M_C,'M_C',M_D,'M_D', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 918 + CALL FMSETVAR(' KROUND = 0 ') + M_C = TO_FM('-1') - TO_FM('3E-555') + M_D = TO_FM('-1.0000000000000000000') + IF (.NOT.(M_D == M_C)) THEN + CALL ERRPRT_FM(' Round',M_A,'M_A',M_C,'M_C',M_D,'M_D', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 919 + CALL FMSETVAR(' KROUND = 2 ') + M_C = TO_FM('-1') - TO_FM('3E-555') + M_D = TO_FM('-1.0000000000000000000') + IF (.NOT.(M_D == M_C)) THEN + CALL ERRPRT_FM(' Round',M_A,'M_A',M_C,'M_C',M_D,'M_D', & + NCASE,NERROR,KLOG) + ENDIF + + CALL FMSETVAR(' MBASE = 2 ') + CALL FMSETVAR(' NDIG = 53 ') + NCASE = 920 + M_A = TO_FM('0.125') + M_B = TO_FM('23.25') + M_C = TO_FM('34.5') + CALL FM_IBTA(M_A,M_B,M_C,MFM6) + CALL FM_EQ(MFM6,M_C) + M_D = TO_FM('6.1345805065305141873M-25') + M_D = ABS((M_C - M_D)/M_D) + IF (.NOT.(M_D <= TO_FM('1.0E-15'))) THEN + CALL ERRPRT_FM(' IBTA ',M_A,'M_A',M_C,'M_C',M_D,'M_D', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 921 + M_A = TO_FM('0.52') + M_B = TO_FM('2.01') + M_C = TO_FM('1.6') + CALL FM_IBTA(M_A,M_B,M_C,MFM6) + CALL FM_EQ(MFM6,M_C) + M_D = TO_FM('1.0304844627978347604M-1') + M_D = ABS((M_C - M_D)/M_D) + IF (.NOT.(M_D <= TO_FM('1.0E-15'))) THEN + CALL ERRPRT_FM(' IBTA ',M_A,'M_A',M_C,'M_C',M_D,'M_D', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 922 + M_A = TO_FM('9.01737835258975M-1') + M_B = TO_FM('2.00853601446773') + M_C = TO_FM('1.59735792202923') + CALL FM_IBTA(M_A,M_B,M_C,MFM6) + CALL FM_EQ(MFM6,M_C) + M_D = TO_FM('2.2512248738228585986M-1') + M_D = ABS((M_C - M_D)/M_D) + IF (.NOT.(M_D <= TO_FM('1.0E-15'))) THEN + CALL ERRPRT_FM(' IBTA ',M_A,'M_A',M_C,'M_C',M_D,'M_D', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 923 + M_A = TO_FM('9.6097615596216720E-01') + M_B = TO_FM('1.970425178583792') + M_C = TO_FM('5.5680052333367') + CALL FM_IBTA(M_A,M_B,M_C,MFM6) + CALL FM_EQ(MFM6,M_C) + M_D = TO_FM('2.8619456987740165927M-2') + M_D = ABS((M_C - M_D)/M_D) + IF (.NOT.(M_D <= TO_FM('1.0E-15'))) THEN + CALL ERRPRT_FM(' IBTA ',M_A,'M_A',M_C,'M_C',M_D,'M_D', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 924 + M_A = TO_FM('4.764360371097952E-01') + M_B = TO_FM('1.161514683661584E+01') + M_C = TO_FM('2.937801562768354E-01') + CALL FM_IBTA(M_A,M_B,M_C,MFM6) + CALL FM_EQ(MFM6,M_C) + M_D = TO_FM('2.3604503996731113869M-5') + M_D = ABS((M_C - M_D)/M_D) + IF (.NOT.(M_D <= TO_FM('1.0E-15'))) THEN + CALL ERRPRT_FM(' IBTA ',M_A,'M_A',M_C,'M_C',M_D,'M_D', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 925 + M_A = TO_FM('0.9') + M_B = TO_FM('23.4') + M_C = TO_FM('34.5') + CALL FM_IBTA(M_A,M_B,M_C,MFM6) + CALL FM_EQ(MFM6,M_C) + M_D = TO_FM('7.3148127865937395334M-18') + M_D = ABS((M_C - M_D)/M_D) + IF (.NOT.(M_D <= TO_FM('1.0E-15'))) THEN + CALL ERRPRT_FM(' IBTA ',M_A,'M_A',M_C,'M_C',M_D,'M_D', & + NCASE,NERROR,KLOG) + ENDIF + + CALL FMSETVAR(' MBASE = 3 ') + CALL FMSETVAR(' NDIG = 55 ') + NCASE = 926 + M_A = TO_FM('0.1') + M_B = TO_FM('23.4') + M_C = TO_FM('34.5') + CALL FM_IBTA(M_A,M_B,M_C,MFM6) + CALL FM_EQ(MFM6,M_C) + M_D = TO_FM('5.87319809189607304633501593392681M-27') + M_D = ABS((M_C - M_D)/M_D) + IF (.NOT.(M_D <= TO_FM('1.0E-25'))) THEN + CALL ERRPRT_FM(' IBTA ',M_A,'M_A',M_C,'M_C',M_D,'M_D', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 927 + M_A = TO_FM('0.52') + M_B = TO_FM('2.1') + M_C = TO_FM('1.6') + CALL FM_IBTA(M_A,M_B,M_C,MFM6) + CALL FM_EQ(MFM6,M_C) + M_D = TO_FM('9.25745341552810210762563659429375M-2') + M_D = ABS((M_C - M_D)/M_D) + IF (.NOT.(M_D <= TO_FM('1.0E-25'))) THEN + CALL ERRPRT_FM(' IBTA ',M_A,'M_A',M_C,'M_C',M_D,'M_D', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 928 + M_A = TO_FM('9.01737835258975M-1') + M_B = TO_FM('2.00853601446773') + M_C = TO_FM('1.59735792202923') + CALL FM_IBTA(M_A,M_B,M_C,MFM6) + CALL FM_EQ(MFM6,M_C) + M_D = TO_FM('2.25122487382285859767535178829535M-1') + M_D = ABS((M_C - M_D)/M_D) + IF (.NOT.(M_D <= TO_FM('1.0E-25'))) THEN + CALL ERRPRT_FM(' IBTA ',M_A,'M_A',M_C,'M_C',M_D,'M_D', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 929 + M_A = TO_FM('9.6097615596216720E-01') + M_B = TO_FM('1.970425178583792') + M_C = TO_FM('5.5680052333367') + CALL FM_IBTA(M_A,M_B,M_C,MFM6) + CALL FM_EQ(MFM6,M_C) + M_D = TO_FM('2.861945698774016536409296855493M-2') + M_D = ABS((M_C - M_D)/M_D) + IF (.NOT.(M_D <= TO_FM('1.0E-25'))) THEN + CALL ERRPRT_FM(' IBTA ',M_A,'M_A',M_C,'M_C',M_D,'M_D', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 930 + M_A = TO_FM('4.764360371097952E-01') + M_B = TO_FM('1.161514683661584E+01') + M_C = TO_FM('2.937801562768354E-01') + CALL FM_IBTA(M_A,M_B,M_C,MFM6) + CALL FM_EQ(MFM6,M_C) + M_D = TO_FM('2.36045039967311138687915158221269M-5') + M_D = ABS((M_C - M_D)/M_D) + IF (.NOT.(M_D <= TO_FM('1.0E-25'))) THEN + CALL ERRPRT_FM(' IBTA ',M_A,'M_A',M_C,'M_C',M_D,'M_D', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 931 + M_A = TO_FM('0.9') + M_B = TO_FM('23.4') + M_C = TO_FM('34.5') + CALL FM_IBTA(M_A,M_B,M_C,MFM6) + CALL FM_EQ(MFM6,M_C) + M_D = TO_FM('7.31481278659372998212468424608367M-18') + M_D = ABS((M_C - M_D)/M_D) + IF (.NOT.(M_D <= TO_FM('1.0E-25'))) THEN + CALL ERRPRT_FM(' IBTA ',M_A,'M_A',M_C,'M_C',M_D,'M_D', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 932 + CALL FPST2M('1.67',MP1) + CALL FPST2M('2.64',MP2) + CALL FPADD(MP1,MP2,MP3) + CALL FPEQ(MP3,MP1) + CALL FPST2M('-3.91',MP2) + CALL FPSUB(MP1,MP2,MP3) + CALL FPEQ(MP3,MP1) + CALL FPST2M('4.58',MP2) + CALL FPMPY(MP1,MP2,MP3) + CALL FPEQ(MP3,MP1) + CALL FPST2M('0.27',MP2) + CALL FPDIV(MP1,MP2,MP3) + CALL FPEQ(MP3,MP1) + CALL FPADDI(MP1,2) + CALL FPMPYI(MP1,13,MP3) + CALL FPEQ(MP3,MP1) + CALL FPDIVI(MP1,11,MP3) + CALL FPEQ(MP3,MP1) + CALL FPLN(MP1,MP3) + CALL FPEQ(MP3,MP1) + CALL FPSIN(MP1,MP3) + CALL FPEQ(MP3,MP1) + CALL FPCOS(MP1,MP3) + CALL FPEQ(MP3,MP1) + CALL FPEXP(MP1,MP3) + CALL FPEQ(MP3,MP1) + CALL FPGAM(MP1,MP3) + CALL FPEQ(MP3,MP1) + CALL FMUNPK(MP1,M_C%MFM) + M_D = TO_FM('0.941122001974472326543759839200398') + M_D = ABS((M_C - M_D)/M_D) + IF (.NOT.(M_D <= TO_FM('1.0E-25'))) THEN + CALL ERRPRT_FM(' Pack ',M_C,'M_C',M_C,'M_C',M_D,'M_D', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 933 + SEED = (/ 2718281,8284590,4523536,0287471,3526624,9775724,7093699 /) + CALL FM_RANDOM_SEED(PUT=SEED) + DO J1 = 1, 10 + CALL FM_RANDOM_NUMBER(D1) + ENDDO + M_C = D1 + M_D = TO_FM('0.945608442536777') + M_D = ABS((M_C - M_D)/M_D) + IF (.NOT.(M_D <= TO_FM('1.0E-10'))) THEN + CALL ERRPRT_FM(' Rand ',M_C,'M_C',M_C,'M_C',M_D,'M_D', & + NCASE,NERROR,KLOG) + ENDIF + + CALL FMSETVAR(' MBASE = 10000 ') + CALL FMSETVAR(' NDIG = 5 ') + + NCASE = 934 + CALL FMSETVAR(' KROUND = 1 ') + CALL FMSETVAR(' KRPERF = 1 ') + M_C = SQRT( TO_FM('.49841718043038996023') ) + M_D = TO_FM('.70598667156709832621') + IF (.NOT.(M_D == M_C)) THEN + CALL ERRPRT_FM(' Round',M_A,'M_A',M_C,'M_C',M_D,'M_D', & + NCASE,NERROR,KLOG) + ENDIF + + NCASE = 935 + CALL FMSETVAR(' KROUND = 1 ') + CALL FMSETVAR(' KRPERF = 0 ') + M_C = SQRT( TO_FM('.49841718043038996023') ) + M_D = TO_FM('.70598667156709832622') + IF (.NOT.(M_D == M_C)) THEN + CALL ERRPRT_FM(' Round',M_A,'M_A',M_C,'M_C',M_D,'M_D', & + NCASE,NERROR,KLOG) + ENDIF + + RETURN + END SUBROUTINE TEST47 + + SUBROUTINE ERRPRTFM(NROUT,M1,NAME1,M2,NAME2,M3,NAME3, & + NCASE,NERROR,KLOG) + +! Print error messages for testing of real (FM) routines. + +! M1 is the value to be tested, as computed by the routine named NROUT. +! M2 is the reference value, usually converted using FMST2M. +! M3 is ABS(M1-M2), and ERRPRT is called if this is too big. +! NAME1,NAME2,NAME3 are strings identifying which variables in the +! calling routine correspond to M1,M2,M3. + + USE FMVALS + USE FMZM + USE TEST_VARS + + IMPLICIT NONE + + REAL (KIND(1.0D0)) :: M1(-1:LUNPCK),M2(-1:LUNPCK),M3(-1:LUNPCK) + + CHARACTER(2) :: NAME1,NAME2,NAME3 + CHARACTER(6) :: NROUT + INTEGER KLOG,KWSAVE,NCASE,NERROR + + NERROR = NERROR + 1 + WRITE (KW, & + "(//' Error in case',I4,'. The routine',' being tested was ',A6)" & + ) NCASE,NROUT + WRITE (KLOG, & + "(//' Error in case',I4,'. The routine',' being tested was ',A6)" & + ) NCASE,NROUT + +! Temporarily change KW to KLOG so FMPRNT +! will write to the log file. + + KWSAVE = KW + KW = KLOG + WRITE (KLOG,"(1X,A,' =')") NAME1 + CALL FMPRNT(M1) + WRITE (KLOG,"(1X,A,' =')") NAME2 + CALL FMPRNT(M2) + WRITE (KLOG,"(1X,A,' =')") NAME3 + CALL FMPRNT(M3) + KW = KWSAVE + RETURN + END SUBROUTINE ERRPRTFM + + SUBROUTINE ERRPRTIM(NROUT,M1,NAME1,M2,NAME2, & + NCASE,NERROR,KLOG) + +! Print error messages for testing of integer (IM) routines. + +! M1 is the value to be tested, as computed by the routine named NROUT. +! M2 is the reference value, usually converted using IMST2M. +! NAME1,NAME2 are strings identifying which variables in the calling routine +! correspond to M1,M2. + + USE FMVALS + USE FMZM + USE TEST_VARS + + IMPLICIT NONE + + REAL (KIND(1.0D0)) :: M1(-1:LUNPCK),M2(-1:LUNPCK) + + CHARACTER(2) :: NAME1,NAME2 + CHARACTER(6) :: NROUT + INTEGER KLOG,KWSAVE,NCASE,NERROR + + NERROR = NERROR + 1 + WRITE (KW, & + "(//' Error in case',I4,'. The routine',' being tested was ',A6)" & + ) NCASE,NROUT + WRITE (KLOG, & + "(//' Error in case',I4,'. The routine',' being tested was ',A6)" & + ) NCASE,NROUT + +! Temporarily change KW to KLOG so IMPRNT +! will write to the log file. + + KWSAVE = KW + KW = KLOG + WRITE (KLOG,"(1X,A,' =')") NAME1 + CALL IMPRNT(M1) + WRITE (KLOG,"(1X,A,' =')") NAME2 + CALL IMPRNT(M2) + KW = KWSAVE + END SUBROUTINE ERRPRTIM + + SUBROUTINE ERRPRTZM(NROUT,M1,NAME1,M2,NAME2,M3,NAME3, & + NCASE,NERROR,KLOG) + +! Print error messages. + +! M1 is the value to be tested, as computed by the routine named NROUT. +! M2 is the reference value, usually converted using ZMST2M. +! M3 is ABS(M1-M2), and ERRPRTZM is called if this is too big. +! NAME1,NAME2,NAME3 are strings identifying which variables in the +! calling routine correspond to M1,M2,M3. + + USE FMVALS + USE FMZM + USE TEST_VARS + + IMPLICIT NONE + + REAL (KIND(1.0D0)) :: M1(-1:LUNPKZ),M2(-1:LUNPKZ),M3(-1:LUNPKZ) + + CHARACTER(2) :: NAME1,NAME2,NAME3 + CHARACTER(6) :: NROUT + INTEGER KLOG,KWSAVE,NCASE,NERROR + + NERROR = NERROR + 1 + WRITE (KW, & + "(//' Error in case',I4,'. The routine',' being tested was ',A6)" & + ) NCASE,NROUT + WRITE (KLOG, & + "(//' Error in case',I4,'. The routine',' being tested was ',A6)" & + ) NCASE,NROUT + +! Temporarily change KW to KLOG so ZMPRNT +! will write to the log file. + + KWSAVE = KW + KW = KLOG + WRITE (KLOG,"(1X,A,' =')") NAME1 + CALL ZMPRNT(M1) + WRITE (KLOG,"(1X,A,' =')") NAME2 + CALL ZMPRNT(M2) + WRITE (KLOG,"(1X,A,' =')") NAME3 + CALL ZMPRNT(M3) + KW = KWSAVE + END SUBROUTINE ERRPRTZM + + SUBROUTINE ERRPRT_FM(NROUT,M1,NAME1,M2,NAME2,M3,NAME3, & + NCASE,NERROR,KLOG) + +! Print error messages for testing of TYPE (FM) interface routines. + +! M1 is the value to be tested, as computed by the routine named NROUT. +! M2 is the reference value, usually converted using FMST2M. +! M3 is ABS(M1-M2), and ERRPRT_FM is called if this is too big. +! NAME1,NAME2,NAME3 are strings identifying which variables in the +! calling routine correspond to M1,M2,M3. + + USE FMVALS + USE FMZM + USE TEST_VARS + + IMPLICIT NONE + + TYPE (FM) M1,M2,M3 + + CHARACTER(3) :: NAME1,NAME2,NAME3 + CHARACTER(6) :: NROUT + INTEGER KLOG,KWSAVE,NCASE,NERROR + + NERROR = NERROR + 1 + WRITE (KW, & + "(//' Error in case',I4,'. The interface',' being tested was ',A6)" & + ) NCASE,NROUT + WRITE (KLOG, & + "(//' Error in case',I4,'. The interface',' being tested was ',A6)" & + ) NCASE,NROUT + +! Temporarily change KW to KLOG so FMPRNT +! will write to the log file. + + KWSAVE = KW + KW = KLOG + WRITE (KLOG,"(1X,A,' =')") NAME1 + CALL FM_PRNT(M1) + WRITE (KLOG,"(1X,A,' =')") NAME2 + CALL FM_PRNT(M2) + WRITE (KLOG,"(1X,A,' =')") NAME3 + CALL FM_PRNT(M3) + KW = KWSAVE + END SUBROUTINE ERRPRT_FM + + SUBROUTINE ERRPRT_IM(NROUT,M1,NAME1,M2,NAME2, & + NCASE,NERROR,KLOG) + +! Print error messages for testing of TYPE (IM) interface routines. + +! M1 is the value to be tested, as computed by the routine named NROUT. +! M2 is the reference value, usually converted using IMST2M. +! NAME1,NAME2 are strings identifying which variables in the calling routine +! correspond to M1,M2. + + USE FMVALS + USE FMZM + USE TEST_VARS + + IMPLICIT NONE + + TYPE (IM) M1,M2 + + CHARACTER(3) :: NAME1,NAME2 + CHARACTER(6) :: NROUT + INTEGER KLOG,KWSAVE,NCASE,NERROR + + NERROR = NERROR + 1 + WRITE (KW, & + "(//' Error in case',I4,'. The interface',' being tested was ',A6)" & + ) NCASE,NROUT + WRITE (KLOG, & + "(//' Error in case',I4,'. The interface',' being tested was ',A6)" & + ) NCASE,NROUT + +! Temporarily change KW to KLOG so IMPRNT +! will write to the log file. + + KWSAVE = KW + KW = KLOG + WRITE (KLOG,"(1X,A,' =')") NAME1 + CALL IM_PRNT(M1) + WRITE (KLOG,"(1X,A,' =')") NAME2 + CALL IM_PRNT(M2) + KW = KWSAVE + END SUBROUTINE ERRPRT_IM + + SUBROUTINE ERRPRT_ZM(NROUT,M1,NAME1,M2,NAME2,M3,NAME3, & + NCASE,NERROR,KLOG) + +! Print error messages for testing of TYPE (ZM) interface routines. + +! M1 is the value to be tested, as computed by the routine named NROUT. +! M2 is the reference value, usually converted using ZMST2M. +! M3 is ABS(M1-M2), and ERRPRT_ZM is called if this is too big. +! NAME1,NAME2,NAME3 are strings identifying which variables in the calling routine +! correspond to M1,M2,M3. + + USE FMVALS + USE FMZM + USE TEST_VARS + + IMPLICIT NONE + + TYPE (ZM) M1,M2,M3 + + CHARACTER(3) :: NAME1,NAME2,NAME3 + CHARACTER(6) :: NROUT + INTEGER KLOG,KWSAVE,NCASE,NERROR + + NERROR = NERROR + 1 + WRITE (KW, & + "(//' Error in case',I4,'. The interface',' being tested was ',A6)" & + ) NCASE,NROUT + WRITE (KLOG, & + "(//' Error in case',I4,'. The interface',' being tested was ',A6)" & + ) NCASE,NROUT + +! Temporarily change KW to KLOG so ZMPRNT +! will write to the log file. + + KWSAVE = KW + KW = KLOG + WRITE (KLOG,"(1X,A,' =')") NAME1 + CALL ZM_PRNT(M1) + WRITE (KLOG,"(1X,A,' =')") NAME2 + CALL ZM_PRNT(M2) + WRITE (KLOG,"(1X,A,' =')") NAME3 + CALL ZM_PRNT(M3) + KW = KWSAVE + END SUBROUTINE ERRPRT_ZM + + SUBROUTINE PRTERR(KW,KLOG,NCASE,NERROR) + IMPLICIT NONE + INTEGER KW,KLOG,NCASE,NERROR + + WRITE (KW,*) ' Error in case ',NCASE + WRITE (KLOG,*) ' ' + WRITE (KLOG,*) ' Error in case ',NCASE + NERROR = NERROR + 1 + END SUBROUTINE PRTERR + + SUBROUTINE TIMEIT(TIME) + + INTEGER JTIME,JRATE + REAL TIME + +! Return the system time. f90 version. + + CALL SYSTEM_CLOCK(JTIME,JRATE) + TIME = REAL(JTIME)/REAL(JRATE) + RETURN + END SUBROUTINE TIMEIT diff --git a/src/gauge/Makefile b/src/gauge/Makefile index 82b7f4099e3c68b01fa6e4e0590a3d2d9a79b0a7..fe77fd120646a339953f3c574097c977aae1cd78 100644 --- a/src/gauge/Makefile +++ b/src/gauge/Makefile @@ -59,4 +59,3 @@ lib_gauge.a: $(OBJS) clobber: rm -f *.[Tiod] *.f90 *.mod lib_gauge.a -clean:;make clobber diff --git a/src/gauge/dsg.F90 b/src/gauge/dsg.F90 index b016084ca2e49a443ce0e1cfc5e80e9fef9bb383..29c11f821d66b47b8e8be645db0099d57cd5d90d 100644 --- a/src/gauge/dsg.F90 +++ b/src/gauge/dsg.F90 @@ -31,6 +31,7 @@ subroutine dsg(p, plaq, step) use module_action_type use module_vol use module_staple + use module_switches implicit none GENERATOR_FIELD, intent(inout) :: p @@ -61,6 +62,8 @@ subroutine dsg(p, plaq, step) enddo enddo + if (switches%boundary_sf) call dsg_sfdiff(p, plaq, step) + call nonactive(p) !! for ddhmc call hmc_forces_new(p, step, plaq%fid) diff --git a/src/gauge/dsig.F90 b/src/gauge/dsig.F90 index 50eb3b1efbce05f7c1e85fd75fa0bc95bc1d7ec9..4a55da21f5f277c15847bcbb3722d864dbafe52b 100644 --- a/src/gauge/dsig.F90 +++ b/src/gauge/dsig.F90 @@ -29,6 +29,91 @@ subroutine dsig(p, impg, step) use module_field use module_action_type use module_vol + use module_switches + implicit none + + GENERATOR_FIELD, intent(inout) :: p + type(type_impg), intent(in) :: impg + REAL, intent(in) :: step + REAL :: s1, s2, s3 + SU3 :: uuu, w + integer :: mu, eo, i + + COMPLEX, allocatable :: w1(:, :, :, :, :) + COMPLEX, allocatable :: w2(:, :, :, :, :) + COMPLEX, allocatable :: w3(:, :, :, :, :) + integer :: ierr + + + if (impg%beta1 == ZERO) return + if (step == ZERO) return + + TIMING_START(timing_bin_dsig) + DEBUG2S("Start: dsig") + + allocate(w1(NCOL, NCOL, volh_tot, EVEN:ODD, DIM), STAT = ierr) + allocate(w2(NCOL, NCOL, volh_tot, EVEN:ODD, DIM), STAT = ierr) + allocate(w3(NCOL, NCOL, volh_tot, EVEN:ODD, DIM), STAT = ierr) + + call hmc_forces_old(p) + s1 = -step * impg%beta1 / THREE + s2 = -step * impg%beta2 / THREE + s3 = -step * impg%beta3 / THREE + + do mu = 1, DIM + call r_staple(w1, gauge(1)%u(1,1,1,0,1), mu) + if (switches%boundary_sf) call schr_boundary_zero4(w1) + do eo = EVEN, ODD + !$omp parallel do private(uuu, w) + do i = 1, volh + call staple_r_fat(uuu, gauge(1)%u(1,1,1,0,1), w1, i, eo, mu) + call uu(w, gauge(1)%u(1, 1, i, eo, mu), uuu) + call im_tr_j(p(1, i, eo, mu), w, s1) + enddo + enddo + + call u_staple(w1, gauge(1)%u(1,1,1,0,1), mu) + call d_staple(w2, gauge(1)%u(1,1,1,0,1), mu) + call l_staple(w3, gauge(1)%u(1,1,1,0,1), mu) + + if (switches%boundary_sf) call schr_boundary_zero4(w1) + if (switches%boundary_sf) call schr_boundary_zero4(w2) + if (switches%boundary_sf) call schr_boundary_zero4(w3) + + do eo = EVEN, ODD + !$omp parallel do private(uuu, w) + do i = 1, volh + call staple_udl(uuu, gauge(1)%u(1,1,1,0,1), w1, w2, w3, i, eo, mu) + call uu(w, gauge(1)%u(1, 1, i, eo, mu), uuu) + call im_tr_j(p(1, i, eo, mu), w, s1) + enddo + enddo + + if (s2 /= ZERO) call die("imp_action ERROR") ! chai + if (s3 /= ZERO) call die("imp_action ERROR") ! para + enddo + + if (switches%boundary_sf) call dsig_sfdiff(p, impg, step) + + call nonactive(p) !! for ddhmc + + call hmc_forces_new(p, step, impg%fid) + + + deallocate(w1, STAT = ierr) + deallocate(w2, STAT = ierr) + + DEBUG2S("End: dsig") + TIMING_STOP(timing_bin_dsig) + +end + +!------------------------------------------------------------------------------- +subroutine dsig_old(p, impg, step) + use module_field + use module_action_type + use module_vol + use module_switches implicit none GENERATOR_FIELD, intent(inout) :: p @@ -69,6 +154,7 @@ subroutine dsig(p, impg, step) do mu = 1, DIM call r_staple(w1, gauge(1)%u(1,1,1,0,1), mu) +if (switches%boundary_sf) call schr_boundary_zero4(w1) do eo = EVEN, ODD !$omp parallel do private(uuu, w) do i = 1, volh @@ -81,6 +167,9 @@ subroutine dsig(p, impg, step) call ul_staple(w1, gauge(1)%u(1,1,1,0,1), mu) call dl_staple(w2, gauge(1)%u(1,1,1,0,1), mu) +if (switches%boundary_sf) call schr_boundary_zero4(w1) +if (switches%boundary_sf) call schr_boundary_zero4(w2) + do eo = EVEN, ODD !$omp parallel do private(uuu, w) do i = 1, volh diff --git a/src/gauge/sig.F90 b/src/gauge/sig.F90 index 4fda40d86ba40f083994722c15e5f57a34025dd9..d4df57fdbd2fd9e54ea75fa9a4aa8ebbf6dbf7e7 100644 --- a/src/gauge/sig.F90 +++ b/src/gauge/sig.F90 @@ -40,16 +40,25 @@ REAL function sig(s_p, plaq, rect) ! returns S_g , s_plaq=sg(u) use module_field use module_action use module_s_plaq + use module_switches implicit none REAL,intent(out) :: s_p, plaq(3), rect(3) - REAL, external :: s_rect + REAL, external :: s_rect, s_plaq_sfdiff, s_rect_sfdiff + REAL :: tmp s_p = s_plaq(gauge(1)%u, plaq) sig = action%plaq%beta * s_p + if (switches%boundary_sf) sig = sig + action%plaq%beta * s_plaq_sfdiff(gauge(1)%u) +!!write(*,*)sig + + if (action%impg%beta1 /= ZERO) then - sig = sig + action%impg%beta1 * s_rect(gauge(1)%u, rect) + tmp = s_rect(gauge(1)%u, rect) + if (switches%boundary_sf) tmp = tmp + s_rect_sfdiff(gauge(1)%u) + sig = sig + action%impg%beta1 * tmp +!!write(*,*) action%impg%beta1 * tmp else rect=0 endif @@ -134,6 +143,7 @@ REAL function s_rect(u, rect) ! returns S_rest use module_lattice use module_nn use module_vol + use module_switches implicit none GAUGE_FIELD, intent(in) :: u @@ -192,12 +202,16 @@ REAL function s_rect(u, rect) ! returns S_rest call xbound_g(w1, e, nu) call xbound_g(w2, e, mu) enddo +if (switches%boundary_sf) call schr_boundary_zero4(w1) +if (switches%boundary_sf) call schr_boundary_zero4(w2) #endif do e = EVEN, ODD o = EVEN + ODD - e #ifndef D500 call xbound_g_rect_ind(w1, o, nu, mu, FWD) call xbound_g_rect_ind(w2, o, mu, nu, FWD) +if (switches%boundary_sf) call schr_boundary_zero4(w1) +if (switches%boundary_sf) call schr_boundary_zero4(w2) #endif p = ZERO !$omp parallel do reduction(+: p) private(j1, j2, uuu) diff --git a/src/gauge/staple_imp.F90 b/src/gauge/staple_imp.F90 index e9f903dab2f041e271005d7ce9abf56b30ffbce2..6e739e256003a9c51b0f1bf21143fec3b109b406 100644 --- a/src/gauge/staple_imp.F90 +++ b/src/gauge/staple_imp.F90 @@ -195,6 +195,47 @@ subroutine staple_r_fat(uuu, u, u_tmp1, i, e, mu) end +!------------------------------------------------------------------------------- +subroutine staple_ud(uuu, u, u_tmp1, u_tmp2, i, e, mu) + + use module_nn + use module_vol + implicit none + + SU3, intent(out) :: uuu + GAUGE_FIELD, intent(in) :: u, u_tmp1, u_tmp2 + integer, intent(in) :: i, e, mu + integer :: o, nu, j1, j2, j3, j4 + + o = EVEN + ODD - e + uuu = 0 + + do nu = 1, DIM + if (nu /= mu) then + ! (j2,o) --<-- x nu + ! | | + ! v ^ ^ + ! | | | + ! (i,e) -->-- (j1,o) x--> mu + ! | | + ! ^ v + ! | | + ! (j3,o) --<-- (j4,e) + j1 = nn(i, e, mu, FWD) + j2 = nn(i, e, nu, FWD) + j3 = nn(i, e, nu, BWD) + j4 = nn(j3,o, mu, FWD) + call uddp(uuu, u(1, 1, j1, o, nu), & + u_tmp1(1, 1, j2, o, nu), & + u(1, 1, i , e, nu)) + call ddup(uuu, u(1, 1, j4, e, nu), & + u_tmp2(1, 1, j3, o, nu), & + u(1, 1, j3, o, nu)) + endif + enddo + +end + !------------------------------------------------------------------------------- subroutine staple_udl(uuu, u, u_tmp1, u_tmp2, u_tmp3, i, e, mu) @@ -390,6 +431,7 @@ subroutine u_staple(u_out, u, mu) u(1, 1, j2, o, mu), & u(1, 1, j1, o, nu)) enddo + call xbound_g(u_out, e, nu) enddo endif enddo @@ -427,6 +469,7 @@ subroutine d_staple(u_out, u, mu) u(1, 1, j1, o, mu), & u(1, 1, j2, e, nu)) enddo + call xbound_g(u_out, e, nu) enddo endif enddo @@ -464,6 +507,7 @@ subroutine l_staple(u_out, u, mu) u(1, 1, j1, o, nu), & u(1, 1, j2, e, mu)) enddo + call xbound_g(u_out, e, nu) enddo endif enddo diff --git a/src/gauge/stout.F90 b/src/gauge/stout.F90 index 6c43ce07773d51673278ed0dce0f58312971ad51..859680f517d9d1ddda9279ce68c52ab6701a2c7c 100644 --- a/src/gauge/stout.F90 +++ b/src/gauge/stout.F90 @@ -205,6 +205,7 @@ subroutine stout_link_smearing_up(u, alpha, stout, dobs) use module_nn use module_vol use module_staple + use module_switches implicit none type(type_stout), intent(out) :: stout @@ -263,6 +264,8 @@ subroutine stout_link_smearing_up(u, alpha, stout, dobs) call xbound_g_field(stout%u(1,1,1,0,1)) TIMING_STOP(timing_bin_hmc_xbound_g) +!! if (switches%boundary_sf) call schr_boundary_zero4(stout%u) + if (switches%boundary_sf) call schr_boundary_gauge(stout%u) TIMING_STOP(timing_bin_stout_smear) DEBUG2S("End: stout_link_smearing_up") @@ -493,6 +496,7 @@ subroutine stout_link_smearing_down(ff, u, stout, alpha) use module_vol use module_p_interface use module_staple + use module_switches implicit none GAUGE_FIELD, intent(inout) :: ff @@ -532,6 +536,8 @@ subroutine stout_link_smearing_down(ff, u, stout, alpha) call xbound_g_field(lam(1,1,1,0,1)) TIMING_STOP(timing_bin_hmc_xbound_g) + if (switches%boundary_sf) call schr_boundary_zero4(lam) + !---------------------------- new force matrix do mu = 1, DIM do eo = EVEN, ODD @@ -547,6 +553,11 @@ subroutine stout_link_smearing_down(ff, u, stout, alpha) enddo !--------------------------------------------- + + + if (switches%boundary_sf) call schr_boundary_zero4(ff) + if (switches%boundary_sf) call schr_boundary_zero3(ff) + TIMING_STOP(timing_bin_stout_diffe) DEBUG2S("End: stout_link_smearing_down") diff --git a/src/ildg/Makefile b/src/ildg/Makefile index cf9ad100ea3f5d721f6c7885b1e8bd1ac0d3042d..8af756ecb472a9ed44e0713e1a415897cfba1257 100644 --- a/src/ildg/Makefile +++ b/src/ildg/Makefile @@ -51,6 +51,10 @@ OBJS = \ ildg_seq_r4.o \ ildg_xml.o +ifdef LEMON +OBJS += ildg_lemon.o +endif + $(LIBILDG): fast: diff --git a/src/ildg/ildg.c b/src/ildg/ildg.c index d9edf5da3fc3ae8bff12a316f151d3a2ec1409c7..b344827a27dfaf1809da998128943be408f49cb5 100644 --- a/src/ildg/ildg.c +++ b/src/ildg/ildg.c @@ -142,6 +142,10 @@ void ILDG_READ(void *buffer, INT8 *bytes) n_uint64_t nbytes = *bytes; status = limeReaderReadData(buffer, &nbytes, r); + if (status != LIME_SUCCESS) + die("failed to read Data (status=%d)", status); + if (nbytes != *bytes) + die("failed to read Data, read bytes /= requested bytes (status=%d)", status); CKSUM_ADD(buffer, bytes); } @@ -156,6 +160,8 @@ void ILDG_WRITE(void *buffer, INT8 *bytes) n_uint64_t nbytes = *bytes; status = limeWriteRecordData(buffer, &nbytes, w); + if (status != LIME_SUCCESS) + die("failed to write Data (status=%d)", status); CKSUM_ADD(buffer, bytes); } diff --git a/src/ildg/ildg.h b/src/ildg/ildg.h index 87c67d340ec9a122465f55b19f150ce825ae1ce0..bd2b3db30308785ab3b7d124b77b53d9cfc8b451 100644 --- a/src/ildg/ildg.h +++ b/src/ildg/ildg.h @@ -34,6 +34,12 @@ # define ILDG_WRITE ildg_write # define ILDG_CLOSE_R ildg_close_r # define ILDG_CLOSE_W ildg_close_w +# define ILDG_OPEN_W_LEMON ildg_open_w_lemon +# define ILDG_OPEN_R_LEMON ildg_open_r_lemon +# define ILDG_CLOSE_W_LEMON ildg_close_w_lemon +# define ILDG_CLOSE_R_LEMON ildg_close_r_lemon +# define ILDG_WRITE_LEMON ildg_write_lemon +# define ILDG_READ_LEMON ildg_read_lemon #endif #ifdef NamesToLower_ @@ -43,6 +49,12 @@ # define ILDG_WRITE ildg_write_ # define ILDG_CLOSE_R ildg_close_r_ # define ILDG_CLOSE_W ildg_close_w_ +# define ILDG_OPEN_W_LEMON ildg_open_w_lemon_ +# define ILDG_OPEN_R_LEMON ildg_open_r_lemon_ +# define ILDG_CLOSE_W_LEMON ildg_close_w_lemon_ +# define ILDG_CLOSE_R_LEMON ildg_close_r_lemon_ +# define ILDG_WRITE_LEMON ildg_write_lemon_ +# define ILDG_READ_LEMON ildg_read_lemon_ #endif #ifdef NamesToLower__ @@ -52,6 +64,12 @@ # define ILDG_WRITE ildg_write__ # define ILDG_CLOSE_R ildg_close_r__ # define ILDG_CLOSE_W ildg_close_w__ +# define ILDG_OPEN_W_LEMON ildg_open_w_lemon__ +# define ILDG_OPEN_R_LEMON ildg_open_r_lemon__ +# define ILDG_CLOSE_W_LEMON ildg_close_w_lemon__ +# define ILDG_CLOSE_R_LEMON ildg_close_r_lemon__ +# define ILDG_WRITE_LEMON ildg_write_lemon__ +# define ILDG_READ_LEMON ildg_read_lemon__ #endif @@ -65,15 +83,30 @@ void ILDG_OPEN_W(char *filename, int *Lx, int *Ly, int *Lz, int *Lt, int *precision, INT8 *bytes_total); +void ILDG_OPEN_R_LEMON(char *filename, + int *Lx, int *Ly, int *Lz, int *Lt, + int npe[4], int *precision, + INT8 *bytes_total); +void ILDG_OPEN_W_LEMON(char *filename, + int *Lx, int *Ly, int *Lz, int *Lt, + int npe[4], int *precision, + INT8 *bytes_total); + + void ILDG_READ(void *buffer, INT8 *bytes); void ILDG_WRITE(void *buffer, INT8 *bytes); +void ILDG_READ_LEMON(void *buffer,int L[4], int *vol, int *precision); +void ILDG_WRITE_LEMON(void *buffer,int L[4], int *vol, int *precision); void ILDG_CLOSE_R(INT8 *cksum, INT8 *bytes_total, char *lfn, int *len); void ILDG_CLOSE_W(INT8 *cksum, INT8 *bytes_total, char *lfn); - +void ILDG_CLOSE_R_LEMON(INT8 *cksum, INT8 *bytes_total, char *lfn, int *len); +void ILDG_CLOSE_W_LEMON(INT8 *cksum, INT8 *bytes_total, char *lfn); /* prototypes for C functions called from C */ void ildg_find_record(char *record); void ildg_read_string(char *record, char *s, int len); +void ildg_find_record_lemon(char *record); +void ildg_read_string_lemon(char *record, char *s, int len); /*===========================================================================*/ diff --git a/src/ildg/ildg_conf.F90 b/src/ildg/ildg_conf.F90 index c81db5591de9bf63db5f2e2e4fe4f21cdac95deb..17c45b48710de588f261b2e87eacee967eab8048 100644 --- a/src/ildg/ildg_conf.F90 +++ b/src/ildg/ildg_conf.F90 @@ -5,6 +5,7 @@ !------------------------------------------------------------------------------- ! ! Copyright (C) 2007-2008 Hinnerk Stueben +! 2010 Yoshifumi Nakamura ! ! This file is part of BQCD -- Berlin Quantum ChromoDynamics program ! @@ -60,12 +61,23 @@ subroutine conf_read_ildg(restart, para, conf) FILENAME :: filename integer :: len_lfn INT8 :: bytes_read + integer :: i, mu, eo call begin(UREC, "ILDGread") ALLOCATE_G_FIELD_ILDG(u_ildg) call ildg_lime_file(filename, READ, restart) +#if defined(LEMON) && !defined(MPI_1) + call ildg_open_r_lemon(filename, lx, ly, lz, lt, para%NPE, precision, bytes) + call ildg_check() + call ildg_set_sizes() + TIMING_START(timing_bin_u_read_ildg) + call ildg_io_lemon(READ, u_ildg, precision) + TIMING_STOP(timing_bin_u_read_ildg) + len_lfn = len(lfn) - 1 + call ildg_close_r_lemon(cksum, bytes_read, lfn, len_lfn) +#else call ildg_open_r(filename, lx, ly, lz, lt, precision, bytes) call ildg_check() call ildg_set_sizes() @@ -76,6 +88,7 @@ subroutine conf_read_ildg(restart, para, conf) len_lfn = len(lfn) - 1 call ildg_close_r(cksum, bytes_read, lfn, len_lfn) +#endif if (my_pe() == 0) then call ildg_check2(restart) @@ -85,6 +98,10 @@ subroutine conf_read_ildg(restart, para, conf) endif call ildg_seq(READ, conf(1)%u, u_ildg) + + call conf_normalize(conf(1)%u) + call conf_check(conf(1)%u) + call xbound_g_field(conf(1)%u) conf(1)%former = 1 @@ -136,7 +153,31 @@ subroutine conf_write_ildg(restart, para, conf) call ildg_check() call ildg_seq(WRITE, conf(1)%u, u_ildg) - + + +#if defined(LEMON) && !defined(MPI_1) + call ildg_open_w_lemon(filename, lx, ly, lz, lt, para%NPE, precision, bytes) + TIMING_START(timing_bin_u_write_ildg) + call ildg_io_lemon(WRITE, u_ildg, precision) + TIMING_STOP(timing_bin_u_write_ildg) + call cksum_get(cksum, bytes_written) + call ildg_set_lfn(filename, restart) + call ildg_close_w_lemon(cksum0, bytes_written, lfn) + + if (my_pe() == 0) then + call ildg_rec(WRITE, filename) + if (.not. restart) then + i = index(lfn, ascii_null) + ASSERT(i > 0) + call ildg_meta("ensemble", para, conf, lfn(1:i-1), plaquette, precision, cksum) + call ildg_meta("conf", para, conf, lfn(1:i-1), plaquette, precision, cksum) + endif + ASSERT(cksum0 == cksum) + ASSERT(bytes == bytes_written) + endif + +#else + if (my_pe() == 0) then call ildg_open_w(filename, lx, ly, lz, lt, precision, bytes) endif @@ -162,6 +203,7 @@ subroutine conf_write_ildg(restart, para, conf) ASSERT(bytes == bytes_written) endif +#endif call end(UREC, "ILDGwrite") end diff --git a/src/ildg/ildg_lemon.c b/src/ildg/ildg_lemon.c new file mode 100644 index 0000000000000000000000000000000000000000..f9e235a3f14f51c6eda0414aa2a52f15073484b0 --- /dev/null +++ b/src/ildg/ildg_lemon.c @@ -0,0 +1,285 @@ +/* +!=============================================================================== +! +! ildg_lemon.c - read/write configuration in ILDG lime format with LEMON +! +!------------------------------------------------------------------------------- +! +! Copyright (C) 2010 Yoshifumi Nakamura +! +! This file is part of BQCD -- Berlin Quantum ChromoDynamics program +! +! BQCD 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 Foundation, either version 3 of the License, or +! (at your option) any later version. +! +! BQCD is distributed in the hope that it will be useful, +! but WITHOUT ANY WARRANTY; without even the implied warranty of +! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +! GNU General Public License for more details. +! +! You should have received a copy of the GNU General Public License +! along with BQCD. If not, see <http://www.gnu.org/licenses/>. +! +!------------------------------------------------------------------------------- +*/ +# include <sys/types.h> +# include <stdio.h> +# include <string.h> +# include <mpi.h> +# include "c_defs.h" +# include "c_util.h" +# include "cksum.h" +# include "ildg.h" +# include "lemon.h" + +static MPI_File fp; +static LemonReader *r; +static LemonWriter *w; +static LemonRecordHeader *h; + +static char xmldoc[1024]; +static int len_xmldoc = 1023; + +int status; +uint64_t nbytes; +/*----------------------------------------------------------------------------*/ +void ILDG_OPEN_R_LEMON(char *filename, + int *Lx, int *Ly, int *Lz, int *Lt, + int npe[4], int *precision, + INT8 *bytes_total) +{ + /* filename (input) + * Lx, Ly, Lz, Lt lattice size (output) + * precision 32|64 (output) + * bytes_total bytes of configuration (output) + */ + int latDist[] = {2, 1, 2, 1}; + int periods[] = {1, 1, 1, 1}; + + latDist[0]=npe[3]; + latDist[1]=npe[2]; + latDist[2]=npe[1]; + latDist[3]=npe[0]; + + MPI_Comm cartesian; + MPI_Cart_create(MPI_COMM_WORLD, 4, latDist, periods, 1, &cartesian); + MPI_File_open(cartesian, filename, MPI_MODE_RDONLY, MPI_INFO_NULL, &fp); + r = lemonCreateReader(&fp, cartesian); + + ildg_find_record_lemon("ildg-format"); + ildg_read_string_lemon("ildg-format", xmldoc, len_xmldoc); + + ildg_xml_check_value(xmldoc, "<version>", "1.0"); + ildg_xml_check_value(xmldoc, "<field>", "su3gauge"); + ildg_xml_get_int(xmldoc, "<precision>", precision); + ildg_xml_get_int(xmldoc, "<lx>", Lx); + ildg_xml_get_int(xmldoc, "<ly>", Ly); + ildg_xml_get_int(xmldoc, "<lz>", Lz); + ildg_xml_get_int(xmldoc, "<lt>", Lt); + + ildg_find_record_lemon("ildg-binary"); + + *bytes_total = lemonReaderBytes(r); + + CKSUM_INIT(); +} + +/*----------------------------------------------------------------------------*/ +void ILDG_OPEN_W_LEMON(char *filename, + int *Lx, int *Ly, int *Lz, int *Lt, + int npe[4], int *precision, + INT8 *bytes_total) +{ + /* filename (input) + * Lx, Ly, Lz, Lt lattice size (input) + * precision 32|64 (input) + * bytes_total bytes of configuration (input) + */ + + int latDist[] = {2, 1, 2, 1}; + int periods[] = {1, 1, 1, 1}; + + latDist[0]=npe[3]; + latDist[1]=npe[2]; + latDist[2]=npe[1]; + latDist[3]=npe[0]; + + MPI_Comm cartesian; + // MPI_Comm_size(MPI_COMM_WORLD, &mpisize); + // MPI_Dims_create(mpisize, 4, latDist); + // printf("latDist %d %d %d %d\n",latDist[0],latDist[1],latDist[2],latDist[3]); + + MPI_Cart_create(MPI_COMM_WORLD, 4, latDist, periods, 1, &cartesian); + MPI_File_open(cartesian, filename, MPI_MODE_WRONLY | MPI_MODE_CREATE, MPI_INFO_NULL, &fp); + MPI_File_set_size(fp, 0); + w = lemonCreateWriter(&fp, cartesian); + + sprintf(xmldoc, + "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" + "<ildgFormat>\n" + " <version>1.0</version>\n" + " <field>su3gauge</field>\n" + " <precision>%d</precision>\n" + " <lx>%d</lx> <ly>%d</ly> <lz>%d</lz> <lt>%d</lt>\n" + "</ildgFormat>\n", + *precision, *Lx, *Ly, *Lz, *Lt); + nbytes = strlen(xmldoc); + + h = lemonCreateHeader(1, 0, "ildg-format", nbytes); + + status=lemonWriteRecordHeader(h, w); + if (status != LEMON_SUCCESS) + die("failed to lemonWriteRecordHeader (status=%d)\n", status); + + lemonDestroyHeader(h); + + status=lemonWriteRecordData(xmldoc, &nbytes, w); + if (status != LEMON_SUCCESS) + die("failed to lemonWriteRecordData (status=%d)\n", status); + + lemonWriterCloseRecord(w); + + nbytes = *bytes_total; + h = lemonCreateHeader(0, 1, "ildg-binary-data", nbytes); + + status=lemonWriteRecordHeader(h, w); + if (status != LEMON_SUCCESS) + die("failed to lemonWriteRecordData (status=%d)\n", status); + + lemonDestroyHeader(h); + + CKSUM_INIT(); +} + +/*----------------------------------------------------------------------------*/ +void ILDG_READ_LEMON(void *buffer, int L[4], int *vol, int *precision) +{ + /* buffer (input) + * bytes (input) + */ + + int const mapping[] = {0, 1, 2, 3}; + uint64_t siteSize=sizeof(double) * 2* 3*3*4; + if (*precision == 32) siteSize/=2; + // INT8 bytes=siteSize * (INT8)*vol; + + status=lemonReadLatticeParallelMapped(r, buffer, siteSize, L, mapping); + if (status != LEMON_SUCCESS) + die("failed lemonReadLatticeParallelMapped (status=%d\n)", status); + lemonReaderCloseRecord(r); +} + +/*----------------------------------------------------------------------------*/ +void ILDG_WRITE_LEMON(void *buffer, int L[4], int *vol, int *precision) +{ + /* buffer (output) + * bytes (input) + */ + + int const mapping[] = {0, 1, 2, 3}; + uint64_t siteSize=sizeof(double) * 2* 3*3*4; + if (*precision == 32) siteSize/=2; + // INT8 bytes=siteSize * (INT8)&vol; + + // printf("ILDG_WRITE_LEMON siteSize:%llu\n",siteSize); + //status=lemonWriteLatticeParallel(w, buffer, siteSize, latSizes); + + status=lemonWriteLatticeParallelMapped(w, buffer, siteSize, L, mapping); + if (status != LEMON_SUCCESS) + die("failed lemonWriteLatticeParallelMapped (status=%d\n)", status); + lemonWriterCloseRecord(w); +} + +/*----------------------------------------------------------------------------*/ +void ILDG_CLOSE_R_LEMON(INT8 *cksum, INT8 *bytes_total, char *lfn, int *len) +{ + /* cksum CRC check sum (output) + * bytes_total (output) (from cksum()) + * lfn logical file name (output) + * len input: max. length of "lfn" + * output: actual length of "lfn" + */ + + // fseek(fp, 0, SEEK_SET); how should I change? + do { + status = lemonReaderNextRecord(r); + if (status == LEMON_EOF) + break; + } while (strncmp(lemonReaderType(r), "ildg-data-lfn", 13) != 0); + + + if (status == LEMON_EOF) + strcpy(lfn, "UNDEFINED"); + else + ildg_read_string_lemon("ildg-data-lfn", lfn, *len); + + *len = strlen(lfn); + + lemonDestroyReader(r); + MPI_File_close(&fp); + CKSUM_GET(cksum, bytes_total); +} + +/*----------------------------------------------------------------------------*/ +void ILDG_CLOSE_W_LEMON(INT8 *cksum, INT8 *bytes_total, char *lfn) +{ + /* cksum CRC check sum (output) + * bytes_total (output) (from cksum()) + * lfn logical file name (input) + */ + + nbytes = strlen(lfn); + + h = lemonCreateHeader(1, 1, "ildg-data-lfn", nbytes); + + status=lemonWriteRecordHeader(h, w); + if (status != LEMON_SUCCESS) + die("failed lemonWriteRecordHeader (status=%d)\n", status); + + lemonDestroyHeader(h); + + status=lemonWriteRecordData(lfn, &nbytes, w); + if (status != LEMON_SUCCESS) + die("failed lemonWriteRecordData (status=%d)\n", status); + + lemonDestroyWriter(w); + MPI_File_close(&fp); + CKSUM_GET(cksum, bytes_total); + +} + +/*----------------------------------------------------------------------------*/ +void ildg_find_record_lemon(char *record) +{ + /* record (input) + */ + + // fseek(fp, 0, SEEK_SET); how should I change? + do { + status = lemonReaderNextRecord(r); + if (status == LEMON_EOF) + die("unexpected end-of-file"); + } while (strncmp(lemonReaderType(r), record, (int) strlen(record)) != 0); +} + +/*----------------------------------------------------------------------------*/ +void ildg_read_string_lemon(char *record, char *s, int len) +{ + /* record (input) + * s string read (output) + * len max. length of "s" + */ + + nbytes = lemonReaderBytes(r); + if (nbytes > len) + die("string (length=%d) too small for reading record %s", len, record); + + status = lemonReaderReadData(s, &nbytes, r); + if (status != LEMON_SUCCESS) + die("failed to read record %s (status=%d)", record, status); + s[nbytes] = '\0'; +} + +/*============================================================================*/ diff --git a/src/include/c_defs.h b/src/include/c_defs.h index 9f8b3912ff3a9f3fd5e1bb2b3b7d5c3cd55b9c18..1ae9acbf225afdca1cc81de1cfb3379e4b2f2a06 100644 --- a/src/include/c_defs.h +++ b/src/include/c_defs.h @@ -1,3 +1,5 @@ +#ifndef BQCD_C_DEFS_H +#define BQCD_C_DEFS_H /* !=============================================================================== ! @@ -5,7 +7,7 @@ ! !------------------------------------------------------------------------------- ! -! Copyright (C) 2007 Hinnerk Stueben +! Copyright (C) 2007-2011 Hinnerk Stueben ! ! This file is part of BQCD -- Berlin Quantum ChromoDynamics program ! @@ -25,6 +27,26 @@ !------------------------------------------------------------------------------- */ +# define CAT(A, B) A ## B +# define STRCAT(A, B) CAT(A, B) +# define STRCAT3(A, B, C) STRCAT(STRCAT(A, B), C) +# define STRING(s) SSTRING(s) +# define SSTRING(s) #s + +# define DIM 4 +# define NCOL 3 +# define NDIRAC 4 +# define NGEN 8 +# define EVEN 0 +# define ODD 1 +# define FWD 0 +# define BWD 1 + +# define SIZE_COMPLEX 2 + +# define FWD_BWD 2 +# define EVEN_ODD 2 + #ifdef LongLong # define INT8 long long #else @@ -32,6 +54,68 @@ #endif +#ifdef PRECISION_R4 +typedef float REAL; +#else +typedef double REAL; +#endif + +typedef int INTEGER; +typedef struct { REAL r; REAL i; } COMPLEX; + +typedef COMPLEX (*SPINCOL_FIELD)[NCOL][NDIRAC]; +typedef COMPLEX (*REORDERED_GAUGE_FIELD)[NCOL][NCOL+NCOL]; +typedef COMPLEX (*SC2_FLD)[NCOL][2]; + +# define Re(z) (z).r +# define Im(z) (z).i + +static const REAL ZERO = 0; +static const REAL ONE = 1; +static const REAL TWO = 2; + +# include "../include_auto/c_timing.h" + +# define timing_bin_d_dag_xf timing_bin_d_xf +# define timing_bin_d_dag_xb timing_bin_d_xb +# define timing_bin_d_dag_yf timing_bin_d_yf +# define timing_bin_d_dag_yb timing_bin_d_yb +# define timing_bin_d_dag_zf timing_bin_d_zf +# define timing_bin_d_dag_zb timing_bin_d_zb +# define timing_bin_d_dag_t timing_bin_d_t +# define timing_bin_d_dag timing_bin_d + +#ifdef TIMING + +#ifdef NamesToLower +# define TIMING_START(bin) timing_start(&bin) +# define TIMING_STOP(bin) timing_stop(&bin) +void timing_start(const int*); +void timing_stop(const int*); +#endif + +#ifdef NamesToLower_ +# define TIMING_START(bin) timing_start_(&bin) +# define TIMING_STOP(bin) timing_stop_(&bin) +void timing_start_(const int*); +void timing_stop_(const int*); +#endif + +#ifdef NamesToLower__ +# define TIMING_START(bin) timing_start__(&bin) +# define TIMING_STOP(bin) timing_stop__(&bin) +void timing_start__(const int*); +void timing_stop__(const int*); +#endif + +#else + +# define TIMING_START(bin) +# define TIMING_STOP(bin) + +#endif /* TIMING */ + + /* prototypes for Fortran Functions called from C */ #ifdef NamesToLower @@ -52,3 +136,4 @@ void ABBRUCH(void); /*===========================================================================*/ +#endif /* BQCD_C_DEFS_H */ diff --git a/src/include/cksum.h b/src/include/cksum.h index 4b1700c495bb8bd8500d7e46bce241086047e361..f59d8cc6e17a5364992fe3d9acbf24122fc9cffa 100644 --- a/src/include/cksum.h +++ b/src/include/cksum.h @@ -31,18 +31,21 @@ # define CKSUM_INIT cksum_init # define CKSUM_ADD cksum_add # define CKSUM_GET cksum_get +# define CKSUM_BCAST cksum_bcast #endif #ifdef NamesToLower_ # define CKSUM_INIT cksum_init_ # define CKSUM_ADD cksum_add_ # define CKSUM_GET cksum_get_ +# define CKSUM_BCAST cksum_bcast_ #endif #ifdef NamesToLower__ # define CKSUM_INIT cksum_init__ # define CKSUM_ADD cksum_add__ # define CKSUM_GET cksum_get__ +# define CKSUM_BCAST cksum_bcast__ #endif /* prototypes for those functions */ @@ -51,4 +54,7 @@ void CKSUM_INIT(void); void CKSUM_ADD(void *, INT8 *); void CKSUM_GET(INT8 *, INT8 *); +/*this is just for */ +void CKSUM_BCAST(int * np); + /*===========================================================================*/ diff --git a/src/include/defs.h b/src/include/defs.h index f44d051cdae2337a2a4f33da31f906beea7e43a4..f2db000245b9e4305d4ccce32597138f52b297ae 100644 --- a/src/include/defs.h +++ b/src/include/defs.h @@ -35,9 +35,21 @@ # define STRCAT3(A, B, C) STRCAT(STRCAT(A, B), C) #ifdef PRECISION_R4 +#// efine D_R4_INTERNAL # define RKIND 4 # define DKIND 8 # define BQCD_REAL mpi_real4 +# include "../include_auto/precision_r4.h" +#elif defined(PRECISION_R16) +#// efine D_R16_INTERNAL +# define RKIND 16 +# define DKIND 16 +# define BQCD_REAL mpi_real16 +# include "../include_auto/precision_r16.h" +# define global_sum_vec global_sum_vec_r16 +# define global_sum global_sum_r16 +# define global_min global_min_r16 +# define global_max global_max_r16 #else # define RKIND 8 # define DKIND 8 @@ -70,9 +82,11 @@ # define DOUBLE real(DKIND) # define REAL4 real(4) # define REAL8 real(8) +# define REAL16 real(16) # define COMPLEX complex(RKIND) # define COMPLEX4 complex(4) # define COMPLEX8 complex(8) +# define COMPLEX16 complex(16) # define INTEGER integer(4) # define INT4 integer(4) # define INT8 integer(8) @@ -145,7 +159,7 @@ # define HALF STRCAT(0.5_, RKIND) # define EIGHTH STRCAT(0.125_, RKIND) -#include "timing.h" +#include "../include_auto/timing.h" # define timing_bin_d_dag_xf timing_bin_d_xf # define timing_bin_d_dag_xb timing_bin_d_xb @@ -204,6 +218,7 @@ # define FULL_SOURCE 0 # define RANDOM_SOURCE 1 # define WALL_SOURCE 2 +# define LOCAL_SOURCE 3 # define EO_NORMAL 1 # define UN_NORMAL 2 diff --git a/src/include/defs_c.h b/src/include/defs_c.h deleted file mode 100644 index a800bf7acc4a3ff68a345dd11ca3f1eb993aa9e4..0000000000000000000000000000000000000000 --- a/src/include/defs_c.h +++ /dev/null @@ -1,40 +0,0 @@ -#ifndef BQCD_DEFS_C_H -#define BQCD_DEFS_C_H - -# define DIM 4 -# define NCOL 3 -# define NDIRAC 4 -# define NGEN 8 -# define EVEN 0 -# define ODD 1 -# define FWD 0 -# define BWD 1 - -# define SIZE_COMPLEX 2 - -# define FWD_BWD 2 -# define EVEN_ODD 2 - -typedef double REAL; -typedef int INTEGER; -typedef struct { REAL r; REAL i; } COMPLEX; -typedef COMPLEX SU3[NCOL][NCOL]; -typedef REAL GENERATOR[NGEN]; - -typedef COMPLEX SPINCOL_FIELD[][NCOL][NDIRAC]; -typedef struct { COMPLEX (*sc)[NCOL][2]; } SC2_FIELD[FWD_BWD][DIM]; -typedef struct { INTEGER (*nn)[DIM]; } NN2[FWD_BWD][EVEN_ODD]; - -# define Re(z) (z).r -# define Im(z) (z).i - -# define CAT(A, B) A ## B -# define STRCAT(A, B) CAT(A, B) -# define STRCAT3(A, B, C) STRCAT(STRCAT(A, B), C) -# define STRING(s) SSTRING(s) -# define SSTRING(s) #s - -# define ZERO 0.0 -# define ONE 1.0 - -#endif diff --git a/src/include/gamma.h b/src/include/gamma.h new file mode 100644 index 0000000000000000000000000000000000000000..cb681aa0ad72381535be4fc1dee30c4993197eaf --- /dev/null +++ b/src/include/gamma.h @@ -0,0 +1,52 @@ +#/* +#!=============================================================================== +#! +#! gamma.h -- Gamma matrix +#! +#!------------------------------------------------------------------------------- +#! +#! Copyright (C) 2007 Yoshifumi Nakamura +#! +#! This file is part of BQCD -- Berlin Quantum ChromoDynamics program +#! +#! BQCD 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 Foundation, either version 3 of the License, or +#! (at your option) any later version. +#! +#! BQCD is distributed in the hope that it will be useful, +#! but WITHOUT ANY WARRANTY; without even the implied warranty of +#! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +#! GNU General Public License for more details. +#! +#! You should have received a copy of the GNU General Public License +#! along with BQCD. If not, see <http://www.gnu.org/licenses/>. +#! +#!------------------------------------------------------------------------------- +#*/ + + + +# define G0 1 +# define G1 2 +# define G2 3 +# define G3 4 +# define G5 5 +# define G01 6 +# define G02 7 +# define G03 8 +# define G05 9 +# define G15 10 +# define G25 11 +# define G35 12 +# define G12 13 +# define G23 14 +# define G31 15 +# define CGm 16 +# define UNP 17 +# define POL 18 + + +# define Gi 93 +# define G0i 94 +# define Gi5 95 diff --git a/src/init_modules.F90 b/src/init_modules.F90 index 77ed0e79540840a8c6a1a8fd272cdbaddd0a8117..cee71e0fb77a32dc35b61ee5c131a2d5d9ee3e94 100644 --- a/src/init_modules.F90 +++ b/src/init_modules.F90 @@ -30,7 +30,7 @@ subroutine init_modules() call init_module_decomp() call init_module_lattice_io() call init_module_sc_size() - call init_module_sc_size_r4() +!! call init_module_sc_size_r4() call init_module_surface() end diff --git a/src/mc/hmc.F90 b/src/mc/hmc.F90 index 1f9218c66688afa704f4727d71c5531452b3b28a..5b6c0f2beab0854010cbf587e976bb63044f9425 100644 --- a/src/mc/hmc.F90 +++ b/src/mc/hmc.F90 @@ -66,7 +66,7 @@ subroutine hmc(para, conf, out, force_accept, test) use module_input implicit none - type(hmc_para), intent(in) :: para + type(hmc_para), intent(inout) :: para type(hmc_conf), intent(inout) :: conf type(hmc_out), intent(out) :: out integer, intent(in) :: force_accept @@ -74,19 +74,30 @@ subroutine hmc(para, conf, out, force_accept, test) P_GAUGE_FIELD, save :: u_bck !! P_SPINCOL_FIELD, save :: phi_bck - P_GENERATOR_FIELD, save :: p + P_GENERATOR_FIELD, save :: p, p_bck integer :: i - REAL :: sd_old, sd_new, sd_dif + REAL :: sd_old, sd_new, sd_dif REAL :: sf1_old, sf1_new, sf1_dif REAL :: sf2_old, sf2_new, sf2_dif REAL :: sf3_old, sf3_new, sf3_dif - REAL :: sg_old, sg_new, sg_dif - REAL :: sp_old, sp_new, sp_dif - REAL :: hg_old, hg_new, hg_dif - REAL :: h_old, h_new, h_dif + REAL :: sg_old, sg_new, sg_dif + REAL :: sp_old, sp_new, sp_dif + REAL :: hg_old, hg_new, hg_dif + REAL :: h_old, h_new, h_dif + REAL :: sd_old1, sd_new1, sd_dif1 + REAL :: sf1_old1, sf1_new1, sf1_dif1 + REAL :: sf2_old1, sf2_new1, sf2_dif1 + REAL :: sf3_old1, sf3_new1, sf3_dif1 + REAL :: sg_old1, sg_new1, sg_dif1 + REAL :: sp_old1, sp_new1, sp_dif1 + REAL :: hg_old1, hg_new1, hg_dif1 + REAL :: h_old1, h_new1, h_dif1 REAL :: plaq, plaq_old(3), plaq_new(3), rect_old(3), rect_new(3) + REAL :: plaq_new1(3), rect_new1(3) + REAL, save :: replay_threshold REAL, external :: sp, sig, sg + logical :: replayed DEBUG2S("Start HMC") TIMING_START(timing_bin_hmc) @@ -125,6 +136,11 @@ subroutine hmc(para, conf, out, force_accept, test) ALLOCATE_GEN_FIELD(p) ALLOCATE_G_FIELD(u_bck) !! ALLOCATE_SC_FIELD(phi_bck) + if (switches%replay) then + read(input%replay_trick_threshold,*)replay_threshold + nullify(p_bck) + ALLOCATE_GEN_FIELD(p_bck) + endif endif @@ -143,11 +159,9 @@ subroutine hmc(para, conf, out, force_accept, test) TIMING_START(timing_bin_hmc_h_old) ! initialize momenta p, phi, phi2 and old action: -#ifdef ZERO_MOMENTUM - p = 0 -#else call hmc_init_p(p) -#endif + if (switches%boundary_sf) call schr_boundary_p(p) + if (switches%replay) p_bck=p call hmc_init_phi(sf1_old, sf2_old, sf3_old) @@ -168,6 +182,8 @@ subroutine hmc(para, conf, out, force_accept, test) !------------------------------------------------------- calculate Hamiltonian: DEBUG2S("Start calculate Hamiltonian") TIMING_START(timing_bin_hmc_h_new) + + if (switches%boundary_sf) call schr_boundary_p(p) sp_new = sp(p) hg_new = sig(sg_new, plaq_new, rect_new) call clover_action_sum(sd_new) @@ -191,6 +207,117 @@ subroutine hmc(para, conf, out, force_accept, test) if (force_accept /= 0) then out%accepted = 1 + elseif (switches%replay) then + replayed = .false. + if (abs(h_dif) > replay_threshold) then + if (my_pe()==0) then + write(*,*)"replay_trcik: start replay mode" + write(*,*)"replay_trcik: h_dif before replaying =",h_dif + endif + + ! + ! reset integrator + ! + call swap_integer(para%ntau, input%replay_trick_ntau) + call delete_integrator() + call init_hmc(para) + + ! + ! copy back gauge field and initialization + ! + call gauge_copy(gauge(1)%u, u_bck) + gauge(1:size(gauge))%init = .true. + if(associated(stout)) stout(1:size(stout))%init = .true. + if(associated(clover))clover(1:size(clover))%init = .true. + hg_new = ZERO + sg_new = ZERO + sp_new = ZERO + sd_new = ZERO + sf1_new = ZERO + sf2_new = ZERO + sf3_new = ZERO + + ! + ! replay with new ntau + ! + call integrate(p_bck, para, conf, sf1_new, sf2_new, sf3_new) + + sp_new = sp(p_bck) + hg_new = sig(sg_new, plaq_new, rect_new) + call clover_action_sum(sd_new) + h_new = sd_new + sp_new + hg_new + sf1_new + sf2_new + sf3_new + + hg_dif = hg_new - hg_old + sp_dif = sp_new - sp_old + sd_dif = sd_new - sd_old + sf1_dif = sf1_new - sf1_old + sf2_dif = sf2_new - sf2_old + sf3_dif = sf3_new - sf3_old + h_dif = sd_dif + sp_dif + hg_dif + sf1_dif + sf2_dif + sf3_dif + out%exp_dh = exp( - h_dif) + if (my_pe()==0) then + write(*,*)"replay_trcik: replayed h_dif =",h_dif + endif + + + ! + ! reconstruct integrator with normal parameters + ! + call swap_integer(para%ntau, input%replay_trick_ntau) + call delete_integrator() + call init_hmc(para) + + replayed = .true. + endif + + if (ran_number() < out%exp_dh) then + out%accepted = 1 + else + out%accepted = 0 + endif + + if ( replayed ) then + if (out%accepted == 1) then + hg_old1 = hg_new + sp_old1 = sp_new + sd_old1 = sd_new + sf1_old1 = sf1_new + sf2_old1 = sf2_new + sf3_old1 = sf3_new + p_bck = - p_bck + hg_new1 = ZERO + sg_new1 = ZERO + sp_new1 = ZERO + sd_new1 = ZERO + sf1_new1 = ZERO + sf2_new1 = ZERO + sf3_new1 = ZERO + + call integrate(p_bck, para, conf, sf1_new1, sf2_new1, sf3_new1) + + sp_new1 = sp(p_bck) + hg_new1 = sig(sg_new1, plaq_new1, rect_new1) + call clover_action_sum(sd_new1) + h_new1 = sd_new1 + sp_new1 + hg_new1 + sf1_new1 + sf2_new1 + sf3_new1 + + hg_dif1 = hg_new1 - hg_old1 + sp_dif1 = sp_new1 - sp_old1 + sd_dif1 = sd_new1 - sd_old1 + sf1_dif1 = sf1_new1 - sf1_old1 + sf2_dif1 = sf2_new1 - sf2_old1 + sf3_dif1 = sf3_new1 - sf3_old1 + h_dif1 = sd_dif1 + sp_dif1 + hg_dif1 + sf1_dif1 + sf2_dif1 + sf3_dif1 + if (abs(h_dif1) < replay_threshold) then + out%accepted = 0 + if (my_pe()==0) write(*,*)"replay_trcik: reversibility is NOT ok" + else + if (my_pe()==0) write(*,*)"replay_trcik: reversibility is ok" + endif + else + if (my_pe()==0) write(*,*)"replay_trcik, replayed but rejected" + endif + endif + else if (ran_number() < out%exp_dh) then out%accepted = 1 diff --git a/src/mc/hmc_init_p.F90 b/src/mc/hmc_init_p.F90 index e609dce81f6bb0731d5a4beac0778dd07241620c..f49e7f8a43d5bfc29388db12ce09720fbb973198 100644 --- a/src/mc/hmc_init_p.F90 +++ b/src/mc/hmc_init_p.F90 @@ -38,12 +38,16 @@ subroutine hmc_init_p(p) TIMING_START(timing_bin_hmc_init_p) ! ALLOCATE_G_FIELD(tmp) -p=ZERO + p=ZERO do mu = 1, DIM do eo = EVEN, ODD call ran_gauss_volh(NGEN/2, p(1,1,eo,mu), ONE, eo) enddo enddo +#ifdef ZERO_MOMENTUM + p=ZERO +#endif + call nonactive(p) !! for ddhmc diff --git a/src/mc/hmc_test.F90 b/src/mc/hmc_test.F90 index fcefe45cacb5b5826d9a19270248b9f6d75a5276..5ec243b23ba067e11f524329d0d1dfda742abf3f 100644 --- a/src/mc/hmc_test.F90 +++ b/src/mc/hmc_test.F90 @@ -1,10 +1,11 @@ !=============================================================================== ! -! hmc_test.F90 - forward/backward leap frog integration +! hmc_test.F90 - forward/backward integration ! !------------------------------------------------------------------------------- ! ! Copyright (C) 2003 Hinnerk Stueben +! 2010 Yoshifumi Nakamura ! ! This file is part of BQCD -- Berlin Quantum ChromoDynamics program ! @@ -30,6 +31,7 @@ subroutine hmc_test(para, conf) use typedef_hmc use module_function_decl use module_vol + use module_switches implicit none type(hmc_para), intent(inout) :: para @@ -38,6 +40,9 @@ subroutine hmc_test(para, conf) call begin(UREC, "HMCtest") + if (.not. switches%fixtad) & + call die("ERROR hmc_test: non-fix-tadpole imp. is not suitable for HMCtest") + call hmc(para, conf, out, .true., HMC_TEST_FORWARDS) call write_out("forward ") @@ -97,7 +102,7 @@ subroutine hmc_test_report(test, p, u, hp, hg, hf1, hf2, hd) REAL, save :: hf2_start REAL, save :: hd_start - REAL :: diff_p, diff_u + REAL :: diff_p, diff_u, tdiff_p, tdiff_u, tdiff_u1,tmpr, tmpi integer :: i, eo, mu, j, c1, c2 if (.not. associated(p_start)) then @@ -119,12 +124,16 @@ subroutine hmc_test_report(test, p, u, hp, hg, hf1, hf2, hd) diff_p = ZERO diff_u = ZERO + tdiff_p = ZERO + tdiff_u = ZERO + tdiff_u1= ZERO do mu = 1, DIM do eo = EVEN, ODD do i = 1, volh do j = 1, NGEN diff_p = max(diff_p, abs(p_start(j,i,eo,mu) - p(j,i,eo,mu))) + tdiff_p = tdiff_p + (p_start(j,i,eo,mu) - p(j,i,eo,mu))**2 enddo do c2 = 1, NCOL do c1 = 1, NCOL @@ -134,12 +143,22 @@ subroutine hmc_test_report(test, p, u, hp, hg, hf1, hf2, hd) diff_u = max(diff_u, & abs(relative_change(Im(u_start(c1,c2,i,eo,mu)), & Im(u(c1,c2,i,eo,mu))))) + tmpr= Re(u_start(c1,c2,i,eo,mu))-Re(u(c1,c2,i,eo,mu)) + tmpi= Im(u_start(c1,c2,i,eo,mu))-Im(u(c1,c2,i,eo,mu)) + tdiff_u = tdiff_u + tmpr**2 + tmpi**2 + tdiff_u1 =tdiff_u1 + abs(tmpr) + abs(tmpi) enddo enddo enddo enddo enddo + diff_p =global_max(diff_p) + diff_u =global_max(diff_u) + tdiff_p =global_sum(tdiff_p) + tdiff_u =global_sum(tdiff_u) + tdiff_u1=global_sum(tdiff_u1) + if (my_pe() == 0) then write(UREC, *) write(UREC,400) "Configuration changes (maximal abs. relative changes):" @@ -148,6 +167,13 @@ subroutine hmc_test_report(test, p, u, hp, hg, hf1, hf2, hd) write(UREC,410) "Gauge field: ", diff_u write(UREC, *) write(UREC, *) + write(UREC,400) "Configuration changes (total changes):" + write(UREC, *) + write(UREC,410) "Generator field:", tdiff_p + write(UREC,410) "Gauge field:x2 ", tdiff_u + write(UREC,410) "Gauge field:abs ", tdiff_u1 + write(UREC, *) + write(UREC, *) write(UREC,400) "Energy changes:" write(UREC, *) write(UREC,420) "Energy ", "old value", "rel.change" @@ -161,7 +187,7 @@ subroutine hmc_test_report(test, p, u, hp, hg, hf1, hf2, hd) endif 400 format (1x, a) -410 format (1x, a, e8.1) +410 format (1x, a, e15.5) 420 format (1x, a, a20, a12) 430 format (1x, a, e20.10, e12.1) diff --git a/src/mc/hmc_u.F90 b/src/mc/hmc_u.F90 index 5cb11f2e25678d6c18f0500424c05476d30c791b..3d9215891bd75250894654e165aae5ea8119ec84 100644 --- a/src/mc/hmc_u.F90 +++ b/src/mc/hmc_u.F90 @@ -46,7 +46,7 @@ subroutine hmc_integrator_q(p, para, conf, step) call hmc_u(p, conf, step, para) -!! if (switches%boundary_sf) call schr_boundary_gauge(gauged(1)%u) + if (switches%boundary_sf) call schr_boundary_gauge(gauge(1)%u) gauge(1:size(gauge))%init = .true. if (associated(stout)) stout(1:size(stout))%init = .true. diff --git a/src/mc/integrator.F90 b/src/mc/integrator.F90 index 7b0fd3a2a83745ec1bc60875a75e9503bd096c78..d20323e7296a3449a4b52ffae5a4e27d1b077f12 100644 --- a/src/mc/integrator.F90 +++ b/src/mc/integrator.F90 @@ -37,6 +37,7 @@ module module_integrator integer,save :: iscale REAL, save :: len + logical, save :: initialized = .false. end !------------------------------------------------------------------------------- @@ -90,10 +91,10 @@ subroutine init_integrator(traj_length, tau) implicit none REAL, intent(in) :: traj_length, tau - integer,save :: count = 0 +!! integer,save :: count = 0 integer :: i - if (count /= 0 .and. tau > 0 ) return + if (initialized .and. tau > 0 ) return len = traj_length if (tau < 0) len = - len @@ -125,10 +126,24 @@ subroutine init_integrator(traj_length, tau) itraj = 0 iscale = 0 call subintegrator(ONE) - count = count + 1 +!! count = count + 1 + initialized = .true. end +!------------------------------------------------------------------------------- +subroutine delete_integrator() + use module_integrator + implicit none + + deallocate(scale, m_scale, jscale) + deallocate(step, step_p) + deallocate(step_q) + if (associated(step_ppq))deallocate(step_ppq) + deallocate(integrator) + initialized = .false. +end + !------------------------------------------------------------------------------- subroutine subintegrator(fac) use module_integrator diff --git a/src/mc/mc.F90 b/src/mc/mc.F90 index 628f74e652995353415e0252adeec4e6c13db639..88aee9b7169a7460751fe3ed69648cf3fa9806c1 100644 --- a/src/mc/mc.F90 +++ b/src/mc/mc.F90 @@ -44,6 +44,7 @@ subroutine mc(para, conf) use module_counter use module_function_decl use module_switches + use module_input use module_vol implicit none @@ -171,10 +172,16 @@ subroutine mc(para, conf) call traces(para%hmc(i), conf(i), counter%traj, i, j) !! call traces2(counter%traj) endif + +!! if (switches%measure_chemical .and. & +!! mod(counter%traj,input%measure_chemical)==0) call chemical_determinant(counter%traj) + if (switches%measure_schrpcac .and. & + mod(counter%traj,input%measure_schrpcac)==0) call schr_pcac(counter%job, counter%traj) + if (switches%measure_polyakov_loop) & call polyakov_loop(conf(i), counter%traj, i, j) call cooling(conf(i)%u, counter%traj, i, j) - call correlations(para%hmc(i), conf(i), counter%traj, i, j) + call correlations(counter%traj) DEBUG2S("End: measurements") enddo diff --git a/src/measure/Makefile b/src/measure/Makefile index f1f318c73fceefdd7e33693d10e08b80a1a93d10..2f2b5ad809da76f04da09ec5bba762fe7a29915e 100644 --- a/src/measure/Makefile +++ b/src/measure/Makefile @@ -27,13 +27,13 @@ include $(DIR)Makefile.in MODULES_DIR = $(DIR)modules ifdef FPP2 - fpp = $(FPP2) -I$(DIR)include $(MYFLAGS) + fpp = $(FPP2) -I$(DIR)include -I$(DIR)fermi/mult $(MYFLAGS) else - fpp = $(FPP) -I$(DIR)include $(MYFLAGS) + fpp = $(FPP) -I$(DIR)include -I$(DIR)fermi/mult $(MYFLAGS) endif .SUFFIXES: -.SUFFIXES: .a .o .F90 +.SUFFIXES: .a .o .F90 .c .F90.o: $(fpp) $< > $*.f90 @@ -45,20 +45,22 @@ OBJS = \ cooling.o \ traces.o \ traces2.o \ - cdotc_12.o \ - vector12.o \ + gamma.o \ make_source.o \ - reduction_space.o \ correlations.o \ - change_info_file.o + change_info_file.o \ + schr_pcac.o +# dirac_matrix.o determinant.o + +ifdef cuda +OBJS+=cublas_wrap.o +MYFLAGS+= -D_CUDA +endif ifdef libdi #OBJS += chemicalp.o endif - -# correlation_tt.o \ -# correlation_p5p.o \ -# ppp.o +# phmc_read.o \ fast: $(FAST_MAKE) lib_measure.a diff --git a/src/measure/correlation_p5p.F90 b/src/measure/correlation_p5p.F90 deleted file mode 100644 index 30deb988b093d0fe4ca1be29aa5df01f7be85d33..0000000000000000000000000000000000000000 --- a/src/measure/correlation_p5p.F90 +++ /dev/null @@ -1,120 +0,0 @@ -!=============================================================================== -! -! correlation_p5p.F90 - correlation psi_gamma5_psi and psi_gamma5_psi -! -!------------------------------------------------------------------------------- -! -! Copyright (C) 2007 Yoshifumi Nakamura -! -! This file is part of BQCD -- Berlin Quantum ChromoDynamics program -! -! BQCD 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 Foundation, either version 3 of the License, or -! (at your option) any later version. -! -! BQCD is distributed in the hope that it will be useful, -! but WITHOUT ANY WARRANTY; without even the implied warranty of -! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -! GNU General Public License for more details. -! -! You should have received a copy of the GNU General Public License -! along with BQCD. If not, see <http://www.gnu.org/licenses/>. -! -!------------------------------------------------------------------------------- -# include "defs.h" -# include "defs_imp_2p1.h" - -!------------------------------------------------------------------------------- -subroutine correlation_p5p(c_t0t1, & - psi1_e,psi2_e,eta1_e,eta2_e,& - psi1_o,psi2_o,eta1_o,eta2_o) - - use module_vol - implicit none - - COMPLEX, dimension(0:LT-2,0:1),intent(out):: c_t0t1 - SPINCOL_FIELD, intent(in) :: psi1_e, psi2_e, psi1_o, psi2_o - SPINCOL_FIELD, intent(in) :: eta1_e, eta2_e, eta1_o, eta2_o - COMPLEX,dimension(volh) :: psi_e, psi_o, eta_e, eta_o - COMPLEX,dimension(vol ) :: psi, eta ! <--------std - COMPLEX, external :: correlation_tt - COMPLEX :: c - integer :: lt, t0, dis_t0_t1, std_t1, coord(DIM) - - lt = decomp%std%L(4) - nt = decomp%std%N(4) - - call real_coord(coord) - c_t0t1 = ZERO - - call psi_g5_psi(psi_e, psi1_e, psi2_e) - call psi_g5_psi(psi_o, psi1_o, psi2_o) - call psi_g5_psi(eta_e, eta1_e, eta2_e) - call psi_g5_psi(eta_o, eta1_o, eta2_o) - call reduction_eo_std(psi, psi_e, psi_o) - call reduction_eo_std(eta, eta_e, eta_o) - - - do dd = 0, lt - 2 - do it = 0, lt - 1 - jt = it + dd - do ix = 0, lx - 1 - do iy = 0, ly - 1 - do iz = 0, lz - 1 - do jx = 0, lx - 1 - do jy = 0, ly - 1 - do jz = 0, lz - 1 - - in1(ix,iy,iz,it)*in1(jx,jy,jz,jt) - - - - - - - do dis_t0_t1 = 0, lt - 2 - do t0 = 0, nt - 1 - - - std_t1 = coord(4) + t0 + dis_t0_t1 - c = correlation_tt(t0, dis_t0_t1, psi, eta) - if (std_t1 < L(4)) then - c_t0t1(dis_t0_t1,0) = c_t0t1(dis_t0_t1,0) + c - else - c_t0t1(dis_t0_t1,1) = c_t0t1(dis_t0_t1,1) + c - endif - enddo - c_t0t1(dis_t0_t1,0) = c_t0t1(dis_t0_t1,0) / dble( LT - dis_t0_t1 ) - if (dis_t0_t1 /= 0) then - c_t0t1(dis_t0_t1,1) = c_t0t1(dis_t0_t1,1) / dble( dis_t0_t1 ) - endif - enddo - -end - -!------------------------------------------------------------------------------- -subroutine psi_g5_psi(p5p,psi1,psi2) - - use module_vol - use module_p_interface - implicit none - SPINCOL_FIELD, intent(in) :: psi1, psi2 - COMPLEX,dimension(volh),intent(out) :: p5p - P_SPINCOL_FIELD, save :: tmp - COMPLEX, external :: cdotc_12 - integer :: i - - ALLOCATE_SC_FIELD(tmp) - - tmp=psi2 - call gamma5(tmp,volh) - - !$omp parallel do - do i = 1, volh - p5p(i) = cdotc_12(psi1(1,1,i), tmp(1,1,i)) - enddo - -end - -!=============================================================================== diff --git a/src/measure/correlations.F90 b/src/measure/correlations.F90 index f64ddb86eb5688dc70909c5f2398dbbb0de12f9d..fb76e4f1beb36122ae79f1501924d45fb6cd83aa 100644 --- a/src/measure/correlations.F90 +++ b/src/measure/correlations.F90 @@ -23,9 +23,394 @@ ! !------------------------------------------------------------------------------- # include "defs.h" +# include "gamma.h" !------------------------------------------------------------------------------- -subroutine correlations(para, conf, traj, i_ensemble1, i_ensemble2) +module hadron_corr + implicit none + integer, save :: n_mom=1 + type quark_prop + COMPLEX, dimension(:,:,:,:,:,:), pointer :: g + end type + + type(quark_prop), dimension(:),pointer,save :: qprop + +end + +!------------------------------------------------------------------------------- +subroutine correlations(traj) + use module_field + use module_action + use module_input + use hadron_corr + use module_vol + use module_switches + implicit none + integer, intent(in) :: traj + integer :: fid, mid, src_at(4) + + if (.not. switches%measure_correlations) return + call gamma_init() + fid = input%hmc_mpf_mass + mid = action%fermi(fid)%mid1 + + allocate(qprop(1)) + allocate(qprop(1)%g(4,4,3,3,volh, EVEN:ODD)) + + src_at = (/2, 2, 2, 11/) + + call get_qprop(qprop(1), mid, LOCAL_SOURCE, src_at) + call meson(qprop(1), qprop(1)) + call baryon(qprop(1),qprop(1),qprop(1)) +end + +!------------------------------------------------------------------------------- +subroutine meson(qprop0, qprop1) ! full meason prop + use gamma + use hadron_corr + use module_lattice + use module_function_decl + implicit none + type(quark_prop), intent(in) :: qprop0, qprop1 + COMPLEX, dimension(DIM, DIM, DIM, DIM, n_mom, 0:lt-1) :: meason_corr + integer :: is1, is2, is3, is4, ic1, ic2, ix,iy,iz,it, j(4), coord(4), ii, eo, imom, igop1, igop2 + COMPLEX :: ctmp, c_local(n_mom), pexp_fac_c, m_corr(0:lt-1,n_mom), g1(4,4), g2(4,4) + integer, external :: e_o, std_xyzt2i + + pexp_fac_c=ONE + call pe2coord(my_pe(), coord) + + meason_corr = 0 + + do is1 = 1, 4 + do is2 = 1, 4 + do is3 = 1, 4 + do is4 = 1, 4 + do it = 0, nt-1 + c_local(:) = 0 + do iz = 0, nz-1 + do iy = 0, ny-1 + do ix = 0, nx-1 + ctmp = 0 + j = (/ix, iy, iz, it/) + ii = std_xyzt2i(j) + eo = e_o(j) + do ic1 = 1, 3 + do ic2 = 1, 3 + ctmp = ctmp + qprop0%g(is1,is2,ic1,ic2,ii,eo) & + * conjg(qprop1%g(is4,is3,ic1,ic2,ii,eo)) + enddo + enddo + do imom = 1, n_mom +!! c_local(imom) = c_local(imom) + pexp_fac_c(imom,ix,iy,iz) * ctmp + c_local(imom) = c_local(imom) + pexp_fac_c * ctmp + enddo + enddo + enddo + enddo + meason_corr(is1,is2,is3,is4,1:n_mom, it + nt*coord(4) ) = c_local(1:n_mom) + enddo + enddo ! is4 + enddo ! is3 + enddo ! is2 + enddo ! is1 + + + + call global_sum_vec(256*n_mom*lt *2, meason_corr) + +!! do igop1 = 1, ngop +!! do igop2 = 1, ngop + do igop1 = 5, 5 + do igop2 = 5, 5 + call spin_mul(g1, gamma_op(G5)%c, gamma_op(igop1)%c) ! gop1 = gamma5 * gop1 + call spin_mul(g2, gamma_op(igop2)%c, gamma_op(G5)%c) ! gop2 = gop2 * gamma5 + do imom = 1, n_mom + do it = 0, lt - 1 + ctmp=0 + do is1 = 1, 4 + do is2 = 1, 4 + do is3 = 1, 4 + do is4 = 1, 4 + if (g1(is4, is1) /= 0 .and. g2(is2, is3) /= 0) then + ctmp= ctmp + g1(is4, is1) * g2(is2, is3) * meason_corr(is1,is2,is3,is4, imom, it) + endif + enddo + enddo + enddo + enddo + m_corr(it, imom) = ctmp + enddo + enddo + write(*,*)igop1, igop2 + do it = 0, lt-1 + write(*,*)m_corr(it, 1) + enddo + enddo + enddo + +end + +!------------------------------------------------------------------------------- +subroutine baryon(qp1, qp2, qp3) ! full baryon prop + use gamma + use hadron_corr + use module_lattice + use module_function_decl + implicit none + type(quark_prop), intent(in) :: qp1, qp2, qp3 + COMPLEX, dimension(n_mom, 0:lt-1) :: baryon_corr + integer :: ix,iy,iz,it, j(4), coord(4), ii, eo, imom, c1, c2 + COMPLEX :: ctmp, s_local(n_mom,0:nt-1), pexp_fac_c, b_corr(0:lt-1,n_mom) + COMPLEX, dimension(4,4,3,3) :: g_aap, g_bbp, g_ccp, tmp1, tmp2, tmp3 + COMPLEX, dimension(4,4) :: tt0 + integer, external :: e_o, std_xyzt2i + COMPLEX, external :: tracespin2 + + pexp_fac_c=ONE + call pe2coord(my_pe(), coord) + + baryon_corr = 0 + + do it = 0, nt-1 + do iz = 0, nz-1 + do iy = 0, ny-1 + do ix = 0, nx-1 + + j = (/ix, iy, iz, it/) + ii = std_xyzt2i(j) + eo = e_o(j) + g_aap = qp1%g(:,:,:,:,ii,eo) + g_bbp = qp2%g(:,:,:,:,ii,eo) + g_ccp = qp3%g(:,:,:,:,ii,eo) + + do c1=1, NCOL + do c2=1, NCOL + call spin_mul( tmp1(1,1,c1,c2), g_bbp(1,1,c1,c2), gamma_op(G31)%c) + call spin_mul( tmp2(1,1,c1,c2), gamma_op(G31)%c, g_bbp(1,1,c1,c2)) + enddo + enddo + call contraction13(tmp3, tmp1, tmp2) + + call tracecol1(tt0 , g_aap, tmp3) + ctmp = tracespin2(gamma_op(POL)%c,tt0) + call tracecol2(tt0 , g_aap, tmp3) + ctmp = ctmp + tracespin2(gamma_op(POL)%c,tt0) + + do imom = 1, n_mom +!!! s_local(imom,it) = s_local(imom,it) + ctmp * epsi_epsip * pexp_fac_c(imom,ix,iy,iz) + s_local(imom,it) = s_local(imom,it) + ctmp * pexp_fac_c + enddo + enddo + enddo + enddo + baryon_corr(:,it+nt*coord(4)) = s_local(:,it) + enddo + + call global_sum_vec(n_mom*lt *2, baryon_corr) + + do imom = 1, n_mom + do it = 0, lt - 1 + b_corr(it, imom) = baryon_corr(imom,it) + enddo + enddo + + write(*,*)"Baryon" + do it = 0, lt-1 + write(*,*)b_corr(it, 1) + enddo +end + +!------------------------------------------------------------------------------- +!!subroutine baryon(qp1, qp2, qp3) ! full baryon prop +!! use gamma +!! use hadron_corr +!! use module_lattice +!! use module_function_decl +!! implicit none +!! type(quark_prop), intent(in) :: qp1, qp2, qp3 +!! COMPLEX, dimension(DIM, DIM, n_mom, 0:lt-1) :: baryon_corr +!! integer :: is1, is2, is3, is4, ic1, ic2, ix,iy,iz,it, j(4), coord(4), ii, eo, imom, epsi_l, epsi_lp, a, b,c ,ap,bp,cp, epsi, epsi_epsip +!! COMPLEX :: ctmp, s_local(4,4,n_mom,0:nt-1), pexp_fac_c, b_corr(0:lt-1,n_mom) +!! COMPLEX, dimension(4,4) :: g_aap, g_bbp, g_ccp, g_bbpccp, g_aapbbpccp, tmp +!! integer, external :: e_o, std_xyzt2i +!! COMPLEX, external :: spintr +!! COMPLEX, external :: tracespin2 +!! pexp_fac_c=ONE +!! call pe2coord(my_pe(), coord) +!! +!! baryon_corr = 0 +!! +!! do it = 0, nt-1 +!! do epsi_l = 0, 1 +!! do a = 1, NCOL +!! b = mod(a+epsi_l , NCOL) + 1 +!! c = mod(a-epsi_l+1, NCOL) + 1 +!! epsi = (1-2*epsi_l) +!! do epsi_lp = 0, 1 +!! do ap = 1, NCOL +!! bp = mod(ap+epsi_lp , NCOL) + 1 +!! cp = mod(ap-epsi_lp+1, NCOL) + 1 +!! epsi_epsip = epsi*(1-2*epsi_lp) +!! +!! do iz = 0, nz-1 +!! do iy = 0, ny-1 +!! do ix = 0, nx-1 +!! +!! j = (/ix, iy, iz, it/) +!! ii = std_xyzt2i(j) +!! eo = e_o(j) +!! g_aap = qp1%g(:,:,a,ap,ii,eo) +!! g_bbp = qp2%g(:,:,b,bp,ii,eo) +!! g_ccp = qp3%g(:,:,c,cp,ii,eo) +!! call g31xg31t(tmp, g_bbp) +!! call spin_mul(g_bbpccp, tmp, g_ccp) +!! call spin_mul(g_aapbbpccp, g_aap, g_bbpccp) +!! tmp = spintr(g_bbpccp) * g_aap + g_aapbbpccp +!! +!! do imom = 1, n_mom +!!!!! s_local(:,:,imom,it) = s_local(:,:,imom,it) + tmp * epsi_epsip * pexp_fac_c(imom,ix,iy,iz) +!! s_local(:,:,imom,it) = s_local(:,:,imom,it) + tmp * epsi_epsip * pexp_fac_c +!! enddo +!! +!! +!! enddo +!! enddo +!! enddo +!! enddo +!! enddo +!! enddo +!! enddo +!! baryon_corr(:,:,:,it+nt*coord(4)) = s_local(:,:,:,it) +!! enddo +!! +!! call global_sum_vec(16*n_mom*lt *2, baryon_corr) +!! +!! do imom = 1, n_mom +!! do it = 0, lt - 1 +!!!! b_corr(it, imom) = spintr(baryon_corr(1,1,imom,it)) +!! b_corr(it, imom) = tracespin2(gamma_op(UNP)%c, baryon_corr(1,1,imom,it)) +!! enddo +!! enddo +!! write(*,*)"Baryon" +!! do it = 0, lt-1 +!! write(*,*)b_corr(it, 1) +!! enddo +!! +!! +!!end + +!------------------------------------------------------------------------------- +subroutine get_qprop(qprop0, mid, source_type, src_at) + use hadron_corr + use module_vol + implicit none + type(quark_prop), intent(out) :: qprop0 + integer, intent(in) :: mid, source_type, src_at(4) + SPINCOL_FIELD :: inp_e, inp_o, out_e, out_o + integer :: is, ic + + call init_quark(mid) + call make_source_local(inp_e, inp_o, src_at) + call make_quark_source(qprop0%g(1,1,1,1,1,0), qprop0%g(1,1,1,1,1,1), inp_e, inp_o) + + do ic = 1, 3 + do is = 1, 4 + call get_quark_source(inp_e, inp_o, qprop0%g(1,1,1,1,1,0), qprop0%g(1,1,1,1,1,1), is, ic) + call solve(mid, out_e, out_o, inp_e, inp_o) + call put_quark_source(qprop0%g(1,1,1,1,1,0), qprop0%g(1,1,1,1,1,1), out_e, out_o, is, ic) + enddo + enddo + +end + +!------------------------------------------------------------------------------- +subroutine contraction13(qout, q1, q2) + implicit none + COMPLEX, dimension(4,4,3,3) :: qout, q1, q2 + integer :: i, j, k, ip, jp, kp, ieps, jeps, eps1, eps2 + integer :: a, b, c + + qout=ZERO + do ieps = 0, 1 + do i = 1, NCOL + j = mod(i + ieps , NCOL) + 1 + k = mod(i - ieps+1, NCOL) + 1 + eps1 = (1-2*ieps) + do jeps = 0, 1 + do ip = 1, NCOL + jp = mod(ip + jeps , NCOL) + 1 + kp = mod(ip - jeps+1, NCOL) + 1 + eps2 = (1-2*jeps) + + do a =1, DIM + do b =1, DIM + do c =1, DIM + qout(a,b,kp,k) = qout(a,b,kp,k) & + + eps1 * eps2 * q1(c,a,i,ip) * q2(c,b,j,jp) + enddo + enddo + enddo + enddo + enddo + enddo + enddo +end + +!------------------------------------------------------------------------------- +subroutine tracecol1(qout, q1, q2) ! traceColor (q1 * traceSpin(q2)) + implicit none + COMPLEX, dimension(4,4) :: qout + COMPLEX, dimension(4,4,3,3) :: q1, q2 + COMPLEX :: tmp + integer :: i, j + + qout=ZERO + do i = 1, NCOL + do j = 1, NCOL + tmp = q2(1,1,j,i)+q2(2,2,j,i)+q2(3,3,j,i)+q2(4,4,j,i) + qout(:,:) = qout(:,:) + q1(:,:,i,j) * tmp + enddo + enddo +end + +!------------------------------------------------------------------------------- +subroutine tracecol2(qout, q1, q2) ! traceColor (q1 * q2) + implicit none + COMPLEX, dimension(4,4) :: qout + COMPLEX, dimension(4,4,3,3) :: q1, q2 + integer :: i, j + + qout=ZERO + do i = 1, NCOL + do j = 1, NCOL + qout(:,:) = qout(:,:) + q1(:,:,i,j) * q2(:,:,j,i) + enddo + enddo +end + +!------------------------------------------------------------------------------- +COMPLEX function tracespin2(q1, q2) ! traceSpin (q1 * q2) + implicit none + COMPLEX, dimension(4,4) :: q1, q2 + COMPLEX :: tmp + integer :: i, j + + tmp=ZERO + do i = 1, DIM + do j = 1, DIM + tmp = tmp + q1(i,j) * q2(j,i) + enddo + enddo + tracespin2 = tmp +end + +!------------------------------------------------------------------------------- +!------------------------------------------------------------------------------- +! +! this subroutine is for cross check, for Dirk's analysis code for theta +! +subroutine quark_prop_test(para, conf, traj, i_ensemble1, i_ensemble2) use module_field use module_action @@ -127,3 +512,109 @@ subroutine correlations(para, conf, traj, i_ensemble1, i_ensemble2) end !=============================================================================== +!=============================================================================== +! +! copy form old version vector12.F90 +! +!------------------------------------------------------------------------------- +! +! Copyright (C) 2007 Yoshifumi Nakamura +! +! This file is part of BQCD -- Berlin Quantum ChromoDynamics program +! +! BQCD 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 Foundation, either version 3 of the License, or +! (at your option) any later version. +! +! BQCD is distributed in the hope that it will be useful, +! but WITHOUT ANY WARRANTY; without even the implied warranty of +! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +! GNU General Public License for more details. +! +! You should have received a copy of the GNU General Public License +! along with BQCD. If not, see <http://www.gnu.org/licenses/>. +! +!------------------------------------------------------------------------------- +# include "defs.h" + +!------------------------------------------------------------------------------- +subroutine global_sum_vector12(sc,in_e,in_o) + + use module_function_decl + use module_vol + implicit none + COMPLEX, dimension(DIM,NCOL), intent(out) :: sc + SPINCOL_FIELD, intent(in) :: in_e, in_o + COMPLEX :: tmp + REAL :: re, im + integer :: i, mu, c + + do c = 1, 3 + do mu = 1, 4 + tmp = ZERO + !$omp parallel do reduction(+: tmp) + do i = 1, volh + tmp = tmp + in_e(mu,c,i) + enddo + !$omp parallel do reduction(+: tmp) + do i = 1, volh + tmp = tmp + in_o(mu,c,i) + enddo + re = global_sum(dble(tmp)) + im = global_sum(dimag(tmp)) + sc(mu,c) = cmplx( re, im, kind = RKIND) + enddo + enddo + +end + +!------------------------------------------------------------------------------- +subroutine write_vector12_0000_sum(in_e,in_o,name) + + use module_function_decl + use module_vol + implicit none + SPINCOL_FIELD, intent(in) :: in_e, in_o + character( len = 6), intent(in) :: name + + COMPLEX, dimension(DIM,NCOL) :: sc + character( len = 10) :: name1, name2 + + call global_sum_vector12(sc, in_e, in_o) + + write(name1,10)name,"0000" + write(name2,10)name,"_sum" + + call write_vector12(0, in_e(1,1,1), name1) + call write_vector12(0, sc, name2) + +10 format (2a) + +end + +!------------------------------------------------------------------------------- +subroutine write_vector12(pe,sc,name) + + use module_function_decl + implicit none + COMPLEX, dimension(DIM,NCOL), intent(in) :: sc + integer, intent(in) :: pe + character( len = 10) :: name + integer :: mu, c + + + if (my_pe() == pe) then + do c = 1, 3 + do mu = 1, 4 + write(*,100)"%%%",name,& + my_pe(),mu,c,dble(sc(mu,c)),dimag(sc(mu,c)) + enddo + enddo + endif + +100 format (1x, 2a, 3i3, 2ES17.7) + +end + +!=============================================================================== diff --git a/src/measure/cublas_wrap.c b/src/measure/cublas_wrap.c new file mode 100644 index 0000000000000000000000000000000000000000..7d890c3fea815c8f08b286fa409a402fe3afe3e0 --- /dev/null +++ b/src/measure/cublas_wrap.c @@ -0,0 +1,346 @@ +/* +!=============================================================================== +! +! cublas_wrap.c - cuda version for some lapack functions +! +!------------------------------------------------------------------------------- +! +! Copyright (C) 2011 Yoshifumi Nakamura +! +! This file is part of BQCD -- Berlin Quantum ChromoDynamics program +! +! BQCD 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 Foundation, either version 3 of the License, or +! (at your option) any later version. +! +! BQCD is distributed in the hope that it will be useful, +! but WITHOUT ANY WARRANTY; without even the implied warranty of +! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +! GNU General Public License for more details. +! +! You should have received a copy of the GNU General Public License +! along with BQCD. If not, see <http://www.gnu.org/licenses/>. +! +!------------------------------------------------------------------------------- +*/ +#ifdef NamesToLower +# define ZMINV_NV zminv_nv +# define ZGETF2_NV zgetf2_nv +# define ZGEMM_NV zgemm_nv +#endif +#ifdef NamesToLower_ +# define ZMINV_NV zminv_nv_ +# define ZGETF2_NV zgetf2_nv_ +# define ZGEMM_NV zgemm_nv_ +#endif +#ifdef NamesToLower__ +# define ZMINV_NV zminv_nv__ +# define ZGETF2_NV zgetf2_nv__ +# define ZGEMM_NV zgemm_nv__ +#endif + +#include <cublas.h> +#include <stdio.h> +#define min(a, b) ((a) < (b) ? (a) : (b)) + +void ZMINV_NV(const int* m, const int* n, const double* A, const int* lda, + int* ipiv, int* info){ + + // printf ("now zminv_nv_ started\n"); + + int stat, i; + cuDoubleComplex *devA, *devW, *zero; + cuDoubleComplex mone, one, tmp, ttmp; + one=make_cuDoubleComplex( 1, 0); + mone=make_cuDoubleComplex(-1, 0); + + zero=( cuDoubleComplex * )malloc(*n *16); + for (i=0; i< *n; i++){ zero[i]=make_cuDoubleComplex( 0, 0);} + + + *info=0; + stat = cublasInit(); + if (stat != CUBLAS_STATUS_SUCCESS) { + printf ("cublasInit failed"); + *info =1; + return; + } + + int mm=(*m); + int nn=(*n); + int size=mm * nn; + + stat = cublasAlloc (size, 16, (void**)&devA); + if (stat != CUBLAS_STATUS_SUCCESS) { + printf ("device memory allocation failed %d %d\n",stat,size); + cublasShutdown(); + *info=1; + return; + } + stat = cublasAlloc (nn, 16, (void**)&devW); + if (stat != CUBLAS_STATUS_SUCCESS) { + printf ("device memory allocation failed %d %d\n",stat,nn); + cublasShutdown(); + *info=1; + return; + } + cublasSetMatrix(*m, *n, 16, A, *n, devA, *m); + +//ZGETF2 start + int j, j0n, j1n, jp; + for (j=0; j<min(mm,nn); j++) { + j0n= j * nn; + j1n= (j+1) * nn; + jp = j - 1 + cublasIzamax( mm-j, &devA[ j+j0n ], 1 ) ; + + ipiv[ j ] = jp + 1 ; + // if (j0n+j >= nn*mm || j0n+j <0){printf ("zgetf2_nv_ j0n+j =%d \n",j0n+j );exit;} + // if (j0n+jp >= nn*mm || j0n+jp <0){printf ("zgetf2_nv_ j0n+jp =%d \n",j0n+jp );exit;} + // if (j >= nn*mm || j <0){printf ("zgetf2_nv_ j =%d \n",j );exit;} + // if (jp >= nn*mm || jp <0){printf ("zgetf2_nv_ jp =%d \n",jp );exit;} + + cublasGetMatrix(1, 1, 16, &devA[ j0n+jp ], 1, (void*)&tmp, 1); + + if(!( tmp.x == 0.0d && tmp.y == 0.0d) ) { + if( jp != j) cublasZswap(nn, &devA[ j ], *lda, &devA[ jp ], *lda); + cublasGetMatrix(1, 1, 16, &devA[j0n+j], 1, (void*)&tmp, 1); + ttmp = cuCdiv(one , tmp); + if( j < mm-1) cublasZscal(mm-j-1, ttmp, &devA[ j+1+j0n], 1); + } else if( *info == 0 ) { + printf ("zgetf2_nv_ tmp=0 at j=%d\n",j); + *info = j; + } + if ( j < min(mm,nn)-1) + cublasZgeru( mm-j-1, nn-j-1, mone, &devA[ j+1+j0n ], 1, &devA[ j+j1n ], *lda, &devA[ j+1+j1n ], *lda); + //ZGERU( M-J, N-J, -ONE, A( J+1, J ), 1, A( J, J+1 ), LDA, A( J+1, J+1 ), LDA ) + } +//ZGETF2 end + +//ZTRTI2 for Upper & No-unit start + for (j=0;j<nn;j++) { + j0n= j * nn; + cublasGetMatrix(1, 1, 16, &devA[j0n+j], 1, (void*)&tmp, 1); + ttmp = cuCdiv(one , tmp); + cublasSetMatrix(1, 1, 16, (void*)&ttmp, 1, &devA[j0n+j], 1); + ttmp.x = -ttmp.x; + ttmp.y = -ttmp.y; + cublasZtrmv('U','N', 'N', j, devA, *lda, &devA[j0n],1); + cublasZscal( j, ttmp, &devA[j0n],1); + } +//ZTRTI2 for Upper & No-unit end + +//=============================================================== +//ZGETRI unblocked start + for (j=nn-1;j>=0;j--) { + j0n= j * nn; + j1n= (j+1) * nn; + if (j!=nn-1)cublasZcopy(nn-j-1, &devA[j0n+j+1], 1, devW, 1); + if (j!=nn-1)cublasSetVector(nn-j-1, 16, zero, 1, &devA[j0n+j+1], 1); + if( j < nn-1 ) + cublasZgemv('N', nn, nn-j-1, mone, &devA[j1n], *lda, devW, 1, one, &devA[ j0n],1); + } +//ZGETRI unblocked end + +// interchange + for (j=nn-2;j>=0;j--) { + jp=ipiv[j]-1; + if (jp != j) cublasZswap(nn, &devA[j*nn],1, &devA[jp*nn],1); + } + + free(zero); + cublasGetMatrix(*m, *n, 16, devA, *n, (void*)A, *m); + stat = cublasFree(devA); + if (stat != CUBLAS_STATUS_SUCCESS) { + printf ("cublasFree failed"); + *info =1; + return; + } + + stat = cublasFree(devW); + if (stat != CUBLAS_STATUS_SUCCESS) { + printf ("cublasFree failed"); + *info =1; + return; + } + + cublasShutdown(); + //if (stat != CUBLAS_STATUS_SUCCESS) { + // printf ("cublasShutdown failed"); + // *info =1; + // return; + // } + //fflush(stdout); +} + + +void ZGETF2_NV(const int* m, const int* n, const double* A, const int* lda, + int* ipiv, int* info){ + int stat, i; + cuDoubleComplex *devA, *devW, *zero; + cuDoubleComplex mone, one, tmp, ttmp; + one=make_cuDoubleComplex( 1, 0); + mone=make_cuDoubleComplex(-1, 0); + + zero=( cuDoubleComplex * )malloc(*n *16); + for (i=0; i< *n; i++){ zero[i]=make_cuDoubleComplex( 0, 0);} + + + *info=0; + stat = cublasInit(); + if (stat != CUBLAS_STATUS_SUCCESS) { + printf ("cublasInit failed"); + *info =1; + return; + } + + int mm=(*m); + int nn=(*n); + int size=mm * nn; + + stat = cublasAlloc (size, 16, (void**)&devA); + if (stat != CUBLAS_STATUS_SUCCESS) { + printf ("device memory allocation failed %d %d\n",stat,size); + cublasShutdown(); + *info=1; + return; + } + stat = cublasAlloc (nn, 16, (void**)&devW); + if (stat != CUBLAS_STATUS_SUCCESS) { + printf ("device memory allocation failed %d %d\n",stat,nn); + cublasShutdown(); + *info=1; + return; + } + cublasSetMatrix(*m, *n, 16, A, *n, devA, *m); + +//ZGETF2 start + int j, j0n, j1n, jp; + for (j=0; j<min(mm,nn); j++) { + j0n= j * nn; + j1n= (j+1) * nn; + jp = j - 1 + cublasIzamax( mm-j, &devA[ j+j0n ], 1 ) ; + + ipiv[ j ] = jp + 1 ; + // if (j0n+j >= nn*mm || j0n+j <0){printf ("zgetf2_nv_ j0n+j =%d \n",j0n+j );exit;} + // if (j0n+jp >= nn*mm || j0n+jp <0){printf ("zgetf2_nv_ j0n+jp =%d \n",j0n+jp );exit;} + // if (j >= nn*mm || j <0){printf ("zgetf2_nv_ j =%d \n",j );exit;} + // if (jp >= nn*mm || jp <0){printf ("zgetf2_nv_ jp =%d \n",jp );exit;} + + cublasGetMatrix(1, 1, 16, &devA[ j0n+jp ], 1, (void*)&tmp, 1); + + if(!( tmp.x == 0.0d && tmp.y == 0.0d) ) { + if( jp != j) cublasZswap(nn, &devA[ j ], *lda, &devA[ jp ], *lda); + cublasGetMatrix(1, 1, 16, &devA[j0n+j], 1, (void*)&tmp, 1); + ttmp = cuCdiv(one , tmp); + if( j < mm-1) cublasZscal(mm-j-1, ttmp, &devA[ j+1+j0n], 1); + } else if( *info == 0 ) { + printf ("zgetf2_nv_ tmp=0 at j=%d\n",j); + *info = j; + } + if ( j < min(mm,nn)-1) + cublasZgeru( mm-j-1, nn-j-1, mone, &devA[ j+1+j0n ], 1, &devA[ j+j1n ], *lda, &devA[ j+1+j1n ], *lda); + //ZGERU( M-J, N-J, -ONE, A( J+1, J ), 1, A( J, J+1 ), LDA, A( J+1, J+1 ), LDA ) + } +//ZGETF2 end + + free(zero); + cublasGetMatrix(*m, *n, 16, devA, *n, (void*)A, *m); + stat = cublasFree(devA); + if (stat != CUBLAS_STATUS_SUCCESS) { + printf ("cublasFree failed"); + *info =1; + return; + } + + stat = cublasFree(devW); + if (stat != CUBLAS_STATUS_SUCCESS) { + printf ("cublasFree failed"); + *info =1; + return; + } + cublasShutdown(); +} + + +//================================================================================ + void ZGEMM_NV(const char *transa, const char *transb, const int *m, + const int *n, const int *k, const cuDoubleComplex *alpha, + const cuDoubleComplex *A, const int *lda, + const cuDoubleComplex *B, const int *ldb, + const cuDoubleComplex *beta, const cuDoubleComplex *C, + const int *ldc, int *info) + +{ + // printf ("now zgemm_nv_ started\n"); + + cuDoubleComplex *devA, *devB, *devC ; + int size=(int)(*m) * (int)(*n) ; + int stat; + + *info=0; + cublasInit(); + //if (stat != CUBLAS_STATUS_SUCCESS) { + // printf ("cublasInit failed"); + // *info =1; + // return; + //} + + stat = cublasAlloc (size, 16, (void**)&devA); + if (stat != CUBLAS_STATUS_SUCCESS) { + printf ("device memory allocation failed %d %d\n",stat,size); + *info =1; + return; + } + stat = cublasAlloc (size, 16, (void**)&devB); + if (stat != CUBLAS_STATUS_SUCCESS) { + printf ("device memory allocation failed %d %d\n",stat,size); + *info =1; + return; + } + stat = cublasAlloc (size, 16, (void**)&devC); + if (stat != CUBLAS_STATUS_SUCCESS) { + printf ("device memory allocation failed %d %d\n",stat,size); + *info =1; + return; + } + // printf ("cublasAlloc done\n"); + + cublasSetMatrix(*m, *n, 16, A, *n, devA, *m); + cublasSetMatrix(*m, *n, 16, B, *n, devB, *m); + + // cublasSetMatrix(*m, *n, 16, C, *n, devC, *m); + // printf ("cublasSetMatrix done\n"); + + cublasZgemm (transa[0], transb[0], *m, *n, *k, *alpha, devA, *lda, devB, *ldb, *beta, devC, *ldc); + // cublasZgemm (transa[0], transb[0], *m, *n, *k, *alpha, devA, *lda, devB, *ldb, *beta, devC, *ldc); + + cublasGetMatrix(*m, *n, 16, devC, *n, (void*)C, *m); + // printf ("cublasGetMatrix done\n"); + + stat = cublasFree(devA); + if (stat != CUBLAS_STATUS_SUCCESS) { + printf ("cublasFree failed"); + *info =1; + return; + } + stat = cublasFree(devB); + if (stat != CUBLAS_STATUS_SUCCESS) { + printf ("cublasFree failed"); + *info =1; + return; + } + stat = cublasFree(devC); + if (stat != CUBLAS_STATUS_SUCCESS) { + printf ("cublasFree failed"); + *info =1; + return; + } + + cublasShutdown(); + //if (stat != CUBLAS_STATUS_SUCCESS) { + // printf ("cublasShutdown failed"); + // *info =1; + // return; + //} +} diff --git a/src/measure/desc.h b/src/measure/desc.h new file mode 100644 index 0000000000000000000000000000000000000000..89c1cc40d36accd744aa690ba457af1bf342c74e --- /dev/null +++ b/src/measure/desc.h @@ -0,0 +1,5 @@ +INTEGER BLOCK_CYCLIC_2D, CSRC_, CTXT_, DLEN_, DTYPE_, & + LLD_, MB_, M_, NB_, N_, RSRC_ +PARAMETER ( BLOCK_CYCLIC_2D = 1, DLEN_ = 9, DTYPE_ = 1, & + CTXT_ = 2, M_ = 3, N_ = 4, MB_ = 5, NB_ = 6, & + RSRC_ = 7, CSRC_ = 8, LLD_ = 9 ) diff --git a/src/measure/dirac_matrix.F90 b/src/measure/dirac_matrix.F90 new file mode 100644 index 0000000000000000000000000000000000000000..d26246231db056a58f9a598de223777d56233271 --- /dev/null +++ b/src/measure/dirac_matrix.F90 @@ -0,0 +1,739 @@ +!=============================================================================== +! +! dirac_matrix.F90 +! +! make Dirac operator as matrix form, +! matrix shape for parallel computing is (12, volume/NPE, 12, volume) +! +!------------------------------------------------------------------------------- +! +! Copyright (C) 2011 Yoshifumi Nakamura +! +! This file is part of BQCD -- Berlin Quantum ChromoDynamics program +! +! BQCD 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 Foundation, either version 3 of the License, or +! (at your option) any later version. +! +! BQCD is distributed in the hope that it will be useful, +! but WITHOUT ANY WARRANTY; without even the implied warranty of +! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +! GNU General Public License for more details. +! +! You should have received a copy of the GNU General Public License +! along with BQCD. If not, see <http://www.gnu.org/licenses/>. +! +!------------------------------------------------------------------------------- +# include "defs.h" + +!------------------------------------------------------------------------------- +module module_dirac_matrix + implicit none + COMPLEX,dimension(4,4),save :: proj_1_p_gamma1, proj_1_m_gamma1 + COMPLEX,dimension(4,4),save :: proj_1_p_gamma2, proj_1_m_gamma2 + COMPLEX,dimension(4,4),save :: proj_1_p_gamma3, proj_1_m_gamma3 + COMPLEX,dimension(4,4),save :: proj_1_p_gammac, proj_1_m_gammac + COMPLEX,dimension(4,4),save :: proj_1_p_gamman, proj_1_m_gamman + + integer, pointer, save :: ieo2_around_i(:,:,:) + integer, pointer, save :: ieo2_around_is(:,:,:) + integer, pointer, save :: ieo2_around_it(:,:,:) +end module + +!------------------------------------------------------------------------------- +subroutine checkmat(id) + use module_field + use module_action + use module_vol + implicit none + integer, intent(in) :: id + SPINCOL_FIELD :: eta_e, eta_o, zeta_e, zeta_o + COMPLEX,allocatable :: zeta(:), eta(:), zeta1(:), mat(:,:) + REAL :: fac1, fac2 + + call stderr2("Now check mat-vec mult with chemical potential") + + allocate(zeta(12*vol), zeta1(12*vol), eta(12*vol), mat(12*vol, 12*volume)) + + call make_source(eta_e, eta_o, RANDOM_SOURCE) + call sceo2sc(eta, eta_e, eta_o) + ! + ! result multiplied by using d + ! +! call d(se, so, zeta_e, eta_o, gauge(2)%u(1,1,1,0,1)) +! call sc_xpby(zeta_e, eta_e, - action%mtilde(id)%kappa) +! call d(so, se, zeta_o, eta_e, gauge(2)%u(1,1,1,0,1)) +! call sc_xpby(zeta_o, eta_o, - action%mtilde(id)%kappa) +! call clover_mult_a(zeta_e, clover(action%mtilde(id)%cid)%a(1,1,se), eta_e, volh) +! call clover_mult_a(zeta_o, clover(action%mtilde(id)%cid)%a(1,1,so), eta_o, volh) + + fac1=exp( chemi) + fac2=exp(-chemi) + if (chemi /= 0)call emuu4(gauge(2)%u, fac1, fac2, .false.) + call unprec_wmul(zeta_e, zeta_o, eta_e, eta_o, id) + if (chemi /= 0)call emuu4(gauge(2)%u, ONE/fac1, ONE/fac2, .false.) + + call sceo2sc(zeta, zeta_e, zeta_o) + call make_dirac_op(mat, id, exp(chemi), exp(-chemi)) + call matvec_mul(mat, zeta1, eta, 12*vol, 12*volume) + call compare_sc(zeta, zeta1, 24*vol) + + deallocate(zeta, zeta1, eta, mat) +!! call comm_finalize() +!! call die("stop") +end + +!------------------------------------------------------------------------------- +# define CLOVER_AS_COMPLEX_ARRAY +# include "clover.h" +subroutine clover_put(mat, eo, a, offset) + use module_dirac_matrix + use module_vol + implicit none + COMPLEX, dimension(18, 2, *) :: a + COMPLEX:: mat(3,4,vol,3,4,volume), cl1(6,6), cl2(6,6), clp(6,6), clm(6,6) + integer :: c1, s1, c2, s2, ii, i, eo, sc1, sc2, offset, jj + + call init_dirac_matrix() + do i=1, volh + ii=ieo2_around_i(i,eo,0) + jj=ii + offset +# undef J +# define J 1 + cl1(1,1) =A11 ; cl1(1,2) =A12 ; cl1(1,3) =A13 ; cl1(1,4) =A14 ; cl1(1,5) =A15 ; cl1(1,6) =A16 + cl1(2,1) =A21 ; cl1(2,2) =A22 ; cl1(2,3) =A23 ; cl1(2,4) =A24 ; cl1(2,5) =A25 ; cl1(2,6) =A26 + cl1(3,1) =A31 ; cl1(3,2) =A32 ; cl1(3,3) =A33 ; cl1(3,4) =A34 ; cl1(3,5) =A35 ; cl1(3,6) =A36 + cl1(4,1) =A41 ; cl1(4,2) =A42 ; cl1(4,3) =A43 ; cl1(4,4) =A44 ; cl1(4,5) =A45 ; cl1(4,6) =A46 + cl1(5,1) =A51 ; cl1(5,2) =A52 ; cl1(5,3) =A53 ; cl1(5,4) =A54 ; cl1(5,5) =A55 ; cl1(5,6) =A56 + cl1(6,1) =A61 ; cl1(6,2) =A62 ; cl1(6,3) =A63 ; cl1(6,4) =A64 ; cl1(6,5) =A65 ; cl1(6,6) =A66 +# undef J +# define J 2 + cl2(1,1) =A11 ; cl2(1,2) =A12 ; cl2(1,3) =A13 ; cl2(1,4) =A14 ; cl2(1,5) =A15 ; cl2(1,6) =A16 + cl2(2,1) =A21 ; cl2(2,2) =A22 ; cl2(2,3) =A23 ; cl2(2,4) =A24 ; cl2(2,5) =A25 ; cl2(2,6) =A26 + cl2(3,1) =A31 ; cl2(3,2) =A32 ; cl2(3,3) =A33 ; cl2(3,4) =A34 ; cl2(3,5) =A35 ; cl2(3,6) =A36 + cl2(4,1) =A41 ; cl2(4,2) =A42 ; cl2(4,3) =A43 ; cl2(4,4) =A44 ; cl2(4,5) =A45 ; cl2(4,6) =A46 + cl2(5,1) =A51 ; cl2(5,2) =A52 ; cl2(5,3) =A53 ; cl2(5,4) =A54 ; cl2(5,5) =A55 ; cl2(5,6) =A56 + cl2(6,1) =A61 ; cl2(6,2) =A62 ; cl2(6,3) =A63 ; cl2(6,4) =A64 ; cl2(6,5) =A65 ; cl2(6,6) =A66 + + clp=cl1+cl2 + clm=cl1-cl2 + do s1=1,2; do s2=1,2 + do c1=1,3; do c2=1,3 + sc1=(s1-1)*3+c1 + sc2=(s2-1)*3+c2 + mat(c1,s1 ,ii,c2,s2 ,jj)=clp(sc1,sc2) + mat(c1,s1+2,ii,c2,s2+2,jj)=clp(sc1,sc2) + mat(c1,s1 ,ii,c2,s2+2,jj)=clm(sc1,sc2) + mat(c1,s1+2,ii,c2,s2 ,jj)=clm(sc1,sc2) + enddo; enddo + enddo; enddo + enddo + +end + +!------------------------------------------------------------------------------- +subroutine clover_put_3d(mat, eo, a, offset) + use module_dirac_matrix + use module_vol + use module_lattice + implicit none + COMPLEX, dimension(18, 2, *) :: a + COMPLEX:: mat(3,4,nx*ny*nz,3,4,lx*ly*lz,lt), cl1(6,6), cl2(6,6), clp(6,6), clm(6,6) + integer :: c1, s1, c2, s2, is, it, i, eo, sc1, sc2, jj, offset + + call init_dirac_matrix() + do i=1, volh + is=ieo2_around_is(i,eo,0) + it=ieo2_around_it(i,eo,0) + jj=is + offset +# undef J +# define J 1 + cl1(1,1) =A11 ; cl1(1,2) =A12 ; cl1(1,3) =A13 ; cl1(1,4) =A14 ; cl1(1,5) =A15 ; cl1(1,6) =A16 + cl1(2,1) =A21 ; cl1(2,2) =A22 ; cl1(2,3) =A23 ; cl1(2,4) =A24 ; cl1(2,5) =A25 ; cl1(2,6) =A26 + cl1(3,1) =A31 ; cl1(3,2) =A32 ; cl1(3,3) =A33 ; cl1(3,4) =A34 ; cl1(3,5) =A35 ; cl1(3,6) =A36 + cl1(4,1) =A41 ; cl1(4,2) =A42 ; cl1(4,3) =A43 ; cl1(4,4) =A44 ; cl1(4,5) =A45 ; cl1(4,6) =A46 + cl1(5,1) =A51 ; cl1(5,2) =A52 ; cl1(5,3) =A53 ; cl1(5,4) =A54 ; cl1(5,5) =A55 ; cl1(5,6) =A56 + cl1(6,1) =A61 ; cl1(6,2) =A62 ; cl1(6,3) =A63 ; cl1(6,4) =A64 ; cl1(6,5) =A65 ; cl1(6,6) =A66 +# undef J +# define J 2 + cl2(1,1) =A11 ; cl2(1,2) =A12 ; cl2(1,3) =A13 ; cl2(1,4) =A14 ; cl2(1,5) =A15 ; cl2(1,6) =A16 + cl2(2,1) =A21 ; cl2(2,2) =A22 ; cl2(2,3) =A23 ; cl2(2,4) =A24 ; cl2(2,5) =A25 ; cl2(2,6) =A26 + cl2(3,1) =A31 ; cl2(3,2) =A32 ; cl2(3,3) =A33 ; cl2(3,4) =A34 ; cl2(3,5) =A35 ; cl2(3,6) =A36 + cl2(4,1) =A41 ; cl2(4,2) =A42 ; cl2(4,3) =A43 ; cl2(4,4) =A44 ; cl2(4,5) =A45 ; cl2(4,6) =A46 + cl2(5,1) =A51 ; cl2(5,2) =A52 ; cl2(5,3) =A53 ; cl2(5,4) =A54 ; cl2(5,5) =A55 ; cl2(5,6) =A56 + cl2(6,1) =A61 ; cl2(6,2) =A62 ; cl2(6,3) =A63 ; cl2(6,4) =A64 ; cl2(6,5) =A65 ; cl2(6,6) =A66 + + clp=cl1+cl2 + clm=cl1-cl2 + do s1=1,2; do s2=1,2 + do c1=1,3; do c2=1,3 + sc1=(s1-1)*3+c1 + sc2=(s2-1)*3+c2 + mat(c1,s1 ,is,c2,s2 ,jj,it)=clp(sc1,sc2) + mat(c1,s1+2,is,c2,s2+2,jj,it)=clp(sc1,sc2) + mat(c1,s1 ,is,c2,s2+2,jj,it)=clm(sc1,sc2) + mat(c1,s1+2,is,c2,s2 ,jj,it)=clm(sc1,sc2) + enddo; enddo + enddo; enddo + enddo + +end + +!------------------------------------------------------------------------------- +subroutine one_put(mat, m, n, offset) + implicit none + integer, intent(in) :: m, n, offset + COMPLEX,intent(inout) :: mat(12,m,12,n) + integer :: i + + do i = 1, m + mat( 1, i, 1, i + offset )=ONE + mat( 2, i, 2, i + offset )=ONE + mat( 3, i, 3, i + offset )=ONE + mat( 4, i, 4, i + offset )=ONE + mat( 5, i, 5, i + offset )=ONE + mat( 6, i, 6, i + offset )=ONE + mat( 7, i, 7, i + offset )=ONE + mat( 8, i, 8, i + offset )=ONE + mat( 9, i, 9, i + offset )=ONE + mat(10, i,10, i + offset )=ONE + mat(11, i,11, i + offset )=ONE + mat(12, i,12, i + offset )=ONE + enddo +end + +!------------------------------------------------------------------------------- +subroutine one_put_3d(mat, m, n, offset, t) + implicit none + integer, intent(in) :: m, n, offset, t + COMPLEX,intent(inout) :: mat(12, m, 12, n, t) + integer :: i + + do i = 1, t + call one_put(mat(:,:,:,:,i), m, n, offset) + enddo +end + +!------------------------------------------------------------------------------- +subroutine hop_put(mat, gp, gm, i, eo, dir, ii, kappa, fac1, fac2) + use module_nn + use module_vol + use module_dirac_matrix + use module_field + implicit none + integer, intent(in) :: i, eo, dir, ii + COMPLEX, intent(in) :: gp(4,4), gm(4,4) + COMPLEX, intent(inout) :: mat(3,4,vol,3,4,volume) + REAL, intent(in) :: kappa, fac1, fac2 + integer :: s1, s2, col1, col2, jm, jj, jb + + jm=nn(i, eo, dir, BWD) + jj=ieo2_around_i(i,eo,1 + 2*(dir-1) ) + jb=ieo2_around_i(i,eo,2 + 2*(dir-1) ) + + do s1 = 1, 4 + do s2 = 1, 4 + if ( gp(s1, s2) /=0 ) then + do col1 = 1, 3 + do col2 = 1, 3 + mat(col1,s1,ii,col2,s2,jj)=mat(col1,s1,ii,col2,s2,jj) & + -kappa* gauge(2)%u(col1,col2, i, eo,dir) *gp(s1,s2)*fac1 + enddo + enddo + endif + if ( gm(s1, s2) /=0 ) then + do col1 = 1, 3 + do col2 = 1, 3 + mat(col1,s1,ii,col2,s2,jb)=mat(col1,s1,ii,col2,s2,jb) & + -kappa*conjg(gauge(2)%u(col2,col1, jm,1-eo,dir))*gm(s1,s2)*fac2 + enddo + enddo + endif + enddo + enddo +end + +!------------------------------------------------------------------------------- +subroutine hop_put_3d(mat, gp, gm, i, eo, dir, is, it, itoffset, kappa) + use module_nn + use module_lattice + use module_dirac_matrix + use module_field + implicit none + integer, intent(in) :: i, eo, dir, is, it, itoffset + COMPLEX, intent(in) :: gp(4,4), gm(4,4) + COMPLEX, intent(inout) :: mat(3,4,nx*ny*nz,3,4,lx*ly*lz,lt) + REAL, intent(in) :: kappa + integer :: s1, s2, col1, col2, jm, jj, jb, it1 + + jm=nn(i, eo, dir, BWD) + jj=ieo2_around_is(i,eo,1 + 2*(dir-1) ) + jb=ieo2_around_is(i,eo,2 + 2*(dir-1) ) + it1=it + itoffset + + do s1 = 1, 4 + do s2 = 1, 4 + if ( gp(s1, s2) /=0 ) then + do col1 = 1, 3 + do col2 = 1, 3 + mat(col1,s1,is,col2,s2,jj, it)=mat(col1,s1,is,col2,s2,jj,it) & + -kappa* gauge(2)%u(col1,col2, i, eo,dir) *gp(s1,s2) + enddo + enddo + endif + if ( gm(s1, s2) /=0 ) then + do col1 = 1, 3 + do col2 = 1, 3 + mat(col1,s1,is,col2,s2,jb, it1)=mat(col1,s1,is,col2,s2,jb,it1) & + -kappa*conjg(gauge(2)%u(col2,col1, jm,1-eo,dir))*gm(s1,s2) + enddo + enddo + endif + enddo + enddo +end + +!------------------------------------------------------------------------------- +subroutine make_dirac_op(mat, id, fac1, fac2) ! for one node + use module_dirac_matrix + use module_vol + use module_field + use module_action + use module_function_decl + implicit none + integer, intent(in) :: id + REAL, intent(in) :: fac1, fac2 + COMPLEX,intent(out) :: mat(3,4,vol,3,4,volume) + REAL :: kappa + integer :: ii, i, eo, offset + + call init_dirac_matrix() + kappa=action%mtilde(id)%kappa + + mat=ZERO + offset = my_pe()*vol + if (action%mtilde(id)%cswkappa == 0) then + call one_put(mat, vol, volume, offset) + else + call clover_put(mat, EVEN, clover(action%mtilde(id)%cid)%a(1,1,se), offset) + call clover_put(mat, ODD, clover(action%mtilde(id)%cid)%a(1,1,so), offset) + endif + + if (kappa /= 0) then + do eo=EVEN, ODD + do i=1, volh + ii=ieo2_around_i(i,eo,0) + call hop_put(mat, proj_1_p_gamma1, proj_1_m_gamma1, i, eo, 1, ii, kappa, ONE, ONE) ! x-dir + call hop_put(mat, proj_1_p_gamma2, proj_1_m_gamma2, i, eo, 2, ii, kappa, ONE, ONE) ! y-dir + call hop_put(mat, proj_1_p_gamma3, proj_1_m_gamma3, i, eo, 3, ii, kappa, ONE, ONE) ! z-dir + call hop_put(mat, proj_1_m_gamman, proj_1_p_gamman, i, eo, 4, ii, kappa,fac1,fac2) ! t-dir + enddo + enddo + endif + +end + +!------------------------------------------------------------------------------- +subroutine make_dirac_op_3d(mat3,matt, id) ! for one node + use module_dirac_matrix + use module_lattice + use module_vol + use module_nn + use module_field + use module_action + use module_function_decl + implicit none + integer, intent(in) :: id + REAL :: kappa + COMPLEX:: mat3(3,4,nx*ny*nz,3,4,lx*ly*lz,lt) + COMPLEX:: matt(3,4,nx*ny*nz,3,4,lx*ly*lz,2*lt) + integer :: col1, s1, col2, s2, is, it, jj, i, j, eo, jb, jm, offset + + call init_dirac_matrix() + kappa=action%mtilde(id)%kappa + + mat3=ZERO + matt=ZERO + offset = my_pe()*vol/nt + if (action%mtilde(id)%cswkappa == 0) then + call one_put_3d(mat3, vol/nt, volume/nt, offset, nt) +! do it=1,nt +! do i=1,vol/nt +! do col1=1,3 +! do s1=1,4 +! mat3(col1,s1,i, col1,s1,i,it)=ONE +! enddo +! enddo +! enddo +! enddo + else + call clover_put_3d(mat3, EVEN, clover(action%mtilde(id)%cid)%a(1,1,se), offset) + call clover_put_3d(mat3, ODD, clover(action%mtilde(id)%cid)%a(1,1,so), offset) + endif + + if (kappa /= 0) then + do eo=EVEN, ODD + do i=1, volh + is=ieo2_around_is(i,eo,0) + it=ieo2_around_it(i,eo,0) + call hop_put_3d(mat3, proj_1_p_gamma1, proj_1_m_gamma1, i, eo, 1, is, it, 0, kappa) ! x-dir + call hop_put_3d(mat3, proj_1_p_gamma2, proj_1_m_gamma2, i, eo, 2, is, it, 0, kappa) ! y-dir + call hop_put_3d(mat3, proj_1_p_gamma3, proj_1_m_gamma3, i, eo, 3, is, it, 0, kappa) ! z-dir + call hop_put_3d(matt, proj_1_m_gamman, proj_1_p_gamman, i, eo, 4, is, it,lt, kappa) ! t-dir + +!! ! +!! ! x-dir +!! ! +!! jj=ieo2_around_is(i,eo,1) +!! jb=ieo2_around_is(i,eo,2) +!! jm=nn(i, eo, 1, BWD) +!! do s1=1,4; do s2=1,4 +!! if (proj_1_p_gamma1(s1,s2) /=0) then +!! do col1=1,3; do col2=1,3 +!! mat3(col1,s1,is,col2,s2,jj,it)=mat3(col1,s1,is,col2,s2,jj,it) -kappa* gauge(1)%u(col1,col2, i, eo,1) *proj_1_p_gamma1(s1,s2) +!! mat3(col1,s1,is,col2,s2,jb,it)=mat3(col1,s1,is,col2,s2,jb,it) -kappa*conjg(gauge(1)%u(col2,col1, jm,1-eo,1))*proj_1_m_gamma1(s1,s2) +!! enddo; enddo +!! endif +!! enddo; enddo +!! ! +!! ! y-dir +!! ! +!! jj=ieo2_around_is(i,eo,3) +!! jb=ieo2_around_is(i,eo,4) +!! jm=nn(i, eo, 2, BWD) +!! do s1=1,4; do s2=1,4 +!! if (proj_1_p_gamma2(s1,s2) /=0) then +!! do col1=1,3; do col2=1,3 +!! mat3(col1,s1,is,col2,s2,jj,it)=mat3(col1,s1,is,col2,s2,jj,it) -kappa* gauge(1)%u(col1,col2, i, eo,2) *proj_1_p_gamma2(s1,s2) +!! mat3(col1,s1,is,col2,s2,jb,it)=mat3(col1,s1,is,col2,s2,jb,it) -kappa*conjg(gauge(1)%u(col2,col1, jm,1-eo,2))*proj_1_m_gamma2(s1,s2) +!! enddo; enddo +!! endif +!! enddo; enddo +!! ! +!! ! z-dir +!! ! +!! jj=ieo2_around_is(i,eo,5) +!! jb=ieo2_around_is(i,eo,6) +!! jm=nn(i, eo, 3, BWD) +!! do s1=1,4; do s2=1,4 +!! if (proj_1_p_gamma3(s1,s2) /=0) then +!! do col1=1,3; do col2=1,3 +!! mat3(col1,s1,is,col2,s2,jj,it)=mat3(col1,s1,is,col2,s2,jj,it) -kappa* gauge(1)%u(col1,col2, i, eo,3) *proj_1_p_gamma3(s1,s2) +!! mat3(col1,s1,is,col2,s2,jb,it)=mat3(col1,s1,is,col2,s2,jb,it) -kappa*conjg(gauge(1)%u(col2,col1, jm,1-eo,3))*proj_1_m_gamma3(s1,s2) +!! enddo; enddo +!! endif +!! enddo; enddo +!! ! +!! ! t-dir +!! ! +!! jj=ieo2_around_is(i,eo,7) +!! jb=ieo2_around_is(i,eo,8) +!! jm=nn(i, eo, 4, BWD) +!! do s1=1,4; do s2=1,4 +!! if (proj_1_m_gamman(s1,s2) /=0) then +!! do col1=1,3; do col2=1,3 +!! matt(col1,s1,is,col2,s2,jj,it)=matt(col1,s1,is,col2,s2,jj,it) -kappa* gauge(2)%u(col1,col2, i, eo,4) *proj_1_m_gamman(s1,s2) +!! enddo; enddo +!! endif +!! if (proj_1_p_gamman(s1,s2) /=0) then +!! do col1=1,3; do col2=1,3 +!! matt(col1,s1,is,col2,s2,jb,it+nt)=matt(col1,s1,is,col2,s2,jb,it+nt) -kappa*conjg(gauge(2)%u(col2,col1, jm,1-eo,4))*proj_1_p_gamman(s1,s2) +!! enddo; enddo +!! endif +!! enddo; enddo + enddo + enddo + endif + +end + +!------------------------------------------------------------------------------- +subroutine init_dirac_matrix() + use module_dirac_matrix + use module_lattice + use module_vol + implicit none + integer :: i, eo, ll(4) + + if (.not. associated(ieo2_around_i)) then + allocate(ieo2_around_i(volh,0:1, 0:8)) + allocate(ieo2_around_is(volh,0:1, 0:8)) + allocate(ieo2_around_it(volh,0:1, 0:8)) + proj_1_m_gamma1=0 + proj_1_p_gamma1=0 + proj_1_m_gamma2=0 + proj_1_p_gamma2=0 + proj_1_m_gamma3=0 + proj_1_p_gamma3=0 + proj_1_m_gammac=0 + proj_1_p_gammac=0 + proj_1_m_gamman=0 + proj_1_p_gamman=0 + + do i=1,4 + proj_1_m_gamma1(i,i)=ONE + proj_1_p_gamma1(i,i)=ONE + proj_1_m_gamma2(i,i)=ONE + proj_1_p_gamma2(i,i)=ONE + proj_1_m_gamma3(i,i)=ONE + proj_1_p_gamma3(i,i)=ONE + proj_1_m_gammac(i,i)=ONE + proj_1_p_gammac(i,i)=ONE + enddo + + proj_1_m_gamman(3,3)=TWO + proj_1_m_gamman(4,4)=TWO + proj_1_p_gamman(1,1)=TWO + proj_1_p_gamman(2,2)=TWO + + proj_1_m_gamma1(1,4)=cmplx(ZERO,ONE) + proj_1_m_gamma1(2,3)=cmplx(ZERO,ONE) + proj_1_m_gamma1(3,2)=cmplx(ZERO,-ONE) + proj_1_m_gamma1(4,1)=cmplx(ZERO,-ONE) + proj_1_p_gamma1(1,4)=cmplx(ZERO,-ONE) + proj_1_p_gamma1(2,3)=cmplx(ZERO,-ONE) + proj_1_p_gamma1(3,2)=cmplx(ZERO,ONE) + proj_1_p_gamma1(4,1)=cmplx(ZERO,ONE) + + proj_1_m_gamma2(1,4)= ONE + proj_1_m_gamma2(2,3)=-ONE + proj_1_m_gamma2(3,2)=-ONE + proj_1_m_gamma2(4,1)= ONE + proj_1_p_gamma2(1,4)=-ONE + proj_1_p_gamma2(2,3)= ONE + proj_1_p_gamma2(3,2)= ONE + proj_1_p_gamma2(4,1)=-ONE + + proj_1_m_gamma3(1,3)=cmplx(ZERO, ONE) + proj_1_m_gamma3(2,4)=cmplx(ZERO,-ONE) + proj_1_m_gamma3(3,1)=cmplx(ZERO,-ONE) + proj_1_m_gamma3(4,2)=cmplx(ZERO, ONE) + proj_1_p_gamma3(1,3)=cmplx(ZERO,-ONE) + proj_1_p_gamma3(2,4)=cmplx(ZERO, ONE) + proj_1_p_gamma3(3,1)=cmplx(ZERO, ONE) + proj_1_p_gamma3(4,2)=cmplx(ZERO,-ONE) + + proj_1_m_gammac(1,3)=-ONE + proj_1_m_gammac(2,4)=-ONE + proj_1_m_gammac(3,1)= ONE + proj_1_m_gammac(4,2)= ONE + proj_1_p_gammac(1,3)= ONE + proj_1_p_gammac(2,4)= ONE + proj_1_p_gammac(3,1)=-ONE + proj_1_p_gammac(4,2)=-ONE + + + do eo=EVEN, ODD + do i=1, volh + call i2xyzt(i, eo, ll) + ieo2_around_i(i,eo,0)= 1 + ll(1) + ll(2)*nx + ll(3)*nx*ny + ll(4)*nx*ny*nz + ieo2_around_is(i,eo,0)= 1 + ll(1) + ll(2)*nx + ll(3)*nx*ny + ieo2_around_it(i,eo,0)= 1 + ll(4) + + call ieo_offset_global(i, eo, 1, FWD, ieo2_around_i(i,eo,1), ieo2_around_is(i,eo,1), ieo2_around_it(i,eo,1)) + call ieo_offset_global(i, eo, 1, BWD, ieo2_around_i(i,eo,2), ieo2_around_is(i,eo,2), ieo2_around_it(i,eo,2)) + call ieo_offset_global(i, eo, 2, FWD, ieo2_around_i(i,eo,3), ieo2_around_is(i,eo,3), ieo2_around_it(i,eo,3)) + call ieo_offset_global(i, eo, 2, BWD, ieo2_around_i(i,eo,4), ieo2_around_is(i,eo,4), ieo2_around_it(i,eo,4)) + call ieo_offset_global(i, eo, 3, FWD, ieo2_around_i(i,eo,5), ieo2_around_is(i,eo,5), ieo2_around_it(i,eo,5)) + call ieo_offset_global(i, eo, 3, BWD, ieo2_around_i(i,eo,6), ieo2_around_is(i,eo,6), ieo2_around_it(i,eo,6)) + call ieo_offset_global(i, eo, 4, FWD, ieo2_around_i(i,eo,7), ieo2_around_is(i,eo,7), ieo2_around_it(i,eo,7)) + call ieo_offset_global(i, eo, 4, BWD, ieo2_around_i(i,eo,8), ieo2_around_is(i,eo,8), ieo2_around_it(i,eo,8)) + enddo + enddo + + endif + + +end + +!------------------------------------------------------------------------------- +subroutine ieo_offset_global(i, eo , dir, fb, i4, i3, it) + use module_function_decl + use module_lattice + use module_nnpe + use module_nn + use module_vol + implicit none + integer, intent(in) :: i, eo, dir, fb + integer, intent(out):: i4, i3, it + integer :: j, ll(4), pe(4), ip + integer, save :: nxy, nxyz, count=0 + + if (count==0) then + nxy = nx * ny + nxyz= nxy * nz + count=-1 + endif + + pe = 0 + j = nn(i, eo, dir, fb) + call i2xyzt(j, 1-eo, ll) + + if ( j > volh ) then + if ( ll(dir) == -1 ) then + pe(dir) = -1 + ll(dir) = n(dir)-1 + elseif( ll(dir) == n(dir) ) then + pe(dir) = 1 + ll(dir) = 0 + endif + endif + + ip=nnpe( pe(1), pe(2), pe(3), pe(4)) + + it = 1 + ll(4) + i3 = 1 + ll(1) + ll(2) * nx + ll(3) * nxy + i4 = i3+ ll(4) * nxyz + + i3 = i3 + ip * nxyz + i4 = i4 + ip * vol + +end + +!------------------------------------------------------------------------------- +subroutine compare_sc(in1, in2, size) + use module_function_decl + implicit none + integer :: i, size + REAL :: in1(size), in2(size), res, tmp + + res=0 + do i=1, size + tmp=(in1(i)-in2(i))**2 + res=res+tmp + if (tmp > 0.00001)write(*,*)i, tmp,in1(i),in2(i) + enddo + res=global_sum(res) + call stderr2_real("vector difference",1,res) + +end + +!------------------------------------------------------------------------------- +subroutine sceo2sc(out, in_e, in_o) + use module_lattice + use module_vol + implicit none + integer :: id, ix, iy, iz, it, i, ii, j(4), spin, col + + SPINCOL_FIELD :: in_e, in_o + COMPLEX :: out(3,4,vol) + integer, external :: std_xyzt2i, e_o + + i=0 + do it=0,nt-1 + do iz=0,nz-1 + do iy=0,ny-1 + do ix=0,nx-1 + i=i+1 + j = (/ix, iy, iz, it/) + ii = std_xyzt2i(j) + if (e_o(j) == EVEN) then + do col=1, 3 + do spin=1, 4 + out(col,spin,i)=in_e(spin,col,ii) + enddo + enddo + else + do col=1, 3 + do spin=1, 4 + out(col,spin,i)=in_o(spin,col,ii) + enddo + enddo + endif + enddo + enddo + enddo + enddo + +end + +!=============================================================================== +! for checking +!------------------------------------------------------------------------------- +module phmc_read + integer, save :: ipeo=0 + + type su3_obj + complex(8) :: u(3,3) + end type + + type gsf_eo_wg_obj + type(su3_obj) :: s(0:2,0:5,0:5,0:5) + integer :: ieo,idummy(3) + end type + + type gvf_eo_wg_obj + type(gsf_eo_wg_obj) :: mu(4) + integer :: ieo,idummy(3) + end type + + type gvf_wg_obj + type(gvf_eo_wg_obj) :: eo(0:1) + end type + +end + +!------------------------------------------------------------------------------- +subroutine read_phmc_config() + use phmc_read + use module_vol + use module_field + implicit none + type(gvf_wg_obj) :: phmc_u + integer :: ix, iy, iz, it, ieo, imu, j(4), itb, jmu(4) , ee, jj, ic,jc + integer :: ntx, nty, ntz, ntt + integer :: ndx, ndy, ndz, ndt + REAL :: plq, tmp + GAUGE_FIELD ::u + REAL, external :: sg + integer, external :: std_xyzt2i, e_o + + write(*,*)"read_phmc_config: start" + + open(40,file="config.x0y0z0",status='unknown',form='unformatted') + write(*,*)"read_phmc_config: open config.x0y0z0" + + read(40)phmc_u + write(*,*)"read_phmc_config: have read config.x0y0z0" + + read(40)NTX,NTY,NTZ,NTT + read(40)NDX,NDY,NDZ + read(40)plq + + jmu(1)=4 + jmu(2)=3 + jmu(3)=2 + jmu(4)=1 + + + do imu = 1,4 + do it=1,4 + itb=it/2 + do iz=1,4 + do iy=1,4 + do ix=1,4 + ieo=mod(ix + iy + iz + it, 2) + j=(/ ix-1 , iy-1, iz-1, it-1/) + jj=std_xyzt2i(j) + ee=e_o(j) + u(:,:, jj ,ee, imu )=phmc_u%eo(ieo)%mu(imu)%s(itb,iz,iy,ix)%u + enddo + enddo + enddo + enddo + enddo + + gauge(1)%u=u + + call xbound_g_field(gauge(1)%u) + call d_g_init(gauge(1)%u) + call conf_check(gauge(1)%u) + + !!call conf_hot(gauge(1)%u) + tmp=sg(gauge(1)%u) + write(*,*)"plaq value calculated by bqcd", ONE - tmp / (SIX * volume) + +end + +!=============================================================================== diff --git a/src/measure/gamma.F90 b/src/measure/gamma.F90 new file mode 100644 index 0000000000000000000000000000000000000000..ec7ec0a262ab18a68d84c9ae411c59ff3cc52f99 --- /dev/null +++ b/src/measure/gamma.F90 @@ -0,0 +1,295 @@ +!=============================================================================== +! +! gamma.F90 +! +!------------------------------------------------------------------------------- +! +! Copyright (C) 2007 Yoshifumi Nakamura +! +! This file is part of BQCD -- Berlin Quantum ChromoDynamics program +! +! BQCD 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 Foundation, either version 3 of the License, or +! (at your option) any later version. +! +! BQCD is distributed in the hope that it will be useful, +! but WITHOUT ANY WARRANTY; without even the implied warranty of +! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +! GNU General Public License for more details. +! +! You should have received a copy of the GNU General Public License +! along with BQCD. If not, see <http://www.gnu.org/licenses/>. +! +!------------------------------------------------------------------------------- +# include "defs.h" +# include "gamma.h" + +!------------------------------------------------------------------------------- +module gamma + implicit none + integer, parameter :: ngop=20 + + type gamma_matrix + complex(8) :: c(4,4) + end type + type(gamma_matrix), save :: gamma_op(ngop) + + logical, save :: ginit=.false. + + + integer, dimension(4,4), save :: igamma + COMPLEX, dimension(4,4), save :: zgamma + +end module gamma + +!------------------------------------------------------------------------------- +subroutine gamma_init() + use gamma + implicit none + complex(8), dimension(4,4) :: g1,g2,g3,g4, gc + integer :: i, j + COMPLEX :: i_times, c + i_times(c) = cmplx(-aimag(c), real(c), kind = RKIND) + + if (ginit) return + DEBUG2S("Start: gamma_init") + + g1=ZERO + g2=ZERO + g3=ZERO + g4=ZERO + gc=ZERO + + do i = 1, ngop + gamma_op(i)%c = ZERO + enddo + + g1(1, 4) = cmplx(ZERO,-ONE) + g1(2, 3) = cmplx(ZERO,-ONE) + g1(3, 2) = cmplx(ZERO, ONE) + g1(4, 1) = cmplx(ZERO, ONE) + g2(1, 4) = -ONE + g2(2, 3) = ONE + g2(3, 2) = ONE + g2(4, 1) = -ONE + g3(1, 3) = cmplx(ZERO,-ONE) + g3(2, 4) = cmplx(ZERO, ONE) + g3(3, 1) = cmplx(ZERO, ONE) + g3(4, 2) = cmplx(ZERO,-ONE) + g4(1, 1) = ONE + g4(2, 2) = ONE + g4(3, 3) =-ONE + g4(4, 4) =-ONE + gc(1, 4) = ONE + gc(2, 3) = ONE + gc(3, 2) = ONE + gc(4, 1) = ONE + + +#ifdef GAMMA_NOTATION_CHROMA + not yet +#elif defined GAMMA_NOTATION_CHIRAL + not yet +#elif defined GAMMA_NOTATION_DDHMC + not yet +#elif defined GAMMA_NOTATION_BQCD + gamma_op(G1)%c= -g1 + gamma_op(G2)%c= -g2 + gamma_op(G3)%c= -g3 + gamma_op(G0)%c= g4 +#endif + + call spin_mul(g1,gamma_op(G1)%c, gamma_op(G2)%c) + call spin_mul(g2,gamma_op(G3)%c, gamma_op(G0)%c) + call spin_mul(gamma_op(G5)%c, g1, g2) + + call spin_mul(gamma_op(G01)%c, gamma_op(G0)%c, gamma_op(G1)%c) + call spin_mul(gamma_op(G02)%c, gamma_op(G0)%c, gamma_op(G2)%c) + call spin_mul(gamma_op(G03)%c, gamma_op(G0)%c, gamma_op(G3)%c) + + call spin_mul(gamma_op(G05)%c, gamma_op(G0)%c, gamma_op(G5)%c) + call spin_mul(gamma_op(G15)%c, gamma_op(G1)%c, gamma_op(G5)%c) + call spin_mul(gamma_op(G25)%c, gamma_op(G2)%c, gamma_op(G5)%c) + call spin_mul(gamma_op(G35)%c, gamma_op(G3)%c, gamma_op(G5)%c) + + call spin_mul(gamma_op(G12)%c, gamma_op(G1)%c, gamma_op(G2)%c) + call spin_mul(gamma_op(G23)%c, gamma_op(G2)%c, gamma_op(G3)%c) + call spin_mul(gamma_op(G31)%c, gamma_op(G3)%c, gamma_op(G1)%c) !! = CG5 + + g1=HALF * (gamma_op(G2)%c + cmplx(ZERO, ONE) * gamma_op(G1)%c ) + call spin_mul(g2, gamma_op(G02)%c, g1) + gamma_op(CGm)%c = - g2 + + gamma_op(UNP)%c = gamma_op(G0)%c + gamma_op(UNP)%c(1,1) = gamma_op(UNP)%c(1,1) + ONE + gamma_op(UNP)%c(2,2) = gamma_op(UNP)%c(2,2) + ONE + gamma_op(UNP)%c(3,3) = gamma_op(UNP)%c(3,3) + ONE + gamma_op(UNP)%c(4,4) = gamma_op(UNP)%c(4,4) + ONE + gamma_op(UNP)%c = gamma_op(UNP)%c * HALF + + do i = 1, DIM + do j = 1, DIM + g1(i,j) = i_times(gamma_op(G35)%c(i,j)) + enddo + enddo + g1(1,1) = g1(1,1) + ONE + g1(2,2) = g1(2,2) + ONE + g1(3,3) = g1(3,3) + ONE + g1(4,4) = g1(4,4) + ONE + + call spin_mul(gamma_op(POL)%c, gamma_op(UNP)%c, g1) + + + call igamma_zgamma() + ginit=.true. + + DEBUG2S("End: gamma_init") +end + +!------------------------------------------------------------------------------- +subroutine spin_mul(g1, g2, g3) ! g1 = g2 * g3 + implicit none + complex(8), dimension(4,4) :: g1, g2, g3 + integer :: i, j, k + + g1=0 + do i=1, 4 + do j=1, 4 + do k=1, 4 + g1(i,j) = g1(i,j) + g2(i, k) * g3(k, j) + enddo + enddo + enddo +end + +!------------------------------------------------------------------------------- +COMPLEX function spintr(g) + implicit none + complex(8), dimension(4,4) :: g + integer :: i + + spintr=0 + do i=1, 4 + spintr = spintr + g(i,i) + enddo +end + +!=============================================================================== +! C= gamma2 gamma4 +! gamma- = (gamma2 + i gamma1)/2 +! +! +! Definition used: ( 1 0 0 0 ) +! ( 0 0 0 0 ) +! Cgamma- = ( 0 0 1 0 ) +! ( 0 0 0 0 ) +! +! +subroutine cgmxcgmt(out, in) ! (Cgamma- * in Cgamma-)^T + implicit none + COMPLEX, dimension(4,4), intent(out) :: out + COMPLEX, dimension(4,4), intent(in) :: in + + out(1,1) = in(1,1) + out(2,1) = ZERO + out(3,1) = in(1,3) + out(4,1) = ZERO + + out(1,2) = ZERO + out(2,2) = ZERO + out(3,2) = ZERO + out(4,2) = ZERO + + out(1,3) = in(3,1) + out(2,3) = ZERO + out(3,3) = in(3,3) + out(4,3) = ZERO + + out(1,4) = ZERO + out(2,4) = ZERO + out(3,4) = ZERO + out(4,4) = ZERO + +end + +!------------------------------------------------------------------------------- +!// +!// copy from K.-I. Ishikawa's code +!// This is same as BQCD gamma notation +!// +subroutine igamma_zgamma() + use gamma + implicit none + COMPLEX, parameter :: z1=(ONE, ZERO), zi=(ZERO, ONE) + integer :: mu + + mu=1 + igamma(1,mu) = 4 + zgamma(1,mu) = -zi + igamma(2,mu) = 3 + zgamma(2,mu) = -zi + igamma(3,mu) = 2 + zgamma(3,mu) = zi + igamma(4,mu) = 1 + zgamma(4,mu) = zi + mu=2 + igamma(1,mu) = 4 + zgamma(1,mu) = -z1 + igamma(2,mu) = 3 + zgamma(2,mu) = z1 + igamma(3,mu) = 2 + zgamma(3,mu) = z1 + igamma(4,mu) = 1 + zgamma(4,mu) = -z1 + mu=3 + igamma(1,mu) = 3 + zgamma(1,mu) = -zi + igamma(2,mu) = 4 + zgamma(2,mu) = zi + igamma(3,mu) = 1 + zgamma(3,mu) = zi + igamma(4,mu) = 2 + zgamma(4,mu) = -zi + mu=4 + igamma(1,mu) = 1 + zgamma(1,mu) = z1 + igamma(2,mu) = 2 + zgamma(2,mu) = z1 + igamma(3,mu) = 3 + zgamma(3,mu) = -z1 + igamma(4,mu) = 4 + zgamma(4,mu) = -z1 + +end + +!------------------------------------------------------------------------------- +!// +!// copy from Dirk's T3E version +!// +subroutine g31xg31t(out, in) ! (G31 * in G31)^T + implicit none + COMPLEX, dimension(4,4), intent(out) :: out + COMPLEX, dimension(4,4), intent(in) :: in + + out(1,1) = -in(2,2) + out(2,1) = in(2,1) + out(3,1) = -in(2,4) + out(4,1) = in(2,3) + + out(1,2) = in(1,2) + out(2,2) = -in(1,1) + out(3,2) = in(1,4) + out(4,2) = -in(1,3) + + out(1,3) = -in(4,2) + out(2,3) = in(4,1) + out(3,3) = -in(4,4) + out(4,3) = in(4,3) + + out(1,4) = in(3,2) + out(2,4) = -in(3,1) + out(3,4) = in(3,4) + out(4,4) = -in(3,3) + +end diff --git a/src/measure/make_source.F90 b/src/measure/make_source.F90 index 1b9f77790a141c6ee2fb36da10f7b63c6b1bdb98..de681826b26fe522b784f49282f30fe0a7a2fd5f 100644 --- a/src/measure/make_source.F90 +++ b/src/measure/make_source.F90 @@ -39,6 +39,8 @@ subroutine make_source(even, odd, sourcetype) elseif (sourcetype == RANDOM_SOURCE) then call ran_gauss_volh(NDIRAC * NCOL, even, HALF, EVEN) call ran_gauss_volh(NDIRAC * NCOL, odd, HALF, ODD) + elseif (sourcetype == LOCAL_SOURCE) then +!! call make_source_local(even, odd, src_at) elseif (sourcetype == WALL_SOURCE) then if (my_pe()==0) call warn("wall source called S=1, C=1, T=0") call make_source_wall(1,1,0,even,odd) @@ -48,6 +50,98 @@ subroutine make_source(even, odd, sourcetype) end +!------------------------------------------------------------------------------- +subroutine make_source_local(even, odd, src_at) + use module_lattice + use module_vol + use module_function_decl + implicit none + integer :: coord(4), j(4) + integer :: it,iz,iy,ix,ii + integer, intent(in) :: src_at(4) + SPINCOL_FIELD, intent(out) :: even, odd + integer, external :: std_xyzt2i, e_o + + call pe2coord(my_pe(), coord) + even = ZERO + odd = ZERO + + it = src_at(4) - nt*coord(4) + iz = src_at(3) - nz*coord(3) + iy = src_at(2) - ny*coord(2) + ix = src_at(1) - nx*coord(1) + + if ( 0<=it .and. it < nt .and. & + 0<=iz .and. iz < nz .and. & + 0<=iy .and. iy < ny .and. & + 0<=ix .and. ix < nx) then + + j = (/ix, iy, iz, it/) + ii = std_xyzt2i(j) + if (e_o(j) == EVEN) then + even(:,:,ii) = ONE + else + odd(:,:,ii) = ONE + endif + endif +end + +!------------------------------------------------------------------------------- +subroutine make_quark_source(qeven,qodd, even, odd) + use module_vol + implicit none + integer :: is, ic, i + complex(8), dimension(4,4,3,3,volh), intent(out) :: qeven,qodd + SPINCOL_FIELD, intent(in) :: even, odd + + do i = 1, volh + do ic = 1, 3 + do is = 1, 4 + qeven(is,is,ic,ic,i)= even(is,ic,i) + qodd( is,is,ic,ic,i)= odd(is,ic,i) + enddo + enddo + enddo +end + +!------------------------------------------------------------------------------- +subroutine get_quark_source(even, odd, qeven,qodd, is0, ic0) + use module_vol + implicit none + integer :: is, ic, i + integer, intent(in) :: is0, ic0 + complex(8), dimension(4,4,3,3,volh), intent(in) :: qeven,qodd + SPINCOL_FIELD, intent(out) :: even, odd + + do i = 1, volh + do ic = 1, 3 + do is = 1, 4 + even(is,ic,i) = qeven(is,is0,ic,ic0,i) + odd( is,ic,i) = qodd( is,is0,ic,ic0,i) + enddo + enddo + enddo +end + +!------------------------------------------------------------------------------- +subroutine put_quark_source(qeven,qodd, even, odd, is0, ic0) + use module_vol + implicit none + integer :: is, ic, i + integer, intent(in) :: is0, ic0 + complex(8), dimension(4,4,3,3,volh), intent(out) :: qeven,qodd + SPINCOL_FIELD, intent(in) :: even, odd + + do i = 1, volh + do ic = 1, 3 + do is = 1, 4 + qeven(is,is0,ic,ic0,i) = even(is,ic,i) + qodd( is,is0,ic,ic0,i) = odd( is,ic,i) + enddo + enddo + enddo +end + !------------------------------------------------------------------------------- subroutine make_source_wall(is, ic, src_t, even, odd) use module_lattice @@ -85,9 +179,8 @@ subroutine make_source_wall(is, ic, src_t, even, odd) end - !------------------------------------------------------------------------------- -subroutine make_source_0000(even, odd) +subroutine make_source_0000(even, odd) !! for test use module_vol use module_function_decl diff --git a/src/measure/phmc_read.F90 b/src/measure/phmc_read.F90 new file mode 100644 index 0000000000000000000000000000000000000000..c977227cfa3c443ed5066823eda8eddd7c06a9d9 --- /dev/null +++ b/src/measure/phmc_read.F90 @@ -0,0 +1,169 @@ +!=============================================================================== +! +! phmc_read.F90 - read phmc config +! +!------------------------------------------------------------------------------- +! +! Copyright (C) 2011 Yoshifumi Nakamura +! +! This file is part of BQCD -- Berlin Quantum ChromoDynamics program +! +! BQCD 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 Foundation, either version 3 of the License, or +! (at your option) any later version. +! +! BQCD is distributed in the hope that it will be useful, +! but WITHOUT ANY WARRANTY; without even the implied warranty of +! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +! GNU General Public License for more details. +! +! You should have received a copy of the GNU General Public License +! along with BQCD. If not, see <http://www.gnu.org/licenses/>. +! +!------------------------------------------------------------------------------- +# include "defs.h" + +!------------------------------------------------------------------------------- +module phmc_read + integer, save :: ipeo=0 + + type su3_obj + complex(8) :: u(3,3) + end type + + type gsf_eo_wg_obj + type(su3_obj) :: s(0:2,0:5,0:5,0:5) + integer :: ieo,idummy(3) + end type + + type gvf_eo_wg_obj + type(gsf_eo_wg_obj) :: mu(4) + integer :: ieo,idummy(3) + end type + + type gvf_wg_obj + type(gvf_eo_wg_obj) :: eo(0:1) + end type + +end + +!------------------------------------------------------------------------------- +subroutine read_phmc_config() + use phmc_read + use module_vol + use module_field + implicit none + type(gvf_wg_obj) :: phmc_u + integer :: ix, iy, iz, it, ieo, imu, j(4), itb, jmu(4) , ee, jj, ic,jc + integer :: ntx, nty, ntz, ntt + integer :: ndx, ndy, ndz, ndt + REAL :: plq, tmp + GAUGE_FIELD ::u + REAL, external :: sg + integer, external :: std_xyzt2i, e_o + + write(*,*)"read_phmc_config: start" + + open(40,file="config.x0y0z0",status='unknown',form='unformatted') + write(*,*)"read_phmc_config: open config.x0y0z0" + + read(40)phmc_u + write(*,*)"read_phmc_config: have read config.x0y0z0" + + read(40)NTX,NTY,NTZ,NTT + read(40)NDX,NDY,NDZ + read(40)plq + + jmu(1)=4 + jmu(2)=3 + jmu(3)=2 + jmu(4)=1 + + do imu = 1,4 + do it=1,4 + itb=it/2 + do iz=1,4 + do iy=1,4 + do ix=1,4 + ieo=mod(ix + iy + iz + it, 2) + j=(/ ix-1 , iy-1, iz-1, it-1/) + jj=std_xyzt2i(j) + ee=e_o(j) + u(:,:, jj ,ee, imu )=phmc_u%eo(ieo)%mu(imu)%s(itb,iz,iy,ix)%u + enddo + enddo + enddo + enddo + enddo + + gauge(1)%u=u + + call xbound_g_field(gauge(1)%u) + call d_g_init(gauge(1)%u) + call conf_check(gauge(1)%u) + + !!call conf_hot(gauge(1)%u) + tmp=sg(gauge(1)%u) + write(*,*)"plaq value calculated by bqcd", ONE - tmp / (SIX * volume) + +end + +!------------------------------------------------------------------------------- +subroutine read_phmc_sf_config() + use module_vol + use module_field + implicit none + integer :: ix, iy, iz, it, ieo, imu, j(4), itb, jmu(4) , ee, jj, ic,jc + integer :: ntx, nty, ntz, ntt + integer :: ndx, ndy, ndz, ndt + COMPLEX, dimension(3,3,0:4,4,4,4,4) :: ue, uo + REAL :: plq, tmp + GAUGE_FIELD ::u + REAL, external :: sg + integer, external :: std_xyzt2i, e_o + + write(*,*)"read_phmc_sf_config: start" + + open(40,file="config.x0y0z0",status='unknown',form='unformatted') + write(*,*)"read_phmc_config: open config.x0y0z0" + + read(40)ue, uo + write(*,*)"read_phmc_config: have read config.x0y0z0" + + jmu(1)=4 + jmu(2)=3 + jmu(3)=2 + jmu(4)=1 + + do imu = 1,4 + do it=1,8 + itb=it/2 + do iz=1,4 + do iy=1,4 + do ix=1,4 + ieo=mod(ix + iy + iz + it, 2) + j=(/ ix-1 , iy-1, iz-1, it-1/) + jj=std_xyzt2i(j) + ee=e_o(j) + if (ieo == 0) u(:,:, jj ,ee, imu ) = ue(:,:,itb,iz,iy,ix,imu) + if (ieo == 1) u(:,:, jj ,ee, imu ) = uo(:,:,itb,iz,iy,ix,imu) + enddo + enddo + enddo + enddo + enddo + + gauge(1)%u=u + + call xbound_g_field(gauge(1)%u) + call d_g_init(gauge(1)%u) + call conf_check(gauge(1)%u) + + !!call conf_hot(gauge(1)%u) + tmp=sg(gauge(1)%u) + write(*,*)"plaq value calculated by bqcd", ONE - tmp / (SIX * volume) + call flush(6) +end + +!=============================================================================== diff --git a/src/measure/ppp.F90 b/src/measure/ppp.F90 deleted file mode 100644 index c7eb7d86d23269b56f35333452c6712d16d28f94..0000000000000000000000000000000000000000 --- a/src/measure/ppp.F90 +++ /dev/null @@ -1,93 +0,0 @@ -!=============================================================================== -! -! ppp.F90 -! -!------------------------------------------------------------------------------- -! -! Copyright (C) 2007 Yoshifumi Nakamura -! -! This file is part of BQCD -- Berlin Quantum ChromoDynamics program -! -! BQCD 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 Foundation, either version 3 of the License, or -! (at your option) any later version. -! -! BQCD is distributed in the hope that it will be useful, -! but WITHOUT ANY WARRANTY; without even the implied warranty of -! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -! GNU General Public License for more details. -! -! You should have received a copy of the GNU General Public License -! along with BQCD. If not, see <http://www.gnu.org/licenses/>. -! -!------------------------------------------------------------------------------- -# include "defs.h" -# include "defs_imp_2p1.h" - -!------------------------------------------------------------------------------- -subroutine ppp(tmp,tmp_e,tmp_o,name) - - use module_function_decl - use module_lattice_io - use module_decomp - use module_vol - implicit none - SPINCOL_FIELD,intent(in) :: tmp_e,tmp_o - SPINCOL_FIELD_XYZT,intent(out) :: tmp - - character(len=3) :: name - integer, dimension(DIM) :: j - integer :: x, y, z, t, i, eo, mu, c - integer, external :: std_xyzt2i, e_o - - do t = 0, NT - 1 - do z = 0, NZ - 1 - do y = 0, NY - 1 - do x = 0, NX - 1 - - j = (/x, y, z, t/) - - i = std_xyzt2i(j) - eo = e_o(j) - - do mu = 1, DIM - do c = 1, NCOL -! if (action == "read") then -! u(c1, c2, i, eo, mu) = u_io(c1, c2, mu, x, y, z, t) -! else - if (eo == EVEN )tmp(mu, c, x, y, z, t) = tmp_e(mu, c, i) - if (eo == ODD )tmp(mu, c, x, y, z, t) = tmp_o(mu, c, i) -! endif - enddo - enddo - enddo - enddo - enddo - enddo - -if (my_pe()==0)then - do t = 0, 0!NT - 1 - do z = 0, 0!NZ - 1 - do y = 0, 0!NY - 1 - do x = 0, 0!NX - 1 - do c = 1, 3 - do mu = 1, 4 - if (Re(tmp(mu,c,x,y,z,t)) /= ZERO .or.& - Im(tmp(mu,c,x,y,z,t)) /= ZERO )& - write(*,100)"%%%",name,& - my_pe(),mu,c,x,y,z,t, & - Re(tmp(mu,c,x,y,z,t)),Im(tmp(mu,c,x,y,z,t)) - enddo - enddo - enddo - enddo - enddo - enddo -endif - -100 format (1x, 2a, 7i3, 2ES17.7) - -end - -!=============================================================================== diff --git a/src/measure/reduction_space.F90 b/src/measure/reduction_space.F90 deleted file mode 100644 index 5a70c9d49e10a30033e3798ab2f954037fbf5fdd..0000000000000000000000000000000000000000 --- a/src/measure/reduction_space.F90 +++ /dev/null @@ -1,64 +0,0 @@ -!=============================================================================== -! -! reduction_space.F90 -! -!------------------------------------------------------------------------------- -! -! Copyright (C) 2007 Yoshifumi Nakamura -! -! This file is part of BQCD -- Berlin Quantum ChromoDynamics program -! -! BQCD 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 Foundation, either version 3 of the License, or -! (at your option) any later version. -! -! BQCD is distributed in the hope that it will be useful, -! but WITHOUT ANY WARRANTY; without even the implied warranty of -! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -! GNU General Public License for more details. -! -! You should have received a copy of the GNU General Public License -! along with BQCD. If not, see <http://www.gnu.org/licenses/>. -! -!------------------------------------------------------------------------------- -# include "defs.h" - -!------------------------------------------------------------------------------- -subroutine reduction_eo_std(out,in_e,in_o) - - use module_decomp - use module_vol - implicit none - COMPLEX, dimension(volh), intent(in) :: in_e,in_o - COMPLEX, dimension(vol ), intent(out) :: out - - integer, dimension(DIM) :: j - integer :: x, y, z, t, i, eo, icount - integer :: nx, ny, nz, nt - integer, external :: std_xyzt2i, e_o - - nx = decomp%std%N(1) - ny = decomp%std%N(2) - nz = decomp%std%N(3) - nt = decomp%std%N(4) - - icount = 1 - do t = 0, nt - 1 - do z = 0, nz - 1 - do y = 0, ny - 1 - do x = 0, nx - 1 - j = (/x, y, z, t/) - i = std_xyzt2i(j) - eo = e_o(j) - if (eo == EVEN )out(icount) = in_e(i) - if (eo == ODD )out(icount) = in_o(i) - icount = icount + 1 - enddo - enddo - enddo - enddo - -end - -!=============================================================================== diff --git a/src/measure/schr_pcac.F90 b/src/measure/schr_pcac.F90 new file mode 100644 index 0000000000000000000000000000000000000000..dda0d08d4f5f986bdebc59ab4ae20acd45cf6b16 --- /dev/null +++ b/src/measure/schr_pcac.F90 @@ -0,0 +1,295 @@ +!=============================================================================== +! +! schr_pcac.F90 - pcac for SF +! +!------------------------------------------------------------------------------- +! +! Copyright (C) 2011 Yoshifumi Nakamura +! +! This file is part of BQCD -- Berlin Quantum ChromoDynamics program +! +! BQCD 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 Foundation, either version 3 of the License, or +! (at your option) any later version. +! +! BQCD is distributed in the hope that it will be useful, +! but WITHOUT ANY WARRANTY; without even the implied warranty of +! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +! GNU General Public License for more details. +! +! You should have received a copy of the GNU General Public License +! along with BQCD. If not, see <http://www.gnu.org/licenses/>. +! +!------------------------------------------------------------------------------- +# include "defs.h" + +!------------------------------------------------------------------------------- +subroutine schr_pcac(job,traj) + use module_action + use module_input + use hadron_corr + use module_vol + use module_switches + use module_lattice + use module_function_decl + implicit none + integer, intent(in) :: job, traj + integer :: mid, it + REAL, dimension(lt) :: fa0, fp0, fa1, fp1 + logical, save :: fileopen = .false. + character(len = 15) :: filename + + if (.not. switches%boundary_sf) return + DEBUG2S("Start: schr_pcac") + + call gamma_init() + mid = action%fermi( input%hmc_mpf_mass )%mid1 + + allocate(qprop(1)) + allocate(qprop(1)%g(4,4,3,3,volh, EVEN:ODD)) + call get_qprop_schrpcac(qprop(1), mid, 0) ; call fafp(qprop(1), fa0, fp0) + call get_qprop_schrpcac(qprop(1), mid, 1) ; call fafp(qprop(1), fa1, fp1) + if (.not. fileopen) then + write(filename, "(a, i6.6)" ) "fAfPhist.", job + open(60, file = filename, action = "write") + fileopen = .true. + endif + + if (my_pe()==0) then +!! do it = 1, lt +!! write(60,'(I6,I3,4E24.16)')traj, it,-fa0( it ), fp0( it ), & +!! fa1(lt-it+1), fp1(lt-it+1) +!! enddo + do it = 1, lt-1 + write(60,'(I6,I3,4E24.16)')traj, it+1,-fa0( it+1), fp0( it+1), & + fa1(lt-it+1), fp1(lt-it+1) + enddo + endif + deallocate(qprop) + + DEBUG2S("End: schr_pcac") +end + +!------------------------------------------------------------------------------- +subroutine fafp(qprop0, fa, fp) + use gamma + use hadron_corr + use module_lattice + use module_function_decl + implicit none + type(quark_prop), intent(in) :: qprop0 + REAL, intent(out) :: fa(0:lt-1), fp(0:lt-1) + integer :: is0, is1, is2, ic1, ic2, ix,iy,iz,it, j(4), coord(4), ii, eo + COMPLEX :: ctmpa, ctmpp, zgm + integer, external :: e_o, std_xyzt2i + + call pe2coord(my_pe(), coord) + fa = ZERO + fp = ZERO + + do it = 0, nt-1 + ctmpa = ZERO + ctmpp = ZERO + do is1 = 1, 4 + is0 =igamma(is1,4) + zgm =zgamma(is1,4) + do is2 = 1, 4 + do iz = 0, nz-1 + do iy = 0, ny-1 + do ix = 0, nx-1 + j = (/ix, iy, iz, it/) + ii = std_xyzt2i(j) + eo = e_o(j) + do ic1 = 1, 3 + do ic2 = 1, 3 + ctmpa = ctmpa + zgm * qprop0%g(is0,is2,ic1,ic2,ii,eo) & + * conjg(qprop0%g(is1,is2,ic1,ic2,ii,eo)) + ctmpp = ctmpp + qprop0%g(is1,is2,ic1,ic2,ii,eo) & + * conjg(qprop0%g(is1,is2,ic1,ic2,ii,eo)) + enddo + enddo + enddo + enddo + enddo + enddo ! is2 + enddo ! is1 + fa( it + nt*coord(4) ) = ctmpa + fp( it + nt*coord(4) ) = ctmpp + enddo + + call global_sum_vec(lt, fa) + call global_sum_vec(lt, fp) + fa=fa/dble(2*lx*ly*lz) + fp=fp/dble(2*lx*ly*lz) + +end + +!------------------------------------------------------------------------------- +subroutine get_qprop_schrpcac(qprop0, mid, prime) + use hadron_corr + use module_vol + implicit none + type(quark_prop), intent(out) :: qprop0 + integer, intent(in) :: mid, prime + SPINCOL_FIELD :: inp_e, inp_o, out_e, out_o + integer :: is, ic + + DEBUG2S("Start: get_qprop_schrpcac") + call init_quark(mid) + do ic = 1, 3 + do is = 1, 4 + call make_source_schrpcac(inp_e, inp_o, is, ic, prime) + call solve(mid, out_e, out_o, inp_e, inp_o) + call put_quark_source(qprop0%g(1,1,1,1,1,0), & + qprop0%g(1,1,1,1,1,1), out_e, out_o, is, ic) + enddo + enddo + DEBUG2S("End: get_qprop_schrpcac") +end + +!------------------------------------------------------------------------------- +subroutine make_source_schrpcac(even, odd, is, ic, prime) + use module_vol + use module_field + use module_stout_field + implicit none + integer, intent(in) :: is,ic,prime + SPINCOL_FIELD, intent(out) :: even, odd + + if (gauge(2)%sid == 0) then + call make_source_schrpcac_u(even, odd, is, ic, prime, gauge(1)%u) + else + call make_source_schrpcac_u(even, odd, is, ic, prime, stout(1)%iter(stout(1)%n)%u) + endif + +end + +!------------------------------------------------------------------------------- +subroutine make_source_schrpcac_u(even, odd, is, ic, prime, u) + use module_lattice + use module_vol + use module_function_decl + use module_nn + implicit none + integer :: coord(4), j(4) + integer :: it,iz,iy,ix,ii,jj,eo,src_t + integer, intent(in) :: is,ic,prime + SPINCOL_FIELD, intent(out) :: even, odd + GAUGE_FIELD, intent(in) :: u + integer, external :: std_xyzt2i, e_o + + DEBUG2S("Start: make_source_schrpcac_u") + + call pe2coord(my_pe(), coord) + even = ZERO + odd = ZERO + select case (prime) + case (0) ! for [\psi(x)\zeta(y)] + if (is == 3 .or. is == 4) return + src_t = 1 + it = src_t - nt*coord(4) + if ( 0<=it .and. it < nt) then + do iz=0,nz-1 + do iy=0,ny-1 + do ix=0,nx-1 + j = (/ix, iy, iz, it/) + ii = std_xyzt2i(j) + eo = e_o(j) + jj = nn(ii, eo, 4, BWD) + if (eo == EVEN) then + even(is,:,ii) = dconjg(u(ic, :, jj, 1-eo, 4)) + else + odd(is,:,ii) = dconjg(u(ic, :, jj, 1-eo, 4)) + endif + enddo + enddo + enddo + endif + case (1) ! for [\psi(x)\zeta'(y)] + if (is == 1 .or. is == 2) return + src_t = lt - 1 + it = src_t - nt*coord(4) + if ( 0<=it .and. it < nt) then + do iz=0,nz-1 + do iy=0,ny-1 + do ix=0,nx-1 + j = (/ix, iy, iz, it/) + ii = std_xyzt2i(j) + eo = e_o(j) + if (eo == EVEN) then + even(is,:,ii) = u(:, ic, ii, eo, 4) + else + odd(is,:,ii) = u(:, ic, ii, eo, 4) + endif + enddo + enddo + enddo + endif + case default + call die("make_source_schrpcac_u: Invalid prime") + end select + + DEBUG2S("End: make_source_schrpcac_u") +end + +!=============================================================================== +! for checking +!------------------------------------------------------------------------------- +subroutine read_phmc_sf_config() + use module_vol + use module_field + implicit none + integer :: ix, iy, iz, it, ieo, imu, j(4), itb, jmu(4) , ee, jj, ic,jc + integer :: ntx, nty, ntz, ntt + integer :: ndx, ndy, ndz, ndt + COMPLEX, dimension(3,3,0:4,4,4,4,4) :: ue, uo + REAL :: plq, tmp + GAUGE_FIELD ::u + REAL, external :: sg + integer, external :: std_xyzt2i, e_o + + write(*,*)"read_phmc_sf_config: start" + + open(40,file="config.x0y0z0",status='unknown',form='unformatted') + write(*,*)"read_phmc_config: open config.x0y0z0" + + read(40)ue, uo + write(*,*)"read_phmc_config: have read config.x0y0z0" + + jmu(1)=4 + jmu(2)=3 + jmu(3)=2 + jmu(4)=1 + + do imu = 1,4 + do it=1,8 + itb=it/2 + do iz=1,4 + do iy=1,4 + do ix=1,4 + ieo=mod(ix + iy + iz + it, 2) + j=(/ ix-1 , iy-1, iz-1, it-1/) + jj=std_xyzt2i(j) + ee=e_o(j) + if (ieo == 0) u(:,:, jj ,ee, imu ) = ue(:,:,itb,iz,iy,ix,imu) + if (ieo == 1) u(:,:, jj ,ee, imu ) = uo(:,:,itb,iz,iy,ix,imu) + enddo + enddo + enddo + enddo + enddo + + gauge(1)%u=u + + call xbound_g_field(gauge(1)%u) + call d_g_init(gauge(1)%u) + call conf_check(gauge(1)%u) + + !!call conf_hot(gauge(1)%u) + tmp=sg(gauge(1)%u) + write(*,*)"plaq value calculated by bqcd", ONE - tmp / (SIX * volume) +!! call flush(6) +end + +!=============================================================================== diff --git a/src/measure/traces.F90 b/src/measure/traces.F90 index 52d1acc071dbeb9f188bf9bd76b451a2b57dc1c1..63ca56dc067216eb74f086bd802dc1d2260f26f9 100644 --- a/src/measure/traces.F90 +++ b/src/measure/traces.F90 @@ -194,7 +194,7 @@ subroutine eo_solve(mid, out_e, out_o, in_e, in_o) ! solves: M out = in SPINCOL_FIELD, intent(in) :: in_e, in_o P_SPINCOL_FIELD, save :: tmp - REAL :: a, b, res + REAL :: a, b, res, fac1, fac2 integer :: iterations, cid DEBUG2S("Start: solve_eo") @@ -204,8 +204,13 @@ subroutine eo_solve(mid, out_e, out_o, in_e, in_o) ! solves: M out = in b = action%mtilde(mid)%kappa / (ONE + action%mtilde(mid)%h**2) cid = action%mtilde(mid)%cid -! in : xi -! out : phi + fac1=exp( chemi) + fac2=exp(-chemi) + if (chemi /= 0)call emuu4(gauge(2)%u, fac1, fac2, .false.) + + + ! in : xi + ! out : phi ! (Moo)^{-1} xi_o if (action%mtilde(mid)%cswkappa /= ZERO) then @@ -221,8 +226,9 @@ subroutine eo_solve(mid, out_e, out_o, in_e, in_o) ! solves: M out = in ! xi_e = xi_e - Meo Moo^-1 xi_o call d(se, so, out_e, out_o, gauge(2)%u) call sc_xpby(out_e, in_e, b) + if (chemi /= 0)call emuu4(gauge(2)%u, ONE, ONE, .false.) -! phi_e = phi_e = (\tilde{M}^{\dagger}\tilde{M})^{-1} \tilde{M}^{\dagger} xi_e + ! phi_e = phi_e = (\tilde{M}^{\dagger}\tilde{M})^{-1} \tilde{M}^{\dagger} xi_e #ifdef OMTDTD if (action%mtilde(mid)%cswkappa /= ZERO) then call clover_mult_ao(clover(cid)%i(1,1,se), out_e, volh) @@ -234,19 +240,22 @@ subroutine eo_solve(mid, out_e, out_o, in_e, in_o) ! solves: M out = in call mtil_dag(tmp, out_e, mid) call cg_outer(out_e, tmp, mid, 0, CG_MC) -! Moe phi_e + ! Moe phi_e + if (chemi /= 0)call emuu4(gauge(2)%u, fac1, fac2, .false.) call d(so, se, out_o, out_e, gauge(2)%u) -! xi_o - Moe phi_e + ! xi_o - Moe phi_e call sc_axpby(out_o, in_o, b, a)!(inout, in, b, a) ! inout = b * inout + a * in -! phi_o = Moo^{-1} ( xi_o - Moe phi_e ) + ! phi_o = Moo^{-1} ( xi_o - Moe phi_e ) if (action%mtilde(mid)%cswkappa /= ZERO) then call clover_mult_ao(clover(cid)%i(1,1,so), out_o, volh) else if (action%mtilde(mid)%h /= ZERO) call h_mult_b(-action%mtilde(mid)%h, out_o, volh) endif + if (chemi /= 0)call emuu4(gauge(2)%u, ONE, ONE, .false.) + DEBUG2S("End: solve_eo") end @@ -292,7 +301,7 @@ subroutine check_solution(mid, zeta_e, zeta_o, eta_e, eta_o) integer, intent(in) :: mid SPINCOL_FIELD, intent(in) :: zeta_e, zeta_o, eta_e, eta_o P_SPINCOL_FIELD, save :: tmp1, tmp2 - REAL :: kappa, residual1, residual2, bb + REAL :: kappa, residual1, residual2, bb, fac1, fac2 integer :: cid ALLOCATE_SC_FIELD(tmp1) @@ -301,8 +310,11 @@ subroutine check_solution(mid, zeta_e, zeta_o, eta_e, eta_o) cid = action%mtilde(mid)%cid kappa = action%mtilde(mid)%kappa - bb=sc_norm2(eta_e) + sc_norm2(eta_o) ; bb=global_sum(bb) + fac1 = exp( chemi) + fac2 = exp(-chemi) + if (chemi /= 0)call emuu4(gauge(2)%u, fac1, fac2, .false.) + bb=sc_norm2(eta_e) + sc_norm2(eta_o) ; bb=global_sum(bb) ! (1) Mee zeta_e + Meo zeta_o = eta_e ! (2) Moe zeta_e + Moo zeta_o = eta_o @@ -331,52 +343,7 @@ subroutine check_solution(mid, zeta_e, zeta_o, eta_e, eta_o) if (my_pe()==0)write(0,*) "residual of solution |b-Dx|/|b|: ", & sqrt(residual1+residual2)/sqrt(bb) -end - -!------------------------------------------------------------------------------- -subroutine make_propagator() - use module_field - use module_action - use module_input - use module_function_decl - use module_p_interface - use module_vol - use module_cg - implicit none - - P_SPINCOL_FIELD, save :: in_e, in_o, out_e, out_o - SECONDS :: time0, sekunden, time - integer :: fid, mid, cid, iters, mu, col - DOUBLE :: res - - fid = max(input%hmc_mpf_dd_mass,input%hmc_mpf_mass) - fid = max(input%hmc_mpf_hh_mass,fid) - fid = max(input%hmc_mpf_un_mass,fid) - - if (fid <= 0 .or. fid > 5 ) call die("traces: unexpected fid") - mid = action%fermi(fid)%mid1 - - ALLOCATE_SC_FIELD(in_e) - ALLOCATE_SC_FIELD(in_o) - ALLOCATE_SC_FIELD(out_e) - ALLOCATE_SC_FIELD(out_o) - - call init_cg_stat(cg_stat) - call init_imp_all(.true.) - - if (my_pe()==0) write(0,*) "WALL SOURCE" - call make_source_wall(1,1,0,in_e,in_o) - call solve(mid, out_e, out_o, in_e, in_o) ! solves: M out = in - - if (my_pe()==0) then - write(0,*)"solver summary:CG" - write(0,*)"first 12 components" - do col=1,3 - do mu=1,4 - write(0,*)mu,col,out_e(mu,col,1) - enddo - enddo - endif + if (chemi /= 0)call emuu4(gauge(2)%u, ONE, ONE, .false.) end diff --git a/src/measure/vector12.F90 b/src/measure/vector12.F90 deleted file mode 100644 index 9ca29afa602caf6e69a86db06f2f57c5e1d6fcd0..0000000000000000000000000000000000000000 --- a/src/measure/vector12.F90 +++ /dev/null @@ -1,106 +0,0 @@ -!=============================================================================== -! -! vector12.F90 -! -!------------------------------------------------------------------------------- -! -! Copyright (C) 2007 Yoshifumi Nakamura -! -! This file is part of BQCD -- Berlin Quantum ChromoDynamics program -! -! BQCD 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 Foundation, either version 3 of the License, or -! (at your option) any later version. -! -! BQCD is distributed in the hope that it will be useful, -! but WITHOUT ANY WARRANTY; without even the implied warranty of -! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -! GNU General Public License for more details. -! -! You should have received a copy of the GNU General Public License -! along with BQCD. If not, see <http://www.gnu.org/licenses/>. -! -!------------------------------------------------------------------------------- -# include "defs.h" - -!------------------------------------------------------------------------------- -subroutine global_sum_vector12(sc,in_e,in_o) - - use module_function_decl - use module_vol - implicit none - COMPLEX, dimension(DIM,NCOL), intent(out) :: sc - SPINCOL_FIELD, intent(in) :: in_e, in_o - COMPLEX :: tmp - REAL :: re, im - integer :: i, mu, c - - do c = 1, 3 - do mu = 1, 4 - tmp = ZERO - !$omp parallel do reduction(+: tmp) - do i = 1, volh - tmp = tmp + in_e(mu,c,i) - enddo - !$omp parallel do reduction(+: tmp) - do i = 1, volh - tmp = tmp + in_o(mu,c,i) - enddo - re = global_sum(dble(tmp)) - im = global_sum(dimag(tmp)) - sc(mu,c) = cmplx( re, im, kind = RKIND) - enddo - enddo - -end - -!------------------------------------------------------------------------------- -subroutine write_vector12_0000_sum(in_e,in_o,name) - - use module_function_decl - use module_vol - implicit none - SPINCOL_FIELD, intent(in) :: in_e, in_o - character( len = 6), intent(in) :: name - - COMPLEX, dimension(DIM,NCOL) :: sc - character( len = 10) :: name1, name2 - - call global_sum_vector12(sc, in_e, in_o) - - write(name1,10)name,"0000" - write(name2,10)name,"_sum" - - call write_vector12(0, in_e(1,1,1), name1) - call write_vector12(0, sc, name2) - -10 format (2a) - -end - -!------------------------------------------------------------------------------- -subroutine write_vector12(pe,sc,name) - - use module_function_decl - implicit none - COMPLEX, dimension(DIM,NCOL), intent(in) :: sc - integer, intent(in) :: pe - character( len = 10) :: name - integer :: mu, c - - - if (my_pe() == pe) then - do c = 1, 3 - do mu = 1, 4 - write(*,100)"%%%",name,& - my_pe(),mu,c,dble(sc(mu,c)),dimag(sc(mu,c)) - enddo - enddo - endif - -100 format (1x, 2a, 3i3, 2ES17.7) - -end - -!=============================================================================== diff --git a/src/modules/Makefile b/src/modules/Makefile index 1207e00488ef5281db5f1dffe93f536a116a4005..370bf1c26cab61bb8ffb33a670ea346e32447735 100644 --- a/src/modules/Makefile +++ b/src/modules/Makefile @@ -36,7 +36,13 @@ fpp = $(FPP) -I../include $(MYFLAGS) MODULES_DIR = . -MODULES = \ +ifdef quad +MODULES = typedef_clover_r16.o +else +MODULES = +endif + +MODULES += \ typedef_cksum.o \ typedef_clover.o \ typedef_clover_r4.o \ @@ -73,16 +79,38 @@ MODULES = \ module_schr_weight.o \ module_surface.o +ifdef quad +MODULES += \ + module_p_interface_r16.o \ + module_mre_r16.o +endif + modules: $(MODULES) fast: $(MAKE) +module_mre_r16.o: module_mre.F90 + $(fpp) -DPRECISION_R16 $< > $*.f90 + $(F90) -c $(FFLAGS) $*.f90 + typedef_clover_r4.o: typedef_clover.F90 + $(fpp) -DPRECISION_R4 $< > $*.f90 + $(F90) -c $(FFLAGS32) $*.f90 + +typedef_clover_r16.o: typedef_clover.F90 + $(fpp) -DPRECISION_R16 $< > $*.f90 + $(F90) -c $(FFLAGS) $*.f90 typedef_hmc_r4.o: typedef_hmc.F90 module_p_interface_r4.o: module_p_interface.F90 + $(fpp) -DPRECISION_R4 $< > $*.f90 + $(F90) -c $(FFLAGS32) $*.f90 + +module_p_interface_r16.o: module_p_interface.F90 + $(fpp) -DPRECISION_R16 $< > $*.f90 + $(F90) -c $(FFLAGS) $*.f90 module_input.o: module_input.F90 m4 test.m4 >ttt.h diff --git a/src/modules/module_action.F90 b/src/modules/module_action.F90 index e021ea41113db27cfaab4a6ed6d4e436af68dc57..5ce9c8306225defc52c68bb0347b71f24598836a 100644 --- a/src/modules/module_action.F90 +++ b/src/modules/module_action.F90 @@ -135,6 +135,8 @@ module module_action integer, parameter :: so = 1 #endif + REAL, save :: chemi + end !=============================================================================== diff --git a/src/modules/module_bqcd.F90 b/src/modules/module_bqcd.F90 index 85eee13544997acd0d7090f9f9b0139e2db7b83c..56682d09bdd0e0d2e09b52dd513144b8724ed5f4 100644 --- a/src/modules/module_bqcd.F90 +++ b/src/modules/module_bqcd.F90 @@ -30,7 +30,7 @@ module module_bqcd character(len = *), parameter :: prog_name = "bqcd" - character(len = *), parameter :: prog_version = "4.0.0" + character(len = *), parameter :: prog_version = "4.1.0" character(len = n), parameter :: prog_revision = & " (revision" // trim(svn_revision(11:n-1)) // ")" diff --git a/src/modules/module_cg.F90 b/src/modules/module_cg.F90 index 7e4b5243810f915064e6a5fcf354deac795c74d0..079b6482ba85ba4256b76e951dd29f772ab41d79 100644 --- a/src/modules/module_cg.F90 +++ b/src/modules/module_cg.F90 @@ -223,7 +223,7 @@ end subroutine update_cg_stat !------------------------------------------------------------------------------- logical function stop_condition(rtr, res, b) implicit none - REAL,intent(in) :: rtr, res, b + REAL8,intent(in) :: rtr, res, b stop_condition = .false. @@ -235,6 +235,22 @@ logical function stop_condition(rtr, res, b) end function stop_condition +!------------------------------------------------------------------------------- +#ifdef QUAD +logical function stop_condition_r16(rtr, res, b) + implicit none + REAL16,intent(in) :: rtr, res, b + + stop_condition_r16 = .false. + + if (criterion == 0) then + stop_condition_r16 = (rtr <= res) + else + stop_condition_r16 = (rtr <= b*res**2 ) + endif + +end function stop_condition_r16 +#endif !------------------------------------------------------------------------------- REAL function res_cg_inner(res, rtr, b, n) implicit none diff --git a/src/modules/module_field.F90 b/src/modules/module_field.F90 index 212d2ec1c3349aff2e60c4d81e1ecdb854e22e27..e30a25672939040ca62d3a3188f6f1687ea97e40 100644 --- a/src/modules/module_field.F90 +++ b/src/modules/module_field.F90 @@ -41,6 +41,11 @@ module module_field type(gauge_field_r4), dimension(:),pointer,save :: gauge_r4 type(clover_field_r4), dimension(:),pointer,save :: clover_r4 +#ifdef QUAD + type(gauge_field_r16), dimension(:),pointer,save :: gauge_r16 + type(clover_field_r16), dimension(:),pointer,save :: clover_r16 +#endif + #ifdef BAGEL COMPLEX, dimension (:,:,:,:,:), pointer, save :: bagel_u #endif diff --git a/src/modules/module_function_decl.F90 b/src/modules/module_function_decl.F90 index c1b0c1f6ae21f4b60abe84affa0a8aee19a8de0e..d4b04c2c4437d89221473614e93da85dfd94e26f 100644 --- a/src/modules/module_function_decl.F90 +++ b/src/modules/module_function_decl.F90 @@ -58,6 +58,12 @@ module module_function_decl REAL, external :: global_min REAL, external :: global_max +#ifdef QUAD +!! REAL, external :: dotprod + REAL, external :: global_sum_r16 + REAL, external :: global_min_r16 + REAL, external :: global_max_r16 +#endif ! sc-field (-> sc.F90) @@ -71,6 +77,14 @@ module module_function_decl REAL4, external :: sc_dot_r4 COMPLEX4, external :: sc_cdotc_r4 + ! sc-field (-> sc_r16.F90) + +#ifdef QUAD + REAL16, external :: sc_norm2_r16 + REAL16, external :: sc_dot_r16 + COMPLEX16, external :: sc_cdotc_r16 +#endif + ! random numbers (-> ran/.../ran.F90): RAN_NAME, external :: ran_name diff --git a/src/modules/module_input.F90 b/src/modules/module_input.F90 index bb628849c45d3d79f3066258826a19b658d39ab3..75af28dafbb892a63cb743f2fdd3d57a6a71a7d6 100644 --- a/src/modules/module_input.F90 +++ b/src/modules/module_input.F90 @@ -180,6 +180,7 @@ contains allocate(input%n_stout(size)) allocate(input%alpha(size)) allocate(input%theta(size)) + allocate(input%chemi(size)) allocate(input%u04(size)) allocate(input%start_info_file(size)) @@ -206,6 +207,7 @@ contains input%n_stout = "0" input%alpha = "0.0" input%theta = "0.0" + input%chemi = "0.0" input%u04 = "0.0" input%start_info_file = "" @@ -241,6 +243,7 @@ contains deallocate(input%n_stout) deallocate(input%alpha) deallocate(input%theta) + deallocate(input%chemi) deallocate(input%u04) deallocate(input%start_info_file) diff --git a/src/modules/module_input.h b/src/modules/module_input.h index a631e3f53649ce27f1924dc97a0ec6a230579a68..e89db44aaccecc391c350de5cc794ba8cce4330b 100644 --- a/src/modules/module_input.h +++ b/src/modules/module_input.h @@ -6,7 +6,7 @@ #------------------------------------------------------------------------------- # # Copyright (C) 2003-2010 Hinnerk Stueben -# 2007-2010 Yoshifumi Nakamura +# 2007-2011 Yoshifumi Nakamura # # This file is part of BQCD -- Berlin Quantum ChromoDynamics program # @@ -72,6 +72,8 @@ INPUT_INPUT(ran_ranlux_level, integer, 2) INPUT_INPUT(measure_cooling_list, FILENAME, "") INPUT_INPUT(measure_polyakov_loop, integer, 0) INPUT_INPUT(measure_traces, integer, 0) +INPUT_INPUT(measure_chemical, integer, 0) +INPUT_INPUT(measure_schrpcac, integer, 0) INPUT_INPUT(tuning_xbound_sc_i, integer, 1) INPUT_INPUT(tuning_xbound_g_i, integer, 1) @@ -120,6 +122,7 @@ INPUT_INPUT(kappa_strange, INPUT_ARRAY_ENSEMBLES, "0.0") INPUT_INPUT(n_stout, INPUT_ARRAY_ENSEMBLES, "0") INPUT_INPUT(alpha, INPUT_ARRAY_ENSEMBLES, "0.0") INPUT_INPUT(theta, INPUT_ARRAY_ENSEMBLES, "0.0") +INPUT_INPUT(chemi, INPUT_ARRAY_ENSEMBLES, "0.0") INPUT_INPUT(hmc_integrator1, character(para_len), "LPFSTS") INPUT_INPUT(hmc_integrator2, character(para_len), "LPFSTS") @@ -192,6 +195,11 @@ INPUT_INPUT(solver_defsapgcr_nkv, integer, 16) INPUT_INPUT(solver_defsapgcr_nsp, integer, 8) INPUT_INPUT(solver_numkrylov_mtdmtdd, integer, 10) INPUT_INPUT(solver_numdefvec_mtdmtdd, integer, 0) + +INPUT_INPUT(solver_gcrodr_numarstep, integer, 10) +INPUT_INPUT(solver_gcrodr_numdefvec, integer, 5) + + INPUT_INPUT(fullsolver, character(para_len), "eo") INPUT_INPUT(measure_minmax, integer, 0) @@ -205,6 +213,11 @@ INPUT_INPUT(boundary_sf, integer, 0) INPUT_INPUT(nonactivelink, integer, 0) INPUT_INPUT(tuning_approx_range, integer, 0) INPUT_INPUT(tuning_approx_range_list, FILENAME, "") +INPUT_INPUT(tuning_fraction_tolerance, FILENAME, "") + +INPUT_INPUT(replay_trick_ntau, integer, 0) +INPUT_INPUT(replay_trick_threshold, character(para_len), "1.0") + ! ! TEST diff --git a/src/modules/module_mre.F90 b/src/modules/module_mre.F90 index f111bb8b353595c7e4c4826edf62aec776b1f86c..607f45a059a2016698c3b9ad8915e9e5b16b8fac 100644 --- a/src/modules/module_mre.F90 +++ b/src/modules/module_mre.F90 @@ -48,7 +48,7 @@ module module_mre2 integer, save :: mre2_n_vec = 0 type mre2_pointer - complex(8),pointer :: x(:) + COMPLEX,pointer :: x(:) end type mre2_pointer type type_mre2 @@ -63,8 +63,8 @@ module mre2_get_interface subroutine mre2_get(matrix, basis, trial, phi, id, ip) use module_mre2 type(type_mre2), intent(inout) :: basis - complex(8), intent(out) :: trial(:) - complex(8),target,intent(in) :: phi(:) + COMPLEX, intent(out) :: trial(:) + COMPLEX,target,intent(in) :: phi(:) external :: matrix integer, intent(in) :: id integer,optional, intent(in) :: ip diff --git a/src/modules/module_rhmc.F90 b/src/modules/module_rhmc.F90 index c8b157e37d36ffa3a0cb06c8efb6ad587d472cc2..f978bdc64f036611c47d0abd248b9de1d9a18f7c 100644 --- a/src/modules/module_rhmc.F90 +++ b/src/modules/module_rhmc.F90 @@ -39,6 +39,8 @@ module module_rhmc type(rational_approx), save :: ratapp(0:10) + REAL,dimension(:),pointer, save :: relax + end !=============================================================================== diff --git a/src/modules/module_svn.F90 b/src/modules/module_svn.F90 index 26fa5557ae10506b64977675f38d108e3b5971f7..a83423c14364a65ab06904ddce1c9c39a80d67dc 100644 --- a/src/modules/module_svn.F90 +++ b/src/modules/module_svn.F90 @@ -7,7 +7,7 @@ ! ! The modification is to increment "count" (see target "commit" in ../Makefile): ! -!count= 78 +!count= 124 ! !------------------------------------------------------------------------------- ! @@ -32,8 +32,8 @@ module module_svn - character(*), parameter :: svn_revision = "$Revision: 274 $" - character(*), parameter :: svn_date = "$Date: 2010-06-14 20:03:24 +0200 (Mon, 14 Jun 2010) $" + character(*), parameter :: svn_revision = "$Revision: 354 $" + character(*), parameter :: svn_date = "$Date: 2011-10-14 09:33:50 +0200 (Fri, 14 Oct 2011) $" end diff --git a/src/modules/module_switches.F90 b/src/modules/module_switches.F90 index eb76be9cdd78b7dab3a680f5101c07791bffadeb..08e5fac54dd367dca3d32fc1bb07a7d96879e58f 100644 --- a/src/modules/module_switches.F90 +++ b/src/modules/module_switches.F90 @@ -35,6 +35,8 @@ module module_switches logical :: hmc_test logical :: measure_polyakov_loop logical :: measure_traces + logical :: measure_chemical + logical :: measure_schrpcac logical :: improved_gauge logical :: rhmc @@ -52,6 +54,7 @@ module module_switches logical :: measure_correlations logical :: measurement_only logical :: boundary_sf + logical :: replay end type type_switches diff --git a/src/modules/typedef.F90 b/src/modules/typedef.F90 index 09980f8fdc5a47f824b2ff46025e1eea8440938e..dfe079451047276d65899bd44e448c24e338074e 100644 --- a/src/modules/typedef.F90 +++ b/src/modules/typedef.F90 @@ -28,11 +28,19 @@ # define P_CLOVER_FIELD_A_R4 type(type_clover_a_r4), dimension(:, :, :), pointer # define P_CLOVER_FIELD_B_R4 type(type_clover_b_r4), dimension(:, :, :), pointer +# define P_GAUGE_FIELD_R16 complex(16), dimension(:, :, :, :, :), pointer +# define P_CLOVER_FIELD_A_R16 type(type_clover_a_r16), dimension(:, :, :), pointer +# define P_CLOVER_FIELD_B_R16 type(type_clover_b_r16), dimension(:, :, :), pointer + !------------------------------------------------------------------------------- module typedef use typedef_clover use typedef_clover_r4 +#ifdef QUAD + use typedef_clover_r16 +#endif + type :: sc_field P_SPINCOL_FIELD :: sc P_SPINCOL_FIELD :: sc_e @@ -78,6 +86,23 @@ module typedef P_CLOVER_FIELD_B_R4 :: b end type clover_field_r4 +#ifdef QUAD + type gauge_field_r16 + logical :: init + integer :: sid + P_GAUGE_FIELD_R16 :: u + end type gauge_field_r16 + + type clover_field_r16 + logical :: init + integer :: nf + real(16) :: kappa, csw, cswkappa, theta + P_CLOVER_FIELD_A_R16 :: a + P_CLOVER_FIELD_A_R16 :: i + P_CLOVER_FIELD_B_R16 :: b + end type clover_field_r16 +#endif + end !=============================================================================== diff --git a/src/modules/typedef_hmc.F90 b/src/modules/typedef_hmc.F90 index e85831b45917aa1cbdc721b0c91668158fcb0dde..666322fec08f2c7d3edb20b1327f1341b0360b61 100644 --- a/src/modules/typedef_hmc.F90 +++ b/src/modules/typedef_hmc.F90 @@ -39,6 +39,7 @@ module typedef_hmc integer :: n_stout REAL :: alpha REAL :: theta + REAL :: chemi REAL :: h REAL :: traj_length REAL :: tau @@ -63,6 +64,7 @@ module typedef_hmc character(len = 20) :: n_stout character(len = 20) :: alpha character(len = 20) :: theta + character(len = 20) :: chemi character(len = 20) :: h character(len = 20) :: traj_length character(len = 20) :: tau diff --git a/src/platform/FMLIB_makefile b/src/platform/FMLIB_makefile new file mode 100644 index 0000000000000000000000000000000000000000..c77cf11740c4533089b8a698bd8d1e5a90a1dc59 --- /dev/null +++ b/src/platform/FMLIB_makefile @@ -0,0 +1,46 @@ +#=============================================================================== +# +# Sample Makefile for FMLIB +# +#------------------------------------------------------------------------------- +# +# Copyright (C) 2011 Yoshifumi Nakamura +# +# This file is part of BQCD -- Berlin Quantum ChromoDynamics program +# +# BQCD 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 Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BQCD is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BQCD. If not, see <http://www.gnu.org/licenses/>. +# +#=============================================================================== + +.SUFFIXES: +.SUFFIXES: .a .o .f90 + +F90=gfortran -O3 + +.f90.o: + $(F90) -c $(FFLAGS) $*.f90 + +OBJS = \ + FMSAVE.o \ + FMZM90.o \ + FM.o +# SampleFM.o \ +# TestFM.o + +lib_FM.a: $(OBJS) + ar rv $@ $(OBJS) + +clobber: + rm -f *.[Tiod] *.mod work.pc work.pcl + rm -f lib_FM.a diff --git a/src/platform/Makefile-EXPLAINED.var b/src/platform/Makefile-EXPLAINED.var index 0bfa87ed4f309209ee717e95fd7a98d611382a60..5c9bf8bf6edfb298b9f62b7a2196d364b690fa76 100644 --- a/src/platform/Makefile-EXPLAINED.var +++ b/src/platform/Makefile-EXPLAINED.var @@ -41,7 +41,7 @@ ARFLAGS = # additional flags (to "rv") LDFLAGS = # loader flags (loader = ${F90}) SYSLIBS = # system libraries (e.g. for BLAS) -FAST_MAKE = gmake -j 8 # parallel make +FAST_MAKE = gmake -j 1 # parallel make (currently make has to run serial) BLAS_O = # not used any more CKSUM_O = cksum.o # or "cksum_dummy.o" diff --git a/src/platform/Makefile-altix.var b/src/platform/Makefile-altix.var index 73a5c77fb81ecfb2370d4d0699a426cbaff639ba..e9440c7be7af166e7b770a8518df3df5c36ef082 100644 --- a/src/platform/Makefile-altix.var +++ b/src/platform/Makefile-altix.var @@ -49,7 +49,7 @@ ARFLAGS = LDFLAGS = -Vaxlib -lmpi SYSLIBS = -FAST_MAKE = gmake -j 8 +FAST_MAKE = gmake -j 1 BLAS_O = blas.o CKSUM_O = cksum.o diff --git a/src/platform/Makefile-altix2.var b/src/platform/Makefile-altix2.var index d684a0ad3c9528e6aa403b8ba36f18a1552f85f6..4d32111da588dffb78b9453277ae65cf0d7ff93e 100644 --- a/src/platform/Makefile-altix2.var +++ b/src/platform/Makefile-altix2.var @@ -43,14 +43,14 @@ CC = icc MODULES_FLAG = -I$(MODULES_DIR) MYFLAGS = -DINTEL -DALTIX -DMPI_1 -FFLAGS_STD= $(MODULES_FLAG) +FFLAGS_STD= $(MODULES_FLAG) -fno-alias CFLAGS_STD= -DNamesToLower_ ARFLAGS = LDFLAGS = -Vaxlib -lmpi SYSLIBS = -FAST_MAKE = gmake -j 8 +FAST_MAKE = gmake -j 1 CKSUM_O = cksum.o UUU_O = uuu_f90.o @@ -70,10 +70,14 @@ endif ifdef mpi LIBCOMM = lib_mpi.a LDFLAGS += -lsma +else + MYFLAGS += -DNONMPI + CFLAGS_STD+= -DNONMPI endif ifdef omp F90 += -openmp + CC += -openmp MYFLAGS += -D_OPENMP endif diff --git a/src/platform/Makefile-bluegene1-epcc.var b/src/platform/Makefile-bluegene1-epcc.var index 2b4b30f22a3e215354ad2a5a247382b9f1fcdf43..c98e0e9df3da63e84d7e096c5388a0f9aa3066e7 100644 --- a/src/platform/Makefile-bluegene1-epcc.var +++ b/src/platform/Makefile-bluegene1-epcc.var @@ -61,7 +61,7 @@ ARFLAGS = LDFLAGS = -L$(BGLSYS)/lib SYSLIBS = -lmpich.rts -lfmpich.rts -lmsglayer.rts -lrts.rts -ldevices.rts -FAST_MAKE = gmake -j 8 +FAST_MAKE = gmake -j 1 CKSUM_O = cksum.o UUU_O = uuu_f90.o diff --git a/src/platform/Makefile-cray.var b/src/platform/Makefile-cray.var index 1a9cb777d4872edb675a7023343766afd74209cd..d42be97b04b417fb6df97bdac24f1f535a1ed24c 100644 --- a/src/platform/Makefile-cray.var +++ b/src/platform/Makefile-cray.var @@ -41,7 +41,7 @@ ARFLAGS = LDFLAGS = SYSLIBS = -FAST_MAKE = NPROC=4 make +FAST_MAKE = NPROC=1 make BLAS_O = CKSUM_O = cksum.o diff --git a/src/platform/Makefile-gnu.var b/src/platform/Makefile-gnu.var index 5c4faba27d4b61b921ea6843770cb1a6ee255afb..c65e669d408d1909ff10b9b97719fa5a11d5015f 100644 --- a/src/platform/Makefile-gnu.var +++ b/src/platform/Makefile-gnu.var @@ -23,9 +23,9 @@ # #------------------------------------------------------------------------------- -timing = 1 +timing =1 mpi = -omp = +omp = shmem = shmempi = debug = @@ -37,15 +37,14 @@ random = ranlux-3.2 SHELL = /bin/ksh FPP = cpp -E -C -P -FPP2 = -F90 = gfortran -ffree-line-length-none -fno-range-check +F90 = gfortran CC = gcc MODULES_FLAG = -I$(MODULES_DIR) -MYFLAGS = -DNONMPI -FFLAGS_STD= $(MODULES_FLAG) -CFLAGS_STD= -DNamesToLower_ -DNONMPI +MYFLAGS = +FFLAGS_STD= $(MODULES_FLAG) -ffree-line-length-none -fno-range-check +CFLAGS_STD= -DNamesToLower_ -DLongLong ARFLAGS = LDFLAGS = @@ -69,7 +68,11 @@ endif ifdef mpi LIBCOMM = lib_mpi.a - LDFLAGS += -lsma + F90 = mpif90 + CC = mpicc +else + MYFLAGS += -DNONMPI + CFLAGS_STD+= -DNONMPI endif ifdef omp diff --git a/src/platform/Makefile-hitachi-omp.var b/src/platform/Makefile-hitachi-omp.var index f4d7a74f7050da026cb569c8159f34028c92d0e2..1798517d55dcab634e00b6f511f03fd16de3bde6 100644 --- a/src/platform/Makefile-hitachi-omp.var +++ b/src/platform/Makefile-hitachi-omp.var @@ -40,7 +40,7 @@ ARFLAGS = LDFLAGS = +BTLB -omp -rdma SYSLIBS = /usr/local/lib/liblrz.a -lf90c -lpl -FAST_MAKE = JOBTYPE=SS prun -p IAPAR gmake -j 8 +FAST_MAKE = JOBTYPE=SS prun -p IAPAR gmake -j 1 BLAS_O = blas.o CKSUM_O = cksum.o diff --git a/src/platform/Makefile-hitachi.var b/src/platform/Makefile-hitachi.var index ff915d8cfd67e3f10f4a407d24d7a465f4b7e335..5e28c8eaf78857d4b4c37308d4e79121501d4270 100644 --- a/src/platform/Makefile-hitachi.var +++ b/src/platform/Makefile-hitachi.var @@ -39,7 +39,7 @@ ARFLAGS = LDFLAGS = +BTLB SYSLIBS = /usr/local/lib/liblrz.a -lf90c -lpl -FAST_MAKE = JOBTYPE=SS prun -p IAPAR gmake -j 8 +FAST_MAKE = JOBTYPE=SS prun -p IAPAR gmake -j 1 BLAS_O = blas.o CKSUM_O = cksum.o diff --git a/src/platform/Makefile-hlrn2.var b/src/platform/Makefile-hlrn2.var index 946a0f2d752fedfb7e10ab0107a661d2f5ddd60f..4f8d3890f1f0e9eaace2cf9ed899259bde8ad790 100644 --- a/src/platform/Makefile-hlrn2.var +++ b/src/platform/Makefile-hlrn2.var @@ -4,7 +4,7 @@ # #------------------------------------------------------------------------------- # -# Copyright (C) 2008 Hinnerk Stueben +# Copyright (C) 2008-2011 Hinnerk Stueben # # This file is part of BQCD -- Berlin Quantum ChromoDynamics program # @@ -45,14 +45,14 @@ CC = icc MODULES_FLAG = -I$(MODULES_DIR) MYFLAGS = -DINTEL -DALTIX -DMPI_1 -FFLAGS_STD= $(MODULES_FLAG) -CFLAGS_STD= -DNamesToLower_ +FFLAGS_STD= $(MODULES_FLAG) -fno-alias +CFLAGS_STD= -DNamesToLower_ -DMPI_1 ARFLAGS = LDFLAGS = -Vaxlib SYSLIBS = -FAST_MAKE = gmake -j 8 +FAST_MAKE = make CKSUM_O = cksum.o UUU_O = uuu_f90.o @@ -89,6 +89,7 @@ endif ifdef omp F90 += -openmp + CC += -openmp MYFLAGS += -D_OPENMP endif @@ -116,4 +117,18 @@ else LIBD = libd$(libd).a endif +### Scalapack (use MKL): + +MKL_LIBDIR = $(MKLROOT)/lib/em64t + +LDFLAGS += -Wl,-rpath,$(MKL_LIBDIR) -L$(MKL_LIBDIR) + +ifdef omp + LAPACK = -lmkl_intel_lp64 -lmkl_intel_thread -lmkl_core +else + LAPACK = -lmkl_intel_lp64 -lmkl_sequential -lmkl_core +endif + +SCALAPACK = -lmkl_blacs_intelmpi_lp64 -lmkl_scalapack_lp64 -lmkl_blacs_intelmpi_lp64 $(LAPACK) + #=============================================================================== diff --git a/src/platform/Makefile-ibm.var b/src/platform/Makefile-ibm.var index d70147940f99dbf6faa1a7097ffb7a9341c7ad2a..56b9d0f7b5fd2bdd3dedfb81532b40b37b2704c2 100644 --- a/src/platform/Makefile-ibm.var +++ b/src/platform/Makefile-ibm.var @@ -64,7 +64,7 @@ ARFLAGS = LDFLAGS = SYSLIBS = -FAST_MAKE = gmake -j 8 +FAST_MAKE = gmake -j 1 CKSUM_O = cksum.o UUU_O = uuu_f90.o diff --git a/src/platform/Makefile-intel.var b/src/platform/Makefile-intel.var index 58151a089088ed5d0251a69fcbd4ef2113dd3f18..5a181a769b78cb966e1332073229f2205fa30be3 100644 --- a/src/platform/Makefile-intel.var +++ b/src/platform/Makefile-intel.var @@ -5,6 +5,7 @@ #------------------------------------------------------------------------------- # # Copyright (C) 2002-2008 Hinnerk Stueben +# 2011 Yoshifumi Nakamura # # This file is part of BQCD -- Berlin Quantum ChromoDynamics program # @@ -23,37 +24,71 @@ # #------------------------------------------------------------------------------- -random = ranlux-3.2 - +omp = +timing = 1 +libd = 100 +random = ranlux-3.2 +cuda = #------------------------------------------------------------------------------- SHELL = /bin/ksh FPP = cpp -C -P -F90 = ifort -CC = icc +F90 = mpiifort +CC = mpiicc MODULES_FLAG = -I$(MODULES_DIR) -MYFLAGS = -FFLAGS = $(MODULES_FLAG) -CFLAGS = -DLongLong -DNamesToLower_ +MYFLAGS = +FFLAGS_STD= $(MODULES_FLAG) -xSSE3 -align all +CFLAGS_STD= -DLongLong -DNamesToLower_ -I./include ARFLAGS = -LDFLAGS = -Vaxlib +LDFLAGS = SYSLIBS = -FAST_MAKE = gmake -j 2 +FAST_MAKE = gmake -j 1 BLAS_O = blas.o CKSUM_O = cksum.o RANDOM_O = ran.o ranf.o UUU_O = uuu_f90.o -LIBD = libd2.a -LIBCOMM = lib_single_pe.a +LIBD = libd.a +LIBCOMM = lib_mpi.a LIBCLOVER = libclover.a LIBILDG = ildg_stubs.o LIBRANDOM = ran/$(random)/libran.a +#------------------------------------------------------------------------------- + +ifdef timing + MYFLAGS += -DTIMING +endif + +ifeq ($(libd),1) + LIBD = libd.a +else + LIBD = libd$(libd).a +endif + +ifdef debug + FFLAGS = -g -O0 $(FFLAGS_STD) + CFLAGS = -g -O0 $(CFLAGS_STD) +else + FFLAGS = -O3 $(FFLAGS_STD) + CFLAGS = -O2 $(CFLAGS_STD) +endif + +ifdef omp + F90 += -openmp + MYFLAGS += -D_OPENMP +endif + +ifdef cuda + CFLAGS += -I/usr/local/cuda/include/ + LDFLAGS+= -L/usr/local/cuda/lib64 + SYSLIBS+= -lcublas +endif + #=============================================================================== diff --git a/src/platform/Makefile-jubl.var b/src/platform/Makefile-jubl.var index 04f6501dc99add30a1e2175ab9fe15abf658c496..a4380918e3bce219cf0d7a2e7f5d27b6e2a4cdc3 100644 --- a/src/platform/Makefile-jubl.var +++ b/src/platform/Makefile-jubl.var @@ -60,7 +60,7 @@ ARFLAGS = LDFLAGS = -L$(BGLSYS)/lib SYSLIBS = -lmpich.rts -lfmpich.rts -lmsglayer.rts -lrts.rts -ldevices.rts -FAST_MAKE = gmake -j 8 +FAST_MAKE = gmake -j 1 BLAS_O = blas.o CKSUM_O = cksum.o diff --git a/src/platform/Makefile-jugene.var b/src/platform/Makefile-jugene.var index b39da4e7bfd00082d89931e58f4b6dd26cc54087..c3234632cfb359c4b1c6b0434da2dc492d669a0c 100644 --- a/src/platform/Makefile-jugene.var +++ b/src/platform/Makefile-jugene.var @@ -37,7 +37,7 @@ libd = 520 # for all other libd's -mapfile must be XYZT as well # for testing begin with libd100: -libd = 100 +#libd = 100 random = ranlux-3.2 omp = diff --git a/src/platform/Makefile-linux.var b/src/platform/Makefile-linux.var index 3ff1471d0150e4aa04b65bd92ad703a536e33a10..9de7c2f9ff58b0cd2c1d4e4fc5d039ed0c8fb8d8 100644 --- a/src/platform/Makefile-linux.var +++ b/src/platform/Makefile-linux.var @@ -29,7 +29,7 @@ omp = shmem = shmempi = debug = -libd = 2 +libd = 100 random = ranlux-3.2 #------------------------------------------------------------------------------- @@ -43,9 +43,9 @@ CC = gcc MODULES_FLAG = -I$(MODULES_DIR) -MYFLAGS = -DNONMPI +MYFLAGS = FFLAGS_STD= $(MODULES_FLAG) -ffree-line-length-none -fno-range-check -CFLAGS_STD= -DNamesToLower_ -DNONMPI +CFLAGS_STD= -DNamesToLower_ ARFLAGS = LDFLAGS = @@ -71,6 +71,9 @@ endif ifdef mpi F90 = mpif90 LIBCOMM = lib_mpi.a +else + MYFLAGS += -DNONMPI + CFLAGS_STD+= -DNONMPI endif ifdef omp diff --git a/src/platform/Makefile-supermig.var b/src/platform/Makefile-supermig.var new file mode 100644 index 0000000000000000000000000000000000000000..b4c1253b13e7778e0cf12dd9dcb23279454395e2 --- /dev/null +++ b/src/platform/Makefile-supermig.var @@ -0,0 +1,126 @@ +#=============================================================================== +# +# Makefile-supermig.var - settings on SuperMIG (IBM iDataPlex) +# +#------------------------------------------------------------------------------- +# +# Copyright (C) 2011 Hinnerk Stueben +# +# This file is part of BQCD -- Berlin Quantum ChromoDynamics program +# +# BQCD 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 Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BQCD is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BQCD. If not, see <http://www.gnu.org/licenses/>. +# +#------------------------------------------------------------------------------- + +## mpi = { <empty> | poe | impi } + +timing = 1 +mpi = impi +omp = +shmem = +shmempi = +debug = +libd = 100 +random = ranlux-3.2 + +#------------------------------------------------------------------------------- + +SHELL = /bin/ksh + +FPP = cpp -E -C -P +F90 = ifort +CC = icc + +MODULES_FLAG = -I$(MODULES_DIR) + +MYFLAGS = -DINTEL +FFLAGS_STD= $(MODULES_FLAG) -fno-alias +CFLAGS_STD= -DNamesToLower_ +ARFLAGS = + +LDFLAGS = +SYSLIBS = + +FAST_MAKE = gmake -j 1 + +CKSUM_O = cksum.o +UUU_O = uuu_f90.o + +LIBD = +LIBCOMM = lib_single_pe.a +LIBCLOVER = libclover.a +LIBILDG = ildg_stubs.o +LIBRANDOM = ran/$(random)/libran.a + +#------------------------------------------------------------------------------- + +ifdef timing + MYFLAGS += -DTIMING +endif + +ifdef mpi + LIBCOMM = lib_mpi.a + F90 = mpiifort + CC = mpiicc +else + MYFLAGS += -DNONMPI + CFLAGS_STD+= -DNONMPI +endif + +ifdef omp + F90 += -openmp + CC += -openmp + MYFLAGS += -D_OPENMP +endif + +ifdef debug + FFLAGS = -g -O0 $(FFLAGS_STD) + CFLAGS = -g -O0 $(CFLAGS_STD) +else + FFLAGS = -O3 $(FFLAGS_STD) + CFLAGS = -O2 $(CFLAGS_STD) +endif + +ifeq ($(libd),1) + LIBD = libd.a +else + LIBD = libd$(libd).a +endif + +LIME = $(HOME)/supermig/lib-serial/lime-1.3.1 + +### Scalapack (use MKL if possible): + +#LIBBLAS = $(HOME)/supermig/lib-serial/BLAS/blas_LINUX.a +#LIBLAPACK = $(HOME)/supermig/lib-serial/lapack-3.3.1/lapack_LINUX.a +LIBBLACS = $(HOME)/supermig/lib-mpi-ibm/BLACS/LIB/blacsF77init_MPI-LINUX-0.a \ + $(HOME)/supermig/lib-mpi-ibm/BLACS/LIB/blacs_MPI-LINUX-0.a +LIBSCALAPACK = $(HOME)/supermig/lib-mpi-ibm/scalapack-1.8.0/libscalapack.a + +LDFLAGS += -Wl,-rpath,$(MKL_LIBDIR) -L$(MKL_LIBDIR) + +#LAPACK = $(LIBLAPACK) $(LIBBLAS) +ifdef omp + LAPACK = -lmkl_intel_lp64 -lmkl_intel_thread -lmkl_core +else + LAPACK = -lmkl_intel_lp64 -lmkl_sequential -lmkl_core +endif + +ifeq ($(mpi),impi) + SCALAPACK = -lmkl_blacs_intelmpi_lp64 -lmkl_scalapack_lp64 -lmkl_blacs_intelmpi_lp64 $(LAPACK) +else + SCALAPACK = $(LIBSCALAPACK) $(LIBBLACS) +endif + +#=============================================================================== diff --git a/src/measure/correlation_tt.F90 b/src/platform/service-k.F90 similarity index 50% rename from src/measure/correlation_tt.F90 rename to src/platform/service-k.F90 index a202e1325f30e881b7f11cb0f18ac0d62fd2d779..cc2a9fd142dae21d4bfd5ac22cdb9577515b3383 100644 --- a/src/measure/correlation_tt.F90 +++ b/src/platform/service-k.F90 @@ -1,10 +1,10 @@ !=============================================================================== ! -! correlation_tt.F90 +! service-K.F90 - calls to service routine for K ! !------------------------------------------------------------------------------- ! -! Copyright (C) 2007 Yoshifumi Nakamura +! Copyright (C) 2011 Yoshifumi Nakamura ! ! This file is part of BQCD -- Berlin Quantum ChromoDynamics program ! @@ -23,48 +23,56 @@ ! !------------------------------------------------------------------------------- # include "defs.h" -# include "defs_imp_2p1.h" !------------------------------------------------------------------------------- -COMPLEX function correlation_tt(t0,dis,in1,in2) +subroutine abbruch() - use module_decomp - implicit none - integer, intent(in) :: t0, dis - COMPLEX_FIELD_ST, intent(in) :: in1,in2 - integer, external :: std_xyzt2i, e_o - integer :: vols ,t, t1, , coord(DIM) + integer(4) status + status = 1 + call exit(status) +end +!------------------------------------------------------------------------------- +function rechner() ! returns hostname - nx = decomp%std%N(1) - ny = decomp%std%N(2) - nz = decomp%std%N(3) - nt = decomp%std%N(4) + character(len = 20) rechner + character(len = 32) r + call hostnm(r) + rechner = r +end - vols = NX*NY*NZ - t1 = dis + t0 - tt = dis / NT - tr = mod(dis,NT) +!------------------------------------------------------------------------------- +SECONDS function sekunden() + use module_function_decl + call cpu_time(sekunden) + sekunden=sekunden/num_threads() - npe(1) = LX/NX - npe(2) = LY/NY - npe(3) = LZ/NZ +end - do xx = 0, npe(1) - 1 - do yy = 0, npe(2) - 1 - do zz = 0, npe(3) - 1 - pe_shift = nnpe(xx, yy, zz, tt) +!------------------------------------------------------------------------------- +subroutine pxfgetarg(iarg, arg, larg, status) - do i = 1, vols - do j = 1, vols - in1(i, t0)*in2(j, tr) - enddo - enddo + implicit none + integer :: iarg, larg, status + character(len = *) :: arg + character(100) :: a + + call getarg(iarg, a) + larg = len_trim(a) + arg = a + status = 0 +end - correlation_tt = ZERO +!------------------------------------------------------------------------------- +integer function ipxfargc() + ipxfargc = iargc() +end +!------------------------------------------------------------------------------- +logical function is_big_endian() + is_big_endian = .true. end !=============================================================================== diff --git a/src/platform/service-supermig.F90 b/src/platform/service-supermig.F90 new file mode 120000 index 0000000000000000000000000000000000000000..6f01ff08d84e6d07ecc55f8e3081b5100b220e73 --- /dev/null +++ b/src/platform/service-supermig.F90 @@ -0,0 +1 @@ +service-intel.F90 \ No newline at end of file diff --git a/src/precision.H b/src/precision.H new file mode 100644 index 0000000000000000000000000000000000000000..1c3895995d5bee762de8f60dfcd9c8034eac9324 --- /dev/null +++ b/src/precision.H @@ -0,0 +1,183 @@ + +# define module_mre +# define module_mre2 +# define type_mre +# define type_mre2 +# define mre_pointer_to_sc_field +# define mre2_pointer +# define mre2_get_interface +# define mre2_get +# define mre2_put +# define mre_pointer +# define mre_get +# define mre_put +# define mre_allocate +# define mre2_allocate +# define mre_gram_schmidt +# define mre_gauss_jordan +# define mre2_gram_schmidt +# define mre2_gauss_jordan +# define mre_n_vec + +# define allocate_clover_field_a +# define allocate_clover_field_b +# define allocate_gen_field +# define allocate_g_field +# define allocate_g_field_ildg +# define allocate_g_field_io +# define allocate_sc2_field +# define allocate_sc_field +# define allocate_sc_field_io +# define allocate_sc_overindexed +# define _bwd +# define cg +# define clover +# define clover_mult_a +# define clover_mult_a2_block +# define clover_mult_ao +# define clover_mult_ao_block +# define clover_mult_ao2_block +# define clover_mult_b +#ifndef D_R4_INTERNAL +# define d +# define d_dag +#endif +# define d_block +# define d_dag_block + +# define d_projection +# define d_projection_block +# define d_dag_projection +# define d_dag_projection_block + +# define d_xyzt + +# define d_t +# define d_xb +# define d_xf +# define d_yb +# define d_yf +# define d_zb +# define d_zf +# define d_dag_t +# define d_dag_xb +# define d_dag_xf +# define d_dag_yb +# define d_dag_yf +# define d_dag_zb +# define d_dag_zf + +# define d_t_block +# define d_x_block +# define d_y_block +# define d_z_block +# define d_t_block2 +# define d_x_block2 +# define d_y_block2 +# define d_z_block2 + +# define d_dag_t_block +# define d_dag_x_block +# define d_dag_y_block +# define d_dag_z_block +# define d_dag_t_block2 +# define d_dag_x_block2 +# define d_dag_y_block2 +# define d_dag_z_block2 + +# define d_xbound + + + + +# define _fwd +# define gauge +# define hmc_conf +# define h_mult_a +# define h_mult_b +# define h_mult_c +# define init_xbound +# define init_xbound_d_proj +# define init_xbound_g +# define init_xbound_g_rect +# define init_xbound_sc +# define init_xbound_sc2 +# define init_xch_bound +# define init_xch_bound_no_diagonal +# define mdag +# define mmul +# define module_d21 +# define module_d_g +# define module_m_mult_block +# define module_p_interface +# define module_p_interface +# define module_xbound +# define module_xbound_d_proj +# define module_xbound_g +# define module_xbound_g_rect +# define module_xbound_sc +# define module_xbound_sc2 +# define mtdagmt +# define mtil +# define mtil_dag +# define sc_axpby +# define sc_axpy +# define sc_axpy_block +# define sc_cax2 +# define sc_caxpy +# define sc_caxpy2 +# define sc_cdotc +# define sc_copy +# define sc_dot +# define sc_dprod_block +# define sc_norm2 +# define sc_scale +# define sc_xmy +# define sc_xpby +# define sc_xpby_block +# define sc_zero +# define sc_zero_halo +# define swap_p_clover_field_a +# define swap_p_clover_field_b +# define swap_p_g_field +# define swap_p_sc_field +# define type_clover_a +# define type_clover_b +# define typedef_clover +# define unprec_cmul +# define unprec_mdag +# define unprec_mdagm +# define unprec_mmul +# define unprec_wdag +# define unprec_wdagw +# define unprec_wmul +# define u_reorder +# define wdag +# define wdag_block +# define w_dagger_w +# define wdagw +# define wdagw_block +# define wmul +# define wmul_block +# define w_mult +# define w_mult_dag +# define xbound_d_proj +# define xbound_d_proj_i +# define xbound_d_proj_sr +# define xbound_g +# define xbound_g_field +# define xbound_g_field_rect +# define xbound_g_i +# define xbound_g_rect +# define xbound_g_rect_i +# define xbound_g_rect_i_ind +# define xbound_g_rect_ind +# define xbound_g_rect_sr +# define xbound_g_rect_sr_ind +# define xbound_g_sr +# define xbound_sc +# define xbound_sc2 +# define xbound_sc2_field +# define xbound_sc2_field_i +# define xbound_sc_field +# define xbound_sc_field_i diff --git a/src/service.F90 b/src/service.F90 index ce7439ee66470b3939be1882175b8bb76ae80719..e41a1f90d167f8d9fcd3ae545485b35aefd6f640 120000 --- a/src/service.F90 +++ b/src/service.F90 @@ -1 +1 @@ -platform/service-linux.F90 \ No newline at end of file +platform/service-gnu.F90 \ No newline at end of file diff --git a/src/su3sc/Makefile b/src/su3sc/Makefile index 18c57ffb55c22122eb5e3cb8d8e3fd27782159ca..33d45c124823be3d14196118633446ff15c84c78 100644 --- a/src/su3sc/Makefile +++ b/src/su3sc/Makefile @@ -26,9 +26,9 @@ DIR = ../ include ../Makefile.in ifdef FPP2 - fpp = $(FPP2) + fpp = $(FPP2) -I../include $(MYFLAGS) else - fpp = $(FPP) + fpp = $(FPP) -I../include $(MYFLAGS) endif FAST_MAKE = make -j 1 @@ -37,7 +37,7 @@ FAST_MAKE = make -j 1 .SUFFIXES: .a .o .F90 .F90.o: - $(fpp) -I../include $(MYFLAGS) $< > $*.f90 + $(fpp) $< > $*.f90 $(F90) -c $(FFLAGS) $*.f90 MODULES_DIR = ../modules @@ -56,6 +56,10 @@ OBJS = \ su3.o \ vec.o +ifdef quad +OBJS += sc_r16.o +endif + fast: $(FAST_MAKE) lib_su3sc.a -cp *.mod $(MODULES_DIR) @@ -66,3 +70,10 @@ lib_su3sc.a: $(OBJS) clobber: rm -f *.[Tiod] *.f90 *.mod work.pc work.pcl rm -f lib_su3sc.a + +sc_r4.o: sc.F90 + $(fpp) -DPRECISION_R4 $< > $*.f90 + $(F90) -c $(FFLAGS32) $*.f90 +sc_r16.o: sc.F90 + $(fpp) -DPRECISION_R16 $< > $*.f90 + $(F90) -c $(FFLAGS) $*.f90 diff --git a/src/su3sc/init_sc.F90 b/src/su3sc/init_sc.F90 index 8d914e7a8c3f071eb62601ff0a9b7cda4749b6c8..4d19e26756a08391fa2b1fd367e286aa575cb017 100644 --- a/src/su3sc/init_sc.F90 +++ b/src/su3sc/init_sc.F90 @@ -45,23 +45,23 @@ subroutine init_module_sc_size() end !------------------------------------------------------------------------------- -module module_sc_size_r4 - - integer :: sc_n_real ! number of real numbers of an sc-field - integer :: sc_n_complex ! number of complex numbers of an sc-field - -end - -!------------------------------------------------------------------------------- -subroutine init_module_sc_size_r4() - - use module_sc_size_r4 - use module_vol - implicit none - - sc_n_complex = NDIRAC * NCOL * volh - sc_n_real = NDIRAC * NCOL * volh * SIZE_COMPLEX - -end - +!!module module_sc_size_r4 +!! +!! integer :: sc_n_real ! number of real numbers of an sc-field +!! integer :: sc_n_complex ! number of complex numbers of an sc-field +!! +!!end +!! +!!!------------------------------------------------------------------------------- +!!subroutine init_module_sc_size_r4() +!! +!! use module_sc_size_r4 +!! use module_vol +!! implicit none +!! +!! sc_n_complex = NDIRAC * NCOL * volh +!! sc_n_real = NDIRAC * NCOL * volh * SIZE_COMPLEX +!! +!!end +!! !=============================================================================== diff --git a/src/su3sc/su3.F90 b/src/su3sc/su3.F90 index ee97976bc2dea56b21e19fea08335c71a790e566..be8454929e42032be82d7024da7b1f528888a4dd 100644 --- a/src/su3sc/su3.F90 +++ b/src/su3sc/su3.F90 @@ -303,9 +303,14 @@ subroutine su3_check_det(u) - u(1,2) * u(2,1) * u(3,3) & - u(1,3) * u(2,2) * u(3,1) - if (abs(Re(det) - ONE) > eps) call die("check_su3_det(): Re(det) /= 1") - if (abs(Im(det)) > eps) call die("check_su3_det(): Im(det) /= 0") - + if (abs(Re(det) - ONE) > eps) then + write(0,*)"check_su3_det(): Re(det) /= 1, det=", det + call die("check_su3_det(): Re(det) /= 1") + endif + if (abs(Im(det)) > eps) then + write(0,*)"check_su3_det(): Im(det) /= 0, det=", det + call die("check_su3_det(): Im(det) /= 0") + endif end !------------------------------------------------------------------------------- diff --git a/src/su3sc/su3_2.F90 b/src/su3sc/su3_2.F90 index 2542b332bfffff5f3391688bdc5682a8d74ccb1c..584928fab9b420cf8460206c2b81eca26e1cb3fc 100644 --- a/src/su3sc/su3_2.F90 +++ b/src/su3sc/su3_2.F90 @@ -363,6 +363,7 @@ end subroutine gen_m_force(p, uuu) use module_field use module_vol + use module_switches implicit none GENERATOR_FIELD, intent(inout) :: p @@ -370,6 +371,8 @@ subroutine gen_m_force(p, uuu) integer :: mu, eo, i SU3 :: w + if (switches%boundary_sf) call schr_boundary_zero3(uuu) + do mu = 1, DIM do eo = EVEN, ODD !$omp parallel do private(w) diff --git a/src/su3sc/vec.F90 b/src/su3sc/vec.F90 index bfd3452045852c65c6a0f8dabdec1a7f298f344f..00e69cc32d3a5ad02a5544bb8cf22858a38c4160 100644 --- a/src/su3sc/vec.F90 +++ b/src/su3sc/vec.F90 @@ -35,6 +35,12 @@ module vec complex(4), pointer :: in(:) end +#ifdef QUAD + real(16) function vec_norm2_c16(in) + complex(16), pointer :: in(:) + end +#endif + real(8) function vec_dot_c8(x,y) complex(8), pointer :: x(:),y(:) end @@ -42,12 +48,23 @@ module vec complex(4), pointer :: x(:),y(:) end +#ifdef QUAD + real(16) function vec_dot_c16(x,y) + complex(16), pointer :: x(:),y(:) + end +#endif + complex(8) function vec_cdotc_c8(x,y) complex(8), pointer :: x(:),y(:) end complex(8) function vec_cdotc_c4(x,y) complex(4), pointer :: x(:),y(:) end +#ifdef QUAD + complex(16) function vec_cdotc_c16(x,y) + complex(16), pointer :: x(:),y(:) + end +#endif end interface end module vec @@ -140,4 +157,54 @@ complex(8) function vec_cdotc_c4(x, y) ! Sum_i conjg(x_i) * y_i enddo vec_cdotc_c4 = tmp end function vec_cdotc_c4 +!------------------------------------------------------------------------------- +! c16 +!------------------------------------------------------------------------------- + +#ifdef QUAD + +real(16) function vec_norm2_c16(in) ! Sum_i abs(in_i)**2 + implicit none + complex(16), pointer :: in(:) + real(16) :: tmp + integer :: i + + tmp = 0 + !$omp parallel do reduction(+: tmp) + do i = 1, size(in) + tmp = tmp + conjg(in(i)) * in(i) + enddo + vec_norm2_c16 = tmp +end function vec_norm2_c16 +!------------------------------------------------------------------------------- +real(16) function vec_dot_c16(x, y) ! Sum_i [Re(x_i) * Re(y_i) + Im(x_i) * Im(y_i)] + implicit none + complex(16), pointer :: x(:), y(:) + real(16) :: tmp + integer :: i + + tmp = 0 + !$omp parallel do reduction(+: tmp) + do i = 1, size(x) + tmp = tmp + y(i) * conjg(x(i)) + enddo + vec_dot_c16 = tmp +end function vec_dot_c16 +!------------------------------------------------------------------------------- +complex(16) function vec_cdotc_c16(x, y) ! Sum_i conjg(x_i) * y_i + implicit none + complex(16), pointer :: x(:), y(:) + complex(16) :: tmp + integer :: i + + tmp = 0 + !$omp parallel do reduction(+: tmp) + do i = 1, size(x) + tmp = tmp + y(i) * conjg(x(i)) + enddo + vec_cdotc_c16 = tmp +end function vec_cdotc_c16 + +#endif + !=============================================================================== diff --git a/src/util/copy.F90 b/src/util/copy.F90 index b704baaaf34d9617a10917276ed1e6d879055fd3..370ec10849b9cefd507636c06e50c0d691157855 100644 --- a/src/util/copy.F90 +++ b/src/util/copy.F90 @@ -28,6 +28,8 @@ # define GAUGE_FIELD_R4 complex(4), dimension (NCOL, NCOL, volh_tot, EVEN:ODD, DIM) # define CLOVER_FIELD_A_R4 type(type_clover_a_r4), dimension(2, volh, EVEN:ODD) # define CLOVER_FIELD_B_R4 type(type_clover_b_r4), dimension(2, volh, EVEN:ODD) +# define CLOVER_FIELD_A_R16 type(type_clover_a_r16), dimension(2, volh, EVEN:ODD) +# define CLOVER_FIELD_B_R16 type(type_clover_b_r16), dimension(2, volh, EVEN:ODD) !------------------------------------------------------------------------------- subroutine gauge_copy_r8_to_r4(u4, u8) @@ -96,6 +98,50 @@ subroutine clover_b_copy_r8_to_r4(b4, b8) end +!------------------------------------------------------------------------------- +#ifdef QUAD +subroutine clover_a_copy_r8_to_r16(out, in) + use typedef_clover + use typedef_clover_r16 + use module_vol + implicit none + CLOVER_FIELD_A_R16, intent(out) :: out + CLOVER_FIELD_A , intent(in) :: in + integer :: i, j, eo + + do eo = EVEN, ODD + !$omp parallel do private(j) + do i = 1, VOLH + do j = 1, 2 + call type_clover_a_copy_r8_to_r16(out(j, i, eo), in(j, i, eo)) + enddo + enddo + enddo + + +end + +!------------------------------------------------------------------------------- +subroutine clover_b_copy_r8_to_r16(out, in) + use typedef_clover + use typedef_clover_r16 + use module_vol + implicit none + CLOVER_FIELD_B_R16, intent(out) :: out + CLOVER_FIELD_B , intent(in) :: in + integer :: i, j, eo + + do eo = EVEN, ODD + !$omp parallel do private(j) + do i = 1, VOLH + do j = 1, 2 + call type_clover_b_copy_r8_to_r16(out(j, i, eo), in(j, i, eo)) + enddo + enddo + enddo + +end +#endif !------------------------------------------------------------------------------- subroutine type_clover_a_copy_r8_to_r4(a4, a8) use typedef_clover @@ -160,6 +206,71 @@ subroutine type_clover_b_copy_r8_to_r4(b4, b8) end +!------------------------------------------------------------------------------- +#ifdef QUAD +subroutine type_clover_a_copy_r8_to_r16(out, in) + use typedef_clover + use typedef_clover_r16 + implicit none + type(type_clover_a_r16), intent(out) :: out + type(type_clover_a), intent(in) :: in + + out%i11 = in%i11 + out%i22 = in%i22 + out%i12 = in%i12 + out%i13 = in%i13 + out%i14 = in%i14 + out%i15 = in%i15 + out%i16 = in%i16 + out%i23 = in%i23 + out%i24 = in%i24 + out%i25 = in%i25 + out%i26 = in%i26 + out%i33 = in%i33 + out%i44 = in%i44 + out%i34 = in%i34 + out%i35 = in%i35 + out%i36 = in%i36 + out%i45 = in%i45 + out%i46 = in%i46 + out%i55 = in%i55 + out%i66 = in%i66 + out%i56 = in%i56 + +end + +!------------------------------------------------------------------------------- +subroutine type_clover_b_copy_r8_to_r16(out, in) + use typedef_clover + use typedef_clover_r16 + implicit none + type(type_clover_b_r16), intent(out) :: out + type(type_clover_b), intent(in) :: in + + out%i21 = in%i21 + out%i31 = in%i31 + out%i32 = in%i32 + out%i41 = in%i41 + out%i42 = in%i42 + out%i43 = in%i43 + out%i51 = in%i51 + out%i52 = in%i52 + out%i53 = in%i53 + out%i54 = in%i54 + out%i61 = in%i61 + out%i62 = in%i62 + out%i63 = in%i63 + out%i64 = in%i64 + out%i65 = in%i65 + out%i11 = in%i11 + out%i22 = in%i22 + out%i33 = in%i33 + out%i44 = in%i44 + out%i55 = in%i55 + out%i66 = in%i66 + +end +#endif !------------------------------------------------------------------------------- subroutine type_clover_a_copy_r8(out, in) use typedef_clover diff --git a/src/util/init_confs2.F90 b/src/util/init_confs2.F90 index 2ebe72907fdd13a2cc4c3740148aab0962dfbe0b..ae40afefd44569195cbe73fe323b65a2459cf72e 100644 --- a/src/util/init_confs2.F90 +++ b/src/util/init_confs2.F90 @@ -35,6 +35,9 @@ subroutine init_confs2(para, conf) use typedef_para use module_p_interface use module_p_interface_r4 +#ifdef QUAD + use module_p_interface_r16 +#endif use module_switches use module_dd implicit none @@ -77,14 +80,21 @@ subroutine init_confs2(para, conf) endif allocate(gauge(count)) ! for u ds cl allocate(gauge_r4(count)) ! for u ds cl +#ifdef QUAD + allocate(gauge_r16(count)) ! for u ds cl +#endif gauge(1:count)%init = .true. - do i = 2, count + do i = 2, 2!!count nullify(gauge(i)%u) call allocate_g_field(gauge(i)%u) enddo if (switches%dynamical) then nullify(gauge_r4(2)%u) call allocate_g_field_r4(gauge_r4(2)%u) +#ifdef QUAD + nullify(gauge_r16(2)%u) + call allocate_g_field_r16(gauge_r16(2)%u) +#endif if (switches%stout_ds) then gauge(2)%sid = 1 else @@ -105,6 +115,7 @@ subroutine init_confs2(para, conf) endif endif gauge(1)%u => conf(1)%u !!! conf(1)%u must have "target" attribution + if (switches%boundary_sf) call schr_boundary_gauge(gauge(1)%u) if (switches%stout) then allocate(stout(1)) @@ -128,6 +139,9 @@ subroutine init_clover_field(para) use module_input use module_p_interface use module_p_interface_r4 +#ifdef QUAD + use module_p_interface_r16 +#endif implicit none type(hmc_para) :: para integer, dimension(:), allocatable :: nf @@ -167,6 +181,10 @@ subroutine init_clover_field(para) nullify(clover_r4) allocate(clover(cid)) ! # of kappa allocate(clover_r4(cid)) ! # of kappa +#ifdef QUAD + nullify(clover_r16) + allocate(clover_r16(cid)) ! # of kappa +#endif allocate(nf(cid)) allocate(theta(cid)) allocate(csw(cid)) @@ -184,6 +202,14 @@ subroutine init_clover_field(para) call allocate_clover_field_a_r4(clover_r4(i)%a) call allocate_clover_field_a_r4(clover_r4(i)%i) call allocate_clover_field_b_r4(clover_r4(i)%b) +#ifdef QUAD + nullify(clover_r16(i)%a) + nullify(clover_r16(i)%i) + nullify(clover_r16(i)%b) + call allocate_clover_field_a_r16(clover_r16(i)%a) + call allocate_clover_field_a_r16(clover_r16(i)%i) + call allocate_clover_field_b_r16(clover_r16(i)%b) +#endif enddo endif diff --git a/src/util/init_imp.F90 b/src/util/init_imp.F90 index 35b58ec49bf8ce23c382d5081362aa19a8b5d990..feea07cdb86430e7666890513b0970ed30446e3b 100644 --- a/src/util/init_imp.F90 +++ b/src/util/init_imp.F90 @@ -101,6 +101,9 @@ subroutine init_imp_all(doall) call init_clover(i) enddo endif + + call init_rid() !! just to initialize rid for next print + ! ! check ! @@ -215,7 +218,7 @@ subroutine init_gauge(id) if (id == 2) then select case (version_of_d()) - case(4,45,8,85,520,100) + case(4,45,8,85,520,100,101,102,103) call d_g_init(gauge(2)%u) end select call u2ddu(gauge(2)%u) @@ -248,12 +251,19 @@ subroutine init_clover(id) !! write(0,*)id, size(clover), size(gauge) !! stop - call clover_init(clover(id)%a, clover(id)%i, clover(id)%b, gauge(1)%u, & + call clover_init(clover(id)%a, clover(id)%i, clover(id)%b, gauge(3)%u, & clover(id)%cswkappa, m1, m2) DEBUG2S("Start: init_clover 3") call clover_a_copy_r8_to_r4(clover_r4(id)%a, clover(id)%a) call clover_a_copy_r8_to_r4(clover_r4(id)%i, clover(id)%i) call clover_b_copy_r8_to_r4(clover_r4(id)%b, clover(id)%b) + DEBUG2S("Start: init_clover 3-5") + +#ifdef QUAD + call clover_a_copy_r8_to_r16(clover_r16(id)%a, clover(id)%a) + call clover_a_copy_r8_to_r16(clover_r16(id)%i, clover(id)%i) + call clover_b_copy_r8_to_r16(clover_r16(id)%b, clover(id)%b) +#endif DEBUG2S("Start: init_clover 4") call clover2cloverdd(id)