summaryrefslogtreecommitdiff
path: root/mpc/src
diff options
context:
space:
mode:
Diffstat (limited to 'mpc/src')
-rw-r--r--mpc/src/Makefile.am34
-rw-r--r--mpc/src/Makefile.in755
-rw-r--r--mpc/src/abs.c28
-rw-r--r--mpc/src/acos.c228
-rw-r--r--mpc/src/acosh.c76
-rw-r--r--mpc/src/add.c33
-rw-r--r--mpc/src/add_fr.c33
-rw-r--r--mpc/src/add_si.c32
-rw-r--r--mpc/src/add_ui.c33
-rw-r--r--mpc/src/arg.c27
-rw-r--r--mpc/src/asin.c226
-rw-r--r--mpc/src/asinh.c55
-rw-r--r--mpc/src/atan.c367
-rw-r--r--mpc/src/atanh.c52
-rw-r--r--mpc/src/clear.c28
-rw-r--r--mpc/src/cmp.c33
-rw-r--r--mpc/src/cmp_si_si.c34
-rw-r--r--mpc/src/conj.c32
-rw-r--r--mpc/src/cos.c27
-rw-r--r--mpc/src/cosh.c35
-rw-r--r--mpc/src/div.c449
-rw-r--r--mpc/src/div_2si.c32
-rw-r--r--mpc/src/div_2ui.c32
-rw-r--r--mpc/src/div_fr.c39
-rw-r--r--mpc/src/div_ui.c32
-rw-r--r--mpc/src/exp.c202
-rw-r--r--mpc/src/fma.c191
-rw-r--r--mpc/src/fr_div.c39
-rw-r--r--mpc/src/fr_sub.c33
-rw-r--r--mpc/src/get_prec.c28
-rw-r--r--mpc/src/get_prec2.c29
-rw-r--r--mpc/src/get_version.c49
-rw-r--r--mpc/src/get_x.c236
-rw-r--r--mpc/src/imag.c27
-rw-r--r--mpc/src/init2.c28
-rw-r--r--mpc/src/init3.c28
-rw-r--r--mpc/src/inp_str.c239
-rw-r--r--mpc/src/log.c217
-rw-r--r--mpc/src/log10.c286
-rw-r--r--mpc/src/logging.c147
-rw-r--r--mpc/src/mem.c46
-rw-r--r--mpc/src/mpc-impl.h194
-rw-r--r--mpc/src/mpc-log.h51
-rw-r--r--mpc/src/mpc.h269
-rw-r--r--mpc/src/mul.c639
-rw-r--r--mpc/src/mul_2si.c32
-rw-r--r--mpc/src/mul_2ui.c32
-rw-r--r--mpc/src/mul_fr.c43
-rw-r--r--mpc/src/mul_i.c80
-rw-r--r--mpc/src/mul_si.c32
-rw-r--r--mpc/src/mul_ui.c32
-rw-r--r--mpc/src/neg.c32
-rw-r--r--mpc/src/norm.c182
-rw-r--r--mpc/src/out_str.c39
-rw-r--r--mpc/src/pow.c818
-rw-r--r--mpc/src/pow_d.c38
-rw-r--r--mpc/src/pow_fr.c37
-rw-r--r--mpc/src/pow_ld.c38
-rw-r--r--mpc/src/pow_si.c30
-rw-r--r--mpc/src/pow_ui.c169
-rw-r--r--mpc/src/pow_z.c47
-rw-r--r--mpc/src/proj.c34
-rw-r--r--mpc/src/real.c27
-rw-r--r--mpc/src/set.c32
-rw-r--r--mpc/src/set_prec.c28
-rw-r--r--mpc/src/set_str.c42
-rw-r--r--mpc/src/set_x.c104
-rw-r--r--mpc/src/set_x_x.c78
-rw-r--r--mpc/src/sin.c27
-rw-r--r--mpc/src/sin_cos.c402
-rw-r--r--mpc/src/sinh.c47
-rw-r--r--mpc/src/sqr.c324
-rw-r--r--mpc/src/sqrt.c364
-rw-r--r--mpc/src/strtoc.c89
-rw-r--r--mpc/src/sub.c32
-rw-r--r--mpc/src/sub_fr.c34
-rw-r--r--mpc/src/sub_ui.c33
-rw-r--r--mpc/src/swap.c29
-rw-r--r--mpc/src/tan.c284
-rw-r--r--mpc/src/tanh.c47
-rw-r--r--mpc/src/uceil_log2.c33
-rw-r--r--mpc/src/ui_div.c36
-rw-r--r--mpc/src/ui_ui_sub.c34
-rw-r--r--mpc/src/urandom.c32
84 files changed, 9603 insertions, 0 deletions
diff --git a/mpc/src/Makefile.am b/mpc/src/Makefile.am
new file mode 100644
index 0000000000..0ece3117e8
--- /dev/null
+++ b/mpc/src/Makefile.am
@@ -0,0 +1,34 @@
+## src/Makefile.am -- Process this file with automake to produce Makefile.in
+##
+## Copyright (C) 2008, 2009, 2010, 2011, 2012 INRIA
+##
+## This file is part of GNU MPC.
+##
+## GNU MPC is free software; you can redistribute it and/or modify it under
+## the terms of the GNU Lesser General Public License as published by the
+## Free Software Foundation; either version 3 of the License, or (at your
+## option) any later version.
+##
+## GNU MPC 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 Lesser General Public License for
+## more details.
+##
+## You should have received a copy of the GNU Lesser General Public License
+## along with this program. If not, see http://www.gnu.org/licenses/ .
+
+lib_LTLIBRARIES = libmpc.la
+libmpc_la_LDFLAGS = $(MPC_LDFLAGS) -version-info 3:0:0
+libmpc_la_SOURCES = mpc-impl.h abs.c acos.c acosh.c add.c add_fr.c \
+ add_si.c add_ui.c arg.c asin.c asinh.c atan.c atanh.c clear.c cmp.c \
+ cmp_si_si.c conj.c cos.c cosh.c div_2si.c div_2ui.c div.c div_fr.c \
+ div_ui.c exp.c fma.c fr_div.c fr_sub.c get_prec2.c get_prec.c \
+ get_version.c get_x.c imag.c init2.c init3.c inp_str.c log.c log10.c \
+ mem.c mul_2si.c mul_2ui.c mul.c mul_fr.c mul_i.c mul_si.c mul_ui.c \
+ neg.c norm.c out_str.c pow.c pow_fr.c \
+ pow_ld.c pow_d.c pow_si.c pow_ui.c pow_z.c proj.c real.c urandom.c set.c \
+ set_prec.c set_str.c set_x.c set_x_x.c sin.c sin_cos.c sinh.c sqr.c \
+ sqrt.c strtoc.c sub.c sub_fr.c sub_ui.c swap.c tan.c tanh.c uceil_log2.c \
+ ui_div.c ui_ui_sub.c
+
+libmpc_la_LIBADD = @LTLIBOBJS@
diff --git a/mpc/src/Makefile.in b/mpc/src/Makefile.in
new file mode 100644
index 0000000000..d0fd25de8c
--- /dev/null
+++ b/mpc/src/Makefile.in
@@ -0,0 +1,755 @@
+# Makefile.in generated by automake 1.15 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2014 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.
+
+@SET_MAKE@
+
+VPATH = @srcdir@
+am__is_gnu_make = { \
+ if test -z '$(MAKELEVEL)'; then \
+ false; \
+ elif test -n '$(MAKE_HOST)'; then \
+ true; \
+ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+ true; \
+ else \
+ false; \
+ fi; \
+}
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = src
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/ax_c_check_flag.m4 \
+ $(top_srcdir)/m4/ax_gcc_option.m4 \
+ $(top_srcdir)/m4/ax_gcc_version.m4 $(top_srcdir)/m4/libtool.m4 \
+ $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
+ $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \
+ $(top_srcdir)/m4/mpc.m4 $(top_srcdir)/m4/valgrind-tests.m4 \
+ $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+ *) f=$$p;; \
+ esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+ if (++n[$$2] == $(am__install_max)) \
+ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+ END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__uninstall_files_from_dir = { \
+ test -z "$$files" \
+ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
+ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \
+ $(am__cd) "$$dir" && rm -f $$files; }; \
+ }
+am__installdirs = "$(DESTDIR)$(libdir)"
+LTLIBRARIES = $(lib_LTLIBRARIES)
+libmpc_la_DEPENDENCIES = @LTLIBOBJS@
+am_libmpc_la_OBJECTS = abs.lo acos.lo acosh.lo add.lo add_fr.lo \
+ add_si.lo add_ui.lo arg.lo asin.lo asinh.lo atan.lo atanh.lo \
+ clear.lo cmp.lo cmp_si_si.lo conj.lo cos.lo cosh.lo div_2si.lo \
+ div_2ui.lo div.lo div_fr.lo div_ui.lo exp.lo fma.lo fr_div.lo \
+ fr_sub.lo get_prec2.lo get_prec.lo get_version.lo get_x.lo \
+ imag.lo init2.lo init3.lo inp_str.lo log.lo log10.lo mem.lo \
+ mul_2si.lo mul_2ui.lo mul.lo mul_fr.lo mul_i.lo mul_si.lo \
+ mul_ui.lo neg.lo norm.lo out_str.lo pow.lo pow_fr.lo pow_ld.lo \
+ pow_d.lo pow_si.lo pow_ui.lo pow_z.lo proj.lo real.lo \
+ urandom.lo set.lo set_prec.lo set_str.lo set_x.lo set_x_x.lo \
+ sin.lo sin_cos.lo sinh.lo sqr.lo sqrt.lo strtoc.lo sub.lo \
+ sub_fr.lo sub_ui.lo swap.lo tan.lo tanh.lo uceil_log2.lo \
+ ui_div.lo ui_ui_sub.lo
+libmpc_la_OBJECTS = $(am_libmpc_la_OBJECTS)
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+am__v_lt_1 =
+libmpc_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(libmpc_la_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__depfiles_maybe = depfiles
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo " CC " $@;
+am__v_CC_1 =
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo " CCLD " $@;
+am__v_CCLD_1 =
+SOURCES = $(libmpc_la_SOURCES)
+DIST_SOURCES = $(libmpc_la_SOURCES)
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates. Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+ BEGIN { nonempty = 0; } \
+ { items[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique. This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+ list='$(am__tagged_files)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | $(am__uniquify_input)`
+ETAGS = etags
+CTAGS = ctags
+am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/depcomp \
+ logging.c
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AS = @AS@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DLLTOOL = @DLLTOOL@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GCC_VERSION = @GCC_VERSION@
+GITVERSION = @GITVERSION@
+GREP = @GREP@
+HASGIT = @HASGIT@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+MPC_LDFLAGS = @MPC_LDFLAGS@
+MPC_LOG_H = @MPC_LOG_H@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+RANLIB = @RANLIB@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VALGRIND = @VALGRIND@
+VERSION = @VERSION@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+lib_LTLIBRARIES = libmpc.la
+libmpc_la_LDFLAGS = $(MPC_LDFLAGS) -version-info 3:0:0
+libmpc_la_SOURCES = mpc-impl.h abs.c acos.c acosh.c add.c add_fr.c \
+ add_si.c add_ui.c arg.c asin.c asinh.c atan.c atanh.c clear.c cmp.c \
+ cmp_si_si.c conj.c cos.c cosh.c div_2si.c div_2ui.c div.c div_fr.c \
+ div_ui.c exp.c fma.c fr_div.c fr_sub.c get_prec2.c get_prec.c \
+ get_version.c get_x.c imag.c init2.c init3.c inp_str.c log.c log10.c \
+ mem.c mul_2si.c mul_2ui.c mul.c mul_fr.c mul_i.c mul_si.c mul_ui.c \
+ neg.c norm.c out_str.c pow.c pow_fr.c \
+ pow_ld.c pow_d.c pow_si.c pow_ui.c pow_z.c proj.c real.c urandom.c set.c \
+ set_prec.c set_str.c set_x.c set_x_x.c sin.c sin_cos.c sinh.c sqr.c \
+ sqrt.c strtoc.c sub.c sub_fr.c sub_ui.c swap.c tan.c tanh.c uceil_log2.c \
+ ui_div.c ui_ui_sub.c
+
+libmpc_la_LIBADD = @LTLIBOBJS@
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --gnu src/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+install-libLTLIBRARIES: $(lib_LTLIBRARIES)
+ @$(NORMAL_INSTALL)
+ @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \
+ list2=; for p in $$list; do \
+ if test -f $$p; then \
+ list2="$$list2 $$p"; \
+ else :; fi; \
+ done; \
+ test -z "$$list2" || { \
+ echo " $(MKDIR_P) '$(DESTDIR)$(libdir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(libdir)" || exit 1; \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(libdir)'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(libdir)"; \
+ }
+
+uninstall-libLTLIBRARIES:
+ @$(NORMAL_UNINSTALL)
+ @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \
+ for p in $$list; do \
+ $(am__strip_dir) \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$f'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$f"; \
+ done
+
+clean-libLTLIBRARIES:
+ -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES)
+ @list='$(lib_LTLIBRARIES)'; \
+ locs=`for p in $$list; do echo $$p; done | \
+ sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \
+ sort -u`; \
+ test -z "$$locs" || { \
+ echo rm -f $${locs}; \
+ rm -f $${locs}; \
+ }
+
+libmpc.la: $(libmpc_la_OBJECTS) $(libmpc_la_DEPENDENCIES) $(EXTRA_libmpc_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(libmpc_la_LINK) -rpath $(libdir) $(libmpc_la_OBJECTS) $(libmpc_la_LIBADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/logging.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/abs.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/acos.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/acosh.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/add.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/add_fr.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/add_si.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/add_ui.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/arg.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/asin.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/asinh.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/atan.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/atanh.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/clear.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cmp.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cmp_si_si.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/conj.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cos.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cosh.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/div.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/div_2si.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/div_2ui.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/div_fr.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/div_ui.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/exp.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fma.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fr_div.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fr_sub.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/get_prec.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/get_prec2.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/get_version.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/get_x.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/imag.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/init2.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/init3.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/inp_str.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/log.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/log10.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mem.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mul.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mul_2si.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mul_2ui.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mul_fr.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mul_i.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mul_si.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mul_ui.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/neg.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/norm.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/out_str.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pow.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pow_d.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pow_fr.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pow_ld.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pow_si.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pow_ui.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pow_z.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/proj.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/real.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/set.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/set_prec.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/set_str.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/set_x.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/set_x_x.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sin.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sin_cos.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sinh.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sqr.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sqrt.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/strtoc.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sub.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sub_fr.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sub_ui.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/swap.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tan.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tanh.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/uceil_log2.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ui_div.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ui_ui_sub.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/urandom.Plo@am__quote@
+
+.c.o:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+ID: $(am__tagged_files)
+ $(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-am
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ set x; \
+ here=`pwd`; \
+ $(am__define_uniq_tagged_files); \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: ctags-am
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ $(am__define_uniq_tagged_files); \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-am
+
+cscopelist-am: $(am__tagged_files)
+ list='$(am__tagged_files)'; \
+ case "$(srcdir)" in \
+ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+ *) sdir=$(subdir)/$(srcdir) ;; \
+ esac; \
+ for i in $$list; do \
+ if test -f "$$i"; then \
+ echo "$(subdir)/$$i"; \
+ else \
+ echo "$$sdir/$$i"; \
+ fi; \
+ done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(LTLIBRARIES)
+installdirs:
+ for dir in "$(DESTDIR)$(libdir)"; do \
+ test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+ done
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libLTLIBRARIES clean-libtool \
+ mostlyclean-am
+
+distclean: distclean-am
+ -rm -rf $(DEPDIR) ./$(DEPDIR)
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am: install-libLTLIBRARIES
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -rf $(DEPDIR) ./$(DEPDIR)
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-libLTLIBRARIES
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS TAGS all all-am check check-am clean clean-generic \
+ clean-libLTLIBRARIES clean-libtool cscopelist-am ctags \
+ ctags-am distclean distclean-compile distclean-generic \
+ distclean-libtool distclean-tags distdir dvi dvi-am html \
+ html-am info info-am install install-am install-data \
+ install-data-am install-dvi install-dvi-am install-exec \
+ install-exec-am install-html install-html-am install-info \
+ install-info-am install-libLTLIBRARIES install-man install-pdf \
+ install-pdf-am install-ps install-ps-am install-strip \
+ installcheck installcheck-am installdirs maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-compile \
+ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+ tags tags-am uninstall uninstall-am uninstall-libLTLIBRARIES
+
+.PRECIOUS: Makefile
+
+
+# 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/mpc/src/abs.c b/mpc/src/abs.c
new file mode 100644
index 0000000000..bf1e5fda09
--- /dev/null
+++ b/mpc/src/abs.c
@@ -0,0 +1,28 @@
+/* mpc_abs -- Absolute value of a complex number.
+
+Copyright (C) 2008, 2009, 2011 INRIA
+
+This file is part of GNU MPC.
+
+GNU MPC is free software; you can redistribute it and/or modify it under
+the terms of the GNU Lesser General Public License as published by the
+Free Software Foundation; either version 3 of the License, or (at your
+option) any later version.
+
+GNU MPC 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 Lesser General Public License for
+more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+
+#include "mpc-impl.h"
+
+/* the rounding mode is mpfr_rnd_t here since we return an mpfr number */
+int
+mpc_abs (mpfr_ptr a, mpc_srcptr b, mpfr_rnd_t rnd)
+{
+ return mpfr_hypot (a, mpc_realref(b), mpc_imagref(b), rnd);
+}
diff --git a/mpc/src/acos.c b/mpc/src/acos.c
new file mode 100644
index 0000000000..e7a269149a
--- /dev/null
+++ b/mpc/src/acos.c
@@ -0,0 +1,228 @@
+/* mpc_acos -- arccosine of a complex number.
+
+Copyright (C) 2009, 2010, 2011, 2012 INRIA
+
+This file is part of GNU MPC.
+
+GNU MPC is free software; you can redistribute it and/or modify it under
+the terms of the GNU Lesser General Public License as published by the
+Free Software Foundation; either version 3 of the License, or (at your
+option) any later version.
+
+GNU MPC 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 Lesser General Public License for
+more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+
+#include <stdio.h> /* for MPC_ASSERT */
+#include "mpc-impl.h"
+
+int
+mpc_acos (mpc_ptr rop, mpc_srcptr op, mpc_rnd_t rnd)
+{
+ int inex_re, inex_im, inex;
+ mpfr_prec_t p_re, p_im, p;
+ mpc_t z1;
+ mpfr_t pi_over_2;
+ mpfr_exp_t e1, e2;
+ mpfr_rnd_t rnd_im;
+ mpc_rnd_t rnd1;
+
+ inex_re = 0;
+ inex_im = 0;
+
+ /* special values */
+ if (mpfr_nan_p (mpc_realref (op)) || mpfr_nan_p (mpc_imagref (op)))
+ {
+ if (mpfr_inf_p (mpc_realref (op)) || mpfr_inf_p (mpc_imagref (op)))
+ {
+ mpfr_set_inf (mpc_imagref (rop), mpfr_signbit (mpc_imagref (op)) ? +1 : -1);
+ mpfr_set_nan (mpc_realref (rop));
+ }
+ else if (mpfr_zero_p (mpc_realref (op)))
+ {
+ inex_re = set_pi_over_2 (mpc_realref (rop), +1, MPC_RND_RE (rnd));
+ mpfr_set_nan (mpc_imagref (rop));
+ }
+ else
+ {
+ mpfr_set_nan (mpc_realref (rop));
+ mpfr_set_nan (mpc_imagref (rop));
+ }
+
+ return MPC_INEX (inex_re, 0);
+ }
+
+ if (mpfr_inf_p (mpc_realref (op)) || mpfr_inf_p (mpc_imagref (op)))
+ {
+ if (mpfr_inf_p (mpc_realref (op)))
+ {
+ if (mpfr_inf_p (mpc_imagref (op)))
+ {
+ if (mpfr_sgn (mpc_realref (op)) > 0)
+ {
+ inex_re =
+ set_pi_over_2 (mpc_realref (rop), +1, MPC_RND_RE (rnd));
+ mpfr_div_2ui (mpc_realref (rop), mpc_realref (rop), 1, GMP_RNDN);
+ }
+ else
+ {
+
+ /* the real part of the result is 3*pi/4
+ a = o(pi) error(a) < 1 ulp(a)
+ b = o(3*a) error(b) < 2 ulp(b)
+ c = b/4 exact
+ thus 1 bit is lost */
+ mpfr_t x;
+ mpfr_prec_t prec;
+ int ok;
+ mpfr_init (x);
+ prec = mpfr_get_prec (mpc_realref (rop));
+ p = prec;
+
+ do
+ {
+ p += mpc_ceil_log2 (p);
+ mpfr_set_prec (x, p);
+ mpfr_const_pi (x, GMP_RNDD);
+ mpfr_mul_ui (x, x, 3, GMP_RNDD);
+ ok =
+ mpfr_can_round (x, p - 1, GMP_RNDD, MPC_RND_RE (rnd),
+ prec+(MPC_RND_RE (rnd) == GMP_RNDN));
+
+ } while (ok == 0);
+ inex_re =
+ mpfr_div_2ui (mpc_realref (rop), x, 2, MPC_RND_RE (rnd));
+ mpfr_clear (x);
+ }
+ }
+ else
+ {
+ if (mpfr_sgn (mpc_realref (op)) > 0)
+ mpfr_set_ui (mpc_realref (rop), 0, GMP_RNDN);
+ else
+ inex_re = mpfr_const_pi (mpc_realref (rop), MPC_RND_RE (rnd));
+ }
+ }
+ else
+ inex_re = set_pi_over_2 (mpc_realref (rop), +1, MPC_RND_RE (rnd));
+
+ mpfr_set_inf (mpc_imagref (rop), mpfr_signbit (mpc_imagref (op)) ? +1 : -1);
+
+ return MPC_INEX (inex_re, 0);
+ }
+
+ /* pure real argument */
+ if (mpfr_zero_p (mpc_imagref (op)))
+ {
+ int s_im;
+ s_im = mpfr_signbit (mpc_imagref (op));
+
+ if (mpfr_cmp_ui (mpc_realref (op), 1) > 0)
+ {
+ if (s_im)
+ inex_im = mpfr_acosh (mpc_imagref (rop), mpc_realref (op),
+ MPC_RND_IM (rnd));
+ else
+ inex_im = -mpfr_acosh (mpc_imagref (rop), mpc_realref (op),
+ INV_RND (MPC_RND_IM (rnd)));
+
+ mpfr_set_ui (mpc_realref (rop), 0, GMP_RNDN);
+ }
+ else if (mpfr_cmp_si (mpc_realref (op), -1) < 0)
+ {
+ mpfr_t minus_op_re;
+ minus_op_re[0] = mpc_realref (op)[0];
+ MPFR_CHANGE_SIGN (minus_op_re);
+
+ if (s_im)
+ inex_im = mpfr_acosh (mpc_imagref (rop), minus_op_re,
+ MPC_RND_IM (rnd));
+ else
+ inex_im = -mpfr_acosh (mpc_imagref (rop), minus_op_re,
+ INV_RND (MPC_RND_IM (rnd)));
+ inex_re = mpfr_const_pi (mpc_realref (rop), MPC_RND_RE (rnd));
+ }
+ else
+ {
+ inex_re = mpfr_acos (mpc_realref (rop), mpc_realref (op), MPC_RND_RE (rnd));
+ mpfr_set_ui (mpc_imagref (rop), 0, MPC_RND_IM (rnd));
+ }
+
+ if (!s_im)
+ mpc_conj (rop, rop, MPC_RNDNN);
+
+ return MPC_INEX (inex_re, inex_im);
+ }
+
+ /* pure imaginary argument */
+ if (mpfr_zero_p (mpc_realref (op)))
+ {
+ inex_re = set_pi_over_2 (mpc_realref (rop), +1, MPC_RND_RE (rnd));
+ inex_im = -mpfr_asinh (mpc_imagref (rop), mpc_imagref (op),
+ INV_RND (MPC_RND_IM (rnd)));
+ mpc_conj (rop,rop, MPC_RNDNN);
+
+ return MPC_INEX (inex_re, inex_im);
+ }
+
+ /* regular complex argument: acos(z) = Pi/2 - asin(z) */
+ p_re = mpfr_get_prec (mpc_realref(rop));
+ p_im = mpfr_get_prec (mpc_imagref(rop));
+ p = p_re;
+ mpc_init3 (z1, p, p_im); /* we round directly the imaginary part to p_im,
+ with rounding mode opposite to rnd_im */
+ rnd_im = MPC_RND_IM(rnd);
+ /* the imaginary part of asin(z) has the same sign as Im(z), thus if
+ Im(z) > 0 and rnd_im = RNDZ, we want to round the Im(asin(z)) to -Inf
+ so that -Im(asin(z)) is rounded to zero */
+ if (rnd_im == GMP_RNDZ)
+ rnd_im = mpfr_sgn (mpc_imagref(op)) > 0 ? GMP_RNDD : GMP_RNDU;
+ else
+ rnd_im = rnd_im == GMP_RNDU ? GMP_RNDD
+ : rnd_im == GMP_RNDD ? GMP_RNDU
+ : rnd_im; /* both RNDZ and RNDA map to themselves for -asin(z) */
+ rnd1 = MPC_RND (GMP_RNDN, rnd_im);
+ mpfr_init2 (pi_over_2, p);
+ for (;;)
+ {
+ p += mpc_ceil_log2 (p) + 3;
+
+ mpfr_set_prec (mpc_realref(z1), p);
+ mpfr_set_prec (pi_over_2, p);
+
+ set_pi_over_2 (pi_over_2, +1, GMP_RNDN);
+ e1 = 1; /* Exp(pi_over_2) */
+ inex = mpc_asin (z1, op, rnd1); /* asin(z) */
+ MPC_ASSERT (mpfr_sgn (mpc_imagref(z1)) * mpfr_sgn (mpc_imagref(op)) > 0);
+ inex_im = MPC_INEX_IM(inex); /* inex_im is in {-1, 0, 1} */
+ e2 = mpfr_get_exp (mpc_realref(z1));
+ mpfr_sub (mpc_realref(z1), pi_over_2, mpc_realref(z1), GMP_RNDN);
+ if (!mpfr_zero_p (mpc_realref(z1)))
+ {
+ /* the error on x=Re(z1) is bounded by 1/2 ulp(x) + 2^(e1-p-1) +
+ 2^(e2-p-1) */
+ e1 = e1 >= e2 ? e1 + 1 : e2 + 1;
+ /* the error on x is bounded by 1/2 ulp(x) + 2^(e1-p-1) */
+ e1 -= mpfr_get_exp (mpc_realref(z1));
+ /* the error on x is bounded by 1/2 ulp(x) [1 + 2^e1] */
+ e1 = e1 <= 0 ? 0 : e1;
+ /* the error on x is bounded by 2^e1 * ulp(x) */
+ mpfr_neg (mpc_imagref(z1), mpc_imagref(z1), GMP_RNDN); /* exact */
+ inex_im = -inex_im;
+ if (mpfr_can_round (mpc_realref(z1), p - e1, GMP_RNDN, GMP_RNDZ,
+ p_re + (MPC_RND_RE(rnd) == GMP_RNDN)))
+ break;
+ }
+ }
+ inex = mpc_set (rop, z1, rnd);
+ inex_re = MPC_INEX_RE(inex);
+ mpc_clear (z1);
+ mpfr_clear (pi_over_2);
+
+ return MPC_INEX(inex_re, inex_im);
+}
diff --git a/mpc/src/acosh.c b/mpc/src/acosh.c
new file mode 100644
index 0000000000..782f5550c2
--- /dev/null
+++ b/mpc/src/acosh.c
@@ -0,0 +1,76 @@
+/* mpc_acosh -- inverse hyperbolic cosine of a complex number.
+
+Copyright (C) 2009, 2011, 2012 INRIA
+
+This file is part of GNU MPC.
+
+GNU MPC is free software; you can redistribute it and/or modify it under
+the terms of the GNU Lesser General Public License as published by the
+Free Software Foundation; either version 3 of the License, or (at your
+option) any later version.
+
+GNU MPC 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 Lesser General Public License for
+more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+
+#include "mpc-impl.h"
+
+int
+mpc_acosh (mpc_ptr rop, mpc_srcptr op, mpc_rnd_t rnd)
+{
+ /* acosh(z) =
+ NaN + i*NaN, if z=0+i*NaN
+ -i*acos(z), if sign(Im(z)) = -
+ i*acos(z), if sign(Im(z)) = +
+ http://functions.wolfram.com/ElementaryFunctions/ArcCosh/27/02/03/01/01/
+ */
+ mpc_t a;
+ mpfr_t tmp;
+ int inex;
+
+ if (mpfr_zero_p (mpc_realref (op)) && mpfr_nan_p (mpc_imagref (op)))
+ {
+ mpfr_set_nan (mpc_realref (rop));
+ mpfr_set_nan (mpc_imagref (rop));
+ return 0;
+ }
+
+ /* Note reversal of precisions due to later multiplication by i or -i */
+ mpc_init3 (a, MPC_PREC_IM(rop), MPC_PREC_RE(rop));
+
+ if (mpfr_signbit (mpc_imagref (op)))
+ {
+ inex = mpc_acos (a, op,
+ MPC_RND (INV_RND (MPC_RND_IM (rnd)), MPC_RND_RE (rnd)));
+
+ /* change a to -i*a, i.e., -y+i*x to x+i*y */
+ tmp[0] = mpc_realref (a)[0];
+ mpc_realref (a)[0] = mpc_imagref (a)[0];
+ mpc_imagref (a)[0] = tmp[0];
+ MPFR_CHANGE_SIGN (mpc_imagref (a));
+ inex = MPC_INEX (MPC_INEX_IM (inex), -MPC_INEX_RE (inex));
+ }
+ else
+ {
+ inex = mpc_acos (a, op,
+ MPC_RND (MPC_RND_IM (rnd), INV_RND(MPC_RND_RE (rnd))));
+
+ /* change a to i*a, i.e., y-i*x to x+i*y */
+ tmp[0] = mpc_realref (a)[0];
+ mpc_realref (a)[0] = mpc_imagref (a)[0];
+ mpc_imagref (a)[0] = tmp[0];
+ MPFR_CHANGE_SIGN (mpc_realref (a));
+ inex = MPC_INEX (-MPC_INEX_IM (inex), MPC_INEX_RE (inex));
+ }
+
+ mpc_set (rop, a, rnd);
+
+ mpc_clear (a);
+
+ return inex;
+}
diff --git a/mpc/src/add.c b/mpc/src/add.c
new file mode 100644
index 0000000000..ee9ec19b3c
--- /dev/null
+++ b/mpc/src/add.c
@@ -0,0 +1,33 @@
+/* mpc_add -- Add two complex numbers.
+
+Copyright (C) 2002, 2009, 2011 INRIA
+
+This file is part of GNU MPC.
+
+GNU MPC is free software; you can redistribute it and/or modify it under
+the terms of the GNU Lesser General Public License as published by the
+Free Software Foundation; either version 3 of the License, or (at your
+option) any later version.
+
+GNU MPC 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 Lesser General Public License for
+more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+
+#include "mpc-impl.h"
+
+/* return 0 iff both the real and imaginary parts are exact */
+int
+mpc_add (mpc_ptr a, mpc_srcptr b, mpc_srcptr c, mpc_rnd_t rnd)
+{
+ int inex_re, inex_im;
+
+ inex_re = mpfr_add (mpc_realref(a), mpc_realref(b), mpc_realref(c), MPC_RND_RE(rnd));
+ inex_im = mpfr_add (mpc_imagref(a), mpc_imagref(b), mpc_imagref(c), MPC_RND_IM(rnd));
+
+ return MPC_INEX(inex_re, inex_im);
+}
diff --git a/mpc/src/add_fr.c b/mpc/src/add_fr.c
new file mode 100644
index 0000000000..ea7b59560d
--- /dev/null
+++ b/mpc/src/add_fr.c
@@ -0,0 +1,33 @@
+/* mpc_add_fr -- Add a complex number and a floating-point number.
+
+Copyright (C) 2002, 2009, 2011 INRIA
+
+This file is part of GNU MPC.
+
+GNU MPC is free software; you can redistribute it and/or modify it under
+the terms of the GNU Lesser General Public License as published by the
+Free Software Foundation; either version 3 of the License, or (at your
+option) any later version.
+
+GNU MPC 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 Lesser General Public License for
+more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+
+#include "mpc-impl.h"
+
+/* return 0 iff both the real and imaginary parts are exact */
+int
+mpc_add_fr (mpc_ptr a, mpc_srcptr b, mpfr_srcptr c, mpc_rnd_t rnd)
+{
+ int inex_re, inex_im;
+
+ inex_re = mpfr_add (mpc_realref(a), mpc_realref(b), c, MPC_RND_RE(rnd));
+ inex_im = mpfr_set (mpc_imagref(a), mpc_imagref(b), MPC_RND_IM(rnd));
+
+ return MPC_INEX(inex_re, inex_im);
+}
diff --git a/mpc/src/add_si.c b/mpc/src/add_si.c
new file mode 100644
index 0000000000..ba14803e76
--- /dev/null
+++ b/mpc/src/add_si.c
@@ -0,0 +1,32 @@
+/* mpc_add_si -- Add a complex number and a signed long int.
+
+Copyright (C) 2011 INRIA
+
+This file is part of GNU MPC.
+
+GNU MPC is free software; you can redistribute it and/or modify it under
+the terms of the GNU Lesser General Public License as published by the
+Free Software Foundation; either version 3 of the License, or (at your
+option) any later version.
+
+GNU MPC 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 Lesser General Public License for
+more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+
+#include "mpc-impl.h"
+
+int
+mpc_add_si (mpc_ptr rop, mpc_srcptr op1, long int op2, mpc_rnd_t rnd)
+{
+ int inex_re, inex_im;
+
+ inex_re = mpfr_add_si (mpc_realref (rop), mpc_realref (op1), op2, MPC_RND_RE (rnd));
+ inex_im = mpfr_set (mpc_imagref (rop), mpc_imagref (op1), MPC_RND_IM (rnd));
+
+ return MPC_INEX (inex_re, inex_im);
+}
diff --git a/mpc/src/add_ui.c b/mpc/src/add_ui.c
new file mode 100644
index 0000000000..85f4d13d2d
--- /dev/null
+++ b/mpc/src/add_ui.c
@@ -0,0 +1,33 @@
+/* mpc_add_ui -- Add a complex number and an unsigned long int.
+
+Copyright (C) 2002, 2009, 2011 INRIA
+
+This file is part of GNU MPC.
+
+GNU MPC is free software; you can redistribute it and/or modify it under
+the terms of the GNU Lesser General Public License as published by the
+Free Software Foundation; either version 3 of the License, or (at your
+option) any later version.
+
+GNU MPC 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 Lesser General Public License for
+more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+
+#include "mpc-impl.h"
+
+/* return 0 iff both the real and imaginary parts are exact */
+int
+mpc_add_ui (mpc_ptr a, mpc_srcptr b, unsigned long int c, mpc_rnd_t rnd)
+{
+ int inex_re, inex_im;
+
+ inex_re = mpfr_add_ui (mpc_realref(a), mpc_realref(b), c, MPC_RND_RE(rnd));
+ inex_im = mpfr_set (mpc_imagref(a), mpc_imagref(b), MPC_RND_IM(rnd));
+
+ return MPC_INEX(inex_re, inex_im);
+}
diff --git a/mpc/src/arg.c b/mpc/src/arg.c
new file mode 100644
index 0000000000..20b5180926
--- /dev/null
+++ b/mpc/src/arg.c
@@ -0,0 +1,27 @@
+/* mpc_arg -- Get the argument of a complex number.
+
+Copyright (C) 2008, 2009, 2011 INRIA
+
+This file is part of GNU MPC.
+
+GNU MPC is free software; you can redistribute it and/or modify it under
+the terms of the GNU Lesser General Public License as published by the
+Free Software Foundation; either version 3 of the License, or (at your
+option) any later version.
+
+GNU MPC 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 Lesser General Public License for
+more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+
+#include "mpc-impl.h"
+
+int
+mpc_arg (mpfr_ptr a, mpc_srcptr b, mpfr_rnd_t rnd)
+{
+ return mpfr_atan2 (a, mpc_imagref (b), mpc_realref (b), rnd);
+}
diff --git a/mpc/src/asin.c b/mpc/src/asin.c
new file mode 100644
index 0000000000..bd4e3132de
--- /dev/null
+++ b/mpc/src/asin.c
@@ -0,0 +1,226 @@
+/* mpc_asin -- arcsine of a complex number.
+
+Copyright (C) 2009, 2010, 2011 INRIA
+
+This file is part of GNU MPC.
+
+GNU MPC is free software; you can redistribute it and/or modify it under
+the terms of the GNU Lesser General Public License as published by the
+Free Software Foundation; either version 3 of the License, or (at your
+option) any later version.
+
+GNU MPC 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 Lesser General Public License for
+more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+
+#include "mpc-impl.h"
+
+int
+mpc_asin (mpc_ptr rop, mpc_srcptr op, mpc_rnd_t rnd)
+{
+ mpfr_prec_t p, p_re, p_im, incr_p = 0;
+ mpfr_rnd_t rnd_re, rnd_im;
+ mpc_t z1;
+ int inex;
+
+ /* special values */
+ if (mpfr_nan_p (mpc_realref (op)) || mpfr_nan_p (mpc_imagref (op)))
+ {
+ if (mpfr_inf_p (mpc_realref (op)) || mpfr_inf_p (mpc_imagref (op)))
+ {
+ mpfr_set_nan (mpc_realref (rop));
+ mpfr_set_inf (mpc_imagref (rop), mpfr_signbit (mpc_imagref (op)) ? -1 : +1);
+ }
+ else if (mpfr_zero_p (mpc_realref (op)))
+ {
+ mpfr_set (mpc_realref (rop), mpc_realref (op), GMP_RNDN);
+ mpfr_set_nan (mpc_imagref (rop));
+ }
+ else
+ {
+ mpfr_set_nan (mpc_realref (rop));
+ mpfr_set_nan (mpc_imagref (rop));
+ }
+
+ return 0;
+ }
+
+ if (mpfr_inf_p (mpc_realref (op)) || mpfr_inf_p (mpc_imagref (op)))
+ {
+ int inex_re;
+ if (mpfr_inf_p (mpc_realref (op)))
+ {
+ int inf_im = mpfr_inf_p (mpc_imagref (op));
+
+ inex_re = set_pi_over_2 (mpc_realref (rop),
+ (mpfr_signbit (mpc_realref (op)) ? -1 : 1), MPC_RND_RE (rnd));
+ mpfr_set_inf (mpc_imagref (rop), (mpfr_signbit (mpc_imagref (op)) ? -1 : 1));
+
+ if (inf_im)
+ mpfr_div_2ui (mpc_realref (rop), mpc_realref (rop), 1, GMP_RNDN);
+ }
+ else
+ {
+ mpfr_set_zero (mpc_realref (rop), (mpfr_signbit (mpc_realref (op)) ? -1 : 1));
+ inex_re = 0;
+ mpfr_set_inf (mpc_imagref (rop), (mpfr_signbit (mpc_imagref (op)) ? -1 : 1));
+ }
+
+ return MPC_INEX (inex_re, 0);
+ }
+
+ /* pure real argument */
+ if (mpfr_zero_p (mpc_imagref (op)))
+ {
+ int inex_re;
+ int inex_im;
+ int s_im;
+ s_im = mpfr_signbit (mpc_imagref (op));
+
+ if (mpfr_cmp_ui (mpc_realref (op), 1) > 0)
+ {
+ if (s_im)
+ inex_im = -mpfr_acosh (mpc_imagref (rop), mpc_realref (op),
+ INV_RND (MPC_RND_IM (rnd)));
+ else
+ inex_im = mpfr_acosh (mpc_imagref (rop), mpc_realref (op),
+ MPC_RND_IM (rnd));
+ inex_re = set_pi_over_2 (mpc_realref (rop),
+ (mpfr_signbit (mpc_realref (op)) ? -1 : 1), MPC_RND_RE (rnd));
+ if (s_im)
+ mpc_conj (rop, rop, MPC_RNDNN);
+ }
+ else if (mpfr_cmp_si (mpc_realref (op), -1) < 0)
+ {
+ mpfr_t minus_op_re;
+ minus_op_re[0] = mpc_realref (op)[0];
+ MPFR_CHANGE_SIGN (minus_op_re);
+
+ if (s_im)
+ inex_im = -mpfr_acosh (mpc_imagref (rop), minus_op_re,
+ INV_RND (MPC_RND_IM (rnd)));
+ else
+ inex_im = mpfr_acosh (mpc_imagref (rop), minus_op_re,
+ MPC_RND_IM (rnd));
+ inex_re = set_pi_over_2 (mpc_realref (rop),
+ (mpfr_signbit (mpc_realref (op)) ? -1 : 1), MPC_RND_RE (rnd));
+ if (s_im)
+ mpc_conj (rop, rop, MPC_RNDNN);
+ }
+ else
+ {
+ inex_im = mpfr_set_ui (mpc_imagref (rop), 0, MPC_RND_IM (rnd));
+ if (s_im)
+ mpfr_neg (mpc_imagref (rop), mpc_imagref (rop), GMP_RNDN);
+ inex_re = mpfr_asin (mpc_realref (rop), mpc_realref (op), MPC_RND_RE (rnd));
+ }
+
+ return MPC_INEX (inex_re, inex_im);
+ }
+
+ /* pure imaginary argument */
+ if (mpfr_zero_p (mpc_realref (op)))
+ {
+ int inex_im;
+ int s;
+ s = mpfr_signbit (mpc_realref (op));
+ mpfr_set_ui (mpc_realref (rop), 0, GMP_RNDN);
+ if (s)
+ mpfr_neg (mpc_realref (rop), mpc_realref (rop), GMP_RNDN);
+ inex_im = mpfr_asinh (mpc_imagref (rop), mpc_imagref (op), MPC_RND_IM (rnd));
+
+ return MPC_INEX (0, inex_im);
+ }
+
+ /* regular complex: asin(z) = -i*log(i*z+sqrt(1-z^2)) */
+ p_re = mpfr_get_prec (mpc_realref(rop));
+ p_im = mpfr_get_prec (mpc_imagref(rop));
+ rnd_re = MPC_RND_RE(rnd);
+ rnd_im = MPC_RND_IM(rnd);
+ p = p_re >= p_im ? p_re : p_im;
+ mpc_init2 (z1, p);
+ while (1)
+ {
+ mpfr_exp_t ex, ey, err;
+
+ p += mpc_ceil_log2 (p) + 3 + incr_p; /* incr_p is zero initially */
+ incr_p = p / 2;
+ mpfr_set_prec (mpc_realref(z1), p);
+ mpfr_set_prec (mpc_imagref(z1), p);
+
+ /* z1 <- z^2 */
+ mpc_sqr (z1, op, MPC_RNDNN);
+ /* err(x) <= 1/2 ulp(x), err(y) <= 1/2 ulp(y) */
+ /* z1 <- 1-z1 */
+ ex = mpfr_get_exp (mpc_realref(z1));
+ mpfr_ui_sub (mpc_realref(z1), 1, mpc_realref(z1), GMP_RNDN);
+ mpfr_neg (mpc_imagref(z1), mpc_imagref(z1), GMP_RNDN);
+ ex = ex - mpfr_get_exp (mpc_realref(z1));
+ ex = (ex <= 0) ? 0 : ex;
+ /* err(x) <= 2^ex * ulp(x) */
+ ex = ex + mpfr_get_exp (mpc_realref(z1)) - p;
+ /* err(x) <= 2^ex */
+ ey = mpfr_get_exp (mpc_imagref(z1)) - p - 1;
+ /* err(y) <= 2^ey */
+ ex = (ex >= ey) ? ex : ey; /* err(x), err(y) <= 2^ex, i.e., the norm
+ of the error is bounded by |h|<=2^(ex+1/2) */
+ /* z1 <- sqrt(z1): if z1 = z + h, then sqrt(z1) = sqrt(z) + h/2/sqrt(t) */
+ ey = mpfr_get_exp (mpc_realref(z1)) >= mpfr_get_exp (mpc_imagref(z1))
+ ? mpfr_get_exp (mpc_realref(z1)) : mpfr_get_exp (mpc_imagref(z1));
+ /* we have |z1| >= 2^(ey-1) thus 1/|z1| <= 2^(1-ey) */
+ mpc_sqrt (z1, z1, MPC_RNDNN);
+ ex = (2 * ex + 1) - 2 - (ey - 1); /* |h^2/4/|t| <= 2^ex */
+ ex = (ex + 1) / 2; /* ceil(ex/2) */
+ /* express ex in terms of ulp(z1) */
+ ey = mpfr_get_exp (mpc_realref(z1)) <= mpfr_get_exp (mpc_imagref(z1))
+ ? mpfr_get_exp (mpc_realref(z1)) : mpfr_get_exp (mpc_imagref(z1));
+ ex = ex - ey + p;
+ /* take into account the rounding error in the mpc_sqrt call */
+ err = (ex <= 0) ? 1 : ex + 1;
+ /* err(x) <= 2^err * ulp(x), err(y) <= 2^err * ulp(y) */
+ /* z1 <- i*z + z1 */
+ ex = mpfr_get_exp (mpc_realref(z1));
+ ey = mpfr_get_exp (mpc_imagref(z1));
+ mpfr_sub (mpc_realref(z1), mpc_realref(z1), mpc_imagref(op), GMP_RNDN);
+ mpfr_add (mpc_imagref(z1), mpc_imagref(z1), mpc_realref(op), GMP_RNDN);
+ if (mpfr_cmp_ui (mpc_realref(z1), 0) == 0 || mpfr_cmp_ui (mpc_imagref(z1), 0) == 0)
+ continue;
+ ex -= mpfr_get_exp (mpc_realref(z1)); /* cancellation in x */
+ ey -= mpfr_get_exp (mpc_imagref(z1)); /* cancellation in y */
+ ex = (ex >= ey) ? ex : ey; /* maximum cancellation */
+ err += ex;
+ err = (err <= 0) ? 1 : err + 1; /* rounding error in sub/add */
+ /* z1 <- log(z1): if z1 = z + h, then log(z1) = log(z) + h/t with
+ |t| >= min(|z1|,|z|) */
+ ex = mpfr_get_exp (mpc_realref(z1));
+ ey = mpfr_get_exp (mpc_imagref(z1));
+ ex = (ex >= ey) ? ex : ey;
+ err += ex - p; /* revert to absolute error <= 2^err */
+ mpc_log (z1, z1, GMP_RNDN);
+ err -= ex - 1; /* 1/|t| <= 1/|z| <= 2^(1-ex) */
+ /* express err in terms of ulp(z1) */
+ ey = mpfr_get_exp (mpc_realref(z1)) <= mpfr_get_exp (mpc_imagref(z1))
+ ? mpfr_get_exp (mpc_realref(z1)) : mpfr_get_exp (mpc_imagref(z1));
+ err = err - ey + p;
+ /* take into account the rounding error in the mpc_log call */
+ err = (err <= 0) ? 1 : err + 1;
+ /* z1 <- -i*z1 */
+ mpfr_swap (mpc_realref(z1), mpc_imagref(z1));
+ mpfr_neg (mpc_imagref(z1), mpc_imagref(z1), GMP_RNDN);
+ if (mpfr_can_round (mpc_realref(z1), p - err, GMP_RNDN, GMP_RNDZ,
+ p_re + (rnd_re == GMP_RNDN)) &&
+ mpfr_can_round (mpc_imagref(z1), p - err, GMP_RNDN, GMP_RNDZ,
+ p_im + (rnd_im == GMP_RNDN)))
+ break;
+ }
+
+ inex = mpc_set (rop, z1, rnd);
+ mpc_clear (z1);
+
+ return inex;
+}
diff --git a/mpc/src/asinh.c b/mpc/src/asinh.c
new file mode 100644
index 0000000000..2807a8bb31
--- /dev/null
+++ b/mpc/src/asinh.c
@@ -0,0 +1,55 @@
+/* mpc_asinh -- inverse hyperbolic sine of a complex number.
+
+Copyright (C) 2009, 2011, 2012 INRIA
+
+This file is part of GNU MPC.
+
+GNU MPC is free software; you can redistribute it and/or modify it under
+the terms of the GNU Lesser General Public License as published by the
+Free Software Foundation; either version 3 of the License, or (at your
+option) any later version.
+
+GNU MPC 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 Lesser General Public License for
+more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+
+#include "mpc-impl.h"
+
+int
+mpc_asinh (mpc_ptr rop, mpc_srcptr op, mpc_rnd_t rnd)
+{
+ /* asinh(op) = -i*asin(i*op) */
+ int inex;
+ mpc_t z, a;
+ mpfr_t tmp;
+
+ /* z = i*op */
+ mpc_realref (z)[0] = mpc_imagref (op)[0];
+ mpc_imagref (z)[0] = mpc_realref (op)[0];
+ MPFR_CHANGE_SIGN (mpc_realref (z));
+
+ /* Note reversal of precisions due to later multiplication by -i */
+ mpc_init3 (a, MPC_PREC_IM(rop), MPC_PREC_RE(rop));
+
+ inex = mpc_asin (a, z,
+ MPC_RND (INV_RND (MPC_RND_IM (rnd)), MPC_RND_RE (rnd)));
+
+ /* if a = asin(i*op) = x+i*y, and we want y-i*x */
+
+ /* change a to -i*a */
+ tmp[0] = mpc_realref (a)[0];
+ mpc_realref (a)[0] = mpc_imagref (a)[0];
+ mpc_imagref (a)[0] = tmp[0];
+ MPFR_CHANGE_SIGN (mpc_imagref (a));
+
+ mpc_set (rop, a, MPC_RNDNN); /* exact */
+
+ mpc_clear (a);
+
+ return MPC_INEX (MPC_INEX_IM (inex), -MPC_INEX_RE (inex));
+}
diff --git a/mpc/src/atan.c b/mpc/src/atan.c
new file mode 100644
index 0000000000..285f79f6cb
--- /dev/null
+++ b/mpc/src/atan.c
@@ -0,0 +1,367 @@
+/* mpc_atan -- arctangent of a complex number.
+
+Copyright (C) 2009, 2010, 2011, 2012, 2013 INRIA
+
+This file is part of GNU MPC.
+
+GNU MPC is free software; you can redistribute it and/or modify it under
+the terms of the GNU Lesser General Public License as published by the
+Free Software Foundation; either version 3 of the License, or (at your
+option) any later version.
+
+GNU MPC 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 Lesser General Public License for
+more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+
+#include <stdio.h>
+#include "mpc-impl.h"
+
+/* set rop to
+ -pi/2 if s < 0
+ +pi/2 else
+ rounded in the direction rnd
+*/
+int
+set_pi_over_2 (mpfr_ptr rop, int s, mpfr_rnd_t rnd)
+{
+ int inex;
+
+ inex = mpfr_const_pi (rop, s < 0 ? INV_RND (rnd) : rnd);
+ mpfr_div_2ui (rop, rop, 1, GMP_RNDN);
+ if (s < 0)
+ {
+ inex = -inex;
+ mpfr_neg (rop, rop, GMP_RNDN);
+ }
+
+ return inex;
+}
+
+int
+mpc_atan (mpc_ptr rop, mpc_srcptr op, mpc_rnd_t rnd)
+{
+ int s_re;
+ int s_im;
+ int inex_re;
+ int inex_im;
+ int inex;
+
+ inex_re = 0;
+ inex_im = 0;
+ s_re = mpfr_signbit (mpc_realref (op));
+ s_im = mpfr_signbit (mpc_imagref (op));
+
+ /* special values */
+ if (mpfr_nan_p (mpc_realref (op)) || mpfr_nan_p (mpc_imagref (op)))
+ {
+ if (mpfr_nan_p (mpc_realref (op)))
+ {
+ mpfr_set_nan (mpc_realref (rop));
+ if (mpfr_zero_p (mpc_imagref (op)) || mpfr_inf_p (mpc_imagref (op)))
+ {
+ mpfr_set_ui (mpc_imagref (rop), 0, GMP_RNDN);
+ if (s_im)
+ mpc_conj (rop, rop, MPC_RNDNN);
+ }
+ else
+ mpfr_set_nan (mpc_imagref (rop));
+ }
+ else
+ {
+ if (mpfr_inf_p (mpc_realref (op)))
+ {
+ inex_re = set_pi_over_2 (mpc_realref (rop), -s_re, MPC_RND_RE (rnd));
+ mpfr_set_ui (mpc_imagref (rop), 0, GMP_RNDN);
+ }
+ else
+ {
+ mpfr_set_nan (mpc_realref (rop));
+ mpfr_set_nan (mpc_imagref (rop));
+ }
+ }
+ return MPC_INEX (inex_re, 0);
+ }
+
+ if (mpfr_inf_p (mpc_realref (op)) || mpfr_inf_p (mpc_imagref (op)))
+ {
+ inex_re = set_pi_over_2 (mpc_realref (rop), -s_re, MPC_RND_RE (rnd));
+
+ mpfr_set_ui (mpc_imagref (rop), 0, GMP_RNDN);
+ if (s_im)
+ mpc_conj (rop, rop, GMP_RNDN);
+
+ return MPC_INEX (inex_re, 0);
+ }
+
+ /* pure real argument */
+ if (mpfr_zero_p (mpc_imagref (op)))
+ {
+ inex_re = mpfr_atan (mpc_realref (rop), mpc_realref (op), MPC_RND_RE (rnd));
+
+ mpfr_set_ui (mpc_imagref (rop), 0, GMP_RNDN);
+ if (s_im)
+ mpc_conj (rop, rop, GMP_RNDN);
+
+ return MPC_INEX (inex_re, 0);
+ }
+
+ /* pure imaginary argument */
+ if (mpfr_zero_p (mpc_realref (op)))
+ {
+ int cmp_1;
+
+ if (s_im)
+ cmp_1 = -mpfr_cmp_si (mpc_imagref (op), -1);
+ else
+ cmp_1 = mpfr_cmp_ui (mpc_imagref (op), +1);
+
+ if (cmp_1 < 0)
+ {
+ /* atan(+0+iy) = +0 +i*atanh(y), if |y| < 1
+ atan(-0+iy) = -0 +i*atanh(y), if |y| < 1 */
+
+ mpfr_set_ui (mpc_realref (rop), 0, GMP_RNDN);
+ if (s_re)
+ mpfr_neg (mpc_realref (rop), mpc_realref (rop), GMP_RNDN);
+
+ inex_im = mpfr_atanh (mpc_imagref (rop), mpc_imagref (op), MPC_RND_IM (rnd));
+ }
+ else if (cmp_1 == 0)
+ {
+ /* atan(+/-0 +i) = +/-0 +i*inf
+ atan(+/-0 -i) = +/-0 -i*inf */
+ mpfr_set_zero (mpc_realref (rop), s_re ? -1 : +1);
+ mpfr_set_inf (mpc_imagref (rop), s_im ? -1 : +1);
+ }
+ else
+ {
+ /* atan(+0+iy) = +pi/2 +i*atanh(1/y), if |y| > 1
+ atan(-0+iy) = -pi/2 +i*atanh(1/y), if |y| > 1 */
+ mpfr_rnd_t rnd_im, rnd_away;
+ mpfr_t y;
+ mpfr_prec_t p, p_im;
+ int ok;
+
+ rnd_im = MPC_RND_IM (rnd);
+ mpfr_init (y);
+ p_im = mpfr_get_prec (mpc_imagref (rop));
+ p = p_im;
+
+ /* a = o(1/y) with error(a) < 1 ulp(a)
+ b = o(atanh(a)) with error(b) < (1+2^{1+Exp(a)-Exp(b)}) ulp(b)
+
+ As |atanh (1/y)| > |1/y| we have Exp(a)-Exp(b) <=0 so, at most,
+ 2 bits of precision are lost.
+
+ We round atanh(1/y) away from 0.
+ */
+ do
+ {
+ p += mpc_ceil_log2 (p) + 2;
+ mpfr_set_prec (y, p);
+ rnd_away = s_im == 0 ? GMP_RNDU : GMP_RNDD;
+ inex_im = mpfr_ui_div (y, 1, mpc_imagref (op), rnd_away);
+ /* FIXME: should we consider the case with unreasonably huge
+ precision prec(y)>3*exp_min, where atanh(1/Im(op)) could be
+ representable while 1/Im(op) underflows ?
+ This corresponds to |y| = 0.5*2^emin, in which case the
+ result may be wrong. */
+
+ /* atanh cannot underflow: |atanh(x)| > |x| for |x| < 1 */
+ inex_im |= mpfr_atanh (y, y, rnd_away);
+
+ ok = inex_im == 0
+ || mpfr_can_round (y, p - 2, rnd_away, GMP_RNDZ,
+ p_im + (rnd_im == GMP_RNDN));
+ } while (ok == 0);
+
+ inex_re = set_pi_over_2 (mpc_realref (rop), -s_re, MPC_RND_RE (rnd));
+ inex_im = mpfr_set (mpc_imagref (rop), y, rnd_im);
+ mpfr_clear (y);
+ }
+ return MPC_INEX (inex_re, inex_im);
+ }
+
+ /* regular number argument */
+ {
+ mpfr_t a, b, x, y;
+ mpfr_prec_t prec, p;
+ mpfr_exp_t err, expo;
+ int ok = 0;
+ mpfr_t minus_op_re;
+ mpfr_exp_t op_re_exp, op_im_exp;
+ mpfr_rnd_t rnd1, rnd2;
+
+ mpfr_inits2 (MPFR_PREC_MIN, a, b, x, y, (mpfr_ptr) 0);
+
+ /* real part: Re(arctan(x+i*y)) = [arctan2(x,1-y) - arctan2(-x,1+y)]/2 */
+ minus_op_re[0] = mpc_realref (op)[0];
+ MPFR_CHANGE_SIGN (minus_op_re);
+ op_re_exp = mpfr_get_exp (mpc_realref (op));
+ op_im_exp = mpfr_get_exp (mpc_imagref (op));
+
+ prec = mpfr_get_prec (mpc_realref (rop)); /* result precision */
+
+ /* a = o(1-y) error(a) < 1 ulp(a)
+ b = o(atan2(x,a)) error(b) < [1+2^{3+Exp(x)-Exp(a)-Exp(b)}] ulp(b)
+ = kb ulp(b)
+ c = o(1+y) error(c) < 1 ulp(c)
+ d = o(atan2(-x,c)) error(d) < [1+2^{3+Exp(x)-Exp(c)-Exp(d)}] ulp(d)
+ = kd ulp(d)
+ e = o(b - d) error(e) < [1 + kb*2^{Exp(b}-Exp(e)}
+ + kd*2^{Exp(d)-Exp(e)}] ulp(e)
+ error(e) < [1 + 2^{4+Exp(x)-Exp(a)-Exp(e)}
+ + 2^{4+Exp(x)-Exp(c)-Exp(e)}] ulp(e)
+ because |atan(u)| < |u|
+ < [1 + 2^{5+Exp(x)-min(Exp(a),Exp(c))
+ -Exp(e)}] ulp(e)
+ f = e/2 exact
+ */
+
+ /* p: working precision */
+ p = (op_im_exp > 0 || prec > SAFE_ABS (mpfr_prec_t, op_im_exp)) ? prec
+ : (prec - op_im_exp);
+ rnd1 = mpfr_sgn (mpc_realref (op)) > 0 ? GMP_RNDD : GMP_RNDU;
+ rnd2 = mpfr_sgn (mpc_realref (op)) < 0 ? GMP_RNDU : GMP_RNDD;
+
+ do
+ {
+ p += mpc_ceil_log2 (p) + 2;
+ mpfr_set_prec (a, p);
+ mpfr_set_prec (b, p);
+ mpfr_set_prec (x, p);
+
+ /* x = upper bound for atan (x/(1-y)). Since atan is increasing, we
+ need an upper bound on x/(1-y), i.e., a lower bound on 1-y for
+ x positive, and an upper bound on 1-y for x negative */
+ mpfr_ui_sub (a, 1, mpc_imagref (op), rnd1);
+ if (mpfr_sgn (a) == 0) /* y is near 1, thus 1+y is near 2, and
+ expo will be 1 or 2 below */
+ {
+ MPC_ASSERT (mpfr_cmp_ui (mpc_imagref(op), 1) == 0);
+ /* check for intermediate underflow */
+ err = 2; /* ensures err will be expo below */
+ }
+ else
+ err = mpfr_get_exp (a); /* err = Exp(a) with the notations above */
+ mpfr_atan2 (x, mpc_realref (op), a, GMP_RNDU);
+
+ /* b = lower bound for atan (-x/(1+y)): for x negative, we need a
+ lower bound on -x/(1+y), i.e., an upper bound on 1+y */
+ mpfr_add_ui (a, mpc_imagref(op), 1, rnd2);
+ /* if a is exactly zero, i.e., Im(op) = -1, then the error on a is 0,
+ and we can simply ignore the terms involving Exp(a) in the error */
+ if (mpfr_sgn (a) == 0)
+ {
+ MPC_ASSERT (mpfr_cmp_si (mpc_imagref(op), -1) == 0);
+ /* check for intermediate underflow */
+ expo = err; /* will leave err unchanged below */
+ }
+ else
+ expo = mpfr_get_exp (a); /* expo = Exp(c) with the notations above */
+ mpfr_atan2 (b, minus_op_re, a, GMP_RNDD);
+
+ err = err < expo ? err : expo; /* err = min(Exp(a),Exp(c)) */
+ mpfr_sub (x, x, b, GMP_RNDU);
+
+ err = 5 + op_re_exp - err - mpfr_get_exp (x);
+ /* error is bounded by [1 + 2^err] ulp(e) */
+ err = err < 0 ? 1 : err + 1;
+
+ mpfr_div_2ui (x, x, 1, GMP_RNDU);
+
+ /* Note: using RND2=RNDD guarantees that if x is exactly representable
+ on prec + ... bits, mpfr_can_round will return 0 */
+ ok = mpfr_can_round (x, p - err, GMP_RNDU, GMP_RNDD,
+ prec + (MPC_RND_RE (rnd) == GMP_RNDN));
+ } while (ok == 0);
+
+ /* Imaginary part
+ Im(atan(x+I*y)) = 1/4 * [log(x^2+(1+y)^2) - log (x^2 +(1-y)^2)] */
+ prec = mpfr_get_prec (mpc_imagref (rop)); /* result precision */
+
+ /* a = o(1+y) error(a) < 1 ulp(a)
+ b = o(a^2) error(b) < 5 ulp(b)
+ c = o(x^2) error(c) < 1 ulp(c)
+ d = o(b+c) error(d) < 7 ulp(d)
+ e = o(log(d)) error(e) < [1 + 7*2^{2-Exp(e)}] ulp(e) = ke ulp(e)
+ f = o(1-y) error(f) < 1 ulp(f)
+ g = o(f^2) error(g) < 5 ulp(g)
+ h = o(c+f) error(h) < 7 ulp(h)
+ i = o(log(h)) error(i) < [1 + 7*2^{2-Exp(i)}] ulp(i) = ki ulp(i)
+ j = o(e-i) error(j) < [1 + ke*2^{Exp(e)-Exp(j)}
+ + ki*2^{Exp(i)-Exp(j)}] ulp(j)
+ error(j) < [1 + 2^{Exp(e)-Exp(j)} + 2^{Exp(i)-Exp(j)}
+ + 7*2^{3-Exp(j)}] ulp(j)
+ < [1 + 2^{max(Exp(e),Exp(i))-Exp(j)+1}
+ + 7*2^{3-Exp(j)}] ulp(j)
+ k = j/4 exact
+ */
+ err = 2;
+ p = prec; /* working precision */
+
+ do
+ {
+ p += mpc_ceil_log2 (p) + err;
+ mpfr_set_prec (a, p);
+ mpfr_set_prec (b, p);
+ mpfr_set_prec (y, p);
+
+ /* a = upper bound for log(x^2 + (1+y)^2) */
+ ROUND_AWAY (mpfr_add_ui (a, mpc_imagref (op), 1, MPFR_RNDA), a);
+ mpfr_sqr (a, a, GMP_RNDU);
+ mpfr_sqr (y, mpc_realref (op), GMP_RNDU);
+ mpfr_add (a, a, y, GMP_RNDU);
+ mpfr_log (a, a, GMP_RNDU);
+
+ /* b = lower bound for log(x^2 + (1-y)^2) */
+ mpfr_ui_sub (b, 1, mpc_imagref (op), GMP_RNDZ); /* round to zero */
+ mpfr_sqr (b, b, GMP_RNDZ);
+ /* we could write mpfr_sqr (y, mpc_realref (op), GMP_RNDZ) but it is
+ more efficient to reuse the value of y (x^2) above and subtract
+ one ulp */
+ mpfr_nextbelow (y);
+ mpfr_add (b, b, y, GMP_RNDZ);
+ mpfr_log (b, b, GMP_RNDZ);
+
+ mpfr_sub (y, a, b, GMP_RNDU);
+
+ if (mpfr_zero_p (y))
+ /* FIXME: happens when x and y have very different magnitudes;
+ could be handled more efficiently */
+ ok = 0;
+ else
+ {
+ expo = MPC_MAX (mpfr_get_exp (a), mpfr_get_exp (b));
+ expo = expo - mpfr_get_exp (y) + 1;
+ err = 3 - mpfr_get_exp (y);
+ /* error(j) <= [1 + 2^expo + 7*2^err] ulp(j) */
+ if (expo <= err) /* error(j) <= [1 + 2^{err+1}] ulp(j) */
+ err = (err < 0) ? 1 : err + 2;
+ else
+ err = (expo < 0) ? 1 : expo + 2;
+
+ mpfr_div_2ui (y, y, 2, GMP_RNDN);
+ MPC_ASSERT (!mpfr_zero_p (y));
+ /* FIXME: underflow. Since the main term of the Taylor series
+ in y=0 is 1/(x^2+1) * y, this means that y is very small
+ and/or x very large; but then the mpfr_zero_p (y) above
+ should be true. This needs a proof, or better yet,
+ special code. */
+
+ ok = mpfr_can_round (y, p - err, GMP_RNDU, GMP_RNDD,
+ prec + (MPC_RND_IM (rnd) == GMP_RNDN));
+ }
+ } while (ok == 0);
+
+ inex = mpc_set_fr_fr (rop, x, y, rnd);
+
+ mpfr_clears (a, b, x, y, (mpfr_ptr) 0);
+ return inex;
+ }
+}
diff --git a/mpc/src/atanh.c b/mpc/src/atanh.c
new file mode 100644
index 0000000000..e5716cc703
--- /dev/null
+++ b/mpc/src/atanh.c
@@ -0,0 +1,52 @@
+/* mpc_atanh -- inverse hyperbolic tangent of a complex number.
+
+Copyright (C) 2009, 2011, 2012 INRIA
+
+This file is part of GNU MPC.
+
+GNU MPC is free software; you can redistribute it and/or modify it under
+the terms of the GNU Lesser General Public License as published by the
+Free Software Foundation; either version 3 of the License, or (at your
+option) any later version.
+
+GNU MPC 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 Lesser General Public License for
+more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+
+#include "mpc-impl.h"
+
+int
+mpc_atanh (mpc_ptr rop, mpc_srcptr op, mpc_rnd_t rnd)
+{
+ /* atanh(op) = -i*atan(i*op) */
+ int inex;
+ mpfr_t tmp;
+ mpc_t z, a;
+
+ mpc_realref (z)[0] = mpc_imagref (op)[0];
+ mpc_imagref (z)[0] = mpc_realref (op)[0];
+ MPFR_CHANGE_SIGN (mpc_realref (z));
+
+ /* Note reversal of precisions due to later multiplication by -i */
+ mpc_init3 (a, MPC_PREC_IM(rop), MPC_PREC_RE(rop));
+
+ inex = mpc_atan (a, z,
+ MPC_RND (INV_RND (MPC_RND_IM (rnd)), MPC_RND_RE (rnd)));
+
+ /* change a to -i*a, i.e., x+i*y to y-i*x */
+ tmp[0] = mpc_realref (a)[0];
+ mpc_realref (a)[0] = mpc_imagref (a)[0];
+ mpc_imagref (a)[0] = tmp[0];
+ MPFR_CHANGE_SIGN (mpc_imagref (a));
+
+ mpc_set (rop, a, rnd);
+
+ mpc_clear (a);
+
+ return MPC_INEX (MPC_INEX_IM (inex), -MPC_INEX_RE (inex));
+}
diff --git a/mpc/src/clear.c b/mpc/src/clear.c
new file mode 100644
index 0000000000..f76b5db0f9
--- /dev/null
+++ b/mpc/src/clear.c
@@ -0,0 +1,28 @@
+/* mpc_clear -- Clear a complex variable.
+
+Copyright (C) 2002, 2009, 2011 INRIA
+
+This file is part of GNU MPC.
+
+GNU MPC is free software; you can redistribute it and/or modify it under
+the terms of the GNU Lesser General Public License as published by the
+Free Software Foundation; either version 3 of the License, or (at your
+option) any later version.
+
+GNU MPC 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 Lesser General Public License for
+more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+
+#include "mpc-impl.h"
+
+void
+mpc_clear (mpc_t x)
+{
+ mpfr_clear (mpc_realref(x));
+ mpfr_clear (mpc_imagref(x));
+}
diff --git a/mpc/src/cmp.c b/mpc/src/cmp.c
new file mode 100644
index 0000000000..ce1871c430
--- /dev/null
+++ b/mpc/src/cmp.c
@@ -0,0 +1,33 @@
+/* mpc_cmp -- Compare two complex numbers.
+
+Copyright (C) 2002, 2009, 2010, 2011 INRIA
+
+This file is part of GNU MPC.
+
+GNU MPC is free software; you can redistribute it and/or modify it under
+the terms of the GNU Lesser General Public License as published by the
+Free Software Foundation; either version 3 of the License, or (at your
+option) any later version.
+
+GNU MPC 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 Lesser General Public License for
+more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+
+#include "mpc-impl.h"
+
+/* return 0 iff a = b */
+int
+mpc_cmp (mpc_srcptr a, mpc_srcptr b)
+{
+ int cmp_re, cmp_im;
+
+ cmp_re = mpfr_cmp (mpc_realref(a), mpc_realref(b));
+ cmp_im = mpfr_cmp (mpc_imagref(a), mpc_imagref(b));
+
+ return MPC_INEX(cmp_re, cmp_im);
+}
diff --git a/mpc/src/cmp_si_si.c b/mpc/src/cmp_si_si.c
new file mode 100644
index 0000000000..a50b7585f5
--- /dev/null
+++ b/mpc/src/cmp_si_si.c
@@ -0,0 +1,34 @@
+/* mpc_cmp_si_si -- Compare a complex number to a number of the form
+ b+c*i with b and c signed integers.
+
+Copyright (C) 2005, 2009, 2011 INRIA
+
+This file is part of GNU MPC.
+
+GNU MPC is free software; you can redistribute it and/or modify it under
+the terms of the GNU Lesser General Public License as published by the
+Free Software Foundation; either version 3 of the License, or (at your
+option) any later version.
+
+GNU MPC 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 Lesser General Public License for
+more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+
+#include "mpc-impl.h"
+
+/* return 0 iff a = b */
+int
+mpc_cmp_si_si (mpc_srcptr a, long int b, long int c)
+{
+ int cmp_re, cmp_im;
+
+ cmp_re = mpfr_cmp_si (mpc_realref(a), b);
+ cmp_im = mpfr_cmp_si (mpc_imagref(a), c);
+
+ return MPC_INEX(cmp_re, cmp_im);
+}
diff --git a/mpc/src/conj.c b/mpc/src/conj.c
new file mode 100644
index 0000000000..0905b1d358
--- /dev/null
+++ b/mpc/src/conj.c
@@ -0,0 +1,32 @@
+/* mpc_conj -- Conjugate of a complex number.
+
+Copyright (C) 2002, 2009, 2011 INRIA
+
+This file is part of GNU MPC.
+
+GNU MPC is free software; you can redistribute it and/or modify it under
+the terms of the GNU Lesser General Public License as published by the
+Free Software Foundation; either version 3 of the License, or (at your
+option) any later version.
+
+GNU MPC 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 Lesser General Public License for
+more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+
+#include "mpc-impl.h"
+
+int
+mpc_conj (mpc_ptr a, mpc_srcptr b, mpc_rnd_t rnd)
+{
+ int inex_re, inex_im;
+
+ inex_re = mpfr_set (mpc_realref(a), mpc_realref(b), MPC_RND_RE(rnd));
+ inex_im = mpfr_neg (mpc_imagref(a), mpc_imagref(b), MPC_RND_IM(rnd));
+
+ return MPC_INEX(inex_re, inex_im);
+}
diff --git a/mpc/src/cos.c b/mpc/src/cos.c
new file mode 100644
index 0000000000..3810f3ec4c
--- /dev/null
+++ b/mpc/src/cos.c
@@ -0,0 +1,27 @@
+/* mpc_cos -- cosine of a complex number.
+
+Copyright (C) 2010, 2011 INRIA
+
+This file is part of GNU MPC.
+
+GNU MPC is free software; you can redistribute it and/or modify it under
+the terms of the GNU Lesser General Public License as published by the
+Free Software Foundation; either version 3 of the License, or (at your
+option) any later version.
+
+GNU MPC 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 Lesser General Public License for
+more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+
+#include "mpc-impl.h"
+
+int
+mpc_cos (mpc_ptr rop, mpc_srcptr op, mpc_rnd_t rnd)
+{
+ return MPC_INEX2 (mpc_sin_cos (NULL, rop, op, 0, rnd));
+}
diff --git a/mpc/src/cosh.c b/mpc/src/cosh.c
new file mode 100644
index 0000000000..0d4aab9e4d
--- /dev/null
+++ b/mpc/src/cosh.c
@@ -0,0 +1,35 @@
+/* mpc_cosh -- hyperbolic cosine of a complex number.
+
+Copyright (C) 2008, 2009, 2011 INRIA
+
+This file is part of GNU MPC.
+
+GNU MPC is free software; you can redistribute it and/or modify it under
+the terms of the GNU Lesser General Public License as published by the
+Free Software Foundation; either version 3 of the License, or (at your
+option) any later version.
+
+GNU MPC 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 Lesser General Public License for
+more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+
+#include "mpc-impl.h"
+
+int
+mpc_cosh (mpc_ptr rop, mpc_srcptr op, mpc_rnd_t rnd)
+{
+ /* cosh(op) = cos(i*op) */
+ mpc_t z;
+
+ /* z = i*op without copying significand */
+ mpc_realref (z)[0] = mpc_imagref (op)[0];
+ mpc_imagref (z)[0] = mpc_realref (op)[0];
+ MPFR_CHANGE_SIGN (mpc_realref (z));
+
+ return mpc_cos (rop, z, rnd);
+}
diff --git a/mpc/src/div.c b/mpc/src/div.c
new file mode 100644
index 0000000000..83584b8b5f
--- /dev/null
+++ b/mpc/src/div.c
@@ -0,0 +1,449 @@
+/* mpc_div -- Divide two complex numbers.
+
+Copyright (C) 2002, 2003, 2004, 2005, 2008, 2009, 2010, 2011, 2012 INRIA
+
+This file is part of GNU MPC.
+
+GNU MPC is free software; you can redistribute it and/or modify it under
+the terms of the GNU Lesser General Public License as published by the
+Free Software Foundation; either version 3 of the License, or (at your
+option) any later version.
+
+GNU MPC 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 Lesser General Public License for
+more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+
+#include "mpc-impl.h"
+
+/* this routine deals with the case where w is zero */
+static int
+mpc_div_zero (mpc_ptr a, mpc_srcptr z, mpc_srcptr w, mpc_rnd_t rnd)
+/* Assumes w==0, implementation according to C99 G.5.1.8 */
+{
+ int sign = MPFR_SIGNBIT (mpc_realref (w));
+ mpfr_t infty;
+
+ mpfr_init2 (infty, MPFR_PREC_MIN);
+ mpfr_set_inf (infty, sign);
+ mpfr_mul (mpc_realref (a), infty, mpc_realref (z), MPC_RND_RE (rnd));
+ mpfr_mul (mpc_imagref (a), infty, mpc_imagref (z), MPC_RND_IM (rnd));
+ mpfr_clear (infty);
+ return MPC_INEX (0, 0); /* exact */
+}
+
+/* this routine deals with the case where z is infinite and w finite */
+static int
+mpc_div_inf_fin (mpc_ptr rop, mpc_srcptr z, mpc_srcptr w)
+/* Assumes w finite and non-zero and z infinite; implementation
+ according to C99 G.5.1.8 */
+{
+ int a, b, x, y;
+
+ a = (mpfr_inf_p (mpc_realref (z)) ? MPFR_SIGNBIT (mpc_realref (z)) : 0);
+ b = (mpfr_inf_p (mpc_imagref (z)) ? MPFR_SIGNBIT (mpc_imagref (z)) : 0);
+
+ /* a is -1 if Re(z) = -Inf, 1 if Re(z) = +Inf, 0 if Re(z) is finite
+ b is -1 if Im(z) = -Inf, 1 if Im(z) = +Inf, 0 if Im(z) is finite */
+
+ /* x = MPC_MPFR_SIGN (a * mpc_realref (w) + b * mpc_imagref (w)) */
+ /* y = MPC_MPFR_SIGN (b * mpc_realref (w) - a * mpc_imagref (w)) */
+ if (a == 0 || b == 0) {
+ /* only one of a or b can be zero, since z is infinite */
+ x = a * MPC_MPFR_SIGN (mpc_realref (w)) + b * MPC_MPFR_SIGN (mpc_imagref (w));
+ y = b * MPC_MPFR_SIGN (mpc_realref (w)) - a * MPC_MPFR_SIGN (mpc_imagref (w));
+ }
+ else {
+ /* Both parts of z are infinite; x could be determined by sign
+ considerations and comparisons. Since operations with non-finite
+ numbers are not considered time-critical, we let mpfr do the work. */
+ mpfr_t sign;
+
+ mpfr_init2 (sign, 2);
+ /* This is enough to determine the sign of sums and differences. */
+
+ if (a == 1)
+ if (b == 1) {
+ mpfr_add (sign, mpc_realref (w), mpc_imagref (w), GMP_RNDN);
+ x = MPC_MPFR_SIGN (sign);
+ mpfr_sub (sign, mpc_realref (w), mpc_imagref (w), GMP_RNDN);
+ y = MPC_MPFR_SIGN (sign);
+ }
+ else { /* b == -1 */
+ mpfr_sub (sign, mpc_realref (w), mpc_imagref (w), GMP_RNDN);
+ x = MPC_MPFR_SIGN (sign);
+ mpfr_add (sign, mpc_realref (w), mpc_imagref (w), GMP_RNDN);
+ y = -MPC_MPFR_SIGN (sign);
+ }
+ else /* a == -1 */
+ if (b == 1) {
+ mpfr_sub (sign, mpc_imagref (w), mpc_realref (w), GMP_RNDN);
+ x = MPC_MPFR_SIGN (sign);
+ mpfr_add (sign, mpc_realref (w), mpc_imagref (w), GMP_RNDN);
+ y = MPC_MPFR_SIGN (sign);
+ }
+ else { /* b == -1 */
+ mpfr_add (sign, mpc_realref (w), mpc_imagref (w), GMP_RNDN);
+ x = -MPC_MPFR_SIGN (sign);
+ mpfr_sub (sign, mpc_imagref (w), mpc_realref (w), GMP_RNDN);
+ y = MPC_MPFR_SIGN (sign);
+ }
+ mpfr_clear (sign);
+ }
+
+ if (x == 0)
+ mpfr_set_nan (mpc_realref (rop));
+ else
+ mpfr_set_inf (mpc_realref (rop), x);
+ if (y == 0)
+ mpfr_set_nan (mpc_imagref (rop));
+ else
+ mpfr_set_inf (mpc_imagref (rop), y);
+
+ return MPC_INEX (0, 0); /* exact */
+}
+
+
+/* this routine deals with the case where z if finite and w infinite */
+static int
+mpc_div_fin_inf (mpc_ptr rop, mpc_srcptr z, mpc_srcptr w)
+/* Assumes z finite and w infinite; implementation according to
+ C99 G.5.1.8 */
+{
+ mpfr_t c, d, a, b, x, y, zero;
+
+ mpfr_init2 (c, 2); /* needed to hold a signed zero, +1 or -1 */
+ mpfr_init2 (d, 2);
+ mpfr_init2 (x, 2);
+ mpfr_init2 (y, 2);
+ mpfr_init2 (zero, 2);
+ mpfr_set_ui (zero, 0ul, GMP_RNDN);
+ mpfr_init2 (a, mpfr_get_prec (mpc_realref (z)));
+ mpfr_init2 (b, mpfr_get_prec (mpc_imagref (z)));
+
+ mpfr_set_ui (c, (mpfr_inf_p (mpc_realref (w)) ? 1 : 0), GMP_RNDN);
+ MPFR_COPYSIGN (c, c, mpc_realref (w), GMP_RNDN);
+ mpfr_set_ui (d, (mpfr_inf_p (mpc_imagref (w)) ? 1 : 0), GMP_RNDN);
+ MPFR_COPYSIGN (d, d, mpc_imagref (w), GMP_RNDN);
+
+ mpfr_mul (a, mpc_realref (z), c, GMP_RNDN); /* exact */
+ mpfr_mul (b, mpc_imagref (z), d, GMP_RNDN);
+ mpfr_add (x, a, b, GMP_RNDN);
+
+ mpfr_mul (b, mpc_imagref (z), c, GMP_RNDN);
+ mpfr_mul (a, mpc_realref (z), d, GMP_RNDN);
+ mpfr_sub (y, b, a, GMP_RNDN);
+
+ MPFR_COPYSIGN (mpc_realref (rop), zero, x, GMP_RNDN);
+ MPFR_COPYSIGN (mpc_imagref (rop), zero, y, GMP_RNDN);
+
+ mpfr_clear (c);
+ mpfr_clear (d);
+ mpfr_clear (x);
+ mpfr_clear (y);
+ mpfr_clear (zero);
+ mpfr_clear (a);
+ mpfr_clear (b);
+
+ return MPC_INEX (0, 0); /* exact */
+}
+
+
+static int
+mpc_div_real (mpc_ptr rop, mpc_srcptr z, mpc_srcptr w, mpc_rnd_t rnd)
+/* Assumes z finite and w finite and non-zero, with imaginary part
+ of w a signed zero. */
+{
+ int inex_re, inex_im;
+ /* save signs of operands in case there are overlaps */
+ int zrs = MPFR_SIGNBIT (mpc_realref (z));
+ int zis = MPFR_SIGNBIT (mpc_imagref (z));
+ int wrs = MPFR_SIGNBIT (mpc_realref (w));
+ int wis = MPFR_SIGNBIT (mpc_imagref (w));
+
+ /* warning: rop may overlap with z,w so treat the imaginary part first */
+ inex_im = mpfr_div (mpc_imagref(rop), mpc_imagref(z), mpc_realref(w), MPC_RND_IM(rnd));
+ inex_re = mpfr_div (mpc_realref(rop), mpc_realref(z), mpc_realref(w), MPC_RND_RE(rnd));
+
+ /* correct signs of zeroes if necessary, which does not affect the
+ inexact flags */
+ if (mpfr_zero_p (mpc_realref (rop)))
+ mpfr_setsign (mpc_realref (rop), mpc_realref (rop), (zrs != wrs && zis != wis),
+ GMP_RNDN); /* exact */
+ if (mpfr_zero_p (mpc_imagref (rop)))
+ mpfr_setsign (mpc_imagref (rop), mpc_imagref (rop), (zis != wrs && zrs == wis),
+ GMP_RNDN);
+
+ return MPC_INEX(inex_re, inex_im);
+}
+
+
+static int
+mpc_div_imag (mpc_ptr rop, mpc_srcptr z, mpc_srcptr w, mpc_rnd_t rnd)
+/* Assumes z finite and w finite and non-zero, with real part
+ of w a signed zero. */
+{
+ int inex_re, inex_im;
+ int overlap = (rop == z) || (rop == w);
+ int imag_z = mpfr_zero_p (mpc_realref (z));
+ mpfr_t wloc;
+ mpc_t tmprop;
+ mpc_ptr dest = (overlap) ? tmprop : rop;
+ /* save signs of operands in case there are overlaps */
+ int zrs = MPFR_SIGNBIT (mpc_realref (z));
+ int zis = MPFR_SIGNBIT (mpc_imagref (z));
+ int wrs = MPFR_SIGNBIT (mpc_realref (w));
+ int wis = MPFR_SIGNBIT (mpc_imagref (w));
+
+ if (overlap)
+ mpc_init3 (tmprop, MPC_PREC_RE (rop), MPC_PREC_IM (rop));
+
+ wloc[0] = mpc_imagref(w)[0]; /* copies mpfr struct IM(w) into wloc */
+ inex_re = mpfr_div (mpc_realref(dest), mpc_imagref(z), wloc, MPC_RND_RE(rnd));
+ mpfr_neg (wloc, wloc, GMP_RNDN);
+ /* changes the sign only in wloc, not in w; no need to correct later */
+ inex_im = mpfr_div (mpc_imagref(dest), mpc_realref(z), wloc, MPC_RND_IM(rnd));
+
+ if (overlap) {
+ /* Note: we could use mpc_swap here, but this might cause problems
+ if rop and tmprop have been allocated using different methods, since
+ it will swap the significands of rop and tmprop. See
+ http://lists.gforge.inria.fr/pipermail/mpc-discuss/2009-August/000504.html */
+ mpc_set (rop, tmprop, MPC_RNDNN); /* exact */
+ mpc_clear (tmprop);
+ }
+
+ /* correct signs of zeroes if necessary, which does not affect the
+ inexact flags */
+ if (mpfr_zero_p (mpc_realref (rop)))
+ mpfr_setsign (mpc_realref (rop), mpc_realref (rop), (zrs != wrs && zis != wis),
+ GMP_RNDN); /* exact */
+ if (imag_z)
+ mpfr_setsign (mpc_imagref (rop), mpc_imagref (rop), (zis != wrs && zrs == wis),
+ GMP_RNDN);
+
+ return MPC_INEX(inex_re, inex_im);
+}
+
+
+int
+mpc_div (mpc_ptr a, mpc_srcptr b, mpc_srcptr c, mpc_rnd_t rnd)
+{
+ int ok_re = 0, ok_im = 0;
+ mpc_t res, c_conj;
+ mpfr_t q;
+ mpfr_prec_t prec;
+ int inex, inexact_prod, inexact_norm, inexact_re, inexact_im, loops = 0;
+ int underflow_norm, overflow_norm, underflow_prod, overflow_prod;
+ int underflow_re = 0, overflow_re = 0, underflow_im = 0, overflow_im = 0;
+ mpfr_rnd_t rnd_re = MPC_RND_RE (rnd), rnd_im = MPC_RND_IM (rnd);
+ int saved_underflow, saved_overflow;
+ int tmpsgn;
+
+ /* According to the C standard G.3, there are three types of numbers: */
+ /* finite (both parts are usual real numbers; contains 0), infinite */
+ /* (at least one part is a real infinity) and all others; the latter */
+ /* are numbers containing a nan, but no infinity, and could reasonably */
+ /* be called nan. */
+ /* By G.5.1.4, infinite/finite=infinite; finite/infinite=0; */
+ /* all other divisions that are not finite/finite return nan+i*nan. */
+ /* Division by 0 could be handled by the following case of division by */
+ /* a real; we handle it separately instead. */
+ if (mpc_zero_p (c))
+ return mpc_div_zero (a, b, c, rnd);
+ else if (mpc_inf_p (b) && mpc_fin_p (c))
+ return mpc_div_inf_fin (a, b, c);
+ else if (mpc_fin_p (b) && mpc_inf_p (c))
+ return mpc_div_fin_inf (a, b, c);
+ else if (!mpc_fin_p (b) || !mpc_fin_p (c)) {
+ mpc_set_nan (a);
+ return MPC_INEX (0, 0);
+ }
+ else if (mpfr_zero_p(mpc_imagref(c)))
+ return mpc_div_real (a, b, c, rnd);
+ else if (mpfr_zero_p(mpc_realref(c)))
+ return mpc_div_imag (a, b, c, rnd);
+
+ prec = MPC_MAX_PREC(a);
+
+ mpc_init2 (res, 2);
+ mpfr_init (q);
+
+ /* create the conjugate of c in c_conj without allocating new memory */
+ mpc_realref (c_conj)[0] = mpc_realref (c)[0];
+ mpc_imagref (c_conj)[0] = mpc_imagref (c)[0];
+ MPFR_CHANGE_SIGN (mpc_imagref (c_conj));
+
+ /* save the underflow or overflow flags from MPFR */
+ saved_underflow = mpfr_underflow_p ();
+ saved_overflow = mpfr_overflow_p ();
+
+ do {
+ loops ++;
+ prec += loops <= 2 ? mpc_ceil_log2 (prec) + 5 : prec / 2;
+
+ mpc_set_prec (res, prec);
+ mpfr_set_prec (q, prec);
+
+ /* first compute norm(c) */
+ mpfr_clear_underflow ();
+ mpfr_clear_overflow ();
+ inexact_norm = mpc_norm (q, c, GMP_RNDU);
+ underflow_norm = mpfr_underflow_p ();
+ overflow_norm = mpfr_overflow_p ();
+ if (underflow_norm)
+ mpfr_set_ui (q, 0ul, GMP_RNDN);
+ /* to obtain divisions by 0 later on */
+
+ /* now compute b*conjugate(c) */
+ mpfr_clear_underflow ();
+ mpfr_clear_overflow ();
+ inexact_prod = mpc_mul (res, b, c_conj, MPC_RNDZZ);
+ inexact_re = MPC_INEX_RE (inexact_prod);
+ inexact_im = MPC_INEX_IM (inexact_prod);
+ underflow_prod = mpfr_underflow_p ();
+ overflow_prod = mpfr_overflow_p ();
+ /* unfortunately, does not distinguish between under-/overflow
+ in real or imaginary parts
+ hopefully, the side-effects of mpc_mul do indeed raise the
+ mpfr exceptions */
+ if (overflow_prod) {
+ int isinf = 0;
+ tmpsgn = mpfr_sgn (mpc_realref(res));
+ if (tmpsgn > 0)
+ {
+ mpfr_nextabove (mpc_realref(res));
+ isinf = mpfr_inf_p (mpc_realref(res));
+ mpfr_nextbelow (mpc_realref(res));
+ }
+ else if (tmpsgn < 0)
+ {
+ mpfr_nextbelow (mpc_realref(res));
+ isinf = mpfr_inf_p (mpc_realref(res));
+ mpfr_nextabove (mpc_realref(res));
+ }
+ if (isinf)
+ {
+ mpfr_set_inf (mpc_realref(res), tmpsgn);
+ overflow_re = 1;
+ }
+ tmpsgn = mpfr_sgn (mpc_imagref(res));
+ isinf = 0;
+ if (tmpsgn > 0)
+ {
+ mpfr_nextabove (mpc_imagref(res));
+ isinf = mpfr_inf_p (mpc_imagref(res));
+ mpfr_nextbelow (mpc_imagref(res));
+ }
+ else if (tmpsgn < 0)
+ {
+ mpfr_nextbelow (mpc_imagref(res));
+ isinf = mpfr_inf_p (mpc_imagref(res));
+ mpfr_nextabove (mpc_imagref(res));
+ }
+ if (isinf)
+ {
+ mpfr_set_inf (mpc_imagref(res), tmpsgn);
+ overflow_im = 1;
+ }
+ mpc_set (a, res, rnd);
+ goto end;
+ }
+
+ /* divide the product by the norm */
+ if (inexact_norm == 0 && (inexact_re == 0 || inexact_im == 0)) {
+ /* The division has good chances to be exact in at least one part. */
+ /* Since this can cause problems when not rounding to the nearest, */
+ /* we use the division code of mpfr, which handles the situation. */
+ mpfr_clear_underflow ();
+ mpfr_clear_overflow ();
+ inexact_re |= mpfr_div (mpc_realref (res), mpc_realref (res), q, GMP_RNDZ);
+ underflow_re = mpfr_underflow_p ();
+ overflow_re = mpfr_overflow_p ();
+ ok_re = !inexact_re || underflow_re || overflow_re
+ || mpfr_can_round (mpc_realref (res), prec - 4, GMP_RNDN,
+ GMP_RNDZ, MPC_PREC_RE(a) + (rnd_re == GMP_RNDN));
+
+ if (ok_re) /* compute imaginary part */ {
+ mpfr_clear_underflow ();
+ mpfr_clear_overflow ();
+ inexact_im |= mpfr_div (mpc_imagref (res), mpc_imagref (res), q, GMP_RNDZ);
+ underflow_im = mpfr_underflow_p ();
+ overflow_im = mpfr_overflow_p ();
+ ok_im = !inexact_im || underflow_im || overflow_im
+ || mpfr_can_round (mpc_imagref (res), prec - 4, GMP_RNDN,
+ GMP_RNDZ, MPC_PREC_IM(a) + (rnd_im == GMP_RNDN));
+ }
+ }
+ else {
+ /* The division is inexact, so for efficiency reasons we invert q */
+ /* only once and multiply by the inverse. */
+ if (mpfr_ui_div (q, 1ul, q, GMP_RNDZ) || inexact_norm) {
+ /* if 1/q is inexact, the approximations of the real and
+ imaginary part below will be inexact, unless RE(res)
+ or IM(res) is zero */
+ inexact_re |= ~mpfr_zero_p (mpc_realref (res));
+ inexact_im |= ~mpfr_zero_p (mpc_imagref (res));
+ }
+ mpfr_clear_underflow ();
+ mpfr_clear_overflow ();
+ inexact_re |= mpfr_mul (mpc_realref (res), mpc_realref (res), q, GMP_RNDZ);
+ underflow_re = mpfr_underflow_p ();
+ overflow_re = mpfr_overflow_p ();
+ ok_re = !inexact_re || underflow_re || overflow_re
+ || mpfr_can_round (mpc_realref (res), prec - 4, GMP_RNDN,
+ GMP_RNDZ, MPC_PREC_RE(a) + (rnd_re == GMP_RNDN));
+
+ if (ok_re) /* compute imaginary part */ {
+ mpfr_clear_underflow ();
+ mpfr_clear_overflow ();
+ inexact_im |= mpfr_mul (mpc_imagref (res), mpc_imagref (res), q, GMP_RNDZ);
+ underflow_im = mpfr_underflow_p ();
+ overflow_im = mpfr_overflow_p ();
+ ok_im = !inexact_im || underflow_im || overflow_im
+ || mpfr_can_round (mpc_imagref (res), prec - 4, GMP_RNDN,
+ GMP_RNDZ, MPC_PREC_IM(a) + (rnd_im == GMP_RNDN));
+ }
+ }
+ } while ((!ok_re || !ok_im) && !underflow_norm && !overflow_norm
+ && !underflow_prod && !overflow_prod);
+
+ inex = mpc_set (a, res, rnd);
+ inexact_re = MPC_INEX_RE (inex);
+ inexact_im = MPC_INEX_IM (inex);
+
+ end:
+ /* fix values and inexact flags in case of overflow/underflow */
+ /* FIXME: heuristic, certainly does not cover all cases */
+ if (overflow_re || (underflow_norm && !underflow_prod)) {
+ mpfr_set_inf (mpc_realref (a), mpfr_sgn (mpc_realref (res)));
+ inexact_re = mpfr_sgn (mpc_realref (res));
+ }
+ else if (underflow_re || (overflow_norm && !overflow_prod)) {
+ inexact_re = mpfr_signbit (mpc_realref (res)) ? 1 : -1;
+ mpfr_set_zero (mpc_realref (a), -inexact_re);
+ }
+ if (overflow_im || (underflow_norm && !underflow_prod)) {
+ mpfr_set_inf (mpc_imagref (a), mpfr_sgn (mpc_imagref (res)));
+ inexact_im = mpfr_sgn (mpc_imagref (res));
+ }
+ else if (underflow_im || (overflow_norm && !overflow_prod)) {
+ inexact_im = mpfr_signbit (mpc_imagref (res)) ? 1 : -1;
+ mpfr_set_zero (mpc_imagref (a), -inexact_im);
+ }
+
+ mpc_clear (res);
+ mpfr_clear (q);
+
+ /* restore underflow and overflow flags from MPFR */
+ if (saved_underflow)
+ mpfr_set_underflow ();
+ if (saved_overflow)
+ mpfr_set_overflow ();
+
+ return MPC_INEX (inexact_re, inexact_im);
+}
diff --git a/mpc/src/div_2si.c b/mpc/src/div_2si.c
new file mode 100644
index 0000000000..511f2cb52f
--- /dev/null
+++ b/mpc/src/div_2si.c
@@ -0,0 +1,32 @@
+/* mpc_div_2si -- Divide a complex number by 2^e.
+
+Copyright (C) 2012 INRIA
+
+This file is part of GNU MPC.
+
+GNU MPC is free software; you can redistribute it and/or modify it under
+the terms of the GNU Lesser General Public License as published by the
+Free Software Foundation; either version 3 of the License, or (at your
+option) any later version.
+
+GNU MPC 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 Lesser General Public License for
+more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+
+#include "mpc-impl.h"
+
+int
+mpc_div_2si (mpc_ptr a, mpc_srcptr b, long int c, mpc_rnd_t rnd)
+{
+ int inex_re, inex_im;
+
+ inex_re = mpfr_div_2si (mpc_realref(a), mpc_realref(b), c, MPC_RND_RE(rnd));
+ inex_im = mpfr_div_2si (mpc_imagref(a), mpc_imagref(b), c, MPC_RND_IM(rnd));
+
+ return MPC_INEX(inex_re, inex_im);
+}
diff --git a/mpc/src/div_2ui.c b/mpc/src/div_2ui.c
new file mode 100644
index 0000000000..cd53855cf6
--- /dev/null
+++ b/mpc/src/div_2ui.c
@@ -0,0 +1,32 @@
+/* mpc_div_2ui -- Divide a complex number by 2^e.
+
+Copyright (C) 2002, 2009, 2011, 2012 INRIA
+
+This file is part of GNU MPC.
+
+GNU MPC is free software; you can redistribute it and/or modify it under
+the terms of the GNU Lesser General Public License as published by the
+Free Software Foundation; either version 3 of the License, or (at your
+option) any later version.
+
+GNU MPC 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 Lesser General Public License for
+more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+
+#include "mpc-impl.h"
+
+int
+mpc_div_2ui (mpc_ptr a, mpc_srcptr b, unsigned long int c, mpc_rnd_t rnd)
+{
+ int inex_re, inex_im;
+
+ inex_re = mpfr_div_2ui (mpc_realref(a), mpc_realref(b), c, MPC_RND_RE(rnd));
+ inex_im = mpfr_div_2ui (mpc_imagref(a), mpc_imagref(b), c, MPC_RND_IM(rnd));
+
+ return MPC_INEX(inex_re, inex_im);
+}
diff --git a/mpc/src/div_fr.c b/mpc/src/div_fr.c
new file mode 100644
index 0000000000..d5ea24030f
--- /dev/null
+++ b/mpc/src/div_fr.c
@@ -0,0 +1,39 @@
+/* mpc_div_fr -- Divide a complex number by a floating-point number.
+
+Copyright (C) 2002, 2008, 2009, 2010, 2011 INRIA
+
+This file is part of GNU MPC.
+
+GNU MPC is free software; you can redistribute it and/or modify it under
+the terms of the GNU Lesser General Public License as published by the
+Free Software Foundation; either version 3 of the License, or (at your
+option) any later version.
+
+GNU MPC 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 Lesser General Public License for
+more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+
+#include "mpc-impl.h"
+
+int
+mpc_div_fr (mpc_ptr a, mpc_srcptr b, mpfr_srcptr c, mpc_rnd_t rnd)
+{
+ int inex_re, inex_im;
+ mpfr_t real;
+
+ /* We have to use temporary variable in case c=mpc_realref (a). */
+ mpfr_init2 (real, MPC_PREC_RE (a));
+
+ inex_re = mpfr_div (real, mpc_realref(b), c, MPC_RND_RE(rnd));
+ inex_im = mpfr_div (mpc_imagref(a), mpc_imagref(b), c, MPC_RND_IM(rnd));
+ mpfr_set (mpc_realref (a), real, GMP_RNDN);
+
+ mpfr_clear (real);
+
+ return MPC_INEX(inex_re, inex_im);
+}
diff --git a/mpc/src/div_ui.c b/mpc/src/div_ui.c
new file mode 100644
index 0000000000..26debf7dfe
--- /dev/null
+++ b/mpc/src/div_ui.c
@@ -0,0 +1,32 @@
+/* mpc_div_ui -- Divide a complex number by a nonnegative integer.
+
+Copyright (C) 2002, 2009, 2011 INRIA
+
+This file is part of GNU MPC.
+
+GNU MPC is free software; you can redistribute it and/or modify it under
+the terms of the GNU Lesser General Public License as published by the
+Free Software Foundation; either version 3 of the License, or (at your
+option) any later version.
+
+GNU MPC 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 Lesser General Public License for
+more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+
+#include "mpc-impl.h"
+
+int
+mpc_div_ui (mpc_ptr a, mpc_srcptr b, unsigned long int c, mpc_rnd_t rnd)
+{
+ int inex_re, inex_im;
+
+ inex_re = mpfr_div_ui (mpc_realref(a), mpc_realref(b), c, MPC_RND_RE(rnd));
+ inex_im = mpfr_div_ui (mpc_imagref(a), mpc_imagref(b), c, MPC_RND_IM(rnd));
+
+ return MPC_INEX(inex_re, inex_im);
+}
diff --git a/mpc/src/exp.c b/mpc/src/exp.c
new file mode 100644
index 0000000000..36462251c1
--- /dev/null
+++ b/mpc/src/exp.c
@@ -0,0 +1,202 @@
+/* mpc_exp -- exponential of a complex number.
+
+Copyright (C) 2002, 2009, 2010, 2011 INRIA
+
+This file is part of GNU MPC.
+
+GNU MPC is free software; you can redistribute it and/or modify it under
+the terms of the GNU Lesser General Public License as published by the
+Free Software Foundation; either version 3 of the License, or (at your
+option) any later version.
+
+GNU MPC 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 Lesser General Public License for
+more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+
+#include "mpc-impl.h"
+
+int
+mpc_exp (mpc_ptr rop, mpc_srcptr op, mpc_rnd_t rnd)
+{
+ mpfr_t x, y, z;
+ mpfr_prec_t prec;
+ int ok = 0;
+ int inex_re, inex_im;
+ int saved_underflow, saved_overflow;
+
+ /* special values */
+ if (mpfr_nan_p (mpc_realref (op)) || mpfr_nan_p (mpc_imagref (op)))
+ /* NaNs
+ exp(nan +i*y) = nan -i*0 if y = -0,
+ nan +i*0 if y = +0,
+ nan +i*nan otherwise
+ exp(x+i*nan) = +/-0 +/-i*0 if x=-inf,
+ +/-inf +i*nan if x=+inf,
+ nan +i*nan otherwise */
+ {
+ if (mpfr_zero_p (mpc_imagref (op)))
+ return mpc_set (rop, op, MPC_RNDNN);
+
+ if (mpfr_inf_p (mpc_realref (op)))
+ {
+ if (mpfr_signbit (mpc_realref (op)))
+ return mpc_set_ui_ui (rop, 0, 0, MPC_RNDNN);
+ else
+ {
+ mpfr_set_inf (mpc_realref (rop), +1);
+ mpfr_set_nan (mpc_imagref (rop));
+ return MPC_INEX(0, 0); /* Inf/NaN are exact */
+ }
+ }
+ mpfr_set_nan (mpc_realref (rop));
+ mpfr_set_nan (mpc_imagref (rop));
+ return MPC_INEX(0, 0); /* NaN is exact */
+ }
+
+
+ if (mpfr_zero_p (mpc_imagref(op)))
+ /* special case when the input is real
+ exp(x-i*0) = exp(x) -i*0, even if x is NaN
+ exp(x+i*0) = exp(x) +i*0, even if x is NaN */
+ {
+ inex_re = mpfr_exp (mpc_realref(rop), mpc_realref(op), MPC_RND_RE(rnd));
+ inex_im = mpfr_set (mpc_imagref(rop), mpc_imagref(op), MPC_RND_IM(rnd));
+ return MPC_INEX(inex_re, inex_im);
+ }
+
+ if (mpfr_zero_p (mpc_realref (op)))
+ /* special case when the input is imaginary */
+ {
+ inex_re = mpfr_cos (mpc_realref (rop), mpc_imagref (op), MPC_RND_RE(rnd));
+ inex_im = mpfr_sin (mpc_imagref (rop), mpc_imagref (op), MPC_RND_IM(rnd));
+ return MPC_INEX(inex_re, inex_im);
+ }
+
+
+ if (mpfr_inf_p (mpc_realref (op)))
+ /* real part is an infinity,
+ exp(-inf +i*y) = 0*(cos y +i*sin y)
+ exp(+inf +i*y) = +/-inf +i*nan if y = +/-inf
+ +inf*(cos y +i*sin y) if 0 < |y| < inf */
+ {
+ mpfr_t n;
+
+ mpfr_init2 (n, 2);
+ if (mpfr_signbit (mpc_realref (op)))
+ mpfr_set_ui (n, 0, GMP_RNDN);
+ else
+ mpfr_set_inf (n, +1);
+
+ if (mpfr_inf_p (mpc_imagref (op)))
+ {
+ inex_re = mpfr_set (mpc_realref (rop), n, GMP_RNDN);
+ if (mpfr_signbit (mpc_realref (op)))
+ inex_im = mpfr_set (mpc_imagref (rop), n, GMP_RNDN);
+ else
+ {
+ mpfr_set_nan (mpc_imagref (rop));
+ inex_im = 0; /* NaN is exact */
+ }
+ }
+ else
+ {
+ mpfr_t c, s;
+ mpfr_init2 (c, 2);
+ mpfr_init2 (s, 2);
+
+ mpfr_sin_cos (s, c, mpc_imagref (op), GMP_RNDN);
+ inex_re = mpfr_copysign (mpc_realref (rop), n, c, GMP_RNDN);
+ inex_im = mpfr_copysign (mpc_imagref (rop), n, s, GMP_RNDN);
+
+ mpfr_clear (s);
+ mpfr_clear (c);
+ }
+
+ mpfr_clear (n);
+ return MPC_INEX(inex_re, inex_im);
+ }
+
+ if (mpfr_inf_p (mpc_imagref (op)))
+ /* real part is finite non-zero number, imaginary part is an infinity */
+ {
+ mpfr_set_nan (mpc_realref (rop));
+ mpfr_set_nan (mpc_imagref (rop));
+ return MPC_INEX(0, 0); /* NaN is exact */
+ }
+
+
+ /* from now on, both parts of op are regular numbers */
+
+ prec = MPC_MAX_PREC(rop)
+ + MPC_MAX (MPC_MAX (-mpfr_get_exp (mpc_realref (op)), 0),
+ -mpfr_get_exp (mpc_imagref (op)));
+ /* When op is close to 0, then exp is close to 1+Re(op), while
+ cos is close to 1-Im(op); to decide on the ternary value of exp*cos,
+ we need a high enough precision so that none of exp or cos is
+ computed as 1. */
+ mpfr_init2 (x, 2);
+ mpfr_init2 (y, 2);
+ mpfr_init2 (z, 2);
+
+ /* save the underflow or overflow flags from MPFR */
+ saved_underflow = mpfr_underflow_p ();
+ saved_overflow = mpfr_overflow_p ();
+
+ do
+ {
+ prec += mpc_ceil_log2 (prec) + 5;
+
+ mpfr_set_prec (x, prec);
+ mpfr_set_prec (y, prec);
+ mpfr_set_prec (z, prec);
+
+ /* FIXME: x may overflow so x.y does overflow too, while Re(exp(op))
+ could be represented in the precision of rop. */
+ mpfr_clear_overflow ();
+ mpfr_clear_underflow ();
+ mpfr_exp (x, mpc_realref(op), GMP_RNDN); /* error <= 0.5ulp */
+ mpfr_sin_cos (z, y, mpc_imagref(op), GMP_RNDN); /* errors <= 0.5ulp */
+ mpfr_mul (y, y, x, GMP_RNDN); /* error <= 2ulp */
+ ok = mpfr_overflow_p () || mpfr_zero_p (x)
+ || mpfr_can_round (y, prec - 2, GMP_RNDN, GMP_RNDZ,
+ MPC_PREC_RE(rop) + (MPC_RND_RE(rnd) == GMP_RNDN));
+ if (ok) /* compute imaginary part */
+ {
+ mpfr_mul (z, z, x, GMP_RNDN);
+ ok = mpfr_overflow_p () || mpfr_zero_p (x)
+ || mpfr_can_round (z, prec - 2, GMP_RNDN, GMP_RNDZ,
+ MPC_PREC_IM(rop) + (MPC_RND_IM(rnd) == GMP_RNDN));
+ }
+ }
+ while (ok == 0);
+
+ inex_re = mpfr_set (mpc_realref(rop), y, MPC_RND_RE(rnd));
+ inex_im = mpfr_set (mpc_imagref(rop), z, MPC_RND_IM(rnd));
+ if (mpfr_overflow_p ()) {
+ /* overflow in real exponential, inex is sign of infinite result */
+ inex_re = mpfr_sgn (y);
+ inex_im = mpfr_sgn (z);
+ }
+ else if (mpfr_underflow_p ()) {
+ /* underflow in real exponential, inex is opposite of sign of 0 result */
+ inex_re = (mpfr_signbit (y) ? +1 : -1);
+ inex_im = (mpfr_signbit (z) ? +1 : -1);
+ }
+
+ mpfr_clear (x);
+ mpfr_clear (y);
+ mpfr_clear (z);
+
+ /* restore underflow and overflow flags from MPFR */
+ if (saved_underflow)
+ mpfr_set_underflow ();
+ if (saved_overflow)
+ mpfr_set_overflow ();
+
+ return MPC_INEX(inex_re, inex_im);
+}
diff --git a/mpc/src/fma.c b/mpc/src/fma.c
new file mode 100644
index 0000000000..7f5cd31b8a
--- /dev/null
+++ b/mpc/src/fma.c
@@ -0,0 +1,191 @@
+/* mpc_fma -- Fused multiply-add of three complex numbers
+
+Copyright (C) 2011, 2012 INRIA
+
+This file is part of GNU MPC.
+
+GNU MPC is free software; you can redistribute it and/or modify it under
+the terms of the GNU Lesser General Public License as published by the
+Free Software Foundation; either version 3 of the License, or (at your
+option) any later version.
+
+GNU MPC 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 Lesser General Public License for
+more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+
+#include "mpc-impl.h"
+
+/* return a bound on the precision needed to add or subtract x and y exactly */
+static mpfr_prec_t
+bound_prec_addsub (mpfr_srcptr x, mpfr_srcptr y)
+{
+ if (!mpfr_regular_p (x))
+ return mpfr_get_prec (y);
+ else if (!mpfr_regular_p (y))
+ return mpfr_get_prec (x);
+ else /* neither x nor y are NaN, Inf or zero */
+ {
+ mpfr_exp_t ex = mpfr_get_exp (x);
+ mpfr_exp_t ey = mpfr_get_exp (y);
+ mpfr_exp_t ulpx = ex - mpfr_get_prec (x);
+ mpfr_exp_t ulpy = ey - mpfr_get_prec (y);
+ return ((ex >= ey) ? ex : ey) + 1 - ((ulpx <= ulpy) ? ulpx : ulpy);
+ }
+}
+
+/* r <- a*b+c */
+int
+mpc_fma_naive (mpc_ptr r, mpc_srcptr a, mpc_srcptr b, mpc_srcptr c, mpc_rnd_t rnd)
+{
+ mpfr_t rea_reb, rea_imb, ima_reb, ima_imb, tmp;
+ mpfr_prec_t pre12, pre13, pre23, pim12, pim13, pim23;
+ int inex_re, inex_im;
+
+ mpfr_init2 (rea_reb, mpfr_get_prec (mpc_realref(a)) + mpfr_get_prec (mpc_realref(b)));
+ mpfr_init2 (rea_imb, mpfr_get_prec (mpc_realref(a)) + mpfr_get_prec (mpc_imagref(b)));
+ mpfr_init2 (ima_reb, mpfr_get_prec (mpc_imagref(a)) + mpfr_get_prec (mpc_realref(b)));
+ mpfr_init2 (ima_imb, mpfr_get_prec (mpc_imagref(a)) + mpfr_get_prec (mpc_imagref(b)));
+
+ mpfr_mul (rea_reb, mpc_realref(a), mpc_realref(b), GMP_RNDZ); /* exact */
+ mpfr_mul (rea_imb, mpc_realref(a), mpc_imagref(b), GMP_RNDZ); /* exact */
+ mpfr_mul (ima_reb, mpc_imagref(a), mpc_realref(b), GMP_RNDZ); /* exact */
+ mpfr_mul (ima_imb, mpc_imagref(a), mpc_imagref(b), GMP_RNDZ); /* exact */
+
+ /* Re(r) <- rea_reb - ima_imb + Re(c) */
+
+ pre12 = bound_prec_addsub (rea_reb, ima_imb); /* bound on exact precision for
+ rea_reb - ima_imb */
+ pre13 = bound_prec_addsub (rea_reb, mpc_realref(c));
+ /* bound for rea_reb + Re(c) */
+ pre23 = bound_prec_addsub (ima_imb, mpc_realref(c));
+ /* bound for ima_imb - Re(c) */
+ if (pre12 <= pre13 && pre12 <= pre23) /* (rea_reb - ima_imb) + Re(c) */
+ {
+ mpfr_init2 (tmp, pre12);
+ mpfr_sub (tmp, rea_reb, ima_imb, GMP_RNDZ); /* exact */
+ inex_re = mpfr_add (mpc_realref(r), tmp, mpc_realref(c), MPC_RND_RE(rnd));
+ /* the only possible bad overlap is between r and c, but since we are
+ only touching the real part of both, it is ok */
+ }
+ else if (pre13 <= pre23) /* (rea_reb + Re(c)) - ima_imb */
+ {
+ mpfr_init2 (tmp, pre13);
+ mpfr_add (tmp, rea_reb, mpc_realref(c), GMP_RNDZ); /* exact */
+ inex_re = mpfr_sub (mpc_realref(r), tmp, ima_imb, MPC_RND_RE(rnd));
+ /* the only possible bad overlap is between r and c, but since we are
+ only touching the real part of both, it is ok */
+ }
+ else /* rea_reb + (Re(c) - ima_imb) */
+ {
+ mpfr_init2 (tmp, pre23);
+ mpfr_sub (tmp, mpc_realref(c), ima_imb, GMP_RNDZ); /* exact */
+ inex_re = mpfr_add (mpc_realref(r), tmp, rea_reb, MPC_RND_RE(rnd));
+ /* the only possible bad overlap is between r and c, but since we are
+ only touching the real part of both, it is ok */
+ }
+
+ /* Im(r) <- rea_imb + ima_reb + Im(c) */
+ pim12 = bound_prec_addsub (rea_imb, ima_reb); /* bound on exact precision for
+ rea_imb + ima_reb */
+ pim13 = bound_prec_addsub (rea_imb, mpc_imagref(c));
+ /* bound for rea_imb + Im(c) */
+ pim23 = bound_prec_addsub (ima_reb, mpc_imagref(c));
+ /* bound for ima_reb + Im(c) */
+ if (pim12 <= pim13 && pim12 <= pim23) /* (rea_imb + ima_reb) + Im(c) */
+ {
+ mpfr_set_prec (tmp, pim12);
+ mpfr_add (tmp, rea_imb, ima_reb, GMP_RNDZ); /* exact */
+ inex_im = mpfr_add (mpc_imagref(r), tmp, mpc_imagref(c), MPC_RND_IM(rnd));
+ /* the only possible bad overlap is between r and c, but since we are
+ only touching the imaginary part of both, it is ok */
+ }
+ else if (pim13 <= pim23) /* (rea_imb + Im(c)) + ima_reb */
+ {
+ mpfr_set_prec (tmp, pim13);
+ mpfr_add (tmp, rea_imb, mpc_imagref(c), GMP_RNDZ); /* exact */
+ inex_im = mpfr_add (mpc_imagref(r), tmp, ima_reb, MPC_RND_IM(rnd));
+ /* the only possible bad overlap is between r and c, but since we are
+ only touching the imaginary part of both, it is ok */
+ }
+ else /* rea_imb + (Im(c) + ima_reb) */
+ {
+ mpfr_set_prec (tmp, pre23);
+ mpfr_add (tmp, mpc_imagref(c), ima_reb, GMP_RNDZ); /* exact */
+ inex_im = mpfr_add (mpc_imagref(r), tmp, rea_imb, MPC_RND_IM(rnd));
+ /* the only possible bad overlap is between r and c, but since we are
+ only touching the imaginary part of both, it is ok */
+ }
+
+ mpfr_clear (rea_reb);
+ mpfr_clear (rea_imb);
+ mpfr_clear (ima_reb);
+ mpfr_clear (ima_imb);
+ mpfr_clear (tmp);
+
+ return MPC_INEX(inex_re, inex_im);
+}
+
+/* The algorithm is as follows:
+ - in a first pass, we use the target precision + some extra bits
+ - if it fails, we add the number of cancelled bits when adding
+ Re(a*b) and Re(c) [similarly for the imaginary part]
+ - it is fails again, we call the mpc_fma_naive function, which also
+ deals with the special cases */
+int
+mpc_fma (mpc_ptr r, mpc_srcptr a, mpc_srcptr b, mpc_srcptr c, mpc_rnd_t rnd)
+{
+ mpc_t ab;
+ mpfr_prec_t pre, pim, wpre, wpim;
+ mpfr_exp_t diffre, diffim;
+ int i, inex = 0, okre = 0, okim = 0;
+
+ if (mpc_fin_p (a) == 0 || mpc_fin_p (b) == 0 || mpc_fin_p (c) == 0)
+ return mpc_fma_naive (r, a, b, c, rnd);
+
+ pre = mpfr_get_prec (mpc_realref(r));
+ pim = mpfr_get_prec (mpc_imagref(r));
+ wpre = pre + mpc_ceil_log2 (pre) + 10;
+ wpim = pim + mpc_ceil_log2 (pim) + 10;
+ mpc_init3 (ab, wpre, wpim);
+ for (i = 0; i < 2; ++i)
+ {
+ mpc_mul (ab, a, b, MPC_RNDZZ);
+ if (mpfr_zero_p (mpc_realref(ab)) || mpfr_zero_p (mpc_imagref(ab)))
+ break;
+ diffre = mpfr_get_exp (mpc_realref(ab));
+ diffim = mpfr_get_exp (mpc_imagref(ab));
+ mpc_add (ab, ab, c, MPC_RNDZZ);
+ if (mpfr_zero_p (mpc_realref(ab)) || mpfr_zero_p (mpc_imagref(ab)))
+ break;
+ diffre -= mpfr_get_exp (mpc_realref(ab));
+ diffim -= mpfr_get_exp (mpc_imagref(ab));
+ diffre = (diffre > 0 ? diffre + 1 : 1);
+ diffim = (diffim > 0 ? diffim + 1 : 1);
+ okre = diffre > (mpfr_exp_t) wpre ? 0 : mpfr_can_round (mpc_realref(ab),
+ wpre - diffre, GMP_RNDN, GMP_RNDZ,
+ pre + (MPC_RND_RE (rnd) == GMP_RNDN));
+ okim = diffim > (mpfr_exp_t) wpim ? 0 : mpfr_can_round (mpc_imagref(ab),
+ wpim - diffim, GMP_RNDN, GMP_RNDZ,
+ pim + (MPC_RND_IM (rnd) == GMP_RNDN));
+ if (okre && okim)
+ {
+ inex = mpc_set (r, ab, rnd);
+ break;
+ }
+ if (i == 1)
+ break;
+ if (okre == 0 && diffre > 1)
+ wpre += diffre;
+ if (okim == 0 && diffim > 1)
+ wpim += diffim;
+ mpfr_set_prec (mpc_realref(ab), wpre);
+ mpfr_set_prec (mpc_imagref(ab), wpim);
+ }
+ mpc_clear (ab);
+ return okre && okim ? inex : mpc_fma_naive (r, a, b, c, rnd);
+}
diff --git a/mpc/src/fr_div.c b/mpc/src/fr_div.c
new file mode 100644
index 0000000000..e57eced1f8
--- /dev/null
+++ b/mpc/src/fr_div.c
@@ -0,0 +1,39 @@
+/* mpc_fr_div -- Divide a floating-point number by a complex number.
+
+Copyright (C) 2008, 2009, 2011 INRIA
+
+This file is part of GNU MPC.
+
+GNU MPC is free software; you can redistribute it and/or modify it under
+the terms of the GNU Lesser General Public License as published by the
+Free Software Foundation; either version 3 of the License, or (at your
+option) any later version.
+
+GNU MPC 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 Lesser General Public License for
+more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+
+#include "mpc-impl.h"
+
+int
+mpc_fr_div (mpc_ptr a, mpfr_srcptr b, mpc_srcptr c, mpc_rnd_t rnd)
+{
+ mpc_t bc;
+ int inexact;
+
+ mpc_realref (bc)[0] = b [0];
+ mpfr_init (mpc_imagref (bc));
+ /* we consider the operand b to have imaginary part +0 */
+ mpfr_set_ui (mpc_imagref (bc), 0, GMP_RNDN);
+
+ inexact = mpc_div (a, bc, c, rnd);
+
+ mpfr_clear (mpc_imagref (bc));
+
+ return inexact;
+}
diff --git a/mpc/src/fr_sub.c b/mpc/src/fr_sub.c
new file mode 100644
index 0000000000..91338a4fd6
--- /dev/null
+++ b/mpc/src/fr_sub.c
@@ -0,0 +1,33 @@
+/* mpc_fr_sub -- Substract a complex number from a floating-point number.
+
+Copyright (C) 2008, 2009, 2011, 2012 INRIA
+
+This file is part of GNU MPC.
+
+GNU MPC is free software; you can redistribute it and/or modify it under
+the terms of the GNU Lesser General Public License as published by the
+Free Software Foundation; either version 3 of the License, or (at your
+option) any later version.
+
+GNU MPC 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 Lesser General Public License for
+more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+
+#include "mpc-impl.h"
+
+/* return 0 iff both the real and imaginary parts are exact */
+int
+mpc_fr_sub (mpc_ptr a, mpfr_srcptr b, mpc_srcptr c, mpc_rnd_t rnd)
+{
+ int inex_re, inex_im;
+
+ inex_re = mpfr_sub (mpc_realref (a), b, mpc_realref (c), MPC_RND_RE (rnd));
+ inex_im = mpfr_neg (mpc_imagref (a), mpc_imagref (c), MPC_RND_IM (rnd));
+
+ return MPC_INEX(inex_re, inex_im);
+}
diff --git a/mpc/src/get_prec.c b/mpc/src/get_prec.c
new file mode 100644
index 0000000000..f1fe856c3e
--- /dev/null
+++ b/mpc/src/get_prec.c
@@ -0,0 +1,28 @@
+/* mpc_get_prec -- returns the common precision of real and imaginary part, or 0 if they differ
+
+Copyright (C) 2007, 2009, 2010 INRIA
+
+This file is part of GNU MPC.
+
+GNU MPC is free software; you can redistribute it and/or modify it under
+the terms of the GNU Lesser General Public License as published by the
+Free Software Foundation; either version 3 of the License, or (at your
+option) any later version.
+
+GNU MPC 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 Lesser General Public License for
+more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+
+#include "mpc-impl.h"
+
+mpfr_prec_t
+mpc_get_prec (mpc_srcptr x)
+{
+ mpfr_prec_t precre = MPC_PREC_RE (x);
+ return (MPC_PREC_IM (x) == precre ? precre : 0);
+}
diff --git a/mpc/src/get_prec2.c b/mpc/src/get_prec2.c
new file mode 100644
index 0000000000..79015c8392
--- /dev/null
+++ b/mpc/src/get_prec2.c
@@ -0,0 +1,29 @@
+/* mpc_get_prec2 -- returns the precisions of the real and of the imaginary
+ part through the first two arguments
+
+Copyright (C) 2007, 2009, 2010 INRIA
+
+This file is part of GNU MPC.
+
+GNU MPC is free software; you can redistribute it and/or modify it under
+the terms of the GNU Lesser General Public License as published by the
+Free Software Foundation; either version 3 of the License, or (at your
+option) any later version.
+
+GNU MPC 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 Lesser General Public License for
+more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+
+#include "mpc-impl.h"
+
+void
+mpc_get_prec2 (mpfr_prec_t *pr, mpfr_prec_t *pi, mpc_srcptr x)
+{
+ *pr = MPC_PREC_RE (x);
+ *pi = MPC_PREC_IM (x);
+}
diff --git a/mpc/src/get_version.c b/mpc/src/get_version.c
new file mode 100644
index 0000000000..88e7e986a9
--- /dev/null
+++ b/mpc/src/get_version.c
@@ -0,0 +1,49 @@
+/* mpc_get_version -- MPC version
+
+Copyright (C) 2008, 2009, 2010, 2011, 2012, 2014, 2015 INRIA
+
+This file is part of GNU MPC.
+
+GNU MPC is free software; you can redistribute it and/or modify it under
+the terms of the GNU Lesser General Public License as published by the
+Free Software Foundation; either version 3 of the License, or (at your
+option) any later version.
+
+GNU MPC 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 Lesser General Public License for
+more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+
+#include "mpc-impl.h"
+
+#if MPFR_VERSION_MAJOR < 3
+/* The following are functions defined for compatibility with mpfr < 3;
+ logically, they should be defined in a separate file, but then gcc
+ complains about an empty translation unit with mpfr >= 3. */
+
+void
+mpfr_set_zero (mpfr_ptr z, int s)
+{
+ mpfr_set_ui (z, 0ul, GMP_RNDN);
+ if (s < 0)
+ mpfr_neg (z, z, GMP_RNDN);
+}
+
+int
+mpfr_regular_p (mpfr_srcptr z)
+{
+ return (mpfr_number_p (z) && !mpfr_zero_p (z));
+}
+#endif /* mpfr < 3 */
+
+
+const char *
+mpc_get_version (void)
+{
+ return "1.0.3";
+}
+
diff --git a/mpc/src/get_x.c b/mpc/src/get_x.c
new file mode 100644
index 0000000000..31610ac61d
--- /dev/null
+++ b/mpc/src/get_x.c
@@ -0,0 +1,236 @@
+/* mpc_get_dc, mpc_get_ldc -- Transform mpc number into C complex number
+ mpc_get_str -- Convert a complex number into a string.
+
+Copyright (C) 2009, 2010, 2011 INRIA
+
+This file is part of GNU MPC.
+
+GNU MPC is free software; you can redistribute it and/or modify it under
+the terms of the GNU Lesser General Public License as published by the
+Free Software Foundation; either version 3 of the License, or (at your
+option) any later version.
+
+GNU MPC 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 Lesser General Public License for
+more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+
+#include "config.h"
+
+#ifdef HAVE_COMPLEX_H
+#include <complex.h>
+#endif
+
+#ifdef HAVE_LOCALE_H
+#include <locale.h>
+#endif
+
+#include <stdio.h> /* for sprintf, fprintf */
+#include <ctype.h>
+#include <string.h>
+#include "mpc-impl.h"
+
+#ifdef HAVE_COMPLEX_H
+double _Complex
+mpc_get_dc (mpc_srcptr op, mpc_rnd_t rnd) {
+ return I * mpfr_get_d (mpc_imagref (op), MPC_RND_IM (rnd))
+ + mpfr_get_d (mpc_realref (op), MPC_RND_RE (rnd));
+}
+
+long double _Complex
+mpc_get_ldc (mpc_srcptr op, mpc_rnd_t rnd) {
+ return I * mpfr_get_ld (mpc_imagref (op), MPC_RND_IM (rnd))
+ + mpfr_get_ld (mpc_realref (op), MPC_RND_RE (rnd));
+}
+#endif
+
+
+/* Code for mpc_get_str. The output format is "(real imag)", the decimal point
+ of the locale is used. */
+
+/* mpfr_prec_t can be either int or long int */
+#if (__GMP_MP_SIZE_T_INT == 1)
+#define MPC_EXP_FORMAT_SPEC "i"
+#elif (__GMP_MP_SIZE_T_INT == 0)
+#define MPC_EXP_FORMAT_SPEC "li"
+#else
+#error "mpfr_exp_t size not supported"
+#endif
+
+static char *
+pretty_zero (mpfr_srcptr zero)
+{
+ char *pretty;
+
+ pretty = mpc_alloc_str (3);
+
+ pretty[0] = mpfr_signbit (zero) ? '-' : '+';
+ pretty[1] = '0';
+ pretty[2] = '\0';
+
+ return pretty;
+}
+
+static char *
+prettify (const char *str, const mp_exp_t expo, int base, int special)
+{
+ size_t sz;
+ char *pretty;
+ char *p;
+ const char *s;
+ mp_exp_t x;
+ int sign;
+
+ sz = strlen (str) + 1; /* + terminal '\0' */
+
+ if (special)
+ {
+ /* special number: nan or inf */
+ pretty = mpc_alloc_str (sz);
+ strcpy (pretty, str);
+
+ return pretty;
+ }
+
+ /* regular number */
+
+ sign = (str[0] == '-' || str[0] == '+');
+
+ x = expo - 1; /* expo is the exponent value with decimal point BEFORE
+ the first digit, we wants decimal point AFTER the first
+ digit */
+ if (base == 16)
+ x <<= 2; /* the output exponent is a binary exponent */
+
+ ++sz; /* + decimal point */
+
+ if (x != 0)
+ {
+ /* augment sz with the size needed for an exponent written in base
+ ten */
+ mp_exp_t xx;
+
+ sz += 3; /* + exponent char + sign + 1 digit */
+
+ if (x < 0)
+ {
+ /* avoid overflow when changing sign (assuming that, for the
+ mp_exp_t type, (max value) is greater than (- min value / 10)) */
+ if (x < -10)
+ {
+ xx = - (x / 10);
+ sz++;
+ }
+ else
+ xx = -x;
+ }
+ else
+ xx = x;
+
+ /* compute sz += floor(log(expo)/log(10)) without using libm
+ functions */
+ while (xx > 9)
+ {
+ sz++;
+ xx /= 10;
+ }
+ }
+
+ pretty = mpc_alloc_str (sz);
+ p = pretty;
+
+ /* 1. optional sign plus first digit */
+ s = str;
+ *p++ = *s++;
+ if (sign)
+ *p++ = *s++;
+
+ /* 2. decimal point */
+#ifdef HAVE_LOCALECONV
+ *p++ = *localeconv ()->decimal_point;
+#else
+ *p++ = '.';
+#endif
+ *p = '\0';
+
+ /* 3. other significant digits */
+ strcat (pretty, s);
+
+ /* 4. exponent (in base ten) */
+ if (x == 0)
+ return pretty;
+
+ p = pretty + strlen (str) + 1;
+
+ switch (base)
+ {
+ case 10:
+ *p++ = 'e';
+ break;
+ case 2:
+ case 16:
+ *p++ = 'p';
+ break;
+ default:
+ *p++ = '@';
+ }
+
+ *p = '\0';
+
+ sprintf (p, "%+"MPC_EXP_FORMAT_SPEC, x);
+
+ return pretty;
+}
+
+static char *
+get_pretty_str (const int base, const size_t n, mpfr_srcptr x, mpfr_rnd_t rnd)
+{
+ mp_exp_t expo;
+ char *ugly;
+ char *pretty;
+
+ if (mpfr_zero_p (x))
+ return pretty_zero (x);
+
+ ugly = mpfr_get_str (NULL, &expo, base, n, x, rnd);
+ MPC_ASSERT (ugly != NULL);
+ pretty = prettify (ugly, expo, base, !mpfr_number_p (x));
+ mpfr_free_str (ugly);
+
+ return pretty;
+}
+
+char *
+mpc_get_str (int base, size_t n, mpc_srcptr op, mpc_rnd_t rnd)
+{
+ size_t needed_size;
+ char *real_str;
+ char *imag_str;
+ char *complex_str = NULL;
+
+ if (base < 2 || base > 36)
+ return NULL;
+
+ real_str = get_pretty_str (base, n, mpc_realref (op), MPC_RND_RE (rnd));
+ imag_str = get_pretty_str (base, n, mpc_imagref (op), MPC_RND_IM (rnd));
+
+ needed_size = strlen (real_str) + strlen (imag_str) + 4;
+
+ complex_str = mpc_alloc_str (needed_size);
+MPC_ASSERT (complex_str != NULL);
+
+ strcpy (complex_str, "(");
+ strcat (complex_str, real_str);
+ strcat (complex_str, " ");
+ strcat (complex_str, imag_str);
+ strcat (complex_str, ")");
+
+ mpc_free_str (real_str);
+ mpc_free_str (imag_str);
+
+ return complex_str;
+}
diff --git a/mpc/src/imag.c b/mpc/src/imag.c
new file mode 100644
index 0000000000..5f3b3a5873
--- /dev/null
+++ b/mpc/src/imag.c
@@ -0,0 +1,27 @@
+/* mpc_imag -- Get the imaginary part of a complex number.
+
+Copyright (C) 2008, 2009, 2011 INRIA
+
+This file is part of GNU MPC.
+
+GNU MPC is free software; you can redistribute it and/or modify it under
+the terms of the GNU Lesser General Public License as published by the
+Free Software Foundation; either version 3 of the License, or (at your
+option) any later version.
+
+GNU MPC 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 Lesser General Public License for
+more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+
+#include "mpc-impl.h"
+
+int
+mpc_imag (mpfr_ptr a, mpc_srcptr b, mpfr_rnd_t rnd)
+{
+ return mpfr_set (a, mpc_imagref (b), rnd);
+}
diff --git a/mpc/src/init2.c b/mpc/src/init2.c
new file mode 100644
index 0000000000..ce4173e72e
--- /dev/null
+++ b/mpc/src/init2.c
@@ -0,0 +1,28 @@
+/* mpc_init2 -- Initialize a complex variable with a given precision.
+
+Copyright (C) 2002, 2009, 2011 INRIA
+
+This file is part of GNU MPC.
+
+GNU MPC is free software; you can redistribute it and/or modify it under
+the terms of the GNU Lesser General Public License as published by the
+Free Software Foundation; either version 3 of the License, or (at your
+option) any later version.
+
+GNU MPC 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 Lesser General Public License for
+more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+
+#include "mpc-impl.h"
+
+void
+mpc_init2 (mpc_t x, mpfr_prec_t prec)
+{
+ mpfr_init2 (mpc_realref(x), prec);
+ mpfr_init2 (mpc_imagref(x), prec);
+}
diff --git a/mpc/src/init3.c b/mpc/src/init3.c
new file mode 100644
index 0000000000..69f91b2580
--- /dev/null
+++ b/mpc/src/init3.c
@@ -0,0 +1,28 @@
+/* mpc_init3 -- Initialize a complex variable with given precisions.
+
+Copyright (C) 2002, 2009, 2011 INRIA
+
+This file is part of GNU MPC.
+
+GNU MPC is free software; you can redistribute it and/or modify it under
+the terms of the GNU Lesser General Public License as published by the
+Free Software Foundation; either version 3 of the License, or (at your
+option) any later version.
+
+GNU MPC 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 Lesser General Public License for
+more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+
+#include "mpc-impl.h"
+
+void
+mpc_init3 (mpc_t x, mpfr_prec_t prec_re, mpfr_prec_t prec_im)
+{
+ mpfr_init2 (mpc_realref(x), prec_re);
+ mpfr_init2 (mpc_imagref(x), prec_im);
+}
diff --git a/mpc/src/inp_str.c b/mpc/src/inp_str.c
new file mode 100644
index 0000000000..695a3adff6
--- /dev/null
+++ b/mpc/src/inp_str.c
@@ -0,0 +1,239 @@
+/* mpc_inp_str -- Input a complex number from a given stream.
+
+Copyright (C) 2009, 2010, 2011 INRIA
+
+This file is part of GNU MPC.
+
+GNU MPC is free software; you can redistribute it and/or modify it under
+the terms of the GNU Lesser General Public License as published by the
+Free Software Foundation; either version 3 of the License, or (at your
+option) any later version.
+
+GNU MPC 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 Lesser General Public License for
+more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+
+#include <stdio.h> /* for FILE */
+#include <ctype.h>
+#include <string.h>
+#include "mpc-impl.h"
+
+static size_t
+skip_whitespace (FILE *stream)
+{
+ int c = getc (stream);
+ size_t size = 0;
+ while (c != EOF && isspace ((unsigned char) c)) {
+ c = getc (stream);
+ size++;
+ }
+ if (c != EOF)
+ ungetc (c, stream);
+ return size;
+}
+
+/* Extract from stream the longest string made up of alphanumeric char and
+ '_' (i.e. n-char-sequence).
+ The user must free the returned string. */
+static char *
+extract_suffix (FILE *stream)
+{
+ int c;
+ size_t nread = 0;
+ size_t strsize = 100;
+ char *str = mpc_alloc_str (strsize);
+
+ c = getc (stream);
+ while (isalnum ((unsigned char) c) || c == '_') {
+ str [nread] = (char) c;
+ nread++;
+ if (nread == strsize) {
+ str = mpc_realloc_str (str, strsize, 2 * strsize);
+ strsize *= 2;
+ }
+ c = getc (stream);
+ }
+
+ str = mpc_realloc_str (str, strsize, nread + 1);
+ strsize = nread + 1;
+ str [nread] = '\0';
+
+ if (c != EOF)
+ ungetc (c, stream);
+ return str;
+}
+
+
+/* Extract from the stream the longest string of characters which are neither
+ whitespace nor brackets (except for an optional bracketed n-char_sequence
+ directly following nan or @nan@ independently of case).
+ The user must free the returned string. */
+static char *
+extract_string (FILE *stream)
+{
+ int c;
+ size_t nread = 0;
+ size_t strsize = 100;
+ char *str = mpc_alloc_str (strsize);
+ size_t lenstr;
+
+ c = getc (stream);
+ while (c != EOF && c != '\n'
+ && !isspace ((unsigned char) c)
+ && c != '(' && c != ')') {
+ str [nread] = (char) c;
+ nread++;
+ if (nread == strsize) {
+ str = mpc_realloc_str (str, strsize, 2 * strsize);
+ strsize *= 2;
+ }
+ c = getc (stream);
+ }
+
+ str = mpc_realloc_str (str, strsize, nread + 1);
+ strsize = nread + 1;
+ str [nread] = '\0';
+
+ if (nread == 0)
+ return str;
+
+ lenstr = nread;
+
+ if (c == '(') {
+ size_t n;
+ char *suffix;
+ int ret;
+
+ /* (n-char-sequence) only after a NaN */
+ if ((nread != 3
+ || tolower ((unsigned char) (str[0])) != 'n'
+ || tolower ((unsigned char) (str[1])) != 'a'
+ || tolower ((unsigned char) (str[2])) != 'n')
+ && (nread != 5
+ || str[0] != '@'
+ || tolower ((unsigned char) (str[1])) != 'n'
+ || tolower ((unsigned char) (str[2])) != 'a'
+ || tolower ((unsigned char) (str[3])) != 'n'
+ || str[4] != '@')) {
+ ungetc (c, stream);
+ return str;
+ }
+
+ suffix = extract_suffix (stream);
+ nread += strlen (suffix) + 1;
+ if (nread >= strsize) {
+ str = mpc_realloc_str (str, strsize, nread + 1);
+ strsize = nread + 1;
+ }
+
+ /* Warning: the sprintf does not allow overlap between arguments. */
+ ret = sprintf (str + lenstr, "(%s", suffix);
+ MPC_ASSERT (ret >= 0);
+ n = lenstr + (size_t) ret;
+ MPC_ASSERT (n == nread);
+
+ c = getc (stream);
+ if (c == ')') {
+ str = mpc_realloc_str (str, strsize, nread + 2);
+ strsize = nread + 2;
+ str [nread] = (char) c;
+ str [nread+1] = '\0';
+ nread++;
+ }
+ else if (c != EOF)
+ ungetc (c, stream);
+
+ mpc_free_str (suffix);
+ }
+ else if (c != EOF)
+ ungetc (c, stream);
+
+ return str;
+}
+
+
+int
+mpc_inp_str (mpc_ptr rop, FILE *stream, size_t *read, int base,
+mpc_rnd_t rnd_mode)
+{
+ size_t white, nread = 0;
+ int inex = -1;
+ int c;
+ char *str;
+
+ if (stream == NULL)
+ stream = stdin;
+
+ white = skip_whitespace (stream);
+ c = getc (stream);
+ if (c != EOF) {
+ if (c == '(') {
+ char *real_str;
+ char *imag_str;
+ size_t n;
+ int ret;
+
+ nread++; /* the opening parenthesis */
+ white = skip_whitespace (stream);
+ real_str = extract_string (stream);
+ nread += strlen(real_str);
+
+ c = getc (stream);
+ if (!isspace ((unsigned int) c)) {
+ if (c != EOF)
+ ungetc (c, stream);
+ mpc_free_str (real_str);
+ goto error;
+ }
+ else
+ ungetc (c, stream);
+
+ white += skip_whitespace (stream);
+ imag_str = extract_string (stream);
+ nread += strlen (imag_str);
+
+ str = mpc_alloc_str (nread + 2);
+ ret = sprintf (str, "(%s %s", real_str, imag_str);
+ MPC_ASSERT (ret >= 0);
+ n = (size_t) ret;
+ MPC_ASSERT (n == nread + 1);
+ mpc_free_str (real_str);
+ mpc_free_str (imag_str);
+
+ white += skip_whitespace (stream);
+ c = getc (stream);
+ if (c == ')') {
+ str = mpc_realloc_str (str, nread +2, nread + 3);
+ str [nread+1] = (char) c;
+ str [nread+2] = '\0';
+ nread++;
+ }
+ else if (c != EOF)
+ ungetc (c, stream);
+ }
+ else {
+ if (c != EOF)
+ ungetc (c, stream);
+ str = extract_string (stream);
+ nread += strlen (str);
+ }
+
+ inex = mpc_set_str (rop, str, base, rnd_mode);
+
+ mpc_free_str (str);
+ }
+
+error:
+ if (inex == -1) {
+ mpfr_set_nan (mpc_realref(rop));
+ mpfr_set_nan (mpc_imagref(rop));
+ }
+ if (read != NULL)
+ *read = white + nread;
+ return inex;
+}
diff --git a/mpc/src/log.c b/mpc/src/log.c
new file mode 100644
index 0000000000..ad1d448053
--- /dev/null
+++ b/mpc/src/log.c
@@ -0,0 +1,217 @@
+/* mpc_log -- Take the logarithm of a complex number.
+
+Copyright (C) 2008, 2009, 2010, 2011, 2012 INRIA
+
+This file is part of GNU MPC.
+
+GNU MPC is free software; you can redistribute it and/or modify it under
+the terms of the GNU Lesser General Public License as published by the
+Free Software Foundation; either version 3 of the License, or (at your
+option) any later version.
+
+GNU MPC 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 Lesser General Public License for
+more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+
+#include <stdio.h> /* for MPC_ASSERT */
+#include "mpc-impl.h"
+
+int
+mpc_log (mpc_ptr rop, mpc_srcptr op, mpc_rnd_t rnd){
+ int ok, underflow = 0;
+ mpfr_srcptr x, y;
+ mpfr_t v, w;
+ mpfr_prec_t prec;
+ int loops;
+ int re_cmp, im_cmp;
+ int inex_re, inex_im;
+ int err;
+ mpfr_exp_t expw;
+ int sgnw;
+
+ /* special values: NaN and infinities */
+ if (!mpc_fin_p (op)) {
+ if (mpfr_nan_p (mpc_realref (op))) {
+ if (mpfr_inf_p (mpc_imagref (op)))
+ mpfr_set_inf (mpc_realref (rop), +1);
+ else
+ mpfr_set_nan (mpc_realref (rop));
+ mpfr_set_nan (mpc_imagref (rop));
+ inex_im = 0; /* Inf/NaN is exact */
+ }
+ else if (mpfr_nan_p (mpc_imagref (op))) {
+ if (mpfr_inf_p (mpc_realref (op)))
+ mpfr_set_inf (mpc_realref (rop), +1);
+ else
+ mpfr_set_nan (mpc_realref (rop));
+ mpfr_set_nan (mpc_imagref (rop));
+ inex_im = 0; /* Inf/NaN is exact */
+ }
+ else /* We have an infinity in at least one part. */ {
+ inex_im = mpfr_atan2 (mpc_imagref (rop), mpc_imagref (op), mpc_realref (op),
+ MPC_RND_IM (rnd));
+ mpfr_set_inf (mpc_realref (rop), +1);
+ }
+ return MPC_INEX(0, inex_im);
+ }
+
+ /* special cases: real and purely imaginary numbers */
+ re_cmp = mpfr_cmp_ui (mpc_realref (op), 0);
+ im_cmp = mpfr_cmp_ui (mpc_imagref (op), 0);
+ if (im_cmp == 0) {
+ if (re_cmp == 0) {
+ inex_im = mpfr_atan2 (mpc_imagref (rop), mpc_imagref (op), mpc_realref (op),
+ MPC_RND_IM (rnd));
+ mpfr_set_inf (mpc_realref (rop), -1);
+ inex_re = 0; /* -Inf is exact */
+ }
+ else if (re_cmp > 0) {
+ inex_re = mpfr_log (mpc_realref (rop), mpc_realref (op), MPC_RND_RE (rnd));
+ inex_im = mpfr_set (mpc_imagref (rop), mpc_imagref (op), MPC_RND_IM (rnd));
+ }
+ else {
+ /* op = x + 0*y; let w = -x = |x| */
+ int negative_zero;
+ mpfr_rnd_t rnd_im;
+
+ negative_zero = mpfr_signbit (mpc_imagref (op));
+ if (negative_zero)
+ rnd_im = INV_RND (MPC_RND_IM (rnd));
+ else
+ rnd_im = MPC_RND_IM (rnd);
+ w [0] = *mpc_realref (op);
+ MPFR_CHANGE_SIGN (w);
+ inex_re = mpfr_log (mpc_realref (rop), w, MPC_RND_RE (rnd));
+ inex_im = mpfr_const_pi (mpc_imagref (rop), rnd_im);
+ if (negative_zero) {
+ mpc_conj (rop, rop, MPC_RNDNN);
+ inex_im = -inex_im;
+ }
+ }
+ return MPC_INEX(inex_re, inex_im);
+ }
+ else if (re_cmp == 0) {
+ if (im_cmp > 0) {
+ inex_re = mpfr_log (mpc_realref (rop), mpc_imagref (op), MPC_RND_RE (rnd));
+ inex_im = mpfr_const_pi (mpc_imagref (rop), MPC_RND_IM (rnd));
+ /* division by 2 does not change the ternary flag */
+ mpfr_div_2ui (mpc_imagref (rop), mpc_imagref (rop), 1, GMP_RNDN);
+ }
+ else {
+ w [0] = *mpc_imagref (op);
+ MPFR_CHANGE_SIGN (w);
+ inex_re = mpfr_log (mpc_realref (rop), w, MPC_RND_RE (rnd));
+ inex_im = mpfr_const_pi (mpc_imagref (rop), INV_RND (MPC_RND_IM (rnd)));
+ /* division by 2 does not change the ternary flag */
+ mpfr_div_2ui (mpc_imagref (rop), mpc_imagref (rop), 1, GMP_RNDN);
+ mpfr_neg (mpc_imagref (rop), mpc_imagref (rop), GMP_RNDN);
+ inex_im = -inex_im; /* negate the ternary flag */
+ }
+ return MPC_INEX(inex_re, inex_im);
+ }
+
+ prec = MPC_PREC_RE(rop);
+ mpfr_init2 (w, 2);
+ /* let op = x + iy; log = 1/2 log (x^2 + y^2) + i atan2 (y, x) */
+ /* loop for the real part: 1/2 log (x^2 + y^2), fast, but unsafe */
+ /* implementation */
+ ok = 0;
+ for (loops = 1; !ok && loops <= 2; loops++) {
+ prec += mpc_ceil_log2 (prec) + 4;
+ mpfr_set_prec (w, prec);
+
+ mpc_abs (w, op, GMP_RNDN);
+ /* error 0.5 ulp */
+ if (mpfr_inf_p (w))
+ /* intermediate overflow; the logarithm may be representable.
+ Intermediate underflow is impossible. */
+ break;
+
+ mpfr_log (w, w, GMP_RNDN);
+ /* generic error of log: (2^(- exp(w)) + 0.5) ulp */
+
+ if (mpfr_zero_p (w))
+ /* impossible to round, switch to second algorithm */
+ break;
+
+ err = MPC_MAX (-mpfr_get_exp (w), 0) + 1;
+ /* number of lost digits */
+ ok = mpfr_can_round (w, prec - err, GMP_RNDN, GMP_RNDZ,
+ mpfr_get_prec (mpc_realref (rop)) + (MPC_RND_RE (rnd) == GMP_RNDN));
+ }
+
+ if (!ok) {
+ prec = MPC_PREC_RE(rop);
+ mpfr_init2 (v, 2);
+ /* compute 1/2 log (x^2 + y^2) = log |x| + 1/2 * log (1 + (y/x)^2)
+ if |x| >= |y|; otherwise, exchange x and y */
+ if (mpfr_cmpabs (mpc_realref (op), mpc_imagref (op)) >= 0) {
+ x = mpc_realref (op);
+ y = mpc_imagref (op);
+ }
+ else {
+ x = mpc_imagref (op);
+ y = mpc_realref (op);
+ }
+
+ do {
+ prec += mpc_ceil_log2 (prec) + 4;
+ mpfr_set_prec (v, prec);
+ mpfr_set_prec (w, prec);
+
+ mpfr_div (v, y, x, GMP_RNDD); /* error 1 ulp */
+ mpfr_sqr (v, v, GMP_RNDD);
+ /* generic error of multiplication:
+ 1 + 2*1*(2+1*2^(1-prec)) <= 5.0625 since prec >= 6 */
+ mpfr_log1p (v, v, GMP_RNDD);
+ /* error 1 + 4*5.0625 = 21.25 , see algorithms.tex */
+ mpfr_div_2ui (v, v, 1, GMP_RNDD);
+ /* If the result is 0, then there has been an underflow somewhere. */
+
+ mpfr_abs (w, x, GMP_RNDN); /* exact */
+ mpfr_log (w, w, GMP_RNDN); /* error 0.5 ulp */
+ expw = mpfr_get_exp (w);
+ sgnw = mpfr_signbit (w);
+
+ mpfr_add (w, w, v, GMP_RNDN);
+ if (!sgnw) /* v is positive, so no cancellation;
+ error 22.25 ulp; error counts lost bits */
+ err = 5;
+ else
+ err = MPC_MAX (5 + mpfr_get_exp (v),
+ /* 21.25 ulp (v) rewritten in ulp (result, now in w) */
+ -1 + expw - mpfr_get_exp (w)
+ /* 0.5 ulp (previous w), rewritten in ulp (result) */
+ ) + 2;
+
+ /* handle one special case: |x|=1, and (y/x)^2 underflows;
+ then 1/2*log(x^2+y^2) \approx 1/2*y^2 also underflows. */
+ if ( (mpfr_cmp_si (x, -1) == 0 || mpfr_cmp_ui (x, 1) == 0)
+ && mpfr_zero_p (w))
+ underflow = 1;
+
+ } while (!underflow &&
+ !mpfr_can_round (w, prec - err, GMP_RNDN, GMP_RNDZ,
+ mpfr_get_prec (mpc_realref (rop)) + (MPC_RND_RE (rnd) == GMP_RNDN)));
+ mpfr_clear (v);
+ }
+
+ /* imaginary part */
+ inex_im = mpfr_atan2 (mpc_imagref (rop), mpc_imagref (op), mpc_realref (op),
+ MPC_RND_IM (rnd));
+
+ /* set the real part; cannot be done before if rop==op */
+ if (underflow)
+ /* create underflow in result */
+ inex_re = mpfr_set_ui_2exp (mpc_realref (rop), 1,
+ mpfr_get_emin_min () - 2, MPC_RND_RE (rnd));
+ else
+ inex_re = mpfr_set (mpc_realref (rop), w, MPC_RND_RE (rnd));
+ mpfr_clear (w);
+ return MPC_INEX(inex_re, inex_im);
+}
diff --git a/mpc/src/log10.c b/mpc/src/log10.c
new file mode 100644
index 0000000000..4e77aafe15
--- /dev/null
+++ b/mpc/src/log10.c
@@ -0,0 +1,286 @@
+/* mpc_log10 -- Take the base-10 logarithm of a complex number.
+
+Copyright (C) 2012 INRIA
+
+This file is part of GNU MPC.
+
+GNU MPC is free software; you can redistribute it and/or modify it under
+the terms of the GNU Lesser General Public License as published by the
+Free Software Foundation; either version 3 of the License, or (at your
+option) any later version.
+
+GNU MPC 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 Lesser General Public License for
+more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+
+#include <limits.h> /* for CHAR_BIT */
+#include "mpc-impl.h"
+
+/* Auxiliary functions which implement Ziv's strategy for special cases.
+ if flag = 0: compute only real part
+ if flag = 1: compute only imaginary
+ Exact cases should be dealt with separately. */
+static int
+mpc_log10_aux (mpc_ptr rop, mpc_srcptr op, mpc_rnd_t rnd, int flag, int nb)
+{
+ mp_prec_t prec = (MPFR_PREC_MIN > 4) ? MPFR_PREC_MIN : 4;
+ mpc_t tmp;
+ mpfr_t log10;
+ int ok = 0, ret;
+
+ prec = mpfr_get_prec ((flag == 0) ? mpc_realref (rop) : mpc_imagref (rop));
+ prec += 10;
+ mpc_init2 (tmp, prec);
+ mpfr_init2 (log10, prec);
+ while (ok == 0)
+ {
+ mpfr_set_ui (log10, 10, GMP_RNDN); /* exact since prec >= 4 */
+ mpfr_log (log10, log10, GMP_RNDN);
+ /* In each case we have two roundings, thus the final value is
+ x * (1+u)^2 where x is the exact value, and |u| <= 2^(-prec-1).
+ Thus the error is always less than 3 ulps. */
+ switch (nb)
+ {
+ case 0: /* imag <- atan2(y/x) */
+ mpfr_atan2 (mpc_imagref (tmp), mpc_imagref (op), mpc_realref (op),
+ MPC_RND_IM (rnd));
+ mpfr_div (mpc_imagref (tmp), mpc_imagref (tmp), log10, GMP_RNDN);
+ ok = mpfr_can_round (mpc_imagref (tmp), prec - 2, GMP_RNDN,
+ GMP_RNDZ, MPC_PREC_IM(rop) +
+ (MPC_RND_IM (rnd) == GMP_RNDN));
+ if (ok)
+ ret = mpfr_set (mpc_imagref (rop), mpc_imagref (tmp),
+ MPC_RND_IM (rnd));
+ break;
+ case 1: /* real <- log(x) */
+ mpfr_log (mpc_realref (tmp), mpc_realref (op), MPC_RND_RE (rnd));
+ mpfr_div (mpc_realref (tmp), mpc_realref (tmp), log10, GMP_RNDN);
+ ok = mpfr_can_round (mpc_realref (tmp), prec - 2, GMP_RNDN,
+ GMP_RNDZ, MPC_PREC_RE(rop) +
+ (MPC_RND_RE (rnd) == GMP_RNDN));
+ if (ok)
+ ret = mpfr_set (mpc_realref (rop), mpc_realref (tmp),
+ MPC_RND_RE (rnd));
+ break;
+ case 2: /* imag <- pi */
+ mpfr_const_pi (mpc_imagref (tmp), MPC_RND_IM (rnd));
+ mpfr_div (mpc_imagref (tmp), mpc_imagref (tmp), log10, GMP_RNDN);
+ ok = mpfr_can_round (mpc_imagref (tmp), prec - 2, GMP_RNDN,
+ GMP_RNDZ, MPC_PREC_IM(rop) +
+ (MPC_RND_IM (rnd) == GMP_RNDN));
+ if (ok)
+ ret = mpfr_set (mpc_imagref (rop), mpc_imagref (tmp),
+ MPC_RND_IM (rnd));
+ break;
+ }
+ prec += prec / 2;
+ mpc_set_prec (tmp, prec);
+ mpfr_set_prec (log10, prec);
+ }
+ mpc_clear (tmp);
+ mpfr_clear (log10);
+ return ret;
+}
+
+int
+mpc_log10 (mpc_ptr rop, mpc_srcptr op, mpc_rnd_t rnd)
+{
+ int ok = 0, loops = 0, re_cmp, im_cmp, inex_re, inex_im, negative_zero;
+ mpfr_t w;
+ mpfr_prec_t prec;
+ mpfr_rnd_t rnd_im;
+ mpc_t ww;
+ mpc_rnd_t invrnd;
+
+ /* special values: NaN and infinities: same as mpc_log */
+ if (!mpc_fin_p (op)) /* real or imaginary parts are NaN or Inf */
+ {
+ if (mpfr_nan_p (mpc_realref (op)))
+ {
+ if (mpfr_inf_p (mpc_imagref (op)))
+ /* (NaN, Inf) -> (+Inf, NaN) */
+ mpfr_set_inf (mpc_realref (rop), +1);
+ else
+ /* (NaN, xxx) -> (NaN, NaN) */
+ mpfr_set_nan (mpc_realref (rop));
+ mpfr_set_nan (mpc_imagref (rop));
+ inex_im = 0; /* Inf/NaN is exact */
+ }
+ else if (mpfr_nan_p (mpc_imagref (op)))
+ {
+ if (mpfr_inf_p (mpc_realref (op)))
+ /* (Inf, NaN) -> (+Inf, NaN) */
+ mpfr_set_inf (mpc_realref (rop), +1);
+ else
+ /* (xxx, NaN) -> (NaN, NaN) */
+ mpfr_set_nan (mpc_realref (rop));
+ mpfr_set_nan (mpc_imagref (rop));
+ inex_im = 0; /* Inf/NaN is exact */
+ }
+ else /* We have an infinity in at least one part. */
+ {
+ /* (+Inf, y) -> (+Inf, 0) for finite positive-signed y */
+ if (mpfr_inf_p (mpc_realref (op)) && mpfr_signbit (mpc_realref (op))
+ == 0 && mpfr_number_p (mpc_imagref (op)))
+ inex_im = mpfr_atan2 (mpc_imagref (rop), mpc_imagref (op),
+ mpc_realref (op), MPC_RND_IM (rnd));
+ else
+ /* (xxx, Inf) -> (+Inf, atan2(Inf/xxx))
+ (Inf, yyy) -> (+Inf, atan2(yyy/Inf)) */
+ inex_im = mpc_log10_aux (rop, op, rnd, 1, 0);
+ mpfr_set_inf (mpc_realref (rop), +1);
+ }
+ return MPC_INEX(0, inex_im);
+ }
+
+ /* special cases: real and purely imaginary numbers */
+ re_cmp = mpfr_cmp_ui (mpc_realref (op), 0);
+ im_cmp = mpfr_cmp_ui (mpc_imagref (op), 0);
+ if (im_cmp == 0) /* Im(op) = 0 */
+ {
+ if (re_cmp == 0) /* Re(op) = 0 */
+ {
+ if (mpfr_signbit (mpc_realref (op)) == 0)
+ inex_im = mpfr_atan2 (mpc_imagref (rop), mpc_imagref (op),
+ mpc_realref (op), MPC_RND_IM (rnd));
+ else
+ inex_im = mpc_log10_aux (rop, op, rnd, 1, 0);
+ mpfr_set_inf (mpc_realref (rop), -1);
+ inex_re = 0; /* -Inf is exact */
+ }
+ else if (re_cmp > 0)
+ {
+ inex_re = mpfr_log10 (mpc_realref (rop), mpc_realref (op),
+ MPC_RND_RE (rnd));
+ inex_im = mpfr_set (mpc_imagref (rop), mpc_imagref (op),
+ MPC_RND_IM (rnd));
+ }
+ else /* log10(x + 0*i) for negative x */
+ { /* op = x + 0*i; let w = -x = |x| */
+ negative_zero = mpfr_signbit (mpc_imagref (op));
+ if (negative_zero)
+ rnd_im = INV_RND (MPC_RND_IM (rnd));
+ else
+ rnd_im = MPC_RND_IM (rnd);
+ ww->re[0] = *mpc_realref (op);
+ MPFR_CHANGE_SIGN (ww->re);
+ ww->im[0] = *mpc_imagref (op);
+ if (mpfr_cmp_ui (ww->re, 1) == 0)
+ inex_re = mpfr_set_ui (mpc_realref (rop), 0, MPC_RND_RE (rnd));
+ else
+ inex_re = mpc_log10_aux (rop, ww, rnd, 0, 1);
+ inex_im = mpc_log10_aux (rop, op, MPC_RND (0,rnd_im), 1, 2);
+ if (negative_zero)
+ {
+ mpc_conj (rop, rop, MPC_RNDNN);
+ inex_im = -inex_im;
+ }
+ }
+ return MPC_INEX(inex_re, inex_im);
+ }
+ else if (re_cmp == 0)
+ {
+ if (im_cmp > 0)
+ {
+ inex_re = mpfr_log10 (mpc_realref (rop), mpc_imagref (op), MPC_RND_RE (rnd));
+ inex_im = mpc_log10_aux (rop, op, rnd, 1, 2);
+ /* division by 2 does not change the ternary flag */
+ mpfr_div_2ui (mpc_imagref (rop), mpc_imagref (rop), 1, GMP_RNDN);
+ }
+ else
+ {
+ w [0] = *mpc_imagref (op);
+ MPFR_CHANGE_SIGN (w);
+ inex_re = mpfr_log10 (mpc_realref (rop), w, MPC_RND_RE (rnd));
+ invrnd = MPC_RND (0, INV_RND (MPC_RND_IM (rnd)));
+ inex_im = mpc_log10_aux (rop, op, invrnd, 1, 2);
+ /* division by 2 does not change the ternary flag */
+ mpfr_div_2ui (mpc_imagref (rop), mpc_imagref (rop), 1, GMP_RNDN);
+ mpfr_neg (mpc_imagref (rop), mpc_imagref (rop), GMP_RNDN);
+ inex_im = -inex_im; /* negate the ternary flag */
+ }
+ return MPC_INEX(inex_re, inex_im);
+ }
+
+ /* generic case: neither Re(op) nor Im(op) is NaN, Inf or zero */
+ prec = MPC_PREC_RE(rop);
+ mpfr_init2 (w, prec);
+ mpc_init2 (ww, prec);
+ /* let op = x + iy; compute log(op)/log(10) */
+ while (ok == 0)
+ {
+ loops ++;
+ prec += (loops <= 2) ? mpc_ceil_log2 (prec) + 4 : prec / 2;
+ mpfr_set_prec (w, prec);
+ mpc_set_prec (ww, prec);
+
+ mpc_log (ww, op, MPC_RNDNN);
+ mpfr_set_ui (w, 10, GMP_RNDN); /* exact since prec >= 4 */
+ mpfr_log (w, w, GMP_RNDN);
+ mpc_div_fr (ww, ww, w, MPC_RNDNN);
+
+ ok = mpfr_can_round (mpc_realref (ww), prec - 2, GMP_RNDN, GMP_RNDZ,
+ MPC_PREC_RE(rop) + (MPC_RND_RE (rnd) == GMP_RNDN));
+
+ /* Special code to deal with cases where the real part of log10(x+i*y)
+ is exact, like x=3 and y=1. Since Re(log10(x+i*y)) = log10(x^2+y^2)/2
+ this happens whenever x^2+y^2 is a nonnegative power of 10.
+ Indeed x^2+y^2 cannot equal 10^(a/2^b) for a, b integers, a odd, b>0,
+ since x^2+y^2 is rational, and 10^(a/2^b) is irrational.
+ Similarly, for b=0, x^2+y^2 cannot equal 10^a for a < 0 since x^2+y^2
+ is a rational with denominator a power of 2.
+ Now let x^2+y^2 = 10^s. Without loss of generality we can assume
+ x = u/2^e and y = v/2^e with u, v, e integers: u^2+v^2 = 10^s*2^(2e)
+ thus u^2+v^2 = 0 mod 2^(2e). By recurrence on e, necessarily
+ u = v = 0 mod 2^e, thus x and y are necessarily integers.
+ */
+ if ((ok == 0) && (loops == 1) && mpfr_integer_p (mpc_realref (op)) &&
+ mpfr_integer_p (mpc_imagref (op)))
+ {
+ mpz_t x, y;
+ unsigned long s, v;
+
+ mpz_init (x);
+ mpz_init (y);
+ mpfr_get_z (x, mpc_realref (op), GMP_RNDN); /* exact */
+ mpfr_get_z (y, mpc_imagref (op), GMP_RNDN); /* exact */
+ mpz_mul (x, x, x);
+ mpz_mul (y, y, y);
+ mpz_add (x, x, y); /* x^2+y^2 */
+ v = mpz_scan1 (x, 0);
+ /* if x = 10^s then necessarily s = v */
+ s = mpz_sizeinbase (x, 10);
+ /* since s is either the number of digits of x or one more,
+ then x = 10^(s-1) or 10^(s-2) */
+ if (s == v + 1 || s == v + 2)
+ {
+ mpz_div_2exp (x, x, v);
+ mpz_ui_pow_ui (y, 5, v);
+ if (mpz_cmp (y, x) == 0) /* Re(log10(x+i*y)) is exactly v/2 */
+ {
+ /* we reset the precision of Re(ww) so that v can be
+ represented exactly */
+ mpfr_set_prec (mpc_realref (ww), sizeof(unsigned long)*CHAR_BIT);
+ mpfr_set_ui_2exp (mpc_realref (ww), v, -1, GMP_RNDN); /* exact */
+ ok = 1;
+ }
+ }
+ mpz_clear (x);
+ mpz_clear (y);
+ }
+
+ ok = ok && mpfr_can_round (mpc_imagref (ww), prec-2, GMP_RNDN, GMP_RNDZ,
+ MPC_PREC_IM(rop) + (MPC_RND_IM (rnd) == GMP_RNDN));
+ }
+
+ inex_re = mpfr_set (mpc_realref(rop), mpc_realref (ww), MPC_RND_RE (rnd));
+ inex_im = mpfr_set (mpc_imagref(rop), mpc_imagref (ww), MPC_RND_IM (rnd));
+ mpfr_clear (w);
+ mpc_clear (ww);
+ return MPC_INEX(inex_re, inex_im);
+}
diff --git a/mpc/src/logging.c b/mpc/src/logging.c
new file mode 100644
index 0000000000..79ed0338e7
--- /dev/null
+++ b/mpc/src/logging.c
@@ -0,0 +1,147 @@
+/* logging.c -- "Dummy" functions logging calls to real mpc functions.
+
+Copyright (C) 2011 INRIA
+
+This file is part of GNU MPC.
+
+GNU MPC is free software; you can redistribute it and/or modify it under
+the terms of the GNU Lesser General Public License as published by the
+Free Software Foundation; either version 3 of the License, or (at your
+option) any later version.
+
+GNU MPC 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 Lesser General Public License for
+more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+
+#include "config.h"
+#include <stdio.h>
+
+#ifdef HAVE_INTTYPES_H
+#include <inttypes.h>
+#endif
+#ifdef HAVE_STDINT_H
+#include <stdint.h>
+#endif
+
+#define __MPC_LIBRARY_BUILD
+ /* to indicate we are inside the library build; needed here since mpc-log.h
+ includes mpc.h and not mpc-impl.h */
+#include "mpc-log.h"
+
+#ifdef HAVE_DLFCN_H
+#include <dlfcn.h>
+#endif
+
+typedef int (*c_c_func_ptr) (mpc_ptr, mpc_srcptr, mpc_rnd_t);
+typedef int (*c_cc_func_ptr) (mpc_ptr, mpc_srcptr, mpc_srcptr, mpc_rnd_t);
+typedef int (*c_ccc_func_ptr) (mpc_ptr, mpc_srcptr, mpc_srcptr, mpc_srcptr, mpc_rnd_t);
+typedef int (*cc_c_func_ptr) (mpc_ptr, mpc_ptr, mpc_srcptr, mpc_rnd_t, mpc_rnd_t);
+
+#define MPC_LOGGING_OUT_PREC(z) \
+ do { \
+ fprintf (stderr, " %li %li", (long) mpfr_get_prec (mpc_realref (z)), \
+ (long) mpfr_get_prec (mpc_imagref (z))); \
+ } while (0);
+
+#define MPC_LOGGING_OUT_C(z) \
+ do { \
+ MPC_LOGGING_OUT_PREC (z); \
+ fprintf (stderr, " "); \
+ mpc_out_str (stderr, 16, 0, z, MPC_RNDNN); \
+ } while (0);
+
+#define MPC_LOGGING_FUNC_TYPE(funcname, type) \
+ do { \
+ fprintf (stderr, "mpc_"#funcname" "#type); \
+ } while (0);
+
+#define MPC_LOGGING_C_C(funcname) \
+__MPC_DECLSPEC int mpc_log_##funcname (mpc_ptr rop, mpc_srcptr op, mpc_rnd_t rnd) \
+{ \
+ static c_c_func_ptr func = NULL; \
+ if (func == NULL) \
+ func = (c_c_func_ptr) (intptr_t) dlsym (NULL, "mpc_"#funcname); \
+ MPC_LOGGING_FUNC_TYPE (funcname, c_c); \
+ MPC_LOGGING_OUT_PREC (rop); \
+ MPC_LOGGING_OUT_C (op); \
+ fprintf (stderr, "\n"); \
+ return func (rop, op, rnd); \
+}
+
+#define MPC_LOGGING_C_CC(funcname) \
+__MPC_DECLSPEC int mpc_log_##funcname (mpc_ptr rop, mpc_srcptr op1, mpc_srcptr op2, mpc_rnd_t rnd) \
+{ \
+ static c_cc_func_ptr func = NULL; \
+ if (func == NULL) \
+ func = (c_cc_func_ptr) (intptr_t) dlsym (NULL, "mpc_"#funcname); \
+ MPC_LOGGING_FUNC_TYPE (funcname, c_cc); \
+ MPC_LOGGING_OUT_PREC (rop); \
+ MPC_LOGGING_OUT_C (op1); \
+ MPC_LOGGING_OUT_C (op2); \
+ fprintf (stderr, "\n"); \
+ return func (rop, op1, op2, rnd); \
+}
+
+#define MPC_LOGGING_C_CCC(funcname) \
+__MPC_DECLSPEC int mpc_log_##funcname (mpc_ptr rop, mpc_srcptr op1, mpc_srcptr op2, mpc_srcptr op3, mpc_rnd_t rnd) \
+{ \
+ static c_ccc_func_ptr func = NULL; \
+ if (func == NULL) \
+ func = (c_ccc_func_ptr) (intptr_t) dlsym (NULL, "mpc_"#funcname); \
+ MPC_LOGGING_FUNC_TYPE (funcname, c_ccc); \
+ MPC_LOGGING_OUT_PREC (rop); \
+ MPC_LOGGING_OUT_C (op1); \
+ MPC_LOGGING_OUT_C (op2); \
+ MPC_LOGGING_OUT_C (op3); \
+ fprintf (stderr, "\n"); \
+ return func (rop, op1, op2, op3, rnd); \
+}
+
+#define MPC_LOGGING_CC_C(funcname) \
+__MPC_DECLSPEC int mpc_log_##funcname (mpc_ptr rop1, mpc_ptr rop2, mpc_srcptr op, mpc_rnd_t rnd1, mpc_rnd_t rnd2) \
+{ \
+ static cc_c_func_ptr func = NULL; \
+ if (func == NULL) \
+ func = (cc_c_func_ptr) (intptr_t) dlsym (NULL, "mpc_"#funcname); \
+ MPC_LOGGING_FUNC_TYPE (funcname, cc_c); \
+ MPC_LOGGING_OUT_PREC (rop1); \
+ MPC_LOGGING_OUT_PREC (rop2); \
+ MPC_LOGGING_OUT_C (op); \
+ fprintf (stderr, "\n"); \
+ return func (rop1, rop2, op, rnd1, rnd2); \
+}
+
+MPC_LOGGING_C_C (sqr)
+MPC_LOGGING_C_C (conj)
+MPC_LOGGING_C_C (neg)
+MPC_LOGGING_C_C (sqrt)
+MPC_LOGGING_C_C (proj)
+MPC_LOGGING_C_C (exp)
+MPC_LOGGING_C_C (log)
+MPC_LOGGING_C_C (sin)
+MPC_LOGGING_C_C (cos)
+MPC_LOGGING_C_C (tan)
+MPC_LOGGING_C_C (sinh)
+MPC_LOGGING_C_C (cosh)
+MPC_LOGGING_C_C (tanh)
+MPC_LOGGING_C_C (asin)
+MPC_LOGGING_C_C (acos)
+MPC_LOGGING_C_C (atan)
+MPC_LOGGING_C_C (asinh)
+MPC_LOGGING_C_C (acosh)
+MPC_LOGGING_C_C (atanh)
+
+MPC_LOGGING_C_CC (add)
+MPC_LOGGING_C_CC (sub)
+MPC_LOGGING_C_CC (mul)
+MPC_LOGGING_C_CC (div)
+MPC_LOGGING_C_CC (pow)
+
+MPC_LOGGING_C_CCC (fma)
+
+MPC_LOGGING_CC_C (sin_cos)
diff --git a/mpc/src/mem.c b/mpc/src/mem.c
new file mode 100644
index 0000000000..b4c327c079
--- /dev/null
+++ b/mpc/src/mem.c
@@ -0,0 +1,46 @@
+/* wrapper functions to allocate, reallocate and free memory
+
+Copyright (C) 2009 INRIA
+
+This file is part of GNU MPC.
+
+GNU MPC is free software; you can redistribute it and/or modify it under
+the terms of the GNU Lesser General Public License as published by the
+Free Software Foundation; either version 3 of the License, or (at your
+option) any later version.
+
+GNU MPC 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 Lesser General Public License for
+more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+
+#include <string.h> /* for strlen */
+#include "mpc-impl.h"
+
+char *
+mpc_alloc_str (size_t len)
+{
+ void * (*allocfunc) (size_t);
+ mp_get_memory_functions (&allocfunc, NULL, NULL);
+ return (char *) ((*allocfunc) (len));
+}
+
+char *
+mpc_realloc_str (char * str, size_t oldlen, size_t newlen)
+{
+ void * (*reallocfunc) (void *, size_t, size_t);
+ mp_get_memory_functions (NULL, &reallocfunc, NULL);
+ return (char *) ((*reallocfunc) (str, oldlen, newlen));
+}
+
+void
+mpc_free_str (char *str)
+{
+ void (*freefunc) (void *, size_t);
+ mp_get_memory_functions (NULL, NULL, &freefunc);
+ (*freefunc) (str, strlen (str) + 1);
+}
diff --git a/mpc/src/mpc-impl.h b/mpc/src/mpc-impl.h
new file mode 100644
index 0000000000..b2aaa90eb3
--- /dev/null
+++ b/mpc/src/mpc-impl.h
@@ -0,0 +1,194 @@
+/* mpc-impl.h -- Internal include file for mpc.
+
+Copyright (C) 2002, 2004, 2005, 2008, 2009, 2010, 2011, 2012 INRIA
+
+This file is part of GNU MPC.
+
+GNU MPC is free software; you can redistribute it and/or modify it under
+the terms of the GNU Lesser General Public License as published by the
+Free Software Foundation; either version 3 of the License, or (at your
+option) any later version.
+
+GNU MPC 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 Lesser General Public License for
+more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+
+#ifndef __MPC_IMPL_H
+#define __MPC_IMPL_H
+#define __MPC_LIBRARY_BUILD
+ /* to indicate we are inside the library build */
+
+#include "config.h"
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#include "mpc.h"
+
+/*
+ * Miscellaneous useful macros
+ */
+
+#define MPC_MIN(h,i) ((h) < (i) ? (h) : (i))
+#define MPC_MAX(h,i) ((h) > (i) ? (h) : (i))
+
+/* Safe absolute value (to avoid possible integer overflow) */
+/* type is the target (unsigned) type (copied from mpfr-impl.h) */
+#ifdef SAFE_ABS
+#undef SAFE_ABS
+#endif
+#define SAFE_ABS(type,x) ((x) >= 0 ? (type)(x) : -(type)(x))
+
+
+/*
+ * MPFR constants and macros
+ */
+
+#ifndef BITS_PER_MP_LIMB
+#define BITS_PER_MP_LIMB mp_bits_per_limb
+#endif
+
+#define MPFR_SIGNBIT(x) (mpfr_signbit (x) ? -1 : 1)
+#define MPC_MPFR_SIGN(x) (mpfr_zero_p (x) ? 0 : MPFR_SIGNBIT (x))
+ /* should be called MPFR_SIGN, but this is taken in mpfr.h */
+#define MPFR_CHANGE_SIGN(x) mpfr_neg(x,x,GMP_RNDN)
+#define MPFR_COPYSIGN(x,y,z,rnd) (mpfr_nan_p (z) ? \
+ mpfr_setsign (x, y, 0, rnd) : \
+ mpfr_copysign (x, y, z, rnd))
+ /* work around spurious signs in nan */
+#define MPFR_ADD_ONE_ULP(x) mpfr_add_one_ulp (x, GMP_RNDN)
+#define MPFR_SUB_ONE_ULP(x) mpfr_sub_one_ulp (x, GMP_RNDN)
+ /* drop unused rounding mode from macroes */
+#define MPFR_SWAP(a,b) do { mpfr_srcptr tmp; tmp = a; a = b; b = tmp; } while (0)
+
+
+/*
+ * Macro implementing rounding away from zero, to ease compatibility with
+ * mpfr < 3. f is the complete function call with a rounding mode of
+ * MPFR_RNDA, rop the name of the variable containing the result; it is
+ * already contained in f, but needs to be repeated so that the macro can
+ * modify the variable.
+ * Usage: replace each call to a function such as
+ * mpfr_add (rop, a, b, MPFR_RNDA)
+ * by
+ * ROUND_AWAY (mpfr_add (rop, a, b, MPFR_RNDA), rop)
+*/
+#if MPFR_VERSION_MAJOR < 3
+ /* round towards zero, add 1 ulp if not exact */
+#define MPFR_RNDA GMP_RNDZ
+#define ROUND_AWAY(f,rop) \
+ ((f) ? MPFR_ADD_ONE_ULP (rop), MPFR_SIGNBIT (rop) : 0)
+#else
+#define ROUND_AWAY(f,rop) \
+ (f)
+#endif /* mpfr < 3 */
+
+#if MPFR_VERSION_MAJOR < 3
+/* declare missing functions, defined in get_version.c */
+__MPC_DECLSPEC void mpfr_set_zero (mpfr_ptr, int);
+__MPC_DECLSPEC int mpfr_regular_p (mpfr_srcptr);
+#endif /* mpfr < 3 */
+
+
+/*
+ * MPC macros
+ */
+
+#define MPC_PREC_RE(x) (mpfr_get_prec(mpc_realref(x)))
+#define MPC_PREC_IM(x) (mpfr_get_prec(mpc_imagref(x)))
+#define MPC_MAX_PREC(x) MPC_MAX(MPC_PREC_RE(x), MPC_PREC_IM(x))
+
+#define INV_RND(r) \
+ (((r) == GMP_RNDU) ? GMP_RNDD : (((r) == GMP_RNDD) ? GMP_RNDU : (r)))
+
+#define mpc_inf_p(z) (mpfr_inf_p(mpc_realref(z))||mpfr_inf_p(mpc_imagref(z)))
+ /* Convention in C99 (G.3): z is regarded as an infinity if at least one of
+ its parts is infinite */
+#define mpc_zero_p(z) (mpfr_zero_p(mpc_realref(z))&&mpfr_zero_p(mpc_imagref(z)))
+ /* Convention in C99 (G.3): z is regarded as a zero if each of its parts is
+ a zero */
+#define mpc_fin_p(z) (mpfr_number_p(mpc_realref(z))&&mpfr_number_p(mpc_imagref(z)))
+ /* Convention in C99 (G.3): z is regarded as finite if both its parts are */
+#define mpc_nan_p(z) ((mpfr_nan_p(mpc_realref(z)) && !mpfr_inf_p(mpc_imagref(z))) || (mpfr_nan_p(mpc_imagref(z)) && !mpfr_inf_p(mpc_realref(z))))
+ /* Consider as NaN all other numbers containing at least one NaN */
+
+
+/*
+ * ASSERT macros
+ */
+
+#ifdef NDEBUG
+#define MPC_ASSERT(expr) \
+ do { \
+ } while (0)
+#else
+#define MPC_ASSERT(expr) \
+ do { \
+ if (!(expr)) \
+ { \
+ fprintf (stderr, "%s:%d: MPC assertion failed: %s\n", \
+ __FILE__, __LINE__, #expr); \
+ abort(); \
+ } \
+ } while (0)
+#endif
+
+
+/*
+ * Debug macros
+ */
+
+#define MPC_OUT(x) \
+do { \
+ printf (#x "[%lu,%lu]=", (unsigned long int) MPC_PREC_RE (x), \
+ (unsigned long int) MPC_PREC_IM (x)); \
+ mpc_out_str (stdout, 2, 0, x, MPC_RNDNN); \
+ printf ("\n"); \
+} while (0)
+
+#define MPFR_OUT(x) \
+do { \
+ printf (#x "[%lu]=", (unsigned long int) mpfr_get_prec (x)); \
+ mpfr_out_str (stdout, 2, 0, x, GMP_RNDN); \
+ printf ("\n"); \
+} while (0)
+
+
+/*
+ * Constants
+ */
+
+#ifndef MUL_KARATSUBA_THRESHOLD
+#define MUL_KARATSUBA_THRESHOLD 23
+#endif
+
+
+/*
+ * Define internal functions
+ */
+
+#if defined (__cplusplus)
+extern "C" {
+#endif
+
+
+__MPC_DECLSPEC int mpc_mul_naive (mpc_ptr, mpc_srcptr, mpc_srcptr, mpc_rnd_t);
+__MPC_DECLSPEC int mpc_mul_karatsuba (mpc_ptr, mpc_srcptr, mpc_srcptr, mpc_rnd_t);
+__MPC_DECLSPEC int mpc_fma_naive (mpc_ptr, mpc_srcptr, mpc_srcptr, mpc_srcptr, mpc_rnd_t);
+__MPC_DECLSPEC int mpc_pow_usi (mpc_ptr, mpc_srcptr, unsigned long, int, mpc_rnd_t);
+__MPC_DECLSPEC char* mpc_alloc_str (size_t);
+__MPC_DECLSPEC char* mpc_realloc_str (char*, size_t, size_t);
+__MPC_DECLSPEC void mpc_free_str (char*);
+__MPC_DECLSPEC mpfr_prec_t mpc_ceil_log2 (mpfr_prec_t);
+__MPC_DECLSPEC int set_pi_over_2 (mpfr_ptr, int, mpfr_rnd_t);
+
+#if defined (__cplusplus)
+}
+#endif
+
+
+#endif
diff --git a/mpc/src/mpc-log.h b/mpc/src/mpc-log.h
new file mode 100644
index 0000000000..78c98d2da4
--- /dev/null
+++ b/mpc/src/mpc-log.h
@@ -0,0 +1,51 @@
+/* mpc-log.h -- Include file to enable function call logging; replaces mpc.h.
+
+Copyright (C) 2011 INRIA
+
+This file is part of GNU MPC.
+
+GNU MPC is free software; you can redistribute it and/or modify it under
+the terms of the GNU Lesser General Public License as published by the
+Free Software Foundation; either version 3 of the License, or (at your
+option) any later version.
+
+GNU MPC 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 Lesser General Public License for
+more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+
+#define mpc_sqr mpc_log_sqr
+#define mpc_conj mpc_log_conj
+#define mpc_neg mpc_log_neg
+#define mpc_sqrt mpc_log_sqrt
+#define mpc_proj mpc_log_proj
+#define mpc_exp mpc_log_exp
+#define mpc_log mpc_log_log
+#define mpc_sin mpc_log_sin
+#define mpc_cos mpc_log_cos
+#define mpc_tan mpc_log_tan
+#define mpc_sinh mpc_log_sinh
+#define mpc_cosh mpc_log_cosh
+#define mpc_tanh mpc_log_tanh
+#define mpc_asin mpc_log_asin
+#define mpc_acos mpc_log_acos
+#define mpc_atan mpc_log_atan
+#define mpc_asinh mpc_log_asinh
+#define mpc_acosh mpc_log_acosh
+#define mpc_atanh mpc_log_atanh
+
+#define mpc_add mpc_log_add
+#define mpc_sub mpc_log_sub
+#define mpc_mul mpc_log_mul
+#define mpc_div mpc_log_div
+#define mpc_pow mpc_log_pow
+
+#define mpc_fma mpc_log_fma
+
+#define mpc_sin_cos mpc_log_sin_cos
+
+#include "mpc.h"
diff --git a/mpc/src/mpc.h b/mpc/src/mpc.h
new file mode 100644
index 0000000000..f6e1beefe2
--- /dev/null
+++ b/mpc/src/mpc.h
@@ -0,0 +1,269 @@
+/* mpc.h -- Include file for mpc.
+
+Copyright (C) 2002, 2003, 2004, 2005, 2007, 2008, 2009, 2010, 2011, 2012, 2014, 2015 INRIA
+
+This file is part of GNU MPC.
+
+GNU MPC is free software; you can redistribute it and/or modify it under
+the terms of the GNU Lesser General Public License as published by the
+Free Software Foundation; either version 3 of the License, or (at your
+option) any later version.
+
+GNU MPC 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 Lesser General Public License for
+more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+
+#ifndef __MPC_H
+#define __MPC_H
+
+#include "gmp.h"
+#include "mpfr.h"
+
+/* Backwards compatibility with mpfr<3.0.0 */
+#ifndef mpfr_exp_t
+#define mpfr_exp_t mp_exp_t
+#endif
+
+/* Define MPC version number */
+#define MPC_VERSION_MAJOR 1
+#define MPC_VERSION_MINOR 0
+#define MPC_VERSION_PATCHLEVEL 3
+#define MPC_VERSION_STRING "1.0.3"
+
+/* Macros dealing with MPC VERSION */
+#define MPC_VERSION_NUM(a,b,c) (((a) << 16L) | ((b) << 8) | (c))
+#define MPC_VERSION \
+ MPC_VERSION_NUM(MPC_VERSION_MAJOR,MPC_VERSION_MINOR,MPC_VERSION_PATCHLEVEL)
+
+/* Check if stdint.h/inttypes.h is included */
+#if defined (INTMAX_C) && defined (UINTMAX_C)
+#define _MPC_H_HAVE_INTMAX_T 1
+#endif
+
+/* Return values */
+
+/* Transform negative to 2, positive to 1, leave 0 unchanged */
+#define MPC_INEX_POS(inex) (((inex) < 0) ? 2 : ((inex) == 0) ? 0 : 1)
+/* Transform 2 to negative, 1 to positive, leave 0 unchanged */
+#define MPC_INEX_NEG(inex) (((inex) == 2) ? -1 : ((inex) == 0) ? 0 : 1)
+
+/* The global inexact flag is made of (real flag) + 4 * (imaginary flag), where
+ each of the real and imaginary inexact flag are:
+ 0 when the result is exact (no rounding error)
+ 1 when the result is larger than the exact value
+ 2 when the result is smaller than the exact value */
+#define MPC_INEX(inex_re, inex_im) \
+ (MPC_INEX_POS(inex_re) | (MPC_INEX_POS(inex_im) << 2))
+#define MPC_INEX_RE(inex) MPC_INEX_NEG((inex) & 3)
+#define MPC_INEX_IM(inex) MPC_INEX_NEG((inex) >> 2)
+
+/* For functions computing two results, the return value is
+ inexact1+16*inexact2, which is 0 iif both results are exact. */
+#define MPC_INEX12(inex1, inex2) (inex1 | (inex2 << 4))
+#define MPC_INEX1(inex) (inex & 15)
+#define MPC_INEX2(inex) (inex >> 4)
+
+/* Definition of rounding modes */
+
+/* a complex rounding mode is just a pair of two real rounding modes
+ we reserve four bits for a real rounding mode. */
+typedef int mpc_rnd_t;
+
+#define MPC_RND(r1,r2) (((int)(r1)) + ((int)(r2) << 4))
+#define MPC_RND_RE(x) ((mpfr_rnd_t)((x) & 0x0F))
+#define MPC_RND_IM(x) ((mpfr_rnd_t)((x) >> 4))
+
+#define MPC_RNDNN MPC_RND (GMP_RNDN,GMP_RNDN)
+#define MPC_RNDNZ MPC_RND (GMP_RNDN,GMP_RNDZ)
+#define MPC_RNDNU MPC_RND (GMP_RNDN,GMP_RNDU)
+#define MPC_RNDND MPC_RND (GMP_RNDN,GMP_RNDD)
+
+#define MPC_RNDZN MPC_RND (GMP_RNDZ,GMP_RNDN)
+#define MPC_RNDZZ MPC_RND (GMP_RNDZ,GMP_RNDZ)
+#define MPC_RNDZU MPC_RND (GMP_RNDZ,GMP_RNDU)
+#define MPC_RNDZD MPC_RND (GMP_RNDZ,GMP_RNDD)
+
+#define MPC_RNDUN MPC_RND (GMP_RNDU,GMP_RNDN)
+#define MPC_RNDUZ MPC_RND (GMP_RNDU,GMP_RNDZ)
+#define MPC_RNDUU MPC_RND (GMP_RNDU,GMP_RNDU)
+#define MPC_RNDUD MPC_RND (GMP_RNDU,GMP_RNDD)
+
+#define MPC_RNDDN MPC_RND (GMP_RNDD,GMP_RNDN)
+#define MPC_RNDDZ MPC_RND (GMP_RNDD,GMP_RNDZ)
+#define MPC_RNDDU MPC_RND (GMP_RNDD,GMP_RNDU)
+#define MPC_RNDDD MPC_RND (GMP_RNDD,GMP_RNDD)
+
+
+/* Definitions of types and their semantics */
+
+typedef struct {
+ mpfr_t re;
+ mpfr_t im;
+}
+__mpc_struct;
+
+typedef __mpc_struct mpc_t[1];
+typedef __mpc_struct *mpc_ptr;
+typedef const __mpc_struct *mpc_srcptr;
+
+/* Support for WINDOWS DLL, see
+ http://lists.gforge.inria.fr/pipermail/mpc-discuss/2011-November/000990.html;
+ when building the DLL, export symbols, otherwise behave as GMP */
+#if defined (__MPC_LIBRARY_BUILD) && __GMP_LIBGMP_DLL
+#define __MPC_DECLSPEC __GMP_DECLSPEC_EXPORT
+#else
+#define __MPC_DECLSPEC __GMP_DECLSPEC
+#endif
+
+#if defined (__cplusplus)
+extern "C" {
+#endif
+
+__MPC_DECLSPEC int mpc_add (mpc_ptr, mpc_srcptr, mpc_srcptr, mpc_rnd_t);
+__MPC_DECLSPEC int mpc_add_fr (mpc_ptr, mpc_srcptr, mpfr_srcptr, mpc_rnd_t);
+__MPC_DECLSPEC int mpc_add_si (mpc_ptr, mpc_srcptr, long int, mpc_rnd_t);
+__MPC_DECLSPEC int mpc_add_ui (mpc_ptr, mpc_srcptr, unsigned long int, mpc_rnd_t);
+__MPC_DECLSPEC int mpc_sub (mpc_ptr, mpc_srcptr, mpc_srcptr, mpc_rnd_t);
+__MPC_DECLSPEC int mpc_sub_fr (mpc_ptr, mpc_srcptr, mpfr_srcptr, mpc_rnd_t);
+__MPC_DECLSPEC int mpc_fr_sub (mpc_ptr, mpfr_srcptr, mpc_srcptr, mpc_rnd_t);
+__MPC_DECLSPEC int mpc_sub_ui (mpc_ptr, mpc_srcptr, unsigned long int, mpc_rnd_t);
+__MPC_DECLSPEC int mpc_ui_ui_sub (mpc_ptr, unsigned long int, unsigned long int, mpc_srcptr, mpc_rnd_t);
+__MPC_DECLSPEC int mpc_mul (mpc_ptr, mpc_srcptr, mpc_srcptr, mpc_rnd_t);
+__MPC_DECLSPEC int mpc_mul_fr (mpc_ptr, mpc_srcptr, mpfr_srcptr, mpc_rnd_t);
+__MPC_DECLSPEC int mpc_mul_ui (mpc_ptr, mpc_srcptr, unsigned long int, mpc_rnd_t);
+__MPC_DECLSPEC int mpc_mul_si (mpc_ptr, mpc_srcptr, long int, mpc_rnd_t);
+__MPC_DECLSPEC int mpc_mul_i (mpc_ptr, mpc_srcptr, int, mpc_rnd_t);
+__MPC_DECLSPEC int mpc_sqr (mpc_ptr, mpc_srcptr, mpc_rnd_t);
+__MPC_DECLSPEC int mpc_div (mpc_ptr, mpc_srcptr, mpc_srcptr, mpc_rnd_t);
+__MPC_DECLSPEC int mpc_pow (mpc_ptr, mpc_srcptr, mpc_srcptr, mpc_rnd_t);
+__MPC_DECLSPEC int mpc_pow_fr (mpc_ptr, mpc_srcptr, mpfr_srcptr, mpc_rnd_t);
+__MPC_DECLSPEC int mpc_pow_ld (mpc_ptr, mpc_srcptr, long double, mpc_rnd_t);
+__MPC_DECLSPEC int mpc_pow_d (mpc_ptr, mpc_srcptr, double, mpc_rnd_t);
+__MPC_DECLSPEC int mpc_pow_si (mpc_ptr, mpc_srcptr, long, mpc_rnd_t);
+__MPC_DECLSPEC int mpc_pow_ui (mpc_ptr, mpc_srcptr, unsigned long, mpc_rnd_t);
+__MPC_DECLSPEC int mpc_pow_z (mpc_ptr, mpc_srcptr, mpz_srcptr, mpc_rnd_t);
+__MPC_DECLSPEC int mpc_div_fr (mpc_ptr, mpc_srcptr, mpfr_srcptr, mpc_rnd_t);
+__MPC_DECLSPEC int mpc_fr_div (mpc_ptr, mpfr_srcptr, mpc_srcptr, mpc_rnd_t);
+__MPC_DECLSPEC int mpc_div_ui (mpc_ptr, mpc_srcptr, unsigned long int, mpc_rnd_t);
+__MPC_DECLSPEC int mpc_ui_div (mpc_ptr, unsigned long int, mpc_srcptr, mpc_rnd_t);
+__MPC_DECLSPEC int mpc_div_2ui (mpc_ptr, mpc_srcptr, unsigned long int, mpc_rnd_t);
+__MPC_DECLSPEC int mpc_mul_2ui (mpc_ptr, mpc_srcptr, unsigned long int, mpc_rnd_t);
+__MPC_DECLSPEC int mpc_div_2si (mpc_ptr, mpc_srcptr, long int, mpc_rnd_t);
+__MPC_DECLSPEC int mpc_mul_2si (mpc_ptr, mpc_srcptr, long int, mpc_rnd_t);
+__MPC_DECLSPEC int mpc_conj (mpc_ptr, mpc_srcptr, mpc_rnd_t);
+__MPC_DECLSPEC int mpc_neg (mpc_ptr, mpc_srcptr, mpc_rnd_t);
+__MPC_DECLSPEC int mpc_norm (mpfr_ptr, mpc_srcptr, mpfr_rnd_t);
+__MPC_DECLSPEC int mpc_abs (mpfr_ptr, mpc_srcptr, mpfr_rnd_t);
+__MPC_DECLSPEC int mpc_sqrt (mpc_ptr, mpc_srcptr, mpc_rnd_t);
+__MPC_DECLSPEC int mpc_set (mpc_ptr, mpc_srcptr, mpc_rnd_t);
+__MPC_DECLSPEC int mpc_set_d (mpc_ptr, double, mpc_rnd_t);
+__MPC_DECLSPEC int mpc_set_d_d (mpc_ptr, double, double, mpc_rnd_t);
+__MPC_DECLSPEC int mpc_set_ld (mpc_ptr, long double, mpc_rnd_t);
+__MPC_DECLSPEC int mpc_set_ld_ld (mpc_ptr, long double, long double, mpc_rnd_t);
+__MPC_DECLSPEC int mpc_set_f (mpc_ptr, mpf_srcptr, mpc_rnd_t);
+__MPC_DECLSPEC int mpc_set_f_f (mpc_ptr, mpf_srcptr, mpf_srcptr, mpc_rnd_t);
+__MPC_DECLSPEC int mpc_set_fr (mpc_ptr, mpfr_srcptr, mpc_rnd_t);
+__MPC_DECLSPEC int mpc_set_fr_fr (mpc_ptr, mpfr_srcptr, mpfr_srcptr, mpc_rnd_t);
+__MPC_DECLSPEC int mpc_set_q (mpc_ptr, mpq_srcptr, mpc_rnd_t);
+__MPC_DECLSPEC int mpc_set_q_q (mpc_ptr, mpq_srcptr, mpq_srcptr, mpc_rnd_t);
+__MPC_DECLSPEC int mpc_set_si (mpc_ptr, long int, mpc_rnd_t);
+__MPC_DECLSPEC int mpc_set_si_si (mpc_ptr, long int, long int, mpc_rnd_t);
+__MPC_DECLSPEC int mpc_set_ui (mpc_ptr, unsigned long int, mpc_rnd_t);
+__MPC_DECLSPEC int mpc_set_ui_ui (mpc_ptr, unsigned long int, unsigned long int, mpc_rnd_t);
+__MPC_DECLSPEC int mpc_set_z (mpc_ptr, mpz_srcptr, mpc_rnd_t);
+__MPC_DECLSPEC int mpc_set_z_z (mpc_ptr, mpz_srcptr, mpz_srcptr, mpc_rnd_t);
+__MPC_DECLSPEC void mpc_swap (mpc_ptr, mpc_ptr);
+__MPC_DECLSPEC int mpc_fma (mpc_ptr, mpc_srcptr, mpc_srcptr, mpc_srcptr, mpc_rnd_t);
+
+__MPC_DECLSPEC void mpc_set_nan (mpc_ptr);
+
+__MPC_DECLSPEC int mpc_real (mpfr_ptr, mpc_srcptr, mpfr_rnd_t);
+__MPC_DECLSPEC int mpc_imag (mpfr_ptr, mpc_srcptr, mpfr_rnd_t);
+__MPC_DECLSPEC int mpc_arg (mpfr_ptr, mpc_srcptr, mpfr_rnd_t);
+__MPC_DECLSPEC int mpc_proj (mpc_ptr, mpc_srcptr, mpc_rnd_t);
+__MPC_DECLSPEC int mpc_cmp (mpc_srcptr, mpc_srcptr);
+__MPC_DECLSPEC int mpc_cmp_si_si (mpc_srcptr, long int, long int);
+__MPC_DECLSPEC int mpc_exp (mpc_ptr, mpc_srcptr, mpc_rnd_t);
+__MPC_DECLSPEC int mpc_log (mpc_ptr, mpc_srcptr, mpc_rnd_t);
+__MPC_DECLSPEC int mpc_log10 (mpc_ptr, mpc_srcptr, mpc_rnd_t);
+__MPC_DECLSPEC int mpc_sin (mpc_ptr, mpc_srcptr, mpc_rnd_t);
+__MPC_DECLSPEC int mpc_cos (mpc_ptr, mpc_srcptr, mpc_rnd_t);
+__MPC_DECLSPEC int mpc_sin_cos (mpc_ptr, mpc_ptr, mpc_srcptr, mpc_rnd_t, mpc_rnd_t);
+__MPC_DECLSPEC int mpc_tan (mpc_ptr, mpc_srcptr, mpc_rnd_t);
+__MPC_DECLSPEC int mpc_sinh (mpc_ptr, mpc_srcptr, mpc_rnd_t);
+__MPC_DECLSPEC int mpc_cosh (mpc_ptr, mpc_srcptr, mpc_rnd_t);
+__MPC_DECLSPEC int mpc_tanh (mpc_ptr, mpc_srcptr, mpc_rnd_t);
+__MPC_DECLSPEC int mpc_asin (mpc_ptr, mpc_srcptr, mpc_rnd_t);
+__MPC_DECLSPEC int mpc_acos (mpc_ptr, mpc_srcptr, mpc_rnd_t);
+__MPC_DECLSPEC int mpc_atan (mpc_ptr, mpc_srcptr, mpc_rnd_t);
+__MPC_DECLSPEC int mpc_asinh (mpc_ptr, mpc_srcptr, mpc_rnd_t);
+__MPC_DECLSPEC int mpc_acosh (mpc_ptr, mpc_srcptr, mpc_rnd_t);
+__MPC_DECLSPEC int mpc_atanh (mpc_ptr, mpc_srcptr, mpc_rnd_t);
+__MPC_DECLSPEC void mpc_clear (mpc_ptr);
+__MPC_DECLSPEC int mpc_urandom (mpc_ptr, gmp_randstate_t);
+__MPC_DECLSPEC void mpc_init2 (mpc_ptr, mpfr_prec_t);
+__MPC_DECLSPEC void mpc_init3 (mpc_ptr, mpfr_prec_t, mpfr_prec_t);
+__MPC_DECLSPEC mpfr_prec_t mpc_get_prec (mpc_srcptr x);
+__MPC_DECLSPEC void mpc_get_prec2 (mpfr_prec_t *pr, mpfr_prec_t *pi, mpc_srcptr x);
+__MPC_DECLSPEC void mpc_set_prec (mpc_ptr, mpfr_prec_t);
+__MPC_DECLSPEC const char * mpc_get_version (void);
+
+__MPC_DECLSPEC int mpc_strtoc (mpc_ptr, const char *, char **, int, mpc_rnd_t);
+__MPC_DECLSPEC int mpc_set_str (mpc_ptr, const char *, int, mpc_rnd_t);
+__MPC_DECLSPEC char * mpc_get_str (int, size_t, mpc_srcptr, mpc_rnd_t);
+__MPC_DECLSPEC void mpc_free_str (char *);
+
+/* declare certain functions only if appropriate headers have been included */
+#ifdef _MPC_H_HAVE_INTMAX_T
+__MPC_DECLSPEC int mpc_set_sj (mpc_ptr, intmax_t, mpc_rnd_t);
+__MPC_DECLSPEC int mpc_set_uj (mpc_ptr, uintmax_t, mpc_rnd_t);
+__MPC_DECLSPEC int mpc_set_sj_sj (mpc_ptr, intmax_t, intmax_t, mpc_rnd_t);
+__MPC_DECLSPEC int mpc_set_uj_uj (mpc_ptr, uintmax_t, uintmax_t, mpc_rnd_t);
+#endif
+
+#ifdef _Complex_I
+__MPC_DECLSPEC int mpc_set_dc (mpc_ptr, double _Complex, mpc_rnd_t);
+__MPC_DECLSPEC int mpc_set_ldc (mpc_ptr, long double _Complex, mpc_rnd_t);
+__MPC_DECLSPEC double _Complex mpc_get_dc (mpc_srcptr, mpc_rnd_t);
+__MPC_DECLSPEC long double _Complex mpc_get_ldc (mpc_srcptr, mpc_rnd_t);
+#endif
+
+#ifdef _GMP_H_HAVE_FILE
+__MPC_DECLSPEC int mpc_inp_str (mpc_ptr, FILE *, size_t *, int, mpc_rnd_t);
+__MPC_DECLSPEC size_t mpc_out_str (FILE *, int, size_t, mpc_srcptr, mpc_rnd_t);
+#endif
+
+#if defined (__cplusplus)
+}
+#endif
+
+#define mpc_realref(x) ((x)->re)
+#define mpc_imagref(x) ((x)->im)
+
+#define mpc_cmp_si(x, y) \
+ ( mpc_cmp_si_si ((x), (y), 0l) )
+#define mpc_ui_sub(x, y, z, r) mpc_ui_ui_sub (x, y, 0ul, z, r)
+
+/*
+ Define a fake mpfr_set_fr so that, for instance, mpc_set_fr_z would
+ be defined as follows:
+ mpc_set_fr_z (mpc_t rop, mpfr_t x, mpz_t y, mpc_rnd_t rnd)
+ MPC_SET_X_Y (fr, z, rop, x, y, rnd)
+*/
+#ifndef mpfr_set_fr
+#define mpfr_set_fr mpfr_set
+#endif
+#define MPC_SET_X_Y(real_t, imag_t, z, real_value, imag_value, rnd) \
+ { \
+ int _inex_re, _inex_im; \
+ _inex_re = (mpfr_set_ ## real_t) (mpc_realref (z), (real_value), MPC_RND_RE (rnd)); \
+ _inex_im = (mpfr_set_ ## imag_t) (mpc_imagref (z), (imag_value), MPC_RND_IM (rnd)); \
+ return MPC_INEX (_inex_re, _inex_im); \
+ }
+
+#endif /* ifndef __MPC_H */
diff --git a/mpc/src/mul.c b/mpc/src/mul.c
new file mode 100644
index 0000000000..2be9b8d646
--- /dev/null
+++ b/mpc/src/mul.c
@@ -0,0 +1,639 @@
+/* mpc_mul -- Multiply two complex numbers
+
+Copyright (C) 2002, 2004, 2005, 2008, 2009, 2010, 2011, 2012 INRIA
+
+This file is part of GNU MPC.
+
+GNU MPC is free software; you can redistribute it and/or modify it under
+the terms of the GNU Lesser General Public License as published by the
+Free Software Foundation; either version 3 of the License, or (at your
+option) any later version.
+
+GNU MPC 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 Lesser General Public License for
+more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+
+#include <stdio.h> /* for MPC_ASSERT */
+#include "mpc-impl.h"
+
+#define mpz_add_si(z,x,y) do { \
+ if (y >= 0) \
+ mpz_add_ui (z, x, (long int) y); \
+ else \
+ mpz_sub_ui (z, x, (long int) (-y)); \
+ } while (0);
+
+/* compute z=x*y when x has an infinite part */
+static int
+mul_infinite (mpc_ptr z, mpc_srcptr x, mpc_srcptr y)
+{
+ /* Let x=xr+i*xi and y=yr+i*yi; extract the signs of the operands */
+ int xrs = mpfr_signbit (mpc_realref (x)) ? -1 : 1;
+ int xis = mpfr_signbit (mpc_imagref (x)) ? -1 : 1;
+ int yrs = mpfr_signbit (mpc_realref (y)) ? -1 : 1;
+ int yis = mpfr_signbit (mpc_imagref (y)) ? -1 : 1;
+
+ int u, v;
+
+ /* compute the sign of
+ u = xrs * yrs * xr * yr - xis * yis * xi * yi
+ v = xrs * yis * xr * yi + xis * yrs * xi * yr
+ +1 if positive, -1 if negatiye, 0 if NaN */
+ if ( mpfr_nan_p (mpc_realref (x)) || mpfr_nan_p (mpc_imagref (x))
+ || mpfr_nan_p (mpc_realref (y)) || mpfr_nan_p (mpc_imagref (y))) {
+ u = 0;
+ v = 0;
+ }
+ else if (mpfr_inf_p (mpc_realref (x))) {
+ /* x = (+/-inf) xr + i*xi */
+ u = ( mpfr_zero_p (mpc_realref (y))
+ || (mpfr_inf_p (mpc_imagref (x)) && mpfr_zero_p (mpc_imagref (y)))
+ || (mpfr_zero_p (mpc_imagref (x)) && mpfr_inf_p (mpc_imagref (y)))
+ || ( (mpfr_inf_p (mpc_imagref (x)) || mpfr_inf_p (mpc_imagref (y)))
+ && xrs*yrs == xis*yis)
+ ? 0 : xrs * yrs);
+ v = ( mpfr_zero_p (mpc_imagref (y))
+ || (mpfr_inf_p (mpc_imagref (x)) && mpfr_zero_p (mpc_realref (y)))
+ || (mpfr_zero_p (mpc_imagref (x)) && mpfr_inf_p (mpc_realref (y)))
+ || ( (mpfr_inf_p (mpc_imagref (x)) || mpfr_inf_p (mpc_imagref (x)))
+ && xrs*yis != xis*yrs)
+ ? 0 : xrs * yis);
+ }
+ else {
+ /* x = xr + i*(+/-inf) with |xr| != inf */
+ u = ( mpfr_zero_p (mpc_imagref (y))
+ || (mpfr_zero_p (mpc_realref (x)) && mpfr_inf_p (mpc_realref (y)))
+ || (mpfr_inf_p (mpc_realref (y)) && xrs*yrs == xis*yis)
+ ? 0 : -xis * yis);
+ v = ( mpfr_zero_p (mpc_realref (y))
+ || (mpfr_zero_p (mpc_realref (x)) && mpfr_inf_p (mpc_imagref (y)))
+ || (mpfr_inf_p (mpc_imagref (y)) && xrs*yis != xis*yrs)
+ ? 0 : xis * yrs);
+ }
+
+ if (u == 0 && v == 0) {
+ /* Naive result is NaN+i*NaN. Obtain an infinity using the algorithm
+ given in Annex G.5.1 of the ISO C99 standard */
+ int xr = (mpfr_zero_p (mpc_realref (x)) || mpfr_nan_p (mpc_realref (x)) ? 0
+ : (mpfr_inf_p (mpc_realref (x)) ? 1 : 0));
+ int xi = (mpfr_zero_p (mpc_imagref (x)) || mpfr_nan_p (mpc_imagref (x)) ? 0
+ : (mpfr_inf_p (mpc_imagref (x)) ? 1 : 0));
+ int yr = (mpfr_zero_p (mpc_realref (y)) || mpfr_nan_p (mpc_realref (y)) ? 0 : 1);
+ int yi = (mpfr_zero_p (mpc_imagref (y)) || mpfr_nan_p (mpc_imagref (y)) ? 0 : 1);
+ if (mpc_inf_p (y)) {
+ yr = mpfr_inf_p (mpc_realref (y)) ? 1 : 0;
+ yi = mpfr_inf_p (mpc_imagref (y)) ? 1 : 0;
+ }
+
+ u = xrs * xr * yrs * yr - xis * xi * yis * yi;
+ v = xrs * xr * yis * yi + xis * xi * yrs * yr;
+ }
+
+ if (u == 0)
+ mpfr_set_nan (mpc_realref (z));
+ else
+ mpfr_set_inf (mpc_realref (z), u);
+
+ if (v == 0)
+ mpfr_set_nan (mpc_imagref (z));
+ else
+ mpfr_set_inf (mpc_imagref (z), v);
+
+ return MPC_INEX (0, 0); /* exact */
+}
+
+
+/* compute z = x*y for Im(y) == 0 */
+static int
+mul_real (mpc_ptr z, mpc_srcptr x, mpc_srcptr y, mpc_rnd_t rnd)
+{
+ int xrs, xis, yrs, yis;
+ int inex;
+
+ /* save signs of operands */
+ xrs = MPFR_SIGNBIT (mpc_realref (x));
+ xis = MPFR_SIGNBIT (mpc_imagref (x));
+ yrs = MPFR_SIGNBIT (mpc_realref (y));
+ yis = MPFR_SIGNBIT (mpc_imagref (y));
+
+ inex = mpc_mul_fr (z, x, mpc_realref (y), rnd);
+ /* Signs of zeroes may be wrong. Their correction does not change the
+ inexact flag. */
+ if (mpfr_zero_p (mpc_realref (z)))
+ mpfr_setsign (mpc_realref (z), mpc_realref (z), MPC_RND_RE(rnd) == GMP_RNDD
+ || (xrs != yrs && xis == yis), GMP_RNDN);
+ if (mpfr_zero_p (mpc_imagref (z)))
+ mpfr_setsign (mpc_imagref (z), mpc_imagref (z), MPC_RND_IM (rnd) == GMP_RNDD
+ || (xrs != yis && xis != yrs), GMP_RNDN);
+
+ return inex;
+}
+
+
+/* compute z = x*y for Re(y) == 0, and Im(x) != 0 and Im(y) != 0 */
+static int
+mul_imag (mpc_ptr z, mpc_srcptr x, mpc_srcptr y, mpc_rnd_t rnd)
+{
+ int sign;
+ int inex_re, inex_im;
+ int overlap = z == x || z == y;
+ mpc_t rop;
+
+ if (overlap)
+ mpc_init3 (rop, MPC_PREC_RE (z), MPC_PREC_IM (z));
+ else
+ rop [0] = z[0];
+
+ sign = (MPFR_SIGNBIT (mpc_realref (y)) != MPFR_SIGNBIT (mpc_imagref (x)))
+ && (MPFR_SIGNBIT (mpc_imagref (y)) != MPFR_SIGNBIT (mpc_realref (x)));
+
+ inex_re = -mpfr_mul (mpc_realref (rop), mpc_imagref (x), mpc_imagref (y),
+ INV_RND (MPC_RND_RE (rnd)));
+ mpfr_neg (mpc_realref (rop), mpc_realref (rop), GMP_RNDN); /* exact */
+ inex_im = mpfr_mul (mpc_imagref (rop), mpc_realref (x), mpc_imagref (y),
+ MPC_RND_IM (rnd));
+ mpc_set (z, rop, MPC_RNDNN);
+
+ /* Sign of zeroes may be wrong (note that Re(z) cannot be zero) */
+ if (mpfr_zero_p (mpc_imagref (z)))
+ mpfr_setsign (mpc_imagref (z), mpc_imagref (z), MPC_RND_IM (rnd) == GMP_RNDD
+ || sign, GMP_RNDN);
+
+ if (overlap)
+ mpc_clear (rop);
+
+ return MPC_INEX (inex_re, inex_im);
+}
+
+
+static int
+mpfr_fmma (mpfr_ptr z, mpfr_srcptr a, mpfr_srcptr b, mpfr_srcptr c,
+ mpfr_srcptr d, int sign, mpfr_rnd_t rnd)
+{
+ /* Computes z = ab+cd if sign >= 0, or z = ab-cd if sign < 0.
+ Assumes that a, b, c, d are finite and non-zero; so any multiplication
+ of two of them yielding an infinity is an overflow, and a
+ multiplication yielding 0 is an underflow.
+ Assumes further that z is distinct from a, b, c, d. */
+
+ int inex;
+ mpfr_t u, v;
+
+ /* u=a*b, v=sign*c*d exactly */
+ mpfr_init2 (u, mpfr_get_prec (a) + mpfr_get_prec (b));
+ mpfr_init2 (v, mpfr_get_prec (c) + mpfr_get_prec (d));
+ mpfr_mul (u, a, b, GMP_RNDN);
+ mpfr_mul (v, c, d, GMP_RNDN);
+ if (sign < 0)
+ mpfr_neg (v, v, GMP_RNDN);
+
+ /* tentatively compute z as u+v; here we need z to be distinct
+ from a, b, c, d to not lose the latter */
+ inex = mpfr_add (z, u, v, rnd);
+
+ if (mpfr_inf_p (z)) {
+ /* replace by "correctly rounded overflow" */
+ mpfr_set_si (z, (mpfr_signbit (z) ? -1 : 1), GMP_RNDN);
+ inex = mpfr_mul_2ui (z, z, mpfr_get_emax (), rnd);
+ }
+ else if (mpfr_zero_p (u) && !mpfr_zero_p (v)) {
+ /* exactly u underflowed, determine inexact flag */
+ inex = (mpfr_signbit (u) ? 1 : -1);
+ }
+ else if (mpfr_zero_p (v) && !mpfr_zero_p (u)) {
+ /* exactly v underflowed, determine inexact flag */
+ inex = (mpfr_signbit (v) ? 1 : -1);
+ }
+ else if (mpfr_nan_p (z) || (mpfr_zero_p (u) && mpfr_zero_p (v))) {
+ /* In the first case, u and v are infinities with opposite signs.
+ In the second case, u and v are zeroes; their sum may be 0 or the
+ least representable number, with a sign to be determined.
+ Redo the computations with mpz_t exponents */
+ mpfr_exp_t ea, eb, ec, ed;
+ mpz_t eu, ev;
+ /* cheat to work around the const qualifiers */
+
+ /* Normalise the input by shifting and keep track of the shifts in
+ the exponents of u and v */
+ ea = mpfr_get_exp (a);
+ eb = mpfr_get_exp (b);
+ ec = mpfr_get_exp (c);
+ ed = mpfr_get_exp (d);
+
+ mpfr_set_exp ((mpfr_ptr) a, (mpfr_prec_t) 0);
+ mpfr_set_exp ((mpfr_ptr) b, (mpfr_prec_t) 0);
+ mpfr_set_exp ((mpfr_ptr) c, (mpfr_prec_t) 0);
+ mpfr_set_exp ((mpfr_ptr) d, (mpfr_prec_t) 0);
+
+ mpz_init (eu);
+ mpz_init (ev);
+ mpz_set_si (eu, (long int) ea);
+ mpz_add_si (eu, eu, (long int) eb);
+ mpz_set_si (ev, (long int) ec);
+ mpz_add_si (ev, ev, (long int) ed);
+
+ /* recompute u and v and move exponents to eu and ev */
+ mpfr_mul (u, a, b, GMP_RNDN);
+ /* exponent of u is non-positive */
+ mpz_sub_ui (eu, eu, (unsigned long int) (-mpfr_get_exp (u)));
+ mpfr_set_exp (u, (mpfr_prec_t) 0);
+ mpfr_mul (v, c, d, GMP_RNDN);
+ if (sign < 0)
+ mpfr_neg (v, v, GMP_RNDN);
+ mpz_sub_ui (ev, ev, (unsigned long int) (-mpfr_get_exp (v)));
+ mpfr_set_exp (v, (mpfr_prec_t) 0);
+
+ if (mpfr_nan_p (z)) {
+ mpfr_exp_t emax = mpfr_get_emax ();
+ int overflow;
+ /* We have a = ma * 2^ea with 1/2 <= |ma| < 1 and ea <= emax, and
+ analogously for b. So eu <= 2*emax, and eu > emax since we have
+ an overflow. The same holds for ev. Shift u and v by as much as
+ possible so that one of them has exponent emax and the
+ remaining exponents in eu and ev are the same. Then carry out
+ the addition. Shifting u and v prevents an underflow. */
+ if (mpz_cmp (eu, ev) >= 0) {
+ mpfr_set_exp (u, emax);
+ mpz_sub_ui (eu, eu, (long int) emax);
+ mpz_sub (ev, ev, eu);
+ mpfr_set_exp (v, (mpfr_exp_t) mpz_get_ui (ev));
+ /* remaining common exponent is now in eu */
+ }
+ else {
+ mpfr_set_exp (v, emax);
+ mpz_sub_ui (ev, ev, (long int) emax);
+ mpz_sub (eu, eu, ev);
+ mpfr_set_exp (u, (mpfr_exp_t) mpz_get_ui (eu));
+ mpz_set (eu, ev);
+ /* remaining common exponent is now also in eu */
+ }
+ inex = mpfr_add (z, u, v, rnd);
+ /* Result is finite since u and v have different signs. */
+ overflow = mpfr_mul_2ui (z, z, mpz_get_ui (eu), rnd);
+ if (overflow)
+ inex = overflow;
+ }
+ else {
+ int underflow;
+ /* Addition of two zeroes with same sign. We have a = ma * 2^ea
+ with 1/2 <= |ma| < 1 and ea >= emin and similarly for b.
+ So 2*emin < 2*emin+1 <= eu < emin < 0, and analogously for v. */
+ mpfr_exp_t emin = mpfr_get_emin ();
+ if (mpz_cmp (eu, ev) <= 0) {
+ mpfr_set_exp (u, emin);
+ mpz_add_ui (eu, eu, (unsigned long int) (-emin));
+ mpz_sub (ev, ev, eu);
+ mpfr_set_exp (v, (mpfr_exp_t) mpz_get_si (ev));
+ }
+ else {
+ mpfr_set_exp (v, emin);
+ mpz_add_ui (ev, ev, (unsigned long int) (-emin));
+ mpz_sub (eu, eu, ev);
+ mpfr_set_exp (u, (mpfr_exp_t) mpz_get_si (eu));
+ mpz_set (eu, ev);
+ }
+ inex = mpfr_add (z, u, v, rnd);
+ mpz_neg (eu, eu);
+ underflow = mpfr_div_2ui (z, z, mpz_get_ui (eu), rnd);
+ if (underflow)
+ inex = underflow;
+ }
+
+ mpz_clear (eu);
+ mpz_clear (ev);
+
+ mpfr_set_exp ((mpfr_ptr) a, ea);
+ mpfr_set_exp ((mpfr_ptr) b, eb);
+ mpfr_set_exp ((mpfr_ptr) c, ec);
+ mpfr_set_exp ((mpfr_ptr) d, ed);
+ /* works also when some of a, b, c, d are not all distinct */
+ }
+
+ mpfr_clear (u);
+ mpfr_clear (v);
+
+ return inex;
+}
+
+
+int
+mpc_mul_naive (mpc_ptr z, mpc_srcptr x, mpc_srcptr y, mpc_rnd_t rnd)
+{
+ /* computes z=x*y by the schoolbook method, where x and y are assumed
+ to be finite and without zero parts */
+ int overlap, inex;
+ mpc_t rop;
+
+ MPC_ASSERT ( mpfr_regular_p (mpc_realref (x)) && mpfr_regular_p (mpc_imagref (x))
+ && mpfr_regular_p (mpc_realref (y)) && mpfr_regular_p (mpc_imagref (y)));
+ overlap = (z == x) || (z == y);
+ if (overlap)
+ mpc_init3 (rop, MPC_PREC_RE (z), MPC_PREC_IM (z));
+ else
+ rop [0] = z [0];
+
+ inex = MPC_INEX (mpfr_fmma (mpc_realref (rop), mpc_realref (x), mpc_realref (y), mpc_imagref (x),
+ mpc_imagref (y), -1, MPC_RND_RE (rnd)),
+ mpfr_fmma (mpc_imagref (rop), mpc_realref (x), mpc_imagref (y), mpc_imagref (x),
+ mpc_realref (y), +1, MPC_RND_IM (rnd)));
+
+ mpc_set (z, rop, MPC_RNDNN);
+ if (overlap)
+ mpc_clear (rop);
+
+ return inex;
+}
+
+
+int
+mpc_mul_karatsuba (mpc_ptr rop, mpc_srcptr op1, mpc_srcptr op2, mpc_rnd_t rnd)
+{
+ /* computes rop=op1*op2 by a Karatsuba algorithm, where op1 and op2
+ are assumed to be finite and without zero parts */
+ mpfr_srcptr a, b, c, d;
+ int mul_i, ok, inexact, mul_a, mul_c, inex_re = 0, inex_im = 0, sign_x, sign_u;
+ mpfr_t u, v, w, x;
+ mpfr_prec_t prec, prec_re, prec_u, prec_v, prec_w;
+ mpfr_rnd_t rnd_re, rnd_u;
+ int overlap;
+ /* true if rop == op1 or rop == op2 */
+ mpc_t result;
+ /* overlap is quite difficult to handle, because we have to tentatively
+ round the variable u in the end to either the real or the imaginary
+ part of rop (it is not possible to tell now whether the real or
+ imaginary part is used). If this fails, we have to start again and
+ need the correct values of op1 and op2.
+ So we just create a new variable for the result in this case. */
+ int loop;
+ const int MAX_MUL_LOOP = 1;
+
+ overlap = (rop == op1) || (rop == op2);
+ if (overlap)
+ mpc_init3 (result, MPC_PREC_RE (rop), MPC_PREC_IM (rop));
+ else
+ result [0] = rop [0];
+
+ a = mpc_realref(op1);
+ b = mpc_imagref(op1);
+ c = mpc_realref(op2);
+ d = mpc_imagref(op2);
+
+ /* (a + i*b) * (c + i*d) = [ac - bd] + i*[ad + bc] */
+
+ mul_i = 0; /* number of multiplications by i */
+ mul_a = 1; /* implicit factor for a */
+ mul_c = 1; /* implicit factor for c */
+
+ if (mpfr_cmp_abs (a, b) < 0)
+ {
+ MPFR_SWAP (a, b);
+ mul_i ++;
+ mul_a = -1; /* consider i * (a+i*b) = -b + i*a */
+ }
+
+ if (mpfr_cmp_abs (c, d) < 0)
+ {
+ MPFR_SWAP (c, d);
+ mul_i ++;
+ mul_c = -1; /* consider -d + i*c instead of c + i*d */
+ }
+
+ /* find the precision and rounding mode for the new real part */
+ if (mul_i % 2)
+ {
+ prec_re = MPC_PREC_IM(rop);
+ rnd_re = MPC_RND_IM(rnd);
+ }
+ else /* mul_i = 0 or 2 */
+ {
+ prec_re = MPC_PREC_RE(rop);
+ rnd_re = MPC_RND_RE(rnd);
+ }
+
+ if (mul_i)
+ rnd_re = INV_RND(rnd_re);
+
+ /* now |a| >= |b| and |c| >= |d| */
+ prec = MPC_MAX_PREC(rop);
+
+ mpfr_init2 (v, prec_v = mpfr_get_prec (a) + mpfr_get_prec (d));
+ mpfr_init2 (w, prec_w = mpfr_get_prec (b) + mpfr_get_prec (c));
+ mpfr_init2 (u, 2);
+ mpfr_init2 (x, 2);
+
+ inexact = mpfr_mul (v, a, d, GMP_RNDN);
+ if (inexact) {
+ /* over- or underflow */
+ ok = 0;
+ goto clear;
+ }
+ if (mul_a == -1)
+ mpfr_neg (v, v, GMP_RNDN);
+
+ inexact = mpfr_mul (w, b, c, GMP_RNDN);
+ if (inexact) {
+ /* over- or underflow */
+ ok = 0;
+ goto clear;
+ }
+ if (mul_c == -1)
+ mpfr_neg (w, w, GMP_RNDN);
+
+ /* compute sign(v-w) */
+ sign_x = mpfr_cmp_abs (v, w);
+ if (sign_x > 0)
+ sign_x = 2 * mpfr_sgn (v) - mpfr_sgn (w);
+ else if (sign_x == 0)
+ sign_x = mpfr_sgn (v) - mpfr_sgn (w);
+ else
+ sign_x = mpfr_sgn (v) - 2 * mpfr_sgn (w);
+
+ sign_u = mul_a * mpfr_sgn (a) * mul_c * mpfr_sgn (c);
+
+ if (sign_x * sign_u < 0)
+ { /* swap inputs */
+ MPFR_SWAP (a, c);
+ MPFR_SWAP (b, d);
+ mpfr_swap (v, w);
+ { int tmp; tmp = mul_a; mul_a = mul_c; mul_c = tmp; }
+ sign_x = - sign_x;
+ }
+
+ /* now sign_x * sign_u >= 0 */
+ loop = 0;
+ do
+ {
+ loop++;
+ /* the following should give failures with prob. <= 1/prec */
+ prec += mpc_ceil_log2 (prec) + 3;
+
+ mpfr_set_prec (u, prec_u = prec);
+ mpfr_set_prec (x, prec);
+
+ /* first compute away(b +/- a) and store it in u */
+ inexact = (mul_a == -1 ?
+ ROUND_AWAY (mpfr_sub (u, b, a, MPFR_RNDA), u) :
+ ROUND_AWAY (mpfr_add (u, b, a, MPFR_RNDA), u));
+
+ /* then compute away(+/-c - d) and store it in x */
+ inexact |= (mul_c == -1 ?
+ ROUND_AWAY (mpfr_add (x, c, d, MPFR_RNDA), x) :
+ ROUND_AWAY (mpfr_sub (x, c, d, MPFR_RNDA), x));
+ if (mul_c == -1)
+ mpfr_neg (x, x, GMP_RNDN);
+
+ if (inexact == 0)
+ mpfr_prec_round (u, prec_u = 2 * prec, GMP_RNDN);
+
+ /* compute away(u*x) and store it in u */
+ inexact |= ROUND_AWAY (mpfr_mul (u, u, x, MPFR_RNDA), u);
+ /* (a+b)*(c-d) */
+
+ /* if all computations are exact up to here, it may be that
+ the real part is exact, thus we need if possible to
+ compute v - w exactly */
+ if (inexact == 0)
+ {
+ mpfr_prec_t prec_x;
+ /* v and w are different from 0, so mpfr_get_exp is safe to use */
+ prec_x = SAFE_ABS (mpfr_exp_t, mpfr_get_exp (v) - mpfr_get_exp (w))
+ + MPC_MAX (prec_v, prec_w) + 1;
+ /* +1 is necessary for a potential carry */
+ /* ensure we do not use a too large precision */
+ if (prec_x > prec_u)
+ prec_x = prec_u;
+ if (prec_x > prec)
+ mpfr_prec_round (x, prec_x, GMP_RNDN);
+ }
+
+ rnd_u = (sign_u > 0) ? GMP_RNDU : GMP_RNDD;
+ inexact |= mpfr_sub (x, v, w, rnd_u); /* ad - bc */
+
+ /* in case u=0, ensure that rnd_u rounds x away from zero */
+ if (mpfr_sgn (u) == 0)
+ rnd_u = (mpfr_sgn (x) > 0) ? GMP_RNDU : GMP_RNDD;
+ inexact |= mpfr_add (u, u, x, rnd_u); /* ac - bd */
+
+ ok = inexact == 0 ||
+ mpfr_can_round (u, prec_u - 3, rnd_u, GMP_RNDZ,
+ prec_re + (rnd_re == GMP_RNDN));
+ /* this ensures both we can round correctly and determine the correct
+ inexact flag (for rounding to nearest) */
+ }
+ while (!ok && loop <= MAX_MUL_LOOP);
+ /* after MAX_MUL_LOOP rounds, use mpc_naive instead */
+
+ if (ok) {
+ /* if inexact is zero, then u is exactly ac-bd, otherwise fix the sign
+ of the inexact flag for u, which was rounded away from ac-bd */
+ if (inexact != 0)
+ inexact = mpfr_sgn (u);
+
+ if (mul_i == 0)
+ {
+ inex_re = mpfr_set (mpc_realref(result), u, MPC_RND_RE(rnd));
+ if (inex_re == 0)
+ {
+ inex_re = inexact; /* u is rounded away from 0 */
+ inex_im = mpfr_add (mpc_imagref(result), v, w, MPC_RND_IM(rnd));
+ }
+ else
+ inex_im = mpfr_add (mpc_imagref(result), v, w, MPC_RND_IM(rnd));
+ }
+ else if (mul_i == 1) /* (x+i*y)/i = y - i*x */
+ {
+ inex_im = mpfr_neg (mpc_imagref(result), u, MPC_RND_IM(rnd));
+ if (inex_im == 0)
+ {
+ inex_im = -inexact; /* u is rounded away from 0 */
+ inex_re = mpfr_add (mpc_realref(result), v, w, MPC_RND_RE(rnd));
+ }
+ else
+ inex_re = mpfr_add (mpc_realref(result), v, w, MPC_RND_RE(rnd));
+ }
+ else /* mul_i = 2, z/i^2 = -z */
+ {
+ inex_re = mpfr_neg (mpc_realref(result), u, MPC_RND_RE(rnd));
+ if (inex_re == 0)
+ {
+ inex_re = -inexact; /* u is rounded away from 0 */
+ inex_im = -mpfr_add (mpc_imagref(result), v, w,
+ INV_RND(MPC_RND_IM(rnd)));
+ mpfr_neg (mpc_imagref(result), mpc_imagref(result), MPC_RND_IM(rnd));
+ }
+ else
+ {
+ inex_im = -mpfr_add (mpc_imagref(result), v, w,
+ INV_RND(MPC_RND_IM(rnd)));
+ mpfr_neg (mpc_imagref(result), mpc_imagref(result), MPC_RND_IM(rnd));
+ }
+ }
+
+ mpc_set (rop, result, MPC_RNDNN);
+ }
+
+clear:
+ mpfr_clear (u);
+ mpfr_clear (v);
+ mpfr_clear (w);
+ mpfr_clear (x);
+ if (overlap)
+ mpc_clear (result);
+
+ if (ok)
+ return MPC_INEX(inex_re, inex_im);
+ else
+ return mpc_mul_naive (rop, op1, op2, rnd);
+}
+
+
+int
+mpc_mul (mpc_ptr a, mpc_srcptr b, mpc_srcptr c, mpc_rnd_t rnd)
+{
+ /* Conforming to ISO C99 standard (G.5.1 multiplicative operators),
+ infinities are treated specially if both parts are NaN when computed
+ naively. */
+ if (mpc_inf_p (b))
+ return mul_infinite (a, b, c);
+ if (mpc_inf_p (c))
+ return mul_infinite (a, c, b);
+
+ /* NaN contamination of both parts in result */
+ if (mpfr_nan_p (mpc_realref (b)) || mpfr_nan_p (mpc_imagref (b))
+ || mpfr_nan_p (mpc_realref (c)) || mpfr_nan_p (mpc_imagref (c))) {
+ mpfr_set_nan (mpc_realref (a));
+ mpfr_set_nan (mpc_imagref (a));
+ return MPC_INEX (0, 0);
+ }
+
+ /* check for real multiplication */
+ if (mpfr_zero_p (mpc_imagref (b)))
+ return mul_real (a, c, b, rnd);
+ if (mpfr_zero_p (mpc_imagref (c)))
+ return mul_real (a, b, c, rnd);
+
+ /* check for purely imaginary multiplication */
+ if (mpfr_zero_p (mpc_realref (b)))
+ return mul_imag (a, c, b, rnd);
+ if (mpfr_zero_p (mpc_realref (c)))
+ return mul_imag (a, b, c, rnd);
+
+ /* If the real and imaginary part of one argument have a very different */
+ /* exponent, it is not reasonable to use Karatsuba multiplication. */
+ if ( SAFE_ABS (mpfr_exp_t,
+ mpfr_get_exp (mpc_realref (b)) - mpfr_get_exp (mpc_imagref (b)))
+ > (mpfr_exp_t) MPC_MAX_PREC (b) / 2
+ || SAFE_ABS (mpfr_exp_t,
+ mpfr_get_exp (mpc_realref (c)) - mpfr_get_exp (mpc_imagref (c)))
+ > (mpfr_exp_t) MPC_MAX_PREC (c) / 2)
+ return mpc_mul_naive (a, b, c, rnd);
+ else
+ return ((MPC_MAX_PREC(a)
+ <= (mpfr_prec_t) MUL_KARATSUBA_THRESHOLD * BITS_PER_MP_LIMB)
+ ? mpc_mul_naive : mpc_mul_karatsuba) (a, b, c, rnd);
+}
diff --git a/mpc/src/mul_2si.c b/mpc/src/mul_2si.c
new file mode 100644
index 0000000000..14d0ca2516
--- /dev/null
+++ b/mpc/src/mul_2si.c
@@ -0,0 +1,32 @@
+/* mpc_mul_2si -- Multiply a complex number by 2^e.
+
+Copyright (C) 2012 INRIA
+
+This file is part of GNU MPC.
+
+GNU MPC is free software; you can redistribute it and/or modify it under
+the terms of the GNU Lesser General Public License as published by the
+Free Software Foundation; either version 3 of the License, or (at your
+option) any later version.
+
+GNU MPC 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 Lesser General Public License for
+more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+
+#include "mpc-impl.h"
+
+int
+mpc_mul_2si (mpc_ptr a, mpc_srcptr b, long int c, mpc_rnd_t rnd)
+{
+ int inex_re, inex_im;
+
+ inex_re = mpfr_mul_2si (mpc_realref(a), mpc_realref(b), c, MPC_RND_RE(rnd));
+ inex_im = mpfr_mul_2si (mpc_imagref(a), mpc_imagref(b), c, MPC_RND_IM(rnd));
+
+ return MPC_INEX(inex_re, inex_im);
+}
diff --git a/mpc/src/mul_2ui.c b/mpc/src/mul_2ui.c
new file mode 100644
index 0000000000..46aa788ec9
--- /dev/null
+++ b/mpc/src/mul_2ui.c
@@ -0,0 +1,32 @@
+/* mpc_mul_2ui -- Multiply a complex number by 2^e.
+
+Copyright (C) 2002, 2009, 2011, 2012 INRIA
+
+This file is part of GNU MPC.
+
+GNU MPC is free software; you can redistribute it and/or modify it under
+the terms of the GNU Lesser General Public License as published by the
+Free Software Foundation; either version 3 of the License, or (at your
+option) any later version.
+
+GNU MPC 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 Lesser General Public License for
+more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+
+#include "mpc-impl.h"
+
+int
+mpc_mul_2ui (mpc_ptr a, mpc_srcptr b, unsigned long int c, mpc_rnd_t rnd)
+{
+ int inex_re, inex_im;
+
+ inex_re = mpfr_mul_2ui (mpc_realref(a), mpc_realref(b), c, MPC_RND_RE(rnd));
+ inex_im = mpfr_mul_2ui (mpc_imagref(a), mpc_imagref(b), c, MPC_RND_IM(rnd));
+
+ return MPC_INEX(inex_re, inex_im);
+}
diff --git a/mpc/src/mul_fr.c b/mpc/src/mul_fr.c
new file mode 100644
index 0000000000..bd3574d857
--- /dev/null
+++ b/mpc/src/mul_fr.c
@@ -0,0 +1,43 @@
+/* mpc_mul_fr -- Multiply a complex number by a floating-point number.
+
+Copyright (C) 2002, 2008, 2009, 2010, 2011 INRIA
+
+This file is part of GNU MPC.
+
+GNU MPC is free software; you can redistribute it and/or modify it under
+the terms of the GNU Lesser General Public License as published by the
+Free Software Foundation; either version 3 of the License, or (at your
+option) any later version.
+
+GNU MPC 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 Lesser General Public License for
+more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+
+#include "mpc-impl.h"
+
+int
+mpc_mul_fr (mpc_ptr a, mpc_srcptr b, mpfr_srcptr c, mpc_rnd_t rnd)
+{
+ int inex_re, inex_im;
+ mpfr_t real;
+
+ if (c == mpc_realref (a))
+ /* We have to use a temporary variable. */
+ mpfr_init2 (real, MPC_PREC_RE (a));
+ else
+ real [0] = mpc_realref (a) [0];
+
+ inex_re = mpfr_mul (real, mpc_realref(b), c, MPC_RND_RE(rnd));
+ inex_im = mpfr_mul (mpc_imagref(a), mpc_imagref(b), c, MPC_RND_IM(rnd));
+ mpfr_set (mpc_realref (a), real, GMP_RNDN); /* exact */
+
+ if (c == mpc_realref (a))
+ mpfr_clear (real);
+
+ return MPC_INEX(inex_re, inex_im);
+}
diff --git a/mpc/src/mul_i.c b/mpc/src/mul_i.c
new file mode 100644
index 0000000000..591b0c6d7f
--- /dev/null
+++ b/mpc/src/mul_i.c
@@ -0,0 +1,80 @@
+/* mpc_mul_i -- Multiply a complex number by plus or minus i.
+
+Copyright (C) 2005, 2009, 2010, 2011 INRIA
+
+This file is part of GNU MPC.
+
+GNU MPC is free software; you can redistribute it and/or modify it under
+the terms of the GNU Lesser General Public License as published by the
+Free Software Foundation; either version 3 of the License, or (at your
+option) any later version.
+
+GNU MPC 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 Lesser General Public License for
+more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+
+#include "mpc-impl.h"
+
+int
+mpc_mul_i (mpc_ptr a, mpc_srcptr b, int sign, mpc_rnd_t rnd)
+/* if sign is >= 0, multiply by i, otherwise by -i */
+{
+ int inex_re, inex_im;
+ mpfr_t tmp;
+
+ /* Treat the most probable case of compatible precisions first */
+ if ( MPC_PREC_RE (b) == MPC_PREC_IM (a)
+ && MPC_PREC_IM (b) == MPC_PREC_RE (a))
+ {
+ if (a == b)
+ mpfr_swap (mpc_realref (a), mpc_imagref (a));
+ else
+ {
+ mpfr_set (mpc_realref (a), mpc_imagref (b), GMP_RNDN);
+ mpfr_set (mpc_imagref (a), mpc_realref (b), GMP_RNDN);
+ }
+ if (sign >= 0)
+ MPFR_CHANGE_SIGN (mpc_realref (a));
+ else
+ MPFR_CHANGE_SIGN (mpc_imagref (a));
+ inex_re = 0;
+ inex_im = 0;
+ }
+ else
+ {
+ if (a == b)
+ {
+ mpfr_init2 (tmp, MPC_PREC_RE (a));
+ if (sign >= 0)
+ {
+ inex_re = mpfr_neg (tmp, mpc_imagref (b), MPC_RND_RE (rnd));
+ inex_im = mpfr_set (mpc_imagref (a), mpc_realref (b), MPC_RND_IM (rnd));
+ }
+ else
+ {
+ inex_re = mpfr_set (tmp, mpc_imagref (b), MPC_RND_RE (rnd));
+ inex_im = mpfr_neg (mpc_imagref (a), mpc_realref (b), MPC_RND_IM (rnd));
+ }
+ mpfr_clear (mpc_realref (a));
+ mpc_realref (a)[0] = tmp [0];
+ }
+ else
+ if (sign >= 0)
+ {
+ inex_re = mpfr_neg (mpc_realref (a), mpc_imagref (b), MPC_RND_RE (rnd));
+ inex_im = mpfr_set (mpc_imagref (a), mpc_realref (b), MPC_RND_IM (rnd));
+ }
+ else
+ {
+ inex_re = mpfr_set (mpc_realref (a), mpc_imagref (b), MPC_RND_RE (rnd));
+ inex_im = mpfr_neg (mpc_imagref (a), mpc_realref (b), MPC_RND_IM (rnd));
+ }
+ }
+
+ return MPC_INEX(inex_re, inex_im);
+}
diff --git a/mpc/src/mul_si.c b/mpc/src/mul_si.c
new file mode 100644
index 0000000000..f539d8b075
--- /dev/null
+++ b/mpc/src/mul_si.c
@@ -0,0 +1,32 @@
+/* mpc_mul_si -- Multiply a complex number by a signed integer.
+
+Copyright (C) 2005, 2009, 2011 INRIA
+
+This file is part of GNU MPC.
+
+GNU MPC is free software; you can redistribute it and/or modify it under
+the terms of the GNU Lesser General Public License as published by the
+Free Software Foundation; either version 3 of the License, or (at your
+option) any later version.
+
+GNU MPC 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 Lesser General Public License for
+more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+
+#include "mpc-impl.h"
+
+int
+mpc_mul_si (mpc_ptr a, mpc_srcptr b, long int c, mpc_rnd_t rnd)
+{
+ int inex_re, inex_im;
+
+ inex_re = mpfr_mul_si (mpc_realref(a), mpc_realref(b), c, MPC_RND_RE(rnd));
+ inex_im = mpfr_mul_si (mpc_imagref(a), mpc_imagref(b), c, MPC_RND_IM(rnd));
+
+ return MPC_INEX(inex_re, inex_im);
+}
diff --git a/mpc/src/mul_ui.c b/mpc/src/mul_ui.c
new file mode 100644
index 0000000000..922e4b3777
--- /dev/null
+++ b/mpc/src/mul_ui.c
@@ -0,0 +1,32 @@
+/* mpc_mul_ui -- Multiply a complex number by a nonnegative integer.
+
+Copyright (C) 2002, 2009, 2011 INRIA
+
+This file is part of GNU MPC.
+
+GNU MPC is free software; you can redistribute it and/or modify it under
+the terms of the GNU Lesser General Public License as published by the
+Free Software Foundation; either version 3 of the License, or (at your
+option) any later version.
+
+GNU MPC 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 Lesser General Public License for
+more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+
+#include "mpc-impl.h"
+
+int
+mpc_mul_ui (mpc_ptr a, mpc_srcptr b, unsigned long int c, mpc_rnd_t rnd)
+{
+ int inex_re, inex_im;
+
+ inex_re = mpfr_mul_ui (mpc_realref(a), mpc_realref(b), c, MPC_RND_RE(rnd));
+ inex_im = mpfr_mul_ui (mpc_imagref(a), mpc_imagref(b), c, MPC_RND_IM(rnd));
+
+ return MPC_INEX(inex_re, inex_im);
+}
diff --git a/mpc/src/neg.c b/mpc/src/neg.c
new file mode 100644
index 0000000000..2aae7ca4db
--- /dev/null
+++ b/mpc/src/neg.c
@@ -0,0 +1,32 @@
+/* mpc_neg -- Negate a complex number.
+
+Copyright (C) 2002, 2009, 2011 INRIA
+
+This file is part of GNU MPC.
+
+GNU MPC is free software; you can redistribute it and/or modify it under
+the terms of the GNU Lesser General Public License as published by the
+Free Software Foundation; either version 3 of the License, or (at your
+option) any later version.
+
+GNU MPC 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 Lesser General Public License for
+more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+
+#include "mpc-impl.h"
+
+int
+mpc_neg (mpc_ptr a, mpc_srcptr b, mpc_rnd_t rnd)
+{
+ int inex_re, inex_im;
+
+ inex_re = mpfr_neg (mpc_realref(a), mpc_realref(b), MPC_RND_RE(rnd));
+ inex_im = mpfr_neg (mpc_imagref(a), mpc_imagref(b), MPC_RND_IM(rnd));
+
+ return MPC_INEX(inex_re, inex_im);
+}
diff --git a/mpc/src/norm.c b/mpc/src/norm.c
new file mode 100644
index 0000000000..ab413b6798
--- /dev/null
+++ b/mpc/src/norm.c
@@ -0,0 +1,182 @@
+/* mpc_norm -- Square of the norm of a complex number.
+
+Copyright (C) 2002, 2005, 2008, 2009, 2010, 2011 INRIA
+
+This file is part of GNU MPC.
+
+GNU MPC is free software; you can redistribute it and/or modify it under
+the terms of the GNU Lesser General Public License as published by the
+Free Software Foundation; either version 3 of the License, or (at your
+option) any later version.
+
+GNU MPC 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 Lesser General Public License for
+more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+
+#include <stdio.h> /* for MPC_ASSERT */
+#include "mpc-impl.h"
+
+/* a <- norm(b) = b * conj(b)
+ (the rounding mode is mpfr_rnd_t here since we return an mpfr number) */
+int
+mpc_norm (mpfr_ptr a, mpc_srcptr b, mpfr_rnd_t rnd)
+{
+ int inexact;
+ int saved_underflow, saved_overflow;
+
+ /* handling of special values; consistent with abs in that
+ norm = abs^2; so norm (+-inf, xxx) = norm (xxx, +-inf) = +inf */
+ if (!mpc_fin_p (b))
+ return mpc_abs (a, b, rnd);
+ else if (mpfr_zero_p (mpc_realref (b))) {
+ if (mpfr_zero_p (mpc_imagref (b)))
+ return mpfr_set_ui (a, 0, rnd); /* +0 */
+ else
+ return mpfr_sqr (a, mpc_imagref (b), rnd);
+ }
+ else if (mpfr_zero_p (mpc_imagref (b)))
+ return mpfr_sqr (a, mpc_realref (b), rnd); /* Re(b) <> 0 */
+
+ else /* everything finite and non-zero */ {
+ mpfr_t u, v, res;
+ mpfr_prec_t prec, prec_u, prec_v;
+ int loops;
+ const int max_loops = 2;
+ /* switch to exact squarings when loops==max_loops */
+
+ prec = mpfr_get_prec (a);
+
+ mpfr_init (u);
+ mpfr_init (v);
+ mpfr_init (res);
+
+ /* save the underflow or overflow flags from MPFR */
+ saved_underflow = mpfr_underflow_p ();
+ saved_overflow = mpfr_overflow_p ();
+
+ loops = 0;
+ mpfr_clear_underflow ();
+ mpfr_clear_overflow ();
+ do {
+ loops++;
+ prec += mpc_ceil_log2 (prec) + 3;
+ if (loops >= max_loops) {
+ prec_u = 2 * MPC_PREC_RE (b);
+ prec_v = 2 * MPC_PREC_IM (b);
+ }
+ else {
+ prec_u = MPC_MIN (prec, 2 * MPC_PREC_RE (b));
+ prec_v = MPC_MIN (prec, 2 * MPC_PREC_IM (b));
+ }
+
+ mpfr_set_prec (u, prec_u);
+ mpfr_set_prec (v, prec_v);
+
+ inexact = mpfr_sqr (u, mpc_realref(b), GMP_RNDD); /* err <= 1 ulp in prec */
+ inexact |= mpfr_sqr (v, mpc_imagref(b), GMP_RNDD); /* err <= 1 ulp in prec */
+
+ /* If loops = max_loops, inexact should be 0 here, except in case
+ of underflow or overflow.
+ If loops < max_loops and inexact is zero, we can exit the
+ while-loop since it only remains to add u and v into a. */
+ if (inexact) {
+ mpfr_set_prec (res, prec);
+ mpfr_add (res, u, v, GMP_RNDD); /* err <= 3 ulp in prec */
+ }
+
+ } while (loops < max_loops && inexact != 0
+ && !mpfr_can_round (res, prec - 2, GMP_RNDD, GMP_RNDU,
+ mpfr_get_prec (a) + (rnd == GMP_RNDN)));
+
+ if (!inexact)
+ /* squarings were exact, neither underflow nor overflow */
+ inexact = mpfr_add (a, u, v, rnd);
+ /* if there was an overflow in Re(b)^2 or Im(b)^2 or their sum,
+ since the norm is larger, there is an overflow for the norm */
+ else if (mpfr_overflow_p ()) {
+ /* replace by "correctly rounded overflow" */
+ mpfr_set_ui (a, 1ul, GMP_RNDN);
+ inexact = mpfr_mul_2ui (a, a, mpfr_get_emax (), rnd);
+ }
+ else if (mpfr_underflow_p ()) {
+ /* necessarily one of the squarings did underflow (otherwise their
+ sum could not underflow), thus one of u, v is zero. */
+ mpfr_exp_t emin = mpfr_get_emin ();
+
+ /* Now either both u and v are zero, or u is zero and v exact,
+ or v is zero and u exact.
+ In the latter case, Im(b)^2 < 2^(emin-1).
+ If ulp(u) >= 2^(emin+1) and norm(b) is not exactly
+ representable at the target precision, then rounding u+Im(b)^2
+ is equivalent to rounding u+2^(emin-1).
+ For instance, if exp(u)>0 and the target precision is smaller
+ than about |emin|, the norm is not representable. To make the
+ scaling in the "else" case work without underflow, we test
+ whether exp(u) is larger than a small negative number instead.
+ The second case is handled analogously. */
+ if (!mpfr_zero_p (u)
+ && mpfr_get_exp (u) - 2 * (mpfr_exp_t) prec_u > emin
+ && mpfr_get_exp (u) > -10) {
+ mpfr_set_prec (v, MPFR_PREC_MIN);
+ mpfr_set_ui_2exp (v, 1, emin - 1, GMP_RNDZ);
+ inexact = mpfr_add (a, u, v, rnd);
+ }
+ else if (!mpfr_zero_p (v)
+ && mpfr_get_exp (v) - 2 * (mpfr_exp_t) prec_v > emin
+ && mpfr_get_exp (v) > -10) {
+ mpfr_set_prec (u, MPFR_PREC_MIN);
+ mpfr_set_ui_2exp (u, 1, emin - 1, GMP_RNDZ);
+ inexact = mpfr_add (a, u, v, rnd);
+ }
+ else {
+ unsigned long int scale, exp_re, exp_im;
+ int inex_underflow;
+
+ /* scale the input to an average exponent close to 0 */
+ exp_re = (unsigned long int) (-mpfr_get_exp (mpc_realref (b)));
+ exp_im = (unsigned long int) (-mpfr_get_exp (mpc_imagref (b)));
+ scale = exp_re / 2 + exp_im / 2 + (exp_re % 2 + exp_im % 2) / 2;
+ /* (exp_re + exp_im) / 2, computed in a way avoiding
+ integer overflow */
+ if (mpfr_zero_p (u)) {
+ /* recompute the scaled value exactly */
+ mpfr_mul_2ui (u, mpc_realref (b), scale, GMP_RNDN);
+ mpfr_sqr (u, u, GMP_RNDN);
+ }
+ else /* just scale */
+ mpfr_mul_2ui (u, u, 2*scale, GMP_RNDN);
+ if (mpfr_zero_p (v)) {
+ mpfr_mul_2ui (v, mpc_imagref (b), scale, GMP_RNDN);
+ mpfr_sqr (v, v, GMP_RNDN);
+ }
+ else
+ mpfr_mul_2ui (v, v, 2*scale, GMP_RNDN);
+
+ inexact = mpfr_add (a, u, v, rnd);
+ mpfr_clear_underflow ();
+ inex_underflow = mpfr_div_2ui (a, a, 2*scale, rnd);
+ if (mpfr_underflow_p ())
+ inexact = inex_underflow;
+ }
+ }
+ else /* no problems, ternary value due to mpfr_can_round trick */
+ inexact = mpfr_set (a, res, rnd);
+
+ /* restore underflow and overflow flags from MPFR */
+ if (saved_underflow)
+ mpfr_set_underflow ();
+ if (saved_overflow)
+ mpfr_set_overflow ();
+
+ mpfr_clear (u);
+ mpfr_clear (v);
+ mpfr_clear (res);
+ }
+
+ return inexact;
+}
diff --git a/mpc/src/out_str.c b/mpc/src/out_str.c
new file mode 100644
index 0000000000..87cc823308
--- /dev/null
+++ b/mpc/src/out_str.c
@@ -0,0 +1,39 @@
+/* mpc_out_str -- Output a complex number on a given stream.
+
+Copyright (C) 2009, 2011 INRIA
+
+This file is part of GNU MPC.
+
+GNU MPC is free software; you can redistribute it and/or modify it under
+the terms of the GNU Lesser General Public License as published by the
+Free Software Foundation; either version 3 of the License, or (at your
+option) any later version.
+
+GNU MPC 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 Lesser General Public License for
+more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+
+#include <stdio.h> /* for FILE */
+#include <ctype.h>
+#include "mpc-impl.h"
+
+size_t
+mpc_out_str (FILE *stream, int base, size_t n, mpc_srcptr op, mpc_rnd_t rnd) {
+ size_t size = 3; /* for '(', ' ' and ')' */
+
+ if (stream == NULL)
+ stream = stdout; /* fprintf does not allow NULL as first argument */
+
+ fprintf (stream, "(");
+ size += mpfr_out_str (stream, base, n, mpc_realref(op), MPC_RND_RE(rnd));
+ fprintf (stream, " ");
+ size += mpfr_out_str (stream, base, n, mpc_imagref(op), MPC_RND_RE(rnd));
+ fprintf (stream, ")");
+
+ return size;
+}
diff --git a/mpc/src/pow.c b/mpc/src/pow.c
new file mode 100644
index 0000000000..2525644a4c
--- /dev/null
+++ b/mpc/src/pow.c
@@ -0,0 +1,818 @@
+/* mpc_pow -- Raise a complex number to the power of another complex number.
+
+Copyright (C) 2009, 2010, 2011, 2012 INRIA
+
+This file is part of GNU MPC.
+
+GNU MPC is free software; you can redistribute it and/or modify it under
+the terms of the GNU Lesser General Public License as published by the
+Free Software Foundation; either version 3 of the License, or (at your
+option) any later version.
+
+GNU MPC 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 Lesser General Public License for
+more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+
+#include <stdio.h> /* for MPC_ASSERT */
+#include "mpc-impl.h"
+
+/* Return non-zero iff c+i*d is an exact square (a+i*b)^2,
+ with a, b both of the form m*2^e with m, e integers.
+ If so, returns in a+i*b the corresponding square root, with a >= 0.
+ The variables a, b must not overlap with c, d.
+
+ We have c = a^2 - b^2 and d = 2*a*b.
+
+ If one of a, b is exact, then both are (see algorithms.tex).
+
+ Case 1: a <> 0 and b <> 0.
+ Let a = m*2^e and b = n*2^f with m, e, n, f integers, m and n odd
+ (we will treat apart the case a = 0 or b = 0).
+ Then 2*a*b = m*n*2^(e+f+1), thus necessarily e+f >= -1.
+ Assume e < 0, then f >= 0, then a^2 - b^2 = m^2*2^(2e) - n^2*2^(2f) cannot
+ be an integer, since n^2*2^(2f) is an integer, and m^2*2^(2e) is not.
+ Similarly when f < 0 (and thus e >= 0).
+ Thus we have e, f >= 0, and a, b are both integers.
+ Let A = 2a^2, then eliminating b between c = a^2 - b^2 and d = 2*a*b
+ gives A^2 - 2c*A - d^2 = 0, which has solutions c +/- sqrt(c^2+d^2).
+ We thus need c^2+d^2 to be a square, and c + sqrt(c^2+d^2) --- the solution
+ we are interested in --- to be two times a square. Then b = d/(2a) is
+ necessarily an integer.
+
+ Case 2: a = 0. Then d is necessarily zero, thus it suffices to check
+ whether c = -b^2, i.e., if -c is a square.
+
+ Case 3: b = 0. Then d is necessarily zero, thus it suffices to check
+ whether c = a^2, i.e., if c is a square.
+*/
+static int
+mpc_perfect_square_p (mpz_t a, mpz_t b, mpz_t c, mpz_t d)
+{
+ if (mpz_cmp_ui (d, 0) == 0) /* case a = 0 or b = 0 */
+ {
+ /* necessarily c < 0 here, since we have already considered the case
+ where x is real non-negative and y is real */
+ MPC_ASSERT (mpz_cmp_ui (c, 0) < 0);
+ mpz_neg (b, c);
+ if (mpz_perfect_square_p (b)) /* case 2 above */
+ {
+ mpz_sqrt (b, b);
+ mpz_set_ui (a, 0);
+ return 1; /* c + i*d = (0 + i*b)^2 */
+ }
+ }
+ else /* both a and b are non-zero */
+ {
+ if (mpz_divisible_2exp_p (d, 1) == 0)
+ return 0; /* d must be even */
+ mpz_mul (a, c, c);
+ mpz_addmul (a, d, d); /* c^2 + d^2 */
+ if (mpz_perfect_square_p (a))
+ {
+ mpz_sqrt (a, a);
+ mpz_add (a, c, a); /* c + sqrt(c^2+d^2) */
+ if (mpz_divisible_2exp_p (a, 1))
+ {
+ mpz_tdiv_q_2exp (a, a, 1);
+ if (mpz_perfect_square_p (a))
+ {
+ mpz_sqrt (a, a);
+ mpz_tdiv_q_2exp (b, d, 1); /* d/2 */
+ mpz_divexact (b, b, a); /* d/(2a) */
+ return 1;
+ }
+ }
+ }
+ }
+ return 0; /* not a square */
+}
+
+/* fix the sign of Re(z) or Im(z) in case it is zero,
+ and Re(x) is zero.
+ sign_eps is 0 if Re(x) = +0, 1 if Re(x) = -0
+ sign_a is the sign bit of Im(x).
+ Assume y is an integer (does nothing otherwise).
+*/
+static void
+fix_sign (mpc_ptr z, int sign_eps, int sign_a, mpfr_srcptr y)
+{
+ int ymod4 = -1;
+ mpfr_exp_t ey;
+ mpz_t my;
+ unsigned long int t;
+
+ mpz_init (my);
+
+ ey = mpfr_get_z_exp (my, y);
+ /* normalize so that my is odd */
+ t = mpz_scan1 (my, 0);
+ ey += (mpfr_exp_t) t;
+ mpz_tdiv_q_2exp (my, my, t);
+ /* y = my*2^ey */
+
+ /* compute y mod 4 (in case y is an integer) */
+ if (ey >= 2)
+ ymod4 = 0;
+ else if (ey == 1)
+ ymod4 = mpz_tstbit (my, 0) * 2; /* correct if my < 0 */
+ else if (ey == 0)
+ {
+ ymod4 = mpz_tstbit (my, 1) * 2 + mpz_tstbit (my, 0);
+ if (mpz_cmp_ui (my , 0) < 0)
+ ymod4 = 4 - ymod4;
+ }
+ else /* y is not an integer */
+ goto end;
+
+ if (mpfr_zero_p (mpc_realref(z)))
+ {
+ /* we assume y is always integer in that case (FIXME: prove it):
+ (eps+I*a)^y = +0 + I*a^y for y = 1 mod 4 and sign_eps = 0
+ (eps+I*a)^y = -0 - I*a^y for y = 3 mod 4 and sign_eps = 0 */
+ MPC_ASSERT (ymod4 == 1 || ymod4 == 3);
+ if ((ymod4 == 3 && sign_eps == 0) ||
+ (ymod4 == 1 && sign_eps == 1))
+ mpfr_neg (mpc_realref(z), mpc_realref(z), GMP_RNDZ);
+ }
+ else if (mpfr_zero_p (mpc_imagref(z)))
+ {
+ /* we assume y is always integer in that case (FIXME: prove it):
+ (eps+I*a)^y = a^y - 0*I for y = 0 mod 4 and sign_a = sign_eps
+ (eps+I*a)^y = -a^y +0*I for y = 2 mod 4 and sign_a = sign_eps */
+ MPC_ASSERT (ymod4 == 0 || ymod4 == 2);
+ if ((ymod4 == 0 && sign_a == sign_eps) ||
+ (ymod4 == 2 && sign_a != sign_eps))
+ mpfr_neg (mpc_imagref(z), mpc_imagref(z), GMP_RNDZ);
+ }
+
+ end:
+ mpz_clear (my);
+}
+
+/* If x^y is exactly representable (with maybe a larger precision than z),
+ round it in z and return the (mpc) inexact flag in [0, 10].
+
+ If x^y is not exactly representable, return -1.
+
+ If intermediate computations lead to numbers of more than maxprec bits,
+ then abort and return -2 (in that case, to avoid loops, mpc_pow_exact
+ should be called again with a larger value of maxprec).
+
+ Assume one of Re(x) or Im(x) is non-zero, and y is non-zero (y is real).
+
+ Warning: z and x might be the same variable, same for Re(z) or Im(z) and y.
+
+ In case -1 or -2 is returned, z is not modified.
+*/
+static int
+mpc_pow_exact (mpc_ptr z, mpc_srcptr x, mpfr_srcptr y, mpc_rnd_t rnd,
+ mpfr_prec_t maxprec)
+{
+ mpfr_exp_t ec, ed, ey;
+ mpz_t my, a, b, c, d, u;
+ unsigned long int t;
+ int ret = -2;
+ int sign_rex = mpfr_signbit (mpc_realref(x));
+ int sign_imx = mpfr_signbit (mpc_imagref(x));
+ int x_imag = mpfr_zero_p (mpc_realref(x));
+ int z_is_y = 0;
+ mpfr_t copy_of_y;
+
+ if (mpc_realref (z) == y || mpc_imagref (z) == y)
+ {
+ z_is_y = 1;
+ mpfr_init2 (copy_of_y, mpfr_get_prec (y));
+ mpfr_set (copy_of_y, y, GMP_RNDN);
+ }
+
+ mpz_init (my);
+ mpz_init (a);
+ mpz_init (b);
+ mpz_init (c);
+ mpz_init (d);
+ mpz_init (u);
+
+ ey = mpfr_get_z_exp (my, y);
+ /* normalize so that my is odd */
+ t = mpz_scan1 (my, 0);
+ ey += (mpfr_exp_t) t;
+ mpz_tdiv_q_2exp (my, my, t);
+ /* y = my*2^ey with my odd */
+
+ if (x_imag)
+ {
+ mpz_set_ui (c, 0);
+ ec = 0;
+ }
+ else
+ ec = mpfr_get_z_exp (c, mpc_realref(x));
+ if (mpfr_zero_p (mpc_imagref(x)))
+ {
+ mpz_set_ui (d, 0);
+ ed = ec;
+ }
+ else
+ {
+ ed = mpfr_get_z_exp (d, mpc_imagref(x));
+ if (x_imag)
+ ec = ed;
+ }
+ /* x = c*2^ec + I * d*2^ed */
+ /* equalize the exponents of x */
+ if (ec < ed)
+ {
+ mpz_mul_2exp (d, d, (unsigned long int) (ed - ec));
+ if ((mpfr_prec_t) mpz_sizeinbase (d, 2) > maxprec)
+ goto end;
+ }
+ else if (ed < ec)
+ {
+ mpz_mul_2exp (c, c, (unsigned long int) (ec - ed));
+ if ((mpfr_prec_t) mpz_sizeinbase (c, 2) > maxprec)
+ goto end;
+ ec = ed;
+ }
+ /* now ec=ed and x = (c + I * d) * 2^ec */
+
+ /* divide by two if possible */
+ if (mpz_cmp_ui (c, 0) == 0)
+ {
+ t = mpz_scan1 (d, 0);
+ mpz_tdiv_q_2exp (d, d, t);
+ ec += (mpfr_exp_t) t;
+ }
+ else if (mpz_cmp_ui (d, 0) == 0)
+ {
+ t = mpz_scan1 (c, 0);
+ mpz_tdiv_q_2exp (c, c, t);
+ ec += (mpfr_exp_t) t;
+ }
+ else /* neither c nor d is zero */
+ {
+ unsigned long v;
+ t = mpz_scan1 (c, 0);
+ v = mpz_scan1 (d, 0);
+ if (v < t)
+ t = v;
+ mpz_tdiv_q_2exp (c, c, t);
+ mpz_tdiv_q_2exp (d, d, t);
+ ec += (mpfr_exp_t) t;
+ }
+
+ /* now either one of c, d is odd */
+
+ while (ey < 0)
+ {
+ /* check if x is a square */
+ if (ec & 1)
+ {
+ mpz_mul_2exp (c, c, 1);
+ mpz_mul_2exp (d, d, 1);
+ ec --;
+ }
+ /* now ec is even */
+ if (mpc_perfect_square_p (a, b, c, d) == 0)
+ break;
+ mpz_swap (a, c);
+ mpz_swap (b, d);
+ ec /= 2;
+ ey ++;
+ }
+
+ if (ey < 0)
+ {
+ ret = -1; /* not representable */
+ goto end;
+ }
+
+ /* Now ey >= 0, it thus suffices to check that x^my is representable.
+ If my > 0, this is always true. If my < 0, we first try to invert
+ (c+I*d)*2^ec.
+ */
+ if (mpz_cmp_ui (my, 0) < 0)
+ {
+ /* If my < 0, 1 / (c + I*d) = (c - I*d)/(c^2 + d^2), thus a sufficient
+ condition is that c^2 + d^2 is a power of two, assuming |c| <> |d|.
+ Assume a prime p <> 2 divides c^2 + d^2,
+ then if p does not divide c or d, 1 / (c + I*d) cannot be exact.
+ If p divides both c and d, then we can write c = p*c', d = p*d',
+ and 1 / (c + I*d) = 1/p * 1/(c' + I*d'). This shows that if 1/(c+I*d)
+ is exact, then 1/(c' + I*d') is exact too, and we are back to the
+ previous case. In conclusion, a necessary and sufficient condition
+ is that c^2 + d^2 is a power of two.
+ */
+ /* FIXME: we could first compute c^2+d^2 mod a limb for example */
+ mpz_mul (a, c, c);
+ mpz_addmul (a, d, d);
+ t = mpz_scan1 (a, 0);
+ if (mpz_sizeinbase (a, 2) != 1 + t) /* a is not a power of two */
+ {
+ ret = -1; /* not representable */
+ goto end;
+ }
+ /* replace (c,d) by (c/(c^2+d^2), -d/(c^2+d^2)) */
+ mpz_neg (d, d);
+ ec = -ec - (mpfr_exp_t) t;
+ mpz_neg (my, my);
+ }
+
+ /* now ey >= 0 and my >= 0, and we want to compute
+ [(c + I * d) * 2^ec] ^ (my * 2^ey).
+
+ We first compute [(c + I * d) * 2^ec]^my, then square ey times. */
+ t = mpz_sizeinbase (my, 2) - 1;
+ mpz_set (a, c);
+ mpz_set (b, d);
+ ed = ec;
+ /* invariant: (a + I*b) * 2^ed = ((c + I*d) * 2^ec)^trunc(my/2^t) */
+ while (t-- > 0)
+ {
+ unsigned long int v, w;
+ /* square a + I*b */
+ mpz_mul (u, a, b);
+ mpz_mul (a, a, a);
+ mpz_submul (a, b, b);
+ mpz_mul_2exp (b, u, 1);
+ ed *= 2;
+ if (mpz_tstbit (my, t)) /* multiply by c + I*d */
+ {
+ mpz_mul (u, a, c);
+ mpz_submul (u, b, d); /* ac-bd */
+ mpz_mul (b, b, c);
+ mpz_addmul (b, a, d); /* bc+ad */
+ mpz_swap (a, u);
+ ed += ec;
+ }
+ /* remove powers of two in (a,b) */
+ if (mpz_cmp_ui (a, 0) == 0)
+ {
+ w = mpz_scan1 (b, 0);
+ mpz_tdiv_q_2exp (b, b, w);
+ ed += (mpfr_exp_t) w;
+ }
+ else if (mpz_cmp_ui (b, 0) == 0)
+ {
+ w = mpz_scan1 (a, 0);
+ mpz_tdiv_q_2exp (a, a, w);
+ ed += (mpfr_exp_t) w;
+ }
+ else
+ {
+ w = mpz_scan1 (a, 0);
+ v = mpz_scan1 (b, 0);
+ if (v < w)
+ w = v;
+ mpz_tdiv_q_2exp (a, a, w);
+ mpz_tdiv_q_2exp (b, b, w);
+ ed += (mpfr_exp_t) w;
+ }
+ if ( (mpfr_prec_t) mpz_sizeinbase (a, 2) > maxprec
+ || (mpfr_prec_t) mpz_sizeinbase (b, 2) > maxprec)
+ goto end;
+ }
+ /* now a+I*b = (c+I*d)^my */
+
+ while (ey-- > 0)
+ {
+ unsigned long sa, sb;
+
+ /* square a + I*b */
+ mpz_mul (u, a, b);
+ mpz_mul (a, a, a);
+ mpz_submul (a, b, b);
+ mpz_mul_2exp (b, u, 1);
+ ed *= 2;
+
+ /* divide by largest 2^n possible, to avoid many loops for e.g.,
+ (2+2*I)^16777216 */
+ sa = mpz_scan1 (a, 0);
+ sb = mpz_scan1 (b, 0);
+ sa = (sa <= sb) ? sa : sb;
+ mpz_tdiv_q_2exp (a, a, sa);
+ mpz_tdiv_q_2exp (b, b, sa);
+ ed += (mpfr_exp_t) sa;
+
+ if ( (mpfr_prec_t) mpz_sizeinbase (a, 2) > maxprec
+ || (mpfr_prec_t) mpz_sizeinbase (b, 2) > maxprec)
+ goto end;
+ }
+
+ ret = mpfr_set_z (mpc_realref(z), a, MPC_RND_RE(rnd));
+ ret = MPC_INEX(ret, mpfr_set_z (mpc_imagref(z), b, MPC_RND_IM(rnd)));
+ mpfr_mul_2si (mpc_realref(z), mpc_realref(z), ed, MPC_RND_RE(rnd));
+ mpfr_mul_2si (mpc_imagref(z), mpc_imagref(z), ed, MPC_RND_IM(rnd));
+
+ end:
+ mpz_clear (my);
+ mpz_clear (a);
+ mpz_clear (b);
+ mpz_clear (c);
+ mpz_clear (d);
+ mpz_clear (u);
+
+ if (ret >= 0 && x_imag)
+ fix_sign (z, sign_rex, sign_imx, (z_is_y) ? copy_of_y : y);
+
+ if (z_is_y)
+ mpfr_clear (copy_of_y);
+
+ return ret;
+}
+
+/* Return 1 if y*2^k is an odd integer, 0 otherwise.
+ Adapted from MPFR, file pow.c.
+
+ Examples: with k=0, check if y is an odd integer,
+ with k=1, check if y is half-an-integer,
+ with k=-1, check if y/2 is an odd integer.
+*/
+#define MPFR_LIMB_HIGHBIT ((mp_limb_t) 1 << (BITS_PER_MP_LIMB - 1))
+static int
+is_odd (mpfr_srcptr y, mpfr_exp_t k)
+{
+ mpfr_exp_t expo;
+ mpfr_prec_t prec;
+ mp_size_t yn;
+ mp_limb_t *yp;
+
+ expo = mpfr_get_exp (y) + k;
+ if (expo <= 0)
+ return 0; /* |y| < 1 and not 0 */
+
+ prec = mpfr_get_prec (y);
+ if ((mpfr_prec_t) expo > prec)
+ return 0; /* y is a multiple of 2^(expo-prec), thus not odd */
+
+ /* 0 < expo <= prec:
+ y = 1xxxxxxxxxt.zzzzzzzzzzzzzzzzzz[000]
+ expo bits (prec-expo) bits
+
+ We have to check that:
+ (a) the bit 't' is set
+ (b) all the 'z' bits are zero
+ */
+
+ prec = ((prec - 1) / BITS_PER_MP_LIMB + 1) * BITS_PER_MP_LIMB - expo;
+ /* number of z+0 bits */
+
+ yn = prec / BITS_PER_MP_LIMB;
+ /* yn is the index of limb containing the 't' bit */
+
+ yp = y->_mpfr_d;
+ /* if expo is a multiple of BITS_PER_MP_LIMB, t is bit 0 */
+ if (expo % BITS_PER_MP_LIMB == 0 ? (yp[yn] & 1) == 0
+ : yp[yn] << ((expo % BITS_PER_MP_LIMB) - 1) != MPFR_LIMB_HIGHBIT)
+ return 0;
+ while (--yn >= 0)
+ if (yp[yn] != 0)
+ return 0;
+ return 1;
+}
+
+/* Put in z the value of x^y, rounded according to 'rnd'.
+ Return the inexact flag in [0, 10]. */
+int
+mpc_pow (mpc_ptr z, mpc_srcptr x, mpc_srcptr y, mpc_rnd_t rnd)
+{
+ int ret = -2, loop, x_real, x_imag, y_real, z_real = 0, z_imag = 0;
+ mpc_t t, u;
+ mpfr_prec_t p, pr, pi, maxprec;
+ int saved_underflow, saved_overflow;
+
+ /* save the underflow or overflow flags from MPFR */
+ saved_underflow = mpfr_underflow_p ();
+ saved_overflow = mpfr_overflow_p ();
+
+ x_real = mpfr_zero_p (mpc_imagref(x));
+ y_real = mpfr_zero_p (mpc_imagref(y));
+
+ if (y_real && mpfr_zero_p (mpc_realref(y))) /* case y zero */
+ {
+ if (x_real && mpfr_zero_p (mpc_realref(x)))
+ {
+ /* we define 0^0 to be (1, +0) since the real part is
+ coherent with MPFR where 0^0 gives 1, and the sign of the
+ imaginary part cannot be determined */
+ mpc_set_ui_ui (z, 1, 0, MPC_RNDNN);
+ return 0;
+ }
+ else /* x^0 = 1 +/- i*0 even for x=NaN see algorithms.tex for the
+ sign of zero */
+ {
+ mpfr_t n;
+ int inex, cx1;
+ int sign_zi;
+ /* cx1 < 0 if |x| < 1
+ cx1 = 0 if |x| = 1
+ cx1 > 0 if |x| > 1
+ */
+ mpfr_init (n);
+ inex = mpc_norm (n, x, GMP_RNDN);
+ cx1 = mpfr_cmp_ui (n, 1);
+ if (cx1 == 0 && inex != 0)
+ cx1 = -inex;
+
+ sign_zi = (cx1 < 0 && mpfr_signbit (mpc_imagref (y)) == 0)
+ || (cx1 == 0
+ && mpfr_signbit (mpc_imagref (x)) != mpfr_signbit (mpc_realref (y)))
+ || (cx1 > 0 && mpfr_signbit (mpc_imagref (y)));
+
+ /* warning: mpc_set_ui_ui does not set Im(z) to -0 if Im(rnd)=RNDD */
+ ret = mpc_set_ui_ui (z, 1, 0, rnd);
+
+ if (MPC_RND_IM (rnd) == GMP_RNDD || sign_zi)
+ mpc_conj (z, z, MPC_RNDNN);
+
+ mpfr_clear (n);
+ return ret;
+ }
+ }
+
+ if (!mpc_fin_p (x) || !mpc_fin_p (y))
+ {
+ /* special values: exp(y*log(x)) */
+ mpc_init2 (u, 2);
+ mpc_log (u, x, MPC_RNDNN);
+ mpc_mul (u, u, y, MPC_RNDNN);
+ ret = mpc_exp (z, u, rnd);
+ mpc_clear (u);
+ goto end;
+ }
+
+ if (x_real) /* case x real */
+ {
+ if (mpfr_zero_p (mpc_realref(x))) /* x is zero */
+ {
+ /* special values: exp(y*log(x)) */
+ mpc_init2 (u, 2);
+ mpc_log (u, x, MPC_RNDNN);
+ mpc_mul (u, u, y, MPC_RNDNN);
+ ret = mpc_exp (z, u, rnd);
+ mpc_clear (u);
+ goto end;
+ }
+
+ /* Special case 1^y = 1 */
+ if (mpfr_cmp_ui (mpc_realref(x), 1) == 0)
+ {
+ int s1, s2;
+ s1 = mpfr_signbit (mpc_realref (y));
+ s2 = mpfr_signbit (mpc_imagref (x));
+
+ ret = mpc_set_ui (z, +1, rnd);
+ /* the sign of the zero imaginary part is known in some cases (see
+ algorithm.tex). In such cases we have
+ (x +s*0i)^(y+/-0i) = x^y + s*sign(y)*0i
+ where s = +/-1. We extend here this rule to fix the sign of the
+ zero part.
+
+ Note that the sign must also be set explicitly when rnd=RNDD
+ because mpfr_set_ui(z_i, 0, rnd) always sets z_i to +0.
+ */
+ if (MPC_RND_IM (rnd) == GMP_RNDD || s1 != s2)
+ mpc_conj (z, z, MPC_RNDNN);
+ goto end;
+ }
+
+ /* x^y is real when:
+ (a) x is real and y is integer
+ (b) x is real non-negative and y is real */
+ if (y_real && (mpfr_integer_p (mpc_realref(y)) ||
+ mpfr_cmp_ui (mpc_realref(x), 0) >= 0))
+ {
+ int s1, s2;
+ s1 = mpfr_signbit (mpc_realref (y));
+ s2 = mpfr_signbit (mpc_imagref (x));
+
+ ret = mpfr_pow (mpc_realref(z), mpc_realref(x), mpc_realref(y), MPC_RND_RE(rnd));
+ ret = MPC_INEX(ret, mpfr_set_ui (mpc_imagref(z), 0, MPC_RND_IM(rnd)));
+
+ /* the sign of the zero imaginary part is known in some cases
+ (see algorithm.tex). In such cases we have (x +s*0i)^(y+/-0i)
+ = x^y + s*sign(y)*0i where s = +/-1.
+ We extend here this rule to fix the sign of the zero part.
+
+ Note that the sign must also be set explicitly when rnd=RNDD
+ because mpfr_set_ui(z_i, 0, rnd) always sets z_i to +0.
+ */
+ if (MPC_RND_IM(rnd) == GMP_RNDD || s1 != s2)
+ mpfr_neg (mpc_imagref(z), mpc_imagref(z), MPC_RND_IM(rnd));
+ goto end;
+ }
+
+ /* (-1)^(n+I*t) is real for n integer and t real */
+ if (mpfr_cmp_si (mpc_realref(x), -1) == 0 && mpfr_integer_p (mpc_realref(y)))
+ z_real = 1;
+
+ /* for x real, x^y is imaginary when:
+ (a) x is negative and y is half-an-integer
+ (b) x = -1 and Re(y) is half-an-integer
+ */
+ if ((mpfr_cmp_ui (mpc_realref(x), 0) < 0) && is_odd (mpc_realref(y), 1)
+ && (y_real || mpfr_cmp_si (mpc_realref(x), -1) == 0))
+ z_imag = 1;
+ }
+ else /* x non real */
+ /* I^(t*I) and (-I)^(t*I) are real for t real,
+ I^(n+t*I) and (-I)^(n+t*I) are real for n even and t real, and
+ I^(n+t*I) and (-I)^(n+t*I) are imaginary for n odd and t real
+ (s*I)^n is real for n even and imaginary for n odd */
+ if ((mpc_cmp_si_si (x, 0, 1) == 0 || mpc_cmp_si_si (x, 0, -1) == 0 ||
+ (mpfr_cmp_ui (mpc_realref(x), 0) == 0 && y_real)) &&
+ mpfr_integer_p (mpc_realref(y)))
+ { /* x is I or -I, and Re(y) is an integer */
+ if (is_odd (mpc_realref(y), 0))
+ z_imag = 1; /* Re(y) odd: z is imaginary */
+ else
+ z_real = 1; /* Re(y) even: z is real */
+ }
+ else /* (t+/-t*I)^(2n) is imaginary for n odd and real for n even */
+ if (mpfr_cmpabs (mpc_realref(x), mpc_imagref(x)) == 0 && y_real &&
+ mpfr_integer_p (mpc_realref(y)) && is_odd (mpc_realref(y), 0) == 0)
+ {
+ if (is_odd (mpc_realref(y), -1)) /* y/2 is odd */
+ z_imag = 1;
+ else
+ z_real = 1;
+ }
+
+ pr = mpfr_get_prec (mpc_realref(z));
+ pi = mpfr_get_prec (mpc_imagref(z));
+ p = (pr > pi) ? pr : pi;
+ p += 12; /* experimentally, seems to give less than 10% of failures in
+ Ziv's strategy; probably wrong now since q is not computed */
+ if (p < 64)
+ p = 64;
+ mpc_init2 (u, p);
+ mpc_init2 (t, p);
+ pr += MPC_RND_RE(rnd) == GMP_RNDN;
+ pi += MPC_RND_IM(rnd) == GMP_RNDN;
+ maxprec = MPC_MAX_PREC (z);
+ x_imag = mpfr_zero_p (mpc_realref(x));
+ for (loop = 0;; loop++)
+ {
+ int ret_exp;
+ mpfr_exp_t dr, di;
+ mpfr_prec_t q;
+
+ mpc_log (t, x, MPC_RNDNN);
+ mpc_mul (t, t, y, MPC_RNDNN);
+
+ /* Compute q such that |Re (y log x)|, |Im (y log x)| < 2^q.
+ We recompute it at each loop since we might get different
+ bounds if the precision is not enough. */
+ q = mpfr_get_exp (mpc_realref(t)) > 0 ? mpfr_get_exp (mpc_realref(t)) : 0;
+ if (mpfr_get_exp (mpc_imagref(t)) > (mpfr_exp_t) q)
+ q = mpfr_get_exp (mpc_imagref(t));
+
+ mpfr_clear_overflow ();
+ mpfr_clear_underflow ();
+ ret_exp = mpc_exp (u, t, MPC_RNDNN);
+ if (mpfr_underflow_p () || mpfr_overflow_p ()) {
+ /* under- and overflow flags are set by mpc_exp */
+ mpc_set (z, u, MPC_RNDNN);
+ ret = ret_exp;
+ goto exact;
+ }
+
+ /* Since the error bound is global, we have to take into account the
+ exponent difference between the real and imaginary parts. We assume
+ either the real or the imaginary part of u is not zero.
+ */
+ dr = mpfr_zero_p (mpc_realref(u)) ? mpfr_get_exp (mpc_imagref(u))
+ : mpfr_get_exp (mpc_realref(u));
+ di = mpfr_zero_p (mpc_imagref(u)) ? dr : mpfr_get_exp (mpc_imagref(u));
+ if (dr > di)
+ {
+ di = dr - di;
+ dr = 0;
+ }
+ else
+ {
+ dr = di - dr;
+ di = 0;
+ }
+ /* the term -3 takes into account the factor 4 in the complex error
+ (see algorithms.tex) plus one due to the exponent difference: if
+ z = a + I*b, where the relative error on z is at most 2^(-p), and
+ EXP(a) = EXP(b) + k, the relative error on b is at most 2^(k-p) */
+ if ((z_imag || (p > q + 3 + dr && mpfr_can_round (mpc_realref(u), p - q - 3 - dr, GMP_RNDN, GMP_RNDZ, pr))) &&
+ (z_real || (p > q + 3 + di && mpfr_can_round (mpc_imagref(u), p - q - 3 - di, GMP_RNDN, GMP_RNDZ, pi))))
+ break;
+
+ /* if Re(u) is not known to be zero, assume it is a normal number, i.e.,
+ neither zero, Inf or NaN, otherwise we might enter an infinite loop */
+ MPC_ASSERT (z_imag || mpfr_number_p (mpc_realref(u)));
+ /* idem for Im(u) */
+ MPC_ASSERT (z_real || mpfr_number_p (mpc_imagref(u)));
+
+ if (ret == -2) /* we did not yet call mpc_pow_exact, or it aborted
+ because intermediate computations had > maxprec bits */
+ {
+ /* check exact cases (see algorithms.tex) */
+ if (y_real)
+ {
+ maxprec *= 2;
+ ret = mpc_pow_exact (z, x, mpc_realref(y), rnd, maxprec);
+ if (ret != -1 && ret != -2)
+ goto exact;
+ }
+ p += dr + di + 64;
+ }
+ else
+ p += p / 2;
+ mpc_set_prec (t, p);
+ mpc_set_prec (u, p);
+ }
+
+ if (z_real)
+ {
+ /* When the result is real (see algorithm.tex for details),
+ Im(x^y) =
+ + sign(imag(y))*0i, if |x| > 1
+ + sign(imag(x))*sign(real(y))*0i, if |x| = 1
+ - sign(imag(y))*0i, if |x| < 1
+ */
+ mpfr_t n;
+ int inex, cx1;
+ int sign_zi, sign_rex, sign_imx;
+ /* cx1 < 0 if |x| < 1
+ cx1 = 0 if |x| = 1
+ cx1 > 0 if |x| > 1
+ */
+
+ sign_rex = mpfr_signbit (mpc_realref (x));
+ sign_imx = mpfr_signbit (mpc_imagref (x));
+ mpfr_init (n);
+ inex = mpc_norm (n, x, GMP_RNDN);
+ cx1 = mpfr_cmp_ui (n, 1);
+ if (cx1 == 0 && inex != 0)
+ cx1 = -inex;
+
+ sign_zi = (cx1 < 0 && mpfr_signbit (mpc_imagref (y)) == 0)
+ || (cx1 == 0 && sign_imx != mpfr_signbit (mpc_realref (y)))
+ || (cx1 > 0 && mpfr_signbit (mpc_imagref (y)));
+
+ /* copy RE(y) to n since if z==y we will destroy Re(y) below */
+ mpfr_set_prec (n, mpfr_get_prec (mpc_realref (y)));
+ mpfr_set (n, mpc_realref (y), GMP_RNDN);
+ ret = mpfr_set (mpc_realref(z), mpc_realref(u), MPC_RND_RE(rnd));
+ if (y_real && (x_real || x_imag))
+ {
+ /* FIXME: with y_real we assume Im(y) is really 0, which is the case
+ for example when y comes from pow_fr, but in case Im(y) is +0 or
+ -0, we might get different results */
+ mpfr_set_ui (mpc_imagref (z), 0, MPC_RND_IM (rnd));
+ fix_sign (z, sign_rex, sign_imx, n);
+ ret = MPC_INEX(ret, 0); /* imaginary part is exact */
+ }
+ else
+ {
+ ret = MPC_INEX (ret, mpfr_set_ui (mpc_imagref (z), 0, MPC_RND_IM (rnd)));
+ /* warning: mpfr_set_ui does not set Im(z) to -0 if Im(rnd) = RNDD */
+ if (MPC_RND_IM (rnd) == GMP_RNDD || sign_zi)
+ mpc_conj (z, z, MPC_RNDNN);
+ }
+
+ mpfr_clear (n);
+ }
+ else if (z_imag)
+ {
+ ret = mpfr_set (mpc_imagref(z), mpc_imagref(u), MPC_RND_IM(rnd));
+ /* if z is imaginary and y real, then x cannot be real */
+ if (y_real && x_imag)
+ {
+ int sign_rex = mpfr_signbit (mpc_realref (x));
+
+ /* If z overlaps with y we set Re(z) before checking Re(y) below,
+ but in that case y=0, which was dealt with above. */
+ mpfr_set_ui (mpc_realref (z), 0, MPC_RND_RE (rnd));
+ /* Note: fix_sign only does something when y is an integer,
+ then necessarily y = 1 or 3 (mod 4), and in that case the
+ sign of Im(x) is irrelevant. */
+ fix_sign (z, sign_rex, 0, mpc_realref (y));
+ ret = MPC_INEX(0, ret);
+ }
+ else
+ ret = MPC_INEX(mpfr_set_ui (mpc_realref(z), 0, MPC_RND_RE(rnd)), ret);
+ }
+ else
+ ret = mpc_set (z, u, rnd);
+ exact:
+ mpc_clear (t);
+ mpc_clear (u);
+
+ /* restore underflow and overflow flags from MPFR */
+ if (saved_underflow)
+ mpfr_set_underflow ();
+ if (saved_overflow)
+ mpfr_set_overflow ();
+
+ end:
+ return ret;
+}
diff --git a/mpc/src/pow_d.c b/mpc/src/pow_d.c
new file mode 100644
index 0000000000..8034b26293
--- /dev/null
+++ b/mpc/src/pow_d.c
@@ -0,0 +1,38 @@
+/* mpc_pow_d -- Raise a complex number to a double-precision power.
+
+Copyright (C) 2009 INRIA
+
+This file is part of GNU MPC.
+
+GNU MPC is free software; you can redistribute it and/or modify it under
+the terms of the GNU Lesser General Public License as published by the
+Free Software Foundation; either version 3 of the License, or (at your
+option) any later version.
+
+GNU MPC 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 Lesser General Public License for
+more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+
+#include <stdio.h> /* for MPC_ASSERT */
+#include <float.h> /* for DBL_MANT_DIG */
+#include "mpc-impl.h"
+
+int
+mpc_pow_d (mpc_ptr z, mpc_srcptr x, double y, mpc_rnd_t rnd)
+{
+ mpc_t yy;
+ int inex;
+
+ MPC_ASSERT(FLT_RADIX == 2);
+ mpc_init3 (yy, DBL_MANT_DIG, MPFR_PREC_MIN);
+ mpc_set_d (yy, y, MPC_RNDNN); /* exact */
+ inex = mpc_pow (z, x, yy, rnd);
+ mpc_clear (yy);
+ return inex;
+}
+
diff --git a/mpc/src/pow_fr.c b/mpc/src/pow_fr.c
new file mode 100644
index 0000000000..8c5d930421
--- /dev/null
+++ b/mpc/src/pow_fr.c
@@ -0,0 +1,37 @@
+/* mpc_pow_fr -- Raise a complex number to a floating-point power.
+
+Copyright (C) 2009, 2011 INRIA
+
+This file is part of GNU MPC.
+
+GNU MPC is free software; you can redistribute it and/or modify it under
+the terms of the GNU Lesser General Public License as published by the
+Free Software Foundation; either version 3 of the License, or (at your
+option) any later version.
+
+GNU MPC 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 Lesser General Public License for
+more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+
+#include "mpc-impl.h"
+
+int
+mpc_pow_fr (mpc_ptr z, mpc_srcptr x, mpfr_srcptr y, mpc_rnd_t rnd)
+{
+ mpc_t yy;
+ int inex;
+
+ /* avoid copying the significand of y by copying only the struct */
+ mpc_realref(yy)[0] = y[0];
+ mpfr_init2 (mpc_imagref(yy), MPFR_PREC_MIN);
+ mpfr_set_ui (mpc_imagref(yy), 0, GMP_RNDN);
+ inex = mpc_pow (z, x, yy, rnd);
+ mpfr_clear (mpc_imagref(yy));
+ return inex;
+}
+
diff --git a/mpc/src/pow_ld.c b/mpc/src/pow_ld.c
new file mode 100644
index 0000000000..9d98a98478
--- /dev/null
+++ b/mpc/src/pow_ld.c
@@ -0,0 +1,38 @@
+/* mpc_pow_ld -- Raise a complex number to a long double power.
+
+Copyright (C) 2009 INRIA
+
+This file is part of GNU MPC.
+
+GNU MPC is free software; you can redistribute it and/or modify it under
+the terms of the GNU Lesser General Public License as published by the
+Free Software Foundation; either version 3 of the License, or (at your
+option) any later version.
+
+GNU MPC 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 Lesser General Public License for
+more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+
+#include <stdio.h> /* for MPC_ASSERT */
+#include <float.h> /* for LDBL_MANT_DIG */
+#include "mpc-impl.h"
+
+int
+mpc_pow_ld (mpc_ptr z, mpc_srcptr x, long double y, mpc_rnd_t rnd)
+{
+ mpc_t yy;
+ int inex;
+
+ MPC_ASSERT(FLT_RADIX == 2);
+ mpc_init3 (yy, LDBL_MANT_DIG, MPFR_PREC_MIN);
+ mpc_set_ld (yy, y, MPC_RNDNN); /* exact */
+ inex = mpc_pow (z, x, yy, rnd);
+ mpc_clear (yy);
+ return inex;
+}
+
diff --git a/mpc/src/pow_si.c b/mpc/src/pow_si.c
new file mode 100644
index 0000000000..5b5c5d9dfb
--- /dev/null
+++ b/mpc/src/pow_si.c
@@ -0,0 +1,30 @@
+/* mpc_pow_si -- Raise a complex number to an integer power.
+
+Copyright (C) 2009, 2010 INRIA
+
+This file is part of GNU MPC.
+
+GNU MPC is free software; you can redistribute it and/or modify it under
+the terms of the GNU Lesser General Public License as published by the
+Free Software Foundation; either version 3 of the License, or (at your
+option) any later version.
+
+GNU MPC 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 Lesser General Public License for
+more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+
+#include "mpc-impl.h"
+
+int
+mpc_pow_si (mpc_ptr z, mpc_srcptr x, long y, mpc_rnd_t rnd)
+{
+ if (y >= 0)
+ return mpc_pow_usi (z, x, (unsigned long) y, 1, rnd);
+ else
+ return mpc_pow_usi (z, x, (unsigned long) (-y), -1, rnd);
+}
diff --git a/mpc/src/pow_ui.c b/mpc/src/pow_ui.c
new file mode 100644
index 0000000000..da82a9471f
--- /dev/null
+++ b/mpc/src/pow_ui.c
@@ -0,0 +1,169 @@
+/* mpc_pow_ui -- Raise a complex number to an integer power.
+
+Copyright (C) 2009, 2010, 2011, 2012 INRIA
+
+This file is part of GNU MPC.
+
+GNU MPC is free software; you can redistribute it and/or modify it under
+the terms of the GNU Lesser General Public License as published by the
+Free Software Foundation; either version 3 of the License, or (at your
+option) any later version.
+
+GNU MPC 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 Lesser General Public License for
+more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+
+#include <limits.h> /* for CHAR_BIT */
+#include "mpc-impl.h"
+
+static int
+mpc_pow_usi_naive (mpc_ptr z, mpc_srcptr x, unsigned long y, int sign,
+ mpc_rnd_t rnd)
+{
+ int inex;
+ mpc_t t;
+
+ mpc_init3 (t, sizeof (unsigned long) * CHAR_BIT, MPFR_PREC_MIN);
+ if (sign > 0)
+ mpc_set_ui (t, y, MPC_RNDNN); /* exact */
+ else
+ mpc_set_si (t, - (signed long) y, MPC_RNDNN);
+ inex = mpc_pow (z, x, t, rnd);
+ mpc_clear (t);
+
+ return inex;
+}
+
+
+int
+mpc_pow_usi (mpc_ptr z, mpc_srcptr x, unsigned long y, int sign,
+ mpc_rnd_t rnd)
+ /* computes z = x^(sign*y) */
+{
+ int inex;
+ mpc_t t, x3;
+ mpfr_prec_t p, l, l0;
+ long unsigned int u;
+ int has3; /* non-zero if y has '11' in its binary representation */
+ int loop, done;
+
+ /* let mpc_pow deal with special values */
+ if (!mpc_fin_p (x) || mpfr_zero_p (mpc_realref (x)) || mpfr_zero_p (mpc_imagref(x))
+ || y == 0)
+ return mpc_pow_usi_naive (z, x, y, sign, rnd);
+ /* easy special cases */
+ else if (y == 1) {
+ if (sign > 0)
+ return mpc_set (z, x, rnd);
+ else
+ return mpc_ui_div (z, 1ul, x, rnd);
+ }
+ else if (y == 2 && sign > 0)
+ return mpc_sqr (z, x, rnd);
+ /* let mpc_pow treat potential over- and underflows */
+ else {
+ mpfr_exp_t exp_r = mpfr_get_exp (mpc_realref (x)),
+ exp_i = mpfr_get_exp (mpc_imagref (x));
+ if ( MPC_MAX (exp_r, exp_i) > mpfr_get_emax () / (mpfr_exp_t) y
+ /* heuristic for overflow */
+ || MPC_MAX (-exp_r, -exp_i) > (-mpfr_get_emin ()) / (mpfr_exp_t) y
+ /* heuristic for underflow */
+ )
+ return mpc_pow_usi_naive (z, x, y, sign, rnd);
+ }
+
+ has3 = (y & (y >> 1)) != 0;
+ for (l = 0, u = y; u > 3; l ++, u >>= 1);
+ /* l>0 is the number of bits of y, minus 2, thus y has bits:
+ y_{l+1} y_l y_{l-1} ... y_1 y_0 */
+ l0 = l + 2;
+ p = MPC_MAX_PREC(z) + l0 + 32; /* l0 ensures that y*2^{-p} <= 1 below */
+ mpc_init2 (t, p);
+ if (has3)
+ mpc_init2 (x3, p);
+
+ loop = 0;
+ done = 0;
+ while (!done) {
+ loop++;
+
+ mpc_sqr (t, x, MPC_RNDNN);
+ if (has3) {
+ mpc_mul (x3, t, x, MPC_RNDNN);
+ if ((y >> l) & 1) /* y starts with 11... */
+ mpc_set (t, x3, MPC_RNDNN);
+ }
+ while (l-- > 0) {
+ mpc_sqr (t, t, MPC_RNDNN);
+ if ((y >> l) & 1) {
+ if ((l > 0) && ((y >> (l-1)) & 1)) /* implies has3 <> 0 */ {
+ l--;
+ mpc_sqr (t, t, MPC_RNDNN);
+ mpc_mul (t, t, x3, MPC_RNDNN);
+ }
+ else
+ mpc_mul (t, t, x, MPC_RNDNN);
+ }
+ }
+ if (sign < 0)
+ mpc_ui_div (t, 1ul, t, MPC_RNDNN);
+
+ if (mpfr_zero_p (mpc_realref(t)) || mpfr_zero_p (mpc_imagref(t))) {
+ inex = mpc_pow_usi_naive (z, x, y, sign, rnd);
+ /* since mpfr_get_exp() is not defined for zero */
+ done = 1;
+ }
+ else {
+ /* see error bound in algorithms.tex; we use y<2^l0 instead of y-1
+ also when sign>0 */
+ mpfr_exp_t diff;
+ mpfr_prec_t er, ei;
+
+ diff = mpfr_get_exp (mpc_realref(t)) - mpfr_get_exp (mpc_imagref(t));
+ /* the factor on the real part is 2+2^(-diff+2) <= 4 for diff >= 1
+ and < 2^(-diff+3) for diff <= 0 */
+ er = (diff >= 1) ? l0 + 3 : l0 + (-diff) + 3;
+ /* the factor on the imaginary part is 2+2^(diff+2) <= 4 for diff <= -1
+ and < 2^(diff+3) for diff >= 0 */
+ ei = (diff <= -1) ? l0 + 3 : l0 + diff + 3;
+ if (mpfr_can_round (mpc_realref(t), p - er, GMP_RNDN, GMP_RNDZ,
+ MPC_PREC_RE(z) + (MPC_RND_RE(rnd) == GMP_RNDN))
+ && mpfr_can_round (mpc_imagref(t), p - ei, GMP_RNDN, GMP_RNDZ,
+ MPC_PREC_IM(z) + (MPC_RND_IM(rnd) == GMP_RNDN))) {
+ inex = mpc_set (z, t, rnd);
+ done = 1;
+ }
+ else if (loop == 1 && SAFE_ABS(mpfr_prec_t, diff) < MPC_MAX_PREC(z)) {
+ /* common case, make a second trial at higher precision */
+ p += MPC_MAX_PREC(x);
+ mpc_set_prec (t, p);
+ if (has3)
+ mpc_set_prec (x3, p);
+ l = l0 - 2;
+ }
+ else {
+ /* stop the loop and use mpc_pow */
+ inex = mpc_pow_usi_naive (z, x, y, sign, rnd);
+ done = 1;
+ }
+ }
+ }
+
+ mpc_clear (t);
+ if (has3)
+ mpc_clear (x3);
+
+ return inex;
+}
+
+
+int
+mpc_pow_ui (mpc_ptr z, mpc_srcptr x, unsigned long y, mpc_rnd_t rnd)
+{
+ return mpc_pow_usi (z, x, y, 1, rnd);
+}
diff --git a/mpc/src/pow_z.c b/mpc/src/pow_z.c
new file mode 100644
index 0000000000..22eb544ca9
--- /dev/null
+++ b/mpc/src/pow_z.c
@@ -0,0 +1,47 @@
+/* mpc_pow_z -- Raise a complex number to an integer power.
+
+Copyright (C) 2009, 2010 INRIA
+
+This file is part of GNU MPC.
+
+GNU MPC is free software; you can redistribute it and/or modify it under
+the terms of the GNU Lesser General Public License as published by the
+Free Software Foundation; either version 3 of the License, or (at your
+option) any later version.
+
+GNU MPC 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 Lesser General Public License for
+more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+
+#include "mpc-impl.h"
+
+int
+mpc_pow_z (mpc_ptr z, mpc_srcptr x, mpz_srcptr y, mpc_rnd_t rnd)
+{
+ mpc_t yy;
+ int inex;
+ mpfr_prec_t n = (mpfr_prec_t) mpz_sizeinbase (y, 2);
+
+ /* if y fits in an unsigned long or long, call the corresponding functions,
+ which are supposed to be more efficient */
+ if (mpz_cmp_ui (y, 0ul) >= 0) {
+ if (mpz_fits_ulong_p (y))
+ return mpc_pow_usi (z, x, mpz_get_ui (y), 1, rnd);
+ }
+ else {
+ if (mpz_fits_slong_p (y))
+ return mpc_pow_usi (z, x, (unsigned long) (-mpz_get_si (y)), -1, rnd);
+ }
+
+ mpc_init3 (yy, (n < MPFR_PREC_MIN) ? MPFR_PREC_MIN : n, MPFR_PREC_MIN);
+ mpc_set_z (yy, y, MPC_RNDNN); /* exact */
+ inex = mpc_pow (z, x, yy, rnd);
+ mpc_clear (yy);
+ return inex;
+}
+
diff --git a/mpc/src/proj.c b/mpc/src/proj.c
new file mode 100644
index 0000000000..ace58c5331
--- /dev/null
+++ b/mpc/src/proj.c
@@ -0,0 +1,34 @@
+/* mpc_proj -- projection of a complex number onto the Riemann sphere.
+
+Copyright (C) 2008, 2009, 2011 INRIA
+
+This file is part of GNU MPC.
+
+GNU MPC is free software; you can redistribute it and/or modify it under
+the terms of the GNU Lesser General Public License as published by the
+Free Software Foundation; either version 3 of the License, or (at your
+option) any later version.
+
+GNU MPC 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 Lesser General Public License for
+more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+
+#include "mpc-impl.h"
+
+int
+mpc_proj (mpc_ptr a, mpc_srcptr b, mpc_rnd_t rnd)
+{
+ if (mpc_inf_p (b)) {
+ /* infinities project to +Inf +i* copysign(0.0, cimag(z)) */
+ mpfr_set_inf (mpc_realref (a), +1);
+ mpfr_set_zero (mpc_imagref (a), (mpfr_signbit (mpc_imagref (b)) ? -1 : 1));
+ return MPC_INEX (0, 0);
+ }
+ else
+ return mpc_set (a, b, rnd);
+}
diff --git a/mpc/src/real.c b/mpc/src/real.c
new file mode 100644
index 0000000000..041dddb5ff
--- /dev/null
+++ b/mpc/src/real.c
@@ -0,0 +1,27 @@
+/* mpc_real -- Get the real part of a complex number.
+
+Copyright (C) 2008, 2009, 2011 INRIA
+
+This file is part of GNU MPC.
+
+GNU MPC is free software; you can redistribute it and/or modify it under
+the terms of the GNU Lesser General Public License as published by the
+Free Software Foundation; either version 3 of the License, or (at your
+option) any later version.
+
+GNU MPC 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 Lesser General Public License for
+more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+
+#include "mpc-impl.h"
+
+int
+mpc_real (mpfr_ptr a, mpc_srcptr b, mpfr_rnd_t rnd)
+{
+ return mpfr_set (a, mpc_realref (b), rnd);
+}
diff --git a/mpc/src/set.c b/mpc/src/set.c
new file mode 100644
index 0000000000..e7a3c1148c
--- /dev/null
+++ b/mpc/src/set.c
@@ -0,0 +1,32 @@
+/* mpc_set -- Set a complex number from another complex number.
+
+Copyright (C) 2002, 2009, 2011 INRIA
+
+This file is part of GNU MPC.
+
+GNU MPC is free software; you can redistribute it and/or modify it under
+the terms of the GNU Lesser General Public License as published by the
+Free Software Foundation; either version 3 of the License, or (at your
+option) any later version.
+
+GNU MPC 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 Lesser General Public License for
+more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+
+#include "mpc-impl.h"
+
+int
+mpc_set (mpc_ptr a, mpc_srcptr b, mpc_rnd_t rnd)
+{
+ int inex_re, inex_im;
+
+ inex_re = mpfr_set (mpc_realref(a), mpc_realref(b), MPC_RND_RE(rnd));
+ inex_im = mpfr_set (mpc_imagref(a), mpc_imagref(b), MPC_RND_IM(rnd));
+
+ return MPC_INEX(inex_re, inex_im);
+}
diff --git a/mpc/src/set_prec.c b/mpc/src/set_prec.c
new file mode 100644
index 0000000000..c5e6f24a37
--- /dev/null
+++ b/mpc/src/set_prec.c
@@ -0,0 +1,28 @@
+/* mpc_set_prec -- reset the precision of a complex variable.
+
+Copyright (C) 2002, 2009, 2011 INRIA
+
+This file is part of GNU MPC.
+
+GNU MPC is free software; you can redistribute it and/or modify it under
+the terms of the GNU Lesser General Public License as published by the
+Free Software Foundation; either version 3 of the License, or (at your
+option) any later version.
+
+GNU MPC 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 Lesser General Public License for
+more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+
+#include "mpc-impl.h"
+
+void
+mpc_set_prec (mpc_t x, mpfr_prec_t prec)
+{
+ mpfr_set_prec (mpc_realref(x), prec);
+ mpfr_set_prec (mpc_imagref(x), prec);
+}
diff --git a/mpc/src/set_str.c b/mpc/src/set_str.c
new file mode 100644
index 0000000000..195b9ac0bf
--- /dev/null
+++ b/mpc/src/set_str.c
@@ -0,0 +1,42 @@
+/* mpc_set_str -- Convert a string into a complex number.
+
+Copyright (C) 2009, 2010, 2011 INRIA
+
+This file is part of GNU MPC.
+
+GNU MPC is free software; you can redistribute it and/or modify it under
+the terms of the GNU Lesser General Public License as published by the
+Free Software Foundation; either version 3 of the License, or (at your
+option) any later version.
+
+GNU MPC 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 Lesser General Public License for
+more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+
+#include <ctype.h>
+#include "mpc-impl.h"
+
+int
+mpc_set_str (mpc_t z, const char *str, int base, mpc_rnd_t rnd)
+{
+ char *p;
+ int inex;
+
+ inex = mpc_strtoc (z, str, &p, base, rnd);
+
+ if (inex != -1){
+ while (isspace ((unsigned char) (*p)))
+ p++;
+ if (*p == '\0')
+ return inex;
+ }
+
+ mpfr_set_nan (mpc_realref (z));
+ mpfr_set_nan (mpc_imagref (z));
+ return -1;
+}
diff --git a/mpc/src/set_x.c b/mpc/src/set_x.c
new file mode 100644
index 0000000000..94ec12d96b
--- /dev/null
+++ b/mpc/src/set_x.c
@@ -0,0 +1,104 @@
+/* mpc_set_x -- Set the real part of a complex number
+ (imaginary part equals +0 regardless of rounding mode).
+
+Copyright (C) 2008, 2009, 2010, 2011 INRIA
+
+This file is part of GNU MPC.
+
+GNU MPC is free software; you can redistribute it and/or modify it under
+the terms of the GNU Lesser General Public License as published by the
+Free Software Foundation; either version 3 of the License, or (at your
+option) any later version.
+
+GNU MPC 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 Lesser General Public License for
+more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+
+#include "config.h"
+
+#ifdef HAVE_INTTYPES_H
+# include <inttypes.h> /* for intmax_t */
+#else
+# ifdef HAVE_STDINT_H
+# include <stdint.h>
+# endif
+#endif
+
+#ifdef HAVE_COMPLEX_H
+# include <complex.h>
+#endif
+
+#include "mpc-impl.h"
+
+#define MPC_SET_X(real_t, z, real_value, rnd) \
+ { \
+ int _inex_re, _inex_im; \
+ _inex_re = (mpfr_set_ ## real_t) (mpc_realref (z), (real_value), MPC_RND_RE (rnd)); \
+ _inex_im = mpfr_set_ui (mpc_imagref (z), 0, MPC_RND_IM (rnd)); \
+ return MPC_INEX (_inex_re, _inex_im); \
+ }
+
+int
+mpc_set_fr (mpc_ptr a, mpfr_srcptr b, mpc_rnd_t rnd)
+ MPC_SET_X (fr, a, b, rnd)
+
+int
+mpc_set_d (mpc_ptr a, double b, mpc_rnd_t rnd)
+ MPC_SET_X (d, a, b, rnd)
+
+int
+mpc_set_ld (mpc_ptr a, long double b, mpc_rnd_t rnd)
+ MPC_SET_X (ld, a, b, rnd)
+
+int
+mpc_set_ui (mpc_ptr a, unsigned long int b, mpc_rnd_t rnd)
+ MPC_SET_X (ui, a, b, rnd)
+
+int
+mpc_set_si (mpc_ptr a, long int b, mpc_rnd_t rnd)
+ MPC_SET_X (si, a, b, rnd)
+
+int
+mpc_set_z (mpc_ptr a, mpz_srcptr b, mpc_rnd_t rnd)
+ MPC_SET_X (z, a, b, rnd)
+
+int
+mpc_set_q (mpc_ptr a, mpq_srcptr b, mpc_rnd_t rnd)
+ MPC_SET_X (q, a, b, rnd)
+
+int
+mpc_set_f (mpc_ptr a, mpf_srcptr b, mpc_rnd_t rnd)
+ MPC_SET_X (f, a, b, rnd)
+
+#ifdef _MPC_H_HAVE_INTMAX_T
+int
+mpc_set_uj (mpc_ptr a, uintmax_t b, mpc_rnd_t rnd)
+ MPC_SET_X (uj, a, b, rnd)
+
+int
+mpc_set_sj (mpc_ptr a, intmax_t b, mpc_rnd_t rnd)
+ MPC_SET_X (sj, a, b, rnd)
+#endif
+
+#ifdef HAVE_COMPLEX_H
+int
+mpc_set_dc (mpc_ptr a, double _Complex b, mpc_rnd_t rnd) {
+ return mpc_set_d_d (a, creal (b), cimag (b), rnd);
+}
+
+int
+mpc_set_ldc (mpc_ptr a, long double _Complex b, mpc_rnd_t rnd) {
+ return mpc_set_ld_ld (a, creall (b), cimagl (b), rnd);
+}
+#endif
+
+void
+mpc_set_nan (mpc_ptr a) {
+ mpfr_set_nan (mpc_realref (a));
+ mpfr_set_nan (mpc_imagref (a));
+}
diff --git a/mpc/src/set_x_x.c b/mpc/src/set_x_x.c
new file mode 100644
index 0000000000..3ce69f2454
--- /dev/null
+++ b/mpc/src/set_x_x.c
@@ -0,0 +1,78 @@
+/* mpc_set_x_x -- Set complex number real and imaginary parts from parameters
+ whose type is known by mpfr.
+
+Copyright (C) 2009, 2011 INRIA
+
+This file is part of GNU MPC.
+
+GNU MPC is free software; you can redistribute it and/or modify it under
+the terms of the GNU Lesser General Public License as published by the
+Free Software Foundation; either version 3 of the License, or (at your
+option) any later version.
+
+GNU MPC 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 Lesser General Public License for
+more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+
+#include "config.h"
+
+#ifdef HAVE_INTTYPES_H
+# include <inttypes.h> /* for intmax_t */
+#else
+# ifdef HAVE_STDINT_H
+# include <stdint.h>
+# endif
+#endif
+
+#include "mpc-impl.h"
+
+#define MPC_SET_X_X(type, z, real_value, imag_value, rnd) \
+ MPC_SET_X_Y (type, type, z, real_value, imag_value, rnd)
+
+int
+mpc_set_d_d (mpc_ptr z, double a, double b, mpc_rnd_t rnd)
+ MPC_SET_X_X (d, z, a, b, rnd)
+
+int
+mpc_set_f_f (mpc_ptr z, mpf_srcptr a, mpf_srcptr b, mpc_rnd_t rnd)
+ MPC_SET_X_X (f, z, a, b, rnd)
+
+int
+mpc_set_fr_fr (mpc_ptr z, mpfr_srcptr a, mpfr_srcptr b, mpc_rnd_t rnd)
+ MPC_SET_X_X (fr, z, a, b, rnd)
+
+int
+mpc_set_ld_ld (mpc_ptr z, long double a, long double b, mpc_rnd_t rnd)
+ MPC_SET_X_X (ld, z, a, b, rnd)
+
+int
+mpc_set_q_q (mpc_ptr z, mpq_srcptr a, mpq_srcptr b, mpc_rnd_t rnd)
+ MPC_SET_X_X (q, z, a, b, rnd)
+
+int
+mpc_set_si_si (mpc_ptr z, long int a, long int b, mpc_rnd_t rnd)
+ MPC_SET_X_X (si, z, a, b, rnd)
+
+int
+mpc_set_ui_ui (mpc_ptr z, unsigned long int a, unsigned long int b,
+ mpc_rnd_t rnd)
+ MPC_SET_X_X (ui, z, a, b, rnd)
+
+int
+mpc_set_z_z (mpc_ptr z, mpz_srcptr a, mpz_srcptr b, mpc_rnd_t rnd)
+ MPC_SET_X_X (z, z, a, b, rnd)
+
+#ifdef _MPC_H_HAVE_INTMAX_T
+int
+mpc_set_uj_uj (mpc_ptr z, uintmax_t a, uintmax_t b, mpc_rnd_t rnd)
+ MPC_SET_X_X (uj, z, a, b, rnd)
+
+int
+mpc_set_sj_sj (mpc_ptr z, intmax_t a, intmax_t b, mpc_rnd_t rnd)
+ MPC_SET_X_X (sj, z, a, b, rnd)
+#endif
diff --git a/mpc/src/sin.c b/mpc/src/sin.c
new file mode 100644
index 0000000000..27df7618df
--- /dev/null
+++ b/mpc/src/sin.c
@@ -0,0 +1,27 @@
+/* mpc_sin -- sine of a complex number.
+
+Copyright (C) 2010, 2011 INRIA
+
+This file is part of GNU MPC.
+
+GNU MPC is free software; you can redistribute it and/or modify it under
+the terms of the GNU Lesser General Public License as published by the
+Free Software Foundation; either version 3 of the License, or (at your
+option) any later version.
+
+GNU MPC 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 Lesser General Public License for
+more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+
+#include "mpc-impl.h"
+
+int
+mpc_sin (mpc_ptr rop, mpc_srcptr op, mpc_rnd_t rnd)
+{
+ return MPC_INEX1 (mpc_sin_cos (rop, NULL, op, rnd, 0));
+}
diff --git a/mpc/src/sin_cos.c b/mpc/src/sin_cos.c
new file mode 100644
index 0000000000..0cff45acd5
--- /dev/null
+++ b/mpc/src/sin_cos.c
@@ -0,0 +1,402 @@
+/* mpc_sin_cos -- combined sine and cosine of a complex number.
+
+Copyright (C) 2010, 2011 INRIA
+
+This file is part of GNU MPC.
+
+GNU MPC is free software; you can redistribute it and/or modify it under
+the terms of the GNU Lesser General Public License as published by the
+Free Software Foundation; either version 3 of the License, or (at your
+option) any later version.
+
+GNU MPC 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 Lesser General Public License for
+more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+
+#include "mpc-impl.h"
+
+static int
+mpc_sin_cos_nonfinite (mpc_ptr rop_sin, mpc_ptr rop_cos, mpc_srcptr op,
+ mpc_rnd_t rnd_sin, mpc_rnd_t rnd_cos)
+ /* assumes that op (that is, its real or imaginary part) is not finite */
+{
+ int overlap;
+ mpc_t op_loc;
+
+ overlap = (rop_sin == op || rop_cos == op);
+ if (overlap) {
+ mpc_init3 (op_loc, MPC_PREC_RE (op), MPC_PREC_IM (op));
+ mpc_set (op_loc, op, MPC_RNDNN);
+ }
+ else
+ op_loc [0] = op [0];
+
+ if (rop_sin != NULL) {
+ if (mpfr_nan_p (mpc_realref (op_loc)) || mpfr_nan_p (mpc_imagref (op_loc))) {
+ mpc_set (rop_sin, op_loc, rnd_sin);
+ if (mpfr_nan_p (mpc_imagref (op_loc))) {
+ /* sin(x +i*NaN) = NaN +i*NaN, except for x=0 */
+ /* sin(-0 +i*NaN) = -0 +i*NaN */
+ /* sin(+0 +i*NaN) = +0 +i*NaN */
+ if (!mpfr_zero_p (mpc_realref (op_loc)))
+ mpfr_set_nan (mpc_realref (rop_sin));
+ }
+ else /* op = NaN + i*y */
+ if (!mpfr_inf_p (mpc_imagref (op_loc)) && !mpfr_zero_p (mpc_imagref (op_loc)))
+ /* sin(NaN -i*Inf) = NaN -i*Inf */
+ /* sin(NaN -i*0) = NaN -i*0 */
+ /* sin(NaN +i*0) = NaN +i*0 */
+ /* sin(NaN +i*Inf) = NaN +i*Inf */
+ /* sin(NaN +i*y) = NaN +i*NaN, when 0<|y|<Inf */
+ mpfr_set_nan (mpc_imagref (rop_sin));
+ }
+ else if (mpfr_inf_p (mpc_realref (op_loc))) {
+ mpfr_set_nan (mpc_realref (rop_sin));
+
+ if (!mpfr_inf_p (mpc_imagref (op_loc)) && !mpfr_zero_p (mpc_imagref (op_loc)))
+ /* sin(+/-Inf +i*y) = NaN +i*NaN, when 0<|y|<Inf */
+ mpfr_set_nan (mpc_imagref (rop_sin));
+ else
+ /* sin(+/-Inf -i*Inf) = NaN -i*Inf */
+ /* sin(+/-Inf +i*Inf) = NaN +i*Inf */
+ /* sin(+/-Inf -i*0) = NaN -i*0 */
+ /* sin(+/-Inf +i*0) = NaN +i*0 */
+ mpfr_set (mpc_imagref (rop_sin), mpc_imagref (op_loc), MPC_RND_IM (rnd_sin));
+ }
+ else if (mpfr_zero_p (mpc_realref (op_loc))) {
+ /* sin(-0 -i*Inf) = -0 -i*Inf */
+ /* sin(+0 -i*Inf) = +0 -i*Inf */
+ /* sin(-0 +i*Inf) = -0 +i*Inf */
+ /* sin(+0 +i*Inf) = +0 +i*Inf */
+ mpc_set (rop_sin, op_loc, rnd_sin);
+ }
+ else {
+ /* sin(x -i*Inf) = +Inf*(sin(x) -i*cos(x)) */
+ /* sin(x +i*Inf) = +Inf*(sin(x) +i*cos(x)) */
+ mpfr_t s, c;
+ mpfr_init2 (s, 2);
+ mpfr_init2 (c, 2);
+ mpfr_sin_cos (s, c, mpc_realref (op_loc), GMP_RNDZ);
+ mpfr_set_inf (mpc_realref (rop_sin), MPFR_SIGN (s));
+ mpfr_set_inf (mpc_imagref (rop_sin), MPFR_SIGN (c)*MPFR_SIGN (mpc_imagref (op_loc)));
+ mpfr_clear (s);
+ mpfr_clear (c);
+ }
+ }
+
+ if (rop_cos != NULL) {
+ if (mpfr_nan_p (mpc_realref (op_loc))) {
+ /* cos(NaN + i * NaN) = NaN + i * NaN */
+ /* cos(NaN - i * Inf) = +Inf + i * NaN */
+ /* cos(NaN + i * Inf) = +Inf + i * NaN */
+ /* cos(NaN - i * 0) = NaN - i * 0 */
+ /* cos(NaN + i * 0) = NaN + i * 0 */
+ /* cos(NaN + i * y) = NaN + i * NaN, when y != 0 */
+ if (mpfr_inf_p (mpc_imagref (op_loc)))
+ mpfr_set_inf (mpc_realref (rop_cos), +1);
+ else
+ mpfr_set_nan (mpc_realref (rop_cos));
+
+ if (mpfr_zero_p (mpc_imagref (op_loc)))
+ mpfr_set (mpc_imagref (rop_cos), mpc_imagref (op_loc), MPC_RND_IM (rnd_cos));
+ else
+ mpfr_set_nan (mpc_imagref (rop_cos));
+ }
+ else if (mpfr_nan_p (mpc_imagref (op_loc))) {
+ /* cos(-Inf + i * NaN) = NaN + i * NaN */
+ /* cos(+Inf + i * NaN) = NaN + i * NaN */
+ /* cos(-0 + i * NaN) = NaN - i * 0 */
+ /* cos(+0 + i * NaN) = NaN + i * 0 */
+ /* cos(x + i * NaN) = NaN + i * NaN, when x != 0 */
+ if (mpfr_zero_p (mpc_realref (op_loc)))
+ mpfr_set (mpc_imagref (rop_cos), mpc_realref (op_loc), MPC_RND_IM (rnd_cos));
+ else
+ mpfr_set_nan (mpc_imagref (rop_cos));
+
+ mpfr_set_nan (mpc_realref (rop_cos));
+ }
+ else if (mpfr_inf_p (mpc_realref (op_loc))) {
+ /* cos(-Inf -i*Inf) = cos(+Inf +i*Inf) = -Inf +i*NaN */
+ /* cos(-Inf +i*Inf) = cos(+Inf -i*Inf) = +Inf +i*NaN */
+ /* cos(-Inf -i*0) = cos(+Inf +i*0) = NaN -i*0 */
+ /* cos(-Inf +i*0) = cos(+Inf -i*0) = NaN +i*0 */
+ /* cos(-Inf +i*y) = cos(+Inf +i*y) = NaN +i*NaN, when y != 0 */
+
+ const int same_sign =
+ mpfr_signbit (mpc_realref (op_loc)) == mpfr_signbit (mpc_imagref (op_loc));
+
+ if (mpfr_inf_p (mpc_imagref (op_loc)))
+ mpfr_set_inf (mpc_realref (rop_cos), (same_sign ? -1 : +1));
+ else
+ mpfr_set_nan (mpc_realref (rop_cos));
+
+ if (mpfr_zero_p (mpc_imagref (op_loc)))
+ mpfr_setsign (mpc_imagref (rop_cos), mpc_imagref (op_loc), same_sign,
+ MPC_RND_IM(rnd_cos));
+ else
+ mpfr_set_nan (mpc_imagref (rop_cos));
+ }
+ else if (mpfr_zero_p (mpc_realref (op_loc))) {
+ /* cos(-0 -i*Inf) = cos(+0 +i*Inf) = +Inf -i*0 */
+ /* cos(-0 +i*Inf) = cos(+0 -i*Inf) = +Inf +i*0 */
+ const int same_sign =
+ mpfr_signbit (mpc_realref (op_loc)) == mpfr_signbit (mpc_imagref (op_loc));
+
+ mpfr_setsign (mpc_imagref (rop_cos), mpc_realref (op_loc), same_sign,
+ MPC_RND_IM (rnd_cos));
+ mpfr_set_inf (mpc_realref (rop_cos), +1);
+ }
+ else {
+ /* cos(x -i*Inf) = +Inf*cos(x) +i*Inf*sin(x), when x != 0 */
+ /* cos(x +i*Inf) = +Inf*cos(x) -i*Inf*sin(x), when x != 0 */
+ mpfr_t s, c;
+ mpfr_init2 (c, 2);
+ mpfr_init2 (s, 2);
+ mpfr_sin_cos (s, c, mpc_realref (op_loc), GMP_RNDN);
+ mpfr_set_inf (mpc_realref (rop_cos), mpfr_sgn (c));
+ mpfr_set_inf (mpc_imagref (rop_cos),
+ (mpfr_sgn (mpc_imagref (op_loc)) == mpfr_sgn (s) ? -1 : +1));
+ mpfr_clear (s);
+ mpfr_clear (c);
+ }
+ }
+
+ if (overlap)
+ mpc_clear (op_loc);
+
+ return MPC_INEX12 (MPC_INEX (0,0), MPC_INEX (0,0));
+ /* everything is exact */
+}
+
+
+static int
+mpc_sin_cos_real (mpc_ptr rop_sin, mpc_ptr rop_cos, mpc_srcptr op,
+ mpc_rnd_t rnd_sin, mpc_rnd_t rnd_cos)
+ /* assumes that op is real */
+{
+ int inex_sin_re = 0, inex_cos_re = 0;
+ /* Until further notice, assume computations exact; in particular,
+ by definition, for not computed values. */
+ mpfr_t s, c;
+ int inex_s, inex_c;
+ int sign_im = mpfr_signbit (mpc_imagref (op));
+
+ /* sin(x +-0*i) = sin(x) +-0*i*sign(cos(x)) */
+ /* cos(x +-i*0) = cos(x) -+i*0*sign(sin(x)) */
+ if (rop_sin != 0)
+ mpfr_init2 (s, MPC_PREC_RE (rop_sin));
+ else
+ mpfr_init2 (s, 2); /* We need only the sign. */
+ if (rop_cos != NULL)
+ mpfr_init2 (c, MPC_PREC_RE (rop_cos));
+ else
+ mpfr_init2 (c, 2);
+ inex_s = mpfr_sin (s, mpc_realref (op), MPC_RND_RE (rnd_sin));
+ inex_c = mpfr_cos (c, mpc_realref (op), MPC_RND_RE (rnd_cos));
+ /* We cannot use mpfr_sin_cos since we may need two distinct rounding
+ modes and the exact return values. If we need only the sign, an
+ arbitrary rounding mode will work. */
+
+ if (rop_sin != NULL) {
+ mpfr_set (mpc_realref (rop_sin), s, GMP_RNDN); /* exact */
+ inex_sin_re = inex_s;
+ mpfr_set_zero (mpc_imagref (rop_sin),
+ ( ( sign_im && !mpfr_signbit(c))
+ || (!sign_im && mpfr_signbit(c)) ? -1 : 1));
+ }
+
+ if (rop_cos != NULL) {
+ mpfr_set (mpc_realref (rop_cos), c, GMP_RNDN); /* exact */
+ inex_cos_re = inex_c;
+ mpfr_set_zero (mpc_imagref (rop_cos),
+ ( ( sign_im && mpfr_signbit(s))
+ || (!sign_im && !mpfr_signbit(s)) ? -1 : 1));
+ }
+
+ mpfr_clear (s);
+ mpfr_clear (c);
+
+ return MPC_INEX12 (MPC_INEX (inex_sin_re, 0), MPC_INEX (inex_cos_re, 0));
+}
+
+
+static int
+mpc_sin_cos_imag (mpc_ptr rop_sin, mpc_ptr rop_cos, mpc_srcptr op,
+ mpc_rnd_t rnd_sin, mpc_rnd_t rnd_cos)
+ /* assumes that op is purely imaginary, but not zero */
+{
+ int inex_sin_im = 0, inex_cos_re = 0;
+ /* assume exact if not computed */
+ int overlap;
+ mpc_t op_loc;
+
+ overlap = (rop_sin == op || rop_cos == op);
+ if (overlap) {
+ mpc_init3 (op_loc, MPC_PREC_RE (op), MPC_PREC_IM (op));
+ mpc_set (op_loc, op, MPC_RNDNN);
+ }
+ else
+ op_loc [0] = op [0];
+
+ if (rop_sin != NULL) {
+ /* sin(+-O +i*y) = +-0 +i*sinh(y) */
+ mpfr_set (mpc_realref(rop_sin), mpc_realref(op_loc), GMP_RNDN);
+ inex_sin_im = mpfr_sinh (mpc_imagref(rop_sin), mpc_imagref(op_loc), MPC_RND_IM(rnd_sin));
+ }
+
+ if (rop_cos != NULL) {
+ /* cos(-0 - i * y) = cos(+0 + i * y) = cosh(y) - i * 0,
+ cos(-0 + i * y) = cos(+0 - i * y) = cosh(y) + i * 0,
+ where y > 0 */
+ inex_cos_re = mpfr_cosh (mpc_realref (rop_cos), mpc_imagref (op_loc), MPC_RND_RE (rnd_cos));
+
+ mpfr_set_ui (mpc_imagref (rop_cos), 0ul, MPC_RND_IM (rnd_cos));
+ if (mpfr_signbit (mpc_realref (op_loc)) == mpfr_signbit (mpc_imagref (op_loc)))
+ MPFR_CHANGE_SIGN (mpc_imagref (rop_cos));
+ }
+
+ if (overlap)
+ mpc_clear (op_loc);
+
+ return MPC_INEX12 (MPC_INEX (0, inex_sin_im), MPC_INEX (inex_cos_re, 0));
+}
+
+
+int
+mpc_sin_cos (mpc_ptr rop_sin, mpc_ptr rop_cos, mpc_srcptr op,
+ mpc_rnd_t rnd_sin, mpc_rnd_t rnd_cos)
+ /* Feature not documented in the texinfo file: One of rop_sin or
+ rop_cos may be NULL, in which case it is not computed, and the
+ corresponding ternary inexact value is set to 0 (exact). */
+{
+ if (!mpc_fin_p (op))
+ return mpc_sin_cos_nonfinite (rop_sin, rop_cos, op, rnd_sin, rnd_cos);
+ else if (mpfr_zero_p (mpc_imagref (op)))
+ return mpc_sin_cos_real (rop_sin, rop_cos, op, rnd_sin, rnd_cos);
+ else if (mpfr_zero_p (mpc_realref (op)))
+ return mpc_sin_cos_imag (rop_sin, rop_cos, op, rnd_sin, rnd_cos);
+ else {
+ /* let op = a + i*b, then sin(op) = sin(a)*cosh(b) + i*cos(a)*sinh(b)
+ and cos(op) = cos(a)*cosh(b) - i*sin(a)*sinh(b).
+
+ For Re(sin(op)) (and analogously, the other parts), we use the
+ following algorithm, with rounding to nearest for all operations
+ and working precision w:
+
+ (1) x = o(sin(a))
+ (2) y = o(cosh(b))
+ (3) r = o(x*y)
+ then the error on r is at most 4 ulps, since we can write
+ r = sin(a)*cosh(b)*(1+t)^3 with |t| <= 2^(-w),
+ thus for w >= 2, r = sin(a)*cosh(b)*(1+4*t) with |t| <= 2^(-w),
+ thus the relative error is bounded by 4*2^(-w) <= 4*ulp(r).
+ */
+ mpfr_t s, c, sh, ch, sch, csh;
+ mpfr_prec_t prec;
+ int ok;
+ int inex_re, inex_im, inex_sin, inex_cos;
+
+ prec = 2;
+ if (rop_sin != NULL)
+ prec = MPC_MAX (prec, MPC_MAX_PREC (rop_sin));
+ if (rop_cos != NULL)
+ prec = MPC_MAX (prec, MPC_MAX_PREC (rop_cos));
+
+ mpfr_init2 (s, 2);
+ mpfr_init2 (c, 2);
+ mpfr_init2 (sh, 2);
+ mpfr_init2 (ch, 2);
+ mpfr_init2 (sch, 2);
+ mpfr_init2 (csh, 2);
+
+ do {
+ ok = 1;
+ prec += mpc_ceil_log2 (prec) + 5;
+
+ mpfr_set_prec (s, prec);
+ mpfr_set_prec (c, prec);
+ mpfr_set_prec (sh, prec);
+ mpfr_set_prec (ch, prec);
+ mpfr_set_prec (sch, prec);
+ mpfr_set_prec (csh, prec);
+
+ mpfr_sin_cos (s, c, mpc_realref(op), GMP_RNDN);
+ mpfr_sinh_cosh (sh, ch, mpc_imagref(op), GMP_RNDN);
+
+ if (rop_sin != NULL) {
+ /* real part of sine */
+ mpfr_mul (sch, s, ch, GMP_RNDN);
+ ok = (!mpfr_number_p (sch))
+ || mpfr_can_round (sch, prec - 2, GMP_RNDN, GMP_RNDZ,
+ MPC_PREC_RE (rop_sin)
+ + (MPC_RND_RE (rnd_sin) == GMP_RNDN));
+
+ if (ok) {
+ /* imaginary part of sine */
+ mpfr_mul (csh, c, sh, GMP_RNDN);
+ ok = (!mpfr_number_p (csh))
+ || mpfr_can_round (csh, prec - 2, GMP_RNDN, GMP_RNDZ,
+ MPC_PREC_IM (rop_sin)
+ + (MPC_RND_IM (rnd_sin) == GMP_RNDN));
+ }
+ }
+
+ if (rop_cos != NULL && ok) {
+ /* real part of cosine */
+ mpfr_mul (c, c, ch, GMP_RNDN);
+ ok = (!mpfr_number_p (c))
+ || mpfr_can_round (c, prec - 2, GMP_RNDN, GMP_RNDZ,
+ MPC_PREC_RE (rop_cos)
+ + (MPC_RND_RE (rnd_cos) == GMP_RNDN));
+
+ if (ok) {
+ /* imaginary part of cosine */
+ mpfr_mul (s, s, sh, GMP_RNDN);
+ mpfr_neg (s, s, GMP_RNDN);
+ ok = (!mpfr_number_p (s))
+ || mpfr_can_round (s, prec - 2, GMP_RNDN, GMP_RNDZ,
+ MPC_PREC_IM (rop_cos)
+ + (MPC_RND_IM (rnd_cos) == GMP_RNDN));
+ }
+ }
+ } while (ok == 0);
+
+ if (rop_sin != NULL) {
+ inex_re = mpfr_set (mpc_realref (rop_sin), sch, MPC_RND_RE (rnd_sin));
+ if (mpfr_inf_p (sch))
+ inex_re = mpfr_sgn (sch);
+ inex_im = mpfr_set (mpc_imagref (rop_sin), csh, MPC_RND_IM (rnd_sin));
+ if (mpfr_inf_p (csh))
+ inex_im = mpfr_sgn (csh);
+ inex_sin = MPC_INEX (inex_re, inex_im);
+ }
+ else
+ inex_sin = MPC_INEX (0,0); /* return exact if not computed */
+
+ if (rop_cos != NULL) {
+ inex_re = mpfr_set (mpc_realref (rop_cos), c, MPC_RND_RE (rnd_cos));
+ if (mpfr_inf_p (c))
+ inex_re = mpfr_sgn (c);
+ inex_im = mpfr_set (mpc_imagref (rop_cos), s, MPC_RND_IM (rnd_cos));
+ if (mpfr_inf_p (s))
+ inex_im = mpfr_sgn (s);
+ inex_cos = MPC_INEX (inex_re, inex_im);
+ }
+ else
+ inex_cos = MPC_INEX (0,0); /* return exact if not computed */
+
+ mpfr_clear (s);
+ mpfr_clear (c);
+ mpfr_clear (sh);
+ mpfr_clear (ch);
+ mpfr_clear (sch);
+ mpfr_clear (csh);
+
+ return (MPC_INEX12 (inex_sin, inex_cos));
+ }
+}
diff --git a/mpc/src/sinh.c b/mpc/src/sinh.c
new file mode 100644
index 0000000000..509cc57dea
--- /dev/null
+++ b/mpc/src/sinh.c
@@ -0,0 +1,47 @@
+/* mpc_sinh -- hyperbolic sine of a complex number.
+
+Copyright (C)2008, 2009, 2011, 2012 INRIA
+
+This file is part of GNU MPC.
+
+GNU MPC is free software; you can redistribute it and/or modify it under
+the terms of the GNU Lesser General Public License as published by the
+Free Software Foundation; either version 3 of the License, or (at your
+option) any later version.
+
+GNU MPC 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 Lesser General Public License for
+more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+
+#include "mpc-impl.h"
+
+int
+mpc_sinh (mpc_ptr rop, mpc_srcptr op, mpc_rnd_t rnd)
+{
+ /* sinh(op) = -i*sin(i*op) = conj(-i*sin(conj(-i*op))) */
+ mpc_t z;
+ mpc_t sin_z;
+ int inex;
+
+ /* z := conj(-i * op) and rop = conj(-i * sin(z)), in other words, we have
+ to switch real and imaginary parts. Let us set them without copying
+ significands. */
+ mpc_realref (z)[0] = mpc_imagref (op)[0];
+ mpc_imagref (z)[0] = mpc_realref (op)[0];
+ mpc_realref (sin_z)[0] = mpc_imagref (rop)[0];
+ mpc_imagref (sin_z)[0] = mpc_realref (rop)[0];
+
+ inex = mpc_sin (sin_z, z, MPC_RND (MPC_RND_IM (rnd), MPC_RND_RE (rnd)));
+
+ /* sin_z and rop parts share the same significands, copy the rest now. */
+ mpc_realref (rop)[0] = mpc_imagref (sin_z)[0];
+ mpc_imagref (rop)[0] = mpc_realref (sin_z)[0];
+
+ /* swap inexact flags for real and imaginary parts */
+ return MPC_INEX (MPC_INEX_IM (inex), MPC_INEX_RE (inex));
+}
diff --git a/mpc/src/sqr.c b/mpc/src/sqr.c
new file mode 100644
index 0000000000..f1ce1bac8a
--- /dev/null
+++ b/mpc/src/sqr.c
@@ -0,0 +1,324 @@
+/* mpc_sqr -- Square a complex number.
+
+Copyright (C) 2002, 2005, 2008, 2009, 2010, 2011, 2012 INRIA
+
+This file is part of GNU MPC.
+
+GNU MPC is free software; you can redistribute it and/or modify it under
+the terms of the GNU Lesser General Public License as published by the
+Free Software Foundation; either version 3 of the License, or (at your
+option) any later version.
+
+GNU MPC 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 Lesser General Public License for
+more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+
+#include <stdio.h> /* for MPC_ASSERT */
+#include "mpc-impl.h"
+
+
+static int
+mpfr_fsss (mpfr_ptr z, mpfr_srcptr a, mpfr_srcptr c, mpfr_rnd_t rnd)
+{
+ /* Computes z = a^2 - c^2.
+ Assumes that a and c are finite and non-zero; so a squaring yielding
+ an infinity is an overflow, and a squaring yielding 0 is an underflow.
+ Assumes further that z is distinct from a and c. */
+
+ int inex;
+ mpfr_t u, v;
+
+ /* u=a^2, v=c^2 exactly */
+ mpfr_init2 (u, 2*mpfr_get_prec (a));
+ mpfr_init2 (v, 2*mpfr_get_prec (c));
+ mpfr_sqr (u, a, GMP_RNDN);
+ mpfr_sqr (v, c, GMP_RNDN);
+
+ /* tentatively compute z as u-v; here we need z to be distinct
+ from a and c to not lose the latter */
+ inex = mpfr_sub (z, u, v, rnd);
+
+ if (mpfr_inf_p (z)) {
+ /* replace by "correctly rounded overflow" */
+ mpfr_set_si (z, (mpfr_signbit (z) ? -1 : 1), GMP_RNDN);
+ inex = mpfr_mul_2ui (z, z, mpfr_get_emax (), rnd);
+ }
+ else if (mpfr_zero_p (u) && !mpfr_zero_p (v)) {
+ /* exactly u underflowed, determine inexact flag */
+ inex = (mpfr_signbit (u) ? 1 : -1);
+ }
+ else if (mpfr_zero_p (v) && !mpfr_zero_p (u)) {
+ /* exactly v underflowed, determine inexact flag */
+ inex = (mpfr_signbit (v) ? -1 : 1);
+ }
+ else if (mpfr_nan_p (z) || (mpfr_zero_p (u) && mpfr_zero_p (v))) {
+ /* In the first case, u and v are +inf.
+ In the second case, u and v are zeroes; their difference may be 0
+ or the least representable number, with a sign to be determined.
+ Redo the computations with mpz_t exponents */
+ mpfr_exp_t ea, ec;
+ mpz_t eu, ev;
+ /* cheat to work around the const qualifiers */
+
+ /* Normalise the input by shifting and keep track of the shifts in
+ the exponents of u and v */
+ ea = mpfr_get_exp (a);
+ ec = mpfr_get_exp (c);
+
+ mpfr_set_exp ((mpfr_ptr) a, (mpfr_prec_t) 0);
+ mpfr_set_exp ((mpfr_ptr) c, (mpfr_prec_t) 0);
+
+ mpz_init (eu);
+ mpz_init (ev);
+ mpz_set_si (eu, (long int) ea);
+ mpz_mul_2exp (eu, eu, 1);
+ mpz_set_si (ev, (long int) ec);
+ mpz_mul_2exp (ev, ev, 1);
+
+ /* recompute u and v and move exponents to eu and ev */
+ mpfr_sqr (u, a, GMP_RNDN);
+ /* exponent of u is non-positive */
+ mpz_sub_ui (eu, eu, (unsigned long int) (-mpfr_get_exp (u)));
+ mpfr_set_exp (u, (mpfr_prec_t) 0);
+ mpfr_sqr (v, c, GMP_RNDN);
+ mpz_sub_ui (ev, ev, (unsigned long int) (-mpfr_get_exp (v)));
+ mpfr_set_exp (v, (mpfr_prec_t) 0);
+ if (mpfr_nan_p (z)) {
+ mpfr_exp_t emax = mpfr_get_emax ();
+ int overflow;
+ /* We have a = ma * 2^ea with 1/2 <= |ma| < 1 and ea <= emax.
+ So eu <= 2*emax, and eu > emax since we have
+ an overflow. The same holds for ev. Shift u and v by as much as
+ possible so that one of them has exponent emax and the
+ remaining exponents in eu and ev are the same. Then carry out
+ the addition. Shifting u and v prevents an underflow. */
+ if (mpz_cmp (eu, ev) >= 0) {
+ mpfr_set_exp (u, emax);
+ mpz_sub_ui (eu, eu, (long int) emax);
+ mpz_sub (ev, ev, eu);
+ mpfr_set_exp (v, (mpfr_exp_t) mpz_get_ui (ev));
+ /* remaining common exponent is now in eu */
+ }
+ else {
+ mpfr_set_exp (v, emax);
+ mpz_sub_ui (ev, ev, (long int) emax);
+ mpz_sub (eu, eu, ev);
+ mpfr_set_exp (u, (mpfr_exp_t) mpz_get_ui (eu));
+ mpz_set (eu, ev);
+ /* remaining common exponent is now also in eu */
+ }
+ inex = mpfr_sub (z, u, v, rnd);
+ /* Result is finite since u and v have the same sign. */
+ overflow = mpfr_mul_2ui (z, z, mpz_get_ui (eu), rnd);
+ if (overflow)
+ inex = overflow;
+ }
+ else {
+ int underflow;
+ /* Subtraction of two zeroes. We have a = ma * 2^ea
+ with 1/2 <= |ma| < 1 and ea >= emin and similarly for b.
+ So 2*emin < 2*emin+1 <= eu < emin < 0, and analogously for v. */
+ mpfr_exp_t emin = mpfr_get_emin ();
+ if (mpz_cmp (eu, ev) <= 0) {
+ mpfr_set_exp (u, emin);
+ mpz_add_ui (eu, eu, (unsigned long int) (-emin));
+ mpz_sub (ev, ev, eu);
+ mpfr_set_exp (v, (mpfr_exp_t) mpz_get_si (ev));
+ }
+ else {
+ mpfr_set_exp (v, emin);
+ mpz_add_ui (ev, ev, (unsigned long int) (-emin));
+ mpz_sub (eu, eu, ev);
+ mpfr_set_exp (u, (mpfr_exp_t) mpz_get_si (eu));
+ mpz_set (eu, ev);
+ }
+ inex = mpfr_sub (z, u, v, rnd);
+ mpz_neg (eu, eu);
+ underflow = mpfr_div_2ui (z, z, mpz_get_ui (eu), rnd);
+ if (underflow)
+ inex = underflow;
+ }
+
+ mpz_clear (eu);
+ mpz_clear (ev);
+
+ mpfr_set_exp ((mpfr_ptr) a, ea);
+ mpfr_set_exp ((mpfr_ptr) c, ec);
+ /* works also when a == c */
+ }
+
+ mpfr_clear (u);
+ mpfr_clear (v);
+
+ return inex;
+}
+
+
+int
+mpc_sqr (mpc_ptr rop, mpc_srcptr op, mpc_rnd_t rnd)
+{
+ int ok;
+ mpfr_t u, v;
+ mpfr_t x;
+ /* temporary variable to hold the real part of op,
+ needed in the case rop==op */
+ mpfr_prec_t prec;
+ int inex_re, inex_im, inexact;
+ mpfr_exp_t emin;
+ int saved_underflow;
+
+ /* special values: NaN and infinities */
+ if (!mpc_fin_p (op)) {
+ if (mpfr_nan_p (mpc_realref (op)) || mpfr_nan_p (mpc_imagref (op))) {
+ mpfr_set_nan (mpc_realref (rop));
+ mpfr_set_nan (mpc_imagref (rop));
+ }
+ else if (mpfr_inf_p (mpc_realref (op))) {
+ if (mpfr_inf_p (mpc_imagref (op))) {
+ mpfr_set_inf (mpc_imagref (rop),
+ MPFR_SIGN (mpc_realref (op)) * MPFR_SIGN (mpc_imagref (op)));
+ mpfr_set_nan (mpc_realref (rop));
+ }
+ else {
+ if (mpfr_zero_p (mpc_imagref (op)))
+ mpfr_set_nan (mpc_imagref (rop));
+ else
+ mpfr_set_inf (mpc_imagref (rop),
+ MPFR_SIGN (mpc_realref (op)) * MPFR_SIGN (mpc_imagref (op)));
+ mpfr_set_inf (mpc_realref (rop), +1);
+ }
+ }
+ else /* IM(op) is infinity, RE(op) is not */ {
+ if (mpfr_zero_p (mpc_realref (op)))
+ mpfr_set_nan (mpc_imagref (rop));
+ else
+ mpfr_set_inf (mpc_imagref (rop),
+ MPFR_SIGN (mpc_realref (op)) * MPFR_SIGN (mpc_imagref (op)));
+ mpfr_set_inf (mpc_realref (rop), -1);
+ }
+ return MPC_INEX (0, 0); /* exact */
+ }
+
+ prec = MPC_MAX_PREC(rop);
+
+ /* Check for real resp. purely imaginary number */
+ if (mpfr_zero_p (mpc_imagref(op))) {
+ int same_sign = mpfr_signbit (mpc_realref (op)) == mpfr_signbit (mpc_imagref (op));
+ inex_re = mpfr_sqr (mpc_realref(rop), mpc_realref(op), MPC_RND_RE(rnd));
+ inex_im = mpfr_set_ui (mpc_imagref(rop), 0ul, GMP_RNDN);
+ if (!same_sign)
+ mpc_conj (rop, rop, MPC_RNDNN);
+ return MPC_INEX(inex_re, inex_im);
+ }
+ if (mpfr_zero_p (mpc_realref(op))) {
+ int same_sign = mpfr_signbit (mpc_realref (op)) == mpfr_signbit (mpc_imagref (op));
+ inex_re = -mpfr_sqr (mpc_realref(rop), mpc_imagref(op), INV_RND (MPC_RND_RE(rnd)));
+ mpfr_neg (mpc_realref(rop), mpc_realref(rop), GMP_RNDN);
+ inex_im = mpfr_set_ui (mpc_imagref(rop), 0ul, GMP_RNDN);
+ if (!same_sign)
+ mpc_conj (rop, rop, MPC_RNDNN);
+ return MPC_INEX(inex_re, inex_im);
+ }
+
+ if (rop == op)
+ {
+ mpfr_init2 (x, MPC_PREC_RE (op));
+ mpfr_set (x, op->re, GMP_RNDN);
+ }
+ else
+ x [0] = op->re [0];
+ /* From here on, use x instead of op->re and safely overwrite rop->re. */
+
+ /* Compute real part of result. */
+ if (SAFE_ABS (mpfr_exp_t,
+ mpfr_get_exp (mpc_realref (op)) - mpfr_get_exp (mpc_imagref (op)))
+ > (mpfr_exp_t) MPC_MAX_PREC (op) / 2) {
+ /* If the real and imaginary parts of the argument have very different
+ exponents, it is not reasonable to use Karatsuba squaring; compute
+ exactly with the standard formulae instead, even if this means an
+ additional multiplication. Using the approach copied from mul, over-
+ and underflows are also handled correctly. */
+
+ inex_re = mpfr_fsss (rop->re, x, op->im, MPC_RND_RE (rnd));
+ }
+ else {
+ /* Karatsuba squaring: we compute the real part as (x+y)*(x-y) and the
+ imaginary part as 2*x*y, with a total of 2M instead of 2S+1M for the
+ naive algorithm, which computes x^2-y^2 and 2*y*y */
+ mpfr_init (u);
+ mpfr_init (v);
+
+ emin = mpfr_get_emin ();
+
+ do
+ {
+ prec += mpc_ceil_log2 (prec) + 5;
+
+ mpfr_set_prec (u, prec);
+ mpfr_set_prec (v, prec);
+
+ /* Let op = x + iy. We need u = x+y and v = x-y, rounded away. */
+ /* The error is bounded above by 1 ulp. */
+ /* We first let inexact be 1 if the real part is not computed */
+ /* exactly and determine the sign later. */
+ inexact = ROUND_AWAY (mpfr_add (u, x, mpc_imagref (op), MPFR_RNDA), u)
+ | ROUND_AWAY (mpfr_sub (v, x, mpc_imagref (op), MPFR_RNDA), v);
+
+ /* compute the real part as u*v, rounded away */
+ /* determine also the sign of inex_re */
+
+ if (mpfr_sgn (u) == 0 || mpfr_sgn (v) == 0) {
+ /* as we have rounded away, the result is exact */
+ mpfr_set_ui (mpc_realref (rop), 0, GMP_RNDN);
+ inex_re = 0;
+ ok = 1;
+ }
+ else {
+ mpfr_rnd_t rnd_away;
+ /* FIXME: can be replaced by MPFR_RNDA in mpfr >= 3 */
+ rnd_away = (mpfr_sgn (u) * mpfr_sgn (v) > 0 ? GMP_RNDU : GMP_RNDD);
+ inexact |= ROUND_AWAY (mpfr_mul (u, u, v, MPFR_RNDA), u); /* error 5 */
+ if (mpfr_get_exp (u) == emin || mpfr_inf_p (u)) {
+ /* under- or overflow */
+ inex_re = mpfr_fsss (rop->re, x, op->im, MPC_RND_RE (rnd));
+ ok = 1;
+ }
+ else {
+ ok = (!inexact) | mpfr_can_round (u, prec - 3,
+ rnd_away, GMP_RNDZ,
+ MPC_PREC_RE (rop) + (MPC_RND_RE (rnd) == GMP_RNDN));
+ if (ok) {
+ inex_re = mpfr_set (mpc_realref (rop), u, MPC_RND_RE (rnd));
+ if (inex_re == 0)
+ /* remember that u was already rounded */
+ inex_re = inexact;
+ }
+ }
+ }
+ }
+ while (!ok);
+
+ mpfr_clear (u);
+ mpfr_clear (v);
+ }
+
+ saved_underflow = mpfr_underflow_p ();
+ mpfr_clear_underflow ();
+ inex_im = mpfr_mul (rop->im, x, op->im, MPC_RND_IM (rnd));
+ if (!mpfr_underflow_p ())
+ inex_im |= mpfr_mul_2ui (rop->im, rop->im, 1, MPC_RND_IM (rnd));
+ /* We must not multiply by 2 if rop->im has been set to the smallest
+ representable number. */
+ if (saved_underflow)
+ mpfr_set_underflow ();
+
+ if (rop == op)
+ mpfr_clear (x);
+
+ return MPC_INEX (inex_re, inex_im);
+}
diff --git a/mpc/src/sqrt.c b/mpc/src/sqrt.c
new file mode 100644
index 0000000000..dd2ff60034
--- /dev/null
+++ b/mpc/src/sqrt.c
@@ -0,0 +1,364 @@
+/* mpc_sqrt -- Take the square root of a complex number.
+
+Copyright (C) 2002, 2008, 2009, 2010, 2011, 2012 INRIA
+
+This file is part of GNU MPC.
+
+GNU MPC is free software; you can redistribute it and/or modify it under
+the terms of the GNU Lesser General Public License as published by the
+Free Software Foundation; either version 3 of the License, or (at your
+option) any later version.
+
+GNU MPC 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 Lesser General Public License for
+more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+
+#include "mpc-impl.h"
+
+#if MPFR_VERSION_MAJOR < 3
+#define mpfr_min_prec(x) \
+ ( ((prec + BITS_PER_MP_LIMB - 1) / BITS_PER_MP_LIMB) * BITS_PER_MP_LIMB \
+ - mpn_scan1 (x->_mpfr_d, 0))
+#endif
+
+
+int
+mpc_sqrt (mpc_ptr a, mpc_srcptr b, mpc_rnd_t rnd)
+{
+ int ok_w, ok_t = 0;
+ mpfr_t w, t;
+ mpfr_rnd_t rnd_w, rnd_t;
+ mpfr_prec_t prec_w, prec_t;
+ /* the rounding mode and the precision required for w and t, which can */
+ /* be either the real or the imaginary part of a */
+ mpfr_prec_t prec;
+ int inex_w, inex_t = 1, inex_re, inex_im, loops = 0;
+ const int re_cmp = mpfr_cmp_ui (mpc_realref (b), 0),
+ im_cmp = mpfr_cmp_ui (mpc_imagref (b), 0);
+ /* comparison of the real/imaginary part of b with 0 */
+ int repr_w, repr_t = 0 /* to avoid gcc warning */ ;
+ /* flag indicating whether the computed value is already representable
+ at the target precision */
+ const int im_sgn = mpfr_signbit (mpc_imagref (b)) == 0 ? 0 : -1;
+ /* we need to know the sign of Im(b) when it is +/-0 */
+ const mpfr_rnd_t r = im_sgn ? GMP_RNDD : GMP_RNDU;
+ /* rounding mode used when computing t */
+
+ /* special values */
+ if (!mpc_fin_p (b)) {
+ /* sqrt(x +i*Inf) = +Inf +I*Inf, even if x = NaN */
+ /* sqrt(x -i*Inf) = +Inf -I*Inf, even if x = NaN */
+ if (mpfr_inf_p (mpc_imagref (b)))
+ {
+ mpfr_set_inf (mpc_realref (a), +1);
+ mpfr_set_inf (mpc_imagref (a), im_sgn);
+ return MPC_INEX (0, 0);
+ }
+
+ if (mpfr_inf_p (mpc_realref (b)))
+ {
+ if (mpfr_signbit (mpc_realref (b)))
+ {
+ if (mpfr_number_p (mpc_imagref (b)))
+ {
+ /* sqrt(-Inf +i*y) = +0 +i*Inf, when y positive */
+ /* sqrt(-Inf +i*y) = +0 -i*Inf, when y positive */
+ mpfr_set_ui (mpc_realref (a), 0, GMP_RNDN);
+ mpfr_set_inf (mpc_imagref (a), im_sgn);
+ return MPC_INEX (0, 0);
+ }
+ else
+ {
+ /* sqrt(-Inf +i*NaN) = NaN +/-i*Inf */
+ mpfr_set_nan (mpc_realref (a));
+ mpfr_set_inf (mpc_imagref (a), im_sgn);
+ return MPC_INEX (0, 0);
+ }
+ }
+ else
+ {
+ if (mpfr_number_p (mpc_imagref (b)))
+ {
+ /* sqrt(+Inf +i*y) = +Inf +i*0, when y positive */
+ /* sqrt(+Inf +i*y) = +Inf -i*0, when y positive */
+ mpfr_set_inf (mpc_realref (a), +1);
+ mpfr_set_ui (mpc_imagref (a), 0, GMP_RNDN);
+ if (im_sgn)
+ mpc_conj (a, a, MPC_RNDNN);
+ return MPC_INEX (0, 0);
+ }
+ else
+ {
+ /* sqrt(+Inf -i*Inf) = +Inf -i*Inf */
+ /* sqrt(+Inf +i*Inf) = +Inf +i*Inf */
+ /* sqrt(+Inf +i*NaN) = +Inf +i*NaN */
+ return mpc_set (a, b, rnd);
+ }
+ }
+ }
+
+ /* sqrt(x +i*NaN) = NaN +i*NaN, if x is not infinite */
+ /* sqrt(NaN +i*y) = NaN +i*NaN, if y is not infinite */
+ if (mpfr_nan_p (mpc_realref (b)) || mpfr_nan_p (mpc_imagref (b)))
+ {
+ mpfr_set_nan (mpc_realref (a));
+ mpfr_set_nan (mpc_imagref (a));
+ return MPC_INEX (0, 0);
+ }
+ }
+
+ /* purely real */
+ if (im_cmp == 0)
+ {
+ if (re_cmp == 0)
+ {
+ mpc_set_ui_ui (a, 0, 0, MPC_RNDNN);
+ if (im_sgn)
+ mpc_conj (a, a, MPC_RNDNN);
+ return MPC_INEX (0, 0);
+ }
+ else if (re_cmp > 0)
+ {
+ inex_w = mpfr_sqrt (mpc_realref (a), mpc_realref (b), MPC_RND_RE (rnd));
+ mpfr_set_ui (mpc_imagref (a), 0, GMP_RNDN);
+ if (im_sgn)
+ mpc_conj (a, a, MPC_RNDNN);
+ return MPC_INEX (inex_w, 0);
+ }
+ else
+ {
+ mpfr_init2 (w, MPC_PREC_RE (b));
+ mpfr_neg (w, mpc_realref (b), GMP_RNDN);
+ if (im_sgn)
+ {
+ inex_w = -mpfr_sqrt (mpc_imagref (a), w, INV_RND (MPC_RND_IM (rnd)));
+ mpfr_neg (mpc_imagref (a), mpc_imagref (a), GMP_RNDN);
+ }
+ else
+ inex_w = mpfr_sqrt (mpc_imagref (a), w, MPC_RND_IM (rnd));
+
+ mpfr_set_ui (mpc_realref (a), 0, GMP_RNDN);
+ mpfr_clear (w);
+ return MPC_INEX (0, inex_w);
+ }
+ }
+
+ /* purely imaginary */
+ if (re_cmp == 0)
+ {
+ mpfr_t y;
+
+ y[0] = mpc_imagref (b)[0];
+ /* If y/2 underflows, so does sqrt(y/2) */
+ mpfr_div_2ui (y, y, 1, GMP_RNDN);
+ if (im_cmp > 0)
+ {
+ inex_w = mpfr_sqrt (mpc_realref (a), y, MPC_RND_RE (rnd));
+ inex_t = mpfr_sqrt (mpc_imagref (a), y, MPC_RND_IM (rnd));
+ }
+ else
+ {
+ mpfr_neg (y, y, GMP_RNDN);
+ inex_w = mpfr_sqrt (mpc_realref (a), y, MPC_RND_RE (rnd));
+ inex_t = -mpfr_sqrt (mpc_imagref (a), y, INV_RND (MPC_RND_IM (rnd)));
+ mpfr_neg (mpc_imagref (a), mpc_imagref (a), GMP_RNDN);
+ }
+ return MPC_INEX (inex_w, inex_t);
+ }
+
+ prec = MPC_MAX_PREC(a);
+
+ mpfr_init (w);
+ mpfr_init (t);
+
+ if (re_cmp > 0) {
+ rnd_w = MPC_RND_RE (rnd);
+ prec_w = MPC_PREC_RE (a);
+ rnd_t = MPC_RND_IM(rnd);
+ if (rnd_t == GMP_RNDZ)
+ /* force GMP_RNDD or GMP_RNDUP, using sign(t) = sign(y) */
+ rnd_t = (im_cmp > 0 ? GMP_RNDD : GMP_RNDU);
+ prec_t = MPC_PREC_IM (a);
+ }
+ else {
+ prec_w = MPC_PREC_IM (a);
+ prec_t = MPC_PREC_RE (a);
+ if (im_cmp > 0) {
+ rnd_w = MPC_RND_IM(rnd);
+ rnd_t = MPC_RND_RE(rnd);
+ if (rnd_t == GMP_RNDZ)
+ rnd_t = GMP_RNDD;
+ }
+ else {
+ rnd_w = INV_RND(MPC_RND_IM (rnd));
+ rnd_t = INV_RND(MPC_RND_RE (rnd));
+ if (rnd_t == GMP_RNDZ)
+ rnd_t = GMP_RNDU;
+ }
+ }
+
+ do
+ {
+ loops ++;
+ prec += (loops <= 2) ? mpc_ceil_log2 (prec) + 4 : prec / 2;
+ mpfr_set_prec (w, prec);
+ mpfr_set_prec (t, prec);
+ /* let b = x + iy */
+ /* w = sqrt ((|x| + sqrt (x^2 + y^2)) / 2), rounded down */
+ /* total error bounded by 3 ulps */
+ inex_w = mpc_abs (w, b, GMP_RNDD);
+ if (re_cmp < 0)
+ inex_w |= mpfr_sub (w, w, mpc_realref (b), GMP_RNDD);
+ else
+ inex_w |= mpfr_add (w, w, mpc_realref (b), GMP_RNDD);
+ inex_w |= mpfr_div_2ui (w, w, 1, GMP_RNDD);
+ inex_w |= mpfr_sqrt (w, w, GMP_RNDD);
+
+ repr_w = mpfr_min_prec (w) <= prec_w;
+ if (!repr_w)
+ /* use the usual trick for obtaining the ternary value */
+ ok_w = mpfr_can_round (w, prec - 2, GMP_RNDD, GMP_RNDU,
+ prec_w + (rnd_w == GMP_RNDN));
+ else {
+ /* w is representable in the target precision and thus cannot be
+ rounded up */
+ if (rnd_w == GMP_RNDN)
+ /* If w can be rounded to nearest, then actually no rounding
+ occurs, and the ternary value is known from inex_w. */
+ ok_w = mpfr_can_round (w, prec - 2, GMP_RNDD, GMP_RNDN, prec_w);
+ else
+ /* If w can be rounded down, then any direct rounding and the
+ ternary flag can be determined from inex_w. */
+ ok_w = mpfr_can_round (w, prec - 2, GMP_RNDD, GMP_RNDD, prec_w);
+ }
+
+ if (!inex_w || ok_w) {
+ /* t = y / 2w, rounded away */
+ /* total error bounded by 7 ulps */
+ inex_t = mpfr_div (t, mpc_imagref (b), w, r);
+ if (!inex_t && inex_w)
+ /* The division was exact, but w was not. */
+ inex_t = im_sgn ? -1 : 1;
+ inex_t |= mpfr_div_2ui (t, t, 1, r);
+ repr_t = mpfr_min_prec (t) <= prec_t;
+ if (!repr_t)
+ /* As for w; since t was rounded away, we check whether rounding to 0
+ is possible. */
+ ok_t = mpfr_can_round (t, prec - 3, r, GMP_RNDZ,
+ prec_t + (rnd_t == GMP_RNDN));
+ else {
+ if (rnd_t == GMP_RNDN)
+ ok_t = mpfr_can_round (t, prec - 3, r, GMP_RNDN, prec_t);
+ else
+ ok_t = mpfr_can_round (t, prec - 3, r, r, prec_t);
+ }
+ }
+ }
+ while ((inex_w && !ok_w) || (inex_t && !ok_t));
+
+ if (re_cmp > 0) {
+ inex_re = mpfr_set (mpc_realref (a), w, MPC_RND_RE(rnd));
+ inex_im = mpfr_set (mpc_imagref (a), t, MPC_RND_IM(rnd));
+ }
+ else if (im_cmp > 0) {
+ inex_re = mpfr_set (mpc_realref(a), t, MPC_RND_RE(rnd));
+ inex_im = mpfr_set (mpc_imagref(a), w, MPC_RND_IM(rnd));
+ }
+ else {
+ inex_re = mpfr_neg (mpc_realref (a), t, MPC_RND_RE(rnd));
+ inex_im = mpfr_neg (mpc_imagref (a), w, MPC_RND_IM(rnd));
+ }
+
+ if (repr_w && inex_w) {
+ if (rnd_w == GMP_RNDN) {
+ /* w has not been rounded with mpfr_set/mpfr_neg, determine ternary
+ value from inex_w instead */
+ if (re_cmp > 0)
+ inex_re = inex_w;
+ else if (im_cmp > 0)
+ inex_im = inex_w;
+ else
+ inex_im = -inex_w;
+ }
+ else {
+ /* determine ternary value, but also potentially add 1 ulp; can only
+ be done now when we are in the target precision */
+ if (re_cmp > 0) {
+ if (rnd_w == GMP_RNDU) {
+ MPFR_ADD_ONE_ULP (mpc_realref (a));
+ inex_re = +1;
+ }
+ else
+ inex_re = -1;
+ }
+ else if (im_cmp > 0) {
+ if (rnd_w == GMP_RNDU) {
+ MPFR_ADD_ONE_ULP (mpc_imagref (a));
+ inex_im = +1;
+ }
+ else
+ inex_im = -1;
+ }
+ else {
+ if (rnd_w == GMP_RNDU) {
+ MPFR_ADD_ONE_ULP (mpc_imagref (a));
+ inex_im = -1;
+ }
+ else
+ inex_im = +1;
+ }
+ }
+ }
+ if (repr_t && inex_t) {
+ if (rnd_t == GMP_RNDN) {
+ if (re_cmp > 0)
+ inex_im = inex_t;
+ else if (im_cmp > 0)
+ inex_re = inex_t;
+ else
+ inex_re = -inex_t;
+ }
+ else {
+ if (re_cmp > 0) {
+ if (rnd_t == r)
+ inex_im = inex_t;
+ else {
+ inex_im = -inex_t;
+ /* im_cmp > 0 implies that Im(b) > 0, thus im_sgn = 0
+ and r = GMP_RNDU.
+ im_cmp < 0 implies that Im(b) < 0, thus im_sgn = -1
+ and r = GMP_RNDD. */
+ MPFR_SUB_ONE_ULP (mpc_imagref (a));
+ }
+ }
+ else if (im_cmp > 0) {
+ if (rnd_t == r)
+ inex_re = inex_t;
+ else {
+ inex_re = -inex_t;
+ /* im_cmp > 0 implies r = GMP_RNDU (see above) */
+ MPFR_SUB_ONE_ULP (mpc_realref (a));
+ }
+ }
+ else { /* im_cmp < 0 */
+ if (rnd_t == r)
+ inex_re = -inex_t;
+ else {
+ inex_re = inex_t;
+ /* im_cmp < 0 implies r = GMP_RNDD (see above) */
+ MPFR_SUB_ONE_ULP (mpc_realref (a));
+ }
+ }
+ }
+ }
+
+ mpfr_clear (w);
+ mpfr_clear (t);
+
+ return MPC_INEX (inex_re, inex_im);
+}
diff --git a/mpc/src/strtoc.c b/mpc/src/strtoc.c
new file mode 100644
index 0000000000..b96ccee528
--- /dev/null
+++ b/mpc/src/strtoc.c
@@ -0,0 +1,89 @@
+/* mpc_strtoc -- Read a complex number from a string.
+
+Copyright (C) 2009, 2010, 2011 INRIA
+
+This file is part of GNU MPC.
+
+GNU MPC is free software; you can redistribute it and/or modify it under
+the terms of the GNU Lesser General Public License as published by the
+Free Software Foundation; either version 3 of the License, or (at your
+option) any later version.
+
+GNU MPC 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 Lesser General Public License for
+more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+
+#include <string.h>
+#include <ctype.h>
+#include "mpc-impl.h"
+
+static void
+skip_whitespace (const char **p)
+{
+ /* TODO: This function had better be inlined, but it is unclear whether
+ the hassle to get this implemented across all platforms is worth it. */
+ while (isspace ((unsigned char) **p))
+ (*p)++;
+}
+
+int
+mpc_strtoc (mpc_ptr rop, const char *nptr, char **endptr, int base, mpc_rnd_t rnd)
+{
+ const char *p;
+ char *end;
+ int bracketed = 0;
+
+ int inex_re = 0, inex_im = 0;
+
+ if (nptr == NULL || base > 36 || base == 1)
+ goto error;
+
+ p = nptr;
+ skip_whitespace (&p);
+
+ if (*p == '('){
+ bracketed = 1;
+ ++p;
+ }
+
+ inex_re = mpfr_strtofr (mpc_realref(rop), p, &end, base, MPC_RND_RE (rnd));
+ if (end == p)
+ goto error;
+ p = end;
+
+ if (!bracketed)
+ inex_im = mpfr_set_ui (mpc_imagref (rop), 0ul, GMP_RNDN);
+ else {
+ if (!isspace ((unsigned char)*p))
+ goto error;
+
+ skip_whitespace (&p);
+
+ inex_im = mpfr_strtofr (mpc_imagref(rop), p, &end, base, MPC_RND_IM (rnd));
+ if (end == p)
+ goto error;
+ p = end;
+
+ skip_whitespace (&p);
+ if (*p != ')')
+ goto error;
+
+ p++;
+ }
+
+ if (endptr != NULL)
+ *endptr = (char*) p;
+ return MPC_INEX (inex_re, inex_im);
+
+error:
+ if (endptr != NULL)
+ *endptr = (char*) nptr;
+ mpfr_set_nan (mpc_realref (rop));
+ mpfr_set_nan (mpc_imagref (rop));
+ return -1;
+}
diff --git a/mpc/src/sub.c b/mpc/src/sub.c
new file mode 100644
index 0000000000..8b8a97d24f
--- /dev/null
+++ b/mpc/src/sub.c
@@ -0,0 +1,32 @@
+/* mpc_sub -- Subtract two complex numbers.
+
+Copyright (C) 2002, 2009, 2011 INRIA
+
+This file is part of GNU MPC.
+
+GNU MPC is free software; you can redistribute it and/or modify it under
+the terms of the GNU Lesser General Public License as published by the
+Free Software Foundation; either version 3 of the License, or (at your
+option) any later version.
+
+GNU MPC 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 Lesser General Public License for
+more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+
+#include "mpc-impl.h"
+
+int
+mpc_sub (mpc_ptr a, mpc_srcptr b, mpc_srcptr c, mpc_rnd_t rnd)
+{
+ int inex_re, inex_im;
+
+ inex_re = mpfr_sub (mpc_realref(a), mpc_realref(b), mpc_realref(c), MPC_RND_RE(rnd));
+ inex_im = mpfr_sub (mpc_imagref(a), mpc_imagref(b), mpc_imagref(c), MPC_RND_IM(rnd));
+
+ return MPC_INEX(inex_re, inex_im);
+}
diff --git a/mpc/src/sub_fr.c b/mpc/src/sub_fr.c
new file mode 100644
index 0000000000..ade33a95cd
--- /dev/null
+++ b/mpc/src/sub_fr.c
@@ -0,0 +1,34 @@
+/* mpc_sub_fr -- Substract a floating-point number to the real part of a
+ complex number.
+
+Copyright (C) 2008, 2009, 2011 INRIA
+
+This file is part of GNU MPC.
+
+GNU MPC is free software; you can redistribute it and/or modify it under
+the terms of the GNU Lesser General Public License as published by the
+Free Software Foundation; either version 3 of the License, or (at your
+option) any later version.
+
+GNU MPC 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 Lesser General Public License for
+more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+
+#include "mpc-impl.h"
+
+/* return 0 iff both the real and imaginary parts are exact */
+int
+mpc_sub_fr (mpc_ptr a, mpc_srcptr b, mpfr_srcptr c, mpc_rnd_t rnd)
+{
+ int inex_re, inex_im;
+
+ inex_re = mpfr_sub (mpc_realref(a), mpc_realref(b), c, MPC_RND_RE(rnd));
+ inex_im = mpfr_set (mpc_imagref(a), mpc_imagref(b), MPC_RND_IM(rnd));
+
+ return MPC_INEX(inex_re, inex_im);
+}
diff --git a/mpc/src/sub_ui.c b/mpc/src/sub_ui.c
new file mode 100644
index 0000000000..561c469676
--- /dev/null
+++ b/mpc/src/sub_ui.c
@@ -0,0 +1,33 @@
+/* mpc_sub_ui -- Add a complex number and an unsigned long int.
+
+Copyright (C) 2002, 2009, 2011 INRIA
+
+This file is part of GNU MPC.
+
+GNU MPC is free software; you can redistribute it and/or modify it under
+the terms of the GNU Lesser General Public License as published by the
+Free Software Foundation; either version 3 of the License, or (at your
+option) any later version.
+
+GNU MPC 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 Lesser General Public License for
+more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+
+#include "mpc-impl.h"
+
+/* return 0 iff both the real and imaginary parts are exact */
+int
+mpc_sub_ui (mpc_ptr a, mpc_srcptr b, unsigned long int c, mpc_rnd_t rnd)
+{
+ int inex_re, inex_im;
+
+ inex_re = mpfr_sub_ui (mpc_realref(a), mpc_realref(b), c, MPC_RND_RE(rnd));
+ inex_im = mpfr_set (mpc_imagref(a), mpc_imagref(b), MPC_RND_IM(rnd));
+
+ return MPC_INEX(inex_re, inex_im);
+}
diff --git a/mpc/src/swap.c b/mpc/src/swap.c
new file mode 100644
index 0000000000..9590132e3b
--- /dev/null
+++ b/mpc/src/swap.c
@@ -0,0 +1,29 @@
+/* mpc_swap -- Swap two complex numbers.
+
+Copyright (C) 2009, 2011 INRIA
+
+This file is part of GNU MPC.
+
+GNU MPC is free software; you can redistribute it and/or modify it under
+the terms of the GNU Lesser General Public License as published by the
+Free Software Foundation; either version 3 of the License, or (at your
+option) any later version.
+
+GNU MPC 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 Lesser General Public License for
+more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+
+#include "mpc-impl.h"
+
+void
+mpc_swap (mpc_ptr a, mpc_ptr b)
+{
+ /* assumes real and imaginary parts do not overlap */
+ mpfr_swap (mpc_realref(a), mpc_realref(b));
+ mpfr_swap (mpc_imagref(a), mpc_imagref(b));
+}
diff --git a/mpc/src/tan.c b/mpc/src/tan.c
new file mode 100644
index 0000000000..24cd92b7ce
--- /dev/null
+++ b/mpc/src/tan.c
@@ -0,0 +1,284 @@
+/* mpc_tan -- tangent of a complex number.
+
+Copyright (C) 2008, 2009, 2010, 2011 INRIA
+
+This file is part of GNU MPC.
+
+GNU MPC is free software; you can redistribute it and/or modify it under
+the terms of the GNU Lesser General Public License as published by the
+Free Software Foundation; either version 3 of the License, or (at your
+option) any later version.
+
+GNU MPC 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 Lesser General Public License for
+more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+
+#include <stdio.h> /* for MPC_ASSERT */
+#include <limits.h>
+#include "mpc-impl.h"
+
+int
+mpc_tan (mpc_ptr rop, mpc_srcptr op, mpc_rnd_t rnd)
+{
+ mpc_t x, y;
+ mpfr_prec_t prec;
+ mpfr_exp_t err;
+ int ok = 0;
+ int inex;
+
+ /* special values */
+ if (!mpc_fin_p (op))
+ {
+ if (mpfr_nan_p (mpc_realref (op)))
+ {
+ if (mpfr_inf_p (mpc_imagref (op)))
+ /* tan(NaN -i*Inf) = +/-0 -i */
+ /* tan(NaN +i*Inf) = +/-0 +i */
+ {
+ /* exact unless 1 is not in exponent range */
+ inex = mpc_set_si_si (rop, 0,
+ (MPFR_SIGN (mpc_imagref (op)) < 0) ? -1 : +1,
+ rnd);
+ }
+ else
+ /* tan(NaN +i*y) = NaN +i*NaN, when y is finite */
+ /* tan(NaN +i*NaN) = NaN +i*NaN */
+ {
+ mpfr_set_nan (mpc_realref (rop));
+ mpfr_set_nan (mpc_imagref (rop));
+ inex = MPC_INEX (0, 0); /* always exact */
+ }
+ }
+ else if (mpfr_nan_p (mpc_imagref (op)))
+ {
+ if (mpfr_cmp_ui (mpc_realref (op), 0) == 0)
+ /* tan(-0 +i*NaN) = -0 +i*NaN */
+ /* tan(+0 +i*NaN) = +0 +i*NaN */
+ {
+ mpc_set (rop, op, rnd);
+ inex = MPC_INEX (0, 0); /* always exact */
+ }
+ else
+ /* tan(x +i*NaN) = NaN +i*NaN, when x != 0 */
+ {
+ mpfr_set_nan (mpc_realref (rop));
+ mpfr_set_nan (mpc_imagref (rop));
+ inex = MPC_INEX (0, 0); /* always exact */
+ }
+ }
+ else if (mpfr_inf_p (mpc_realref (op)))
+ {
+ if (mpfr_inf_p (mpc_imagref (op)))
+ /* tan(-Inf -i*Inf) = -/+0 -i */
+ /* tan(-Inf +i*Inf) = -/+0 +i */
+ /* tan(+Inf -i*Inf) = +/-0 -i */
+ /* tan(+Inf +i*Inf) = +/-0 +i */
+ {
+ const int sign_re = mpfr_signbit (mpc_realref (op));
+ int inex_im;
+
+ mpfr_set_ui (mpc_realref (rop), 0, MPC_RND_RE (rnd));
+ mpfr_setsign (mpc_realref (rop), mpc_realref (rop), sign_re, GMP_RNDN);
+
+ /* exact, unless 1 is not in exponent range */
+ inex_im = mpfr_set_si (mpc_imagref (rop),
+ mpfr_signbit (mpc_imagref (op)) ? -1 : +1,
+ MPC_RND_IM (rnd));
+ inex = MPC_INEX (0, inex_im);
+ }
+ else
+ /* tan(-Inf +i*y) = tan(+Inf +i*y) = NaN +i*NaN, when y is
+ finite */
+ {
+ mpfr_set_nan (mpc_realref (rop));
+ mpfr_set_nan (mpc_imagref (rop));
+ inex = MPC_INEX (0, 0); /* always exact */
+ }
+ }
+ else
+ /* tan(x -i*Inf) = +0*sin(x)*cos(x) -i, when x is finite */
+ /* tan(x +i*Inf) = +0*sin(x)*cos(x) +i, when x is finite */
+ {
+ mpfr_t c;
+ mpfr_t s;
+ int inex_im;
+
+ mpfr_init (c);
+ mpfr_init (s);
+
+ mpfr_sin_cos (s, c, mpc_realref (op), GMP_RNDN);
+ mpfr_set_ui (mpc_realref (rop), 0, MPC_RND_RE (rnd));
+ mpfr_setsign (mpc_realref (rop), mpc_realref (rop),
+ mpfr_signbit (c) != mpfr_signbit (s), GMP_RNDN);
+ /* exact, unless 1 is not in exponent range */
+ inex_im = mpfr_set_si (mpc_imagref (rop),
+ (mpfr_signbit (mpc_imagref (op)) ? -1 : +1),
+ MPC_RND_IM (rnd));
+ inex = MPC_INEX (0, inex_im);
+
+ mpfr_clear (s);
+ mpfr_clear (c);
+ }
+
+ return inex;
+ }
+
+ if (mpfr_zero_p (mpc_realref (op)))
+ /* tan(-0 -i*y) = -0 +i*tanh(y), when y is finite. */
+ /* tan(+0 +i*y) = +0 +i*tanh(y), when y is finite. */
+ {
+ int inex_im;
+
+ mpfr_set (mpc_realref (rop), mpc_realref (op), MPC_RND_RE (rnd));
+ inex_im = mpfr_tanh (mpc_imagref (rop), mpc_imagref (op), MPC_RND_IM (rnd));
+
+ return MPC_INEX (0, inex_im);
+ }
+
+ if (mpfr_zero_p (mpc_imagref (op)))
+ /* tan(x -i*0) = tan(x) -i*0, when x is finite. */
+ /* tan(x +i*0) = tan(x) +i*0, when x is finite. */
+ {
+ int inex_re;
+
+ inex_re = mpfr_tan (mpc_realref (rop), mpc_realref (op), MPC_RND_RE (rnd));
+ mpfr_set (mpc_imagref (rop), mpc_imagref (op), MPC_RND_IM (rnd));
+
+ return MPC_INEX (inex_re, 0);
+ }
+
+ /* ordinary (non-zero) numbers */
+
+ /* tan(op) = sin(op) / cos(op).
+
+ We use the following algorithm with rounding away from 0 for all
+ operations, and working precision w:
+
+ (1) x = A(sin(op))
+ (2) y = A(cos(op))
+ (3) z = A(x/y)
+
+ the error on Im(z) is at most 81 ulp,
+ the error on Re(z) is at most
+ 7 ulp if k < 2,
+ 8 ulp if k = 2,
+ else 5+k ulp, where
+ k = Exp(Re(x))+Exp(Re(y))-2min{Exp(Re(y)), Exp(Im(y))}-Exp(Re(x/y))
+ see proof in algorithms.tex.
+ */
+
+ prec = MPC_MAX_PREC(rop);
+
+ mpc_init2 (x, 2);
+ mpc_init2 (y, 2);
+
+ err = 7;
+
+ do
+ {
+ mpfr_exp_t k, exr, eyr, eyi, ezr;
+
+ ok = 0;
+
+ /* FIXME: prevent addition overflow */
+ prec += mpc_ceil_log2 (prec) + err;
+ mpc_set_prec (x, prec);
+ mpc_set_prec (y, prec);
+
+ /* rounding away from zero: except in the cases x=0 or y=0 (processed
+ above), sin x and cos y are never exact, so rounding away from 0 is
+ rounding towards 0 and adding one ulp to the absolute value */
+ mpc_sin_cos (x, y, op, MPC_RNDZZ, MPC_RNDZZ);
+ MPFR_ADD_ONE_ULP (mpc_realref (x));
+ MPFR_ADD_ONE_ULP (mpc_imagref (x));
+ MPFR_ADD_ONE_ULP (mpc_realref (y));
+ MPFR_ADD_ONE_ULP (mpc_imagref (y));
+ MPC_ASSERT (mpfr_zero_p (mpc_realref (x)) == 0);
+
+ if ( mpfr_inf_p (mpc_realref (x)) || mpfr_inf_p (mpc_imagref (x))
+ || mpfr_inf_p (mpc_realref (y)) || mpfr_inf_p (mpc_imagref (y))) {
+ /* If the real or imaginary part of x is infinite, it means that
+ Im(op) was large, in which case the result is
+ sign(tan(Re(op)))*0 + sign(Im(op))*I,
+ where sign(tan(Re(op))) = sign(Re(x))*sign(Re(y)). */
+ int inex_re, inex_im;
+ mpfr_set_ui (mpc_realref (rop), 0, GMP_RNDN);
+ if (mpfr_sgn (mpc_realref (x)) * mpfr_sgn (mpc_realref (y)) < 0)
+ {
+ mpfr_neg (mpc_realref (rop), mpc_realref (rop), GMP_RNDN);
+ inex_re = 1;
+ }
+ else
+ inex_re = -1; /* +0 is rounded down */
+ if (mpfr_sgn (mpc_imagref (op)) > 0)
+ {
+ mpfr_set_ui (mpc_imagref (rop), 1, GMP_RNDN);
+ inex_im = 1;
+ }
+ else
+ {
+ mpfr_set_si (mpc_imagref (rop), -1, GMP_RNDN);
+ inex_im = -1;
+ }
+ inex = MPC_INEX(inex_re, inex_im);
+ goto end;
+ }
+
+ exr = mpfr_get_exp (mpc_realref (x));
+ eyr = mpfr_get_exp (mpc_realref (y));
+ eyi = mpfr_get_exp (mpc_imagref (y));
+
+ /* some parts of the quotient may be exact */
+ inex = mpc_div (x, x, y, MPC_RNDZZ);
+ /* OP is no pure real nor pure imaginary, so in theory the real and
+ imaginary parts of its tangent cannot be null. However due to
+ rouding errors this might happen. Consider for example
+ tan(1+14*I) = 1.26e-10 + 1.00*I. For small precision sin(op) and
+ cos(op) differ only by a factor I, thus after mpc_div x = I and
+ its real part is zero. */
+ if (mpfr_zero_p (mpc_realref (x)) || mpfr_zero_p (mpc_imagref (x)))
+ {
+ err = prec; /* double precision */
+ continue;
+ }
+ if (MPC_INEX_RE (inex))
+ MPFR_ADD_ONE_ULP (mpc_realref (x));
+ if (MPC_INEX_IM (inex))
+ MPFR_ADD_ONE_ULP (mpc_imagref (x));
+ MPC_ASSERT (mpfr_zero_p (mpc_realref (x)) == 0);
+ ezr = mpfr_get_exp (mpc_realref (x));
+
+ /* FIXME: compute
+ k = Exp(Re(x))+Exp(Re(y))-2min{Exp(Re(y)), Exp(Im(y))}-Exp(Re(x/y))
+ avoiding overflow */
+ k = exr - ezr + MPC_MAX(-eyr, eyr - 2 * eyi);
+ err = k < 2 ? 7 : (k == 2 ? 8 : (5 + k));
+
+ /* Can the real part be rounded? */
+ ok = (!mpfr_number_p (mpc_realref (x)))
+ || mpfr_can_round (mpc_realref(x), prec - err, GMP_RNDN, GMP_RNDZ,
+ MPC_PREC_RE(rop) + (MPC_RND_RE(rnd) == GMP_RNDN));
+
+ if (ok)
+ {
+ /* Can the imaginary part be rounded? */
+ ok = (!mpfr_number_p (mpc_imagref (x)))
+ || mpfr_can_round (mpc_imagref(x), prec - 6, GMP_RNDN, GMP_RNDZ,
+ MPC_PREC_IM(rop) + (MPC_RND_IM(rnd) == GMP_RNDN));
+ }
+ }
+ while (ok == 0);
+
+ inex = mpc_set (rop, x, rnd);
+
+ end:
+ mpc_clear (x);
+ mpc_clear (y);
+
+ return inex;
+}
diff --git a/mpc/src/tanh.c b/mpc/src/tanh.c
new file mode 100644
index 0000000000..78f21037cf
--- /dev/null
+++ b/mpc/src/tanh.c
@@ -0,0 +1,47 @@
+/* mpc_tanh -- hyperbolic tangent of a complex number.
+
+Copyright (C) 2008, 2009, 2011, 2012 INRIA
+
+This file is part of GNU MPC.
+
+GNU MPC is free software; you can redistribute it and/or modify it under
+the terms of the GNU Lesser General Public License as published by the
+Free Software Foundation; either version 3 of the License, or (at your
+option) any later version.
+
+GNU MPC 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 Lesser General Public License for
+more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+
+#include "mpc-impl.h"
+
+int
+mpc_tanh (mpc_ptr rop, mpc_srcptr op, mpc_rnd_t rnd)
+{
+ /* tanh(op) = -i*tan(i*op) = conj(-i*tan(conj(-i*op))) */
+ mpc_t z;
+ mpc_t tan_z;
+ int inex;
+
+ /* z := conj(-i * op) and rop = conj(-i * tan(z)), in other words, we have
+ to switch real and imaginary parts. Let us set them without copying
+ significands. */
+ mpc_realref (z)[0] = mpc_imagref (op)[0];
+ mpc_imagref (z)[0] = mpc_realref (op)[0];
+ mpc_realref (tan_z)[0] = mpc_imagref (rop)[0];
+ mpc_imagref (tan_z)[0] = mpc_realref (rop)[0];
+
+ inex = mpc_tan (tan_z, z, MPC_RND (MPC_RND_IM (rnd), MPC_RND_RE (rnd)));
+
+ /* tan_z and rop parts share the same significands, copy the rest now. */
+ mpc_realref (rop)[0] = mpc_imagref (tan_z)[0];
+ mpc_imagref (rop)[0] = mpc_realref (tan_z)[0];
+
+ /* swap inexact flags for real and imaginary parts */
+ return MPC_INEX (MPC_INEX_IM (inex), MPC_INEX_RE (inex));
+}
diff --git a/mpc/src/uceil_log2.c b/mpc/src/uceil_log2.c
new file mode 100644
index 0000000000..df946128d8
--- /dev/null
+++ b/mpc/src/uceil_log2.c
@@ -0,0 +1,33 @@
+/* mpc_ceil_log2 - returns ceil(log(d)/log(2))
+
+Copyright (C) 2004, 2009, 2010 INRIA
+
+This file is part of GNU MPC.
+
+GNU MPC is free software; you can redistribute it and/or modify it under
+the terms of the GNU Lesser General Public License as published by the
+Free Software Foundation; either version 3 of the License, or (at your
+option) any later version.
+
+GNU MPC 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 Lesser General Public License for
+more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+
+#include "mpc-impl.h"
+
+/* returns ceil(log(d)/log(2)) if d > 0 */
+/* Don't use count_leading_zeros since it is in longlong.h */
+mpfr_prec_t
+mpc_ceil_log2 (mpfr_prec_t d)
+{
+ mpfr_prec_t exp;
+
+ for (exp = 0; d > 1; d = (d + 1) / 2)
+ exp++;
+ return exp;
+}
diff --git a/mpc/src/ui_div.c b/mpc/src/ui_div.c
new file mode 100644
index 0000000000..6e3b955b53
--- /dev/null
+++ b/mpc/src/ui_div.c
@@ -0,0 +1,36 @@
+/* mpc_ui_div -- Divide an unsigned long int by a complex number.
+
+Copyright (C) 2002, 2009 INRIA
+
+This file is part of GNU MPC.
+
+GNU MPC is free software; you can redistribute it and/or modify it under
+the terms of the GNU Lesser General Public License as published by the
+Free Software Foundation; either version 3 of the License, or (at your
+option) any later version.
+
+GNU MPC 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 Lesser General Public License for
+more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+
+#include <limits.h>
+#include "mpc-impl.h"
+
+int
+mpc_ui_div (mpc_ptr a, unsigned long int b, mpc_srcptr c, mpc_rnd_t rnd)
+{
+ int inex;
+ mpc_t bb;
+
+ mpc_init2 (bb, sizeof(unsigned long int) * CHAR_BIT);
+ mpc_set_ui (bb, b, rnd); /* exact */
+ inex = mpc_div (a, bb, c, rnd);
+ mpc_clear (bb);
+
+ return inex;
+}
diff --git a/mpc/src/ui_ui_sub.c b/mpc/src/ui_ui_sub.c
new file mode 100644
index 0000000000..597ee0566c
--- /dev/null
+++ b/mpc/src/ui_ui_sub.c
@@ -0,0 +1,34 @@
+/* mpc_ui_ui_sub -- Subtract a complex number from another one given
+ implicitly by its real and imaginary parts of type unsigned long int.
+
+Copyright (C) 2011 INRIA
+
+This file is part of GNU MPC.
+
+GNU MPC is free software; you can redistribute it and/or modify it under
+the terms of the GNU Lesser General Public License as published by the
+Free Software Foundation; either version 3 of the License, or (at your
+option) any later version.
+
+GNU MPC 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 Lesser General Public License for
+more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+
+#include "mpc-impl.h"
+
+int
+mpc_ui_ui_sub (mpc_ptr rop, unsigned long int re, unsigned long int im,
+ mpc_srcptr op, mpc_rnd_t rnd)
+{
+ int inex_re, inex_im;
+
+ inex_re = mpfr_ui_sub (mpc_realref (rop), re, mpc_realref (op), MPC_RND_RE (rnd));
+ inex_im = mpfr_ui_sub (mpc_imagref (rop), im, mpc_imagref (op), MPC_RND_IM (rnd));
+
+ return MPC_INEX (inex_re, inex_im);
+}
diff --git a/mpc/src/urandom.c b/mpc/src/urandom.c
new file mode 100644
index 0000000000..f8e5f9004d
--- /dev/null
+++ b/mpc/src/urandom.c
@@ -0,0 +1,32 @@
+/* mpc_urandom -- Generate a random complex number uniformly distributed in
+ the interval [0,1[.
+
+Copyright (C) 2008, 2009, 2011 INRIA
+
+This file is part of GNU MPC.
+
+GNU MPC is free software; you can redistribute it and/or modify it under
+the terms of the GNU Lesser General Public License as published by the
+Free Software Foundation; either version 3 of the License, or (at your
+option) any later version.
+
+GNU MPC 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 Lesser General Public License for
+more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+
+#include "mpc-impl.h"
+
+int
+mpc_urandom (mpc_ptr a, gmp_randstate_t state)
+{
+ int r, i;
+
+ r = mpfr_urandomb (mpc_realref(a), state);
+ i = mpfr_urandomb (mpc_imagref(a), state);
+ return r && i;
+}