diff options
author | Kent Boortz <kent@mysql.se> | 2000-08-02 18:48:06 +0200 |
---|---|---|
committer | Kent Boortz <kent@mysql.se> | 2000-08-02 18:48:06 +0200 |
commit | efe82bb8e93212508c8b292754422df81ef8fbc2 (patch) | |
tree | 6789e688820ffb0661381f240f10f765a8286025 | |
parent | a54783120893faf758d85daee13c0a88c3296553 (diff) | |
download | gmp-efe82bb8e93212508c8b292754422df81ef8fbc2.tar.gz |
Experimental version of mpfr
75 files changed, 10517 insertions, 1 deletions
diff --git a/configure.in b/configure.in index 108bcbdf9..24abf9c23 100644 --- a/configure.in +++ b/configure.in @@ -89,6 +89,16 @@ esac], AM_CONDITIONAL(WANT_MPBSD, test "$enable_mpbsd" = "yes") +AC_ARG_ENABLE(mpfr, +AC_HELP_STRING([--enable-mpfr],[build MPFR [default=no]]), +[case "${enableval}" in +yes|no) ;; +*) AC_MSG_ERROR([bad value ${enableval} for --enable-mpfr, need yes or no]) ;; +esac], +[enable_mpfr=no]) +AM_CONDITIONAL(WANT_MPFR, test "$enable_mpfr" = "yes") + + dnl Switch on OS and determine what compiler to use. dnl dnl os_64bit Set to "yes" if OS is 64-bit capable. @@ -928,4 +938,4 @@ dnl FIXME: Upcoming version of autoconf/automake may not like broken lines. AC_OUTPUT(Makefile mpf/Makefile mpz/Makefile mpn/Makefile mpq/Makefile \ mpf/tests/Makefile mpz/tests/Makefile mpq/tests/Makefile mpn/tests/Makefile \ tests/Makefile tests/rand/Makefile demos/Makefile tune/Makefile \ - mpbsd/Makefile mpbsd/tests/Makefile) + mpbsd/Makefile mpbsd/tests/Makefile mpfr/Makefile mpfr/tests/Makefile) diff --git a/mpfr/Makefile.am b/mpfr/Makefile.am new file mode 100644 index 000000000..4b617f3df --- /dev/null +++ b/mpfr/Makefile.am @@ -0,0 +1,42 @@ +## Process this file with automake to generate Makefile.in + +# Copyright (C) 2000 Free Software Foundation, Inc. +# +# This file is part of the GNU MP Library. +# +# The GNU MP Library is free software; you can redistribute it and/or modify +# it under the terms of the GNU Library General Public License as published by +# the Free Software Foundation; either version 2 of the License, or (at your +# option) any later version. +# +# The GNU MP Library 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 Library General Public +# License for more details. +# +# You should have received a copy of the GNU Library General Public License +# along with the GNU MP Library; see the file COPYING.LIB. If not, write to +# the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, +# MA 02111-1307, USA. + +AUTOMAKE_OPTIONS = gnu no-dependencies + +SUBDIRS = tests + + +INCLUDES = -I$(top_srcdir) + +if WANT_MPFR +noinst_LTLIBRARIES = libmpfr.la +endif + +# FIXME: Add rnd_mode.c when it's clean. +libmpfr_la_SOURCES = \ + add.c div_2exp.c neg.c set_dfl_prec.c set_str_raw.c agm.c get_str.c \ + print_raw.c set_dfl_rnd.c sqrt.c clear.c init.c set_f.c \ + sub.c cmp.c mul.c round.c set_prec.c cmp_ui.c mul_2exp.c set.c \ + set_si.c div.c mul_ui.c set_d.c pow.c out_str.c pi.c set_z.c \ + add_ulp.c log2.c random.c log.c exp.c div_ui.c zeta.c karadiv.c \ + karasqrt.c print_rnd_mode.c + +EXTRA_DIST = mpfr-impl.h diff --git a/mpfr/Makefile.in b/mpfr/Makefile.in new file mode 100644 index 000000000..7f694f873 --- /dev/null +++ b/mpfr/Makefile.in @@ -0,0 +1,423 @@ +# Makefile.in generated automatically by automake 1.4a from Makefile.am + +# Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +SHELL = @SHELL@ + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +prefix = @prefix@ +exec_prefix = @exec_prefix@ + +bindir = @bindir@ +sbindir = @sbindir@ +libexecdir = @libexecdir@ +datadir = @datadir@ +sysconfdir = @sysconfdir@ +sharedstatedir = @sharedstatedir@ +localstatedir = @localstatedir@ +libdir = @libdir@ +infodir = @infodir@ +mandir = @mandir@ +includedir = @includedir@ +oldincludedir = /usr/include + +DESTDIR = + +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ + +top_builddir = .. + +ACLOCAL = @ACLOCAL@ +AUTOCONF = @AUTOCONF@ +AUTOMAKE = @AUTOMAKE@ +AUTOHEADER = @AUTOHEADER@ + +INSTALL = @INSTALL@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_FLAG = +transform = @program_transform_name@ + +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : + +@SET_MAKE@ +build_alias = @build_alias@ +build_triplet = @build@ +host_alias = @host_alias@ +host_triplet = @host@ +target_alias = @target_alias@ +target_triplet = @target@ +AMDEP = @AMDEP@ +AMTAR = @AMTAR@ +AR = @AR@ +AS = @AS@ +AWK = @AWK@ +CALLING_CONVENTIONS_OBJS = @CALLING_CONVENTIONS_OBJS@ +CC = @CC@ +CCAS = @CCAS@ +CPP = @CPP@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +DEPDIR = @DEPDIR@ +DLLTOOL = @DLLTOOL@ +EXEEXT = @EXEEXT@ +LIBTOOL = @LIBTOOL@ +LN_S = @LN_S@ +M4 = @M4@ +MAINT = @MAINT@ +MAKEINFO = @MAKEINFO@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +PACKAGE = @PACKAGE@ +RANLIB = @RANLIB@ +SPEED_CYCLECOUNTER_OBJS = @SPEED_CYCLECOUNTER_OBJS@ +STRIP = @STRIP@ +U = @U@ +VERSION = @VERSION@ +gmp_srclinks = @gmp_srclinks@ +install_sh = @install_sh@ +mpn_objects = @mpn_objects@ +mpn_objs_in_libgmp = @mpn_objs_in_libgmp@ + +# Copyright (C) 2000 Free Software Foundation, Inc. +# +# This file is part of the GNU MP Library. +# +# The GNU MP Library is free software; you can redistribute it and/or modify +# it under the terms of the GNU Library General Public License as published by +# the Free Software Foundation; either version 2 of the License, or (at your +# option) any later version. +# +# The GNU MP Library 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 Library General Public +# License for more details. +# +# You should have received a copy of the GNU Library General Public License +# along with the GNU MP Library; see the file COPYING.LIB. If not, write to +# the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, +# MA 02111-1307, USA. + + +AUTOMAKE_OPTIONS = gnu no-dependencies + +SUBDIRS = tests + +INCLUDES = -I$(top_srcdir) + +@WANT_MPFR_TRUE@noinst_LTLIBRARIES = @WANT_MPFR_TRUE@libmpfr.la + +# FIXME: Add rnd_mode.c when it's clean. +libmpfr_la_SOURCES = \ + add.c div_2exp.c neg.c set_dfl_prec.c set_str_raw.c agm.c get_str.c \ + print_raw.c set_dfl_rnd.c sqrt.c clear.c init.c set_f.c \ + sub.c cmp.c mul.c round.c set_prec.c cmp_ui.c mul_2exp.c set.c \ + set_si.c div.c mul_ui.c set_d.c pow.c out_str.c pi.c set_z.c \ + add_ulp.c log2.c random.c log.c exp.c div_ui.c zeta.c karadiv.c \ + karasqrt.c print_rnd_mode.c + + +EXTRA_DIST = mpfr-impl.h +subdir = mpfr +mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs +CONFIG_HEADER = ../config.h +CONFIG_CLEAN_FILES = +LTLIBRARIES = $(noinst_LTLIBRARIES) + + +DEFS = @DEFS@ -I. -I$(srcdir) -I.. +CPPFLAGS = @CPPFLAGS@ +LDFLAGS = @LDFLAGS@ +LIBS = @LIBS@ +libmpfr_la_LDFLAGS = +libmpfr_la_LIBADD = +am_libmpfr_la_OBJECTS = add.lo div_2exp.lo neg.lo set_dfl_prec.lo \ +set_str_raw.lo agm.lo get_str.lo print_raw.lo set_dfl_rnd.lo sqrt.lo \ +clear.lo init.lo set_f.lo sub.lo cmp.lo mul.lo round.lo set_prec.lo \ +cmp_ui.lo mul_2exp.lo set.lo set_si.lo div.lo mul_ui.lo set_d.lo pow.lo \ +out_str.lo pi.lo set_z.lo add_ulp.lo log2.lo random.lo log.lo exp.lo \ +div_ui.lo zeta.lo karadiv.lo karasqrt.lo print_rnd_mode.lo +libmpfr_la_OBJECTS = $(am_libmpfr_la_OBJECTS) +COMPILE = $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CFLAGS = @CFLAGS@ +CCLD = $(CC) +LINK = $(LIBTOOL) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ +DIST_SOURCES = $(libmpfr_la_SOURCES) +DIST_COMMON = README Makefile.am Makefile.in + + +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) + +GZIP_ENV = --best +depcomp = +SOURCES = $(libmpfr_la_SOURCES) +OBJECTS = $(am_libmpfr_la_OBJECTS) + +all: all-redirect +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4) + cd $(top_srcdir) && $(AUTOMAKE) --gnu mpfr/Makefile + +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + cd $(top_builddir) \ + && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status + + +mostlyclean-noinstLTLIBRARIES: + +clean-noinstLTLIBRARIES: + -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES) + +distclean-noinstLTLIBRARIES: + +maintainer-clean-noinstLTLIBRARIES: + +mostlyclean-compile: + -rm -f *.o core *.core + -rm -f *.$(OBJEXT) + +clean-compile: + +distclean-compile: + -rm -f *.tab.c + +maintainer-clean-compile: + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +distclean-libtool: + +maintainer-clean-libtool: + +libmpfr.la: $(libmpfr_la_OBJECTS) $(libmpfr_la_DEPENDENCIES) + $(LINK) $(libmpfr_la_LDFLAGS) $(libmpfr_la_OBJECTS) $(libmpfr_la_LIBADD) $(LIBS) +.c.o: + $(COMPILE) -c $< +.c.obj: + $(COMPILE) -c `cygpath -w $<` +.c.lo: + $(LTCOMPILE) -c -o $@ $< + +# This directory's subdirectories are mostly independent; you can cd +# into them and run `make' without going through this Makefile. +# To change the values of `make' variables: instead of editing Makefiles, +# (1) if the variable is set in `config.status', edit `config.status' +# (which will cause the Makefiles to be regenerated when you run `make'); +# (2) otherwise, pass the desired values on the `make' command line. + +all-recursive install-data-recursive install-exec-recursive \ +installdirs-recursive install-recursive uninstall-recursive \ +check-recursive installcheck-recursive info-recursive dvi-recursive: + @set fnord $(MAKEFLAGS); amf=$$2; \ + dot_seen=no; \ + target=`echo $@ | sed s/-recursive//`; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + dot_seen=yes; \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || case "$$amf" in *=*) exit 1;; *k*) fail=yes;; *) exit 1;; esac; \ + done; \ + if test "$$dot_seen" = "no"; then \ + $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ + fi; test -z "$$fail" + +mostlyclean-recursive clean-recursive distclean-recursive \ +maintainer-clean-recursive: + @set fnord $(MAKEFLAGS); amf=$$2; \ + dot_seen=no; \ + rev=''; list='$(SUBDIRS)'; for subdir in $$list; do \ + rev="$$subdir $$rev"; \ + if test "$$subdir" = "."; then dot_seen=yes; else :; fi; \ + done; \ + test "$$dot_seen" = "no" && rev=". $$rev"; \ + target=`echo $@ | sed s/-recursive//`; \ + for subdir in $$rev; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || case "$$amf" in *=*) exit 1;; *k*) fail=yes;; *) exit 1;; esac; \ + done && test -z "$$fail" +tags-recursive: + list='$(SUBDIRS)'; for subdir in $$list; do \ + test "$$subdir" = . || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \ + done + +tags: TAGS + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + mkid -f$$here/ID $$unique $(LISP) + +TAGS: tags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test -f $$subdir/TAGS && tags="$$tags -i $$here/$$subdir/TAGS"; \ + fi; \ + done; \ + list='$(SOURCES) $(HEADERS) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(ETAGS_ARGS)$$unique$(LISP)$$tags" \ + || etags $(ETAGS_ARGS) $$tags $$unique $(LISP) + +mostlyclean-tags: + +clean-tags: + +distclean-tags: + -rm -f TAGS ID + +maintainer-clean-tags: + +distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir) + +distdir: $(DISTFILES) + @for file in $(DISTFILES); do \ + d=$(srcdir); \ + if test -d $$d/$$file; then \ + cp -pR $$d/$$file $(distdir); \ + else \ + test -f $(distdir)/$$file \ + || cp -p $$d/$$file $(distdir)/$$file || :; \ + fi; \ + done + for subdir in $(SUBDIRS); do \ + if test "$$subdir" = .; then :; else \ + test -d $(distdir)/$$subdir \ + || mkdir $(distdir)/$$subdir \ + || exit 1; \ + (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir=../$(top_distdir) distdir=../$(distdir)/$$subdir distdir) \ + || exit 1; \ + fi; \ + done +info-am: +info: info-recursive +dvi-am: +dvi: dvi-recursive +check-am: all-am +check: check-recursive +installcheck-am: +installcheck: installcheck-recursive +install-exec-am: +install-exec: install-exec-recursive + +install-data-am: +install-data: install-data-recursive + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am +install: install-recursive +uninstall-am: +uninstall: uninstall-recursive +all-am: Makefile $(LTLIBRARIES) +all-redirect: all-recursive +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_STRIP_FLAG=-s install +installdirs: installdirs-recursive +installdirs-am: + + +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -rm -f Makefile $(CONFIG_CLEAN_FILES) + -rm -f config.cache config.log stamp-h stamp-h[0-9]* + +maintainer-clean-generic: + -rm -f Makefile.in +mostlyclean-am: mostlyclean-noinstLTLIBRARIES mostlyclean-compile \ + mostlyclean-libtool mostlyclean-tags \ + mostlyclean-generic + +mostlyclean: mostlyclean-recursive + +clean-am: clean-noinstLTLIBRARIES clean-compile clean-libtool \ + clean-tags clean-generic mostlyclean-am + +clean: clean-recursive + +distclean-am: distclean-noinstLTLIBRARIES distclean-compile \ + distclean-libtool distclean-tags distclean-generic \ + clean-am + -rm -f libtool + +distclean: distclean-recursive + +maintainer-clean-am: maintainer-clean-noinstLTLIBRARIES \ + maintainer-clean-compile maintainer-clean-libtool \ + maintainer-clean-tags maintainer-clean-generic \ + distclean-am + @echo "This command is intended for maintainers to use;" + @echo "it deletes files that may require special tools to rebuild." + +maintainer-clean: maintainer-clean-recursive + +.PHONY: mostlyclean-noinstLTLIBRARIES distclean-noinstLTLIBRARIES \ +clean-noinstLTLIBRARIES maintainer-clean-noinstLTLIBRARIES \ +mostlyclean-compile distclean-compile clean-compile \ +maintainer-clean-compile mostlyclean-libtool distclean-libtool \ +clean-libtool maintainer-clean-libtool install-recursive \ +uninstall-recursive install-data-recursive uninstall-data-recursive \ +install-exec-recursive uninstall-exec-recursive installdirs-recursive \ +uninstalldirs-recursive all-recursive check-recursive \ +installcheck-recursive info-recursive dvi-recursive \ +mostlyclean-recursive distclean-recursive clean-recursive \ +maintainer-clean-recursive tags tags-recursive mostlyclean-tags \ +distclean-tags clean-tags maintainer-clean-tags distdir info-am info \ +dvi-am dvi check check-am installcheck-am installcheck install-exec-am \ +install-exec install-data-am install-data install-am install \ +uninstall-am uninstall all-redirect all-am all install-strip \ +installdirs-am installdirs mostlyclean-generic distclean-generic \ +clean-generic maintainer-clean-generic clean mostlyclean distclean \ +maintainer-clean + + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/mpfr/README b/mpfr/README new file mode 100644 index 000000000..2915af66e --- /dev/null +++ b/mpfr/README @@ -0,0 +1,81 @@ + + THE MPFR LIBRARY + + ***** EXPERIMENTAL EXPERIMENTAL EXPERIMENTAL EXPERIMENTAL ***** + ***** EXPERIMENTAL EXPERIMENTAL EXPERIMENTAL EXPERIMENTAL ***** + ***** EXPERIMENTAL EXPERIMENTAL EXPERIMENTAL EXPERIMENTAL ***** + +This is a new function class, 'mpfr', for accurate floating-point arithmetic +with rounding control. Unlike the 'mpf' function class, 'mpfr' is a smooth +extension to the IEEE P754 arithmetic. In fact, setting the precision to 53, +'mpfr' functions should work exactly like IEEE doubles. + +This code is *experimental* and it is not fully integrated into GMP. It is +also not as well tested as the other parts of GMP. The original 'mpfr' library +integrated into GMP was version 0.4. + +This code might at some point replace the 'mpf' library. + + + + MORE INFORMATION + +This code was contributed by the French FIABLE project. Please see the 'mpfr' +project page for more info, http://www.loria.fr/projets/mpfr/ + + + + INSTALLATION + +To install this package to the libgmp library you add the "--enable-mpfr" to +configure. This has the unfortune side effect that all programs using GMP +will also depend on 'libm'. + +Two test cases were disabled, 'tcmp' 'tset_d'. + + + + REPORTING BUGS + +Report bugs to bug-gmp@gnu.org and mpfr@loria.fr. What information is +needed in a good bug report is described in the manual. The same address +can be used for suggesting modifications and enhancements. + + + + NOTES FROM THE ORIGINAL INSTALL DOCUMENT + +We tested the installation with GMP 2.0.2 on the following architectures: + + Pentium II and III/Linux 2.2.10 + Alpha 21264/OSF1 V4.0 + SGI R10000/IRIX 6.5 (both using 32- and 64-bit limbs) + Sun UltraSparc/Solaris 2.6 + HP 9000/HP-UX A.09.05 + Pentium/Windows with Cygnus compiler + +Known problems. +=============== + +1) On some architectures (for example Alpha/OSF), the default 'make' command + crashes in step 3. GNU make is preferred. + +2) Under HP-UX and Pentium/Linux, don't use the -pedantic option, otherwise + gcc complains with the longlong.h file from GMP. + +3) On the Alpha, the test file for the square root (tsqrt) may produce + errors as follows: + + libm.a differs from mpfr_sqrt for a=9.89438396044940260000e-134, rnd_mode=2 + libm.a gives 3.14553397063986620000e-67, mpfr_sqrt gives 3.14553397063986680000e-67 (1 ulp) + libm.a differs from mpfr_sqrt for a=7.86528588050363750000e+31, rnd_mode=1 + libm.a gives 8.86864469944739500000e+15, mpfr_sqrt gives 8.86864469944739400000e+15 (-1 ulp) + + Also, Linux on Alpha is known to have problems with IEEE conformance. See + http://www.linux.org.uk/VERSION/relnotes.2211.html. + + In most cases, as above, the error comes from the libm.a. On Alpha/Linux, + which is known to have a bad libm.a, you may even find errors in the + addition or multiplication. + + diff --git a/mpfr/add.c b/mpfr/add.c new file mode 100644 index 000000000..c9bebe443 --- /dev/null +++ b/mpfr/add.c @@ -0,0 +1,404 @@ +/* mpfr_add -- add two floating-point numbers + +Copyright (C) 1999 PolKA project, Inria Lorraine and Loria + +This file is part of the MPFR Library. + +The MPFR Library is free software; you can redistribute it and/or modify +it under the terms of the GNU Library General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at your +option) any later version. + +The MPFR Library 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 Library General Public +License for more details. + +You should have received a copy of the GNU Library General Public License +along with the MPFR Library; see the file COPYING.LIB. If not, write to +the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, +MA 02111-1307, USA. */ + +#include <stdio.h> +#include "gmp.h" +#include "gmp-impl.h" +#include "mpfr.h" + +extern void mpfr_sub1 _PROTO((mpfr_ptr, mpfr_srcptr, mpfr_srcptr, + unsigned char, int)); + +#define ONE ((mp_limb_t) 1) + +/* signs of b and c are supposed equal, + diff_exp is the difference between the exponents of b and c, + which is supposed >= 0 */ + +void +#if __STDC__ +mpfr_add1(mpfr_ptr a, mpfr_srcptr b, mpfr_srcptr c, + unsigned char rnd_mode, int diff_exp) +#else +mpfr_add1(a, b, c, rnd_mode, diff_exp) + mpfr_ptr a; + mpfr_srcptr b; + mpfr_srcptr c; + unsigned char rnd_mode; + int diff_exp; +#endif +{ + mp_limb_t *ap, *bp, *cp, cc, c2, c3=0; unsigned int an,bn,cn; int sh,dif,k; + TMP_DECL(marker); + + TMP_MARK(marker); + ap = MANT(a); + bp = MANT(b); + cp = MANT(c); + if (ap == bp) { + bp = (mp_ptr) TMP_ALLOC(ABSSIZE(b) * BYTES_PER_MP_LIMB); + MPN_COPY (bp, ap, ABSSIZE(b)); + if (ap == cp) { cp = bp; } + } + else if (ap == cp) + { + cp = (mp_ptr) TMP_ALLOC (ABSSIZE(c) * BYTES_PER_MP_LIMB); + MPN_COPY(cp, ap, ABSSIZE(c)); + } + + an = (PREC(a)-1)/mp_bits_per_limb+1; /* number of significant limbs of a */ + + sh = an*mp_bits_per_limb-PREC(a); /* non-significant bits in low limb */ + bn = (PREC(b)-1)/mp_bits_per_limb+1; /* number of significant limbs of b */ + EXP(a) = EXP(b); + + if (SIGN(a)!=SIGN(b)) CHANGE_SIGN(a); + + /* case 1: diff_exp>=prec(a), i.e. c only affects the last bit + through rounding */ + dif = PREC(a)-diff_exp; + + if (dif<=0) { + + /* diff_exp>=PREC(a): c does not overlap with a */ + /* either PREC(b)<=PREC(a), and we can copy the mantissa of b directly + into that of a, or PREC(b)>PREC(a) and we have to round b+c */ + + if (PREC(b)<=PREC(a)) { + + MPN_COPY(ap+(an-bn), bp, bn); + /* fill low significant limbs with zero */ + + for (bp=ap;bn<an;bn++) *bp++=0; + + /* now take c into account */ + if (rnd_mode==GMP_RNDN) { + + /* to nearest */ + /* if diff_exp > PREC(a), no change */ + + if (diff_exp==PREC(a)) { + + /* if c is not zero, then as it is normalized, we have to add + one to the lsb of a if c>1/2, or c=1/2 and lsb(a)=1 (round to + even) */ + + if (NOTZERO(c)) { + + /* c is not zero */ + /* check whether mant(c)=1/2 or not */ + + cc = *cp - (ONE<<(mp_bits_per_limb-1)); + if (cc==0) { + bp = cp+(PREC(c)-1)/mp_bits_per_limb; + while (cp<bp && cc==0) cc = *++cp; + } + + if (cc || (ap[an-1] & (ONE<<sh))) goto add_one_ulp; + /* mant(c) != 1/2 or mant(c) = 1/2: add 1 iff lsb(a)=1 */ + } + } + } + else if ((ISNONNEG(b) && rnd_mode==GMP_RNDU) || + (ISNEG(b) && rnd_mode==GMP_RNDD)) { + + /* round up */ + if (NOTZERO(c)) goto add_one_ulp; + } + /* in the other cases (round to zero, or up/down with sign -/+), + nothing to do */ + } + else { + + /* PREC(b)>PREC(a) : we have to round b+c */ + k=bn-an; + + /* first copy the 'an' most significant limbs of b to a */ + MPN_COPY(ap, bp+k, an); + if (rnd_mode==GMP_RNDN) { + + /* to nearest */ + /* first check whether the truncated bits from b are 1/2*lsb(a) */ + + if (sh) { + cc = *ap & ((ONE<<sh)-1); + *ap &= ~cc; /* truncate last bits */ + cc -= ONE<<(sh-1); + } + else /* no bit to truncate */ + cc = bp[--k] - (ONE<<(mp_bits_per_limb-1)); + + if ((long)cc>0) goto add_one_ulp; /* trunc(b)>1/2*lsb(a) -> round up */ + else if (cc==0) { + + while (k>1 && cc==0) cc=bp[--k]; + + /* now if the truncated part of b = 1/2*lsb(a), check whether c=0 */ + if (NOTZERO(c) || (*ap & (ONE<<sh))) goto add_one_ulp; + /* if trunc(b)+c is exactly 1/2*lsb(a) : round to even lsb */ + } + + /* if cc<0 : trunc(b) < 1/2*lsb(a) -> round down, i.e. do nothing */ + } + else if ((ISNONNEG(b) && rnd_mode==GMP_RNDU) || + (ISNEG(b) && rnd_mode==GMP_RNDD)) { + + /* first check whether trunc(b)+c is zero or not */ + if (sh) { + cc = *ap & ((ONE<<sh)-1); *ap &= ~cc; /* truncate last bits */ + } + else cc = bp[--k] - (ONE<<(mp_bits_per_limb-1)); + while (cc==0 && k>1) cc=bp[--k]; + if (cc || NOTZERO(c)) goto add_one_ulp; + } + + /* in the other cases (round to zero, or up/down with sign -/+), + nothing to do, since b and c don't overlap, there can't be any + carry */ + + } + } + else { + /* diff_exp < PREC(a) : c overlaps with a by dif bits */ + /* first copy upper part of c into a (after shift) */ + unsigned char overlap; + + k = (dif-1)/mp_bits_per_limb + 1; /* only the highest k limbs from c + have to be considered */ + cn = (PREC(c)-1)/mp_bits_per_limb + 1; + MPN_ZERO(ap+k, an-k); /* do it now otherwise ap[k] may be destroyed + in case dif<0 */ + + if (dif<=PREC(c)) { + /* c has to be truncated */ + dif = dif % mp_bits_per_limb; + dif = (dif) ? mp_bits_per_limb-dif-sh : -sh; + + /* we have to shift by dif bits to the right */ + + if (dif>0) mpn_rshift(ap, cp+(cn-k), k, dif); + else if (dif<0) { + ap[k] = mpn_lshift(ap, cp+(cn-k), k, -dif); + + /* put the non-significant bits in low limb for further rounding */ + + if (cn >= k+1) + ap[0] += cp[cn-k-1]>>(mp_bits_per_limb+dif); + } + else MPN_COPY(ap, cp+(cn-k), k); + overlap=1; + } + else { + + /* c is not truncated, but we have to fill low limbs with 0 */ + + k = diff_exp/mp_bits_per_limb; + overlap = diff_exp%mp_bits_per_limb; + + /* warning: a shift of zero bit is not allowed */ + MPN_ZERO(ap, an-k-cn); + if (overlap) { + cc=mpn_rshift(ap+(an-k-cn), cp, cn, overlap); + if (an-k-cn>0) ap[an-k-cn-1]=cc; + } + else MPN_COPY(ap+(an-k-cn), cp, cn); + overlap=0; + } + + /* here overlap=1 iff ulp(c)<ulp(a) */ + /* then put high limbs to zero */ + /* now add 'an' upper limbs of b in place */ + + if (PREC(b)<=PREC(a)) { + overlap += 2; + cc = mpn_add_n(ap+(an-bn), ap+(an-bn), bp, bn); + } + else + /* PREC(b) > PREC(a): we have to truncate b */ + cc = mpn_add_n(ap, ap, bp+(bn-an), an); + + if (cc) { + + /* shift one bit to the right */ + + c3 = (ap[0]&1) && (PREC(a)%mp_bits_per_limb==0); + mpn_rshift(ap, ap, an, 1); + ap[an-1] += ONE<<(mp_bits_per_limb-1); + EXP(a)++; + } + + /* remains to do the rounding */ + + if (rnd_mode==GMP_RNDN) { + + /* to nearest */ + + int kc; + + /* four cases: overlap = + (0) PREC(b) > PREC(a) and diff_exp+PREC(c) <= PREC(a) + (1) PREC(b) > PREC(a) and diff_exp+PREC(c) > PREC(a) + (2) PREC(b) <= PREC(a) and diff_exp+PREC(c) <= PREC(a) + (3) PREC(b) <= PREC(a) and diff_exp+PREC(c) > PREC(a) */ + + switch (overlap) + { + case 1: /* both b and c to round */ + kc = cn-k; /* remains kc limbs from c */ + k = bn-an; /* remains k limbs from b */ + + /* truncate last bits and store the difference with 1/2*ulp in cc */ + + cc = *ap & ((ONE<<sh)-1); + *ap &= ~cc; /* truncate last bits */ + cc -= ONE<<(sh-1); + while ((cc==0 || cc==-1) && k!=0 && kc!=0) { + kc--; + cc += mpn_add_1(&c2, bp+(--k), 1,(cp[kc+1]<<(mp_bits_per_limb-dif)) + +(cp[kc]>>dif)); + if (cc==0 || cc==-1) cc=c2; + } + if ((long)cc>0) goto add_one_ulp; + else if ((long)cc<-1) + { TMP_FREE(marker); return; /* the carry can be at most 1 */ } + else if (kc==0) goto round_b; + + /* else round c: go through */ + + case 3: /* only c to round */ + bp=cp; k=cn-k; goto to_nearest; + + case 0: /* only b to round */ + round_b: + k=bn-an; dif=0; goto to_nearest; + + /* otherwise the result is exact: nothing to do */ + } + } + else if ((ISNONNEG(b) && rnd_mode==GMP_RNDU) || + (ISNEG(b) && rnd_mode==GMP_RNDD)) { + cc = *ap & ((ONE<<sh)-1); + *ap &= ~cc; /* truncate last bits */ + if (cc || c3) goto add_one_ulp; /* will happen most of the time */ + else { + + /* same four cases too */ + + int kc = cn-k; /* remains kc limbs from c */ + switch (overlap) + { + case 1: /* both b and c to round */ + k = bn-an; /* remains k limbs from b */ + while (cc==0 && k!=0 && kc!=0) { + kc--; + cc = mpn_add_1(&c2, bp+(--k), 1,(cp[kc+1]<<(mp_bits_per_limb-dif)) + + (cp[kc]>>dif)); + } + if (cc) goto add_one_ulp; + else if (kc==0) goto round_b2; + /* else round c: go through */ + case 3: /* only c to round */ + while (kc) if (cp[--kc]) goto add_one_ulp; + /* if dif>0 : remains to check last dif bits from c */ + if (dif>0 && (cp[0]<<(mp_bits_per_limb-dif))) goto add_one_ulp; + break; + case 0: /* only b to round */ + round_b2: + k=bn-an; + while (k) if (bp[--k]) goto add_one_ulp; + /* otherwise the result is exact: nothing to do */ + } + } + } + /* else nothing to do: round towards zero, i.e. truncate last sh bits */ + else + *ap &= ~((ONE<<sh)-1); + } + goto end_of_add; + + to_nearest: /* 0 <= sh < mp_bits_per_limb : number of bits of a to truncate + bp[k] : last significant limb from b */ + if (sh) { + cc = *ap & ((ONE<<sh)-1); + *ap &= ~cc; /* truncate last bits */ + c2 = ONE<<(sh-1); + } + else /* no bit to truncate */ + { if (k) cc = bp[--k]; else cc = 0; c2 = ONE<<(mp_bits_per_limb-1); } + if (cc>c2) goto add_one_ulp; /* trunc(b)>1/2*lsb(a) -> round up */ + else if (cc==c2) { + cc=0; while (k && cc==0) cc=bp[--k]; + /* special case of rouding c shifted to the right */ + if (cc==0 && dif>0) cc=cp[0]<<(mp_bits_per_limb-dif); + /* now if the truncated part of b = 1/2*lsb(a), check whether c=0 */ + if (cc || (*ap & (ONE<<sh))) goto add_one_ulp; + } + goto end_of_add; + + add_one_ulp: /* add one unit in last place to a */ + cc = mpn_add_1(ap, ap, an, ONE<<sh); + if (cc) { fprintf(stderr, "carry(3) in mpfr_add\n"); exit(1); } + + end_of_add: + TMP_FREE(marker); + return; +} + +void +#if __STDC__ +mpfr_add(mpfr_ptr a, mpfr_srcptr b, mpfr_srcptr c, + unsigned char rnd_mode) +#else +mpfr_add(a, b, c, rnd_mode) + mpfr_ptr a; + mpfr_srcptr b; + mpfr_srcptr c; + unsigned char rnd_mode; +#endif +{ + int diff_exp; + + if (FLAG_NAN(b) || FLAG_NAN(c)) { + SET_NAN(a); return; + } + + if (!NOTZERO(b)) { mpfr_set(a, c, rnd_mode); return; } + if (!NOTZERO(c)) { mpfr_set(a, b, rnd_mode); return; } + + diff_exp = EXP(b)-EXP(c); + if (SIGN(b) != SIGN(c)) { /* signs differ, it's a subtraction */ + if (diff_exp<0) { + mpfr_sub1(a, c, b, rnd_mode, -diff_exp); + } + else if (diff_exp>0) mpfr_sub1(a, b, c, rnd_mode, diff_exp); + else { /* diff_exp=0 */ + diff_exp = mpfr_cmp3(b,c,-1); + /* if b>0 and diff_exp>0 or b<0 and diff_exp<0: abs(b) > abs(c) */ + if (diff_exp==0) SET_ZERO(a); + else if (diff_exp*SIGN(b)>0) mpfr_sub1(a, b, c, rnd_mode, 0); + else mpfr_sub1(a, c, b, rnd_mode, 0); + } + } + else /* signs are equal, it's an addition */ + if (diff_exp<0) mpfr_add1(a, c, b, rnd_mode, -diff_exp); + else mpfr_add1(a, b, c, rnd_mode, diff_exp); +} + diff --git a/mpfr/add_ulp.c b/mpfr/add_ulp.c new file mode 100644 index 000000000..7a8fa6150 --- /dev/null +++ b/mpfr/add_ulp.c @@ -0,0 +1,64 @@ +/* mpfr_add_one_ulp, mpfr_sub_one_ulp -- add/subtract one unit in last place + +Copyright (C) 1999 PolKA project, Inria Lorraine and Loria + +This file is part of the MPFR Library. + +The MPFR Library is free software; you can redistribute it and/or modify +it under the terms of the GNU Library General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at your +option) any later version. + +The MPFR Library 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 Library General Public +License for more details. + +You should have received a copy of the GNU Library General Public License +along with the MPFR Library; see the file COPYING.LIB. If not, write to +the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, +MA 02111-1307, USA. */ + +#include "gmp.h" +#include "gmp-impl.h" +#include "mpfr.h" + +/* sets x to x+sign(x)*2^(EXP(x)-PREC(x)) */ +int +#if __STDC__ +mpfr_add_one_ulp(mpfr_ptr x) +#else +mpfr_add_one_ulp(x) + mpfr_ptr x; +#endif +{ + int xn, sh; mp_limb_t *xp; + + xn = 1 + (PREC(x)-1)/BITS_PER_MP_LIMB; + sh = xn*BITS_PER_MP_LIMB - PREC(x); + xp = MANT(x); + if (mpn_add_1(xp, xp, xn, (mp_limb_t)1<<sh)) { + EXP(x)++; + mpn_rshift(xp, xp, xn, 1); + xp[xn-1] += (mp_limb_t)1<<(BITS_PER_MP_LIMB-1); + } + return 0; +} + +/* sets x to x-sign(x)*ulp(x) */ +int mpfr_sub_one_ulp(mpfr_ptr x) +{ + int xn, sh; mp_limb_t *xp; + + xn = 1 + (PREC(x)-1)/BITS_PER_MP_LIMB; + sh = xn*BITS_PER_MP_LIMB-PREC(x); + xp = MANT(x); + mpn_sub_1(xp, xp, xn, (mp_limb_t)1<<sh); + if (xp[xn-1] >> (BITS_PER_MP_LIMB-1) == 0) { + /* was an exact power of two: not normalized any more */ + EXP(x)--; + mpn_lshift(xp, xp, xn, 1); + *xp |= ((mp_limb_t)1 << sh); + } + return 0; +} diff --git a/mpfr/agm.c b/mpfr/agm.c new file mode 100644 index 000000000..e4c700961 --- /dev/null +++ b/mpfr/agm.c @@ -0,0 +1,172 @@ +/* mpfr_agm -- arithmetic-geometric mean of two floating-point numbers + +Copyright (C) 1999 PolKA project, Inria Lorraine and Loria + +This file is part of the MPFR Library. + +The MPFR Library is free software; you can redistribute it and/or modify +it under the terms of the GNU Library General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at your +option) any later version. + +The MPFR Library 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 Library General Public +License for more details. + +You should have received a copy of the GNU Library General Public License +along with the MPFR Library; see the file COPYING.LIB. If not, write to +the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, +MA 02111-1307, USA. */ + +#include <stdio.h> +#include <math.h> +#include "gmp.h" +#include "gmp-impl.h" +#include "mpfr.h" + + +/*Memory gestion */ +#define MON_INIT(xp, x, p, s) xp = (mp_ptr) TMP_ALLOC(s*BYTES_PER_MP_LIMB); x -> _mp_prec = p; x -> _mp_d = xp; x -> _mp_size = s; x -> _mp_exp = 0; + + + + +void +#ifdef __STDC__ +mpfr_agm(mpfr_ptr r, mpfr_srcptr op2, mpfr_srcptr op1, unsigned char rnd_mode) +#else +mpfr_agm(r, a, b, rnd_mode) + mpfr_ptr r; + mpfr_srcptr a; + mpfr_srcptr b; + unsigned char rnd_mode; +#endif +{ + int s, p, q, go_on; + double uo, vo; + mp_limb_t *up, *vp, *tmpp, *tmpup, *tmpvp, *ap, *bp; + mpfr_t u, v, tmp, tmpu, tmpv, a, b; + TMP_DECL(marker1); + TMP_DECL(marker2); + + + /* If a or b is NaN, the result is NaN */ + if (FLAG_NAN(op1) || FLAG_NAN(op2)) + { SET_NAN(r); return; } + + + /* If a or b is negative, the result is NaN */ + if ((SIGN(op1)<0)||(SIGN(op2)<0)) + { SET_NAN(r); return; } + + + + /* If a or b is 0, the result is 0 */ + if ((SIGN(op1)==0)||(SIGN(op2)==0)) + { SET_ZERO(r); + return; + } + + /* precision of the following calculus */ + q = PREC(r); + p = q + 15; + + + /* Initialisations */ + go_on=1; + + TMP_MARK(marker1); + s=(p-1)/BITS_PER_MP_LIMB+1; + MON_INIT(ap, a, p, s); + MON_INIT(bp, b, p, s); + TMP_MARK(marker2); + MON_INIT(up, u, p, s); + MON_INIT(vp, v, p, s); + MON_INIT(tmpup, tmpu, p, s); + MON_INIT(tmpvp, tmpv, p, s); + MON_INIT(tmpp, tmp, p, s); + + + + /* b and a will be the 2 operands but I want b>= a */ + if (mpfr_cmp(op1,op2) > 0) { + mpfr_set(b,op1,GMP_RNDN); mpfr_set(a,op2,GMP_RNDN); + } + else { + mpfr_set(b,op2,GMP_RNDN); mpfr_set(a,op1,GMP_RNDN); + } + + vo=mpfr_get_d(b); + uo=mpfr_get_d(a); + + mpfr_set(u,a,GMP_RNDN); + mpfr_set(v,b,GMP_RNDN); + + + /* Main loop */ + + while (go_on) { + int err, eq, can_round; + + eq=0; + + err=ceil((3.0/2.0*log((double)p)/log(2.0)+1.0)*exp(-(double)p*log(2.0))+3.0*exp(-2.0*(double)p*uo*log(2.0)/(vo-uo))); + if(p-err-3<=q) { + p=q+err+4; + err=ceil((3.0/2.0*log((double)p)/log(2.0)+1.0)*exp(-(double)p*log(2.0))+3.0*exp(-2.0*(double)p*uo*log(2.0)/(vo-uo))); + } + + /* Calculus of un and vn */ + while (eq<=p-2) { + mpfr_mul(tmp,u,v,GMP_RNDN); + mpfr_sqrt(tmpu,tmp,GMP_RNDN); + mpfr_add(tmp,u,v,GMP_RNDN); + mpfr_div_2exp(tmpv,tmp,1,GMP_RNDN); + mpfr_set(u,tmpu,GMP_RNDN); + mpfr_set(v,tmpv,GMP_RNDN); + if (mpfr_cmp(v,u)>=0) + eq=mpfr_cmp2(v,u); + else + eq=mpfr_cmp2(u,v); + } + + /* printf("avant can_round %i bits faux\n v : ",err+3); + mpfr_print_raw(v); printf("\n u : "); + mpfr_print_raw(u);printf("\n");*/ + + + /* Roundability of the result */ + can_round=mpfr_can_round(v,p-err-3,GMP_RNDN,rnd_mode,q); + + if (can_round) + go_on=0; + + else { + go_on=1; + p+=5; + TMP_FREE(marker2); + TMP_MARK(marker2); + s=(p-1)/BITS_PER_MP_LIMB+1; + MON_INIT(up, u, p, s); + MON_INIT(vp, v, p, s); + MON_INIT(tmpup, tmpu, p, s); + MON_INIT(tmpvp, tmpv, p, s); + MON_INIT(tmpp, tmp, p, s); + mpfr_set(u,a,GMP_RNDN); + mpfr_set(v,b,GMP_RNDN); + } + } + /* End of while */ + + /* Setting of the result */ + + mpfr_set(r,v,rnd_mode); + + + /* Let's clean */ + TMP_FREE(marker1); + + return ; +} + diff --git a/mpfr/clear.c b/mpfr/clear.c new file mode 100644 index 000000000..371c1a766 --- /dev/null +++ b/mpfr/clear.c @@ -0,0 +1,36 @@ +/* mpfr_clear -- free the memory space allocated for a floating-point number + +Copyright (C) 1999 PolKA project, Inria Lorraine and Loria + +This file is part of the MPFR Library. + +The MPFR Library is free software; you can redistribute it and/or modify +it under the terms of the GNU Library General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at your +option) any later version. + +The MPFR Library 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 Library General Public +License for more details. + +You should have received a copy of the GNU Library General Public License +along with the MPFR Library; see the file COPYING.LIB. If not, write to +the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, +MA 02111-1307, USA. */ + +#include <stdio.h> +#include "gmp.h" +#include "gmp-impl.h" +#include "mpfr.h" + +void +#if __STDC__ +mpfr_clear (mpfr_ptr m) +#else +mpfr_clear (m) + mpfr_ptr m; +#endif +{ + (*_mp_free_func) (m->_mp_d, ((m->_mp_prec>>3) + 1)); +} diff --git a/mpfr/cmp.c b/mpfr/cmp.c new file mode 100644 index 000000000..b64506b03 --- /dev/null +++ b/mpfr/cmp.c @@ -0,0 +1,219 @@ +/* mpfr_cmp -- compare two floating-point numbers + +Copyright (C) 1999 PolKA project, Inria Lorraine and Loria + +This file is part of the MPFR Library. + +The MPFR Library is free software; you can redistribute it and/or modify +it under the terms of the GNU Library General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at your +option) any later version. + +The MPFR Library 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 Library General Public +License for more details. + +You should have received a copy of the GNU Library General Public License +along with the MPFR Library; see the file COPYING.LIB. If not, write to +the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, +MA 02111-1307, USA. */ + +#include <stdio.h> +#include "gmp.h" +#include "gmp-impl.h" +#include "longlong.h" +#include "mpfr.h" + +/* returns 0 iff b = c + a positive value iff b > c + a negative value iff b < c + +More precisely, in case b and c are of same sign, the absolute value +of the result is one plus the absolute difference between the exponents +of b and c, i.e. one plus the number of bits shifts to align b and c +(this value is useful in mpfr_sub). + +*/ + +/* #define DEBUG */ + +/* compares b and sign(s)*c */ +int +#if __STDC__ +mpfr_cmp3 ( mpfr_srcptr b, mpfr_srcptr c, long int s) +#else +mpfr_cmp3(b, c, s) + mpfr_srcptr b; + mpfr_srcptr c; + long int s; +#endif +{ + long int diff_exp; + unsigned long bn, cn; + mp_limb_t *bp, *cp; + + if (!NOTZERO(b) && !NOTZERO(c)) { return 0; } + s = s*SIGN(b)*SIGN(c); + if (s<0) return(SIGN(b)); + + /* now signs are equal */ + + diff_exp = EXP(b)-EXP(c); + s = (SIGN(b)>0) ? 1 : -1; + + if (diff_exp>0) return(s*(1+diff_exp)); + else if (diff_exp<0) return(s*(-1+diff_exp)); + /* both signs and exponents are equal */ + + bn = (PREC(b)-1)/mp_bits_per_limb+1; + cn = (PREC(c)-1)/mp_bits_per_limb+1; + bp = MANT(b); cp = MANT(c); + + while (bn && cn) { + if (bp[--bn] != cp[--cn]) + return((bp[bn]>cp[cn]) ? s : -s); + } + + if (bn) { while (bn) if (bp[--bn]) return(s); } + else if (cn) while (cn) if (cp[--cn]) return(-s); + + return 0; +} + +/* returns the number of cancelled bits when one subtracts abs(c) from abs(b). + Assumes b>=c, which implies EXP(b)>=EXP(c). + if b=c, returns prec(b). +*/ +int +#if __STDC__ +mpfr_cmp2 ( mpfr_srcptr b, mpfr_srcptr c ) +#else +mpfr_cmp2(b, c) + mpfr_srcptr b; + mpfr_srcptr c; +#endif +{ + long int d, bn, cn, k, z; + mp_limb_t *bp, *cp, t, u=0, cc=0; + +#ifdef DEBUG + printf("b="); mpfr_print_raw(b); putchar('\n'); + printf("c="); mpfr_print_raw(c); putchar('\n'); +#endif + if (NOTZERO(c)==0) return (NOTZERO(b)) ? 0 : PREC(b); + d = EXP(b)-EXP(c); + k = 0; /* result can be d or d+1 if d>1, or >= d otherwise */ + /* k is the number of identical bits in the high part, + then z is the number of possibly cancelled bits */ +#ifdef DEBUG + if (d<0) { printf("assumption EXP(b)<EXP(c) violated\n"); exit(1); } +#endif + bn = (PREC(b)-1)/mp_bits_per_limb; + cn = (PREC(c)-1)/mp_bits_per_limb; + bp = MANT(b); cp = MANT(c); + /* subtract c from b from most significant to less significant limbs, + and first determines first non zero limb difference */ + if (d) + { + cc = bp[bn--]; + if (d<mp_bits_per_limb) + cc -= cp[cn]>>d; + } + else { /* d=0 */ + while (bn>=0 && cn>=0 && (cc=(bp[bn--]-cp[cn--]))==0) { + k+=mp_bits_per_limb; + } + + if (cc==0) { /* either bn<0 or cn<0 */ + while (bn>=0 && (cc=bp[bn--])==0) k+=mp_bits_per_limb; + } + /* now bn<0 or cc<>0 */ + if (cc==0 && bn<0) return(PREC(b)); + } + + /* the first non-zero limb difference is cc, and the number + of cancelled bits in the upper limbs is k */ + + count_leading_zeros(u, cc); + k += u; + + if (cc != (1<<(mp_bits_per_limb-u-1))) return k; + + /* now cc is an exact power of two */ + if (cc != 1) + /* We just need to compare the following limbs */ + /* until two of them differ. The result is either k or k+1. */ + { + /* First flush all the unmatched limbs of b ; they all have to + be 0 in order for the process to go on */ + while (bn >= 0) + { + if (cn < 0) { return k; } + t = bp[bn--]; + if (d < mp_bits_per_limb) + { + if (d) + { + u = cp[cn--] << (mp_bits_per_limb - d); + if (cn >= 0) u+=(cp[cn]>>d); + } + else u = cp[cn--]; + + if (t > u || (t == u && cn < 0)) return k; + if (t < u) return k+1; + } + else + if (t) return k; else d -= mp_bits_per_limb; + } + + /* bn < 0; if some limb of c is nonzero, return k+1, otherwise return k*/ + + if (cn>=0 && (cp[cn--] << (mp_bits_per_limb - d))) { return k+1; } + + while (cn >= 0) + if (cp[cn--]) return k+1; + return k; + } + + /* cc = 1. Too bad. */ + z = 0; /* number of possibly cancelled bits - 1 */ + /* thus result is either k if low(b) >= low(c) + or k+z+1 if low(b) < low(c) */ + if (d > mp_bits_per_limb) { return k; } + + while (bn >= 0) + { + if (cn < 0) { return k; } + + if (d) + { + u = cp[cn--] << (mp_bits_per_limb - d); + if (cn >= 0) u+=(cp[cn]>>d); + } + else u = cp[cn--]; + + /* bp[bn--] > cp[cn--] : no borrow possible, k unchanged + bp[bn--] = cp[cn--] : need to consider next limbs + bp[bn--] < cp[cn--] : borrow + */ + if ((cc = bp[bn--]) != u) { + if (cc>u) return k; + else { count_leading_zeros(u, cc-u); return k + 1 + z + u; } + } + else z += mp_bits_per_limb; + } + + if (cn >= 0) + count_leading_zeros(cc, ~(cp[cn--] << (mp_bits_per_limb - d))); + else { cc = 0; } + + k += cc; + if (cc < d) return k; + + while (cn >= 0 && !~cp[cn--]) { z += mp_bits_per_limb; } + if (cn >= 0) { count_leading_zeros(cc, ~cp[cn--]); return (k + z + cc); } + + return k; /* We **need** that the nonsignificant limbs of c are set + to zero there */ +} diff --git a/mpfr/cmp_ui.c b/mpfr/cmp_ui.c new file mode 100644 index 000000000..48217a520 --- /dev/null +++ b/mpfr/cmp_ui.c @@ -0,0 +1,116 @@ +/* mpfr_cmp_ui -- compare a floating-point number with a machine integer + +Copyright (C) 1999 PolKA project, Inria Lorraine and Loria + +This file is part of the MPFR Library. + +The MPFR Library is free software; you can redistribute it and/or modify +it under the terms of the GNU Library General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at your +option) any later version. + +The MPFR Library 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 Library General Public +License for more details. + +You should have received a copy of the GNU Library General Public License +along with the MPFR Library; see the file COPYING.LIB. If not, write to +the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, +MA 02111-1307, USA. */ + +#include <stdio.h> +#include "gmp.h" +#include "gmp-impl.h" +#include "longlong.h" +#include "mpfr.h" + +/* returns a positive value if b>i*2^f, + a negative value if b<i*2^f, + zero if b=i*2^f +*/ + +int +#if __STDC__ +mpfr_cmp_ui_2exp ( mpfr_srcptr b, unsigned long int i, int f ) +#else +mpfr_cmp_ui_2exp (b, i, f) + mpfr_srcptr b; + unsigned long int i; + int f; +#endif +{ + int e, k, bn; mp_limb_t c, *bp; + + if (SIGN(b)<0) return -1; + else if (!NOTZERO(b)) return((i) ? -1 : 0); + else { /* b>0 */ + e = EXP(b); /* 2^(e-1) <= b < 2^e */ + if (e>f+mp_bits_per_limb) return 1; + + c = (mp_limb_t) i; + count_leading_zeros(k, c); + k = f+mp_bits_per_limb - k; /* 2^(k-1) <= i*2^f < 2^k */ + if (k!=e) return (e-k); + + /* now k=e */ + c <<= (f+mp_bits_per_limb-k); + bn = (PREC(b)-1)/mp_bits_per_limb; + bp = MANT(b) + bn; + if (*bp>c) return 1; + else if (*bp<c) return -1; + + /* most significant limbs agree, check remaining limbs from b */ + while (--bn>=0) + if (*--bp) return 1; + return 0; + } +} + +/* returns a positive value if b>i*2^f, + a negative value if b<i*2^f, + zero if b=i*2^f +*/ + +int +#if __STDC__ +mpfr_cmp_si_2exp ( mpfr_srcptr b, long int i, int f ) +#else +mpfr_cmp_si_2exp(b, i, f) + mpfr_srcptr b; + long int i; + int f; +#endif +{ + int e, k, bn, si; mp_limb_t c, *bp; + + si = (i<0) ? -1 : 1; /* sign of i */ + if (SIGN(b)*i<0) return SIGN(b); /* both signs differ */ + else if (!NOTZERO(b) || (i==0)) { /* one is zero */ + if (i==0) return ((NOTZERO(b)) ? SIGN(b) : 0); + else return si; /* b is zero */ + + } + else { /* b and i are of same sign */ + e = EXP(b); /* 2^(e-1) <= b < 2^e */ + if (e>f+mp_bits_per_limb) return si; + + c = (mp_limb_t) ((i<0) ? -i : i); + count_leading_zeros(k, c); + k = f+mp_bits_per_limb - k; /* 2^(k-1) <= i*2^f < 2^k */ + if (k!=e) return (si*(e-k)); + + /* now k=e */ + c <<= (f+mp_bits_per_limb-k); + bn = (PREC(b)-1)/mp_bits_per_limb; + bp = MANT(b) + bn; + if (*bp>c) return si; + else if (*bp<c) return -si; + + /* most significant limbs agree, check remaining limbs from b */ + while (--bn>=0) + if (*--bp) return si; + return 0; + } +} + diff --git a/mpfr/div.c b/mpfr/div.c new file mode 100644 index 000000000..ee1475694 --- /dev/null +++ b/mpfr/div.c @@ -0,0 +1,247 @@ +/* mpfr_div -- divide two floating-point numbers + +Copyright (C) 1999 PolKA project, Inria Lorraine and Loria + +This file is part of the MPFR Library. + +The MPFR Library is free software; you can redistribute it and/or modify +it under the terms of the GNU Library General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at your +option) any later version. + +The MPFR Library 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 Library General Public +License for more details. + +You should have received a copy of the GNU Library General Public License +along with the MPFR Library; see the file COPYING.LIB. If not, write to +the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, +MA 02111-1307, USA. */ + +#include <math.h> +#include <stdio.h> +#include <stdlib.h> +#include "gmp.h" +#include "gmp-impl.h" +#include "mpfr.h" +#include "longlong.h" + +/* #define DEBUG */ + +void +mpfr_div (mpfr_ptr r, mpfr_srcptr u, mpfr_srcptr v, unsigned char rnd_mode) +{ + mp_srcptr up, vp; + mp_ptr rp, tp, tp0, tmp; + mp_size_t usize, vsize, rrsize; + mp_size_t rsize; + mp_size_t sign_quotient; + mp_size_t prec, err; + mp_limb_t q_limb; + mp_exp_t rexp; + long k, mult, vn; + unsigned long cc = 0, rw, nw; + char can_round = 0; + TMP_DECL (marker); + + if (FLAG_NAN(u) || FLAG_NAN(v)) { SET_NAN(r); return; } + + usize = (PREC(u) - 1)/BITS_PER_MP_LIMB + 1; + vsize = (PREC(v) - 1)/BITS_PER_MP_LIMB + 1; + sign_quotient = (SIGN(u) == SIGN(v) ? 1 : -1); + prec = PREC(r); + + if (!NOTZERO(u)) { SET_ZERO(r); return; } + + if (!NOTZERO(v)) + vsize = 1 / v->_mp_d[vsize - 1]; /* Gestion des infinis ? */ + + if (!NOTZERO(v)) + { + r->_mp_exp = 0; + MPN_ZERO(r->_mp_d, r->_mp_size); + return; + } + + up = u->_mp_d; + vp = v->_mp_d; + +#ifdef DEBUG + printf("Entering division : "); + for(k = usize - 1; k >= 0; k--) { printf("%lu ", up[k]); } + printf(" by "); + for(k = vsize - 1; k >= 0; k--) { printf("%lu ", vp[k]); } + printf(".\n"); +#endif + + /* Compare the mantissas */ + mult = mpn_cmp(up, vp, (usize > vsize ? vsize : usize)); + if (mult == 0 && vsize > usize) + { + vn = vsize - usize; + while (vn >= 0) if (vp[vn--]) { mult = 1; break; } + /* On peut diagnostiquer ici pour pas cher le cas u = v */ + } + else { mult = (mult < 0 ? 1 : 0); } + + rsize = (PREC(r) + 3)/BITS_PER_MP_LIMB + 1; + rrsize = PREC(r)/BITS_PER_MP_LIMB + 1; + /* Three extra bits are needed in order to get the quotient with enough + precision ; take one extra bit for rrsize in order to solve more + easily the problem of rounding to nearest. */ + + /* ATTENTION, USIZE DOIT RESTER > A VSIZE !!!!!!!! */ + + do + { + TMP_MARK (marker); + + rexp = u->_mp_exp - v->_mp_exp; + + err = rsize*BITS_PER_MP_LIMB; + if (rsize < vsize) { err-=2; } + if (rsize < usize) { err--; } + if (err > rrsize * BITS_PER_MP_LIMB) + { err = rrsize * BITS_PER_MP_LIMB; } + + tp0 = (mp_ptr) TMP_ALLOC ((rsize+rrsize) * BYTES_PER_MP_LIMB); + /* fill by zero rrsize low limbs of t */ + MPN_ZERO(tp0, rrsize); tp = tp0 + rrsize; + tmp = (mp_ptr) TMP_ALLOC (rsize * BYTES_PER_MP_LIMB); + rp = (mp_ptr) TMP_ALLOC (rrsize * BYTES_PER_MP_LIMB); + + if (vsize >= rsize) { + MPN_COPY (tmp, vp + vsize - rsize, rsize); + } + else { + MPN_COPY (tmp + rsize - vsize, vp, vsize); + MPN_ZERO (tmp, rsize - vsize); + } + + if (usize >= rsize) { + MPN_COPY (tp, up + usize - rsize, rsize); + } + else { + MPN_COPY (tp + rsize - usize, up, usize); + MPN_ZERO (tp, rsize - usize); + } + + /* Do the real job */ + +#ifdef DEBUG + printf("Dividing : "); + for(k = rsize - 1; k >= 0; k--) { printf("%lu ", tp[k]); } + printf(" by "); + for(k = rsize - 1; k >= 0; k--) { printf("%lu ", tmp[k]); } + printf(".\n"); +#endif + + q_limb = (rsize==rrsize) /* use Burnikel-Ziegler algorithm */ + ? mpn_divrem_n (rp, tp0, tmp, rsize) + : mpn_divrem (rp, 0, tp0, rsize+rrsize, tmp, rsize); + tp = tp0; /* location of remainder */ + +#ifdef DEBUG + printf("The result is : \n"); + printf("Quotient : "); + for(k = rrsize - 1; k >= 0; k--) { printf("%lu ", rp[k]); } + printf("Remainder : "); + for(k = rsize - 1; k >= 0; k--) { printf("%lu ", tp[k]); } + printf("(q_limb = %lu)\n", q_limb); +#endif + + /* msb-normalize the result */ + + if (q_limb) + { + count_leading_zeros(k, q_limb); + mpn_rshift(rp, rp, rrsize, BITS_PER_MP_LIMB - k); + rp[rrsize - 1] |= (q_limb << k); + rexp += BITS_PER_MP_LIMB - k; + } + else + { + count_leading_zeros(k, rp[rrsize - 1]); + if (k) { mpn_lshift(rp, rp, rrsize, k); } + rexp -= k; + } + + can_round = (mpfr_can_round_raw(rp, rrsize, sign_quotient, err, + GMP_RNDN, rnd_mode, PREC(r)) + || (usize == rsize && vsize == rsize && + mpfr_can_round_raw(rp, rrsize, sign_quotient, err, + GMP_RNDZ, rnd_mode, PREC(r)))); + + /* If we used all the limbs of both the dividend and the divisor, + then we have the correct RNDZ rounding */ + + if (!can_round && (rsize < usize || rsize < vsize)) + { +#ifdef DEBUG + printf("Increasing the precision.\n"); +#endif + printf("#"); + TMP_FREE(marker); + } + } + while (!can_round && (rsize < usize || rsize < vsize) + && (rsize++) && (rrsize++)); + + /* ON PEUT PROBABLEMENT SE DEBROUILLER DES QUE rsize >= vsize */ + /* MAIS IL FAUT AJOUTER LE BOUT QUI MANQUE DE usize A rsize */ + + if (can_round) + { + cc = mpfr_round_raw(rp, rp, err, (sign_quotient == -1 ? 1 : 0), + PREC(r), rnd_mode); + rrsize = (PREC(r) - 1)/BITS_PER_MP_LIMB + 1; + } + else + /* Use the remainder to find out the correct rounding */ + /* Note that at this point the division has been done */ + /* EXACTLY. */ + if ((rnd_mode == GMP_RNDD && sign_quotient == -1) + || (rnd_mode == GMP_RNDU && sign_quotient == 1) + || (rnd_mode == GMP_RNDN)) + { + /* We cannot round, so that the last bits of the quotient + have to be zero; just look if the remainder is nonzero */ + k = rsize - 1; + while (k >= 0) { if (tp[k]) break; k--; } + if (k >= 0) + cc = mpn_add_1(rp, rp, rrsize, (mp_limb_t)1 << (BITS_PER_MP_LIMB - + (PREC(r) & + (BITS_PER_MP_LIMB - 1)))); + else + if (rnd_mode == GMP_RNDN) /* even rounding */ + { + rw = (PREC(r) + 1) & (BITS_PER_MP_LIMB - 1); + if (rw) { rw = BITS_PER_MP_LIMB - rw; nw = 0; } else nw = 1; + if ((rw ? (rp[nw] >> (rw + 1)) & 1 : + (rp[nw] >> (BITS_PER_MP_LIMB - 1)) & 1)) + { + cc = mpn_add_1(rp + nw, rp + nw, rrsize, + ((mp_limb_t)1) << rw); + } + } + /* cas 0111111 */ + } + + if (sign_quotient != SIGN(r)) { CHANGE_SIGN(r); } + r->_mp_exp = rexp; + + if (cc) { + mpn_rshift(rp, rp, rrsize, 1); + rp[rrsize-1] |= (mp_limb_t) 1 << (BITS_PER_MP_LIMB-1); + r->_mp_exp++; + } + + rsize = rrsize; + rrsize = (PREC(r) - 1)/BITS_PER_MP_LIMB + 1; + MPN_COPY(r->_mp_d, rp + rsize - rrsize, rrsize); + MANT(r) [0] &= ~(((mp_limb_t)1 << (BITS_PER_MP_LIMB - + (PREC(r) & (BITS_PER_MP_LIMB - 1)))) - 1) ; + + TMP_FREE (marker); +} diff --git a/mpfr/div_2exp.c b/mpfr/div_2exp.c new file mode 100644 index 000000000..e7602db44 --- /dev/null +++ b/mpfr/div_2exp.c @@ -0,0 +1,43 @@ +/* mpfr_div_2exp -- divide a floating-point number by a power of two + +Copyright (C) 1999 PolKA project, Inria Lorraine and Loria + +This file is part of the MPFR Library. + +The MPFR Library is free software; you can redistribute it and/or modify +it under the terms of the GNU Library General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at your +option) any later version. + +The MPFR Library 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 Library General Public +License for more details. + +You should have received a copy of the GNU Library General Public License +along with the MPFR Library; see the file COPYING.LIB. If not, write to +the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, +MA 02111-1307, USA. */ + +#include <stdio.h> +#include "gmp.h" +#include "gmp-impl.h" +#include "mpfr.h" + +void +#if __STDC__ +mpfr_div_2exp(mpfr_ptr y, mpfr_srcptr x, unsigned long int n, unsigned char rnd_mode) +#else +mpfr_div_2exp(y, x, n, rnd_mode) + mpfr_ptr y; + mpfr_srcptr x; + unsigned long int n; + unsigned char rnd_mode; +#endif +{ + /* Important particular case */ + if (y != x) mpfr_set(y, x, rnd_mode); + EXP(y) -= n; + return; +} + diff --git a/mpfr/div_ui.c b/mpfr/div_ui.c new file mode 100644 index 000000000..7cd124142 --- /dev/null +++ b/mpfr/div_ui.c @@ -0,0 +1,135 @@ +/* mpfr_div_ui -- divide a floating-point number by a machine integer + +Copyright (C) 1999 PolKA project, Inria Lorraine and Loria + +This file is part of the MPFR Library. + +The MPFR Library is free software; you can redistribute it and/or modify +it under the terms of the GNU Library General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at your +option) any later version. + +The MPFR Library 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 Library General Public +License for more details. + +You should have received a copy of the GNU Library General Public License +along with the MPFR Library; see the file COPYING.LIB. If not, write to +the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, +MA 02111-1307, USA. */ + +#include <stdio.h> +#include "gmp.h" +#include "gmp-impl.h" +#include "longlong.h" +#include "mpfr.h" + +/* #define DEBUG */ + +/* returns 0 if result exact, non-zero otherwise */ +int +#ifdef __STDC__ +mpfr_div_ui(mpfr_ptr y, mpfr_srcptr x, unsigned long u, unsigned char rnd_mode) +#else +mpfr_div_ui(y, x, u, rnd_mode) + mpfr_ptr y; + mpfr_srcptr x; + unsigned long u; + unsigned char rnd_mode; +#endif +{ + int xn, yn, dif, sh, i; mp_limb_t *xp, *yp, *tmp, c, d; + TMP_DECL(marker); + + if (FLAG_NAN(x)) { SET_NAN(y); return 1; } + if (u==0) { printf("infinity\n"); return 1; } + + TMP_MARK(marker); + xn = (PREC(x)-1)/BITS_PER_MP_LIMB + 1; + yn = (PREC(y)-1)/BITS_PER_MP_LIMB + 1; + + xp = MANT(x); + yp = MANT(y); + EXP(y) = EXP(x); + if (SIGN(x)!=SIGN(y)) CHANGE_SIGN(y); + + dif = yn+1-xn; +#ifdef DEBUG + printf("dif=%d u=%lu xn=%d\n",dif,u,xn); + printf("x="); mpfr_print_raw(x); putchar('\n'); +#endif + + /* we need to store yn+1 = xn + dif limbs of the quotient */ + if (ABSSIZE(y)>=yn+1) tmp=yp; + else tmp=TMP_ALLOC((yn+1)*BYTES_PER_MP_LIMB); + + c = (mp_limb_t) u; + if (dif>=0) { + /* patch for bug in mpn_divrem_1 */ +#if (UDIV_NEEDS_NORMALIZATION==1) + count_leading_zeros(sh, c); + c <<= sh; + EXP(y) += sh; +#endif + c = mpn_divrem_1(tmp, dif, xp, xn, c); + } + else /* dif < 0 i.e. xn > yn */ + c = mpn_divrem_1(tmp, 0, xp-dif, yn, c); + + if (tmp[yn]==0) { tmp--; sh=0; EXP(y) -= mp_bits_per_limb; } + /* shift left to normalize */ + count_leading_zeros(sh, tmp[yn]); + if (sh) { + mpn_lshift(yp, tmp+1, yn, sh); + yp[0] += tmp[0] >> (BITS_PER_MP_LIMB-sh); + EXP(y) -= sh; + } + else MPN_COPY(yp, tmp+1, yn); +#ifdef DEBUG +printf("y="); mpfr_print_raw(y); putchar('\n'); +#endif + + sh = yn*BITS_PER_MP_LIMB - PREC(y); + /* it remains sh bits in less significant limb of y */ + + d = *yp & (((mp_limb_t)1 << sh) - 1); + *yp ^= d; /* set to zero lowest sh bits */ + + TMP_FREE(marker); + if ((c | d)==0) { + for (i=0; i<-dif && xp[i]==0; i++); + if (i>=-dif) return 0; /* result is exact */ + } + + switch (rnd_mode) { + case GMP_RNDZ: + return 1; /* result is inexact */ + case GMP_RNDU: + if (SIGN(y)>0) mpfr_add_one_ulp(y); + return 1; /* result is inexact */ + case GMP_RNDD: + if (SIGN(y)<0) mpfr_add_one_ulp(y); + return 1; /* result is inexact */ + case GMP_RNDN: + if (d < ((mp_limb_t)1 << (sh-1))) return 1; + else if (d > ((mp_limb_t)1 << (sh-1))) { + mpfr_add_one_ulp(y); + } + else { /* d = (mp_limb_t)1 << (sh-1) */ + if (c) mpfr_add_one_ulp(y); + else { + for (i=0; i<-dif && xp[i]==0; i++); + if (i<-dif) mpfr_add_one_ulp(y); + else { /* exactly in the middle */ + if (*yp & ((mp_limb_t)1 << sh)) mpfr_add_one_ulp(y); + } + } + } + return 1; + } + return 0; /* to prevent warning from gcc */ +} + + + diff --git a/mpfr/exp.c b/mpfr/exp.c new file mode 100644 index 000000000..c3ec218a0 --- /dev/null +++ b/mpfr/exp.c @@ -0,0 +1,176 @@ +/* mpfr_exp -- exponential of a floating-point number + +Copyright (C) 1999 PolKA project, Inria Lorraine and Loria + +This file is part of the MPFR Library. + +The MPFR Library is free software; you can redistribute it and/or modify +it under the terms of the GNU Library General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at your +option) any later version. + +The MPFR Library 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 Library General Public +License for more details. + +You should have received a copy of the GNU Library General Public License +along with the MPFR Library; see the file COPYING.LIB. If not, write to +the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, +MA 02111-1307, USA. */ + +#include <stdio.h> +#include <math.h> +#include "gmp.h" +#include "gmp-impl.h" +#include "mpfr.h" + +/* #define DEBUG */ + +#define LOG2 0.69314718055994528622 /* log(2) rounded to zero on 53 bits */ + +/* use Brent's formula exp(x) = (1+r+r^2/2!+r^3/3!+...)^(2^K)*2^n + where x = n*log(2)+(2^K)*r + number of operations = O(K+prec(r)/K) +*/ +int +#if __STDC__ +mpfr_exp(mpfr_ptr y, mpfr_srcptr x, unsigned char rnd_mode) +#else +mpfr_exp(y, x, rnd_mode) + mpfr_ptr y; + mpfr_srcptr x; + unsigned char rnd_mode; +#endif +{ + int n, expx, K, precy, q, k, l, expr, err; + mpfr_t r, s, t; + + if (FLAG_NAN(x)) { SET_NAN(y); return 1; } + if (!NOTZERO(x)) { mpfr_set_ui(y, 1, GMP_RNDN); return 0; } + + expx = EXP(x); + precy = PREC(y); +#ifdef DEBUG + printf("EXP(x)=%d\n",expx); +#endif + + /* if x > (2^31-1)*ln(2), then exp(x) > 2^(2^31-1) i.e. gives +infinity */ + if (expx > 30) { + if (SIGN(x)>0) { printf("+infinity"); return 1; } + else { SET_ZERO(y); return 1; } + } + + /* if x < 2^(-precy), then exp(x) i.e. gives 1 +/- 1 ulp(1) */ + if (expx < -precy) { int signx = SIGN(x); + mpfr_set_ui(y, 1, rnd_mode); + if (signx>0 && rnd_mode==GMP_RNDU) mpfr_add_one_ulp(y); + else if (signx<0 && (rnd_mode==GMP_RNDD || rnd_mode==GMP_RNDZ)) + mpfr_sub_one_ulp(y); + return 1; } + + n = (int) floor(mpfr_get_d(x)/LOG2); + + K = (int) sqrt( (double) precy ); + l = (precy-1)/K + 1; + err = K + (int) ceil(log(2.0*(double)l+18.0)/LOG2); + /* add K extra bits, i.e. failure probability <= 1/2^K = O(1/precy) */ + q = precy + err + K + 3; + mpfr_init2(r, q); mpfr_init2(s, q); mpfr_init2(t, q); + /* the algorithm consists in computing an upper bound of exp(x) using + a precision of q bits, and see if we can round to PREC(y) taking + into account the maximal error. Otherwise we increase q. */ + do { +#ifdef DEBUG + printf("n=%d K=%d l=%d q=%d\n",n,K,l,q); +#endif + + /* if n<0, we have to get an upper bound of log(2) + in order to get an upper bound of r = x-n*log(2) */ + mpfr_log2(s, (n>=0) ? GMP_RNDZ : GMP_RNDU); +#ifdef DEBUG + printf("n=%d log(2)=",n); mpfr_print_raw(s); putchar('\n'); +#endif + mpfr_mul_ui(r, s, (n<0) ? -n : n, (n>=0) ? GMP_RNDZ : GMP_RNDU); + if (n<0) mpfr_neg(r, r, GMP_RNDD); + /* r = floor(n*log(2)) */ + +#ifdef DEBUG + printf("x=%1.20e\n",mpfr_get_d(x)); + printf(" ="); mpfr_print_raw(x); putchar('\n'); + printf("r=%1.20e\n",mpfr_get_d(r)); + printf(" ="); mpfr_print_raw(r); putchar('\n'); +#endif + mpfr_sub(r, x, r, GMP_RNDU); + if (SIGN(r)<0) { /* initial approximation n was too large */ + n--; + mpfr_mul_ui(r, s, (n<0) ? -n : n, GMP_RNDZ); + if (n<0) mpfr_neg(r, r, GMP_RNDD); + mpfr_sub(r, x, r, GMP_RNDU); + } +#ifdef DEBUG + printf("x-r=%1.20e\n",mpfr_get_d(r)); + printf(" ="); mpfr_print_raw(r); putchar('\n'); + if (SIGN(r)<0) { fprintf(stderr,"Error in mpfr_exp: r<0\n"); exit(1); } +#endif + mpfr_div_2exp(r, r, K, GMP_RNDU); /* r = (x-n*log(2))/2^K */ + mpfr_set_ui(s, 1, GMP_RNDU); + mpfr_set_ui(t, 1, GMP_RNDU); + + l = 1; expr = EXP(r); + do { + mpfr_mul(t, t, r, GMP_RNDU); + mpfr_div_ui(t, t, l, GMP_RNDU); + mpfr_add(s, s, t, GMP_RNDU); +#ifdef DEBUG + printf("l=%d t=%1.20e\n",l,mpfr_get_d(t)); + printf("s=%1.20e\n",mpfr_get_d(s)); +#endif + l++; + } while (EXP(t)+expr > -q); +#ifdef DEBUG + printf("l=%d q=%d (K+l)*q^2=%1.3e\n", l, q, (K+l)*(double)q*q); +#endif + + /* add 2 ulp to take into account rest of summation */ + mpfr_add_one_ulp(s); + mpfr_add_one_ulp(s); + + for (k=0;k<K;k++) { + mpfr_mul(s, s, s, GMP_RNDU); +#ifdef DEBUG + printf("k=%d s=%1.20e\n",k,mpfr_get_d(s)); +#endif + } + + if (n>0) mpfr_mul_2exp(s, s, n, GMP_RNDU); + else mpfr_div_2exp(s, s, -n, GMP_RNDU); + + /* error is at most 2^K*(2l+18) ulp */ + l = 2*l+17; k=0; while (l) { k++; l >>= 1; } + /* now k = ceil(log(2l+18)/log(2)) */ + K += k; +#ifdef DEBUG + printf("after mult. by 2^n:\n"); + if (EXP(s)>-1024) printf("s=%1.20e\n",mpfr_get_d(s)); + printf(" ="); mpfr_print_raw(s); putchar('\n'); + printf("err=%d bits\n", K); +#endif + + l = mpfr_can_round(s, q-K, GMP_RNDU, rnd_mode, precy); + if (l==0) { +#ifdef DEBUG + printf("not enough precision, use %d\n", q+BITS_PER_MP_LIMB); + printf("q=%d q-K=%d precy=%d\n",q,q-K,precy); +#endif + q += BITS_PER_MP_LIMB; + mpfr_set_prec(r, q); mpfr_set_prec(s, q); mpfr_set_prec(t, q); + } + } while (l==0); + + mpfr_set(y, s, rnd_mode); + + mpfr_clear(r); mpfr_clear(s); mpfr_clear(t); + return 1; +} + diff --git a/mpfr/get_str.c b/mpfr/get_str.c new file mode 100644 index 000000000..e100b300e --- /dev/null +++ b/mpfr/get_str.c @@ -0,0 +1,207 @@ +/* mpfr_get_str -- output a floating-point number to a string + +Copyright (C) 1999 PolKA project, Inria Lorraine and Loria + +This file is part of the MPFR Library. + +The MPFR Library is free software; you can redistribute it and/or modify +it under the terms of the GNU Library General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at your +option) any later version. + +The MPFR Library 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 Library General Public +License for more details. + +You should have received a copy of the GNU Library General Public License +along with the MPFR Library; see the file COPYING.LIB. If not, write to +the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, +MA 02111-1307, USA. */ + +#include <math.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include "gmp.h" +#include "gmp-impl.h" +#include "longlong.h" +#include "mpfr.h" + +/* + Convert op to a string in base 'base' with 'n' digits and writes the + mantissa in 'str', the exponent in 'expptr'. + The result is rounded wrt 'rnd_mode'. + + For op = 3.1416 we get str = "31416" and expptr=1. + */ +#if __STDC__ +char *mpfr_get_str(char *str, mp_exp_t *expptr, int base, size_t n, + mpfr_srcptr op, unsigned char rnd_mode) +#else +char *mpfr_get_str(str, expptr, base, n, op, rnd_mode) + char *str; + mp_exp_t *expptr; + int base; + size_t n; + mpfr_srcptr op; + unsigned char rnd_mode; +#endif +{ + double d; long e, q, div, p, err, prec, sh; mpfr_t a, b; mpz_t bz; + char *str0; unsigned char rnd1; int f, pow2, ok=0, neg; + + if (base<2 || 36<base) { + fprintf(stderr, "Error: too small or too large base in mpfr_get_str: %d\n", + base); + exit(1); + } + + neg = (SIGN(op)<0) ? 1 : 0; + + if (!NOTZERO(op)) { + if (str==NULL) str0=str=(*_mp_allocate_func)(neg + n + 2); + if (SIGN(op)<0) *str++ = '-'; + for (f=0;f<n;f++) *str++ = '0'; + *expptr = 1; + return str0; + } + + count_leading_zeros(pow2, (mp_limb_t)base); + pow2 = BITS_PER_MP_LIMB - pow2 - 1; + if (base != (1<<pow2)) pow2=0; + /* if pow2 <> 0, then base = 2^pow2 */ + + /* first determines the exponent */ + e = EXP(op); + d = fabs(mpfr_get_d2(op, 0)); + /* the absolute value of op is between 1/2*2^e and 2^e */ + /* the output exponent f is such that base^(f-1) <= |op| < base^f + i.e. f = 1 + floor(log(|op|)/log(base)) + = 1 + floor((log(|m|)+e*log(2))/log(base)) */ + f = 1 + (int) floor((log(d)+(double)e*log(2.0))/log((double)base)); + if (n==0) { + /* performs exact rounding, i.e. returns y such that for rnd_mode=RNDN + for example, we have: + y*base^(f-n) <= x*2^(e-p) < (x+1)*2^(e-p) <= (y+1)*base^(f-n) + which implies 2^(EXP(op)-PREC(op)) <= base^(f-n) + */ + n = f + (int) ceil(((double)PREC(op)-e)*log(2.0)/log((double)base)); + } + /* now the first n digits of the mantissa are obtained from + rnd(op*base^(n-f)) */ + prec = (long) ceil((double)n*log((double)base)/log(2.0)); + err = 5; + q = prec+err; + /* one has to use at least q bits */ + q = (((q-1)/BITS_PER_MP_LIMB)+1)*BITS_PER_MP_LIMB; + mpfr_init2(a,q); mpfr_init2(b,q); + + do { + p = n-f; if ((div=(p<0))) p=-p; + rnd1 = rnd_mode; + if (div) { + /* if div we divide by base^p so we have to invert the rounding mode */ + switch (rnd1) { + case GMP_RNDN: rnd1=GMP_RNDN; break; + case GMP_RNDZ: rnd1=GMP_RNDU; break; + case GMP_RNDU: rnd1=GMP_RNDZ; break; + case GMP_RNDD: rnd1=GMP_RNDZ; break; + } + } + + if (pow2) { + if (div) mpfr_div_2exp(b, op, pow2*p, rnd_mode); + else mpfr_mul_2exp(b, op, pow2*p, rnd_mode); + } + else { + /* compute base^p with q bits and rounding towards zero */ + mpfr_set_prec(b, q); + if (p==0) { mpfr_set(b, op, rnd_mode); mpfr_set_ui(a, 1, rnd_mode); } + else { + mpfr_set_prec(a, q); + mpfr_ui_pow_ui(a, base, p, rnd1); + if (div) { + mpfr_set_ui(b, 1, rnd_mode); + mpfr_div(a, b, a, rnd_mode); + } + /* now a is an approximation by default of 1/base^(f-n) */ + mpfr_mul(b, op, a, rnd_mode); + } + } + if (neg) CHANGE_SIGN(b); /* put b positive */ + + if (q>2*prec+BITS_PER_MP_LIMB) { + /* happens when just in the middle between two digits */ + n--; q-=BITS_PER_MP_LIMB; + if (n==0) { + fprintf(stderr, "cannot determine leading digit\n"); exit(1); + } + } + ok = pow2 || mpfr_can_round(b, q-err, rnd_mode, rnd_mode, prec); + + if (ok) { + if (pow2) { + sh = e-PREC(op) + pow2*(n-f); /* error at most 2^e */ + ok = mpfr_can_round(b, EXP(b)-sh-1, rnd_mode, rnd_mode, n*pow2); + } + else { + /* check that value is the same at distance 2^(e-PREC(op))/base^(f-n) + in opposite from rounding direction */ + if (e>=PREC(op)) mpfr_mul_2exp(a, a, e-PREC(op), rnd_mode); + else mpfr_div_2exp(a, a, PREC(op)-e, rnd_mode); + if (rnd_mode==GMP_RNDN) { + mpfr_div_2exp(a, a, 2, rnd_mode); + mpfr_sub(b, b, a, rnd_mode); /* b - a/2 */ + mpfr_mul_2exp(a, a, 2, rnd_mode); + mpfr_add(a, b, a, rnd_mode); /* b + a/2 */ + } + else if ((rnd_mode==GMP_RNDU && neg==0) || (rnd_mode==GMP_RNDD && neg)) + mpfr_sub(a, b, a, rnd_mode); + else mpfr_add(a, b, a, rnd_mode); + /* check that a and b are rounded similarly */ + prec=EXP(b); + if (EXP(a) != prec) ok=0; + else { + mpfr_round(b, rnd_mode, prec); + mpfr_round(a, rnd_mode, prec); + if (mpfr_cmp(a, b)) ok=0; + } + } + if (ok==0) { /* n is too large */ + n--; + if (n==0) { + fprintf(stderr, "cannot determine leading digit\n"); exit(1); + } + q -= BITS_PER_MP_LIMB; + } + } + } while (ok==0 && (q+=BITS_PER_MP_LIMB) ); + if (neg) + switch (rnd_mode) { + case GMP_RNDU: rnd_mode=GMP_RNDZ; break; + case GMP_RNDD: rnd_mode=GMP_RNDU; break; + } + + prec=EXP(b); /* may have changed due to rounding */ + + /* now the mantissa is the integer part of b */ + mpz_init(bz); q=1+(prec-1)/BITS_PER_MP_LIMB; + _mpz_realloc(bz, q); + sh = prec%BITS_PER_MP_LIMB; + e = 1 + (PREC(b)-1)/BITS_PER_MP_LIMB-q; + if (sh) mpn_rshift(PTR(bz), MANT(b)+e, q, BITS_PER_MP_LIMB-sh); + else MPN_COPY(PTR(bz), MANT(b)+e, q); + bz->_mp_size=q; + + /* computes the number of characters needed */ + q = neg + n + 2; /* n+1 may not be enough for 100000... */ + if (str==NULL) str0=str=(*_mp_allocate_func)(q); + if (neg) *str++='-'; + mpz_get_str(str, base, bz); /* n digits of mantissa */ + if (strlen(str)==n+1) f++; /* possible due to rounding */ + *expptr = f; + mpfr_clear(a); mpfr_clear(b); mpz_clear(bz); + return str0; +} + diff --git a/mpfr/init.c b/mpfr/init.c new file mode 100644 index 000000000..e416511c7 --- /dev/null +++ b/mpfr/init.c @@ -0,0 +1,49 @@ +/* mpfr_init -- initialize a floating-point number + +Copyright (C) 1999 PolKA project, Inria Lorraine and Loria + +This file is part of the MPFR Library. + +The MPFR Library is free software; you can redistribute it and/or modify +it under the terms of the GNU Library General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at your +option) any later version. + +The MPFR Library 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 Library General Public +License for more details. + +You should have received a copy of the GNU Library General Public License +along with the MPFR Library; see the file COPYING.LIB. If not, write to +the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, +MA 02111-1307, USA. */ + +#include <stdio.h> +#include "gmp.h" +#include "gmp-impl.h" +#include "mpfr.h" + +void +#if __STDC__ +mpfr_init2 (mpfr_t x, unsigned long int p) +#else +mpfr_init2 (x, p) + mpfr_t x; + unsigned long int p; +#endif +{ + unsigned long xsize; + + if (p==0) { + printf("*** cannot initialize mpfr with precision 0\n"); exit(1); + } + + xsize = (p - 1)/BITS_PER_MP_LIMB + 1; + + x -> _mp_prec = p; + x -> _mp_d = (mp_ptr) (*_mp_allocate_func) + (xsize * BYTES_PER_MP_LIMB); + x -> _mp_size = xsize; + x -> _mp_exp = 0; /* avoids uninitialized memory reads for zero */ +} diff --git a/mpfr/karadiv.c b/mpfr/karadiv.c new file mode 100644 index 000000000..94db05353 --- /dev/null +++ b/mpfr/karadiv.c @@ -0,0 +1,137 @@ +/* mpn_divrem_n -- Karatsuba division in 2*K(n) limb operations + +Copyright (C) 1999-2000 PolKA project, Inria Lorraine and Loria + +This file is part of the MPFR Library. + +The MPFR Library is free software; you can redistribute it and/or modify +it under the terms of the GNU Library General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at your +option) any later version. + +The MPFR Library 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 Library General Public +License for more details. + +You should have received a copy of the GNU Library General Public License +along with the MPFR Library; see the file COPYING.LIB. If not, write to +the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, +MA 02111-1307, USA. */ + +/* +[1] Fast Recursive Division, by Christoph Burnikel and Joachim Ziegler, + Technical report MPI-I-98-1-022, october 1998, + cf http://www.mpi-sb.mpg.de/~ziegler/TechRep.ps.gz. + Implemented by Paul Zimmermann, 1999. +*/ + +#include "gmp.h" +#include "gmp-impl.h" +#include "mpfr.h" + +extern void mpn_divrem_n2 (mp_limb_t *, mp_limb_t *, mp_limb_t *, mp_size_t, mp_limb_t *); +extern void mpn_divrem_3by2 (mp_limb_t *, mp_limb_t *, mp_limb_t *, mp_size_t, mp_limb_t *); + +/* mpn_divrem_n(n) calls 2*mul(n/2)+2*div(n/2), thus to be faster then + div(n)=4*div(n/2), we need mul(n/2) to be faster than the classic way, + i.e. n/2 >= KARATSUBA_MUL_THRESHOLD */ + +#define DIV_LIMIT (7*KARATSUBA_MUL_THRESHOLD) + +static void mpn_decr(mp_limb_t *Q) +{ + while ((*Q++)-- == 0); +} + +/* implements algorithm of page 8 in [1]: divides (A,2n) by (B,n) and puts the + quotient in (Q,n), the remainder in (A,n). + Returns most significant limb of the quotient, which is 0 or 1. +*/ +mp_limb_t +mpn_divrem_n(mp_limb_t *Q, mp_limb_t *A, mp_limb_t *B, mp_size_t n) +{ + if (n<DIV_LIMIT) return mpn_divrem(Q, 0, A, 2*n, B, n); + else { + mp_limb_t cc=0; + if (mpn_cmp(A+n, B, n)>=0) { + cc=1; + mpn_sub_n(A+n, A+n, B, n); + } + if (n%2) { + /* divide (2n-2) most significant limbs from A by those (n-1) from B */ + mpn_divrem_n(Q+1, A+2, B+1, n-1); + /* now (Q+1, n-1) contains the quotient of (A+2,2n-2) by (B+1,n-1) + and (A+2, n-1) contains the remainder */ + if (mpn_sub_1(A+n, A+n, 1, mpn_submul_1(A+1, Q+1, n-1, B[0]))) { + /* quotient two large */ + mpn_decr(Q+1); + if (mpn_add_n(A+1, A+1, B, n)==0) { + mpn_decr(Q+1); mpn_add_n(A+1, A+1, B, n); + } + } + /* now divide (A,n+1) by (B,n) */ + mpn_divrem(Q, 0, A, n+1, B, n); + } + else { + mp_limb_t *tmp; int n2=n/2; + TMP_DECL (marker); + + TMP_MARK (marker); + tmp = (mp_limb_t*) TMP_ALLOC(n*sizeof(mp_limb_t)); + mpn_divrem_3by2(Q+n2, A+n2, B, n2, tmp); + mpn_divrem_3by2(Q, A, B, n2, tmp); + TMP_FREE (marker); + } + return cc; + } +} + +/* inner procedure, with no memory allocation + assumes mpn_cmp(A+n, B, n) < 0 +*/ +void mpn_divrem_n2(mp_limb_t *Q, mp_limb_t *A, mp_limb_t *B, mp_size_t n, + mp_limb_t *tmp) +{ + if (n%2) { + /* divide (2n-2) most significant limbs from A by those (n-1) from B */ + mpn_divrem_n2(Q+1, A+2, B+1, n-1, tmp); + /* now (Q+1, n-1) contains the quotient of (A+2,2n-2) by (B+1,n-1) + and (A+2, n-1) contains the remainder */ + if (mpn_sub_1(A+n, A+n, 1, mpn_submul_1(A+1, Q+1, n-1, B[0]))) { + /* quotient two large */ + mpn_decr(Q+1); + if (mpn_add_n(A+1, A+1, B, n)==0) { /* still too large */ + mpn_decr(Q+1); mpn_add_n(A+1, A+1, B, n); + } + } + /* now divide (A,n+1) by (B,n) */ + mpn_divrem(Q, 0, A, n+1, B, n); + } + else { + int n2=n/2; + mpn_divrem_3by2(Q+n2, A+n2, B, n2, tmp); + mpn_divrem_3by2(Q, A, B, n2, tmp); + } +} + +/* divides (A,3n) by (B,2n) and puts the quotient in (Q,n), + the remainder in (A,2n) */ +void +mpn_divrem_3by2(mp_limb_t *Q, mp_limb_t *A, mp_limb_t *B, + mp_size_t n, mp_limb_t *tmp) +{ + int twon = n+n; + + if (n<DIV_LIMIT) mpn_divrem(Q, 0, A+n, twon, B+n, n); + else mpn_divrem_n2(Q, A+n, B+n, n, tmp); + /* q=(Q,n), c=(A+n,n) with the notations of [1] */ + mpn_mul_n(tmp, Q, B, n); + if (mpn_sub_n(A, A, tmp, twon)) /* R=(A,2n) */ { + mpn_decr(Q); + if (mpn_add_n(A, A, B, twon)==0) { /* Q still too large */ + mpn_decr(Q); mpn_add_n(A, A, B, twon); + } + } + return; +} diff --git a/mpfr/karasqrt.c b/mpfr/karasqrt.c new file mode 100644 index 000000000..74a4bf805 --- /dev/null +++ b/mpfr/karasqrt.c @@ -0,0 +1,102 @@ +/* kara_sqrtrem -- Karatsuba square root + +Copyright (C) 1999-2000 PolKA project, Inria Lorraine and Loria + +This file is part of the MPFR Library. + +The MPFR Library is free software; you can redistribute it and/or modify +it under the terms of the GNU Library General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at your +option) any later version. + +The MPFR Library 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 Library General Public +License for more details. + +You should have received a copy of the GNU Library General Public License +along with the MPFR Library; see the file COPYING.LIB. If not, write to +the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, +MA 02111-1307, USA. */ + +/* Reference: Karatsuba Square Root, Paul Zimmermann, Research Report 3805, + INRIA, November 1999. */ + +#include "gmp.h" +#include "gmp-impl.h" +#include "mpfr.h" + +#define SQRT_LIMIT KARATSUBA_MUL_THRESHOLD /* must be at least 3, should be + near from optimal */ + +/* n must be even */ +mp_size_t kara_sqrtrem(mp_limb_t *s, mp_limb_t *r, mp_limb_t *op, mp_size_t n) +{ + if (n<SQRT_LIMIT) return mpn_sqrtrem(s, r, op, n); + else { + mp_size_t nn, rn, rrn, sn, qn; mp_limb_t *q, tmp; + TMP_DECL (marker); + + TMP_MARK (marker); + nn = n/4; /* block size 'b' corresponds to nn limbs */ + rn = kara_sqrtrem(s+nn, r+nn, op+2*nn, n-2*nn); + /* rn <= ceil(n-2*nn, 2) + 1 <= ceil(2*nn+3, 2) + 1 <= nn+3 */ + /* to divide by 2*s', first divide by 2, to ensure the dividend is + less than b^2 */ + sn=(n-2*nn+1)/2; /* sn >= nn */ + MPN_COPY(r, op+nn, nn); /* copy a_1 */ + tmp = mpn_rshift(r, r, nn+rn, 1); + if (r[nn+rn-1]==0) rn--; + q = (mp_limb_t*) TMP_ALLOC(2*(sn+1)*sizeof(mp_limb_t)); + if (nn+rn < 2*sn) MPN_ZERO(r+nn+rn, 2*sn-nn-rn); + qn = sn; if (mpn_cmp(r+sn, s+nn, sn)>=0) { + q[qn++]=1; mpn_sub_n(r+sn, r+sn, s+nn, sn); + } +#if 0 + mpn_divrem(q, 0, r, 2*sn, s+nn, sn); +#else + mpn_divrem_n(q, r, s+nn, sn); +#endif + while (qn>nn && q[qn-1]==0) qn--; + MPN_COPY(s, q, nn); + if (nn+rn > 2*sn) { + tmp=mpn_add_n(s+sn, s+sn, q+sn, nn+rn-2*sn); + if (tmp) mpn_add_1(s+nn+rn-sn, s+nn+rn-sn, (n+1)/2-nn-rn+sn, tmp); + } + /* multiply remainder by two and add low bit of a_1 */ + rrn = nn+sn; /* size of output remainder */ + rrn += mpn_lshift(r+nn, r, sn, 1); + r[nn] |= (op[nn] & 1); + sn += nn; + if (qn>nn) { + MPN_COPY(r, s+nn, qn-nn); /* save the qn-nn limbs from s */ + MPN_COPY(s+nn, q+nn, qn-nn); /* replace by those of q */ + } + mpn_mul_n(q, s, s, qn); + if (qn>nn) { /* restore the limbs from s, adding them to those of q */ + mp_limb_t cy; + + cy = mpn_add_n(s+nn, s+nn, r, qn-nn); + if (qn<sn) cy = mpn_add_1(s+qn, s+qn, sn-qn, cy); + if (cy) s[sn++]=1; + } + MPN_COPY(r, op, nn); /* copy a_0 */ + qn = 2*qn; + if (qn<sn) MPN_ZERO(q+qn, sn-qn); + if (rrn<sn) MPN_ZERO(r+rrn, sn-rrn); + if (mpn_sub_n(r, r, q, sn) || (qn>sn)) { + if (rrn>sn) rrn=sn; + else { + /* one shift and one add is faster than two add's */ + r[sn] = mpn_lshift(q, s, sn, 1) + mpn_add_n(r, r, q, sn) + - mpn_sub_1(r, r, sn, 1) - 1; + rrn = sn + r[sn]; + mpn_sub_1(s, s, sn, 1); + } + } + else if (rrn>sn) r[sn]=1; + TMP_FREE (marker); + MPN_NORMALIZE(r, rrn); + return rrn; + } +} diff --git a/mpfr/log.c b/mpfr/log.c new file mode 100644 index 000000000..ad8e9856d --- /dev/null +++ b/mpfr/log.c @@ -0,0 +1,150 @@ +/* mpfr_log -- natural logarithm of a floating-point number + +Copyright (C) 1999 PolKA project, Inria Lorraine and Loria + +This file is part of the MPFR Library. + +The MPFR Library is free software; you can redistribute it and/or modify +it under the terms of the GNU Library General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at your +option) any later version. + +The MPFR Library 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 Library General Public +License for more details. + +You should have received a copy of the GNU Library General Public License +along with the MPFR Library; see the file COPYING.LIB. If not, write to +the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, +MA 02111-1307, USA. */ + +#include <stdio.h> +#include <math.h> +#include "gmp.h" +#include "gmp-impl.h" +#include "mpfr.h" + + + /* The computation of log(a) is done using the formula : + if we want p bits of the result, + pi + log(a) ~ ------------ - m log 2 + 2 AG(1,4/s) + + where s = x 2^m > 2^(p/2) + + More precisely, if F(x) = int(1/sqrt(1-(1-x^2)*sin(t)^2), t=0..PI/2), + then for s>=1.26 we have log(s) < F(4/s) < log(s)*(1+4/s^2) + from which we deduce pi/2/AG(1,4/s)*(1-4/s^2) < log(s) < pi/2/AG(1,4/s) + so the relative error 4/s^2 is < 4/2^p i.e. 4 ulps. + */ + + +#define MON_INIT(xp, x, p, s) xp = (mp_ptr) TMP_ALLOC(s*BYTES_PER_MP_LIMB); x -> _mp_prec = p; x -> _mp_d = xp; x -> _mp_size = s; x -> _mp_exp = 0; + +/* #define DEBUG */ + +int +#if __STDC__ +mpfr_log(mpfr_ptr r, mpfr_srcptr a, unsigned char rnd_mode) +#else +mpfr_log() + mpfr_ptr r; + mpfr_srcptr a; + unsigned char rnd_mode; +#endif +{ + int p, m, q, bool, size, cancel; + mpfr_t cst, rapport, agm, tmp1, tmp2, s, mm; + mp_limb_t *cstp, *rapportp, *agmp, *tmp1p, *tmp2p, *sp, *mmp; + double ref; + TMP_DECL(marker); + + /* If a is NaN or a is negative or null, the result is NaN */ + if (FLAG_NAN(a) || (SIGN(a)<=0)) + { SET_NAN(r); return 1; } + + /* If a is 1, the result is 0 */ + if (mpfr_cmp_ui_2exp(a,1,0)==0){ + SET_ZERO(r); + return 0; /* only case where the result is exact */ + } + + q=PREC(r); + + ref=mpfr_get_d(a)-1.0; + if (ref<0) + ref=-ref; + + p=q+4; + /* adjust to entire limb */ + if (p%BITS_PER_MP_LIMB) p += BITS_PER_MP_LIMB - (p%BITS_PER_MP_LIMB); + + bool=1; + + while (bool==1) { +#ifdef DEBUG + printf("a="); mpfr_print_raw(a); putchar('\n'); + printf("p=%d\n", p); +#endif + /* Calculus of m (depends on p) */ + m=(int) ceil(((double) p)/2.0) -EXP(a)+1; + + /* All the mpfr_t needed have a precision of p */ + TMP_MARK(marker); + size=(p-1)/BITS_PER_MP_LIMB+1; + MON_INIT(cstp, cst, p, size); + MON_INIT(rapportp, rapport, p, size); + MON_INIT(agmp, agm, p, size); + MON_INIT(tmp1p, tmp1, p, size); + MON_INIT(tmp2p, tmp2, p, size); + MON_INIT(sp, s, p, size); + MON_INIT(mmp, mm, p, size); + + mpfr_set_si(mm,m,GMP_RNDN); /* I have m, supposed exact */ + mpfr_set_si(tmp1,1,GMP_RNDN); /* I have 1, exact */ + mpfr_set_si(tmp2,4,GMP_RNDN); /* I have 4, exact */ + mpfr_mul_2exp(s,a,m,GMP_RNDN); /* I compute s=a*2^m, err <= 1 ulp */ + mpfr_div(rapport,tmp2,s,GMP_RNDN); /* I compute 4/s, err <= 2 ulps */ + mpfr_agm(agm,tmp1,rapport,GMP_RNDN); /* AG(1,4/s), err<=3 ulps */ + mpfr_mul_2exp(tmp1,agm,1,GMP_RNDN); /* 2*AG(1,4/s), still err<=3 ulps */ + mpfr_pi(cst, GMP_RNDN); /* I compute pi, err<=1ulp */ + mpfr_div(tmp2,cst,tmp1,GMP_RNDN); /* pi/2*AG(1,4/s), err<=5ulps */ + mpfr_log2(cst,GMP_RNDN); /* I compute log(2), err<=1ulp */ + mpfr_mul(tmp1,cst,mm,GMP_RNDN); /* I compute m*log(2), err<=2ulps */ + cancel = EXP(tmp2); + mpfr_sub(cst,tmp2,tmp1,GMP_RNDN); /* log(a), err<=7ulps+cancel */ + cancel -= EXP(cst); +#ifdef DEBUG + printf("cancelled bits=%d\n", cancel); + printf("approx="); mpfr_print_raw(cst); putchar('\n'); +#endif + if (cancel<0) cancel=0; + + /* If we can round the result, we set it and go out of the loop */ + + /* we have 7 ulps of error from the above roundings, + 4 ulps from the 4/s^2 second order term, + plus the cancelled bits */ + if (mpfr_can_round(cst,p-cancel-4,GMP_RNDN,rnd_mode,q)==1) { + mpfr_set(r,cst,rnd_mode); +#ifdef DEBUG + printf("result="); mpfr_print_raw(r); putchar('\n'); +#endif + bool=0; + } + /* else we increase the precision */ + else { + p += BITS_PER_MP_LIMB+cancel; + TMP_FREE(marker); + } + + /* We clean */ + TMP_FREE(marker); + + } + return 1; /* result is inexact */ +} + + diff --git a/mpfr/log2.c b/mpfr/log2.c new file mode 100644 index 000000000..151e0e8cb --- /dev/null +++ b/mpfr/log2.c @@ -0,0 +1,102 @@ +/* mpfr_log2 -- compute natural logarithm of 2 + +Copyright (C) 1999 PolKA project, Inria Lorraine and Loria + +This file is part of the MPFR Library. + +The MPFR Library is free software; you can redistribute it and/or modify +it under the terms of the GNU Library General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at your +option) any later version. + +The MPFR Library 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 Library General Public +License for more details. + +You should have received a copy of the GNU Library General Public License +along with the MPFR Library; see the file COPYING.LIB. If not, write to +the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, +MA 02111-1307, USA. */ + +#include <stdio.h> +#include <math.h> +#include "gmp.h" +#include "gmp-impl.h" +#include "longlong.h" +#include "mpfr.h" + +mpfr_t __mpfr_log2; /* stored value of log(2) with rnd_mode=GMP_RNDZ */ +int __mpfr_log2_prec=0; /* precision of stored value */ + +/* set x to log(2) rounded to precision PREC(x) with direction rnd_mode + + use formula log(2) = sum(1/k/2^k, k=1..infinity) + + whence 2^N*log(2) = S(N) + R(N) + + where S(N) = sum(2^(N-k)/k, k=1..N-1) + and R(N) = sum(1/k/2^(k-N), k=N..infinity) < 2/N + + Let S'(N) = sum(floor(2^(N-k)/k), k=1..N-1) + + Then 2^N*log(2)-S'(N) <= N-1+2/N <= N for N>=2. +*/ +void +#if __STDC__ +mpfr_log2(mpfr_ptr x, unsigned char rnd_mode) +#else +mpfr_log2(x, rnd_mode) mpfr_ptr x; unsigned char rnd_mode; +#endif +{ + int N, oldN, k, precx; mpz_t s, t, u; + + precx = PREC(x); + + /* has stored value enough precision ? */ + if (precx <= __mpfr_log2_prec) { + if (rnd_mode==GMP_RNDZ || rnd_mode==GMP_RNDD || + mpfr_can_round(__mpfr_log2, __mpfr_log2_prec, GMP_RNDZ, rnd_mode, precx)) + { + mpfr_set(x, __mpfr_log2, rnd_mode); return; + } + } + + /* need to recompute */ + N=2; + do { + oldN = N; + N = precx + (int)ceil(log((double)N)/log(2.0)); + } while (N != oldN); + mpz_init_set_ui(s,0); + mpz_init(u); + mpz_init_set_ui(t,1); +#if 0 + /* use log(2) = sum(1/k/2^k, k=1..infinity) */ + mpz_mul_2exp(t, t, N); + for (k=1;k<N;k++) { + mpz_div_2exp(t, t, 1); + mpz_fdiv_q_ui(u, t, k); + mpz_add(s, s, u); + } +#else + /* use log(2) = sum((6*k-1)/(2*k^2-k)/2^(2*k+1), k=1..infinity) */ + mpz_mul_2exp(t, t, N-1); + for (k=1;k<N/2;k++) { + mpz_div_2exp(t, t, 2); + mpz_mul_ui(u, t, 6*k-1); + mpz_fdiv_q_ui(u, u, k*(2*k-1)); + mpz_add(s, s, u); + } +#endif + mpfr_set_z(x, s, rnd_mode); + EXP(x) -= N; + + /* stored computed value */ + if (__mpfr_log2_prec==0) mpfr_init2(__mpfr_log2, precx); + else mpfr_set_prec(__mpfr_log2, precx); + mpfr_set(__mpfr_log2, x, GMP_RNDZ); + __mpfr_log2_prec=precx; + + mpz_clear(s); mpz_clear(t); mpz_clear(u); +} diff --git a/mpfr/mpfr-impl.h b/mpfr/mpfr-impl.h new file mode 100644 index 000000000..3464febb1 --- /dev/null +++ b/mpfr/mpfr-impl.h @@ -0,0 +1,58 @@ +/* Utilities for MPFR developers, not exported. + +Copyright (C) 1999 PolKA project, Inria Lorraine and Loria + +This file is part of the MPFR Library. + +The MPFR Library is free software; you can redistribute it and/or modify +it under the terms of the GNU Library General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at your +option) any later version. + +The MPFR Library 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 Library General Public +License for more details. + +You should have received a copy of the GNU Library General Public License +along with the MPFR Library; see the file COPYING.LIB. If not, write to +the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, +MA 02111-1307, USA. */ + +#include <math.h> + +/* generate a random double using the whole range of possible values, + including denormalized numbers, NaN, infinities, ... */ +double drand() +{ + volatile double d; int *i; + + i = (int*) &d; + i[0] = mrand48(); + i[1] = mrand48(); + return d; +} + +/* returns the number of ulp's between a and b */ +int ulp(a,b) double a,b; +{ + double eps=1.1102230246251565404e-16; /* 2^(-53) */ + if (a==0.0) { + if (b==0.0) return 0; + else if (b<0.0) return 2147483647; + else return -2147483647; + } + b = (a-b)/a; + if (b>0) + return (int) floor(b/eps); + else + return (int) ceil(b/eps); +} + +/* return double m*2^e */ +double dbl(m,e) double m; int e; +{ + if (e>=0) while (e-->0) m *= 2.0; + else while (e++<0) m /= 2.0; + return m; +} diff --git a/mpfr/mpfr.h b/mpfr/mpfr.h new file mode 100644 index 000000000..9f25eba2f --- /dev/null +++ b/mpfr/mpfr.h @@ -0,0 +1,204 @@ +/* mpfr.h -- Include file for mpfr. + +Copyright (C) 1999 PolKA project, Inria Lorraine and Loria + +This file is part of the MPFR Library. + +The MPFR Library is free software; you can redistribute it and/or modify +it under the terms of the GNU Library General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at your +option) any later version. + +The MPFR Library 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 Library General Public +License for more details. + +You should have received a copy of the GNU Library General Public License +along with the MPFR Library; see the file COPYING.LIB. If not, write to +the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, +MA 02111-1307, USA. */ + +#include <stdio.h> + +/* Cygnus does not know about *rand48 functions */ +#ifdef __CYGWIN32__ +#define mrand48 rand +#define drand48 rand +#define lrand48 rand +#define srand48 srand +#endif + +/* Definition of rounding modes */ + +#define GMP_RNDN 0 +#define GMP_RNDZ 1 +#define GMP_RNDU 2 +#define GMP_RNDD 3 + +/* Definitions of types and their semantics */ + +typedef struct { + unsigned long int _mp_prec; /* WARNING : for the mpfr type, the precision */ + /* should be understood as the number of BITS,*/ + /* not the number of mp_limb_t's. This means */ + /* that the corresponding number of allocated + limbs is >= ceil(_mp_prec/BITS_PER_MP_LIMB) */ + mp_size_t _mp_size; /* abs(_mp_size) is the number of allocated + limbs the field _mp_d points to. + The sign is that of _mp_size. + The number 0 is such that _mp_d[k-1]=0 + where k = ceil(_mp_prec/BITS_PER_MP_LIMB) */ + mp_exp_t _mp_exp; + mp_limb_t *_mp_d; +} +__mpfr_struct; + +/* + The number represented is + + sign(_mp_size)*(_mp_d[k-1]/B+_mp_d[k-2]/B^2+...+_mp_d[0]/B^k)*2^_mp_exp + + where k=ceil(_mp_prec/BITS_PER_MP_LIMB) and B=2^BITS_PER_MP_LIMB. + + For the msb (most significant bit) normalized representation, we must have + _mp_d[k-1]>=B/2, unless the number is zero (in that case its sign is still + given by sign(_mp_size)). + + We must also have the last k*BITS_PER_MP_LIMB-_mp_prec bits set to zero. +*/ + +typedef __mpfr_struct mpfr_t[1]; +typedef __mpfr_struct *mpfr_ptr; +typedef __gmp_const __mpfr_struct *mpfr_srcptr; + + +/* Prototypes */ + +#ifndef _PROTO +#if defined (__STDC__) || defined (__cplusplus) +#define _PROTO(x) x +#else +#define _PROTO(x) () +#endif +#endif + +/* bit 31 of _mp_size is used for sign, + bit 30 of _mp_size is used for Nan flag, + remaining bits are used to store the number of allocated limbs */ +#define FLAG_NAN(x) (((x)->_mp_size >> 30)&1) +#define SET_NAN(x) ((x)->_mp_size |= (1<<30)) +#define ABSSIZE(x) ((x)->_mp_size & ((1<<30)-1)) +#define SIZE(x) ((x)->_mp_size) +#define EXP(x) ((x)->_mp_exp) +#define MANT(x) ((x)->_mp_d) +#define SIGN(x) (((x)->_mp_size >> 31) ? -1 : 1) +#define ISNONNEG(x) (SIGN(x)>=0) +#define ISNEG(x) (SIGN(x)==-1) +#define CHANGE_SIGN(x) (SIZE(x) = SIZE(x) ^ (1<<31)) +#define PREC(x) ((x)->_mp_prec) +#define NOTZERO(x) (MANT(x)[(PREC(x)-1)/BITS_PER_MP_LIMB]) +#define SET_ZERO(x) (MANT(x)[(PREC(x)-1)/BITS_PER_MP_LIMB] = 0) + +/* reallocates the mantissa of x to q bits and sets the precision to q */ +#define _mpfr_realloc(x, q) { \ + (x)->_mp_d = (mp_ptr) (*_mp_reallocate_func) \ + ((x)->_mp_d, (x)->_mp_prec>>3 + 1, (q)>>3 + 1); \ + (x)->_mp_prec = q; } + +void mpfr_init2 _PROTO ((mpfr_ptr, unsigned long int)); +int mpfr_round_raw _PROTO ((mp_limb_t *, mp_limb_t *, unsigned long, char, + unsigned long, char)); +int mpfr_round_raw2 _PROTO ((mp_limb_t *, unsigned long, char, char, + unsigned long)); +void mpfr_round _PROTO ((mpfr_ptr, char, unsigned long)); +int mpfr_can_round _PROTO ((mpfr_ptr, unsigned long, unsigned char, + unsigned char, unsigned long)); +int mpfr_can_round_raw _PROTO ((mp_limb_t *, unsigned long, int, + unsigned long, + unsigned char, unsigned char, unsigned long)); +void mpfr_set_d _PROTO ((mpfr_ptr, double, unsigned char)); +int mpfr_set_z _PROTO ((mpfr_ptr, mpz_srcptr, unsigned char)); +double mpfr_get_d _PROTO ((mpfr_srcptr)); +double mpfr_get_d2 _PROTO ((mpfr_srcptr, long)); +void mpfr_set_f _PROTO ((mpfr_ptr, mpf_srcptr, char)); +void mpfr_set_si _PROTO ((mpfr_ptr, long, unsigned char)); +void mpfr_set_ui _PROTO ((mpfr_ptr, unsigned long, unsigned char)); +void mpfr_print_raw _PROTO ((mpfr_srcptr)); +void mpfr_random _PROTO ((mpfr_ptr)); +void mpfr_clear _PROTO ((mpfr_ptr)); +void mpfr_set_str_raw _PROTO ((mpfr_ptr, char *)); +void mpfr_get_str_raw _PROTO ((char *, mpfr_srcptr)); +char* mpfr_get_str _PROTO ((char *, mp_exp_t *, int, size_t, mpfr_srcptr, unsigned char)); +size_t mpfr_out_str _PROTO ((FILE *, int, size_t, mpfr_srcptr, unsigned char)); +void mpfr_mul _PROTO ((mpfr_ptr, mpfr_srcptr, mpfr_srcptr, unsigned char)); +void mpfr_pow_ui _PROTO ((mpfr_ptr, mpfr_srcptr, unsigned int, unsigned char)); +void mpfr_ui_pow_ui _PROTO ((mpfr_ptr, unsigned int, unsigned int, unsigned char)); +mp_limb_t mpn_divrem_n _PROTO ((mp_limb_t *, mp_limb_t *, mp_limb_t *, mp_size_t)); +mp_size_t kara_sqrtrem _PROTO ((mp_limb_t *, mp_limb_t *, mp_limb_t *, mp_size_t)); +void mpfr_div _PROTO ((mpfr_ptr, mpfr_srcptr, mpfr_srcptr, unsigned char)); +void mpfr_agm _PROTO ((mpfr_ptr, mpfr_srcptr, mpfr_srcptr, unsigned char)); +int mpfr_sqrt _PROTO ((mpfr_ptr, mpfr_srcptr, unsigned char)); +void mpfr_add _PROTO ((mpfr_ptr, mpfr_srcptr, mpfr_srcptr, unsigned char)); +int mpfr_add_one_ulp _PROTO ((mpfr_ptr)); +void mpfr_sub _PROTO ((mpfr_ptr, mpfr_srcptr, mpfr_srcptr, unsigned char)); +void mpfr_set4 _PROTO ((mpfr_ptr, mpfr_srcptr, unsigned char, int)); +void mpfr_pi _PROTO ((mpfr_ptr, unsigned char)); +void mpfr_log2 _PROTO ((mpfr_ptr, unsigned char)); +int mpfr_log _PROTO ((mpfr_ptr, mpfr_srcptr, unsigned char)); +int mpfr_exp _PROTO ((mpfr_ptr, mpfr_srcptr, unsigned char)); +int mpfr_zeta _PROTO ((mpfr_ptr, mpfr_srcptr, unsigned char)); +void mpfr_mul_ui _PROTO((mpfr_ptr, mpfr_srcptr, unsigned long, unsigned char)); +void mpfr_set_machine_rnd_mode _PROTO ((unsigned char)); +int mpfr_cmp3 _PROTO ((mpfr_srcptr, mpfr_srcptr, long int)); +int mpfr_cmp_ui_2exp _PROTO ((mpfr_srcptr, unsigned long int, int)); +int mpfr_cmp_si_2exp _PROTO ((mpfr_srcptr, long int, int)); +int mpfr_cmp2 _PROTO ((mpfr_srcptr, mpfr_srcptr)); +void mpfr_mul_2exp _PROTO((mpfr_ptr, mpfr_srcptr, unsigned long int,unsigned char)); +void mpfr_div_2exp _PROTO((mpfr_ptr, mpfr_srcptr, unsigned long int,unsigned char)); +void mpfr_set_prec _PROTO((mpfr_ptr, unsigned long int)); +void mpfr_set_default_prec _PROTO((unsigned long int)); +extern mp_size_t __gmp_default_fp_bit_precision; +extern char __gmp_default_rounding_mode; +char * mpfr_print_rnd_mode _PROTO((unsigned char)); +void mpfr_neg _PROTO((mpfr_ptr, mpfr_srcptr, unsigned char)); +int mpfr_sub_one_ulp _PROTO((mpfr_ptr x)); +int mpfr_div_ui _PROTO((mpfr_ptr y, mpfr_srcptr x, unsigned long u, unsigned char rnd_mode)); +unsigned long int mpfr_get_prec _PROTO((mpfr_t x)); + +#define mpfr_init(x) mpfr_init2(x, __gmp_default_fp_bit_precision) +#define mpfr_cmp_ui(b,i) mpfr_cmp_ui_2exp(b,i,0) +#define mpfr_cmp_si(b,i) mpfr_cmp_si_2exp(b,i,0) +#define mpfr_set(a,b,r) mpfr_set4(a,b,r,SIGN(b)) +#define mpfr_cmp(b,c) mpfr_cmp3(b,c,1) + +#if (BITS_PER_MP_LIMB==32) +#define MPFR_LIMBS_PER_DOUBLE 2 +#elif (BITS_PER_MP_LIMB==64) +#define MPFR_LIMBS_PER_DOUBLE 1 +#endif + +/* gmp-2.0.2 had only one threshold for both multiplication and squaring */ +#ifndef KARATSUBA_MUL_THRESHOLD +#ifdef KARATSUBA_THRESHOLD +#define KARATSUBA_MUL_THRESHOLD KARATSUBA_THRESHOLD +#else +#define KARATSUBA_MUL_THRESHOLD 16 +#endif +#endif + +#define mpfr_init_set_si(x, i, p, rnd) \ + mpfr_init2((x), (p)); mpfr_set_si((x), (i), (rnd)); +#define mpfr_init_set_ui(x, i, p, rnd) \ + mpfr_init2((x), (p)); mpfr_set_ui((x), (i), (rnd)); +#define mpfr_init_set_d(x, d, p, rnd) \ + mpfr_init2((x), (p)); mpfr_set_d((x), (d), (rnd)); +#define mpfr_init_set(x, y, p, rnd) \ + mpfr_init2((x), (p)); mpfr_set((x), (y), (rnd)); +#define mpfr_init_set_f(x, y, p, rnd) \ + mpfr_init2((x), (p)); mpfr_set_f((x), (y), (rnd)); +#define mpfr_init_set_str(x, y, p, rnd) \ + mpfr_init2((x), (p)); mpfr_set_str((x), (y), (rnd)); +#define mpfr_init_set_str_raw(x, y, p, rnd) \ + mpfr_init2((x), (p)); mpfr_set_str_raw((x), (y), (rnd)); + diff --git a/mpfr/mpfr.texi b/mpfr/mpfr.texi new file mode 100644 index 000000000..e74f74a70 --- /dev/null +++ b/mpfr/mpfr.texi @@ -0,0 +1,1075 @@ +\input texinfo @c -*-texinfo-*- +@c %**start of header +@setfilename gmp.info +@settitle MPFR 1.0 +@synindex tp fn +@iftex +@afourpaper +@end iftex +@comment %**end of header + +@ifinfo +@format +START-INFO-DIR-ENTRY +* mpfr: (mpfr.info). Multiple Precision Floating-Point Reliable Library. +END-INFO-DIR-ENTRY +@end format +@end ifinfo + +@c smallbook + +@iftex +@finalout +@end iftex + +@c Note: the edition number is listed in *three* places; please update +@c all three. Also, update the month and year where appropriate. + +@c ==> Update edition number for settitle and subtitle, and in the +@c ==> following paragraph; update date, too. + + +@ifinfo +This file documents MPFR, a library for reliable multiple precision floating-point arithmetic + +Copyright (C) 1999, PolKA team, INRIA Lorraine and LORIA, France + +Permission is granted to make and distribute verbatim copies of +this manual provided the copyright notice and this permission notice +are preserved on all copies. + +@ignore +Permission is granted to process this file through TeX and print the +results, provided the printed document carries copying permission +notice identical to this one except for the removal of this paragraph +(this paragraph not being relevant to the printed manual). + +@end ignore +Permission is granted to copy and distribute modified versions of this +manual under the conditions for verbatim copying, provided that the entire +resulting derived work is distributed under the terms of a permission +notice identical to this one. + +Permission is granted to copy and distribute translations of this manual +into another language, under the above conditions for modified versions, +except that this permission notice may be stated in a translation approved +by the Foundation. +@end ifinfo + +@setchapternewpage on +@titlepage +@c use the new format for titles + +@title MPFR +@subtitle The Multiple Precision Floating-Point Reliable Library +@subtitle Edition 1.0 +@subtitle June 1999 + +@author the PolKA project, INRIA Lorraine and LORIA + +@c Include the Distribution inside the titlepage so +@c that headings are turned off. + +@tex +\global\parindent=0pt +\global\parskip=8pt +\global\baselineskip=13pt +@end tex + +@page +@vskip 0pt plus 1filll +Copyright @copyright{} 1999 The PolKA project + +@sp 2 + +Published by the Free Software Foundation @* +59 Temple Place - Suite 330 @* +Boston, MA 02111-1307, USA @* + +Permission is granted to make and distribute verbatim copies of +this manual provided the copyright notice and this permission notice +are preserved on all copies. + +Permission is granted to copy and distribute modified versions of this +manual under the conditions for verbatim copying, provided that the entire +resulting derived work is distributed under the terms of a permission +notice identical to this one. + +Permission is granted to copy and distribute translations of this manual +into another language, under the above conditions for modified versions, +except that this permission notice may be stated in a translation approved +by the Foundation. +@end titlepage +@headings double + +@ifinfo +@node Top, Copying, (dir), (dir) + +@top MPFR + +This manual documents how to install and use the Multiple Precision +Floating-Point Reliable Library, version 1.0 + +@end ifinfo + +@menu +* Copying:: GMP Copying Conditions (LGPL). +* Introduction to MPFR:: Brief introduction to MPFR. +* Installing MPFR:: How to configure and compile the MPFR library. +* MPFR Basics:: What every MPFR user should now. +* Reporting Bugs:: How to usefully report bugs. +* Floating-point Functions:: Functions for arithmetic on floats. + +* Contributors:: +* References:: +* Concept Index:: +* Function Index:: +@end menu + +@node Copying, Introduction to MPFR, Top, Top +@comment node-name, next, previous, up +@unnumbered MPFR Copying Conditions +@cindex Copying conditions +@cindex Conditions for copying MPFR + +This library is @dfn{free}; this means that everyone is free to use it and +free to redistribute it on a free basis. The library is not in the public +domain; it is copyrighted and there are restrictions on its distribution, but +these restrictions are designed to permit everything that a good cooperating +citizen would want to do. What is not allowed is to try to prevent others +from further sharing any version of this library that they might get from +you.@refill + +Specifically, we want to make sure that you have the right to give away copies +of the library, that you receive source code or else can get it if you want +it, that you can change this library or use pieces of it in new free programs, +and that you know you can do these things.@refill + +To make sure that everyone has such rights, we have to forbid you to deprive +anyone else of these rights. For example, if you distribute copies of the +MPFR library, you must give the recipients all the rights that you have. You +must make sure that they, too, receive or can get the source code. And you +must tell them their rights.@refill + +Also, for our own protection, we must make certain that everyone finds out +that there is no warranty for the MPFR library. If it is modified by +someone else and passed on, we want their recipients to know that what they +have is not what we distributed, so that any problems introduced by others +will not reflect on our reputation.@refill + +The precise conditions of the license for the MPFR library are found in the +Library General Public License that accompany the source code. +See the file COPYING.LIB.@refill + +@node Introduction to MPFR, Installing MPFR, Copying, Top +@comment node-name, next, previous, up +@chapter Introduction to MPFR + + +MPFR is a portable library written in C for arbitrary precision arithmetic +on reliable floating-point numbers. It is based on the GNU MP library. +It aims to extend the class of floating-point numbers provided by the +GNU MP library by @dfn{reliable} floating-point numbers. It may replace +the GNU MP floating-point numbers in a future release. The main differences +with the @code{mpf} class are: +@itemize @bullet +@item the @code{mpfr} code is portable, i.e. the result of any operation +does not depend (or should not) on the machine word size +@code{mp_bits_per_limb} (32 or 64 on most machines); +@item the precision in bits can be set exactly to any positive value + for each variable (including one bit of precision); +@item @code{mpfr} provides the four rounding modes from the IEEE 754 + standard. +@end itemize +In particular, with a precision of 53 bits, @code{mpfr} should be able +to exactly reproduce all computations with double-precision machine +floating-point +numbers (@code{double} type in C), except the range of values is much wider +(the exponent has at least 32 bits instead of 11). + +This version of MPFR is released under the GNU Library General Public +License. +It is permitted to link MPFR to non-free programs, as long as MPFR +source code is provided when distributing the non-free program. + + +@section How to use this Manual + +Everyone should read @ref{MPFR Basics}. If you need to install the library +yourself, you need to read @ref{Installing MPFR}, too. + +The rest of the manual can be used for later reference, although it is +probably a good idea to glance through it. + + +@node Installing MPFR, MPFR Basics, Introduction to MPFR, Top +@comment node-name, next, previous, up +@chapter Installing MPFR +@cindex Installation + +To build MPFR, you first have to install GNU MP +(version 2.0.2 or higher) on your computer. +You need a C compiler, preferably GCC, but any reasonable compiler should +work. And you need a standard Unix @samp{make} program, plus some other +standard Unix utility programs. + +Here are the steps needed to install the library on Unix systems: + +@enumerate +@item +In most cases, @samp{./Configure} should work. +If you get error messages, your machine might +not be supported. + +If you want to compile in a separate object directory, cd to that directory, +and prefix the configure command with the path to the MPFR source directory. +Not all @samp{make} programs have the necessary features to support this. In +particular, SunOS and Slowaris @samp{make} have bugs that make them unable to +build from a separate object directory. Use GNU @samp{make} instead. +Also, the generated makefiles use some pattern matching rules that are not +supported by all @samp{make} programs. Again, use GNU @samp{make} instead. + +@item +@samp{make} + +This will compile MPFR, and create a library archive file @file{libmpfr.a} +in the working directory. + +@item +@samp{make check} + +This will make sure MPFR was built correctly. +If you get error messages, please +report this to @samp{mpfr@@loria.fr}. (@xref{Reporting Bugs}, for +information on what to include in useful bug reports.) + +@item +@samp{make install} + +This will copy the files @file{mpfr.h} and @file{libmpfr.a}, +as well as the info +files, to @file{/usr/local} (or if you passed the @samp{--prefix} option to +@file{configure}, to the directory given as argument to @samp{--prefix}). +@end enumerate + +There are some other useful make targets: + +@itemize @bullet +@item +@samp{doc} + +Create a DVI version of the manual, in @file{mpfr.dvi} and a set of info files, +in @file{mpfr.info}, @file{mpfr.info-1}, @file{mpfr.info-2}, etc. + +@item +@samp{ps} + +Create a Postscript version of the manual, in @file{mpfr.ps}. + +@item +@samp{html} + +Create a HTML version of the manual, in @file{mpfr.html}. + +@item +@samp{clean} + +Delete all object files and archive files, but not the configuration files. + +@item +@samp{distclean} + +Delete all files not included in the distribution. + +@item +@samp{uninstall} + +Delete all files copied by @samp{make install}. +@end itemize + + +@section Known Build Problems + +MPFR suffers from all bugs from the GNU MP library, plus many many more. + +Please report other problems to @samp{mpfr@@loria.fr}. +@xref{Reporting Bugs}. + + +@node MPFR Basics, Reporting Bugs, Installing MPFR, Top +@comment node-name, next, previous, up +@chapter MPFR Basics + + +@cindex @file{mpfr.h} +All declarations needed to use MPFR are collected in the include file +@file{mpfr.h}. It is designed to work with both C and C++ compilers. + + +@section Nomenclature and Types + +@cindex Floating-point number +@tindex @code{mpfr_t} +@noindent +@dfn{Floating point number} or @dfn{Float} for short, is an arbitrary precision +mantissa with a limited precision exponent. The C data type for such objects +is @code{mpfr_t}. + +@cindex Limb +@c @tindex @code{mp_limb_t} +@noindent +A @dfn{limb} means the part of a multi-precision number that fits in a single +word. (We chose this word because a limb of the human body is analogous to a +digit, only larger, and containing several digits.) Normally a limb contains +32 or 64 bits. The C data type for a limb is @code{mp_limb_t}. + +@section Function Classes + +There is only one class of functions in the MPFR library: + +@enumerate +@item +Functions for floating-point arithmetic, with names beginning with +@code{mpfr_}. The associated type is @code{mpfr_t}. There are about 50 +functions is this class. +@end enumerate + + +@section MPFR Variable Conventions + +As a general rule, all MPFR functions expect output arguments before input +arguments. This notation is based on an analogy with the assignment operator. + +MPFR allows you to use the same variable for both input and output in the same +expression. For example, the main function for floating-point multiplication, +@code{mpfr_mul}, can be used like this: @code{mpfr_mul (x, x, x, rnd_mode)}. +This +computes the square of @var{x} with rounding mode @code{rnd_mode} +and puts the result back in @var{x}. + +Before you can assign to an MPFR variable, you need to initialize it by calling +one of the special initialization functions. When you're done with a +variable, you need to clear it out, using one of the functions for that +purpose. + +A variable should only be initialized once, or at least cleared out between +each initialization. After a variable has been initialized, it may be +assigned to any number of times. + +For efficiency reasons, avoid to initialize and clear out a variable in loops. +Instead, initialize it before entering the loop, and clear it out after the +loop has exited. + +You don't need to be concerned about allocating additional space for MPFR +variables, since any variable has a mantissa of fixed size. +Hence unless you change its precision, or clear and reinitialize it, +a floating-point variable will have the same allocated space during all its +life. + +@section Getting the Latest Version of MP + +The latest version of the MPFR library is available from the web page +of the PolKA team at +@samp{http://www.loria.fr/equipes/polka}. + +@node Reporting Bugs, MPFR Basics, Top +@comment node-name, next, previous, up +@chapter Reporting Bugs +@cindex Reporting bugs + +If you think you have found a bug in the MPFR library, please investigate it +and report it. We have made this library available to you, and it is not to ask +too much from you, to ask you to report the bugs that you find. + +There are a few things you should think about when you put your bug report +together. + +You have to send us a test case that makes it possible for us to reproduce the +bug. Include instructions on how to run the test case. + +You also have to explain what is wrong; if you get a crash, or if the results +printed are incorrect and in that case, in what way. + +Please include compiler version information +in your bug report. This can be extracted using @samp{what `which cc`}, or, +if you're using gcc, @samp{gcc -v}. Also, include the output from @samp{uname +-a}. + +If your bug report is good, we will do our best to help you to get a corrected +version of the library; if the bug report is poor, we won't do anything about +it (aside of chiding you to send better bug reports). + +Send your bug report to: @samp{mpfr@@loria.fr}. + +If you think something in this manual is unclear, or downright incorrect, or if +the language needs to be improved, please send a note to the same address. + +@node Floating-point Functions, Low-level Functions, Reporting bugs, Top +@comment node-name, next, previous, up +@chapter Floating-point Functions +@cindex Floating-point functions +@cindex Float functions + +The floating-point functions expect arguments of type @code{mpfr_t}. + +The MPFR floating-point functions have an interface that is similar to the +GNU MP +integer functions. The function prefix for floating-point operations is +@code{mpfr_}. + +There is one significant characteristic of floating-point numbers that has +motivated a difference between this function class and other MPFR function +classes: the inherent inexactness of floating point arithmetic. The user has +to specify the precision of each variable. A computation that assigns a +variable will take place with the precision of the assigned variable; the +cost of that computation should not depend from the +precision of variables used as input on average. + +@cindex User-defined precision +The precision of a calculation is defined as follows: Compute the requested +operation exactly (with ``infinite precision''), and round the result to +the destination variable precision with the given rounding mode. +Even if the user has asked for a very +high precision, MP will not calculate with superfluous digits. For example, +if two low-precision numbers of nearly equal magnitude are added, the +precision of the result will be limited to what is required to represent the +result accurately. + +The MPFR floating-point functions are intended to be a smooth extension +of the IEEE P754 arithmetic. The results obtained on one +computer should not differ from the results obtained on a computer with a +different word size. + +@menu +* Rounding Modes +* Initializing Floats:: +* Assigning Floats:: +* Converting Floats:: +* Float Arithmetic:: +* Float Comparison:: +* I/O of Floats:: +* Miscellaneous Float Functions:: +@end menu + +@cindex Rouding modes +@section Global Variables and Rounding Modes + +@deftypevr {Global Variable} {mp_size_t} __gmp_default_fp_bit_precision +The default precision in bits (53 initially). +@end deftypevr + +@deftypevr {Global Variable} {char} __gmp_default_rounding_mode +The default rounding mode (to nearest initially). +@end deftypevr + +The following four rounding modes are supported: +@itemize @bullet +@item @code{GMP_RNDN}: round to nearest +@item @code{GMP_RNDZ}: round towards zero +@item @code{GMP_RNDU}: round towards plus infinity +@item @code{GMP_RNDD}: round towards minus infinity +@end itemize +The @samp{round to nearest} mode works as in the IEEE P754 standard: in case +the number to be rounded lies exactly in the middle of two reprensentable +numbers, it is rounded to the one with the least significant bit set to zero. +For example, the number 5, which is represented by (101) in binary, is rounded +to (100)=4 with a precision of two bits, and not to (110)=6. +This rule avoids the @dfn{drift} phenomena mentioned by Knuth in volume 2 +of The Art of Computer Programming (section 4.2.2, pages 221-222). + +@deftypefun void mpfr_set_default_rounding_mode (char @var{rnd}) +Sets the default rounding mode to @var{rnd}. +The default rounding mode is to nearest initially. +@end deftypefun + +@deftypefun void mpfr_round (mpfr_t @var{x}, char @var{rnd}, unsigned long @var{prec}) +Round @var{x} according to @var{rnd} with precision @var{prec}, which +may be different from that of @var{x}. +If @var{prec} is greater or equal to the precision of @var{x}, then new +space is allocated for the mantissa, and it is filled with zeroes. +Otherwise, the mantissa is rounded to precision @var{prec} with the given +direction. In both cases, the precision of @var{x} is changed to @var{prec}. +@end deftypefun + +@deftypefun void mpfr_set_machine_rnd_mode (char @var{rnd}) +Set the machine rounding mode to @var{rnd}. +This function is useful for debugging purpose, but +also as a common interface to all different ways of setting the +rounding mode, which unfortunately differ from one operating system to +another one. +@end deftypefun + +@deftypefun {char *} mpfr_print_rnd_mode (unsigned char @var{rnd}) +Returns the input string (GMP_RNDD, GMP_RNDU, GMP_RNDN, GMP_RNDZ) +corresponding to the rounding mode @var{rnd}. +@end deftypefun + +@node Initializing Floats, Assigning Floats, , Floating-point Functions +@comment node-name, next, previous, up +@section Initialization and Assignment Functions + +@deftypefun void mpfr_set_default_prec (unsigned long int @var{prec}) +Set the default precision to be @strong{exactly} @var{prec} bits. The +precision of a variable means the number of bits used to store its mantissa. +All +subsequent calls to @code{mpf_init} will use this precision, but previously +initialized variables are unaffected. +This default precision is set to 53 bits initially. +The precision can be any positive integer, even a precision of 1 is possible. +@end deftypefun + +An @code{mpfr_t} object must be initialized before storing the first value in +it. The functions @code{mpfr_init} and @code{mpfr_init2} are used for that +purpose. + +@deftypefun void mpfr_init (mpfr_t @var{x}) +Initialize @var{x}. No special value is set. +Normally, a variable should be initialized once only +or at least be cleared, using @code{mpfr_clear}, between initializations. The +precision of @var{x} is the default precision, which can be changed +by a call to @code{mpfr_set_default_prec}. +@end deftypefun + +@deftypefun void mpfr_init2 (mpfr_t @var{x}, unsigned long int @var{prec}) +Initialize @var{x} and set its precision to be @strong{exactly} +@var{prec} bits. Normally, a variable should be initialized once only or at +least be cleared, using @code{mpfr_clear}, between initializations. +To change the precision of a variable which has already been initialized, +use @code{mpfr_set_prec} instead. +@end deftypefun + +@deftypefun void mpfr_clear (mpfr_t @var{x}) +Free the space occupied by @var{x}. Make sure to call this function for all +@code{mpfr_t} variables when you are done with them. +@end deftypefun + +@need 2000 +Here is an example on how to initialize floating-point variables: +@example +@{ + mpfr_t x, y; + mpfr_init (x); /* use default precision */ + mpfr_init2 (y, 256); /* precision @emph{exactly} 256 bits */ + @dots{} + /* Unless the program is about to exit, do ... */ + mpfr_clear (x); + mpfr_clear (y); +@} +@end example + +The following two functions are useful for changing the precision during a +calculation. A typical use would be for adjusting the precision gradually in +iterative algorithms like Newton-Raphson, making the computation precision +closely match the actual accurate part of the numbers. + +@deftypefun void mpfr_set_prec (mpfr_t @var{x}, unsigned long int @var{prec}) +Reset the precision of @var{x} to be @strong{exactly} @var{prec} bits. +The previous value stored in @var{x} is lost. It is equivalent to +a call to @code{mpfr_clear(x)} followed by a call to +@code{mpfr_init2(x, prec)}, but more efficient as no allocation is done in +case the current allocated space for the mantissa of @var{x} is enough. + +In case you want to keep the previous value stored in @var{x}, +use @code{mpfr_round} instead. +@end deftypefun + +@deftypefun {unsigned long int} mpfr_get_prec (mpf_t @var{x}) +Return the precision actually used for assignments of @var{x}, i.e. +the number of bits used to store its mantissa. +@end deftypefun + +@node Assigning Floats, Simultaneous Float Init & Assign, Initializing Floats, Floating-point Functions +@comment node-name, next, previous, up +@subsection Assignment Functions +@cindex Float assignment functions + +These functions assign new values to already initialized floats +(@pxref{Initializing Floats}). + +@deftypefun void mpfr_set (mpfr_t @var{rop}, mpfr_t @var{op}, char @var{rnd}) +@deftypefunx void mpfr_set_ui (mpfr_t @var{rop}, unsigned long int @var{op}, char @var{rnd}) +@deftypefunx void mpfr_set_si (mpfr_t @var{rop}, long int @var{op}, char @var{rnd} +@deftypefunx void mpfr_set_d (mpfr_t @var{rop}, double @var{op}, char @var{rnd}) +@deftypefunx void mpfr_set_z (mpfr_t @var{rop}, mpz_t @var{op}, char @var{rnd}) +Set the value of @var{rop} from @var{op}, rounded to the precision of @var{rop} +towards the given direction @var{rnd}. +Please note that even a @code{long int} may have to be rounded, +if the destination precision is less than the machine word width. +@end deftypefun + +@deftypefun void mpfr_set_str_raw (mpfr_t @var{x}, char *@var{s}) +Set @var{x} to the value of the binary number in string @var{s}, which has to +be of the +form +/-xxxx.xxxxxxEyy. The exponent is read in decimal, but is interpreted +as the power of two to be multiplied by the mantissa. +@end deftypefun + +@deftypefun void mpfr_set_f (mpfr_t @var{x}, mpf_t @var{y}, char @var{rnd}) +Set @var{x} to the GNU MP floating-point number +@var{y}, rounded with the @var{rnd} mode and the precision +of @var{x}. +@end deftypefun + +@node Converting Floats, Float Arithmetic, Simultaneous Float Init & Assign, Floating-point Functions +@comment node-name, next, previous, up +@section Conversion Functions +@cindex Conversion functions + +@deftypefun double mpfr_get_d (mpfr_t @var{op}) +Convert @var{op} to a double, using the current @emph{machine} rounding mode. +@end deftypefun + +@deftypefun {char *} mpfr_get_str (char *@var{str}, mp_exp_t *@var{expptr}, int @var{base}, size_t @var{n_digits}, mpfr_t @var{op}, char @var{rnd}) +Convert @var{op} to a string of digits in base @var{base}, with rounding in +direction @var{rnd}. The base may vary +from 2 to 36. Generate exactly @var{n_digits} significant digits. + +If @var{n_digits} is 0, it prints the maximum possible number of digits +giving an exact rounding in the given base @var{base} with the direction +@var{rnd}. In other words, if @var{op} was the exact rounding +of a real number in direction @var{rnd}, then the printed value is also +an exact rounding in base @var{base} of that real number with the same +precision. An error occurs when one is unable to determine the leading +digit, which can happen especially if the precision of @var{op} is small. + +If @var{str} is NULL, space for the mantissa is allocated using the default +allocation function, and a pointer to the string is returned. + +If @var{str} is not NULL, it should point to a block of storage enough large +for the mantissa, i.e., @var{n_digits} + 2. The two extra bytes are for a +possible minus sign, and for the terminating null character. + +The exponent is written through the pointer @var{expptr}. + +If @var{n_digits} is 0, note that the space +requirements for @var{str} in this case will be impossible for the user to +predetermine. Therefore, you need to pass NULL for the string argument +whenever @var{n_digits} is 0. + +The generated string is a fraction, with an implicit radix point immediately +to the left of the first digit. For example, the number 3.1416 would be +returned as "31416" in the string and 1 written at @var{expptr}. +@end deftypefun + + +@node Float Arithmetic, Float Comparison, Converting Floats, Floating-point Functions +@comment node-name, next, previous, up +@section Basic Arithmetic Functions +@cindex Float arithmetic functions +@cindex Arithmetic functions + +@deftypefun void mpfr_add (mpfr_t @var{rop}, mpfr_t @var{op1}, mpfr_t @var{op2}, char @var{rnd}) +@ifinfo +Set @var{rop} to @var{op1} + @var{op2} rounded in the direction @var{rnd}. +@end ifinfo +@iftex +@tex +Set @var{rop} to $@var{op1} + @var{op2}$ rounded in the direction @var{rnd}. +@end tex +@end iftex +@end deftypefun + +@deftypefun void mpfr_sub (mpfr_t @var{rop}, mpfr_t @var{op1}, mpfr_t @var{op2}, char @var{rnd}) +Set @var{rop} to @var{op1} @minus{} @var{op2} rounded in the direction @var{rnd}. +@end deftypefun + +@deftypefun void mpfr_mul (mpfr_t @var{rop}, mpfr_t @var{op1}, mpfr_t @var{op2}, char @var{rnd}) +@deftypefunx void mpfr_mul_ui (mpfr_t @var{rop}, mpfr_t @var{op1}, unsigned long int @var{op2}, char @var{rnd}) +@ifinfo +Set @var{rop} to @var{op1} times @var{op2} rounded in the direction @var{rnd}. +@end ifinfo +@iftex +@tex +Set @var{rop} to $@var{op1} \times @var{op2}$ rounded in the direction @var{rnd}. +@end tex +@end iftex +@end deftypefun + +Division is undefined if the divisor is zero, and passing a zero divisor to +the divide functions will make these functions intentionally divide by zero. +This gives the user the possibility to handle arithmetic exceptions in these +functions in the same manner as other arithmetic exceptions. + +@deftypefun void mpfr_div (mpfr_t @var{rop}, mpfr_t @var{op1}, mpfr_t @var{op2}, char @var{rnd}) +@deftypefunx int mpfr_div_ui (mpfr_t @var{rop}, mpfr_t @var{op1}, unsigned long int @var{op2}, char @var{rnd}) +Set @var{rop} to @var{op1}/@var{op2} rounded in the direction @var{rnd}. +@c Return 0 if the division is exact, a non-zero value otherwise. +@end deftypefun + +@deftypefun int mpfr_sqrt (mpfr_t @var{rop}, mpfr_t @var{op}, char @var{rnd}) +@ifinfo +Set @var{rop} to the square root of @var{op} rounded in the direction @var{rnd}. +@end ifinfo +@iftex +@tex +Set @var{rop} to $\sqrt{@var{op}}$ rounded in the direction @var{rnd}. +@end tex +@end iftex +Set @var{rop} to NaN if @var{op} is negative. +Return 0 if the operation is exact, a non-zero value otherwise. +@end deftypefun + +@deftypefun void mpfr_pow_ui (mpfr_t @var{rop}, mpfr_t @var{op1}, unsigned long int @var{op2}, char @var{rnd}) +@deftypefunx void mpfr_ui_pow_ui (mpfr_t @var{rop}, unsigned long int @var{op1}, unsigned long int @var{op2}, char @var{rnd}) +Set @var{rop} to @var{op1} raised to @var{op2}. The computation is done by +binary exponentiation, each multiplication being rounded to direction +@var{rnd}. Hence the relative error with respect to the exact result may be +larger than one unit in last place (ulp). In other words, this function does +not provide an exact rounding. +@end deftypefun + +@deftypefun void mpfr_neg (mpfr_t @var{rop}, mpfr_t @var{op}, char @var{rnd}) +Set @var{rop} to @minus{}@var{op} rounded in the direction @var{rnd}. +Just changes the sign +if @var{rop} and @var{op} are the same variable. +@end deftypefun + +@c @deftypefun void mpfr_abs (mpfr_t @var{rop}, mpfr_t @var{op}) +@c Set @var{rop} to the absolute value of @var{op}. +@c @end deftypefun + +@deftypefun void mpfr_mul_2exp (mpfr_t @var{rop}, mpfr_t @var{op1}, unsigned long int @var{op2}, char @var{rnd}) +@ifinfo +Set @var{rop} to @var{op1} times 2 raised to @var{op2} +@end ifinfo +@iftex +@tex +Set @var{rop} to $@var{op1} \times 2^{op2}$ +@end tex +@end iftex +rounded to the direction @var{rnd}. Just increases the exponent by @var{op2} +when @var{rop} and @var{op1} are identical. +@end deftypefun + +@deftypefun void mpfr_div_2exp (mpfr_t @var{rop}, mpfr_t @var{op1}, unsigned long int @var{op2}) +@ifinfo +Set @var{rop} to @var{op1} divided by 2 raised to @var{op2}. +@end ifinfo +@iftex +@tex +Set @var{rop} to $@var{op1}/2^{op2}$. +@end tex +@end iftex +rounded to the direction @var{rnd}. Just decreases the exponent by @var{op2} +when @var{rop} and @var{op1} are identical. +@end deftypefun + +@node Float Comparison, I/O of Floats, Float Arithmetic, Floating-point Functions +@comment node-name, next, previous, up +@section Comparison Functions +@cindex Float comparisons functions +@cindex Comparison functions + +@deftypefun int mpfr_cmp (mpfr_t @var{op1}, mpfr_t @var{op2}) +@deftypefunx int mpfr_cmp_ui (mpfr_t @var{op1}, unsigned long int @var{op2}) +@deftypefunx int mpfr_cmp_si (mpfr_t @var{op1}, signed long int @var{op2}) +@ifinfo +Compare @var{op1} and @var{op2}. Return a positive value if @var{op1} > +@var{op2}, zero if @var{op1} = @var{op2}, and a negative value if @var{op1} < +@var{op2}. +@end ifinfo +@iftex +@tex +Compare @var{op1} and @var{op2}. Return a positive value if $@var{op1} > +@var{op2}$, zero if $@var{op1} = @var{op2}$, and a negative value if $@var{op1} +< @var{op2}$. +@end tex +@end iftex +Both @var{op1} and @var{op2} are considered to their full own precision, +which may differ. In case @var{op1} and @var{op2} are of same sign but +different, the absolute value returned is +one plus the absolute difference of their exponents. +@end deftypefun + +@deftypefun int mpfr_cmp_ui_2exp (mpfr_t @var{op1}, unsigned long int @var{op2}, int @var{e}) +@deftypefunx int mpfr_cmp_si_2exp (mpfr_t @var{op1}, unsigned long int @var{op2}, int @var{e}) +Compare @var{op1} and @var{op2} multiplied by two to the power @var{e}. +@end deftypefun + +@c @deftypefun int mpfr_eq (mpfr_t @var{op1}, mpfr_t @var{op2}, unsigned long int op3) +@c Return non-zero if the first @var{op3} bits of @var{op1} and @var{op2} are +@c equal, zero otherwise. I.e., test of @var{op1} and @var{op2} are +@c approximately equal. +@c @end deftypefun + +@c @deftypefun void mpfr_reldiff (mpfr_t @var{rop}, mpfr_t @var{op1}, mpfr_t @var{op2}) +@c Compute the relative difference between @var{op1} and @var{op2} and store the +@c result in @var{rop}. +@c @end deftypefun + +@deftypefn Macro int SIGN (mpfr_t @var{op}) +@ifinfo +Return +1 if @var{op} > 0, and @minus{}1 if @var{op} < 0. +@end ifinfo +@iftex +@tex +Return $+1$ if $@var{op} > 0$, and $-1$ if $@var{op} < 0$. +@end tex +@end iftex +This function is actually implemented as a macro. It evaluates its +arguments multiple times. +As in the IEEE 754 standard, there is a positive zero and a negative one, +therefore the @var{SIGN} macro does not distinguish zero from non-zero +numbers. +@end deftypefn + +@deftypefn Macro int NOTZERO (mpfr_t @var{op}) +Returns zero when its argument is zero, and a non-zero value otherwise. +@end deftypefn + +@section Special Functions +@cindex Special functions + +@deftypefun int mpfr_log (mpfr_t @var{rop}, mpfr_t @var{op}, char @var{rnd}) +Set @var{rop} to the natural logarithm of @var{op}, +rounded to the direction @var{rnd} with the precision of @var{rop}. +Return 0 iff the result is exact (this occurs in fact only when @var{op} is 1 +i.e. the result is 0). +@end deftypefun + +@deftypefun int mpfr_exp (mpfr_t @var{rop}, mpfr_t @var{op}, char @var{rnd}) +Set @var{rop} to the exponential of @var{op}, +rounded to the direction @var{rnd} with the precision of @var{rop}. +Return 0 iff the result is exact (this occurs in fact only when @var{op} is 0 +i.e. the result is 1). +@end deftypefun + +@deftypefun void mpfr_agm (mpfr_t @var{rop}, mpfr_t @var{op1}, mpfr_t @var{op2}, char @var{rnd}) +Set @var{rop} to the arithmetic-geometric mean of @var{op1} and @var{op2}, +rounded to the direction @var{rnd} with the precision of @var{rop}. +@end deftypefun + +@deftypefun void mpfr_log2 (mpfr_t @var{rop}, unsigned char @var{rnd}) +Set @var{rop} to the logarithm of 2 rounded to the direction @var{rnd} +with the precision of @var{rop}. This function stores the computed +value to avoid another calculation if a lower or equal precision is +requested. +@end deftypefun + +@deftypefun void mpfr_pi (mpfr_t @var{rop}, unsigned char @var{rnd}) +Set @var{rop} to the value of Pi rounded to the direction @var{rnd} +with the precision of @var{rop}. This function uses the Borwein, Borwein, +Plouffe formula which directly gives the expansion of Pi in base 16. +@end deftypefun + +@node I/O of Floats, Miscellaneous Float Functions, Float Comparison, Floating-point Functions +@comment node-name, next, previous, up +@section Input and Output Functions +@cindex Float input and output functions +@cindex Input functions +@cindex Output functions +@cindex I/O functions + +Functions that perform input from a stdio stream, and functions that output to +a stdio stream. Passing a NULL pointer for a @var{stream} argument to any of +these functions will make them read from @code{stdin} and write to +@code{stdout}, respectively. + +When using any of these functions, it is a good idea to include @file{stdio.h} +before @file{mpfr.h}, since that will allow @file{mpfr.h} to define prototypes +for these functions. + +@deftypefun size_t mpfr_out_str (FILE *@var{stream}, int @var{base}, size_t @var{n_digits}, mpfr_t @var{op}, char @var{rnd}) +Output @var{op} on stdio stream @var{stream}, as a string of digits in +base @var{base}, rounded to direction @var{rnd}. +The base may vary from 2 to 36. Print at most +@var{n_digits} significant digits, or if @var{n_digits} is 0, the maximum +number of digits accurately representable by @var{op}. + +In addition to the significant digits, a decimal point at the right of the +first digit and a +trailing exponent, in the form @samp{eNNN}, are printed. If @var{base} +is greater than 10, @samp{@@} will be used instead of @samp{e} as +exponent delimiter. + +Return the number of bytes written, or if an error occurred, return 0. +@end deftypefun + +@c @deftypefun size_t mpfr_inp_str (mpfr_t @var{rop}, FILE *@var{stream}, int @var{base}) +@c Input a string in base @var{base} from stdio stream @var{stream}, and put the +@c read float in @var{rop}. The string is of the form @samp{M@@N} or, if the +@c base is 10 or less, alternatively @samp{MeN}. @samp{M} is the mantissa and +@c @samp{N} is the exponent. The mantissa is always in the specified base. The +@c exponent is either in the specified base or, if @var{base} is negative, in +@c decimal. + +@c The argument @var{base} may be in the ranges 2 to 36, or @minus{}36 to +@c @minus{}2. Negative values are used to specify that the exponent is in +@c decimal. + +@c Unlike the corresponding @code{mpz} function, the base will not be determined +@c from the leading characters of the string if @var{base} is 0. This is so that +@c numbers like @samp{0.23} are not interpreted as octal. + +@c Return the number of bytes read, or if an error occurred, return 0. +@c @end deftypefun + +@deftypefun void mpfr_print_raw (mpfr_t @var{float}) +Output @var{float} on stdout (should be changed to allow any io stream), +in raw binary format (the exponent is in decimal, yet). +The last bits from the least significant limb which do not belong to +the mantissa are printed between square brackets; +they should always be zero. +@end deftypefun + +@c @deftypefun void mpfr_inp_raw (mpfr_t @var{float}, FILE *@var{stream}) +@c Input from stdio stream @var{stream} in the format written by +@c @code{mpfr_out_raw}, and put the result in @var{float}. +@c @end deftypefun + + +@node Miscellaneous Float Functions, , I/O of Floats, Floating-point Functions +@comment node-name, next, previous, up +@section Miscellaneous Functions +@cindex Miscellaneous float functions + +@deftypefun void mpfr_random (mpfr_t @var{rop}) +Put in @var{rop} a random float in the interval [0,1[. +Random limbs are generated using the +@code{random} system function. +zeros and ones in the binary representation. The exponent of the number is in +the interval @minus{}@var{exp} to @var{exp}. This function is useful for +testing functions and algorithms, since this kind of random numbers have +proven to be more likely to trigger corner-case bugs. Negative random numbers +are generated when @var{max_size} is negative. +@end deftypefun + +@deftypefun void mpfr_srandom (unsigned long @var{seed}) +Set the random seed used by @code{mpfr_random} to @var{seed}. +@end deftypefun + +@c @deftypefun size_t mpfr_size (mpfr_t @var{op}) +@c Return the size of @var{op} measured in number of limbs. If @var{op} is +@c zero, the returned value will be zero. (@xref{Nomenclature}, for an +@c explanation of the concept @dfn{limb}.) +@c +@c @strong{This function is obsolete. It will disappear from future MP +@c releases.} +@c @end deftypefun + +@section Internal Functions + +These functions were mainly designed for the implementation of @code{mpfr}, +but may be useful for users too. + +@deftypefun Macro int FLAG_NAN (mpfr_t x) +Returns a non-zero value iff its argument is @samp{Not a Number}. +@end deftypefun + +@deftypefun Macro int SET_NAN (mpfr_t x) +Sets its argument to @samp{Not a Number}. +@end deftypefun + +@deftypefun Macro int ABSSIZE (mpfr_t x) +Returns the number of limb the mantissa of @var{x} points to. +@end deftypefun + +@deftypefun Macro int EXP (mpfr_t x) +Returns the exponent of @var{x}. +@end deftypefun + +@deftypefun Macro mp_limb_t* MANT (mpfr_t x) +Returns a pointer to the mantissa of @var{x}. +@end deftypefun + +@deftypefun Macro unsigned int PREC (mpfr_t x) +Returns the precision of @var{x}. +@end deftypefun + +@deftypefun Macro int CHANGE_SIGN (mpfr_t x) +Changes the sign of @var{x}. +@end deftypefun + +@deftypefun int mpfr_add_one_ulp (mpfr_t @var{x}) +Add one unit in last place (ulp) to the mantissa of @var{x} +if it is positive or zero, and subtracts one ulp otherwise. +Always return 0 (result is exact). +@end deftypefun + +@deftypefun int mpfr_sub_one_ulp (mpfr_t @var{x}) +Subtract one ulp to @var{x} if it is positive or zero, +and adds one ulp otherwise. +Always return 0 (result is exact). +@end deftypefun + +@deftypefun int mpfr_cmp2 (mpfr_t @var{a}, mpfr_t @var{b}) +Assuming @var{a} is greater or equal to @var{b}, returns the number of +cancelled bits when one subtracts @var{b} from @var{a}. +Returns the precision of @var{a} when both operands are equal. +Mainly used in @code{mpfr_sub}. +@end deftypefun + +@deftypefun int mpfr_round_raw (mp_limb_t* @var{y}, mp_limb_t* @var{x}, long @var{xprec}, char @var{neg}, long @var{yprec}, char @var{rnd}) +Puts in mantissa beginning at @var{y} the value of that +beginning at @var{x} (with precision @var{xprec} bits and negative iff +@var{neg} is not zero) +rounded with mode @var{rnd} to precision @var{yprec}. +@end deftypefun + +@deftypefun int mpfr_round_raw2 (mp_limb_t* @var{x}, long @var{xn}, char @var{neg}, char @var{rnd}, unsigned long @var{prec}) +Returns 0 if the multiple precision number stored in the @var{xn} limbs +starting at @var{xp} (least significant limbs first) with sign @var{neg} +(positive iff @var{neg} equals zero) +is rounded similarly with direction @var{rnd} and precision @var{prec} +than towards zero, and 1 otherwise. +In other words, the bit returned is what has to be added to bit @var{prec} +to round to mode @var{rnd}. This function @strong{does not modify} the +mantissa stored in @var{xp}. +@end deftypefun + +@deftypefun int mpfr_can_round (mpfr_t @var{b}, unsigned long @var{err}, char @var{rnd1}, char @var{rnd2}, unsigned long @var{prec}) +Assuming @var{b} is an approximation of an unknown number +@var{x} in direction @var{rnd1} with error at most two to the power +E(b)-@var{err} where E(b) is the exponent of +@var{b}, returns 1 if one is able to round exactly @var{x} to precision +@var{prec} with direction @var{rnd2}, + and 0 otherwise. This function @strong{does not modify} its arguments. +@end deftypefun + +@node Contributors, References, Custom Allocation, Top +@comment node-name, next, previous, up +@unnumbered Contributors + +We would like to thank Jean-Michel Muller and Joris van der Hoeven for very +fruitful discussions at the beginning of that project, Torbjorn Granlund +for his help about design issues +and his suggestions for a easy integration into GNU MP. + +Sylvie Boldo from ENS-Lyon, France, +contributed the function @code{mpfr_agm} during her stage in the PolKA team +in June and July 1999. + +@node References, , Contributors, Top +@comment node-name, next, previous, up +@unnumbered References + +@itemize @bullet + +@item +Torbjorn Granlund, "GNU MP: The GNU Multiple Precision Arithmetic Library", + version 2.0.2, 1996. + +@item +IEEE standard for binary floating-point arithmetic, Technical Report +ANSI-IEEE Standard 754-1985, New York, 1985. +Approved March 21, 1985: IEEE Standards Board; approved July 26, + 1985: American National Standards Institute, 18 pages. + +@item +Donald E. Knuth, "The Art of Computer Programming", vol 2, +"Seminumerical Algorithms", 2nd edition, Addison-Wesley, 1981. + +@end itemize + +@node Concept Index, , , Top +@comment node-name, next, previous, up +@unnumbered Concept Index +@printindex cp + +@node Function Index, , , Top +@comment node-name, next, previous, up +@unnumbered Function and Type Index +@printindex fn + +@contents +@bye diff --git a/mpfr/mul.c b/mpfr/mul.c new file mode 100644 index 000000000..c7c3cd3f5 --- /dev/null +++ b/mpfr/mul.c @@ -0,0 +1,78 @@ +/* mpfr_mul -- multiply two floating-point numbers + +Copyright (C) 1999 PolKA project, Inria Lorraine and Loria + +This file is part of the MPFR Library. + +The MPFR Library is free software; you can redistribute it and/or modify +it under the terms of the GNU Library General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at your +option) any later version. + +The MPFR Library 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 Library General Public +License for more details. + +You should have received a copy of the GNU Library General Public License +along with the MPFR Library; see the file COPYING.LIB. If not, write to +the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, +MA 02111-1307, USA. */ + +#include <stdio.h> +#include "gmp.h" +#include "gmp-impl.h" +#include "mpfr.h" + +/* Remains to do: +- do not use all bits of b and c when PREC(b)>PREC(a) or PREC(c)>PREC(a) + [current complexity is O(PREC(b)*PREC(c))] +*/ + +void +#if __STDC__ +mpfr_mul(mpfr_ptr a, mpfr_srcptr b, mpfr_srcptr c, unsigned char rnd_mode) +#else +mpfr_mul(a, b, c, rnd_mode) + mpfr_ptr a; + mpfr_srcptr b; + mpfr_srcptr c; + unsigned char rnd_mode; +#endif +{ + unsigned int bn, cn, an, tn, k; int cc; + mp_limb_t *ap=MANT(a), *bp=MANT(b), *cp=MANT(c), *tmp, b1; + long int sign_product; + TMP_DECL(marker); + + /* deal with NaN and zero */ + if (FLAG_NAN(b) || FLAG_NAN(c)) { SET_NAN(a); return; } + if (!NOTZERO(b) || !NOTZERO(c)) { SET_ZERO(a); return; } + + sign_product = SIGN(b) * SIGN(c); + bn = (PREC(b)-1)/mp_bits_per_limb+1; /* number of significant limbs of b */ + cn = (PREC(c)-1)/mp_bits_per_limb+1; /* number of significant limbs of c */ + tn = (PREC(c)+PREC(b)-1)/mp_bits_per_limb+1; + k = bn+cn; /* effective nb of limbs used by b*c */ + TMP_MARK(marker); + tmp = (mp_limb_t*) TMP_ALLOC(k*BYTES_PER_MP_LIMB); + + /* multiplies two mantissa in temporary allocated space */ + b1 = (bn>=cn) ? mpn_mul(tmp, bp, bn, cp, cn) : mpn_mul(tmp, cp, cn, bp, bn); + + /* now tmp[0]..tmp[k-1] contains the product of both mantissa, + with tmp[k-1]>=2^(mp_bits_per_limb-2) */ + an = (PREC(a)-1)/mp_bits_per_limb+1; /* number of significant limbs of a */ + b1 >>= mp_bits_per_limb-1; /* msb from the product */ + + if (b1==0) mpn_lshift(tmp, tmp, k, 1); + cc = mpfr_round_raw(ap, tmp+bn+cn-tn, + PREC(b)+PREC(c), (sign_product<0), PREC(a), rnd_mode); + if (cc) { /* cc = 1 ==> result is a power of two */ + ap[an-1] = (mp_limb_t) 1 << (BITS_PER_MP_LIMB-1); + } + EXP(a) = EXP(b) + EXP(c) + b1 - 1 + cc; + if (sign_product * SIGN(a)<0) CHANGE_SIGN(a); + TMP_FREE(marker); + return; +} diff --git a/mpfr/mul_2exp.c b/mpfr/mul_2exp.c new file mode 100644 index 000000000..31dab2ac6 --- /dev/null +++ b/mpfr/mul_2exp.c @@ -0,0 +1,43 @@ +/* mpfr_mul_2exp -- multiply a floating-point number by a power of two + +Copyright (C) 1999 PolKA project, Inria Lorraine and Loria + +This file is part of the MPFR Library. + +The MPFR Library is free software; you can redistribute it and/or modify +it under the terms of the GNU Library General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at your +option) any later version. + +The MPFR Library 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 Library General Public +License for more details. + +You should have received a copy of the GNU Library General Public License +along with the MPFR Library; see the file COPYING.LIB. If not, write to +the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, +MA 02111-1307, USA. */ + +#include <stdio.h> +#include "gmp.h" +#include "gmp-impl.h" +#include "mpfr.h" + +void +#if __STDC__ +mpfr_mul_2exp(mpfr_ptr y, mpfr_srcptr x, unsigned long int n, unsigned char rnd_mode) +#else +mpfr_mul_2exp(y, x, n, rnd_mode) + mpfr_ptr y; + mpfr_srcptr x; + unsigned long int n; + unsigned char rnd_mode; +#endif +{ + /* Important particular case */ + if (y != x) mpfr_set(y, x, rnd_mode); + EXP(y) += n; + return; +} + diff --git a/mpfr/mul_ui.c b/mpfr/mul_ui.c new file mode 100644 index 000000000..db4c39a90 --- /dev/null +++ b/mpfr/mul_ui.c @@ -0,0 +1,84 @@ +/* mpfr_mul_ui -- multiply a floating-point number by a machine integer + +Copyright (C) 1999 PolKA project, Inria Lorraine and Loria + +This file is part of the MPFR Library. + +The MPFR Library is free software; you can redistribute it and/or modify +it under the terms of the GNU Library General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at your +option) any later version. + +The MPFR Library 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 Library General Public +License for more details. + +You should have received a copy of the GNU Library General Public License +along with the MPFR Library; see the file COPYING.LIB. If not, write to +the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, +MA 02111-1307, USA. */ + +#include <stdio.h> +#include "gmp.h" +#include "gmp-impl.h" +#include "longlong.h" +#include "mpfr.h" + +void +#if __STDC__ +mpfr_mul_ui(mpfr_ptr y, mpfr_srcptr x, unsigned long u, unsigned char RND_MODE) +#else +mpfr_mul_ui() + mpfr_ptr y; + mpfr_srcptr x; + unsigned long u; + unsigned char RND_MODE; +#endif +{ + mp_limb_t carry, *my, *old_my; unsigned long c; + unsigned long xsize, ysize, cnt, dif; + TMP_DECL(marker); + + TMP_MARK(marker); + my = MANT(y); + ysize = (PREC(y)-1)/BITS_PER_MP_LIMB + 1; + xsize = (PREC(x)-1)/BITS_PER_MP_LIMB + 1; + + if (ysize < xsize) { + old_my = my; + my = (mp_ptr) TMP_ALLOC (xsize * BYTES_PER_MP_LIMB); + dif=0; + } + else dif=ysize-xsize; + + carry = mpn_mul_1(my+dif, MANT(x), xsize, u); + MPN_ZERO(my, dif); + + /* WARNING: count_leading_zeros is undefined for carry=0 */ + if (carry) count_leading_zeros(cnt, carry); + else cnt=BITS_PER_MP_LIMB; + + c = mpfr_round_raw(my, my, PREC(x), (SIGN(x)<0), + PREC(y)-BITS_PER_MP_LIMB+cnt, RND_MODE); + + /* If cnt = 1111111111111 and c = 1 we shall get depressed */ + if (c && (carry == (((mp_limb_t)1) << (BITS_PER_MP_LIMB - cnt)) - 1)) + { + cnt--; + mpn_rshift(my, my, ysize, BITS_PER_MP_LIMB - cnt); + my[ysize - 1] |= ((mp_limb_t) 1) << (BITS_PER_MP_LIMB - 1); + } + else + { + /* Warning: mpn_rshift is undefined for shift=0 */ + if (cnt!=BITS_PER_MP_LIMB) + mpn_rshift(my, my, ysize, BITS_PER_MP_LIMB - cnt); + my[ysize - 1] |= (carry << cnt); + } + EXP(y) = EXP(x) + BITS_PER_MP_LIMB - cnt; + if (ysize < xsize) MPN_COPY(old_my, my, ysize); + /* set sign */ + if (SIGN(y) != SIGN(x)) CHANGE_SIGN(y); + TMP_FREE(marker); +} diff --git a/mpfr/neg.c b/mpfr/neg.c new file mode 100644 index 000000000..fff73a65a --- /dev/null +++ b/mpfr/neg.c @@ -0,0 +1,40 @@ +/* mpfr_neg -- change the sign of a floating-point number + +Copyright (C) 1999 PolKA project, Inria Lorraine and Loria + +This file is part of the MPFR Library. + +The MPFR Library is free software; you can redistribute it and/or modify +it under the terms of the GNU Library General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at your +option) any later version. + +The MPFR Library 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 Library General Public +License for more details. + +You should have received a copy of the GNU Library General Public License +along with the MPFR Library; see the file COPYING.LIB. If not, write to +the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, +MA 02111-1307, USA. */ + +#include <stdio.h> +#include "gmp.h" +#include "gmp-impl.h" +#include "mpfr.h" + +void +#if __STDC__ +mpfr_neg(mpfr_ptr a, mpfr_srcptr b, unsigned char rnd_mode) +#else +mpfr_neg(a, b, rnd_mode) + mpfr_ptr a; + mpfr_srcptr b; + unsigned char rnd_mode; +#endif +{ + if (a != b) mpfr_set4(a, b, rnd_mode, -SIGN(b)); + else CHANGE_SIGN(a); + return; +} diff --git a/mpfr/out_str.c b/mpfr/out_str.c new file mode 100644 index 000000000..aeaf64bd2 --- /dev/null +++ b/mpfr/out_str.c @@ -0,0 +1,65 @@ +/* mpfr_out_str -- output a floating-point number to a stream + +Copyright (C) 1999 PolKA project, Inria Lorraine and Loria + +This file is part of the MPFR Library. + +The MPFR Library is free software; you can redistribute it and/or modify +it under the terms of the GNU Library General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at your +option) any later version. + +The MPFR Library 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 Library General Public +License for more details. + +You should have received a copy of the GNU Library General Public License +along with the MPFR Library; see the file COPYING.LIB. If not, write to +the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, +MA 02111-1307, USA. */ + +#include <stdio.h> +#include <math.h> +#include "gmp.h" +#include "gmp-impl.h" +#include "mpfr.h" + +size_t +#if __STDC__ +mpfr_out_str (FILE *stream, int base, size_t n_digits, mpfr_srcptr op, + unsigned char rnd_mode) +#else +mpfr_out_str (stream, base, n_digits, op, rnd_mode) + FILE *stream; + int base; + size_t n_digits; + mpfr_srcptr op; + unsigned char rnd_mode; +#endif +{ + char *s,*s0; size_t l; mp_exp_t e; + + if (FLAG_NAN(op)) { fprintf(stream, "NaN"); return 3; } + if (!NOTZERO(op)) { fprintf(stream, "0"); return 1; } + + s = mpfr_get_str(NULL, &e, base, n_digits, op, rnd_mode); + s0 = s; + /* for op=3.1416 we have s = "31416" and e = 1 */ + + l = strlen(s)+1; + if (*s == '-') fputc(*s++, stream); + + fputc(*s++, stream); e--; /* writes leading digit */ + fputc('.', stream); /* decimal point */ + fputs(s, stream); /* rest of mantissa */ + if (e) { + fputc((base>10) ? '@' : 'e', stream); l++; + sprintf(s, "%ld", e); + l += strlen(s); + fprintf(stream, "%s", s); + } + + (*_mp_free_func)(s0, l); + return l; +} diff --git a/mpfr/pi.c b/mpfr/pi.c new file mode 100644 index 000000000..322a2ab1c --- /dev/null +++ b/mpfr/pi.c @@ -0,0 +1,131 @@ +/* mpfr_pi -- compute Pi + +Copyright (C) 1999 PolKA project, Inria Lorraine and Loria + +This file is part of the MPFR Library. + +The MPFR Library is free software; you can redistribute it and/or modify +it under the terms of the GNU Library General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at your +option) any later version. + +The MPFR Library 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 Library General Public +License for more details. + +You should have received a copy of the GNU Library General Public License +along with the MPFR Library; see the file COPYING.LIB. If not, write to +the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, +MA 02111-1307, USA. */ + +#include <stdio.h> +#include <math.h> +#include "gmp.h" +#include "gmp-impl.h" +#include "longlong.h" +#include "mpfr.h" + +/* +Set x to the value of Pi to precision PREC(x) rounded to direction rnd_mode. +Use the formula giving the binary representation of Pi found by Simon Plouffe +and the Borwein's brothers: + + infinity 4 2 1 1 + ----- ------- - ------- - ------- - ------- + \ 8 n + 1 8 n + 4 8 n + 5 8 n + 6 + Pi = ) ------------------------------------- + / n + ----- 16 + n = 0 + +i.e. Pi*16^N = S(N) + R(N) where +S(N) = sum(16^(N-n)*(4/(8*n+1)-2/(8*n+4)-1/(8*n+5)-1/(8*n+6)), n=0..N-1) +R(N) = sum((4/(8*n+1)-2/(8*n+4)-1/(8*n+5)-1/(8*n+6))/16^(n-N), n=N..infinity) + +Let f(n) = 4/(8*n+1)-2/(8*n+4)-1/(8*n+5)-1/(8*n+6), we can show easily that +f(n) < 15/(64*n^2), so R(N) < sum(15/(64*n^2)/16^(n-N), n=N..infinity) + < 15/64/N^2*sum(1/16^(n-N), n=N..infinity) + = 1/4/N^2 + +Now let S'(N) = sum(floor(16^(N-n)*(120*n^2+151*n+47), + (512*n^4+1024*n^3+712*n^2+194*n+15)), n=0..N-1) + +S(N)-S'(N) <= sum(1, n=0..N-1) = N + +so Pi*16^N-S'(N) <= N+1 (as 1/4/N^2 < 1) +*/ + +mpfr_t __mpfr_pi; /* stored value of Pi */ +int __mpfr_pi_prec=0; /* precision of stored value */ +char __mpfr_pi_rnd; /* rounding mode of stored value */ + +void +#if __STDC__ +mpfr_pi(mpfr_ptr x, unsigned char rnd_mode) +#else +mpfr_pi(x, rnd_mode) + mpfr_ptr x; + unsigned char rnd_mode; +#endif +{ + int N, oldN, n, prec; mpz_t pi, num, den, d3, d2, tmp; mpfr_t y; + + prec=PREC(x); + + /* has stored value enough precision ? */ + if ((prec==__mpfr_pi_prec && rnd_mode==__mpfr_pi_rnd) || + (prec<=__mpfr_pi_prec && + mpfr_can_round(__mpfr_pi, __mpfr_pi_prec, __mpfr_pi_rnd, rnd_mode, prec))) + { + mpfr_set(x, __mpfr_pi, rnd_mode); return; + } + + /* need to recompute */ + N=1; + do { + oldN = N; + N = (prec+3)/4 + (int)ceil(log((double)N+1.0)/log(2.0)); + } while (N != oldN); + mpz_init(pi); mpz_init(num); mpz_init(den); mpz_init(d3); mpz_init(d2); + mpz_init(tmp); + mpz_set_ui(pi, 0); + mpz_set_ui(num, 16); /* num(-1) */ + mpz_set_ui(den, 21); /* den(-1) */ + mpz_set_si(d3, -2454); + mpz_set_ui(d2, 14736); + /* invariants: num=120*n^2+151*n+47, den=512*n^4+1024*n^3+712*n^2+194*n+15 + d3 = 2048*n^3+400*n-6, d2 = 6144*n^2-6144*n+2448 + */ + for (n=0; n<N; n++) { + /* num(n)-num(n-1) = 240*n+31 */ + mpz_add_ui(num, num, 240*n+31); /* no overflow up to PREC=71M */ + /* d2(n) - d2(n-1) = 12288*(n-1) */ + if (n>0) mpz_add_ui(d2, d2, 12288*(n-1)); + else mpz_sub_ui(d2, d2, 12288); + /* d3(n) - d3(n-1) = d2 */ + mpz_add(d3, d3, d2); + /* den(n)-den(n-1) = 2048*n^3 + 400n - 6 = d3 */ + mpz_add(den, den, d3); + mpz_mul_2exp(tmp, num, 4*(N-n)); + mpz_fdiv_q(tmp, tmp, den); + mpz_add(pi, pi, tmp); + } + mpfr_set_z(x, pi, rnd_mode); + mpfr_init2(y, mpfr_get_prec(x)); + mpz_add_ui(pi, pi, N+1); + mpfr_set_z(y, pi, rnd_mode); + if (mpfr_cmp(x, y) != 0) { + fprintf(stderr, "does not converge\n"); exit(1); + } + EXP(x) -= 4*N; + mpz_clear(pi); mpz_clear(num); mpz_clear(den); mpz_clear(d3); mpz_clear(d2); + mpz_clear(tmp); mpfr_clear(y); + + /* store computed value */ + if (__mpfr_pi_prec==0) mpfr_init2(__mpfr_pi, prec); + else mpfr_set_prec(__mpfr_pi, prec); + mpfr_set(__mpfr_pi, x, rnd_mode); + __mpfr_pi_prec=prec; + __mpfr_pi_rnd=rnd_mode; +} diff --git a/mpfr/pow.c b/mpfr/pow.c new file mode 100644 index 000000000..c53819ec2 --- /dev/null +++ b/mpfr/pow.c @@ -0,0 +1,67 @@ +/* mpfr_pow_ui, mpfr_ui_pow_ui -- compute the power of a floating-point + number or machine integer + +Copyright (C) 1999 PolKA project, Inria Lorraine and Loria + +This file is part of the MPFR Library. + +The MPFR Library is free software; you can redistribute it and/or modify +it under the terms of the GNU Library General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at your +option) any later version. + +The MPFR Library 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 Library General Public +License for more details. + +You should have received a copy of the GNU Library General Public License +along with the MPFR Library; see the file COPYING.LIB. If not, write to +the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, +MA 02111-1307, USA. */ + +#include <stdio.h> +#include "gmp.h" +#include "mpfr.h" + +/* sets x to y^n */ +void +#if __STDC__ +mpfr_pow_ui (mpfr_ptr x, mpfr_srcptr y, unsigned int n, unsigned char rnd) +#else +mpfr_pow_ui (x, y, n, rnd) + mpfr_ptr x; + mpfr_srcptr y; + unsigned int n; + unsigned char rnd; +#endif +{ + int i; + + if (n==0) { mpfr_set_ui(x, 1, rnd); return; } + mpfr_set(x, y, rnd); + for (i=0;(1<<i)<=n;i++); + /* now 2^(i-1) <= n < 2^i */ + for (i-=2; i>=0; i--) { + mpfr_mul(x, x, x, rnd); + if (n & (1<<i)) mpfr_mul(x, x, y, rnd); + } + return; +} + +/* sets x to y^n */ +void mpfr_ui_pow_ui (mpfr_ptr x, unsigned int y, unsigned int n, + unsigned char rnd) +{ + int i; + + if (n==0) { mpfr_set_ui(x, 1, rnd); return; } + mpfr_set_ui(x, y, rnd); + for (i=0;(1<<i)<=n;i++); + /* now 2^(i-1) <= n < 2^i */ + for (i-=2; i>=0; i--) { + mpfr_mul(x, x, x, rnd); + if (n & (1<<i)) mpfr_mul_ui(x, x, y, rnd); + } + return; +} diff --git a/mpfr/print_raw.c b/mpfr/print_raw.c new file mode 100644 index 000000000..4ff68bcaf --- /dev/null +++ b/mpfr/print_raw.c @@ -0,0 +1,91 @@ +/* mpfr_print_raw -- print the internal binary representation of a + floating-point number + +Copyright (C) 1999 PolKA project, Inria Lorraine and Loria + +This file is part of the MPFR Library. + +The MPFR Library is free software; you can redistribute it and/or modify +it under the terms of the GNU Library General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at your +option) any later version. + +The MPFR Library 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 Library General Public +License for more details. + +You should have received a copy of the GNU Library General Public License +along with the MPFR Library; see the file COPYING.LIB. If not, write to +the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, +MA 02111-1307, USA. */ + +#include <stdio.h> +#include "gmp.h" +#include "gmp-impl.h" +#include "mpfr.h" + +void +#if __STDC__ +mpfr_get_str_raw(char *digit_ptr, mpfr_srcptr x) +#else +mpfr_get_str_raw(digit_ptr, x) + char *digit_ptr; + mpfr_srcptr x; +#endif +{ + mp_limb_t *mx, wd, t; long ex, sx, k, l, p; + + mx = MANT(x); + ex = EXP(x); + p = PREC(x); + + if (SIGN(x) < 0) { *digit_ptr = '-'; digit_ptr++; } + sprintf(digit_ptr, "0."); digit_ptr += 2; + + sx = 1+(p-1)/mp_bits_per_limb; /* number of significant limbs */ + for (k = sx - 1; k >= 0 ; k--) + { + wd = mx[k]; + t = ((mp_limb_t)1) << (BITS_PER_MP_LIMB - 1); + for (l = BITS_PER_MP_LIMB - 1; l>=0; l--) + { + if (wd & t) + { *digit_ptr = '1'; digit_ptr++; } + else + { *digit_ptr = '0'; digit_ptr++; } + t >>= 1; + if (--p==0) { *digit_ptr = '['; digit_ptr++; } + } + } + sprintf(digit_ptr, "]E%ld", ex); +} + +void +#if __STDC__ +mpfr_print_raw(mpfr_srcptr x) +#else +mpfr_print_raw(x) + mpfr_srcptr x; +#endif +{ + char *str; + + if (FLAG_NAN(x)) printf("NaN"); + else if (!NOTZERO(x)) printf("0"); + else { + /* 3 char for sign + 0 + binary point + + ABSSIZE(x) * BITS_PER_MP_LIMB for mantissa + + 2 for brackets in mantissa + + 1 for 'E' + + 11 for exponent (including sign) + = 17 + ABSSIZE(x) * BITS_PER_MP_LIMB + */ + str = (char *) malloc((17 + ABSSIZE(x) * BITS_PER_MP_LIMB)*sizeof(char)); + mpfr_get_str_raw(str, x); + + printf("%s", str); + free(str); + } +} + diff --git a/mpfr/print_rnd_mode.c b/mpfr/print_rnd_mode.c new file mode 100644 index 000000000..a7bc1d06d --- /dev/null +++ b/mpfr/print_rnd_mode.c @@ -0,0 +1,43 @@ +/* mpfr_print_rnd_mode -- convert a given rounding mode to a string + +Copyright (C) 1999 PolKA project, Inria Lorraine and Loria + +This file is part of the MPFR Library. + +The MPFR Library is free software; you can redistribute it and/or modify +it under the terms of the GNU Library General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at your +option) any later version. + +The MPFR Library 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 Library General Public +License for more details. + +You should have received a copy of the GNU Library General Public License +along with the MPFR Library; see the file COPYING.LIB. If not, write to +the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, +MA 02111-1307, USA. */ + +#include <stdio.h> +#include "gmp.h" +#include "gmp-impl.h" +#include "mpfr.h" + +char * +#if __STDC__ +mpfr_print_rnd_mode(unsigned char rnd_mode) +#else +mpfr_print_rnd_mode(rnd_mode) + unsigned char rnd_mode; +#endif +{ + switch (rnd_mode) + { + case GMP_RNDD: return("GMP_RNDD"); + case GMP_RNDU: return("GMP_RNDU"); + case GMP_RNDN: return("GMP_RNDN"); + case GMP_RNDZ: return("GMP_RNDZ"); + default: return("unknown rounding mode"); + } +} diff --git a/mpfr/random.c b/mpfr/random.c new file mode 100644 index 000000000..e61ddc0b7 --- /dev/null +++ b/mpfr/random.c @@ -0,0 +1,74 @@ +/* mpfr_random -- generate a random floating-point number + +Copyright (C) 1999 PolKA project, Inria Lorraine and Loria + +This file is part of the MPFR Library. + +The MPFR Library is free software; you can redistribute it and/or modify +it under the terms of the GNU Library General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at your +option) any later version. + +The MPFR Library 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 Library General Public +License for more details. + +You should have received a copy of the GNU Library General Public License +along with the MPFR Library; see the file COPYING.LIB. If not, write to +the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, +MA 02111-1307, USA. */ + +#include <stdio.h> +#include "gmp.h" +#include "gmp-impl.h" +#include "longlong.h" +#include "mpfr.h" + +/* Computes a random mpfr in [0, 1[ with precision PREC */ + +extern long random _PROTO((void)); +extern int srandom _PROTO((unsigned int)); + +/* extracted from GNU mpf */ +#if defined (__hpux) || defined (__alpha) +/* HPUX lacks random(). DEC OSF/1 1.2 random() returns a double. */ +#define random mrand48 +#define srandom srand48 +#endif + +void +#if __STDC__ +mpfr_random(mpfr_ptr x) +#else +mpfr_random(x) + mpfr_ptr x; +#endif +{ + mp_limb_t *xp; unsigned long xn, i, cnt, prec=PREC(x); + + xp = MANT(x); + xn = (prec-1)/BITS_PER_MP_LIMB + 1; + + for (i = 0; i < xn; i++) + { + /* random() c/sh/ould be replaced by a homemade random number generator. + Indeed, if on Linux random is a good RNG, this is definitely not + the case in most Un*xes. */ + xp[i] = random(); + } + + count_leading_zeros(cnt, xp[xn - 1]); + if (cnt) mpn_lshift(xp, xp, xn, cnt); + EXP(x) = -cnt; + + cnt = xn*BITS_PER_MP_LIMB - prec; + /* cnt is the number of non significant bits in the low limb */ + xp[0] &= ~((((mp_limb_t)1)<<cnt) - 1); +} + +void +mpfr_srandom(unsigned long seed) +{ + srandom(seed); +} diff --git a/mpfr/rnd_mode.c b/mpfr/rnd_mode.c new file mode 100644 index 000000000..9c37fb4c1 --- /dev/null +++ b/mpfr/rnd_mode.c @@ -0,0 +1,118 @@ +/* mpfr_set_machine_rnd_mode -- set the rounding mode for machine floats + +Copyright (C) 1999 PolKA project, Inria Lorraine and Loria + +This file is part of the MPFR Library. + +The MPFR Library is free software; you can redistribute it and/or modify +it under the terms of the GNU Library General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at your +option) any later version. + +The MPFR Library 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 Library General Public +License for more details. + +You should have received a copy of the GNU Library General Public License +along with the MPFR Library; see the file COPYING.LIB. If not, write to +the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, +MA 02111-1307, USA. */ + +#include <stdio.h> +#include "gmp.h" +#include "mpfr.h" + +/* functions to set/get the machine rounding mode */ +#ifdef _ISOC9X_SOURCE +#include <fenv.h> +#define TONEAREST fesetround(FE_TONEAREST) +#define TOZERO fesetround(FE_TOWARDZERO) +#define TOINFP fesetround(FE_UPWARD) +#define TOINFM fesetround(FE_DOWNWARD) +#elif IRIX64 +#include <sys/fpu.h> +extern int swapRM(); +#define TOZERO swapRM(ROUND_TO_ZERO) +#define TOINFP swapRM(ROUND_TO_PLUS_INFINITY) +#define TONEAREST swapRM(ROUND_TO_NEAREST) +#define TOINFM swapRM(ROUND_TO_MINUS_INFINITY) +#elif (defined (solaris) || defined (sun4) || defined(hpux)) +#ifdef hpux +#include <math.h> +#else +#include <ieeefp.h> +#endif +#define TOZERO fpsetround(FP_RZ) +#define TOINFP fpsetround(FP_RP) +#define TONEAREST fpsetround(FP_RN) +#define TOINFM fpsetround(FP_RM) +#elif alpha +#ifdef __GNUC__ +/* GCC patched include files forget to define those... */ +#define FP_RND_RZ 0 +#define FP_RND_RN 1 +#define FP_RND_RP 2 +#define FP_RND_RM 3 +#endif +#include <float.h> +#define TOZERO write_rnd(FP_RND_RZ) +#define TOINFP write_rnd(FP_RND_RP) +#define TONEAREST write_rnd(FP_RND_RN) +#define TOINFM write_rnd(FP_RND_RM) +#elif AIX +#include <float.h> +#define TOZERO fp_swap_rnd(FP_RND_RZ) +#define TOINFP fp_swap_rnd(FP_RND_RP) +#define TONEAREST fp_swap_rnd(FP_RND_RN) +#define TOINFM fp_swap_rnd(FP_RND_RM) +#elif sunos +#include <floatingpoint.h> +char *out; +#define TOZERO ieee_flags("set","direction","tozero",&out) +#define TOINFP ieee_flags("set","direction","positive",&out) +#define TONEAREST ieee_flags("set","direction","nearest",&out) +#define TOINFM ieee_flags("set","direction","negative",&out) +#elif (defined (__i386__) || defined (__i486__) || defined (linux)) +#ifdef __CYGWIN32__ /* no fpu_control.h under Cygnus */ +#define _FPU_EXTENDED 0x300 +#define _FPU_DOUBLE 0x200 +#define _FPU_DEFAULT 0x137f +#define _FPU_RC_NEAREST 0x0 +#define _FPU_RC_DOWN 0x400 +#define _FPU_RC_UP 0x800 +#define _FPU_RC_ZERO 0xC00 +#else +#include <fpu_control.h> +#endif +#if defined(LIBC211) || defined(__CYGWIN32__) +#define __setfpucw(cw) __asm__ ("fldcw %0" : : "m" (cw)) +#endif +/* be careful to put Precision control bits + to round to double precision instead of the + default (round to extended precision) */ +#define _fpu_ieee ((_FPU_DEFAULT & (~_FPU_EXTENDED)) | _FPU_DOUBLE) +#define TOZERO __setfpucw(_fpu_ieee | _FPU_RC_ZERO) +#define TOINFP __setfpucw(_fpu_ieee | _FPU_RC_UP) +#define TOINFM __setfpucw(_fpu_ieee | _FPU_RC_DOWN) +#define TONEAREST __setfpucw(_fpu_ieee) +#endif + +/* sets the machine rounding mode to the value rnd_mode */ +void +#if __STDC__ +mpfr_set_machine_rnd_mode(unsigned char rnd_mode) +#else +mpfr_set_machine_rnd_mode(rnd_mode) + unsigned char rnd_mode; +#endif +{ + switch (rnd_mode) { + case GMP_RNDN: TONEAREST; break; + case GMP_RNDZ: TOZERO; break; + case GMP_RNDU: TOINFP; break; + case GMP_RNDD: TOINFM; break; + default: fprintf(stderr,"invalid rounding mode\n"); exit(1); + } +} + diff --git a/mpfr/round.c b/mpfr/round.c new file mode 100644 index 000000000..9fad4c47e --- /dev/null +++ b/mpfr/round.c @@ -0,0 +1,338 @@ +/* mpfr_round_raw2, mpfr_round_raw, mpfr_round, mpfr_can_round, + mpfr_can_round_raw -- various rounding functions + +Copyright (C) 1999 PolKA project, Inria Lorraine and Loria + +This file is part of the MPFR Library. + +The MPFR Library is free software; you can redistribute it and/or modify +it under the terms of the GNU Library General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at your +option) any later version. + +The MPFR Library 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 Library General Public +License for more details. + +You should have received a copy of the GNU Library General Public License +along with the MPFR Library; see the file COPYING.LIB. If not, write to +the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, +MA 02111-1307, USA. */ + +#include <stdio.h> +#include "gmp.h" +#include "gmp-impl.h" +#include "mpfr.h" + +#ifdef Exp +#include "longlong.h" +#endif + +/* returns 0 if round(sign*xp[0..xn-1], prec, rnd) = + round(sign*xp[0..xn-1], prec, GMP_RNDZ), 1 otherwise, + where sign=1 if neg=0, sign=-1 otherwise. + + Does *not* modify anything. +*/ +int +#if __STDC__ +mpfr_round_raw2(mp_limb_t *xp, unsigned long xn, + char neg, char rnd, unsigned long prec) +#else +mpfr_round_raw2(xp, xn, neg, rnd, prec) + mp_limb_t *xp; + unsigned long xn; + char neg; + char rnd; + unsigned long prec; +#endif +{ + unsigned long nw; long wd; char rw; short l; mp_limb_t mask; + + nw = prec / BITS_PER_MP_LIMB; rw = prec & (BITS_PER_MP_LIMB - 1); + if (rw) nw++; + if (rnd==GMP_RNDZ || xn<nw || (rnd==GMP_RNDU && neg) + || (rnd==GMP_RNDD && neg==0)) return 0; + + mask = ~((((mp_limb_t)1)<<(BITS_PER_MP_LIMB - rw)) - 1); + switch (rnd) + { + case GMP_RNDU: + case GMP_RNDD: + if (xp[xn - nw] & ~mask) return 1; + for (l = nw + 1;l <= xn; l++) + if (xp[xn - l]) break; + return (l <= xn); + + case GMP_RNDN: + /* First check if we are just halfway between two representable numbers */ + wd = xn - nw; + if (!rw) + { + if (!wd) /* all bits are significative */ return 0; + wd--; + if (xp[wd] == ((mp_limb_t)1 << (BITS_PER_MP_LIMB - 1))) + { + do wd--; while (wd > 0 && !xp[wd]); + if (!wd) { return 1; } else return xp[xn - nw] & 1; + } + + return xp[wd]>>(BITS_PER_MP_LIMB - 1); + } + else + if (rw + 1 < BITS_PER_MP_LIMB) + { + if ((xp[wd] & (~mask)) == (((mp_limb_t)1) << (BITS_PER_MP_LIMB - rw - 1))) + do { wd--; } while (wd >= 0 && !xp[wd]); + else return ((xp[wd]>>(BITS_PER_MP_LIMB - rw - 1)) & 1); + + /* first limb was in the middle, and others down to wd+1 were 0 */ + if (wd>=0) return 1; + else + return ((xp[xn - nw] & mask) >> (BITS_PER_MP_LIMB - rw)) & 1; + } + else + /* Modified PZ, 27 May 1999: + rw, i.e. the number of bits stored in xp[xn-nw], is + BITS_PER_MP_LIMB-1, i.e. there is exactly one non significant bit. + We are just halfway iff xp[wd] has its low significant bit + set and all limbs xp[0]...xp[wd-1] are zero */ + { + if (xp[wd] & 1) + do wd--; while (wd >= 0 && !xp[wd]); + return ((wd<0) ? xp[xn-nw]>>1 : xp[xn-nw]) & 1; + } + default: return 0; + } +} + +/* puts in y the value of xp (with precision xprec and sign 1 if negative=0, + -1 otherwise) rounded to precision yprec and direction RND_MODE + Supposes x is not zero nor NaN nor +/- Infinity (i.e. *xp != 0). +*/ +int +#if __STDC__ +mpfr_round_raw(mp_limb_t *y, mp_limb_t *xp, unsigned long xprec, char negative, + unsigned long yprec, char RND_MODE) +#else +mpfr_round_raw(y, xp, xprec, negative, yprec, RND_MODE) + mp_limb_t *y; + mp_limb_t *xp; + unsigned long xprec; + cher negative; + unsigned long yprec; + char RND_MODE; +#endif +{ + unsigned long nw, xsize; mp_limb_t mask; + char rw, xrw, carry = 0; + + xsize = (xprec-1)/BITS_PER_MP_LIMB + 1; + xrw = xprec % BITS_PER_MP_LIMB; if (xrw == 0) { xrw = BITS_PER_MP_LIMB; } + +#ifdef Exp + count_leading_zeros(flag, xp[xsize-1]); + yprec += flag; +#endif + + nw = yprec / BITS_PER_MP_LIMB; rw = yprec & (BITS_PER_MP_LIMB - 1); + if (rw) nw++; + /* number of words needed to represent x */ + + mask = ~((((mp_limb_t)1)<<(BITS_PER_MP_LIMB - rw)) - (mp_limb_t)1); + + /* precision is larger than the size of x. No rounding is necessary. + Just add zeroes at the end */ + if (xsize < nw) { + MPN_COPY(y + nw - xsize, xp, xsize); + MPN_ZERO(y, nw - xsize); /* PZ 27 May 99 */ + y[0] &= mask; + return 0; + } + + if (mpfr_round_raw2(xp, xsize, negative, RND_MODE, yprec)) + carry = mpn_add_1(y, xp + xsize - nw, nw, + ((mp_limb_t)1) << (BITS_PER_MP_LIMB - rw)); + else MPN_COPY(y, xp + xsize - nw, nw); + + y[0] &= mask; + return carry; +} + +void +#if __STDC__ +mpfr_round(mpfr_t x, char RND_MODE, unsigned long prec) +#else +mpfr_round(x, RND_MODE, prec) + mpfr_t x; + char RND_MODE; + unsigned long prec; +#endif +{ + mp_limb_t *tmp; int carry; unsigned long nw; + TMP_DECL(marker); + + nw = prec / BITS_PER_MP_LIMB; + if (prec & (BITS_PER_MP_LIMB - 1)) nw++; + TMP_MARK(marker); + tmp = TMP_ALLOC (nw * BYTES_PER_MP_LIMB); + carry = mpfr_round_raw(tmp, MANT(x), PREC(x), (SIGN(x)<0), prec, RND_MODE); + + if (carry) + { + mpn_rshift(tmp, tmp, nw, 1); + tmp [nw-1] |= (((mp_limb_t)1) << (BITS_PER_MP_LIMB - 1)); + EXP(x)++; + } + + if (SIGN(x)<0) { SIZE(x)=nw; CHANGE_SIGN(x); } else SIZE(x)=nw; + PREC(x) = prec; + MPN_COPY(MANT(x), tmp, nw); + TMP_FREE(marker); +} + +/* hypotheses : BITS_PER_MP_LIMB est une puissance de 2 + dans un test, la premiere partie du && est evaluee d'abord */ + + +/* assuming b is an approximation of x in direction rnd1 + with error at most 2^(EXP(b)-err), returns 1 if one is + able to round exactly x to precision prec with direction rnd2, + and 0 otherwise. + + Side effects: none. +*/ + +int +#if __STDC__ +mpfr_can_round(mpfr_t b, unsigned long err, unsigned char rnd1, + unsigned char rnd2, unsigned long prec) +#else +mpfr_can_round(b, err, rnd1, rnd2, prec) + mpfr_t b; + unsigned long err; + unsigned char rnd1; + unsigned char rnd2; + unsigned long prec; +#endif +{ + return mpfr_can_round_raw(MANT(b), (PREC(b) - 1)/BITS_PER_MP_LIMB + 1, + SIGN(b), err, rnd1, rnd2, prec); +} + +int +#if __STDC__ +mpfr_can_round_raw(mp_limb_t *bp, unsigned long bn, int neg, + unsigned long err, unsigned char rnd1, unsigned char rnd2, + unsigned long prec) +#else +mpfr_can_round_raw(bp, bn, neg, err, rnd1, rnd2, prec) + mp_limb_t *bp; + unsigned long bn; + int neg; + unsigned long err; + unsigned char rnd1; + unsigned char rnd2; + unsigned long prec; +#endif +{ + int k, k1, l, l1, tn; mp_limb_t cc, cc2, *tmp; + TMP_DECL(marker); + + if (err<=prec) return 0; + neg = (neg > 0 ? 0 : 1); + + /* warning: if k = m*BITS_PER_MP_LIMB, consider limb m-1 and not m */ + k = (err-1)/BITS_PER_MP_LIMB; + l = err % BITS_PER_MP_LIMB; if (l) l = BITS_PER_MP_LIMB-l; + /* the error corresponds to bit l in limb k */ + k1 = (prec-1)/BITS_PER_MP_LIMB; + l1 = prec%BITS_PER_MP_LIMB; if (l1) l1 = BITS_PER_MP_LIMB-l1; + + /* the last significant bit is bit l1 in limb k1 */ + + /* don't need to consider the k1 most significant limbs */ + k -= k1; bn -= k1; prec -= k1*BITS_PER_MP_LIMB; k1=0; + + if (rnd1==GMP_RNDU) { if (neg) rnd1=GMP_RNDZ; } + if (rnd1==GMP_RNDD) { if (neg) rnd1=GMP_RNDU; else rnd1=GMP_RNDZ; } + + /* in the sequel, RNDU = towards infinity, RNDZ = towards zero */ + + TMP_MARK(marker); + tn = bn; + k++; /* since we work with k+1 everywhere */ + + switch (rnd1) { + + case GMP_RNDZ: /* b <= x <= b+2^(EXP(b)-err) */ + tmp = TMP_ALLOC(tn*BYTES_PER_MP_LIMB); + cc = (bp[bn-1]>>l1) & 1; + cc ^= mpfr_round_raw2(bp, bn, neg, rnd2, prec); + + /* now round b+2^(EXP(b)-err) */ + cc2 = mpn_add_1(tmp+bn-k, bp+bn-k, k, (mp_limb_t)1<<l); + /* if carry, then all bits up to err were to 1, and we can round only + if cc==0 and mpfr_round_raw2 returns 0 below */ + if (cc2 && cc) { TMP_FREE(marker); return 0; } + cc2 = (tmp[bn-1]>>l1) & 1; /* gives 0 when carry */ + cc2 ^= mpfr_round_raw2(tmp, bn, neg, rnd2, prec); + + TMP_FREE(marker); + return (cc == cc2); + + case GMP_RNDU: /* b-2^(EXP(b)-err) <= x <= b */ + tmp = TMP_ALLOC(tn*BYTES_PER_MP_LIMB); + /* first round b */ + cc = (bp[bn-1]>>l1) & 1; + cc ^= mpfr_round_raw2(bp, bn, neg, rnd2, prec); + + /* now round b-2^(EXP(b)-err) */ + cc2 = mpn_sub_1(tmp+bn-k, bp+bn-k, k, (mp_limb_t)1<<l); + /* if borrow, then all bits up to err were to 0, and we can round only + if cc==0 and mpfr_round_raw2 returns 1 below */ + if (cc2 && cc) { TMP_FREE(marker); return 0; } + cc2 = (tmp[bn-1]>>l1) & 1; /* gives 1 when carry */ + cc2 ^= mpfr_round_raw2(tmp, bn, neg, rnd2, prec); + + TMP_FREE(marker); + return (cc == cc2); + + case GMP_RNDN: /* b-2^(EXP(b)-err-1) <= x <= b+2^(EXP(b)-err-1) */ + if (l==0) tn++; + tmp = TMP_ALLOC(tn*BYTES_PER_MP_LIMB); + + /* this case is the same than GMP_RNDZ, except we first have to + subtract 2^(EXP(b)-err-1) from b */ + + if (l) { + l--; /* tn=bn */ + mpn_sub_1(tmp+tn-k, bp+bn-k, k, (mp_limb_t)1<<l); + } + else { + MPN_COPY(tmp+1, bp, bn); *tmp=0; /* extra limb to add or subtract 1 */ + k++; l=BITS_PER_MP_LIMB-1; + mpn_sub_1(tmp+tn-k, tmp+tn-k, k, (mp_limb_t)1<<l); + } + + /* round b-2^(EXP(b)-err-1) */ + /* we can disregard borrow, since we start from tmp in 2nd case too */ + cc = (tmp[tn-1]>>l1) & 1; + cc ^= mpfr_round_raw2(tmp, tn, neg, rnd2, prec); + + if (l==BITS_PER_MP_LIMB-1) { l=0; k--; } else l++; + + /* round b+2^(EXP(b)-err-1) = b-2^(EXP(b)-err-1) + 2^(EXP(b)-err) */ + cc2 = mpn_add_1(tmp+tn-k, tmp+tn-k, k, (mp_limb_t)1<<l); + /* if carry, then all bits up to err were to 1, and we can round only + if cc==0 and mpfr_round_raw2 returns 0 below */ + if (cc2 && cc) { TMP_FREE(marker); return 0; } + cc2 = (tmp[tn-1]>>l1) & 1; /* gives 0 when carry */ + cc2 ^= mpfr_round_raw2(tmp, tn, neg, rnd2, prec); + + TMP_FREE(marker); + return (cc == cc2); + } + return 0; +} diff --git a/mpfr/set.c b/mpfr/set.c new file mode 100644 index 000000000..b4a151dc5 --- /dev/null +++ b/mpfr/set.c @@ -0,0 +1,53 @@ +/* mpfr_set -- copy of a floating-point number + +Copyright (C) 1999 PolKA project, Inria Lorraine and Loria + +This file is part of the MPFR Library. + +The MPFR Library is free software; you can redistribute it and/or modify +it under the terms of the GNU Library General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at your +option) any later version. + +The MPFR Library 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 Library General Public +License for more details. + +You should have received a copy of the GNU Library General Public License +along with the MPFR Library; see the file COPYING.LIB. If not, write to +the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, +MA 02111-1307, USA. */ + +#include <stdio.h> +#include "gmp.h" +#include "gmp-impl.h" +#include "mpfr.h" + +void +#if __STDC__ +mpfr_set4(mpfr_ptr a, mpfr_srcptr b, unsigned char rnd_mode, int signb) +#else +mpfr_set4(a, b, rnd_mode) + mpfr_ptr a; + mpfr_srcptr b; + unsigned char rnd_mode; + int signb; +#endif +{ + int carry, an, preca = PREC(a), sh; mp_limb_t *ap = MANT(a); + + carry = mpfr_round_raw(ap, MANT(b), PREC(b), (signb<0), preca, rnd_mode); + EXP(a) = EXP(b); + if (carry) { + an = (preca-1)/BITS_PER_MP_LIMB + 1; + sh = an * BITS_PER_MP_LIMB - preca; + if ((*ap >> sh) & 1) { + fprintf(stderr, "unable to round in mpfr_set\n"); exit(1); + } + mpn_rshift(ap, ap, an, 1); + ap[an-1] |= (mp_limb_t) 1 << (BITS_PER_MP_LIMB-1); + EXP(a)++; + } + if (SIGN(a) != signb) CHANGE_SIGN(a); +} diff --git a/mpfr/set_d.c b/mpfr/set_d.c new file mode 100644 index 000000000..4863aca76 --- /dev/null +++ b/mpfr/set_d.c @@ -0,0 +1,329 @@ +/* mpfr_set_d, mpfr_get_d -- convert a multiple precision floating-point number + from/to a machine double precision float + +Copyright (C) 1999 PolKA project, Inria Lorraine and Loria + +This file is part of the MPFR Library. + +The MPFR Library is free software; you can redistribute it and/or modify +it under the terms of the GNU Library General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at your +option) any later version. + +The MPFR Library 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 Library General Public +License for more details. + +You should have received a copy of the GNU Library General Public License +along with the MPFR Library; see the file COPYING.LIB. If not, write to +the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, +MA 02111-1307, USA. */ + +#if __GNUC__ /* gcc "patched" headers seem to omit isnan... */ +extern int isnan(double); +#endif +#include <math.h> /* for isnan and NaN */ + +#include "gmp.h" +#include "gmp-impl.h" +#include "longlong.h" +#include "mpfr.h" + +#define NaN sqrt(-1) /* ensures a machine-independent NaN */ + +/* Included from gmp-2.0.2, patched to support denorms */ + +#ifdef XDEBUG +#undef _GMP_IEEE_FLOATS +#endif + +#ifndef _GMP_IEEE_FLOATS +#define _GMP_IEEE_FLOATS 0 +#endif + +int +#if __STDC__ +__mpfr_extract_double (mp_ptr rp, double d, int e) +#else +__mpfr_extract_double (rp, d) + mp_ptr rp; + double d; + int e; +#endif + /* e=0 iff BITS_PER_MP_LIMB=32 and rp has only one limb */ +{ + long exp; + mp_limb_t manl; +#if BITS_PER_MP_LIMB == 32 + mp_limb_t manh; +#endif + + /* BUGS + + 1. Should handle Inf and NaN in IEEE specific code. + 2. Handle Inf and NaN also in default code, to avoid hangs. + 3. Generalize to handle all BITS_PER_MP_LIMB >= 32. + 4. This lits is incomplete and misspelled. + */ + + if (d == 0.0) + { + rp[0] = 0; +#if BITS_PER_MP_LIMB == 32 + if (e) rp[1] = 0; +#endif + return 0; + } + +#if _GMP_IEEE_FLOATS + { + union ieee_double_extract x; + x.d = d; + + exp = x.s.exp; + if (exp) + { +#if BITS_PER_MP_LIMB == 64 + manl = (((mp_limb_t) 1 << 63) + | ((mp_limb_t) x.s.manh << 43) | ((mp_limb_t) x.s.manl << 11)); +#else + manh = ((mp_limb_t) 1 << 31) | (x.s.manh << 11) | (x.s.manl >> 21); + manl = x.s.manl << 11; +#endif + } + else + { +#if BITS_PER_MP_LIMB == 64 + manl = ((mp_limb_t) x.s.manh << 43) | ((mp_limb_t) x.s.manl << 11); +#else + manh = (x.s.manh << 11) | (x.s.manl >> 21); + manl = x.s.manl << 11; +#endif + } + } +#else + { + /* Unknown (or known to be non-IEEE) double format. */ + exp = 0; + if (d >= 1.0) + { + if (d * 0.5 == d) + abort (); + + while (d >= 32768.0) + { + d *= (1.0 / 65536.0); + exp += 16; + } + while (d >= 1.0) + { + d *= 0.5; + exp += 1; + } + } + else if (d < 0.5) + { + while (d < (1.0 / 65536.0)) + { + d *= 65536.0; + exp -= 16; + } + while (d < 0.5) + { + d *= 2.0; + exp -= 1; + } + } + + d *= MP_BASE_AS_DOUBLE; +#if BITS_PER_MP_LIMB == 64 + manl = d; +#else + manh = d; + manl = (d - manh) * MP_BASE_AS_DOUBLE; +#endif + + exp += 1022; + } +#endif + + if (exp) exp = (unsigned) exp - 1022; else exp = -1021; + +#if BITS_PER_MP_LIMB == 64 + rp[0] = manl; +#else + if (e) { + rp[1] = manh; + rp[0] = manl; + } + else { + rp[0] = manh; + } +#endif + + return exp; +} + +/* End of part included from gmp-2.0.2 */ +/* Part included from gmp temporary releases */ +double +#if __STDC__ +__mpfr_scale2 (double d, int exp) +#else +__mpfr_scale2 (d, exp) + double d; + int exp; +#endif +{ +#if _GMP_IEEE_FLOATS + { + union ieee_double_extract x; + x.d = d; + exp += x.s.exp; + x.s.exp = exp; + if (exp >= 2047) + { + /* Return +-infinity */ + x.s.exp = 2047; + x.s.manl = x.s.manh = 0; + } + else if (exp < 1) + { + x.s.exp = 1; /* smallest exponent (biased) */ + /* Divide result by 2 until we have scaled it to the right IEEE + denormalized number, but stop if it becomes zero. */ + while (exp < 1 && x.d != 0) + { + x.d *= 0.5; + exp++; + } + } + return x.d; + } +#else + { + double factor, r; + + factor = 2.0; + if (exp < 0) + { + factor = 0.5; + exp = -exp; + } + r = d; + if (exp != 0) + { + if ((exp & 1) != 0) + r *= factor; + exp >>= 1; + while (exp != 0) + { + factor *= factor; + if ((exp & 1) != 0) + r *= factor; + exp >>= 1; + } + } + return r; + } +#endif +} + + +/* End of part included from gmp */ + +void +#if __STDC__ +mpfr_set_d(mpfr_t r, double d, unsigned char rnd_mode) +#else +mpfr_set_d(r, d, rnd_mode) + mpfr_t r; + double d; + unsigned char rnd_mode; +#endif +{ + int signd, sizer; unsigned int cnt; + + if (d == 0) { SET_ZERO(r); return; } + else if (isnan(d)) { SET_NAN(r); return; } + + signd = (d < 0) ? -1 : 1; + d = ABS (d); + sizer = (PREC(r)-1)/BITS_PER_MP_LIMB + 1; + + /* warning: __mpfr_extract_double requires at least two limbs */ + if (sizer < MPFR_LIMBS_PER_DOUBLE) + EXP(r) = __mpfr_extract_double (MANT(r), d, 0); + else + EXP(r) = __mpfr_extract_double (MANT(r) + sizer - MPFR_LIMBS_PER_DOUBLE, d, 1); + + if (sizer > MPFR_LIMBS_PER_DOUBLE) + MPN_ZERO(MANT(r), sizer - MPFR_LIMBS_PER_DOUBLE); + + count_leading_zeros(cnt, MANT(r)[sizer-1]); + if (cnt) mpn_lshift(MANT(r), MANT(r), sizer, cnt); + + EXP(r) -= cnt; + if (SIZE(r)*signd<0) CHANGE_SIGN(r); + + mpfr_round(r, rnd_mode, PREC(r)); + return; +} + +double +#if __STDC__ +mpfr_get_d2(mpfr_srcptr src, long e) +#else +mpfr_get_d2(src, e) + mpfr_srcptr(src); + long e; +#endif +{ + double res; + mp_size_t size, i, n_limbs_to_use; + mp_ptr qp; + int negative; + + if (FLAG_NAN(src)) { +#ifdef DEBUG + printf("recognized NaN\n"); +#endif + return NaN; } + if (NOTZERO(src)==0) return 0.0; + size = 1+(PREC(src)-1)/BITS_PER_MP_LIMB; + qp = MANT(src); + negative = (SIGN(src)==-1); + + /* Warning: don't compute the abs(res) and set the sign afterwards, + otherwise the current machine rounding mode will not be taken + correctly into account. */ + /* res = (negative) ? -(double)qp[size - 1] : qp[size - 1]; */ + res = 0.0; + /* Warning: an arbitrary number of limbs may be required for an exact + rounding. The following code is correct but not optimal since one + may be able to decide without considering all limbs. */ + /* n_limbs_to_use = MIN (MPFR_LIMBS_PER_DOUBLE, size); */ + n_limbs_to_use = size; + /* Accumulate the limbs from less significant to most significant + otherwise due to rounding we may accumulate several ulps, + especially in rounding towards -/+infinity. */ + for (i = n_limbs_to_use; i>=1; i--) + res = res / MP_BASE_AS_DOUBLE + + ((negative) ? -(double)qp[size - i] : qp[size - i]); + res = __mpfr_scale2 (res, e - BITS_PER_MP_LIMB); + + return res; +} + +double +#if __STDC__ +mpfr_get_d(mpfr_srcptr src) +#else +mpfr_get_d(src) + mpfr_srcptr src; +#endif +{ + return mpfr_get_d2(src, EXP(src)); +} + diff --git a/mpfr/set_dfl_prec.c b/mpfr/set_dfl_prec.c new file mode 100644 index 000000000..aa341be8a --- /dev/null +++ b/mpfr/set_dfl_prec.c @@ -0,0 +1,37 @@ +/* mpfr_set_default_prec -- set the default precision + +Copyright (C) 1999 PolKA project, Inria Lorraine and Loria + +This file is part of the MPFR Library. + +The MPFR Library is free software; you can redistribute it and/or modify +it under the terms of the GNU Library General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at your +option) any later version. + +The MPFR Library 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 Library General Public +License for more details. + +You should have received a copy of the GNU Library General Public License +along with the MPFR Library; see the file COPYING.LIB. If not, write to +the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, +MA 02111-1307, USA. */ + +#include "gmp.h" +#include "gmp-impl.h" + +/* default is 53 bits */ +mp_size_t __gmp_default_fp_bit_precision = 53; + +void +#if __STDC__ +mpfr_set_default_prec (unsigned long int prec_in_bits) +#else +mpfr_set_default_prec (prec_in_bits) + unsigned long int prec_in_bits; +#endif +{ + __gmp_default_fp_bit_precision = prec_in_bits; +} diff --git a/mpfr/set_dfl_rnd.c b/mpfr/set_dfl_rnd.c new file mode 100644 index 000000000..cf8fd0175 --- /dev/null +++ b/mpfr/set_dfl_rnd.c @@ -0,0 +1,37 @@ +/* mpfr_set_default_rounding_mode -- set the default rounding mode + +Copyright (C) 1999 PolKA project, Inria Lorraine and Loria + +This file is part of the MPFR Library. + +The MPFR Library is free software; you can redistribute it and/or modify +it under the terms of the GNU Library General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at your +option) any later version. + +The MPFR Library 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 Library General Public +License for more details. + +You should have received a copy of the GNU Library General Public License +along with the MPFR Library; see the file COPYING.LIB. If not, write to +the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, +MA 02111-1307, USA. */ + +#include "gmp.h" +#include "gmp-impl.h" + +char __gmp_default_rounding_mode = 0; + +void +#if __STDC__ +mpfr_set_default_rounding_mode (char rnd_mode) +#else +mpfr_set_default_rounding_mode (rnd_mode) + char rnd_mode; +#endif +{ + __gmp_default_rounding_mode = rnd_mode; +} + diff --git a/mpfr/set_f.c b/mpfr/set_f.c new file mode 100644 index 000000000..d3bb98dbf --- /dev/null +++ b/mpfr/set_f.c @@ -0,0 +1,72 @@ +/* mpfr_set_f -- set a MPFR number from a GNU MPF number + +Copyright (C) 1999-2000 PolKA project, Inria Lorraine and Loria + +This file is part of the MPFR Library. + +The MPFR Library is free software; you can redistribute it and/or modify +it under the terms of the GNU Library General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at your +option) any later version. + +The MPFR Library 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 Library General Public +License for more details. + +You should have received a copy of the GNU Library General Public License +along with the MPFR Library; see the file COPYING.LIB. If not, write to +the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, +MA 02111-1307, USA. */ + +#include <stdio.h> +#include "gmp.h" +#include "gmp-impl.h" +#include "longlong.h" +#include "mpfr.h" + +void +#if __STDC__ +mpfr_set_f(mpfr_ptr y, mpf_srcptr x, char rnd_mode) +#else +mpfr_set_f(y, x, rnd_mode) + mpfr_ptr y; + mpf_srcptr x; + char rnd_mode; +#endif +{ + mp_limb_t *my, *mx, *tmp; unsigned long cnt, sx, sy; + TMP_DECL(marker); + + sx = ABS(SIZ(x)); sy = ABSSIZE(y); + my = MANT(y); mx = MANT(x); + + if (sx==0) { /* x is zero */ + SET_ZERO(y); return; + } + + count_leading_zeros(cnt, mx[sx - 1]); + + if (SIZ(x)*SIGN(y)<0) CHANGE_SIGN(y); + + if (sy < sx) + { + unsigned long xprec = sx * BITS_PER_MP_LIMB; + + tmp = (mp_limb_t*) TMP_ALLOC(xprec); + if (cnt) mpn_lshift(tmp, mx, sx, cnt); + else MPN_COPY(tmp, mx, sx); + mpfr_round_raw(my, tmp, xprec, (SIZ(x)<0), PREC(y), rnd_mode); + } + else + { + if (cnt) mpn_lshift(my + sy - sx, mx, sx, cnt); + else MPN_COPY(my + sy - sx, mx, sy); + MPN_ZERO(my, sy - sx); + /* no rounding necessary, since y has a larger mantissa */ + } + + EXP(y) = EXP(x) * BITS_PER_MP_LIMB - cnt; + + TMP_FREE(marker); +} diff --git a/mpfr/set_prec.c b/mpfr/set_prec.c new file mode 100644 index 000000000..d85eac3c3 --- /dev/null +++ b/mpfr/set_prec.c @@ -0,0 +1,62 @@ +/* mpfr_set_prec -- reset the precision of a floating-point number + +Copyright (C) 1999 PolKA project, Inria Lorraine and Loria + +This file is part of the MPFR Library. + +The MPFR Library is free software; you can redistribute it and/or modify +it under the terms of the GNU Library General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at your +option) any later version. + +The MPFR Library 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 Library General Public +License for more details. + +You should have received a copy of the GNU Library General Public License +along with the MPFR Library; see the file COPYING.LIB. If not, write to +the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, +MA 02111-1307, USA. */ + +#include <stdio.h> +#include "gmp.h" +#include "gmp-impl.h" +#include "mpfr.h" + +void +#if __STDC__ +mpfr_set_prec (mpfr_t x, unsigned long int p) +#else +mpfr_set_prec (x, p) + mpfr_t x; + unsigned long int p; +#endif +{ + unsigned long xsize; + + if (p==0) { + printf("*** cannot set precision to 0 bits\n"); exit(1); + } + + xsize = (p - 1)/BITS_PER_MP_LIMB + 1; /* new limb size */ + + if (xsize > ABSSIZE(x)) { + x -> _mp_d = (mp_ptr) (*_mp_reallocate_func) + (x -> _mp_d, ABSSIZE(x)*BYTES_PER_MP_LIMB, xsize * BYTES_PER_MP_LIMB); + SIZE(x) = xsize; /* new number of allocated limbs */ + } + + x -> _mp_prec = p; +} + +unsigned long int +#if __STDC__ +mpfr_get_prec (mpfr_t x) +#else +mpfr_get_prec (x) + mpfr_t x; +#endif +{ + return x -> _mp_prec; +} diff --git a/mpfr/set_si.c b/mpfr/set_si.c new file mode 100644 index 000000000..b2d916cd1 --- /dev/null +++ b/mpfr/set_si.c @@ -0,0 +1,81 @@ +/* mpfr_set_si, mpfr_set_ui -- set a MPFR number from a machine integer + +Copyright (C) 1999 PolKA project, Inria Lorraine and Loria + +This file is part of the MPFR Library. + +The MPFR Library is free software; you can redistribute it and/or modify +it under the terms of the GNU Library General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at your +option) any later version. + +The MPFR Library 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 Library General Public +License for more details. + +You should have received a copy of the GNU Library General Public License +along with the MPFR Library; see the file COPYING.LIB. If not, write to +the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, +MA 02111-1307, USA. */ + +#include <stdio.h> +#include "gmp.h" +#include "gmp-impl.h" +#include "longlong.h" +#include "mpfr.h" + +void +#if __STDC__ +mpfr_set_si(mpfr_ptr x, long i, unsigned char rnd_mode) +#else +mpfr_set_si(x, i, rnd_mode) + mpfr_ptr x; + long i; + unsigned char rnd_mode; +#endif +{ + unsigned long xn, cnt; mp_limb_t ai; + + if (i==0) { SET_ZERO(x); return; } + xn = (PREC(x)-1)/BITS_PER_MP_LIMB; + ai = ABS(i); + + count_leading_zeros(cnt, ai); + + x -> _mp_d[xn] = ai << cnt; + /* don't forget to put zero in lower limbs */ + MPN_ZERO(MANT(x), xn); + x -> _mp_exp = BITS_PER_MP_LIMB - cnt; + /* warning: don't change the precision of x! */ + if (i*SIGN(x) < 0) CHANGE_SIGN(x); + + return; +} + +void +#if __STDC__ +mpfr_set_ui(mpfr_ptr x, unsigned long i, unsigned char rnd_mode) +#else +mpfr_set_ui(x, i, rnd_mode) + mpfr_ptr x; + long i; + unsigned char rnd_mode; +#endif +{ + unsigned int xn, cnt; + + if (i==0) { SET_ZERO(x); return; } + xn = (PREC(x)-1)/BITS_PER_MP_LIMB; + count_leading_zeros(cnt, (mp_limb_t) i); + + x -> _mp_d[xn] = ((mp_limb_t) i) << cnt; + /* don't forget to put zero in lower limbs */ + MPN_ZERO(MANT(x), xn); + x -> _mp_exp = BITS_PER_MP_LIMB - cnt; + /* warning: don't change the precision of x! */ + if (SIGN(x) < 0) CHANGE_SIGN(x); + + return; +} + diff --git a/mpfr/set_str_raw.c b/mpfr/set_str_raw.c new file mode 100644 index 000000000..d0945c4bc --- /dev/null +++ b/mpfr/set_str_raw.c @@ -0,0 +1,112 @@ +/* mpfr_set_str_raw -- set a floating-point number from a binary string + +Copyright (C) 1999 PolKA project, Inria Lorraine and Loria + +This file is part of the MPFR Library. + +The MPFR Library is free software; you can redistribute it and/or modify +it under the terms of the GNU Library General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at your +option) any later version. + +The MPFR Library 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 Library General Public +License for more details. + +You should have received a copy of the GNU Library General Public License +along with the MPFR Library; see the file COPYING.LIB. If not, write to +the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, +MA 02111-1307, USA. */ + +#include <stdio.h> +#include <stdlib.h> +#ifdef HAS_STRING_H +#include <string.h> +#else +#include <strings.h> +#endif +#include "gmp.h" +#include "gmp-impl.h" +#include "longlong.h" +#include "mpfr.h" + +/* Currently the number should be of the form +/- xxxx.xxxxxxEyy, with + decimal exponent. The mantissa of x is supposed to be large enough + to hold all the bits of str. */ + +void +#if __STDC__ +mpfr_set_str_raw(mpfr_ptr x, char *str) +#else +mpfr_set_str_raw(x, str) + mpfr_ptr x; + char *str; +#endif +{ + char *str2, *str0, negative = 0; + unsigned long j, l, k = 0, xsize, cnt; mp_limb_t *xp; + long expn = 0, e; char *endstr2; + + xp = x -> _mp_d; + xsize = 1 + (PREC(x)-1)/BITS_PER_MP_LIMB; + str0 = str2 = (char *) malloc((strlen(str)+1)*sizeof(char)); + + if (*str == '-') { negative = 1; str++; } + else if (*str == '+') str++; + + while (*str == '0') { str++; } + + while (*str == '0' || *str == '1') + { *(str2++) = *(str++); k++; } + + if (*str == '.') + { + str++; + while (*str == '0' || *str == '1') + { *(str2++) = *(str++); } + + if (*str == '[') { while (*str != ']') str++; } + } + + if (*str == '[') { while (*str != ']') str++; } + + if (*str == 'e' || *str == 'E') + { + e = atol(++str); /* signed exponent after 'e' or 'E' */ + expn = k + e; + if (expn < e) + fprintf(stderr, "Warning: overflow in exponent in Str -> mpfr\n"); + } + else expn=k; + + endstr2 = str2; + *str2 = (char) 0; /* end of string */ + l = (strlen(str0) - 1) / BITS_PER_MP_LIMB + 1; str2 = str0; + + /* str2[0]..endstr2[-1] contains the mantissa */ + for (k = 1; k <= l; k++) + { + j = 0; + xp[xsize - k] = 0; + while (str2<endstr2 && j < BITS_PER_MP_LIMB) + { + xp[xsize - k] = (xp[xsize - k] << 1) + (*str2 - '0'); + str2++; j++; + } + xp[xsize - k] <<= (BITS_PER_MP_LIMB - j); + } + + for (; k <= xsize; k++) { xp[xsize - k] = 0; } + + count_leading_zeros(cnt, xp[xsize - 1]); + if (cnt) mpn_lshift(xp, xp, xsize, cnt); + + x -> _mp_exp = expn - cnt; + x -> _mp_size = xsize; if (negative) CHANGE_SIGN(x); + + free(str0); + + /* May change to take into account : syntax errors, overflow in exponent, + string truncated because of size of x */ +} diff --git a/mpfr/set_z.c b/mpfr/set_z.c new file mode 100644 index 000000000..de9132033 --- /dev/null +++ b/mpfr/set_z.c @@ -0,0 +1,104 @@ +/* mpfr_set_z -- set a floating-point number from a multiple-precision integer + +Copyright (C) 1999 PolKA project, Inria Lorraine and Loria + +This file is part of the MPFR Library. + +The MPFR Library is free software; you can redistribute it and/or modify +it under the terms of the GNU Library General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at your +option) any later version. + +The MPFR Library 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 Library General Public +License for more details. + +You should have received a copy of the GNU Library General Public License +along with the MPFR Library; see the file COPYING.LIB. If not, write to +the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, +MA 02111-1307, USA. */ + +#include "gmp.h" +#include "gmp-impl.h" +#include "longlong.h" +#include "mpfr.h" + +/* set f to the integer z */ +int +#if __STDC__ +mpfr_set_z (mpfr_ptr f, mpz_srcptr z, unsigned char rnd) +#else +mpfr_set_z (f, z, rnd) + mpfr_ptr f; + mpz_srcptr z; + unsigned char rnd; +#endif +{ + int fn, zn, k, dif, sign_z, sh; mp_limb_t *fp = MANT(f), *zp, cc, c2; + + sign_z = mpz_cmp_ui(z,0); + if (sign_z==0) return (SIZE(f)=0); + fn = 1 + (PREC(f)-1)/BITS_PER_MP_LIMB; + zn = ABS(SIZ(z)); + dif = zn-fn; + zp = PTR(z); + count_leading_zeros(k, zp[zn-1]); + EXP(f) = zn*BITS_PER_MP_LIMB-k; + if (SIGN(f)*sign_z<0) CHANGE_SIGN(f); + if (dif>=0) { /* number has to be truncated */ + if (k) { + mpn_lshift(fp, zp + dif, fn, k); + if (dif) *fp += zp[dif-1] >> (BITS_PER_MP_LIMB-k); + } + else MPN_COPY(fp, zp + dif, fn); + sh = fn*BITS_PER_MP_LIMB-PREC(f); + cc = *fp & (((mp_limb_t)1 << sh) - 1); + *fp = *fp & ~cc; + if (rnd==GMP_RNDN) { + if (sh) c2 = (mp_limb_t)1 << (sh-1); + else { /* sh=0 */ + c2 = ((mp_limb_t)1) << (BITS_PER_MP_LIMB-1); + dif--; + cc = (dif>=0) ? ((zp[dif])<<k) : 0; + if (dif>0 && k) cc += zp[dif-1] >> (BITS_PER_MP_LIMB-k); + } + /* now compares cc to c2 */ + if (cc>c2) { mpfr_add_one_ulp(f); return cc; } + else if (cc<c2) goto towards_zero; + else { + cc=0; + while (dif>0 && (cc=zp[dif-1])==0) dif--; + if (cc) { mpfr_add_one_ulp(f); return cc; } + else /* exactly in middle: inexact in both cases */ + if (*fp & ((mp_limb_t)1<<sh)) { mpfr_add_one_ulp(f); return 1; } + else return 1; + } + } + else if ((sign_z>0 && rnd==GMP_RNDU) || (sign_z<0 && rnd==GMP_RNDD)) { + /* round towards infinity */ + /* result is exact iff all remaining bits are zero */ + if (dif>0 && cc==0) cc=zp[--dif]<<k; + while (cc==0 && dif>0) cc=zp[--dif]; + if (cc) { mpfr_add_one_ulp(f); return 1; } + else return 0; + } + else { /* round towards zero */ + /* result is exact iff all remaining bits are zero */ + towards_zero: + if (cc==0 && dif>0) cc=zp[--dif]<<k; + while (cc==0 && dif>0) cc=zp[--dif]; + return cc; + } + } + else { + if (k) mpn_lshift(fp-dif, zp, zn, k); + else MPN_COPY(fp-dif, zp, zn); + /* fill with zeroes */ + MPN_ZERO(fp, -dif); + return 0; /* result is exact */ + } +} + + + diff --git a/mpfr/sqrt.c b/mpfr/sqrt.c new file mode 100644 index 000000000..a34ff6dae --- /dev/null +++ b/mpfr/sqrt.c @@ -0,0 +1,220 @@ +/* mpfr_sqrt -- square root of a floating-point number + +Copyright (C) 1999 PolKA project, Inria Lorraine and Loria + +This file is part of the MPFR Library. + +The MPFR Library is free software; you can redistribute it and/or modify +it under the terms of the GNU Library General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at your +option) any later version. + +The MPFR Library 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 Library General Public +License for more details. + +You should have received a copy of the GNU Library General Public License +along with the MPFR Library; see the file COPYING.LIB. If not, write to +the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, +MA 02111-1307, USA. */ + +#include <math.h> +#include <stdio.h> +#include <stdlib.h> +#include "gmp.h" +#include "gmp-impl.h" +#include "mpfr.h" +#include "longlong.h" + +/* #define DEBUG */ + +int +mpfr_sqrt (mpfr_ptr r, mpfr_srcptr u, unsigned char rnd_mode) +{ + mp_ptr up, rp, tmp, remp; + mp_size_t usize, rrsize; + mp_size_t rsize; + mp_size_t prec, err; + mp_limb_t q_limb; + long rw, nw, k; + int exact = 0; + unsigned long cc = 0; + char can_round = 0; + TMP_DECL (marker); TMP_DECL(marker0); + + if (FLAG_NAN(u) || SIGN(u) == -1) { SET_NAN(r); return 0; } + + prec = PREC(r); + + if (!NOTZERO(u)) + { + EXP(r) = 0; + MPN_ZERO(MANT(r), ABSSIZE(r)); + return 1; + } + + up = MANT(u); + +#ifdef DEBUG + printf("Entering square root : "); + for(k = usize - 1; k >= 0; k--) { printf("%lu ", up[k]); } + printf(".\n"); +#endif + + /* Compare the mantissas */ + + usize = (PREC(u) - 1)/BITS_PER_MP_LIMB + 1; + rsize = ((PREC(r) + 2 + (EXP(u) & 1))/BITS_PER_MP_LIMB + 1) << 1; + rrsize = (PREC(r) + 2 + (EXP(u) & 1))/BITS_PER_MP_LIMB + 1; + /* One extra bit is needed in order to get the square root with enough + precision ; take one extra bit for rrsize in order to solve more + easily the problem of rounding to nearest. + Need to have 2*rrsize = rsize... + Take one extra bit if the exponent of u is odd since we shall have + to shift then. + */ + + TMP_MARK(marker0); + if (EXP(u) & 1) /* Shift u one bit to the right */ + { + if (PREC(u) & (BITS_PER_MP_LIMB - 1)) + { + up = TMP_ALLOC(usize*BYTES_PER_MP_LIMB); + mpn_rshift(up, u->_mp_d, usize, 1); + } + else + { + up = TMP_ALLOC((usize + 1)*BYTES_PER_MP_LIMB); + if (mpn_rshift(up + 1, u->_mp_d, ABSSIZE(u), 1)) + up [0] = ((mp_limb_t) 1) << (BITS_PER_MP_LIMB - 1); + else up[0] = 0; + usize++; + } + } + + EXP(r) = ((EXP(u) + (EXP(u) & 1)) / 2) ; + + do + { + TMP_MARK (marker); + + err = rsize*BITS_PER_MP_LIMB; + if (rsize < usize) { err--; } + if (err > rrsize * BITS_PER_MP_LIMB) + { err = rrsize * BITS_PER_MP_LIMB; } + + tmp = (mp_ptr) TMP_ALLOC (rsize * BYTES_PER_MP_LIMB); + rp = (mp_ptr) TMP_ALLOC (rrsize * BYTES_PER_MP_LIMB); + remp = (mp_ptr) TMP_ALLOC (rsize * BYTES_PER_MP_LIMB); + + if (usize >= rsize) { + MPN_COPY (tmp, up + usize - rsize, rsize); + } + else { + MPN_COPY (tmp + rsize - usize, up, usize); + MPN_ZERO (tmp, rsize - usize); + } + + /* Do the real job */ + +#ifdef DEBUG + printf("Taking the sqrt of : "); + for(k = rsize - 1; k >= 0; k--) { + printf("+%lu*2^%lu",tmp[k],k*mp_bits_per_limb); } + printf(".\n"); +#endif + + q_limb = kara_sqrtrem (rp, remp, tmp, rsize); + +#ifdef DEBUG + printf("The result is : \n"); + printf("sqrt : "); + for(k = rrsize - 1; k >= 0; k--) { printf("%lu ", rp[k]); } + printf("(q_limb = %lu)\n", q_limb); +#endif + + can_round = (mpfr_can_round_raw(rp, rrsize, 1, err, + GMP_RNDZ, rnd_mode, PREC(r))); + + /* If we used all the limbs of both the dividend and the divisor, + then we have the correct RNDZ rounding */ + + if (!can_round && (rsize < 2*usize)) + { +#ifdef DEBUG + printf("Increasing the precision.\n"); +#endif + TMP_FREE(marker); + } + } + while (!can_round && (rsize < 2*usize) + && (rsize += 2) && (rrsize ++)); + + + /* This part may be deplaced upper to avoid a few mpfr_can_round_raw */ + /* when the square root is exact. It is however very unprobable that */ + /* it would improve the behaviour of the present code on average. */ + + if (!q_limb) /* possibly exact */ + { + /* if we have taken into account the whole of up */ + for (k = usize - rsize - 1; k >= 0; k ++) + if (up[k]) break; + + if (k < 0) { exact = 1; goto fin; } + } + + if (can_round) + { + cc = mpfr_round_raw(rp, rp, err, 0, PREC(r), rnd_mode); + rrsize = (PREC(r) - 1)/BITS_PER_MP_LIMB + 1; + } + else + /* Use the return value of sqrtrem to decide of the rounding */ + /* Note that at this point the sqrt has been computed */ + /* EXACTLY. If rounding = GMP_RNDZ, do nothing [comes from */ + /* the fact that the exact square root can end with a bunch of ones, */ + /* and in that case we indeed cannot round if we do not know that */ + /* the computation was exact. */ + switch (rnd_mode) + { + case GMP_RNDZ : + case GMP_RNDD : break; + + case GMP_RNDN : + /* Not in the situation ...0 111111 */ + rw = (PREC(r) + 1) & (BITS_PER_MP_LIMB - 1); + if (rw) { rw = BITS_PER_MP_LIMB - rw; nw = 0; } else nw = 1; + if ((rp[nw] >> rw) & 1 && /* Not 0111111111 */ + (q_limb || /* Nonzero remainder */ + (rw ? (rp[nw] >> (rw + 1)) & 1 : + (rp[nw] >> (BITS_PER_MP_LIMB - 1)) & 1))) /* or even rounding */ + cc = mpn_add_1(rp + nw, rp + nw, rrsize, ((mp_limb_t)1) << rw); + break; + + case GMP_RNDU : + if (q_limb) + cc = mpn_add_1(rp, rp, rrsize, 1 << (BITS_PER_MP_LIMB - + (PREC(r) & + (BITS_PER_MP_LIMB - 1)))); + } + + if (cc) { + mpn_rshift(rp, rp, rrsize, 1); + rp[rrsize-1] |= (mp_limb_t) 1 << (BITS_PER_MP_LIMB-1); + r->_mp_exp++; + } + + fin: + rsize = rrsize; + rrsize = (PREC(r) - 1)/BITS_PER_MP_LIMB + 1; + MPN_COPY(r->_mp_d, rp + rsize - rrsize, rrsize); + + if (PREC(r) & (BITS_PER_MP_LIMB - 1)) + MANT(r) [0] &= ~(((mp_limb_t)1 << (BITS_PER_MP_LIMB - + (PREC(r) & (BITS_PER_MP_LIMB - 1)))) - 1) ; + + TMP_FREE(marker0); TMP_FREE (marker); + return exact; +} diff --git a/mpfr/sub.c b/mpfr/sub.c new file mode 100644 index 000000000..dfe755b73 --- /dev/null +++ b/mpfr/sub.c @@ -0,0 +1,483 @@ +/* mpfr_sub -- subtract two floating-point numbers + +Copyright (C) 1999 PolKA project, Inria Lorraine and Loria + +This file is part of the MPFR Library. + +The MPFR Library is free software; you can redistribute it and/or modify +it under the terms of the GNU Library General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at your +option) any later version. + +The MPFR Library 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 Library General Public +License for more details. + +You should have received a copy of the GNU Library General Public License +along with the MPFR Library; see the file COPYING.LIB. If not, write to +the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, +MA 02111-1307, USA. */ + +#include <stdio.h> +#include "gmp.h" +#include "gmp-impl.h" +#include "mpfr.h" + +/* #define DEBUG */ + +extern void mpfr_add1 _PROTO((mpfr_ptr, mpfr_srcptr, mpfr_srcptr, + unsigned char, int)); + +/* put in ap[0]..ap[an-1] the value of bp[0]..bp[n-1] shifted by sh bits + to the left minus ap[0]..ap[n-1], with 0 <= sh < mp_bits_per_limb, and + returns the borrow. +*/ +mp_limb_t +#if __STDC__ +mpn_sub_lshift_n (mp_limb_t *ap, mp_limb_t *bp, int n, int sh, int an) +#else +mpn_sub_lshift_n (ap, bp, n, sh, an) mp_limb_t *ap, *bp; int n,sh,an; +#endif +{ + mp_limb_t c, bh; + + /* shift b to the left */ + if (sh) bh = mpn_lshift(bp, bp, n, sh); + c = (n<an) ? mpn_sub_n(ap, bp, ap, n) : mpn_sub_n(ap, bp+(n-an), ap, an); + /* shift back b to the right */ + if (sh) { + mpn_rshift(bp, bp, n, sh); + bp[n-1] += bh<<(mp_bits_per_limb-sh); + } + return c; +} + +/* signs of b and c differ, abs(b)>=abs(c), diff_exp>=0 */ +void +#if __STDC__ +mpfr_sub1(mpfr_ptr a, mpfr_srcptr b, mpfr_srcptr c, unsigned char rnd_mode, int diff_exp) +#else +mpfr_sub1(a, b, c, rnd_mode, diff_exp) + mpfr_ptr a; + mpfr_srcptr b; + mpfr_srcptr c; + unsigned char rnd_mode; + int diff_exp; +#endif +{ + mp_limb_t *ap, *bp, *cp, cc, c2; unsigned int an,bn,cn; + int sh,dif,k,cancel,cancel1,cancel2; + TMP_DECL(marker); + +#ifdef DEBUG + printf("b= "); if (SIGN(b)>=0) putchar(' '); + mpfr_print_raw(b); putchar('\n'); + printf("c= "); if (SIGN(c)>=0) putchar(' '); + for (k=0;k<diff_exp;k++) putchar(' '); mpfr_print_raw(c); + putchar('\n'); + printf("b=%1.20e c=%1.20e\n",mpfr_get_d(b),mpfr_get_d(c)); +#endif + cancel = mpfr_cmp2(b, c); + /* we have to take into account the first (PREC(a)+cancel) bits from b */ + cancel1 = cancel/mp_bits_per_limb; cancel2 = cancel%mp_bits_per_limb; + TMP_MARK(marker); + ap = MANT(a); + bp = MANT(b); + cp = MANT(c); + if (ap == bp) { + bp = (mp_ptr) TMP_ALLOC(ABSSIZE(b) * BYTES_PER_MP_LIMB); + MPN_COPY (bp, ap, ABSSIZE(b)); + if (ap == cp) { cp = bp; } + } + else if (ap == cp) + { + cp = (mp_ptr) TMP_ALLOC (ABSSIZE(c) * BYTES_PER_MP_LIMB); + MPN_COPY(cp, ap, ABSSIZE(c)); + } + an = (PREC(a)-1)/mp_bits_per_limb+1; /* number of significant limbs of a */ + sh = an*mp_bits_per_limb-PREC(a); /* non-significant bits in low limb */ + bn = (PREC(b)-1)/mp_bits_per_limb+1; /* number of significant limbs of b */ + cn = (PREC(c)-1)/mp_bits_per_limb + 1; + EXP(a) = EXP(b)-cancel; + /* adjust sign to that of b */ + if (SIGN(a)*SIGN(b)<0) CHANGE_SIGN(a); + /* case 1: diff_exp>=prec(a), i.e. c only affects the last bit + through rounding */ + dif = PREC(a)-diff_exp; +#ifdef DEBUG + printf("PREC(a)=%d an=%u PREC(b)=%d bn=%u PREC(c)=%d diff_exp=%u dif=%d cancel=%d\n", + PREC(a),an,PREC(b),bn,PREC(c),diff_exp,dif,cancel); +#endif + if (dif<=0) { /* diff_exp>=PREC(a): c does not overlap with a */ + /* either PREC(b)<=PREC(a), and we can copy the mantissa of b directly + into that of a, or PREC(b)>PREC(a) and we have to round b-c */ + if (PREC(b)<=PREC(a)+cancel) { + if (cancel2) mpn_lshift(ap+(an-bn+cancel1), bp, bn-cancel1, cancel2); + else MPN_COPY(ap+(an-bn+cancel1), bp, bn-cancel1); + /* fill low significant limbs with zero */ + MPN_ZERO(ap, an-bn+cancel1); + /* now take c into account */ + if (rnd_mode==GMP_RNDN) { /* to nearest */ + /* if diff_exp > PREC(a), no change */ + if (diff_exp==PREC(a)) { + /* if c is not zero, then as it is normalized, we have to subtract + one to the lsb of a if c>1/2, or c=1/2 and lsb(a)=1 (round to + even) */ + if (NOTZERO(c)) { /* c is not zero */ + /* check whether mant(c)=1/2 or not */ + cc = *cp - ((mp_limb_t)1<<(mp_bits_per_limb-1)); + if (cc==0) { + bp = cp+(PREC(c)-1)/mp_bits_per_limb; + while (cp<bp && cc==0) cc = *++cp; + } + if (cc || (ap[an-1] & (mp_limb_t)1<<sh)) goto sub_one_ulp; + /* mant(c) > 1/2 or mant(c) = 1/2: subtract 1 iff lsb(a)=1 */ + } + } + else if (ap[an-1]==0) { /* case b=2^n */ + ap[an-1] = (mp_limb_t) 1 << (BITS_PER_MP_LIMB-1); + EXP(a)++; + } + } + else if ((ISNONNEG(b) && rnd_mode==GMP_RNDU) || + (ISNEG(b) && rnd_mode==GMP_RNDD)) { + /* round up: nothing to do */ + if (ap[an-1]==0) { /* case b=2^n */ + ap[an-1] = (mp_limb_t) 1 << (BITS_PER_MP_LIMB-1); + EXP(a)++; + } + } + else { + /* round down: subtract 1 ulp iff c<>0 */ + if (NOTZERO(c)) goto sub_one_ulp; + } + } + else { /* PREC(b)>PREC(a) : we have to round b-c */ + k=bn-an; + /* first copy the 'an' most significant limbs of b to a */ + MPN_COPY(ap, bp+k, an); + if (rnd_mode==GMP_RNDN) { /* to nearest */ + /* first check whether the truncated bits from b are 1/2*lsb(a) */ + if (sh) { + cc = *ap & (((mp_limb_t)1<<sh)-1); + *ap &= ~cc; /* truncate last bits */ + cc -= (mp_limb_t)1<<(sh-1); + } + else /* no bit to truncate */ + cc = bp[--k] - ((mp_limb_t)1<<(mp_bits_per_limb-1)); + if ((long)cc>0) { /* suppose sizeof(long)=sizeof(mp_limb_t) */ + goto add_one_ulp; /* trunc(b)>1/2*lsb(a) -> round up */ + } + else if (cc==0) { + while (k>1 && cc==0) cc=bp[--k]; + /* now if the truncated part of b = 1/2*lsb(a), check whether c=0 */ + if (NOTZERO(c) || (*ap & ((mp_limb_t)1<<sh))) goto sub_one_ulp; + /* if trunc(b)-c is exactly 1/2*lsb(a) : round to even lsb */ + } + /* if cc<0 : trunc(b) < 1/2*lsb(a) -> round down, i.e. do nothing */ + } + else { /* round towards infinity or zero */ + if (sh) { + cc = *ap & (((mp_limb_t)1<<sh)-1); + *ap &= ~cc; /* truncate last bits */ + } + else cc=0; + cn--; + c2 = (dif>-sh) ? cp[cn]>>(mp_bits_per_limb-dif-sh) : 0; + while (cc==c2 && (k || cn)) { + if (k) cc = bp[--k]; + if (cn) { + c2 = cp[cn]<<(dif+sh); + if (--cn) c2 += cp[cn]>>(mp_bits_per_limb-dif-sh); + } + } + dif = ((ISNONNEG(b) && rnd_mode==GMP_RNDU) || + (ISNEG(b) && rnd_mode==GMP_RNDD)); + /* round towards infinity if dif=1, towards zero otherwise */ + if (dif && cc>c2) goto add_one_ulp; + else if (dif==0 && cc<c2) goto sub_one_ulp; + } + } + } + else { /* case 2: diff_exp < PREC(a) : c overlaps with a by dif bits */ + /* first copy upper part of c into a (after shift) */ + int overlap; + dif += cancel; + k = (dif-1)/mp_bits_per_limb + 1; /* only the highest k limbs from c + have to be considered */ + if (k<an) { + MPN_ZERO(ap+k, an-k); /* do it now otherwise ap[k] may be + destroyed in case dif<0 */ + } +#ifdef DEBUG + printf("cancel=%d dif=%d k=%d cn=%d sh=%d\n",cancel,dif,k,cn,sh); +#endif + if (dif<=PREC(c)) { /* c has to be truncated */ + dif = dif % mp_bits_per_limb; + dif = (dif) ? mp_bits_per_limb-dif-sh : -sh; + /* we have to shift by dif bits to the right */ + if (dif>0) { + mpn_rshift(ap, cp+(cn-k), (k<=an) ? k : an, dif); + if (k>an) ap[an-1] += cp[cn-k+an]<<(mp_bits_per_limb-dif); + } + else if (dif<0) { + cc = mpn_lshift(ap, cp+(cn-k), k, -dif); + if (k<an) ap[k]=cc; + /* put the non-significant bits in low limb for further rounding */ + if (cn >= k+1) + ap[0] += cp[cn-k-1]>>(mp_bits_per_limb+dif); + } + else MPN_COPY(ap, cp+(cn-k), k); + overlap=1; + } + else { /* c is not truncated, but we have to fill low limbs with 0 */ + MPN_ZERO(ap, k-cn); + overlap = cancel-diff_exp; +#ifdef DEBUG + printf("0:a="); mpfr_print_raw(a); putchar('\n'); + printf("overlap=%d\n",overlap); +#endif + if (overlap>=0) { + cn -= overlap/mp_bits_per_limb; + overlap %= mp_bits_per_limb; + /* warning: a shift of zero with mpn_lshift is not allowed */ + if (overlap) { + if (an<cn) { + mpn_lshift(ap, cp+(cn-an), an, overlap); + ap[0] += cp[cn-an-1]>>(mp_bits_per_limb-overlap); + } + else mpn_lshift(ap+(an-cn), cp, cn, overlap); + } + else MPN_COPY(ap+(an-cn), cp, cn); + } + else { /* shift to the right by -overlap bits */ + overlap = -overlap; + k = overlap/mp_bits_per_limb; + overlap = overlap % mp_bits_per_limb; + if (overlap) cc = mpn_rshift(ap+(an-k-cn), cp, cn, overlap); + else { + MPN_COPY(ap+(an-k-cn), cp, cn); + cc = 0; + } + if (an>k+cn) ap[an-k-cn-1]=cc; + } + overlap=0; + } +#ifdef DEBUG + printf("1:a="); mpfr_print_raw(a); putchar('\n'); +#endif + /* here overlap=1 iff ulp(c)<ulp(a) */ + /* then put high limbs to zero */ + /* now add 'an' upper limbs of b in place */ + if (PREC(b)<=PREC(a)+cancel) { int i, imax; + overlap += 2; + /* invert low limbs */ + imax = (int)an-(int)bn+cancel1; + for (i=0;i<imax;i++) ap[i] = ~ap[i]; + cc = (i) ? mpn_add_1(ap, ap, i, 1) : 1; + mpn_sub_lshift_n(ap+i, bp, bn-cancel1, cancel2, an); + mpn_sub_1(ap+i, ap+i, an-i, (mp_limb_t)1-cc); + } + else /* PREC(b) > PREC(a): we have to truncate b */ + mpn_sub_lshift_n(ap, bp+(bn-an-cancel1), an, cancel2, an); + /* remains to do the rounding */ +#ifdef DEBUG + printf("2:a="); mpfr_print_raw(a); putchar('\n'); + printf("overlap=%d\n",overlap); +#endif + if (rnd_mode==GMP_RNDN) { /* to nearest */ + int kc; + /* four cases: overlap = + (0) PREC(b) > PREC(a) and diff_exp+PREC(c) <= PREC(a) + (1) PREC(b) > PREC(a) and diff_exp+PREC(c) > PREC(a) + (2) PREC(b) <= PREC(a) and diff_exp+PREC(c) <= PREC(a) + (3) PREC(b) <= PREC(a) and diff_exp+PREC(c) > PREC(a) */ + switch (overlap) + { + case 1: /* both b and c to round */ + kc = cn-k; /* remains kc limbs from c */ + k = bn-an; /* remains k limbs from b */ + /* truncate last bits and store the difference with 1/2*ulp in cc */ + cc = *ap & (((mp_limb_t)1<<sh)-1); + *ap &= ~cc; /* truncate last bits */ + cc -= (mp_limb_t)1<<(sh-1); + while ((cc==0 || cc==-1) && k!=0 && kc!=0) { + kc--; + cc -= mpn_sub_1(&c2, bp+(--k), 1, (cp[kc]>>dif) + + (cp[kc+1]<<(mp_bits_per_limb-dif))); + if (cc==0 || cc==-1) cc=c2; + } + if ((long)cc>0) goto add_one_ulp; + else if ((long)cc<-1) goto end_of_sub; /* the carry can be at most 1 */ + else if (kc==0) goto round_b; + /* else round c: go through */ + case 3: /* only c to round */ + bp=cp; k=cn-k; goto to_nearest; + case 0: /* only b to round */ + round_b: + k=bn-an; dif=0; goto to_nearest; + /* otherwise the result is exact: nothing to do */ + } + } + else if ((ISNONNEG(b) && rnd_mode==GMP_RNDU) || + (ISNEG(b) && rnd_mode==GMP_RNDD)) { + cc = *ap & (((mp_limb_t)1<<sh)-1); + *ap &= ~cc; /* truncate last bits */ + if (cc) goto add_one_ulp; /* will happen most of the time */ + else { /* same four cases too */ + int kc = cn-k; /* remains kc limbs from c */ + switch (overlap) + { + case 1: /* both b and c to round */ + k = bn-an; /* remains k limbs from b */ + dif = diff_exp % mp_bits_per_limb; + while (cc==0 && k!=0 && kc!=0) { + kc--; + cc = bp[--k] - (cp[kc]>>dif); + if (dif) cc -= (cp[kc+1]<<(mp_bits_per_limb-dif)); + } + if (cc) goto add_one_ulp; + else if (kc==0) goto round_b2; + /* else round c: go through */ + case 3: /* only c to round: nothing to do */ + /* while (kc) if (cp[--kc]) goto add_one_ulp; */ + /* if dif>0 : remains to check last dif bits from c */ + /* if (dif>0 && (cp[0]<<(mp_bits_per_limb-dif))) goto add_one_ulp; */ + break; + case 0: /* only b to round */ + round_b2: + k=bn-an; + while (k) if (bp[--k]) goto add_one_ulp; + /* otherwise the result is exact: nothing to do */ + } + } + } + /* else round to zero: remove 1 ulp if neglected bits from b-c are < 0 */ + else { + cc = *ap & (((mp_limb_t)1<<sh)-1); + *ap &= ~cc; + if (cc==0) { /* otherwise neglected difference cannot be < 0 */ + /* take into account bp[0]..bp[bn-cancel1-1] shifted by cancel2 to left + and cp[0]..cp[cn-k-1] shifted by dif bits to right */ + switch (overlap) { + case 0: + case 2: + break; /* c is not truncated ==> no borrow */ + case 1: /* both b and c are truncated */ + break; + case 3: /* only c is truncated */ + cn -= k; /* take into account cp[0]..cp[cn-1] shifted by dif bits + to the right */ + cc = (dif>0) ? cp[cn]<<(mp_bits_per_limb-dif) : 0; + while (cc==0 && cn>0) cc = cp[--cn]; + if (cc) goto sub_one_ulp; + break; + } + } + } + } + goto end_of_sub; + + to_nearest: /* 0 <= sh < mp_bits_per_limb : number of bits of a to truncate + bp[k] : last significant limb from b */ +#ifdef DEBUG +mpfr_print_raw(a); putchar('\n'); +#endif + if (sh) { + cc = *ap & (((mp_limb_t)1<<sh)-1); + *ap &= ~cc; /* truncate last bits */ + c2 = (mp_limb_t)1<<(sh-1); + } + else /* no bit to truncate */ + { if (k) cc = bp[--k]; else cc = 0; c2 = (mp_limb_t)1<<(mp_bits_per_limb-1); } +#ifdef DEBUG + printf("cc=%lu c2=%lu k=%u\n",cc,c2,k); +#endif + if (cc>c2) goto add_one_ulp; /* trunc(b)>1/2*lsb(a) -> round up */ + else if (cc==c2) { + cc=0; while (k && cc==0) cc=bp[--k]; +#ifdef DEBUG + printf("cc=%lu\n",cc); +#endif + /* special case of rouding c shifted to the right */ + if (cc==0 && dif>0) cc=bp[0]<<(mp_bits_per_limb-dif); + /* now if the truncated part of b = 1/2*lsb(a), check whether c=0 */ + if (bp!=cp) { + if (cc || (*ap & ((mp_limb_t)1<<sh))) goto add_one_ulp; + } + else { + /* subtract: if cc>0, do nothing */ + if (cc==0 && (*ap & ((mp_limb_t)1<<sh))) goto add_one_ulp; + } + } + goto end_of_sub; + + sub_one_ulp: + cc = mpn_sub_1(ap, ap, an, (mp_limb_t)1<<sh); + goto end_of_sub; + + add_one_ulp: /* add one unit in last place to a */ + cc = mpn_add_1(ap, ap, an, (mp_limb_t)1<<sh); + + end_of_sub: +#ifdef DEBUG +printf("b-c="); if (SIGN(a)>0) putchar(' '); mpfr_print_raw(a); putchar('\n'); +#endif + TMP_FREE(marker); + return; +} + +void +#if __STDC__ +mpfr_sub(mpfr_ptr a, mpfr_srcptr b, mpfr_srcptr c, unsigned char rnd_mode) +#else +mpfr_sub(a, b, c, rnd_mode) + mpfr_ptr a; + mpfr_srcptr b; + mpfr_srcptr c; + unsigned char rnd_mode; +#endif +{ + int diff_exp; + + if (FLAG_NAN(b) || FLAG_NAN(c)) { SET_NAN(a); return; } + + if (!NOTZERO(b)) { mpfr_neg(a, c, rnd_mode); return; } + if (!NOTZERO(c)) { mpfr_set(a, b, rnd_mode); return; } + + diff_exp = EXP(b)-EXP(c); + if (SIGN(b) == SIGN(c)) { /* signs are equal, it's a real subtraction */ + if (diff_exp<0) { + /* exchange rounding modes towards +/- infinity */ + if (rnd_mode==GMP_RNDU) rnd_mode=GMP_RNDD; + else if (rnd_mode==GMP_RNDD) rnd_mode=GMP_RNDU; + mpfr_sub1(a, c, b, rnd_mode, -diff_exp); + CHANGE_SIGN(a); + } + else if (diff_exp>0) mpfr_sub1(a, b, c, rnd_mode, diff_exp); + else { /* diff_exp=0 */ + diff_exp = mpfr_cmp3(b,c,1); + /* if b>0 and diff_exp>0 or b<0 and diff_exp<0: abs(b) > abs(c) */ + if (diff_exp==0) SET_ZERO(a); + else if (diff_exp*SIGN(b)>0) mpfr_sub1(a, b, c, rnd_mode, 0); + else { + /* exchange rounding modes towards +/- infinity */ + if (rnd_mode==GMP_RNDU) rnd_mode=GMP_RNDD; + else if (rnd_mode==GMP_RNDD) rnd_mode=GMP_RNDU; + mpfr_sub1(a, c, b, rnd_mode, 0); + CHANGE_SIGN(a); + } + } + } + else /* signs differ, it's an addition */ + if (diff_exp<0) { + /* exchange rounding modes towards +/- infinity */ + if (rnd_mode==GMP_RNDU) rnd_mode=GMP_RNDD; + else if (rnd_mode==GMP_RNDD) rnd_mode=GMP_RNDU; + mpfr_add1(a, c, b, rnd_mode, -diff_exp); + CHANGE_SIGN(a); + } + else mpfr_add1(a, b, c, rnd_mode, diff_exp); +} + diff --git a/mpfr/tests/Makefile.am b/mpfr/tests/Makefile.am new file mode 100644 index 000000000..c86cbf314 --- /dev/null +++ b/mpfr/tests/Makefile.am @@ -0,0 +1,37 @@ +## Process this file with automake to generate Makefile.in + +# Copyright (C) 2000 Free Software Foundation, Inc. +# +# This file is part of the GNU MP Library. +# +# The GNU MP Library is free software; you can redistribute it and/or modify +# it under the terms of the GNU Library General Public License as published by +# the Free Software Foundation; either version 2 of the License, or (at your +# option) any later version. +# +# The GNU MP Library 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 Library General Public +# License for more details. +# +# You should have received a copy of the GNU Library General Public License +# along with the GNU MP Library; see the file COPYING.LIB. If not, write to +# the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, +# MA 02111-1307, USA. + +AUTOMAKE_OPTIONS = gnu no-dependencies + +INCLUDES = -I$(top_srcdir) -I$(top_srcdir)/mpfr +LDADD = $(top_builddir)/libgmp.la +dummy_LDADD = + +if WANT_MPFR +# FIXME: The following tests need mpfr_set_machine_rnd_mode() which is not +# built right now: +# tadd tget_str tset_f tsqrt tagm tmul tdiv tlog texp tdiv_ui tout_str +MPBSD_check_OPTION = tcmp2 tmul_ui tcmp_ui tround tset_si tcmp tmul_2exp \ + tset_d tset_str tpi tset_z tlog2 tcan_round tzeta +endif + +check_PROGRAMS = dummy $(MPBSD_check_OPTION) +TESTS = $(check_PROGRAMS) diff --git a/mpfr/tests/Makefile.in b/mpfr/tests/Makefile.in new file mode 100644 index 000000000..e1e655895 --- /dev/null +++ b/mpfr/tests/Makefile.in @@ -0,0 +1,525 @@ +# Makefile.in generated automatically by automake 1.4a from Makefile.am + +# Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +SHELL = @SHELL@ + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +prefix = @prefix@ +exec_prefix = @exec_prefix@ + +bindir = @bindir@ +sbindir = @sbindir@ +libexecdir = @libexecdir@ +datadir = @datadir@ +sysconfdir = @sysconfdir@ +sharedstatedir = @sharedstatedir@ +localstatedir = @localstatedir@ +libdir = @libdir@ +infodir = @infodir@ +mandir = @mandir@ +includedir = @includedir@ +oldincludedir = /usr/include + +DESTDIR = + +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ + +top_builddir = ../.. + +ACLOCAL = @ACLOCAL@ +AUTOCONF = @AUTOCONF@ +AUTOMAKE = @AUTOMAKE@ +AUTOHEADER = @AUTOHEADER@ + +INSTALL = @INSTALL@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_FLAG = +transform = @program_transform_name@ + +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : + +@SET_MAKE@ +build_alias = @build_alias@ +build_triplet = @build@ +host_alias = @host_alias@ +host_triplet = @host@ +target_alias = @target_alias@ +target_triplet = @target@ +AMDEP = @AMDEP@ +AMTAR = @AMTAR@ +AR = @AR@ +AS = @AS@ +AWK = @AWK@ +CALLING_CONVENTIONS_OBJS = @CALLING_CONVENTIONS_OBJS@ +CC = @CC@ +CCAS = @CCAS@ +CPP = @CPP@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +DEPDIR = @DEPDIR@ +DLLTOOL = @DLLTOOL@ +EXEEXT = @EXEEXT@ +LIBTOOL = @LIBTOOL@ +LN_S = @LN_S@ +M4 = @M4@ +MAINT = @MAINT@ +MAKEINFO = @MAKEINFO@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +PACKAGE = @PACKAGE@ +RANLIB = @RANLIB@ +SPEED_CYCLECOUNTER_OBJS = @SPEED_CYCLECOUNTER_OBJS@ +STRIP = @STRIP@ +U = @U@ +VERSION = @VERSION@ +gmp_srclinks = @gmp_srclinks@ +install_sh = @install_sh@ +mpn_objects = @mpn_objects@ +mpn_objs_in_libgmp = @mpn_objs_in_libgmp@ + +# Copyright (C) 2000 Free Software Foundation, Inc. +# +# This file is part of the GNU MP Library. +# +# The GNU MP Library is free software; you can redistribute it and/or modify +# it under the terms of the GNU Library General Public License as published by +# the Free Software Foundation; either version 2 of the License, or (at your +# option) any later version. +# +# The GNU MP Library 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 Library General Public +# License for more details. +# +# You should have received a copy of the GNU Library General Public License +# along with the GNU MP Library; see the file COPYING.LIB. If not, write to +# the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, +# MA 02111-1307, USA. + + +AUTOMAKE_OPTIONS = gnu no-dependencies + +INCLUDES = -I$(top_srcdir) -I$(top_srcdir)/mpfr +LDADD = $(top_builddir)/libgmp.la +dummy_LDADD = + +# FIXME: The following tests need mpfr_set_machine_rnd_mode() which is not +# built right now: +# tadd tget_str tset_f tsqrt tagm tmul tdiv tlog texp tdiv_ui tout_str +@WANT_MPFR_TRUE@MPBSD_check_OPTION = @WANT_MPFR_TRUE@tcmp2 tmul_ui tcmp_ui tround tset_si tcmp tmul_2exp \ +@WANT_MPFR_TRUE@ tset_d tset_str tpi tset_z tlog2 tcan_round tzeta + +check_PROGRAMS = dummy $(MPBSD_check_OPTION) +TESTS = $(check_PROGRAMS) +subdir = mpfr/tests +mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs +CONFIG_HEADER = ../../config.h +CONFIG_CLEAN_FILES = +@WANT_MPFR_FALSE@check_PROGRAMS = dummy$(EXEEXT) +@WANT_MPFR_TRUE@check_PROGRAMS = dummy$(EXEEXT) tcmp2$(EXEEXT) \ +@WANT_MPFR_TRUE@tmul_ui$(EXEEXT) tcmp_ui$(EXEEXT) tround$(EXEEXT) \ +@WANT_MPFR_TRUE@tset_si$(EXEEXT) tcmp$(EXEEXT) tmul_2exp$(EXEEXT) \ +@WANT_MPFR_TRUE@tset_d$(EXEEXT) tset_str$(EXEEXT) tpi$(EXEEXT) \ +@WANT_MPFR_TRUE@tset_z$(EXEEXT) tlog2$(EXEEXT) tcan_round$(EXEEXT) \ +@WANT_MPFR_TRUE@tzeta$(EXEEXT) + +DEFS = @DEFS@ -I. -I$(srcdir) -I../.. +CPPFLAGS = @CPPFLAGS@ +LDFLAGS = @LDFLAGS@ +LIBS = @LIBS@ +dummy_SOURCES = dummy.c +dummy_OBJECTS = dummy.$(OBJEXT) +dummy_DEPENDENCIES = +dummy_LDFLAGS = +tcan_round_SOURCES = tcan_round.c +tcan_round_OBJECTS = tcan_round.$(OBJEXT) +tcan_round_LDADD = $(LDADD) +tcan_round_DEPENDENCIES = $(top_builddir)/libgmp.la +tcan_round_LDFLAGS = +tcmp_SOURCES = tcmp.c +tcmp_OBJECTS = tcmp.$(OBJEXT) +tcmp_LDADD = $(LDADD) +tcmp_DEPENDENCIES = $(top_builddir)/libgmp.la +tcmp_LDFLAGS = +tcmp2_SOURCES = tcmp2.c +tcmp2_OBJECTS = tcmp2.$(OBJEXT) +tcmp2_LDADD = $(LDADD) +tcmp2_DEPENDENCIES = $(top_builddir)/libgmp.la +tcmp2_LDFLAGS = +tcmp_ui_SOURCES = tcmp_ui.c +tcmp_ui_OBJECTS = tcmp_ui.$(OBJEXT) +tcmp_ui_LDADD = $(LDADD) +tcmp_ui_DEPENDENCIES = $(top_builddir)/libgmp.la +tcmp_ui_LDFLAGS = +tlog2_SOURCES = tlog2.c +tlog2_OBJECTS = tlog2.$(OBJEXT) +tlog2_LDADD = $(LDADD) +tlog2_DEPENDENCIES = $(top_builddir)/libgmp.la +tlog2_LDFLAGS = +tmul_2exp_SOURCES = tmul_2exp.c +tmul_2exp_OBJECTS = tmul_2exp.$(OBJEXT) +tmul_2exp_LDADD = $(LDADD) +tmul_2exp_DEPENDENCIES = $(top_builddir)/libgmp.la +tmul_2exp_LDFLAGS = +tmul_ui_SOURCES = tmul_ui.c +tmul_ui_OBJECTS = tmul_ui.$(OBJEXT) +tmul_ui_LDADD = $(LDADD) +tmul_ui_DEPENDENCIES = $(top_builddir)/libgmp.la +tmul_ui_LDFLAGS = +tpi_SOURCES = tpi.c +tpi_OBJECTS = tpi.$(OBJEXT) +tpi_LDADD = $(LDADD) +tpi_DEPENDENCIES = $(top_builddir)/libgmp.la +tpi_LDFLAGS = +tround_SOURCES = tround.c +tround_OBJECTS = tround.$(OBJEXT) +tround_LDADD = $(LDADD) +tround_DEPENDENCIES = $(top_builddir)/libgmp.la +tround_LDFLAGS = +tset_d_SOURCES = tset_d.c +tset_d_OBJECTS = tset_d.$(OBJEXT) +tset_d_LDADD = $(LDADD) +tset_d_DEPENDENCIES = $(top_builddir)/libgmp.la +tset_d_LDFLAGS = +tset_si_SOURCES = tset_si.c +tset_si_OBJECTS = tset_si.$(OBJEXT) +tset_si_LDADD = $(LDADD) +tset_si_DEPENDENCIES = $(top_builddir)/libgmp.la +tset_si_LDFLAGS = +tset_str_SOURCES = tset_str.c +tset_str_OBJECTS = tset_str.$(OBJEXT) +tset_str_LDADD = $(LDADD) +tset_str_DEPENDENCIES = $(top_builddir)/libgmp.la +tset_str_LDFLAGS = +tset_z_SOURCES = tset_z.c +tset_z_OBJECTS = tset_z.$(OBJEXT) +tset_z_LDADD = $(LDADD) +tset_z_DEPENDENCIES = $(top_builddir)/libgmp.la +tset_z_LDFLAGS = +tzeta_SOURCES = tzeta.c +tzeta_OBJECTS = tzeta.$(OBJEXT) +tzeta_LDADD = $(LDADD) +tzeta_DEPENDENCIES = $(top_builddir)/libgmp.la +tzeta_LDFLAGS = +COMPILE = $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CFLAGS = @CFLAGS@ +CCLD = $(CC) +LINK = $(LIBTOOL) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ +DIST_SOURCES = dummy.c tcan_round.c tcmp.c tcmp2.c tcmp_ui.c tlog2.c \ +tmul_2exp.c tmul_ui.c tpi.c tround.c tset_d.c tset_si.c tset_str.c \ +tset_z.c tzeta.c +DIST_COMMON = Makefile.am Makefile.in + + +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) + +GZIP_ENV = --best +depcomp = +SOURCES = dummy.c tcan_round.c tcmp.c tcmp2.c tcmp_ui.c tlog2.c tmul_2exp.c tmul_ui.c tpi.c tround.c tset_d.c tset_si.c tset_str.c tset_z.c tzeta.c +OBJECTS = dummy.$(OBJEXT) tcan_round.$(OBJEXT) tcmp.$(OBJEXT) tcmp2.$(OBJEXT) tcmp_ui.$(OBJEXT) tlog2.$(OBJEXT) tmul_2exp.$(OBJEXT) tmul_ui.$(OBJEXT) tpi.$(OBJEXT) tround.$(OBJEXT) tset_d.$(OBJEXT) tset_si.$(OBJEXT) tset_str.$(OBJEXT) tset_z.$(OBJEXT) tzeta.$(OBJEXT) + +all: all-redirect +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4) + cd $(top_srcdir) && $(AUTOMAKE) --gnu mpfr/tests/Makefile + +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + cd $(top_builddir) \ + && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status + + +mostlyclean-checkPROGRAMS: + +clean-checkPROGRAMS: + -test -z "$(check_PROGRAMS)" || rm -f $(check_PROGRAMS) + +distclean-checkPROGRAMS: + +maintainer-clean-checkPROGRAMS: + +mostlyclean-compile: + -rm -f *.o core *.core + -rm -f *.$(OBJEXT) + +clean-compile: + +distclean-compile: + -rm -f *.tab.c + +maintainer-clean-compile: + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +distclean-libtool: + +maintainer-clean-libtool: + +dummy$(EXEEXT): $(dummy_OBJECTS) $(dummy_DEPENDENCIES) + @rm -f dummy$(EXEEXT) + $(LINK) $(dummy_LDFLAGS) $(dummy_OBJECTS) $(dummy_LDADD) $(LIBS) + +tcan_round$(EXEEXT): $(tcan_round_OBJECTS) $(tcan_round_DEPENDENCIES) + @rm -f tcan_round$(EXEEXT) + $(LINK) $(tcan_round_LDFLAGS) $(tcan_round_OBJECTS) $(tcan_round_LDADD) $(LIBS) + +tcmp$(EXEEXT): $(tcmp_OBJECTS) $(tcmp_DEPENDENCIES) + @rm -f tcmp$(EXEEXT) + $(LINK) $(tcmp_LDFLAGS) $(tcmp_OBJECTS) $(tcmp_LDADD) $(LIBS) + +tcmp2$(EXEEXT): $(tcmp2_OBJECTS) $(tcmp2_DEPENDENCIES) + @rm -f tcmp2$(EXEEXT) + $(LINK) $(tcmp2_LDFLAGS) $(tcmp2_OBJECTS) $(tcmp2_LDADD) $(LIBS) + +tcmp_ui$(EXEEXT): $(tcmp_ui_OBJECTS) $(tcmp_ui_DEPENDENCIES) + @rm -f tcmp_ui$(EXEEXT) + $(LINK) $(tcmp_ui_LDFLAGS) $(tcmp_ui_OBJECTS) $(tcmp_ui_LDADD) $(LIBS) + +tlog2$(EXEEXT): $(tlog2_OBJECTS) $(tlog2_DEPENDENCIES) + @rm -f tlog2$(EXEEXT) + $(LINK) $(tlog2_LDFLAGS) $(tlog2_OBJECTS) $(tlog2_LDADD) $(LIBS) + +tmul_2exp$(EXEEXT): $(tmul_2exp_OBJECTS) $(tmul_2exp_DEPENDENCIES) + @rm -f tmul_2exp$(EXEEXT) + $(LINK) $(tmul_2exp_LDFLAGS) $(tmul_2exp_OBJECTS) $(tmul_2exp_LDADD) $(LIBS) + +tmul_ui$(EXEEXT): $(tmul_ui_OBJECTS) $(tmul_ui_DEPENDENCIES) + @rm -f tmul_ui$(EXEEXT) + $(LINK) $(tmul_ui_LDFLAGS) $(tmul_ui_OBJECTS) $(tmul_ui_LDADD) $(LIBS) + +tpi$(EXEEXT): $(tpi_OBJECTS) $(tpi_DEPENDENCIES) + @rm -f tpi$(EXEEXT) + $(LINK) $(tpi_LDFLAGS) $(tpi_OBJECTS) $(tpi_LDADD) $(LIBS) + +tround$(EXEEXT): $(tround_OBJECTS) $(tround_DEPENDENCIES) + @rm -f tround$(EXEEXT) + $(LINK) $(tround_LDFLAGS) $(tround_OBJECTS) $(tround_LDADD) $(LIBS) + +tset_d$(EXEEXT): $(tset_d_OBJECTS) $(tset_d_DEPENDENCIES) + @rm -f tset_d$(EXEEXT) + $(LINK) $(tset_d_LDFLAGS) $(tset_d_OBJECTS) $(tset_d_LDADD) $(LIBS) + +tset_si$(EXEEXT): $(tset_si_OBJECTS) $(tset_si_DEPENDENCIES) + @rm -f tset_si$(EXEEXT) + $(LINK) $(tset_si_LDFLAGS) $(tset_si_OBJECTS) $(tset_si_LDADD) $(LIBS) + +tset_str$(EXEEXT): $(tset_str_OBJECTS) $(tset_str_DEPENDENCIES) + @rm -f tset_str$(EXEEXT) + $(LINK) $(tset_str_LDFLAGS) $(tset_str_OBJECTS) $(tset_str_LDADD) $(LIBS) + +tset_z$(EXEEXT): $(tset_z_OBJECTS) $(tset_z_DEPENDENCIES) + @rm -f tset_z$(EXEEXT) + $(LINK) $(tset_z_LDFLAGS) $(tset_z_OBJECTS) $(tset_z_LDADD) $(LIBS) + +tzeta$(EXEEXT): $(tzeta_OBJECTS) $(tzeta_DEPENDENCIES) + @rm -f tzeta$(EXEEXT) + $(LINK) $(tzeta_LDFLAGS) $(tzeta_OBJECTS) $(tzeta_LDADD) $(LIBS) +.c.o: + $(COMPILE) -c $< +.c.obj: + $(COMPILE) -c `cygpath -w $<` +.c.lo: + $(LTCOMPILE) -c -o $@ $< + +tags: TAGS + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + mkid -f$$here/ID $$unique $(LISP) + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(ETAGS_ARGS)$$unique$(LISP)$$tags" \ + || etags $(ETAGS_ARGS) $$tags $$unique $(LISP) + +mostlyclean-tags: + +clean-tags: + +distclean-tags: + -rm -f TAGS ID + +maintainer-clean-tags: + +distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir) + +distdir: $(DISTFILES) + @for file in $(DISTFILES); do \ + d=$(srcdir); \ + if test -d $$d/$$file; then \ + cp -pR $$d/$$file $(distdir); \ + else \ + test -f $(distdir)/$$file \ + || cp -p $$d/$$file $(distdir)/$$file || :; \ + fi; \ + done +check-TESTS: $(TESTS) + @failed=0; all=0; xfail=0; xpass=0; \ + srcdir=$(srcdir); export srcdir; \ + for tst in $(TESTS); do \ + if test -f ./$$tst; then dir=./; \ + elif test -f $$tst; then dir=; \ + else dir="$(srcdir)/"; fi; \ + if $(TESTS_ENVIRONMENT) $${dir}$$tst; then \ + all=`expr $$all + 1`; \ + case " $(XFAIL_TESTS) " in \ + *" $$tst "*) \ + xpass=`expr $$xpass + 1`; \ + failed=`expr $$failed + 1`; \ + echo "XPASS: $$tst"; \ + ;; \ + *) \ + echo "PASS: $$tst"; \ + ;; \ + esac; \ + elif test $$? -ne 77; then \ + all=`expr $$all + 1`; \ + case " $(XFAIL_TESTS) " in \ + *" $$tst "*) \ + xfail=`expr $$xfail + 1`; \ + echo "XFAIL: $$tst"; \ + ;; \ + *) \ + failed=`expr $$failed + 1`; \ + echo "FAIL: $$tst"; \ + ;; \ + esac; \ + fi; \ + done; \ + if test "$$failed" -eq 0; then \ + if test "$$xfail" -eq 0; then \ + banner="All $$all tests passed"; \ + else \ + banner="All $$all tests behaved as expected ($$xfail expected failures)"; \ + fi; \ + else \ + if test "$$xpass" -eq 0; then \ + banner="$$failed of $$all tests failed"; \ + else \ + banner="$$failed of $$all tests did not behave as expected ($$xpass unexpected passes)"; \ + fi; \ + fi; \ + dashes=`echo "$$banner" | sed s/./=/g`; \ + echo "$$dashes"; \ + echo "$$banner"; \ + echo "$$dashes"; \ + test "$$failed" -eq 0 +info-am: +info: info-am +dvi-am: +dvi: dvi-am +check-am: all-am + $(MAKE) $(AM_MAKEFLAGS) $(check_PROGRAMS) + $(MAKE) $(AM_MAKEFLAGS) check-TESTS +check: check-am +installcheck-am: +installcheck: installcheck-am +install-exec-am: +install-exec: install-exec-am + +install-data-am: +install-data: install-data-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am +install: install-am +uninstall-am: +uninstall: uninstall-am +all-am: Makefile +all-redirect: all-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_STRIP_FLAG=-s install +installdirs: + + +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -rm -f Makefile $(CONFIG_CLEAN_FILES) + -rm -f config.cache config.log stamp-h stamp-h[0-9]* + +maintainer-clean-generic: + -rm -f Makefile.in +mostlyclean-am: mostlyclean-checkPROGRAMS mostlyclean-compile \ + mostlyclean-libtool mostlyclean-tags \ + mostlyclean-generic + +mostlyclean: mostlyclean-am + +clean-am: clean-checkPROGRAMS clean-compile clean-libtool clean-tags \ + clean-generic mostlyclean-am + +clean: clean-am + +distclean-am: distclean-checkPROGRAMS distclean-compile \ + distclean-libtool distclean-tags distclean-generic \ + clean-am + -rm -f libtool + +distclean: distclean-am + +maintainer-clean-am: maintainer-clean-checkPROGRAMS \ + maintainer-clean-compile maintainer-clean-libtool \ + maintainer-clean-tags maintainer-clean-generic \ + distclean-am + @echo "This command is intended for maintainers to use;" + @echo "it deletes files that may require special tools to rebuild." + +maintainer-clean: maintainer-clean-am + +.PHONY: mostlyclean-checkPROGRAMS distclean-checkPROGRAMS \ +clean-checkPROGRAMS maintainer-clean-checkPROGRAMS mostlyclean-compile \ +distclean-compile clean-compile maintainer-clean-compile \ +mostlyclean-libtool distclean-libtool clean-libtool \ +maintainer-clean-libtool tags mostlyclean-tags distclean-tags \ +clean-tags maintainer-clean-tags distdir check-TESTS info-am info \ +dvi-am dvi check check-am installcheck-am installcheck install-exec-am \ +install-exec install-data-am install-data install-am install \ +uninstall-am uninstall all-redirect all-am all install-strip \ +installdirs mostlyclean-generic distclean-generic clean-generic \ +maintainer-clean-generic clean mostlyclean distclean maintainer-clean + + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/mpfr/tests/dummy.c b/mpfr/tests/dummy.c new file mode 100644 index 000000000..fd8c4d3c5 --- /dev/null +++ b/mpfr/tests/dummy.c @@ -0,0 +1,28 @@ +/* A dummy do-nothing test program, which always passes. */ + +/* +Copyright (C) 2000 Free Software Foundation, Inc. + +This file is part of the GNU MP Library. + +The GNU MP Library is free software; you can redistribute it and/or modify +it under the terms of the GNU Library General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at your +option) any later version. + +The GNU MP Library 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 Library General Public +License for more details. + +You should have received a copy of the GNU Library General Public License +along with the GNU MP Library; see the file COPYING.LIB. If not, write to +the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, +MA 02111-1307, USA. +*/ + +int +main () +{ + exit (0); +} diff --git a/mpfr/tests/tadd.c b/mpfr/tests/tadd.c new file mode 100644 index 000000000..517edb9e4 --- /dev/null +++ b/mpfr/tests/tadd.c @@ -0,0 +1,414 @@ +/* Test file for mpfr_add and mpfr_sub. + +Copyright (C) 1999 PolKA project, Inria Lorraine and Loria + +This file is part of the MPFR Library. + +The MPFR Library is free software; you can redistribute it and/or modify +it under the terms of the GNU Library General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at your +option) any later version. + +The MPFR Library 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 Library General Public +License for more details. + +You should have received a copy of the GNU Library General Public License +along with the MPFR Library; see the file COPYING.LIB. If not, write to +the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, +MA 02111-1307, USA. */ + +/* #define DEBUG */ +/* #define VERBOSE */ + +#define N 100000 + +#include <math.h> +#include <stdio.h> +#include <stdlib.h> +#include "gmp.h" +#include "mpfr.h" +#include "mpfr-impl.h" +#ifdef IRIX64 +#include <sys/fpu.h> +#endif + +extern int isnan(); +extern int getpid(); + +#define ABS(x) (((x)>0) ? (x) : (-x)) + +/* checks that x+y gives the same results in double + and with mpfr with 53 bits of precision */ +void check(double x, double y, unsigned int rnd_mode, unsigned int px, +unsigned int py, unsigned int pz, double res) +{ + double z1,z2; mpfr_t xx,yy,zz; + + mpfr_init2(xx, px); + mpfr_init2(yy, py); + mpfr_init2(zz, pz); + mpfr_set_d(xx, x, rnd_mode); + mpfr_set_d(yy, y, rnd_mode); + mpfr_add(zz, xx, yy, rnd_mode); + mpfr_set_machine_rnd_mode(rnd_mode); + z1 = (res==0.0) ? x+y : res; + z2 = mpfr_get_d(zz); + if (px==53 && py==53 && pz==53) res=1.0; + if (res!=0.0 && z1!=z2 && !(isnan(z1) && isnan(z2))) { + printf("expected sum is %1.20e, got %1.20e\n",z1,z2); + printf("mpfr_add failed for x=%1.20e y=%1.20e with rnd_mode=%u\n",x,y,rnd_mode); + exit(1); + } + mpfr_clear(xx); mpfr_clear(yy); mpfr_clear(zz); +} + +/* idem than check for mpfr_add(x, x, y) */ +void check3(double x, double y, unsigned int rnd_mode) +{ + double z1,z2; mpfr_t xx,yy; int neg; + + neg = rand() % 2; + mpfr_init2(xx, 53); + mpfr_init2(yy, 53); + mpfr_set_d(xx, x, rnd_mode); + mpfr_set_d(yy, y, rnd_mode); + if (neg) mpfr_sub(xx, xx, yy, rnd_mode); + else mpfr_add(xx, xx, yy, rnd_mode); + mpfr_set_machine_rnd_mode(rnd_mode); + z1 = (neg) ? x-y : x+y; + z2 = mpfr_get_d(xx); + if (z1!=z2 && !(isnan(z1) && isnan(z2))) { + printf("expected result is %1.20e, got %1.20e\n",z1,z2); + printf("mpfr_%s(x,x,y) failed for x=%1.20e y=%1.20e with rnd_mode=%u\n", + (neg) ? "sub" : "add",x,y,rnd_mode); + exit(1); + } + mpfr_clear(xx); mpfr_clear(yy); +} + +/* idem than check for mpfr_add(x, y, x) */ +void check4(double x, double y, unsigned int rnd_mode) +{ + double z1,z2; mpfr_t xx,yy; int neg; + + neg = rand() % 2; + mpfr_init2(xx, 53); + mpfr_init2(yy, 53); + mpfr_set_d(xx, x, rnd_mode); + mpfr_set_d(yy, y, rnd_mode); + if (neg) mpfr_sub(xx, yy, xx, rnd_mode); + else mpfr_add(xx, yy, xx, rnd_mode); + mpfr_set_machine_rnd_mode(rnd_mode); + z1 = (neg) ? y-x : x+y; + z2 = mpfr_get_d(xx); + if (z1!=z2 && !(isnan(z1) && isnan(z2))) { + printf("expected result is %1.20e, got %1.20e\n",z1,z2); + printf("mpfr_%s(x,y,x) failed for x=%1.20e y=%1.20e with rnd_mode=%u\n", + (neg) ? "sub" : "add",x,y,rnd_mode); + exit(1); + } + mpfr_clear(xx); mpfr_clear(yy); +} + +/* idem than check for mpfr_add(x, x, x) */ +void check5(double x, unsigned int rnd_mode) +{ + double z1,z2; mpfr_t xx; int neg; + + mpfr_init2(xx, 53); neg = rand() % 2; + mpfr_set_d(xx, x, rnd_mode); + if (neg) mpfr_sub(xx, xx, xx, rnd_mode); + else mpfr_add(xx, xx, xx, rnd_mode); + mpfr_set_machine_rnd_mode(rnd_mode); + z1 = (neg) ? x-x : x+x; + z2 = mpfr_get_d(xx); + if (z1!=z2 && !(isnan(z1) && isnan(z2))) { + printf("expected result is %1.20e, got %1.20e\n",z1,z2); + printf("mpfr_%s(x,x,x) failed for x=%1.20e with rnd_mode=%u\n", + (neg) ? "sub" : "add",x,rnd_mode); + exit(1); + } + mpfr_clear(xx); +} + +void check2(x,px,y,py,pz,rnd_mode) double x,y; int px,py,pz,rnd_mode; +{ + mpfr_t xx, yy, zz; double z,z2; int u; + +#ifdef DEBUG +printf("x=%1.20e,%d y=%1.20e,%d pz=%d,rnd=%d\n",x,px,y,py,pz,rnd_mode); +#endif + mpfr_init2(xx,px); mpfr_init2(yy,py); mpfr_init2(zz,pz); + mpfr_set_d(xx, x, rnd_mode); + mpfr_set_d(yy, y, rnd_mode); + mpfr_add(zz, xx, yy, rnd_mode); + mpfr_set_machine_rnd_mode(rnd_mode); + z = x+y; z2=mpfr_get_d(zz); u=ulp(z,z2); +#ifdef DEBUG + printf("x+y=%1.20e,%d (%d ulp) rnd_mode=%d\n",z2,pz,u,rnd_mode); + mpfr_set_d(zz, z2, rnd_mode); + printf("i.e."); mpfr_print_raw(zz); putchar('\n'); +#endif + /* one ulp difference is possible due to composed rounding */ + if (px>=53 && py>=53 && pz>=53 && ABS(u)>1) { + printf("x=%1.20e,%d y=%1.20e,%d pz=%d,rnd=%d\n",x,px,y,py,pz,rnd_mode); + printf("got %1.20e\n",z2); + printf("result should be %1.20e (diff=%d ulp)\n",z,u); + mpfr_set_d(zz, z, rnd_mode); + printf("i.e."); mpfr_print_raw(zz); putchar('\n'); + exit(1); } + mpfr_clear(xx); mpfr_clear(yy); mpfr_clear(zz); +} + +void check64() +{ + mpfr_t x, t, u; + + mpfr_init(x); mpfr_init(t); mpfr_init(u); + mpfr_set_prec(x, 53); mpfr_set_prec(t, 76); mpfr_set_prec(u, 76); + mpfr_set_str_raw(x, "-0.10010010001001011011110000000000001010011011011110001E-32"); + mpfr_set_str_raw(t, "-0.1011000101110010000101111111011111010001110011110111100110101011110010011111"); + mpfr_sub(u, x, t, GMP_RNDU); + mpfr_set_str_raw(t, "0.1011000101110010000101111111011100111111101010011011110110101011101000000100"); + if (mpfr_cmp(u,t)) { + printf("expect "); mpfr_print_raw(t); putchar('\n'); + fprintf(stderr, "mpfr_add failed for precisions 53-76\n"); exit(1); + } + mpfr_set_prec(x, 53); mpfr_set_prec(t, 108); mpfr_set_prec(u, 108); + mpfr_set_str_raw(x, "-0.10010010001001011011110000000000001010011011011110001E-32"); + mpfr_set_str_raw(t, "-0.101100010111001000010111111101111101000111001111011110011010101111001001111000111011001110011000000000111111"); + mpfr_sub(u, x, t, GMP_RNDU); + mpfr_set_str_raw(t, "0.101100010111001000010111111101110011111110101001101111011010101110100000001011000010101110011000000000111111"); + if (mpfr_cmp(u,t)) { + printf("expect "); mpfr_print_raw(t); putchar('\n'); + fprintf(stderr, "mpfr_add failed for precisions 53-108\n"); exit(1); + } + mpfr_set_prec(x, 97); mpfr_set_prec(t, 97); mpfr_set_prec(u, 97); + mpfr_set_str_raw(x, "0.1111101100001000000001011000110111101000001011111000100001000101010100011111110010000000000000000E-39"); + mpfr_set_ui(t, 1, GMP_RNDN); + mpfr_add(u, x, t, GMP_RNDN); + mpfr_set_str_raw(x, "0.1000000000000000000000000000000000000000111110110000100000000101100011011110100000101111100010001E1"); + if (mpfr_cmp(u,x)) { + fprintf(stderr, "mpfr_add failed for precision 97\n"); exit(1); + } + mpfr_set_prec(x, 128); mpfr_set_prec(t, 128); mpfr_set_prec(u, 128); + mpfr_set_str_raw(x, "0.10101011111001001010111011001000101100111101000000111111111011010100001100011101010001010111111101111010100110111111100101100010E-4"); + mpfr_set(t, x, GMP_RNDN); + mpfr_sub(u, x, t, GMP_RNDN); + mpfr_set_prec(x, 96); mpfr_set_prec(t, 96); mpfr_set_prec(u, 96); + mpfr_set_str_raw(x, "0.111000000001110100111100110101101001001010010011010011100111100011010100011001010011011011000010E-4"); + mpfr_set(t, x, GMP_RNDN); + mpfr_sub(u, x, t, GMP_RNDN); + mpfr_set_prec(x, 85); mpfr_set_prec(t, 85); mpfr_set_prec(u, 85); + mpfr_set_str_raw(x, "0.1111101110100110110110100010101011101001100010100011110110110010010011101100101111100E-4"); + mpfr_set_str_raw(t, "0.1111101110100110110110100010101001001000011000111000011101100101110100001110101010110E-4"); + mpfr_sub(u, x, t, GMP_RNDU); + mpfr_sub(x, x, t, GMP_RNDU); + if (mpfr_cmp(x, u) != 0) { + printf("Error in mpfr_sub: u=x-t and x=x-t give different results\n"); + exit(1); + } + if ((MANT(u)[(PREC(u)-1)/mp_bits_per_limb] & + ((mp_limb_t)1<<(mp_bits_per_limb-1)))==0) { + printf("Error in mpfr_sub: result is not msb-normalized\n"); exit(1); + } + mpfr_set_prec(x, 65); mpfr_set_prec(t, 65); mpfr_set_prec(u, 65); + mpfr_set_str_raw(x, "0.10011010101000110101010000000011001001001110001011101011111011101E623"); + mpfr_set_str_raw(t, "0.10011010101000110101010000000011001001001110001011101011111011100E623"); + mpfr_sub(u, x, t, GMP_RNDU); + if (mpfr_get_d(u) != 9.4349060620538533806e167) { /* 2^558 */ + printf("Error (1) in mpfr_sub\n"); exit(1); + } + mpfr_set_prec(x, 64); mpfr_set_prec(t, 64); mpfr_set_prec(u, 64); + mpfr_set_str_raw(x, "0.1000011110101111011110111111000011101011101111101101101100000100E-220"); + mpfr_set_str_raw(t, "0.1000011110101111011110111111000011101011101111101101010011111101E-220"); + mpfr_add(u, x, t, GMP_RNDU); + if ((MANT(u)[0] & 1) != 1) { + printf("error in mpfr_add with rnd_mode=GMP_RNDU\n"); + printf("b= "); mpfr_print_raw(x); putchar('\n'); + printf("c= "); mpfr_print_raw(t); putchar('\n'); + printf("b+c="); mpfr_print_raw(u); putchar('\n'); + exit(1); + } + mpfr_clear(x); mpfr_clear(t); mpfr_clear(u); +} + +/* checks when source and destination are equal */ +void check_same() +{ + mpfr_t x; + + mpfr_init(x); mpfr_set_d(x, 1.0, GMP_RNDZ); + mpfr_add(x, x, x, GMP_RNDZ); + if (mpfr_get_d(x) != 2.0) { + printf("Error when all 3 operands are equal\n"); exit(1); + } + mpfr_clear(x); +} + +int main(argc,argv) int argc; char *argv[]; +{ + double x,y; int i,prec,rnd_mode,px,py,pz,rnd; +#ifdef IRIX64 + /* to get denormalized numbers on IRIX64 */ + union fpc_csr exp; + exp.fc_word = get_fpc_csr(); + exp.fc_struct.flush = 0; + set_fpc_csr(exp.fc_word); +#endif + + check64(); + check_same(); + check(6.14384195492641560499e-02, -6.14384195401037683237e-02, + GMP_RNDU, 53, 53, 53, 0.0); + check(1.16809465359248765399e+196, 7.92883212101990665259e+196, + GMP_RNDU, 53, 53, 53, 0.0); + check(3.14553393112021279444e-67, 3.14553401015952024126e-67, + GMP_RNDU, 53, 53, 53, 0.0); +#ifdef VERBOSE + printf("Checking random precisions\n"); +#endif + srand(getpid()); + check2(5.43885304644369509058e+185,53,-1.87427265794105342763e-57,53,53,0); + check2(5.43885304644369509058e+185,53,-1.87427265794105342763e-57,53,53,1); + check2(5.43885304644369509058e+185,53,-1.87427265794105342763e-57,53,53,2); + check2(5.43885304644369509058e+185,53,-1.87427265794105342763e-57,53,53,3); + check2(2.26531902208967707071e+168,99,-2.67795218510613988524e+168,67,94,2); + check2(-1.21510626304662318398e+145,70,1.21367733647758957118e+145,65,61,3); + check2(2.73028857032080744543e+155,83,-1.16446121423113355603e+163,59,125,1); + check2(-4.38589520019641698848e+78,155,-1.09923643769309483415e+72,15,159,3); + check2(-1.49963910666191123860e+265,76,-2.30915090591874527520e-191,8,75,1); + check2(5.17945380930936917508e+112,119,1.11369077158813567738e+108,15,150,1); + check2(-2.66910493504493276454e-52,117,1.61188644159592323415e-52,61,68,1); + check2(-1.87427265794105342764e-57,175,1.76570844587489516446e+190,2,115,1); + check2(6.85523243386777784171e+107,187,-2.78148588123699111146e+48,87,178,3); + check2(-1.15706375390780417299e-135,94,-1.07455137477117851576e-129,66,111,2); + check2(-1.15706375390780417299e-135,94,-1.07455137477117851576e-129,66,111,3); + check2(-3.31624349995221499866e-22,107,-8.20150212714204839621e+156,79,99,3); + check2(-1.15706375390780417299e-135,94,-1.07455137477117851576e-129,66,111,3); + check2(-1.08007920352320089721e+150,63,1.77607317509426332389e+73,64,64,0); + check2(4.49465557237618783128e+53,108,-2.45103927353799477871e+48,60,105,0); + check2(3.25471707846623300604e-160,81,-7.93846654265839958715e-274,58,54,0); + check2(-8.88471912490080158206e+253,79,-7.84488427404526918825e+124,95,53,3); + check2(-2.18548638152863831959e-125,61,-1.22788940592412363564e+226,71,54,0); + check2(-7.94156823309993162569e+77,74,-5.26820160805275124882e+80,99,101,3); + check2(-3.85170653452493859064e+189,62,2.18827389706660314090e+158,94,106,3); + check2(1.07966151149311101950e+46,88,1.13198076934147457400e+46,67,53,0); + check2(3.36768223223409657622e+209,55,-9.61624007357265441884e+219,113,53,0); + check2(-6.47376909368979326475e+159,111,5.11127211034490340501e+159,99,62,3); + check2(-4.95229483271607845549e+220,110,-6.06992115033276044773e+213,109,55,0); + check2(-6.47376909368979326475e+159,74,5.11127211034490340501e+159,111,75,2); + check2(2.26531902208967707070e+168,99,-2.67795218510613988525e+168,67,94,2); + check2(-2.28886326552077479586e-188,67,3.41419438647157839320e-177,60,110,2); + check2(-2.66910493504493276454e-52,117,1.61188644159592323415e-52,61,68,1); + check2(2.90983392714730768886e+50,101,2.31299792168440591870e+50,74,105,1); + check2(2.72046257722708717791e+243,97,-1.62158447436486437113e+243,83,96,0); + for (i=0;i<N;i++) { +#ifdef DEBUG +printf("\nTest i=%d\n",i); +#endif + px = 53 + (rand() % 64); + py = 53 + (rand() % 64); + pz = 53 + (rand() % 64); + rnd_mode = rand() % 4; + do { x = drand(); } while (isnan(x)); + do { y = drand(); } while (isnan(y)); + check2(x,px,y,py,pz,rnd_mode); + } +#ifdef VERBOSE + printf("Checking double precision (53 bits)\n"); +#endif + prec = (argc<2) ? 53 : atoi(argv[1]); + rnd_mode = (argc<3) ? -1 : atoi(argv[2]); + check(-8.22183238641455905806e-19, 7.42227178769761587878e-19, + GMP_RNDD, 53, 53, 53, 0.0); + check(5.82106394662028628236e+234, -5.21514064202368477230e+89, + GMP_RNDD, 53, 53, 53, 0.0); + check(5.72931679569871602371e+122, -5.72886070363264321230e+122, + GMP_RNDN, 53, 53, 53, 0.0); + check(-5.09937369394650450820e+238, 2.70203299854862982387e+250, + GMP_RNDD, 53, 53, 53, 0.0); + check(-2.96695924472363684394e+27, 1.22842938251111500000e+16, + GMP_RNDD, 53, 53, 53, 0.0); + check(1.74693641655743793422e-227, -7.71776956366861843469e-229, + GMP_RNDN, 53, 53, 53, 0.0); + check(-1.03432206392780011159e-125, 1.30127034799251347548e-133, + GMP_RNDN, 53, 53, 53, 0.0); + check(1.05824655795525779205e+71, -1.06022698059744327881e+71, + GMP_RNDZ, 53, 53, 53, 0.0); + check(-5.84204911040921732219e+240, 7.26658169050749590763e+240, + GMP_RNDD, 53, 53, 53, 0.0); + /* the following check double overflow */ + /* check(6.27557402141211962228e+307, 1.32141396570101687757e+308, + GMP_RNDZ, 53, 53, 53, 0.0); */ + check(1.00944884131046636376e+221, 2.33809162651471520268e+215, + GMP_RNDN, 53, 53, 53, 0.0); + check(4.29232078932667367325e-278, 1.07735250473897938332e-281, + GMP_RNDU, 53, 53, 53, 0.0); + check(5.27584773801377058681e-80, 8.91207657803547196421e-91, + GMP_RNDN, 53, 53, 53, 0.0); + check(2.99280481918991653800e+272, 5.34637717585790933424e+271, + GMP_RNDN, 53, 53, 53, 0.0); + check(4.67302514390488041733e-184, 2.18321376145645689945e-190, + GMP_RNDN, 53, 53, 53, 0.0); + check(5.57294120336300389254e+71, 2.60596167942024924040e+65, + GMP_RNDZ, 53, 53, 53, 0.0); + x=6151626677899716.0; for (i=0;i<30;i++) x = 2.0*x; + check(x, 4938448004894539.0, GMP_RNDU, 53, 53, 53, 0.0); + check(1.23056185051606761523e-190, 1.64589756643433857138e-181, + GMP_RNDU, 53, 53, 53, 0.0); + check(2.93231171510175981584e-280, 3.26266919161341483877e-273, + GMP_RNDU, 53, 53, 53, 0.0); + check(5.76707395945001907217e-58, 4.74752971449827687074e-51, + GMP_RNDD, 53, 53, 53, 0.0); + check(277363943109.0, 11.0, GMP_RNDN, 53, 53, 53, 0.0); + /* test denormalized numbers too */ + check(8.06294740693074521573e-310, 6.95250701071929654575e-310, + GMP_RNDU, 53, 53, 53, 0.0); +#ifdef VERBOSE + printf("Comparing to double precision using machine arithmetic\n"); +#endif + for (i=0;i<N;i++) { + x = drand(); + y = drand(); + if (ABS(x)>2.2e-307 && ABS(y)>2.2e-307 && x+y<1.7e+308 && x+y>-1.7e308) + /* avoid denormalized numbers and overflows */ + rnd = (rnd_mode==-1) ? lrand48()%4 : rnd_mode; + check(x, y, rnd, prec, prec, prec, 0.0); + } +#ifdef VERBOSE + printf("Checking mpfr_add(x, x, y) with prec=53\n"); +#endif + for (i=0;i<N;i++) { + x = drand(); + y = drand(); + if (ABS(x)>2.2e-307 && ABS(y)>2.2e-307 && x+y<1.7e+308 && x+y>-1.7e308) + /* avoid denormalized numbers and overflows */ + rnd = (rnd_mode==-1) ? lrand48()%4 : rnd_mode; + check3(x, y, rnd); + } +#ifdef VERBOSE + printf("Checking mpfr_add(x, y, x) with prec=53\n"); +#endif + for (i=0;i<N;i++) { + x = drand(); + y = drand(); + if (ABS(x)>2.2e-307 && ABS(y)>2.2e-307 && x+y<1.7e+308 && x+y>-1.7e308) + /* avoid denormalized numbers and overflows */ + rnd = (rnd_mode==-1) ? lrand48()%4 : rnd_mode; + check4(x, y, rnd); + } +#ifdef VERBOSE + printf("Checking mpfr_add(x, x, x) with prec=53\n"); +#endif + for (i=0;i<N;i++) { + do { x = drand(); } while ((ABS(x)<2.2e-307) || (ABS(x)>0.8e308)); + /* avoid denormalized numbers and overflows */ + rnd = (rnd_mode==-1) ? lrand48()%4 : rnd_mode; + check5(x, rnd); + } + exit (0); +} + diff --git a/mpfr/tests/tagm.c b/mpfr/tests/tagm.c new file mode 100644 index 000000000..1782911f2 --- /dev/null +++ b/mpfr/tests/tagm.c @@ -0,0 +1,185 @@ +/* Test file for mpfr_agm. + +Copyright (C) 1999 PolKA project, Inria Lorraine and Loria + +This file is part of the MPFR Library. + +The MPFR Library is free software; you can redistribute it and/or modify +it under the terms of the GNU Library General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at your +option) any later version. + +The MPFR Library 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 Library General Public +License for more details. + +You should have received a copy of the GNU Library General Public License +along with the MPFR Library; see the file COPYING.LIB. If not, write to +the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, +MA 02111-1307, USA. */ + +#include <math.h> +#include <stdio.h> +#include <stdlib.h> +#include <sys/types.h> +#include <unistd.h> +#include "gmp.h" +#include "mpfr.h" +#include "mpfr-impl.h" + +extern int isnan(); + +double drand_agm() +{ + double d; long int *i; + + i = (long int*) &d; + do { + i[0] = lrand48(); + i[1] = lrand48(); + /*if (lrand48()%2) d=-d; */ /* generates negative numbers */ + /* useless here */ + } while ((d<1e-153)||(d>1e153)); /* to avoid underflow or overflow + in double calculus in sqrt(u*v) */ + + return d; +} + + +double max(double a,double b) { + if (a>=b) + return a; + return b; +} + +double min(double a,double b) { + if (b>=a) + return a; + return b; +} + +double dagm(double a, double b) { + double u,v,tmpu,tmpv; + + if ((isnan(a))||(isnan(b))) + return a+b; + + tmpv=max(a,b); + tmpu=min(a,b); + + do + { + u=tmpu; + v=tmpv; + tmpu=sqrt(u*v); + tmpv=(u+v)/2.0; + } + while (!(((tmpu==u)&&(tmpv==v))||(ulp(u,v)==0))); + + /* printf("difference : %i ulp\n",ulp(u,v)); */ + return u; +} + +#define check(a,b,r) check4(a,b,r,0.0) + +void check4(double a, double b, unsigned char rnd_mode, double res1) +{ + mpfr_t ta, tb, tres; + double res2; + int ck=0; + + mpfr_init2(ta, 53); + mpfr_init2(tb, 53); + mpfr_init2(tres, 53); + + mpfr_set_d(ta, a, rnd_mode); + mpfr_set_d(tb, b, rnd_mode); + + mpfr_agm(tres, ta, tb, rnd_mode); + mpfr_set_machine_rnd_mode(rnd_mode); + + if (res1==0.0) res1=dagm(a,b); else ck=1; + res2 = mpfr_get_d(tres); + + if (ck && res1!=res2 && (!isnan(res1) || !isnan(res2))) { + printf("mpfr_agm failed for a=%1.20e, b=%1.20e, rnd_mode=%d\n",a,b,rnd_mode); + printf("expected result is %1.20e, got %1.20e (%d ulp)\n",res1,res2, + ulp(res2,res1)); + /*exit(1);*/ + } + mpfr_clear(ta); mpfr_clear(tb); mpfr_clear(tres); +} + +void check_large() +{ + mpfr_t a, b, agm; + + mpfr_init2(a, 82); mpfr_init2(b, 82); mpfr_init2(agm, 82); + mpfr_set_ui(a, 1, GMP_RNDN); + mpfr_set_str_raw(b, "0.1111101100001000000001011000110111101000001011111000100001000101010100011111110010E-39"); + mpfr_agm(agm, a, b, GMP_RNDN); + mpfr_set_str_raw(a, "0.1110001000111101101010101010101101001010001001001011100101111011110101111001111100E-4"); + if (mpfr_cmp(agm, a)) { + fprintf(stderr, "mpfr_agm failed for precision 82\n"); exit(1); + } + mpfr_clear(a); mpfr_clear(b); mpfr_clear(agm); +} + +void slave(int N, int p) { + int i; + double a,b; + mpfr_t ta, tb, tres; + + srand48(getpid()); + mpfr_init2(ta, 53); + mpfr_init2(tb, 53); + mpfr_init2(tres, p); + for(i=0;i<N;i++) { + a=drand_agm(); + b=drand_agm(); + mpfr_set_d(ta, a, GMP_RNDN); + mpfr_set_d(tb, b, GMP_RNDN); + mpfr_agm(tres, ta, tb, rand() % 4 ); + } + mpfr_clear(ta); mpfr_clear(ta); mpfr_clear(tres); + printf("fin\n"); +} + + +int main(int argc, char* argv[]) { + int N; + + if (argc==3) { /* tagm N p : N calculus with precision p*/ + printf("Doing %d random tests in %d precision\n",atoi(argv[1]),atoi(argv[2])); + slave(atoi(argv[1]),atoi(argv[2])); + exit (0); + } + + if (argc==2) { /* tagm N: N tests with random double's */ + int i; + double a,b; + + srand48(getpid()); + N = atoi(argv[1]); + for (i=0;i<N;i++) { + a = drand(); + b = drand(); + check(a, b, rand() % 4); + } + exit (0); + } + else { + check_large(); + check(2,1,GMP_RNDN); + check(6,4,GMP_RNDN); + check(62,61,GMP_RNDN); + check(0.5,1,GMP_RNDN); + check(1,2,GMP_RNDN); + check4(234375765,234375000,GMP_RNDN,2.34375382499843955040e+08); + check(8,1,GMP_RNDU); + check(1,44,GMP_RNDU); + check(1,3.725290298461914062500000e-9,GMP_RNDU); + } + exit (0); +} diff --git a/mpfr/tests/tcan_round.c b/mpfr/tests/tcan_round.c new file mode 100644 index 000000000..7e452ab80 --- /dev/null +++ b/mpfr/tests/tcan_round.c @@ -0,0 +1,40 @@ +/* Test file for mpfr_can_round. + +Copyright (C) 1999 PolKA project, Inria Lorraine and Loria + +This file is part of the MPFR Library. + +The MPFR Library is free software; you can redistribute it and/or modify +it under the terms of the GNU Library General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at your +option) any later version. + +The MPFR Library 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 Library General Public +License for more details. + +You should have received a copy of the GNU Library General Public License +along with the MPFR Library; see the file COPYING.LIB. If not, write to +the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, +MA 02111-1307, USA. */ + +#include <stdio.h> +#include <stdlib.h> +#include "gmp.h" +#include "mpfr.h" + +int main() +{ + mpfr_t x; + + /* checks that rounds to nearest sets the last + bit to zero in case of equal distance */ + mpfr_init2(x, 59); + mpfr_set_str_raw(x, "-0.10010001010111000011110010111010111110000000111101100111111E663"); + if (mpfr_can_round(x, 54, GMP_RNDZ, GMP_RNDZ, 53) != 0) { + fprintf(stderr, "Error in mpfr_can_round\n"); exit(1); + } + mpfr_clear(x); + exit (0); +} diff --git a/mpfr/tests/tcmp.c b/mpfr/tests/tcmp.c new file mode 100644 index 000000000..0f063c235 --- /dev/null +++ b/mpfr/tests/tcmp.c @@ -0,0 +1,73 @@ +/* Test file for mpfr_cmp. + +Copyright (C) 1999 PolKA project, Inria Lorraine and Loria + +This file is part of the MPFR Library. + +The MPFR Library is free software; you can redistribute it and/or modify +it under the terms of the GNU Library General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at your +option) any later version. + +The MPFR Library 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 Library General Public +License for more details. + +You should have received a copy of the GNU Library General Public License +along with the MPFR Library; see the file COPYING.LIB. If not, write to +the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, +MA 02111-1307, USA. */ + +#include <stdio.h> +#include <stdlib.h> +#include <math.h> +#include "gmp.h" +#include "longlong.h" +#include "mpfr.h" +#include "mpfr-impl.h" + +int +main() +{ + double x,y; mpfr_t xx,yy; int i,c; + + fprintf(stderr, "Test case 'tcmp' disabled\n"); + exit(0); /* THIS TEST CASE IS NOT WORKING */ + + mpfr_init2(xx, 65); mpfr_init2(yy, 65); + mpfr_set_str_raw(xx, "0.10011010101000110101010000000011001001001110001011101011111011101E623"); + mpfr_set_str_raw(yy, "0.10011010101000110101010000000011001001001110001011101011111011100E623"); + if (mpfr_cmp2(xx,yy)!=64) { printf("Error (1) in mpfr_cmp\n"); exit(1); } + mpfr_set_str_raw(xx, "0.10100010001110110111000010001000010011111101000100011101000011100"); + mpfr_set_str_raw(yy, "0.10100010001110110111000010001000010011111101000100011101000011011"); + if (mpfr_cmp2(xx,yy)!=64) { printf("Error (1) in mpfr_cmp\n"); exit(1); } + mpfr_set_prec(xx,53); mpfr_set_prec(yy,200); + mpfr_set_d(xx, 1.0, 0); + mpfr_set_d(yy, 1.0, 0); + if (mpfr_cmp(xx,yy)!=0) { + printf("Error in mpfr_cmp: 1.0 != 1.0\n"); exit(1); + } + mpfr_set_prec(yy, 31); + mpfr_set_d(xx, 1.0000000002, 0); + mpfr_set_d(yy, 1.0, 0); + if (!(mpfr_cmp(xx,yy)>0)) { + printf("Error in mpfr_cmp: not 1.0000000002 > 1.0\n"); exit(1); + } + mpfr_set_prec(yy, 53); + for (i=0;i<1000000;) { + x=drand(); y=drand(); + if (!isnan(x) && !isnan(y)) { + i++; + mpfr_set_d(xx, x, 0); + mpfr_set_d(yy, y, 0); + c = mpfr_cmp(xx,yy); + if ((c>0 && x<=y) || (c==0 && x!=y) || (c<0 && x>=y)) { + printf("Error in mpfr_cmp with x=%1.20e, y=%1.20e mpfr_cmp(x,y)=%d\n", + x,y,c); exit(1); + } + } + } + mpfr_clear(xx); mpfr_clear(yy); + exit (0); +} diff --git a/mpfr/tests/tcmp2.c b/mpfr/tests/tcmp2.c new file mode 100644 index 000000000..f7e3f3599 --- /dev/null +++ b/mpfr/tests/tcmp2.c @@ -0,0 +1,88 @@ +/* Test file for mpfr_cmp2. + +Copyright (C) 1999 PolKA project, Inria Lorraine and Loria + +This file is part of the MPFR Library. + +The MPFR Library is free software; you can redistribute it and/or modify +it under the terms of the GNU Library General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at your +option) any later version. + +The MPFR Library 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 Library General Public +License for more details. + +You should have received a copy of the GNU Library General Public License +along with the MPFR Library; see the file COPYING.LIB. If not, write to +the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, +MA 02111-1307, USA. */ + +#include <stdio.h> +#include <stdlib.h> +#include <math.h> +#include "gmp.h" +#include "longlong.h" +#include "mpfr.h" +#include "mpfr-impl.h" +#ifdef IRIX64 +#include <sys/fpu.h> +#endif + +extern int isnan(); + +void tcmp2(x, y, i) double x, y; int i; +{ + mpfr_t xx,yy; int j; + + if (i==-1) { + if (x==y) i=53; + else i = (int) floor(log(x)/log(2.0)) - (int) floor(log(x-y)/log(2.0)); + } + mpfr_init2(xx, 53); mpfr_init2(yy, 53); + mpfr_set_d(xx, x, 0); + mpfr_set_d(yy, y, 0); + if ((j=mpfr_cmp2(xx, yy)) != i) { + printf("Error in mpfr_cmp2: x=%1.20e y=%1.20e mpfr_cmp2(x,y)=%d instead of %d\n",x,y,j,i); + exit(1); + } + mpfr_set_prec(xx, 127); mpfr_set_prec(yy, 127); + mpfr_set_str_raw(xx, "0.1011010000110111111000000101011110110001000101101011011110010010011110010000101101000010011001100110010000000010110000101000101E6"); + mpfr_set_str_raw(yy, "0.1011010000110111111000000101011011111100011101000011001111000010100010100110110100110010011001100110010000110010010110000010110E6"); + if ((j=mpfr_cmp2(xx, yy)) != 32) { + printf("Error in mpfr_cmp2:\n"); + printf("x="); mpfr_print_raw(xx); putchar('\n'); + printf("y="); mpfr_print_raw(yy); putchar('\n'); + printf("got %d, expected 32\n", j); + exit(1); + } + mpfr_clear(xx); mpfr_clear(yy); +} + +int main() +{ + int i,j; double x=1.0, y, z; +#ifdef IRIX64 + /* to get denormalized numbers on IRIX64 */ + union fpc_csr exp; + exp.fc_word = get_fpc_csr(); + exp.fc_struct.flush = 0; + set_fpc_csr(exp.fc_word); +#endif + + tcmp2(1.06022698059744327881e+71, 1.05824655795525779205e+71, -1); + tcmp2(1.0, 1.0, 53); + for (i=0;i<54;i++) { + tcmp2(1.0, 1.0-x, i); + x /= 2.0; + } + for (j=0;j<1000000;j++) { + x = drand48(); + y = drand48(); + if (x<y) { z=x; x=y; y=z; } + if (y != 0.0 && y != -0.0) tcmp2(x, y, -1); + } + exit (0); +} + diff --git a/mpfr/tests/tcmp_ui.c b/mpfr/tests/tcmp_ui.c new file mode 100644 index 000000000..61410edd0 --- /dev/null +++ b/mpfr/tests/tcmp_ui.c @@ -0,0 +1,58 @@ +/* Test file for mpfr_cmp_ui. + +Copyright (C) 1999 PolKA project, Inria Lorraine and Loria + +This file is part of the MPFR Library. + +The MPFR Library is free software; you can redistribute it and/or modify +it under the terms of the GNU Library General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at your +option) any later version. + +The MPFR Library 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 Library General Public +License for more details. + +You should have received a copy of the GNU Library General Public License +along with the MPFR Library; see the file COPYING.LIB. If not, write to +the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, +MA 02111-1307, USA. */ + +#include <stdio.h> +#include <stdlib.h> +#include <math.h> +#include "gmp.h" +#include "longlong.h" +#include "mpfr.h" + +int +main() +{ + mpfr_t x; unsigned long i; long s; + + mpfr_init(x); + + mpfr_set_ui(x, 3, GMP_RNDZ); + if (mpfr_cmp_ui(x, i=3)!=0) { + printf("Error in mpfr_cmp_ui(%1.20f,%d)\n",mpfr_get_d(x), i); exit(1); + } + if (mpfr_cmp_ui(x, i=2)<=0) { + printf("Error in mpfr_cmp_ui(%1.20f,%d)\n",mpfr_get_d(x), i); exit(1); + } + if (mpfr_cmp_ui(x, i=4)>=0) { + printf("Error in mpfr_cmp_ui(%1.20f,%d)\n",mpfr_get_d(x), i); exit(1); + } + + mpfr_set_si(x, -3, GMP_RNDZ); + if (mpfr_cmp_si(x, s=-3)!=0) { + printf("Error in mpfr_cmp_si(%1.20f,%d)\n",mpfr_get_d(x), s); exit(1); + } + if (mpfr_cmp_si(x, s=-4)<=0) { + printf("Error in mpfr_cmp_si(%1.20f,%d)\n",mpfr_get_d(x), s); exit(1); + } + if (mpfr_cmp_si(x, s=1)>=0) { + printf("Error in mpfr_cmp_si(%1.20f,%d)\n",mpfr_get_d(x), s); exit(1); + } + exit (0); +} diff --git a/mpfr/tests/tdiv.c b/mpfr/tests/tdiv.c new file mode 100644 index 000000000..a7de5dde9 --- /dev/null +++ b/mpfr/tests/tdiv.c @@ -0,0 +1,152 @@ +/* Test file for mpfr_div. + +Copyright (C) 1999 PolKA project, Inria Lorraine and Loria + +This file is part of the MPFR Library. + +The MPFR Library is free software; you can redistribute it and/or modify +it under the terms of the GNU Library General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at your +option) any later version. + +The MPFR Library 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 Library General Public +License for more details. + +You should have received a copy of the GNU Library General Public License +along with the MPFR Library; see the file COPYING.LIB. If not, write to +the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, +MA 02111-1307, USA. */ + +#include <math.h> +#include <stdio.h> +#include <stdlib.h> +#include "gmp.h" +#include "gmp-impl.h" +#include "mpfr.h" +#include "mpfr-impl.h" +#ifdef IRIX64 +#include <sys/fpu.h> +#endif + +extern int isnan(); + +/* #define DEBUG */ + +#define check(n,d,r) check4(n,d,r,53) + +void check4(N, D, rnd_mode, p) double N, D; unsigned char rnd_mode; int p; +{ + mpfr_t q, n, d; double Q,Q2; + +#ifdef DEBUG + printf("N=%1.20e D=%1.20e rnd_mode=%d\n",N,D,rnd_mode); +#endif + mpfr_init2(q, p); mpfr_init2(n, p); mpfr_init2(d, p); + mpfr_set_d(n, N, rnd_mode); + mpfr_set_d(d, D, rnd_mode); + mpfr_div(q, n, d, rnd_mode); + mpfr_set_machine_rnd_mode(rnd_mode); + Q = N/D; + Q2 = mpfr_get_d(q); +#ifdef DEBUG + printf("expected quotient is %1.20e, got %1.20e (%d ulp)\n",Q,Q2, + ulp(Q2,Q)); + mpfr_print_raw(q); putchar('\n'); +#endif + if (Q!=Q2 && (!isnan(Q) || !isnan(Q2))) { + printf("mpfr_div failed for n=%1.20e, d=%1.20e, rnd_mode=%d\n",N,D,rnd_mode); + printf("expected quotient is %1.20e, got %1.20e (%d ulp)\n",Q,Q2, + ulp(Q2,Q)); + exit(1); + } + mpfr_clear(q); mpfr_clear(n); mpfr_clear(d); +} + +void check24(float N, float D, unsigned char rnd_mode) +{ + mpfr_t q, n, d; float Q,Q2; + + mpfr_init2(q, 24); mpfr_init2(n, 24); mpfr_init2(d, 24); + mpfr_set_d(n, N, rnd_mode); + mpfr_set_d(d, D, rnd_mode); + mpfr_div(q, n, d, rnd_mode); + mpfr_set_machine_rnd_mode(rnd_mode); + Q = N/D; + Q2 = mpfr_get_d(q); + if (Q!=Q2 && (!isnan(Q) || !isnan(Q2))) { + printf("mpfr_div failed for n=%1.10e, d=%1.10e, prec=24, rnd_mode=%d\n",N,D,rnd_mode); + printf("expected quotient is %1.10e, got %1.10e\n",Q,Q2); + exit(1); + } + mpfr_clear(q); mpfr_clear(n); mpfr_clear(d); +} + +/* the following examples come from the paper "Number-theoretic Test + Generation for Directed Rounding" from Michael Parks, Table 2 */ +void check_float() +{ + int i; float b=8388608.0; /* 2^23 */ + + for (i=0;i<4;i++) { + check24(b*8388610.0, 8388609.0, i); + check24(b*16777215.0, 16777213.0, i); + check24(b*8388612.0, 8388611.0, i); + check24(b*12582914.0, 12582911.0, i); + check24(12582913.0, 12582910.0, i); + check24(b*16777215.0, 8388609.0, i); + check24(b*8388612.0, 8388609.0, i); + check24(b*12582914.0, 8388610.0, i); + check24(b*12582913.0, 8388610.0, i); + } +} + +void check_convergence() +{ + mpfr_t x, y; + + mpfr_init2(x, 130); + mpfr_set_str_raw(x, "0.1011111101011010101000001010011111101000011100011101010011111011000011001010000000111100100111110011001010110100100001001000111001E6944"); + mpfr_init_set_ui(y, 5, 130, GMP_RNDN); + mpfr_div(x, x, y, GMP_RNDD); /* exact division */ + mpfr_clear(x); mpfr_clear(y); +} + +int main(int argc, char *argv[]) +{ + int i, N; double n, d, e; +#ifdef IRIX64 + /* to get denormalized numbers on IRIX64 */ + union fpc_csr exp; + exp.fc_word = get_fpc_csr(); + exp.fc_struct.flush = 0; + set_fpc_csr(exp.fc_word); +#endif + + N = (argc>1) ? atoi(argv[1]) : 100000; + check_float(); /* checks single precision */ + check_convergence(); + check(0.0, 1.0, 1); + check(-7.49889692246885910000e+63, 4.88168664502887320000e+306, GMP_RNDD); + check(-1.33225773037748601769e+199, 3.63449540676937123913e+79, GMP_RNDZ); + d = 1.0; for (i=0;i<52;i++) d *= 2.0; + check4(4.0, d, GMP_RNDZ, 62); + check4(1.0, 2.10263340267725788209e+187, 2, 65); + check4(2.44394909079968374564e-150, 2.10263340267725788209e+187, 2, 65); + /* the following tests when d is an exact power of two */ + check(9.89438396044940256501e-134, 5.93472984109987421717e-67, 2); + check(9.89438396044940256501e-134, -5.93472984109987421717e-67, 2); + check(-4.53063926135729747564e-308, 7.02293374921793516813e-84, 3); + check(6.25089225176473806123e-01, -2.35527154824420243364e-230, 3); + check(6.52308934689126000000e+15, -1.62063546601505417497e+273, 0); + check(1.04636807108079349236e-189, 3.72295730823253012954e-292, 1); + srand48(getpid()); + for (i=0;i<N;i++) { + do { n = drand(); d = drand(); e = fabs(n)/fabs(d); } + /* smallest normalized is 2^(-1022), largest is 2^(1023)*(2-2^(-52)) */ + while (e>=1.7976931348623157081e308 || e<2.225073858507201383e-308); + check(n, d, rand() % 4); + } + exit (0); +} diff --git a/mpfr/tests/tdiv_ui.c b/mpfr/tests/tdiv_ui.c new file mode 100644 index 000000000..bb45287af --- /dev/null +++ b/mpfr/tests/tdiv_ui.c @@ -0,0 +1,68 @@ +/* Test file for mpfr_div_ui. + +Copyright (C) 1999 PolKA project, Inria Lorraine and Loria + +This file is part of the MPFR Library. + +The MPFR Library is free software; you can redistribute it and/or modify +it under the terms of the GNU Library General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at your +option) any later version. + +The MPFR Library 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 Library General Public +License for more details. + +You should have received a copy of the GNU Library General Public License +along with the MPFR Library; see the file COPYING.LIB. If not, write to +the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, +MA 02111-1307, USA. */ + +#include <math.h> +#include <stdio.h> +#include <stdlib.h> +#include "gmp.h" +#include "mpfr.h" +#include "mpfr-impl.h" +#include "time.h" + +extern int isnan(), getpid(); + +void check(double d, unsigned long u, unsigned char rnd) +{ + mpfr_t x, y; double e, f; + + mpfr_init2(x, 53); mpfr_init2(y, 53); + mpfr_set_machine_rnd_mode(rnd); + e = d / u; + mpfr_set_d(x, d, rnd); + mpfr_div_ui(y, x, u, rnd); + f = mpfr_get_d(y); + if (f != e && (!isnan(f) || !isnan(e))) { + printf("mpfr_div_ui failed for x=%1.20e, u=%lu, rnd=%d\n",d,u,rnd); + printf("expected result is %1.20e, got %1.20e, dif=%d ulp\n",e,f, + ulp(e,f)); + exit(1); + } + mpfr_clear(x); +} + +int +main(int argc, char **argv) +{ + int i; unsigned long u; double d; + + srand(getpid()); + check(1.0, 3, 0); + check(1.0, 3, 1); + check(1.0, 3, 2); + check(1.0, 3, 3); + check(1.0, 2116118, 0); + for (i=0;i<1000000;i++) { + do { u = lrand48(); } while (u==0); + do { d = drand(); } while (fabs(d/u)<2.2e-307); + check(d, u, rand() % 4); + } + exit (0); +} diff --git a/mpfr/tests/texp.c b/mpfr/tests/texp.c new file mode 100644 index 000000000..b23d28431 --- /dev/null +++ b/mpfr/tests/texp.c @@ -0,0 +1,239 @@ +/* Test file for mpfr_exp. + +Copyright (C) 1999 PolKA project, Inria Lorraine and Loria + +This file is part of the MPFR Library. + +The MPFR Library is free software; you can redistribute it and/or modify +it under the terms of the GNU Library General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at your +option) any later version. + +The MPFR Library 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 Library General Public +License for more details. + +You should have received a copy of the GNU Library General Public License +along with the MPFR Library; see the file COPYING.LIB. If not, write to +the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, +MA 02111-1307, USA. */ + +#include <math.h> +#include <stdlib.h> +#include "gmp.h" +#include "gmp-impl.h" +#include "mpfr.h" + +/* #define DEBUG */ + +extern int isnan(); +extern int getpid(); + +int maxu=0; + +/* returns the number of ulp's between a and b */ +int ulp(a,b) double a,b; +{ + double eps=1.1102230246251565404e-16; /* 2^(-53) */ + b = (a-b)/a; if (b<0) b = -b; + return (int) floor(b/eps); +} + +#define check(d, r) check3(d, r, 0.0) + +/* returns the number of ulp of error */ +int check3(double d, unsigned char rnd, double e) +{ + mpfr_t x, y; double f; int u=0, ck=0; + +#ifdef DEBUG + printf("d=%1.20e rnd=%d\n",d,rnd); +#endif + mpfr_init2(x, 53); mpfr_init2(y, 53); + mpfr_set_machine_rnd_mode(rnd); + if (e==0.0) e = exp(d); else ck=1; /* really check */ + mpfr_set_d(x, d, rnd); + mpfr_exp(y, x, rnd); + f = mpfr_get_d(y); + if (f != e && (!isnan(f) || !isnan(e))) { + u = ulp(e,f); + if (u<0) { + if (u == (mp_limb_t)1<<(BITS_PER_MP_LIMB-1)) u += 1; + u=-u; + } + if (u!=0) { + if (ck) { + printf("mpfr_exp failed for x=%1.20e, rnd=%s\n", d, + mpfr_print_rnd_mode(rnd)); + printf("expected result is %1.20e, got %1.20e, dif=%d ulp\n",e,f,u); + exit(1); + } + else if (u>maxu) { + maxu=u; + printf("mpfr_exp differs from libm.a for x=%1.20e, rnd=%d\n",d,rnd); + printf("libm.a gave %1.20e, mpfr_exp got %1.20e, dif=%d ulp\n",e,f,u); + } + } + } + mpfr_clear(x); mpfr_clear(y); + return u; +} + +/* computes n bits of exp(d) */ +int check_large (double d, int n, char rnd) +{ + mpfr_t x; mpfr_t y; + + mpfr_init2(x, n); mpfr_init2(y, n); + if (d==0.0) { /* try exp(Pi*sqrt(163)/3)-640320 */ + mpfr_set_d(x, 163.0, rnd); + mpfr_sqrt(x, x, rnd); + mpfr_pi(y, rnd); + mpfr_mul(x, x, y, rnd); + mpfr_div_ui(x, x, 3, rnd); + } + else mpfr_set_d(x, d, rnd); + mpfr_exp(y, x, rnd); + if (d==0.0) { + mpfr_set_d(x, 640320.0, rnd); + mpfr_sub(y, y, x, rnd); + printf("exp(Pi*sqrt(163)/3)-640320="); + } + else printf("exp(%1.20e)=",d); + mpfr_out_str(stdout, 10, 0, y, rnd); + putchar('\n'); + printf(" ="); mpfr_print_raw(y); putchar('\n'); + if (n==53) printf(" =%1.20e\n", mpfr_get_d(y)); + mpfr_clear(x); mpfr_clear(y); + return 0; +} + +/* expx is the value of exp(X) rounded towards -infinity */ +int check_worst_case(double X, double expx) +{ + mpfr_t x, y; + + mpfr_init2(x, 53); mpfr_init2(y, 53); + mpfr_set_d(x, X, GMP_RNDN); +#ifdef DEBUG + printf("x="); mpfr_print_raw(x); putchar('\n'); +#endif + mpfr_exp(y, x, GMP_RNDD); +#ifdef DEBUG + printf("D(exp(x))="); mpfr_print_raw(y); putchar('\n'); +#endif + if (mpfr_get_d(y) != expx) { + fprintf(stderr, "exp(x) rounded towards -infinity is wrong\n"); exit(1); + } + mpfr_exp(x, x, GMP_RNDN); +#ifdef DEBUG + printf("N(exp(x))="); mpfr_print_raw(x); putchar('\n'); +#endif + mpfr_set_d(x, X, GMP_RNDN); + mpfr_exp(x, x, GMP_RNDU); +#ifdef DEBUG + printf("U(exp(x))="); mpfr_print_raw(x); putchar('\n'); +#endif + mpfr_add_one_ulp(y); + if (mpfr_cmp(x,y)) { + fprintf(stderr, "exp(x) rounded towards +infinity is wrong\n"); exit(1); + } + mpfr_clear(x); mpfr_clear(y); + return 0; +} + +/* worst cases communicated by Jean-Michel Muller and Vincent Lefevre */ +int check_worst_cases() +{ + mpfr_t x; + + mpfr_init2(x, 53); + check_worst_case(4.44089209850062517562e-16, 1.00000000000000022204); + check_worst_case(6.39488462184069720009e-14, 1.00000000000006372680); + check_worst_case(1.84741111297455401935e-12, 1.00000000000184718907); + check_worst_case(1.76177628026265550074e-10, 1.00000000017617751702); + check3(1.76177628026265550074e-10, GMP_RNDN, 1.00000000017617773906); + check_worst_case(7.54175277499595900852e-10, 1.00000000075417516676); + check3(7.54175277499595900852e-10, GMP_RNDN, 1.00000000075417538881); + /* bug found by Vincent Lefe`vre on December 8, 1999 */ + check3(-5.42410311287441459172e+02, GMP_RNDN, 2.7176584868845723e-236); + /* further cases communicated by Vincent Lefe`vre on January 27, 2000 */ + check3(-1.32920285897904911589e-10, GMP_RNDN, 0.999999999867079769622); + check3(-1.44037948245738330735e-10, GMP_RNDN, 0.9999999998559621072757); + check3(-1.66795910430705305937e-10, GMP_RNDZ, 0.9999999998332040895832); + check3(-1.64310953745426656203e-10, GMP_RNDN, 0.9999999998356891017792); + check3(-1.38323574826034659172e-10, GMP_RNDZ, 0.9999999998616764251835); + check3(-1.23621668465115401498e-10, GMP_RNDZ, 0.9999999998763783315425); + mpfr_clear(x); + return 0; +} + +int +main(int argc, char **argv) +{ + int i, N, s=0, e, maxe=0; double d, lo, hi; + + if (argc==4) { check_large(atof(argv[1]), atoi(argv[2]), atoi(argv[3])); + exit(1); } + check_worst_cases(); + check3(0.0, GMP_RNDU, 1.0); + check3(-8.88024741073346941839e-17, GMP_RNDU, 1.0); + check3(8.70772839244701057915e-01, GMP_RNDN, 2.38875626491680437269); + check3(1.0, GMP_RNDN, 2.71828182845904509080); + check3(-3.42135637628104173534e-07, GMP_RNDZ, 0.999999657864420798958); + /* worst case for argument reduction, very near from 5*log(2), + thanks to Jean-Michel Muller + */ + check3(3.4657359027997265421, GMP_RNDN, 32.0); + check3(3.4657359027997265421, GMP_RNDU, 32.0); + check3(3.4657359027997265421, GMP_RNDD, 31.999999999999996447); + srand48(getpid()); + N = (argc==1) ? 0 : atoi(argv[1]); + lo = (argc>=3) ? atof(argv[2]) : -7.083964185e2; + hi = (argc>=4) ? atof(argv[3]) : 7.097827129e2; + for (i=0;i<N;i++) { + /* select d such that exp(d) can be represented as a normalized + machine double-precision number, + i.e. 2^(-1022) <= exp(d) <= 2^(1023)*(2-2^(-52)) */ + d = lo + (hi-lo)*drand48(); + e = check(d, rand() % 4); + s += e; + if (e>maxe) maxe=e; + } + if (N) printf("mean error=%1.2e max error=%d\n", (double)s/(double)N,maxe); + check3(2.26523754332090625496e+01, 3, 6.8833785261699581146e9); + /* errors found in libm.a on PC under Linux */ + check3(1.31478962104089092122e+01, GMP_RNDZ, 5.12930793917860137299e+05); + check3(4.25637507920002378103e-01, GMP_RNDU, 1.53056585656161181497e+00); + check3(6.26551618962329307459e-16, GMP_RNDU, 1.00000000000000066613e+00); + check3(-3.35589513871216568383e-03, GMP_RNDD, 9.96649729583626853291e-01); + check3(1.95151388850007272424e+01, GMP_RNDU, 2.98756340674767792225e+08); + check3(2.45045953503350730784e+01, GMP_RNDN, 4.38743344916128387451e+10); + check3(2.58165606081678085104e+01, GMP_RNDD, 1.62925781879432281494e+11); + check3(-2.36539020084338638128e+01, GMP_RNDZ, 5.33630792749924762447e-11); + check3(2.39211946135858077866e+01, GMP_RNDU, 2.44817704330214385986e+10); + check3(-2.78190533055889162029e+01, 1, 8.2858803483596879512e-13); + /* +45 ulp, wrong side */ + check3(2.64028186174889789584e+01, 3, 2.9281844652878973388e11); /* -45 ulp*/ + check3(2.92086338843268329413e+01, 1, 4.8433797301907177734e12); /* -45 ulp*/ + check3(-2.46355324071459982349e+01, 1, 1.9995129297760994791e-11); + /* +45 ulp, wrong side */ + check3(-2.23509444608605427618e+01, 1, 1.9638492867489702307e-10); + /* +45 ulp, wrong side */ + check3(-2.41175390197331687148e+01, 3, 3.3564940885530624592e-11);/*-45 ulp*/ + check3(2.46363885231578088053e+01, 2, 5.0055014282693267822e10); /* +45 ulp*/ + check3(1.111263531080090984914932e2, GMP_RNDN, 1.8262572323517295459e48); + check3(-3.56196340354684821250e+02, 0, 2.0225297096141478156e-155); /*+352 */ + check3(6.59678273772710895173e+02, 2, 3.1234469273830195529e286); /* +459 */ + check3(5.13772529701934331570e+02, 3, 1.3445427121297197752e223); /* -469 */ + check3(3.57430211008718345056e+02, 3, 1.6981197246857298443e155); /* -610 */ + check3(3.82001814471465536371e+02, 2, 7.9667300591087367805e165); /* +705 */ + check3(5.92396038219384422518e+02, 3, 1.880747529554661989e257); /* -707 */ + check3(-5.02678550462488090034e+02, 2, 4.8919201895446217839e-219); /* +708*/ + check3(5.30015757134837031117e+02, 3, 1.5237672861171573939e230); /* -709 */ + check3(5.16239362447650933063e+02, 1, 1.5845518406744492105e224); /* -710 */ + /* between 1/2 and 1 */ + check3(6.00812634798592370977e-01, 0, 1.823600119339019443); /* +1 ulp */ + exit (0); +} diff --git a/mpfr/tests/tget_str.c b/mpfr/tests/tget_str.c new file mode 100644 index 000000000..ef70086a0 --- /dev/null +++ b/mpfr/tests/tget_str.c @@ -0,0 +1,67 @@ +/* Test file for mpfr_get_str. + +Copyright (C) 1999 PolKA project, Inria Lorraine and Loria + +This file is part of the MPFR Library. + +The MPFR Library is free software; you can redistribute it and/or modify +it under the terms of the GNU Library General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at your +option) any later version. + +The MPFR Library 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 Library General Public +License for more details. + +You should have received a copy of the GNU Library General Public License +along with the MPFR Library; see the file COPYING.LIB. If not, write to +the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, +MA 02111-1307, USA. */ + +#include <math.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include "gmp.h" +#include "mpfr.h" +#include "mpfr-impl.h" +#include <time.h> + +void check(d, rnd) double d; unsigned char rnd; +{ + mpfr_t x; char *str, str2[30]; mp_exp_t e; + + mpfr_init2(x, 53); + mpfr_set_d(x, d, rnd); + str = mpfr_get_str(NULL, &e, 10, 5, x, rnd); + mpfr_set_machine_rnd_mode(rnd); + sprintf(str2, "%1.4e", d); + mpfr_clear(x); + free(str); +} + +int +main(int argc, char **argv) +{ + int i; double d; + + srand(getpid()); + /* printf seems to round towards nearest in all cases, at least with gcc */ + check(4.059650008e-83, 0); + check(-6.606499965302424244461355e233, 0); + check(-7.4, 0); + check(0.997, 0); + check(-4.53063926135729747564e-308, 0); + check(2.14478198760196000000e+16, 0); + check(7.02293374921793516813e-84, 0); + check(-6.7274500420134077e-87,0); + for (i=0;i<100000;i++) { + do { d = drand(); } while (isnan(d)); + check(d, 0); + } + exit (0); +} + + + diff --git a/mpfr/tests/tlog.c b/mpfr/tests/tlog.c new file mode 100644 index 000000000..899c13135 --- /dev/null +++ b/mpfr/tests/tlog.c @@ -0,0 +1,303 @@ +/* Test file for mpfr_log. + +Copyright (C) 1999 PolKA project, Inria Lorraine and Loria + +This file is part of the MPFR Library. + +The MPFR Library is free software; you can redistribute it and/or modify +it under the terms of the GNU Library General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at your +option) any later version. + +The MPFR Library 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 Library General Public +License for more details. + +You should have received a copy of the GNU Library General Public License +along with the MPFR Library; see the file COPYING.LIB. If not, write to +the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, +MA 02111-1307, USA. */ + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <math.h> +#include "gmp.h" +#include "mpfr.h" +#include "mpfr-impl.h" + +double drand_log() +{ + double d; long int *i; + + i = (long int*) &d; + do { + i[0] = lrand48(); + i[1] = lrand48(); + } while ((d<1e-153)||(d>1e153)); /* to avoid underflow or overflow + in double calculus in sqrt(u*v) */ + return d; +} + +#define check(a,r) check2(a,r,0.0) + + +int check1(double a, unsigned char rnd_mode, double res1, int ck) +{ + mpfr_t ta, tres; + double res2; + /* ck=1 iff res1 is certified correct */ + + mpfr_set_machine_rnd_mode(rnd_mode); + if (ck==0 && res1==0.0) res1=log(a); + /* printf("mpfr_log working on a=%1.20e, rnd_mode=%d\n",a,rnd_mode);*/ + mpfr_init2(ta, 53); + mpfr_init2(tres, 53); + mpfr_set_d(ta, a, GMP_RNDN); + mpfr_log(tres, ta, rnd_mode); + res2=mpfr_get_d(tres); + mpfr_clear(ta); mpfr_clear(tres); + + if (res1!=res2 && (!isnan(res1) || !isnan(res2))) { + if (ck) { + printf("mpfr_log failed for a=%1.20e, rnd_mode=%d\n",a,rnd_mode); + printf("correct result is %1.20e\n mpfr_log gives %1.20e (%d ulp)\n",res1,res2,ulp(res1,res2)); + exit(1); + } + else { + printf("mpfr_log differs from libm.a for a=%1.20e, rnd_mode=%d\n",a,rnd_mode); + printf(" double calculus gives %1.20e\n mpfr_log gives %1.20e (%d ulp)\n",res1,res2,ulp(res1,res2)); + } + } + if (!isnan(res1) || !isnan(res2)) + return ulp(res1,res2); + else + return 0; +} + + +void check2(double a, unsigned char rnd_mode, double res1) { + check1(a,rnd_mode, res1,1); + return; +} + +void check3(double d, unsigned long prec, unsigned char rnd) +{ + mpfr_t x, y; + + mpfr_init2(x, prec); mpfr_init2(y, prec); + mpfr_set_d(x, d, rnd); + mpfr_log(y, x, rnd); + mpfr_out_str(stdout, 10, 0, y, rnd); putchar('\n'); + mpfr_print_raw(y); putchar('\n'); + mpfr_clear(x); mpfr_clear(y); +} + +void check4(int N) { + int i, max=-1, sum=0, cur; + double d; + + for(i=0;i<N;i++) { + d=drand_log(); + cur=check1(d,rand() % 4,0.0,0); + if (cur<0) + cur = -cur; + if (cur > max) + max=cur; + sum+=cur; + } + d=(double)sum / (double)N; + printf("max error : %i \t mean error : %f (in ulps)\n",max,d); +} + +void slave(int N, int p) { + int i; + double d; + mpfr_t ta, tres; + + mpfr_init2(ta, 53); + mpfr_init2(tres, p); + for(i=0;i<N;i++) { + d=drand_log(); + mpfr_set_d(ta, d, GMP_RNDN); + mpfr_log(tres, ta,rand() % 4 ); + } + mpfr_clear(ta); mpfr_clear(tres); + printf("fin\n"); +} + + + +/* examples from Jean-Michel Muller and Vincent Lefevre + Cf http://www.ens-lyon.fr/~jmmuller/Intro-to-TMD.htm +*/ + +void check_worst_cases() +{ + check2(1.00089971802309629645, GMP_RNDD, 8.99313519443722736088e-04); + check2(1.00089971802309629645, GMP_RNDN, 8.99313519443722844508e-04); + check2(1.00089971802309629645, GMP_RNDU, 8.99313519443722844508e-04); + + check2(1.01979300812244555452, GMP_RNDD, 1.95996734891603630047e-02); + check2(1.01979300812244555452, GMP_RNDN, 1.95996734891603664741e-02); + check2(1.01979300812244555452, GMP_RNDU, 1.95996734891603664741e-02); + + check2(1.02900871924604464525, GMP_RNDD, 2.85959303301472726744e-02); + check2(1.02900871924604464525, GMP_RNDN, 2.85959303301472761438e-02); + check2(1.02900871924604464525, GMP_RNDU, 2.85959303301472761438e-02); + + check2(1.27832870030418943585, GMP_RNDD, 2.45553521871417795852e-01); + check2(1.27832870030418943585, GMP_RNDN, 2.45553521871417823608e-01); + check2(1.27832870030418943585, GMP_RNDU, 2.45553521871417823608e-01); + + check2(1.31706530746788241792, GMP_RNDD, 2.75406009586277422674e-01); + check2(1.31706530746788241792, GMP_RNDN, 2.75406009586277478185e-01); + check2(1.31706530746788241792, GMP_RNDU, 2.75406009586277478185e-01); + + check2(1.47116981099449883885, GMP_RNDD, 3.86057874110010412760e-01); + check2(1.47116981099449883885, GMP_RNDN, 3.86057874110010412760e-01); + check2(1.47116981099449883885, GMP_RNDU, 3.86057874110010468272e-01); + + check2(1.58405446812987782401, GMP_RNDD, 4.59987679246663727639e-01); + check2(1.58405446812987782401, GMP_RNDN, 4.59987679246663783150e-01); + check2(1.58405446812987782401, GMP_RNDU, 4.59987679246663783150e-01); + + check2(1.67192331263391547047, GMP_RNDD, 5.13974647961076613889e-01); + check2(1.67192331263391547047, GMP_RNDN, 5.13974647961076724911e-01); + check2(1.67192331263391547047, GMP_RNDU, 5.13974647961076724911e-01); + + check2(1.71101198068990645318, GMP_RNDD, 5.37084997042120315669e-01); + check2(1.71101198068990645318, GMP_RNDN, 5.37084997042120315669e-01); + check2(1.71101198068990645318, GMP_RNDU, 5.37084997042120426691e-01); + + check2(1.72634853551388700588, GMP_RNDD, 5.46008504786553605648e-01); + check2(1.72634853551388700588, GMP_RNDN, 5.46008504786553716670e-01); + check2(1.72634853551388700588, GMP_RNDU, 5.46008504786553716670e-01); + + check2(2.00028876593004323325, GMP_RNDD, 6.93291553102749702475e-01); + check2(2.00028876593004323325, GMP_RNDN, 6.93291553102749813497e-01); + check2(2.00028876593004323325, GMP_RNDU, 6.93291553102749813497e-01); + + check2(6.27593230200363105808, GMP_RNDD, 1.83672204800630312072); + check2(6.27593230200363105808, GMP_RNDN, 1.83672204800630334276); + check2(6.27593230200363105808, GMP_RNDU, 1.83672204800630334276); + + check2(7.47216682321367997588, GMP_RNDD, 2.01118502712453661729); + check2(7.47216682321367997588, GMP_RNDN, 2.01118502712453706138); + check2(7.47216682321367997588, GMP_RNDU, 2.01118502712453706138); + + check2(9.34589857718275318632, GMP_RNDD, 2.23493759221664944903); + check2(9.34589857718275318632, GMP_RNDN, 2.23493759221664989312); + check2(9.34589857718275318632, GMP_RNDU, 2.23493759221664989312); + + check2(10.6856587560831854944, GMP_RNDD, 2.36890253928838445674); + check2(10.6856587560831854944, GMP_RNDN, 2.36890253928838445674); + check2(10.6856587560831854944, GMP_RNDU, 2.36890253928838490083); + + check2(12.4646345033981766903, GMP_RNDD, 2.52289539471636015122); + check2(12.4646345033981766903, GMP_RNDN, 2.52289539471636015122); + check2(12.4646345033981766903, GMP_RNDU, 2.52289539471636059531); + + check2(17.0953275851761752335, GMP_RNDD, 2.83880518553861849185); + check2(17.0953275851761752335, GMP_RNDN, 2.83880518553861893594); + check2(17.0953275851761752335, GMP_RNDU, 2.83880518553861893594); + + check2(19.8509496207496916043, GMP_RNDD, 2.98825184582516722998); + check2(19.8509496207496916043, GMP_RNDN, 2.98825184582516722998); + check2(19.8509496207496916043, GMP_RNDU, 2.98825184582516767406); + + check2(23.9512076062771335216, GMP_RNDD, 3.17601874455977206679); + check2(23.9512076062771335216, GMP_RNDN, 3.17601874455977206679); + check2(23.9512076062771335216, GMP_RNDU, 3.17601874455977251088); + + check2(428.315247165198229595, GMP_RNDD, 6.05985948325268264369); + check2(428.315247165198229595, GMP_RNDN, 6.05985948325268353187); + check2(428.315247165198229595, GMP_RNDU, 6.05985948325268353187); +} + +int main(int argc, char *argv[]) { + int N=0; + + srand48(getpid()); + if (argc==4) { /* tlog x prec rnd */ + check3(atof(argv[1]), atoi(argv[2]), atoi(argv[3])); + exit (0); + } + + if (argc==3) { /* tlog N p : N calculus with precision p*/ + printf("Doing %d random tests in %d precision\n",atoi(argv[1]),atoi(argv[2])); + slave(atoi(argv[1]),atoi(argv[2])); + exit (0); + } + + if (argc==2) { /* tlog N: N tests with random double's */ + N=atoi(argv[1]); + printf("Doing %d random tests in double precision\n", N); + /*printf("GMP_RNDN : %i, GMP_RNDZ : %i,GMP_RNDU : %i,GMP_RNDD : %i\n",GMP_RNDN, GMP_RNDZ,GMP_RNDU, GMP_RNDD); */ + check4(N); + } + else { + check_worst_cases(); + + check2(1.01979300812244555452, GMP_RNDN, 1.95996734891603664741e-02); + check2(10.0,GMP_RNDU,2.30258509299404590110e+00); + check2(6.0,GMP_RNDU,1.79175946922805517936); + check2(1.0,GMP_RNDZ,0.0); + check2(62.0,GMP_RNDU,4.12713438504509166905); + check2(0.5,GMP_RNDZ,-6.93147180559945286226e-01); + check2(3.0,GMP_RNDZ,1.09861228866810956006e+00); + check2(234375765.0,GMP_RNDU,1.92724362186836231104e+01); + check2(8.0,GMP_RNDZ,2.07944154167983574765e+00); + check2(44.0,GMP_RNDU,3.78418963391826146392e+00); + check2(1.01979300812244555452, GMP_RNDN, 1.95996734891603664741e-02); + /* bugs found by Vincent Lefe`vre */ + check2(0.99999599881598921769, GMP_RNDN, -4.0011920155404068690e-6); + check2(9.99995576063808955247e-01, GMP_RNDZ, -4.42394597667932383816e-06); + check2(9.99993687357856209097e-01, GMP_RNDN, -6.31266206860017342601e-06); + check2(9.99995223520736886691e-01, GMP_RNDN, -4.77649067052670982220e-06); + check2(9.99993025794720935551e-01, GMP_RNDN, -6.97422959894716163837e-06); + check2(9.99987549017837484833e-01, GMP_RNDN, -1.24510596766369924330e-05); + check2(9.99985901426543311032e-01, GMP_RNDN, -1.40986728425098585229e-05); + check2(9.99986053947420794330e-01, GMP_RNDN, -1.39461498263010849386e-05); + check2(9.99971938247442126979e-01, GMP_RNDN, -2.80621462962173414790e-05); + /* other bugs found by Vincent Lefe`vre */ + check2(1.18615436389927785905e+77, GMP_RNDN, 1.77469768607706015473e+02); + check2(9.48868723578399476187e+77, GMP_RNDZ, 1.79549152432275803903e+02); + check2(2.31822210096938820854e+89, GMP_RNDN, 2.05770873832573869322e+02); + /* further bugs found by Vincent Lefe`vre */ + check2(9.99999989485669482647e-01, GMP_RNDZ, -1.05143305726283042331e-08); + check2(9.99999989237970177136e-01, GMP_RNDZ, -1.07620298807745377934e-08); + check2(9.99999989239339082125e-01, GMP_RNDN, -1.07606609757704445430e-08); + + check2(7.3890560989306504,GMP_RNDU,2.0000000000000004); /* exp(2.0) */ + check2(7.3890560989306495,GMP_RNDU,2.0); /* exp(2.0) */ + check2(7.53428236571286402512e+34,GMP_RNDZ,8.03073567492226345621e+01); + check2(6.18784121531737948160e+19,GMP_RNDZ,4.55717030391710693493e+01); + check2(1.02560267603047283735e+00,GMP_RNDD,2.52804164149448735987e-02); + check2(7.53428236571286402512e+34,GMP_RNDZ,8.03073567492226345621e+01); + check2(1.42470900831881198052e+49,GMP_RNDZ,1.13180637144887668910e+02); + + check2(1.08013816255293777466e+11,GMP_RNDN,2.54055249841782604392e+01); + check2(6.72783635300509015581e-37,GMP_RNDU,-8.32893948416799503320e+01); + check2(2.25904918906057891180e-52,GMP_RNDU,-1.18919480823735682406e+02); + check2(1.48901209246462951085e+00,GMP_RNDD,3.98112874867437460668e-01); + check2(1.70322470467612341327e-01,GMP_RNDN,-1.77006175364294615626); + check2(1.94572026316065240791e+01,GMP_RNDD,2.96821731676437838842); + check2(4.01419512207026418764e+04,GMP_RNDD,1.06001772315501128218e+01); + check2(9.47077365236487591672e-04,GMP_RNDZ,-6.96212977303956748187e+00); + check2(3.95906157687589643802e-109,GMP_RNDD,-2.49605768114704119399e+02); + check2(2.73874914516503004113e-02,GMP_RNDD,-3.59766888618655977794e+00); + check2(9.18989072589566467669e-17,GMP_RNDZ,-3.69258425351464083519e+01); + check2(dbl(2830750724514701.0,131),GMP_RNDZ,dbl(1111664301085491.0,-43)); + check2(1.74827399630587801934e-23,GMP_RNDZ,-5.24008281254547156891e+01); + check2(4.35302958401482307665e+22,GMP_RNDD,5.21277441046519527390e+01); + check2(9.70791868689332915209e+00,GMP_RNDD,2.27294191194272210410e+00); + check2(2.22183639799464011100e-01,GMP_RNDN,-1.50425103275253957413e+00); + check2(2.27313466156682375540e+00,GMP_RNDD,8.21159787095675608448e-01); + check2(6.58057413965851156767e-01,GMP_RNDZ,-4.18463096196088235600e-01); + check2(7.34302197248998461006e+43,GMP_RNDZ,1.01004909469513179942e+02); + check2(6.09969788341579732815e+00,GMP_RNDD,1.80823924264386204363e+00); + } + exit (0); +} diff --git a/mpfr/tests/tlog2.c b/mpfr/tests/tlog2.c new file mode 100644 index 000000000..0ba296a83 --- /dev/null +++ b/mpfr/tests/tlog2.c @@ -0,0 +1,44 @@ +/* Test file for mpfr_log2. + +Copyright (C) 1999 PolKA project, Inria Lorraine and Loria + +This file is part of the MPFR Library. + +The MPFR Library is free software; you can redistribute it and/or modify +it under the terms of the GNU Library General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at your +option) any later version. + +The MPFR Library 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 Library General Public +License for more details. + +You should have received a copy of the GNU Library General Public License +along with the MPFR Library; see the file COPYING.LIB. If not, write to +the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, +MA 02111-1307, USA. */ + +#include <stdlib.h> +#include "gmp.h" +#include "mpfr.h" + +/* tlog2 [prec] [rnd] [0 = no print] */ + +int main(argc, argv) int argc; char *argv[]; +{ + mpfr_t x; int p; unsigned char rnd; + + p = (argc>1) ? atoi(argv[1]) : 53; + rnd = (argc>2) ? atoi(argv[2]) : GMP_RNDZ; + mpfr_init2(x, p); + mpfr_log2(x, rnd); + if (argc>=2) { + printf("log(2)="); mpfr_out_str(stdout, 10, 0, x, rnd); putchar('\n'); + } + else if (mpfr_get_d(x) != 6.9314718055994530941e-1) { + fprintf(stderr, "mpfr_log2 failed for prec=53\n"); exit(1); + } + mpfr_clear(x); + exit (0); +} diff --git a/mpfr/tests/tmul.c b/mpfr/tests/tmul.c new file mode 100644 index 000000000..881d0eb64 --- /dev/null +++ b/mpfr/tests/tmul.c @@ -0,0 +1,175 @@ +/* Test file for mpfr_mul. + +Copyright (C) 1999 PolKA project, Inria Lorraine and Loria + +This file is part of the MPFR Library. + +The MPFR Library is free software; you can redistribute it and/or modify +it under the terms of the GNU Library General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at your +option) any later version. + +The MPFR Library 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 Library General Public +License for more details. + +You should have received a copy of the GNU Library General Public License +along with the MPFR Library; see the file COPYING.LIB. If not, write to +the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, +MA 02111-1307, USA. */ + +#include <stdio.h> +#include <stdlib.h> +#include "gmp.h" +#include "mpfr.h" +#include "mpfr-impl.h" + +#define MINNORM 2.2250738585072013831e-308 /* 2^(-1022), smallest normalized */ + +/* checks that x*y gives the same results in double + and with mpfr with 53 bits of precision */ +void check(double x, double y, unsigned int rnd_mode, unsigned int px, +unsigned int py, unsigned int pz, double res) +{ + double z1,z2; mpfr_t xx,yy,zz; + + mpfr_init2(xx, px); + mpfr_init2(yy, py); + mpfr_init2(zz, pz); + mpfr_set_d(xx, x, rnd_mode); + mpfr_set_d(yy, y, rnd_mode); + mpfr_mul(zz, xx, yy, rnd_mode); + mpfr_set_machine_rnd_mode(rnd_mode); + z1 = (res==0.0) ? x*y : res; + z2 = mpfr_get_d(zz); + if (z1!=z2 && (z1>=MINNORM || z1<=-MINNORM)) { + printf("mpfr_mul "); + if (res==0.0) printf("differs from libm.a"); else printf("failed"); + printf(" for x=%1.20e y=%1.20e with rnd_mode=%u\n",x,y,rnd_mode); + mpfr_print_raw(zz); putchar('\n'); + printf("libm.a gives %1.20e, mpfr_mul gives %1.20e\n",z1,z2); + exit(1); + } + mpfr_clear(xx); mpfr_clear(yy); mpfr_clear(zz); +} + +/* checks that x*y gives the same results in double + and with mpfr with 24 bits of precision */ +void check24(float x, float y, unsigned int rnd_mode, float res) +{ + float z1,z2; mpfr_t xx,yy,zz; + + mpfr_init2(xx, 24); + mpfr_init2(yy, 24); + mpfr_init2(zz, 24); + mpfr_set_d(xx, x, rnd_mode); + mpfr_set_d(yy, y, rnd_mode); + mpfr_mul(zz, xx, yy, rnd_mode); + mpfr_set_machine_rnd_mode(rnd_mode); + z1 = (res==0.0) ? x*y : res; + z2 = (float) mpfr_get_d(zz); + if (z1!=z2) { + printf("mpfr_mul "); + if (res==0.0) printf("differs from libm.a"); else printf("failed"); + printf(" for x=%1.10e y=%1.10e with prec=24 and rnd_mode=%u\n",x,y,rnd_mode); + printf("libm.a gives %1.10e, mpfr_mul gives %1.10e\n",z1,z2); + if (res!=0.0) exit(1); + } + mpfr_clear(xx); mpfr_clear(yy); mpfr_clear(zz); +} + +/* the following examples come from the paper "Number-theoretic Test + Generation for Directed Rounding" from Michael Parks, Table 1 */ +void check_float() +{ + int i; + for (i=0;i<4;i++) { + if (i!=2) { + check24(8388609.0, 8388609.0, i, 0.0); + check24(16777213.0, 8388609.0, i, 0.0); + check24(8388611.0, 8388609.0, i, 0.0); + check24(12582911.0, 8388610.0, i, 0.0); + check24(12582914.0, 8388610.0, i, 0.0); + check24(13981013.0, 8388611.0, i, 0.0); + check24(11184811.0, 8388611.0, i, 0.0); + check24(11184810.0, 8388611.0, i, 0.0); + check24(13981014.0, 8388611.0, i, 0.0); + } + } + i=GMP_RNDU; + check24(8388609.0, 8388609.0, GMP_RNDU, 70368769343488.0); + check24(16777213.0, 8388609.0, GMP_RNDU, 140737479966720.0); + check24(8388611.0, 8388609.0, GMP_RNDU, 70368786120704.0); + check24(12582911.0, 8388610.0, GMP_RNDU, 105553133043712.0); + check24(12582914.0, 8388610.0, GMP_RNDU, 105553166598144.0); + check24(13981013.0, 8388611.0, GMP_RNDU, 117281279442944.0); + check24(11184811.0, 8388611.0, GMP_RNDU, 93825036976128.0); + check24(11184810.0, 8388611.0, GMP_RNDU, 93825020198912.0); + check24(13981014.0, 8388611.0, GMP_RNDU, 117281296220160.0); +} + +/* check sign of result */ +void check_sign() +{ + mpfr_t a, b; + + mpfr_init2(a, 53); mpfr_init2(b, 53); + mpfr_set_d(a, -1.0, GMP_RNDN); + mpfr_set_d(b, 2.0, GMP_RNDN); + mpfr_mul(a, b, b, GMP_RNDN); + if (mpfr_get_d(a) != 4.0) { + fprintf(stderr,"2.0*2.0 gives %1.20e\n", mpfr_get_d(a)); exit(1); + } + mpfr_clear(a); mpfr_clear(b); +} + +int main(argc,argv) int argc; char *argv[]; +{ + double x,y,z; int i,prec,rnd_mode; + + check_float(); + check(6.9314718055994530941514e-1, 0.0, GMP_RNDZ, 53, 53, 53, 0.0); + check(0.0, 6.9314718055994530941514e-1, GMP_RNDZ, 53, 53, 53, 0.0); + prec = (argc<2) ? 53 : atoi(argv[1]); + rnd_mode = (argc<3) ? -1 : atoi(argv[2]); + check_sign(); + check(-4.165000000e4, -0.00004801920768307322868063274915, GMP_RNDN, + 53, 53, 53, 2.0); + check(2.71331408349172961467e-08, -6.72658901114033715233e-165, + GMP_RNDZ, 53, 53, 53, 0.0); + x=0.31869277231188065; y=0.88642843322303122; + check(x, y, GMP_RNDZ, 53, 53, 53, 0.0); + x=8.47622108205396074254e-01; y=3.24039313247872939883e-01; + check(x, y, GMP_RNDU, 28, 45, 1, 0.5); + x=2.63978122803639081440e-01; + y=5736014.0/8388608.0; /* 6.83786096444222835089e-01; */ + check(x, y, GMP_RNDN, 34, 23, 31, 0.180504585267044603); + x=9.84891017624509146344e-01; /* rounded to 1.0 with prec=6 */ + x=1.0; + y=1.18351709358762491320e-01; + check(x, y, GMP_RNDU, 6, 41, 36, 0.1183517093595583); + /* the following checks that rounding to nearest sets the last + bit to zero in case of equal distance */ + check(67108865.0, 134217729.0, GMP_RNDN, 53, 53, 53, 0.0); + x=1.37399642157394197284e-01; y=2.28877275604219221350e-01; + check(x, y, GMP_RNDN, 49, 15, 32, 0.0314472340833162888); + x=4.03160720978664954828e-01; y=5.85483042917246621073e-01; + check(x, y, GMP_RNDZ, 51, 22, 32, 0.2360436821472831); + x=3.90798504668055102229e-14; y=9.85394674650308388664e-04; + check(x, y, GMP_RNDN, 46, 22, 12, 0.385027296503914762e-16); + x=4.58687081072827851358e-01; y=2.20543551472118792844e-01; + check(x, y, GMP_RNDN, 49, 3, 1, 0.125); + for (i=0;i<1000000;) { + x = drand(); + y = drand(); + z = x*y; if (z<0) z=-z; + if (z<1e+308 && z>1e-308) /* don't test overflow/underflow for now */ + { i++; + check(x, y, (rnd_mode==-1) ? lrand48()%4 : rnd_mode, + prec, prec, prec, 0.0); + } + } + exit (0); +} + diff --git a/mpfr/tests/tmul_2exp.c b/mpfr/tests/tmul_2exp.c new file mode 100644 index 000000000..c47031313 --- /dev/null +++ b/mpfr/tests/tmul_2exp.c @@ -0,0 +1,49 @@ +/* Test file for mpfr_mul_2exp. + +Copyright (C) 1999 PolKA project, Inria Lorraine and Loria + +This file is part of the MPFR Library. + +The MPFR Library is free software; you can redistribute it and/or modify +it under the terms of the GNU Library General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at your +option) any later version. + +The MPFR Library 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 Library General Public +License for more details. + +You should have received a copy of the GNU Library General Public License +along with the MPFR Library; see the file COPYING.LIB. If not, write to +the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, +MA 02111-1307, USA. */ + +#include <stdio.h> +#include <stdlib.h> +#include <time.h> +#include "gmp.h" +#include "mpfr.h" + +/* checks that x*y gives the same results in double + and with mpfr with 53 bits of precision */ + +int +main(argc,argv) int argc; char *argv[]; +{ + double x, z; mpfr_t w; + + mpfr_init2(w, 53); + + srand48(time(NULL)); + x = drand48(); + mpfr_set_d(w, x, 0); + mpfr_mul_2exp(w, w, 10, GMP_RNDZ); + if (x != (z = mpfr_get_d(w)/1024)) + { + fprintf(stderr, "%f != %f\n", x, z); + exit (1); + } + exit (0); +} + diff --git a/mpfr/tests/tmul_ui.c b/mpfr/tests/tmul_ui.c new file mode 100644 index 000000000..fab7d50fd --- /dev/null +++ b/mpfr/tests/tmul_ui.c @@ -0,0 +1,66 @@ +/* Test file for mpfr_mul_ui. + +Copyright (C) 1999 PolKA project, Inria Lorraine and Loria + +This file is part of the MPFR Library. + +The MPFR Library is free software; you can redistribute it and/or modify +it under the terms of the GNU Library General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at your +option) any later version. + +The MPFR Library 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 Library General Public +License for more details. + +You should have received a copy of the GNU Library General Public License +along with the MPFR Library; see the file COPYING.LIB. If not, write to +the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, +MA 02111-1307, USA. */ + +#include <stdio.h> +#include <stdlib.h> +#include "gmp.h" +#include "gmp-impl.h" +#include "mpfr.h" +#include "time.h" + +int +main(int argc, char **argv) +{ + mpfr_t x, y; + + mpfr_init2(x, 53); mpfr_init2(y, 53); + + /* checks that result is normalized */ + mpfr_set_d(y, 6.93147180559945286227e-01, GMP_RNDZ); + mpfr_mul_ui(x, y, 1, GMP_RNDZ); + if (MANT(x)[PREC(x)/BITS_PER_MP_LIMB] >> (BITS_PER_MP_LIMB-1) == 0) { + fprintf(stderr, "Error in mpfr_mul_ui: result not normalized\n"); + exit(1); + } + if (mpfr_cmp(x,y)) { + fprintf(stderr, "Error in mpfr_mul_ui: 1*y != y\n"); + printf("y= "); mpfr_print_raw(y); putchar('\n'); + printf("1*y="); mpfr_print_raw(x); putchar('\n'); + exit(1); + } + + mpfr_set_d(x, 1.0/3.0, GMP_RNDZ); + mpfr_mul_ui(x, x, 3, GMP_RNDU); + if (mpfr_get_d(x) != 1.0) { + fprintf(stderr, "Error in mpfr_mul_ui: U(Z(1/3)*3) does not give 1\n"); exit(1); + } + + /* checks sign is correct */ + mpfr_set_d(x, -2.0, GMP_RNDZ); + mpfr_set_d(y, 3.0, GMP_RNDZ); + mpfr_mul_ui(x, y, 4, GMP_RNDZ); + if (SIGN(x) != 1) { + fprintf(stderr, "Error in mpfr_mul_ui: 4*3.0 does not give a positive result\n"); exit(1); + } + + mpfr_clear(x); mpfr_clear(y); + exit (0); +} diff --git a/mpfr/tests/tout_str.c b/mpfr/tests/tout_str.c new file mode 100644 index 000000000..cfb8a822e --- /dev/null +++ b/mpfr/tests/tout_str.c @@ -0,0 +1,85 @@ +/* Test file for mpfr_out_str. + +Copyright (C) 1999 PolKA project, Inria Lorraine and Loria + +This file is part of the MPFR Library. + +The MPFR Library is free software; you can redistribute it and/or modify +it under the terms of the GNU Library General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at your +option) any later version. + +The MPFR Library 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 Library General Public +License for more details. + +You should have received a copy of the GNU Library General Public License +along with the MPFR Library; see the file COPYING.LIB. If not, write to +the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, +MA 02111-1307, USA. */ + +#include <math.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> +#include "gmp.h" +#include "mpfr.h" +#include "mpfr-impl.h" + +FILE *fout; + +#define check(d,r,b) check4(d,r,b,53) + +void check4(d, rnd, base, prec) double d; unsigned char rnd; int base, prec; +{ + mpfr_t x; + + mpfr_init2(x, prec); + mpfr_set_d(x, d, rnd); + mpfr_set_machine_rnd_mode(rnd); + fprintf(fout, "%1.19e base %d rnd %d:\n ", d, base, rnd); + mpfr_out_str(fout, base, (base==2) ? prec : 0, x, rnd); + fputc('\n', fout); + mpfr_clear(x); +} + +int +main(int argc, char **argv) +{ + int i,N=100,r,p; double d; + + /* with no argument: prints to /dev/null, + tout_str N: prints N tests to stdout */ + if (argc==1) fout=fopen("/dev/null", "w"); + else { fout=stdout; N=atoi(argv[1]); } + check(-1.5674376729569697500e+15, GMP_RNDN, 19); + check(-5.71262771772792640000e-79, GMP_RNDU, 16); + check(-0.0, GMP_RNDU, 7); + check(-4.5306392613572974756e-308, GMP_RNDN, 8); + check(-6.7265890111403371523e-165, GMP_RNDN, 4); + check(-1.3242553591261807653e+156, GMP_RNDN, 16); + check(-6.606499965302424244461355e233, GMP_RNDN, 10); + check4(1.0, GMP_RNDN, 10, 120); + check(1.0, GMP_RNDU, 10); + check(4.059650008e-83, GMP_RNDN, 10); + check(-7.4, GMP_RNDN, 10); + check(0.997, GMP_RNDN, 10); + check(-4.53063926135729747564e-308, GMP_RNDN, 10); + check(2.14478198760196000000e+16, GMP_RNDN, 10); + check(7.02293374921793516813e-84, GMP_RNDN, 10); + + /* random tests */ + srand(getpid()); + for (i=0;i<N;i++) { + do { d = drand(); } while (isnan(d)); + r = rand()%4; + p = 2 + rand()%35; + check(d, r, p); + } + exit (0); +} + + + diff --git a/mpfr/tests/tpi.c b/mpfr/tests/tpi.c new file mode 100644 index 000000000..487983c5f --- /dev/null +++ b/mpfr/tests/tpi.c @@ -0,0 +1,44 @@ +/* Test file for mpfr_pi. + +Copyright (C) 1999 PolKA project, Inria Lorraine and Loria + +This file is part of the MPFR Library. + +The MPFR Library is free software; you can redistribute it and/or modify +it under the terms of the GNU Library General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at your +option) any later version. + +The MPFR Library 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 Library General Public +License for more details. + +You should have received a copy of the GNU Library General Public License +along with the MPFR Library; see the file COPYING.LIB. If not, write to +the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, +MA 02111-1307, USA. */ + +#include <stdlib.h> +#include "gmp.h" +#include "mpfr.h" + +/* tpi [prec] [rnd] [0 = no print] */ + +int main(argc, argv) int argc; char *argv[]; +{ + mpfr_t x; int p; unsigned char rnd; + + p = (argc>1) ? atoi(argv[1]) : 53; + rnd = (argc>2) ? atoi(argv[2]) : GMP_RNDZ; + mpfr_init2(x, p); + mpfr_pi(x, rnd); + if (argc>=2) { + printf("Pi="); mpfr_out_str(stdout, 10, 0, x, rnd); putchar('\n'); + } + else if (mpfr_get_d(x) != 3.141592653589793116) { + fprintf(stderr, "mpfr_pi failed for prec=53\n"); exit(1); + } + mpfr_clear(x); + exit (0); +} diff --git a/mpfr/tests/tround.c b/mpfr/tests/tround.c new file mode 100644 index 000000000..3ccd6ff7f --- /dev/null +++ b/mpfr/tests/tround.c @@ -0,0 +1,45 @@ +/* Test file for mpfr_round. + +Copyright (C) 1999 PolKA project, Inria Lorraine and Loria + +This file is part of the MPFR Library. + +The MPFR Library is free software; you can redistribute it and/or modify +it under the terms of the GNU Library General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at your +option) any later version. + +The MPFR Library 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 Library General Public +License for more details. + +You should have received a copy of the GNU Library General Public License +along with the MPFR Library; see the file COPYING.LIB. If not, write to +the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, +MA 02111-1307, USA. */ + +#include <stdio.h> +#include <stdlib.h> +#include "gmp.h" +#include "mpfr.h" + +int +main() +{ + mpfr_t x; + + /* checks that rounds to nearest sets the last + bit to zero in case of equal distance */ + mpfr_init2(x, 2); + mpfr_set_d(x, 5.0, 0); + if (mpfr_get_d(x) != 4.0) { printf("Error in tround: got %1.1f instead of 4.0\n",mpfr_get_d(x)); } + + mpfr_set_d(x, 0.00098539467465030839, 0); + + mpfr_set_d(x, 9.84891017624509146344e-01, GMP_RNDU); + if (mpfr_get_d(x) != 1.0) { printf("Error in tround: got %f instead of 1.0\n",mpfr_get_d(x)); exit(1); } + + mpfr_clear(x); + exit (0); +} diff --git a/mpfr/tests/tset_d.c b/mpfr/tests/tset_d.c new file mode 100644 index 000000000..c542dc1e2 --- /dev/null +++ b/mpfr/tests/tset_d.c @@ -0,0 +1,90 @@ +/* Test file for mpfr_set_d and mpfr_get_d. + +Copyright (C) 1999 PolKA project, Inria Lorraine and Loria + +This file is part of the MPFR Library. + +The MPFR Library is free software; you can redistribute it and/or modify +it under the terms of the GNU Library General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at your +option) any later version. + +The MPFR Library 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 Library General Public +License for more details. + +You should have received a copy of the GNU Library General Public License +along with the MPFR Library; see the file COPYING.LIB. If not, write to +the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, +MA 02111-1307, USA. */ + +#include <stdio.h> +#include <stdlib.h> +#include <time.h> +#ifdef IRIX64 +#include <sys/fpu.h> +#endif +#include "gmp.h" +#include "mpfr.h" +#include "mpfr-impl.h" + +extern int isnan(); + +int +main(int argc, char **argv) +{ + fprintf(stderr, "Test case tset_d disabled\n"); + exit(0); /* THIS TEST CASE IS NOT WORKING */ + +#if 0 + mpfr_t x,y,z; unsigned long k,n; double d, dd; +#ifdef IRIX64 + /* to get denormalized numbers on IRIX64 */ + union fpc_csr exp; + exp.fc_word = get_fpc_csr(); + exp.fc_struct.flush = 0; + set_fpc_csr(exp.fc_word); +#endif + + mpfr_init2(z, 32); + mpfr_set_d(z, 1.0, 0); + if (mpfr_get_d(z) != 1.0) { + mpfr_print_raw(z); putchar('\n'); + printf("Error: 1.0 != 1.0\n"); exit(1); + } + mpfr_init2(x, 53); mpfr_init2(y, 53); + mpfr_set_d(x, d=-1.08007920352320089721e+150, 0); + if (mpfr_get_d(x) != d) { + mpfr_print_raw(x); putchar('\n'); + printf("Error: get_d o set_d <> identity for d = %1.20e %1.20e\n",d, + mpfr_get_d(x)); exit(1); + } + srand48(time(NULL)); + mpfr_set_d(x, 8.06294740693074521573e-310, 0); + d = -6.72658901114033715233e-165; + mpfr_set_d(x, d, 0); + if (d != mpfr_get_d(x)) { + mpfr_print_raw(x); putchar('\n'); + printf("Error: get_d o set_d <> identity for d = %1.20e %1.20e\n",d, + mpfr_get_d(x)); exit(1); + } + n = (argc==1) ? 1000000 : atoi(argv[1]); + for (k = 1; k <= n; k++) + { + d = drand(); + mpfr_set_d(x, d, 0); + dd = mpfr_get_d(x); + if (d != dd && (!isnan(d) || !isnan(dd))) + { + fprintf(stderr, + "Mismatch on : %1.18g != %1.18g\n", d, mpfr_get_d(x)); + mpfr_print_raw(x); putchar('\n'); + } + } + + mpfr_clear(x); mpfr_clear(y); mpfr_clear(z); + exit (0); +#endif /* 0 */ +} + diff --git a/mpfr/tests/tset_f.c b/mpfr/tests/tset_f.c new file mode 100644 index 000000000..4a82f0a40 --- /dev/null +++ b/mpfr/tests/tset_f.c @@ -0,0 +1,74 @@ +/* Test file for mpfr_set_f. + +Copyright (C) 1999 PolKA project, Inria Lorraine and Loria + +This file is part of the MPFR Library. + +The MPFR Library is free software; you can redistribute it and/or modify +it under the terms of the GNU Library General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at your +option) any later version. + +The MPFR Library 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 Library General Public +License for more details. + +You should have received a copy of the GNU Library General Public License +along with the MPFR Library; see the file COPYING.LIB. If not, write to +the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, +MA 02111-1307, USA. */ + +#include <stdio.h> +#include <stdlib.h> +#include "gmp.h" +#include "mpfr.h" +#include "time.h" + +#if defined(hpux) +#define srandom srand48 +#endif + +int +main() +{ + mpfr_t x; mpf_t y; mpf_t z; unsigned long k, pr; double f; + + mpfr_init2(x, 100); + mpf_init(y); + + mpf_set_d(y, 0.0); + mpfr_set_f(x, y, GMP_RNDN); + + srandom(time(NULL)); + mpf_random2(y, 10, 0); + mpfr_set_f(x, y, rand() & 3); + + /* bug found by Jean-Pierre Merlet on February 3, 2000 */ + mpfr_set_prec(x, 256); mpf_init2(y, 256); + mpfr_set_machine_rnd_mode(GMP_RNDD); + mpf_set_str(y, "2033.033", 10); + mpfr_set_f(x, y, GMP_RNDN); + f = mpfr_get_d(x); + if (f != 2033.0329999999999017745722085) { + fprintf(stderr, "mpfr_set_f failed for y=2033.033\n"); exit(1); + } + mpf_set_str(y, "-2033.033", 10); + mpfr_set_f(x, y, GMP_RNDN); + f = mpfr_get_d(x); + if (f != -2033.0330000000001291482476518) { + fprintf(stderr, "mpfr_set_f failed for y=-2033.033\n"); exit(1); + } + + mpf_clear(y); mpfr_clear(x); + + for (k = 1; k <= 100000; k++) + { + pr = 1 + (rand()&255); + mpf_init2(z, pr); + mpf_random2(z, z->_mp_prec, 0); + mpfr_init2(x, pr); + mpfr_set_f(x, z, 0); + } + exit (0); +} diff --git a/mpfr/tests/tset_si.c b/mpfr/tests/tset_si.c new file mode 100644 index 000000000..db4e73ac7 --- /dev/null +++ b/mpfr/tests/tset_si.c @@ -0,0 +1,65 @@ +/* Test file for mpfr_set_si and mpfr_set_ui. + +Copyright (C) 1999 PolKA project, Inria Lorraine and Loria + +This file is part of the MPFR Library. + +The MPFR Library is free software; you can redistribute it and/or modify +it under the terms of the GNU Library General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at your +option) any later version. + +The MPFR Library 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 Library General Public +License for more details. + +You should have received a copy of the GNU Library General Public License +along with the MPFR Library; see the file COPYING.LIB. If not, write to +the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, +MA 02111-1307, USA. */ + +#include <stdio.h> +#include <stdlib.h> +#include "gmp.h" +#include "mpfr.h" +#include "time.h" + +int +main(int argc, char **argv) +{ + mpfr_t x; long k, z, d; unsigned long zl, dl, N; + + mpfr_init2(x, 100); + + srandom(time(NULL)); + + N = (argc==1) ? 1000000 : atoi(argv[1]); + + for (k = 1; k <= N; k++) + { + z = random() - (1 << 30); + mpfr_set_si(x, z, GMP_RNDZ); + d = (int)mpfr_get_d(x); + if (d != z) + { + fprintf(stderr, "Expected %ld got %ld\n", z, d); + exit(1); + } + } + + for (k = 1; k <= N; k++) + { + zl = random(); + mpfr_set_ui(x, zl, GMP_RNDZ); + dl = (unsigned int) mpfr_get_d(x); + if (dl != zl) + { + fprintf(stderr, "Expected %lu got %lu\n", zl, dl); + exit(1); + } + } + + mpfr_clear(x); + exit (0); +} diff --git a/mpfr/tests/tset_str.c b/mpfr/tests/tset_str.c new file mode 100644 index 000000000..a1cd3000d --- /dev/null +++ b/mpfr/tests/tset_str.c @@ -0,0 +1,87 @@ +/* Test file for mpfr_set_str. + +Copyright (C) 1999 PolKA project, Inria Lorraine and Loria + +This file is part of the MPFR Library. + +The MPFR Library is free software; you can redistribute it and/or modify +it under the terms of the GNU Library General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at your +option) any later version. + +The MPFR Library 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 Library General Public +License for more details. + +You should have received a copy of the GNU Library General Public License +along with the MPFR Library; see the file COPYING.LIB. If not, write to +the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, +MA 02111-1307, USA. */ + +#include <stdio.h> +#include <stdlib.h> +#include "gmp.h" +#include "mpfr.h" +#include <time.h> + +#if defined (hpux) +#define srandom srand48 +#define random mrand48 +#endif + +int +main(int argc, char **argv) +{ + mpfr_t x; unsigned long k, bd, nc; char *str, *str2; + + if (argc==2) { /* tset_str <string> */ + mpfr_init2(x, 53); + mpfr_set_str_raw(x, argv[1]); + printf("%1.20e\n", mpfr_get_d(x)); + mpfr_clear(x); + exit (0); + } + + srandom(time(NULL)); + + if (argc > 1) { nc = atoi(argv[1]); } else { nc = 53; } + if (nc < 24) { nc = 24; } + + bd = random()&8; + + str2 = str = (char *) malloc (nc*sizeof(char)); + + if (bd) + { + for(k = 1; k <= bd; k++) + { *(str2++) = (random() & 1) + '0'; } + } + else { *(str2++) = '0'; } + + *(str2++) = '.'; + + for(k = 1; k < nc - 17 - bd; k++) + { + *(str2++) = '0' + (random() & 1); + } + + *(str2++) = 'e'; + sprintf(str2, "%d", random() - (1 << 30)); + + /* printf("%s\n", str); */ + mpfr_init2(x, nc + 10); + mpfr_set_str_raw(x, str); + /* mpfr_print_raw(x); printf("\n"); */ + + mpfr_set_prec(x, 53); + mpfr_set_str_raw(x, "+110101100.01010000101101000000100111001000101011101110E00"); + + mpfr_set_str_raw(x, "1.0"); + if (mpfr_get_d(x) != 1.0) { + fprintf(stderr, "Error in mpfr_set_str_raw for s=1.0\n"); exit(1); + } + + mpfr_clear(x); free(str); + exit (0); +} diff --git a/mpfr/tests/tset_z.c b/mpfr/tests/tset_z.c new file mode 100644 index 000000000..61fe654f3 --- /dev/null +++ b/mpfr/tests/tset_z.c @@ -0,0 +1,66 @@ +/* Test file for mpfr_set_z. + +Copyright (C) 1999 PolKA project, Inria Lorraine and Loria + +This file is part of the MPFR Library. + +The MPFR Library is free software; you can redistribute it and/or modify +it under the terms of the GNU Library General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at your +option) any later version. + +The MPFR Library 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 Library General Public +License for more details. + +You should have received a copy of the GNU Library General Public License +along with the MPFR Library; see the file COPYING.LIB. If not, write to +the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, +MA 02111-1307, USA. */ + +#include <stdlib.h> +#include <unistd.h> +#include "gmp.h" +#include "mpfr.h" + +/* tset_z z rnd prec */ + +void check(long i, unsigned char rnd) { + mpfr_t f; mpz_t z; + + mpfr_init2(f, 53); mpz_init(z); + mpz_set_ui(z, i); + mpfr_set_z(f, z, rnd); + if ((long)mpfr_get_d(f) != i) { + printf("Error in mpfr_set_z for i=%ld rnd_mode=%d\n",i,rnd); + exit(1); + } + mpfr_clear(f); mpz_clear(z); +} + +void check_large() +{ + mpz_t z; mpfr_t x,y; + + mpz_init(z); mpfr_init2(x, 160); mpfr_init2(y, 160); + mpz_set_str(z, "77031627725494291259359895954016675357279104942148788042", 10); + mpfr_set_z(x, z, GMP_RNDN); + mpfr_set_str_raw(y, "0.1100100100001111110110101010001000100001011010001100001000110100110001001100011001100010100010111000000011011100000111001101000100101001000000100100111000001001E186"); + if (mpfr_cmp(x,y)) { + fprintf(stderr, "Error in mpfr_set_z on large input\n"); exit(1); + } + mpz_clear(z); mpfr_clear(x); mpfr_clear(y); +} + +int main(argc,argv) int argc; char *argv[]; +{ + long j; + + check_large(); + srand(getpid()); + for (j=0; j<1000000; j++) + check(lrand48(), rand()%4); + exit (0); +} + diff --git a/mpfr/tests/tsqrt.c b/mpfr/tests/tsqrt.c new file mode 100644 index 000000000..ccffad0c5 --- /dev/null +++ b/mpfr/tests/tsqrt.c @@ -0,0 +1,149 @@ +/* Test file for mpfr_sqrt. + +Copyright (C) 1999 PolKA project, Inria Lorraine and Loria + +This file is part of the MPFR Library. + +The MPFR Library is free software; you can redistribute it and/or modify +it under the terms of the GNU Library General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at your +option) any later version. + +The MPFR Library 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 Library General Public +License for more details. + +You should have received a copy of the GNU Library General Public License +along with the MPFR Library; see the file COPYING.LIB. If not, write to +the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, +MA 02111-1307, USA. */ + +#include <math.h> +#include <stdio.h> +#include <stdlib.h> +#include "gmp.h" +#include "gmp-impl.h" +#include "mpfr.h" +#include "mpfr-impl.h" +#ifdef IRIX64 +#include <sys/fpu.h> +#endif + +extern int isnan(), getpid(); + +#define check(a,r) check3(a,r,-1.0) + +int maxulp=0; + +void check3(a, rnd_mode, Q) double a; unsigned char rnd_mode; double Q; +{ + mpfr_t q; double Q2; int ck,u; + + ck = (Q!=-1.0); /* if ck=1, then Q is certified correct */ + mpfr_init2(q, 53); + mpfr_set_d(q, a, rnd_mode); + mpfr_set_machine_rnd_mode(rnd_mode); + mpfr_sqrt(q, q, rnd_mode); + if (ck==0) Q = sqrt(a); + Q2 = mpfr_get_d(q); + if (Q!=Q2 && (!isnan(Q) || !isnan(Q2))) { + u = ulp(Q2,Q); + if (ck) { + printf("mpfr_sqrt failed for a=%1.20e, rnd_mode=%d\n",a,rnd_mode); + printf("expected sqrt is %1.20e, got %1.20e (%d ulp)\n",Q,Q2,u); + exit(1); + } + else if (u>maxulp || u<-maxulp) { + maxulp = (u>maxulp) ? u : -u; + printf("libm.a differs from mpfr_sqrt for a=%1.20e, rnd_mode=%d\n",a,rnd_mode); + printf("libm.a gives %1.20e, mpfr_sqrt gives %1.20e (%d ulp)\n",Q,Q2,u); + } + } + mpfr_clear(q); +} + +void check24(a, rnd_mode) float a; unsigned char rnd_mode; +{ + mpfr_t q; float Q,Q2; + + mpfr_init2(q, 24); + mpfr_set_d(q, a, rnd_mode); + mpfr_set_machine_rnd_mode(rnd_mode); + mpfr_sqrt(q, q, rnd_mode); + Q = sqrt(a); + Q2 = mpfr_get_d(q); + if (Q!=Q2 && (!isnan(Q) || !isnan(Q2))) { + printf("mpfr_sqrt failed for a=%1.10e, rnd_mode=%d\n",a,rnd_mode); + printf("expected sqrt is %1.10e, got %1.10e\n",Q,Q2); + exit(1); + } + mpfr_clear(q); +} + +/* the following examples come from the paper "Number-theoretic Test + Generation for Directed Rounding" from Michael Parks, Table 3 */ +void check_float() +{ + int i; float b = 8388608.0; /* 2^23 */ + + for (i=0;i<4;i++) { + check24(b*8388610.0, i); + check24(b*2.0*16777214.0, i); + check24(b*8388612.0, i); + check24(b*2.0*16777212.0, i); + check24(b*11946704.0, i); + check24(b*14321479.0, i); + check24(b*2.0*13689673.0, i); + check24(b*8388614.0, i); + check24(b*2.0*16777210.0, i); + check24(b*10873622.0, i); + } +} + +int main() +{ + int i; double a; +#ifdef IRIX64 + /* to get denormalized numbers on IRIX64 */ + union fpc_csr exp; + exp.fc_word = get_fpc_csr(); + exp.fc_struct.flush = 0; + set_fpc_csr(exp.fc_word); +#endif + + check_float(); + srand(getpid()); +/* the following examples come from the paper "Number-theoretic Test + Generation for Directed Rounding" from Michael Parks, Table 4 */ + a = 4503599627370496.0; /* 2^52 */ + for (i=0;i<4;i++) { + check(a*2.0*8732221479794286.0, i); + check(a*8550954388695124.0, i); + check(a*7842344481681754.0, i); + check(a*5935035262218600.0, i); + check(a*5039650445085418.0, i); + check(a*5039721545366078.0, i); + check(a*8005963117781324.0, i); + check(a*6703494707970582.0, i); + check(a*8010323124937260.0, i); + check(a*2.0*8010776873384260.0, i); + } + check(6.37983013646045901440e+32, GMP_RNDN); + check(1.0, GMP_RNDN); + check(1.0, GMP_RNDZ); + check(3.725290298461914062500000e-9, GMP_RNDN); + check(3.725290298461914062500000e-9, GMP_RNDZ); + a=1190456976439861.0; + check3(a, GMP_RNDZ, dbl(4630914205854029.0,-27)); + check3(1024.0*a, GMP_RNDZ, dbl(4630914205854029.0,-22)); + /* the following examples are bugs in Cygnus compiler/system, found by + Fabrice Rouillier while porting mpfr to Windows */ + check3(9.89438396044940256501e-134, GMP_RNDU, 3.14553397063986684729e-67); + check3(7.86528588050363751914e+31, GMP_RNDZ, 8.86864469944739400000e+15); + for (i=0;i<100000;i++) { + a = drand(); + check(a, rand() % 4); + } + exit (0); +} diff --git a/mpfr/tests/tzeta.c b/mpfr/tests/tzeta.c new file mode 100644 index 000000000..d9495e57b --- /dev/null +++ b/mpfr/tests/tzeta.c @@ -0,0 +1,70 @@ +/* Test file for mpfr_zeta. + +Copyright (C) 1999 PolKA project, Inria Lorraine and Loria + +This file is part of the MPFR Library. + +The MPFR Library is free software; you can redistribute it and/or modify +it under the terms of the GNU Library General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at your +option) any later version. + +The MPFR Library 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 Library General Public +License for more details. + +You should have received a copy of the GNU Library General Public License +along with the MPFR Library; see the file COPYING.LIB. If not, write to +the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, +MA 02111-1307, USA. */ + +#include <stdio.h> +#include <math.h> +#include "gmp.h" +#include "gmp-impl.h" +#include "longlong.h" +#include "mpfr.h" + +/* #define DEBUG */ + +int main() +{mpfr_t p,result,res_p; int succes; size_t t; +mpfr_init2(result, 53); +mpfr_init2(res_p, 53); +mpfr_init2(p, 53); mpfr_set_d(p, 2.0, GMP_RNDN); + +mpfr_zeta(result,p,GMP_RNDN); +/*printf("%d\n",succes);*/ +#ifdef DEBUG +printf("Valeur de zeta(2) avec prec=53 et arrondi au plus pres:\n"); +mpfr_print_raw(result);printf("\n"); +t=mpfr_out_str(stdout,10,0,result,GMP_RNDN);printf("\n"); +#endif + if (mpfr_get_d(result) != 1.64493406684822640607e+00) { + fprintf(stderr, "mpfr_zeta fails for s=2 and rnd_mode=GMP_RNDN\n"); + exit(1); + } + +/*Test de comparaison avec pi^2/6*/ +mpfr_set_prec(p, 67); +mpfr_pi(p,GMP_RNDN); +mpfr_mul(p,p,p,GMP_RNDN); +mpfr_set_ui(res_p,6,GMP_RNDN); +mpfr_div(p,p,res_p,GMP_RNDN); +/*mpfr_print_raw(p);printf("\n"); +t=mpfr_out_str(stdout,10,0,p,GMP_RNDN);printf("\n");*/ +succes=mpfr_can_round(p,63,GMP_RNDN,GMP_RNDN,53); +mpfr_set(res_p,p,GMP_RNDN); +/*printf("%d\n",succes);*/ +#ifdef DEBUG +printf("Valeur de pi^2/6 avec prec=53 et arrondi au plus pres:\n"); +mpfr_print_raw(res_p);printf("\n"); +t=mpfr_out_str(stdout,10,0,res_p,GMP_RNDN);printf("\n"); +#endif + +mpfr_clear(p); +mpfr_clear(result); +mpfr_clear(res_p); +exit (0); +} diff --git a/mpfr/zeta.c b/mpfr/zeta.c new file mode 100644 index 000000000..5250a9dd7 --- /dev/null +++ b/mpfr/zeta.c @@ -0,0 +1,116 @@ +/* mpfr_zeta -- Riemann Zeta function at a floating-point number + +Copyright (C) 1999 PolKA project, Inria Lorraine and Loria + +This file is part of the MPFR Library. + +The MPFR Library is free software; you can redistribute it and/or modify +it under the terms of the GNU Library General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at your +option) any later version. + +The MPFR Library 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 Library General Public +License for more details. + +You should have received a copy of the GNU Library General Public License +along with the MPFR Library; see the file COPYING.LIB. If not, write to +the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, +MA 02111-1307, USA. */ + +#include <stdio.h> +#include <math.h> +#include "gmp.h" +#include "gmp-impl.h" +#include "longlong.h" +#include "mpfr.h" + +int +#if __STDC__ +mpfr_zeta(mpfr_ptr result, mpfr_srcptr op, unsigned char rnd_mode) +#else +mpfr_zeta(result, op, rnd_mode) + mpfr_ptr result; + mpfr_srcptr op; + unsigned char rnd_mode; +#endif +{ + mpfr_t s,s2,x,y,u,b,v,nn,z,z2; + int i,n,succes; + + /* first version */ + if (mpfr_get_d(op) != 2.0 || rnd_mode != GMP_RNDN + || PREC(result) != 53) { + fprintf(stderr, "not yet implemented\n"); exit(1); + } + +mpfr_set_default_prec(67); +mpfr_init(x); +mpfr_init(y); +mpfr_init(s); +mpfr_init(s2); +mpfr_init(u); +mpfr_init(b); +mpfr_init(v); +mpfr_init(nn); +mpfr_init(z); +mpfr_init(z2); +mpfr_set_ui(u,1,GMP_RNDN); +mpfr_set_ui(s,0,GMP_RNDN); +/*s=Somme des 1/i^2 (i=100...2)*/ +n=100; +for (i=n; i>1; i--) +{ +mpfr_set_ui(x,i*i,GMP_RNDN); +mpfr_div(y,u,x,GMP_RNDN); +mpfr_add(s,s,y,GMP_RNDN); +}; +/*mpfr_print_raw(s);printf("\n"); +t=mpfr_out_str(stdout,10,0,s,GMP_RNDN);printf("\n");*/ +/*Application d'Euler-Maclaurin, jusqu'au terme 1/n^7 - n=100)*/ +mpfr_set_ui(nn,n,GMP_RNDN); +mpfr_div(z,u,nn,GMP_RNDN); +mpfr_set(s2,z,GMP_RNDN); +mpfr_mul(z2,z,z,GMP_RNDN); +mpfr_div_2exp(v,z2,1,GMP_RNDN); +mpfr_sub(s2,s2,v,GMP_RNDN); +mpfr_set_ui(b,6,GMP_RNDN); +mpfr_mul(z,z,z2,GMP_RNDN); +mpfr_div(v,z,b,GMP_RNDN); +mpfr_add(s2,s2,v,GMP_RNDN); +mpfr_set_si(b,-30,GMP_RNDN); +mpfr_mul(z,z,z2,GMP_RNDN); +mpfr_div(v,z,b,GMP_RNDN); +mpfr_add(s2,s2,v,GMP_RNDN); +mpfr_set_si(b,42,GMP_RNDN); +mpfr_mul(z,z,z2,GMP_RNDN); +mpfr_div(v,z,b,GMP_RNDN); +mpfr_add(s2,s2,v,GMP_RNDN); +/*mpfr_print_raw(s2);printf("\n"); +t=mpfr_out_str(stdout,10,0,s2,GMP_RNDN);printf("\n");*/ +mpfr_add(s,s,s2,GMP_RNDN); +/*mpfr_print_raw(s);printf("\n"); +t=mpfr_out_str(stdout,10,0,s,GMP_RNDN);printf("\n");*/ +mpfr_add(s,s,u,GMP_RNDN); +/*mpfr_print_raw(s);printf("\n"); +t=mpfr_out_str(stdout,10,0,s,GMP_RNDN);printf("\n");*/ +/*Peut-on arrondir ? La reponse est oui*/ +succes=mpfr_can_round(s,57,GMP_RNDN,GMP_RNDN,53); +if (succes) mpfr_set(result,s,GMP_RNDN); +else { + fprintf(stderr, "can't round in mpfr_zeta\n"); exit(1); +} + +mpfr_clear(x); +mpfr_clear(y); +mpfr_clear(s); +mpfr_clear(s2); +mpfr_clear(u); +mpfr_clear(b); +mpfr_clear(v); +mpfr_clear(nn); +mpfr_clear(z); +mpfr_clear(z2); +return 1; /* result is inexact */ +} |