summaryrefslogtreecommitdiff
path: root/vendor/bundle/ruby/3.4.0/gems/bigdecimal-4.1.2/ext
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/bundle/ruby/3.4.0/gems/bigdecimal-4.1.2/ext')
-rw-r--r--vendor/bundle/ruby/3.4.0/gems/bigdecimal-4.1.2/ext/bigdecimal/Makefile274
-rw-r--r--vendor/bundle/ruby/3.4.0/gems/bigdecimal-4.1.2/ext/bigdecimal/bigdecimal.c6207
-rw-r--r--vendor/bundle/ruby/3.4.0/gems/bigdecimal-4.1.2/ext/bigdecimal/bigdecimal.h298
-rw-r--r--vendor/bundle/ruby/3.4.0/gems/bigdecimal-4.1.2/ext/bigdecimal/bits.h144
-rw-r--r--vendor/bundle/ruby/3.4.0/gems/bigdecimal-4.1.2/ext/bigdecimal/div.h192
-rw-r--r--vendor/bundle/ruby/3.4.0/gems/bigdecimal-4.1.2/ext/bigdecimal/extconf.rb63
-rw-r--r--vendor/bundle/ruby/3.4.0/gems/bigdecimal-4.1.2/ext/bigdecimal/feature.h68
-rw-r--r--vendor/bundle/ruby/3.4.0/gems/bigdecimal-4.1.2/ext/bigdecimal/missing.c28
-rw-r--r--vendor/bundle/ruby/3.4.0/gems/bigdecimal-4.1.2/ext/bigdecimal/missing.h106
-rw-r--r--vendor/bundle/ruby/3.4.0/gems/bigdecimal-4.1.2/ext/bigdecimal/missing/dtoa.c3509
-rw-r--r--vendor/bundle/ruby/3.4.0/gems/bigdecimal-4.1.2/ext/bigdecimal/ntt.h191
-rw-r--r--vendor/bundle/ruby/3.4.0/gems/bigdecimal-4.1.2/ext/bigdecimal/static_assert.h54
12 files changed, 11134 insertions, 0 deletions
diff --git a/vendor/bundle/ruby/3.4.0/gems/bigdecimal-4.1.2/ext/bigdecimal/Makefile b/vendor/bundle/ruby/3.4.0/gems/bigdecimal-4.1.2/ext/bigdecimal/Makefile
new file mode 100644
index 0000000..d69f069
--- /dev/null
+++ b/vendor/bundle/ruby/3.4.0/gems/bigdecimal-4.1.2/ext/bigdecimal/Makefile
@@ -0,0 +1,274 @@
+
+SHELL = /bin/sh
+
+# V=0 quiet, V=1 verbose. other values don't work.
+V = 0
+V0 = $(V:0=)
+Q1 = $(V:1=)
+Q = $(Q1:0=@)
+ECHO1 = $(V:1=@ :)
+ECHO = $(ECHO1:0=@ echo)
+NULLCMD = :
+
+#### Start of system configuration section. ####
+
+srcdir = .
+topdir = /Users/ben/.rubies/ruby-3.4.1/include/ruby-3.4.0
+hdrdir = $(topdir)
+arch_hdrdir = /Users/ben/.rubies/ruby-3.4.1/include/ruby-3.4.0/arm64-darwin24
+PATH_SEPARATOR = :
+VPATH = $(srcdir):$(arch_hdrdir)/ruby:$(hdrdir)/ruby
+prefix = $(DESTDIR)/Users/ben/.rubies/ruby-3.4.1
+rubysitearchprefix = $(rubylibprefix)/$(sitearch)
+rubyarchprefix = $(rubylibprefix)/$(arch)
+rubylibprefix = $(libdir)/$(RUBY_BASE_NAME)
+exec_prefix = $(prefix)
+vendorarchhdrdir = $(vendorhdrdir)/$(sitearch)
+sitearchhdrdir = $(sitehdrdir)/$(sitearch)
+rubyarchhdrdir = $(rubyhdrdir)/$(arch)
+vendorhdrdir = $(rubyhdrdir)/vendor_ruby
+sitehdrdir = $(rubyhdrdir)/site_ruby
+rubyhdrdir = $(includedir)/$(RUBY_VERSION_NAME)
+vendorarchdir = $(vendorlibdir)/$(sitearch)
+vendorlibdir = $(vendordir)/$(ruby_version)
+vendordir = $(rubylibprefix)/vendor_ruby
+sitearchdir = $(sitelibdir)/$(sitearch)
+sitelibdir = $(sitedir)/$(ruby_version)
+sitedir = $(rubylibprefix)/site_ruby
+rubyarchdir = $(rubylibdir)/$(arch)
+rubylibdir = $(rubylibprefix)/$(ruby_version)
+sitearchincludedir = $(includedir)/$(sitearch)
+archincludedir = $(includedir)/$(arch)
+sitearchlibdir = $(libdir)/$(sitearch)
+archlibdir = $(libdir)/$(arch)
+ridir = $(datarootdir)/$(RI_BASE_NAME)
+modular_gc_dir = $(DESTDIR)
+mandir = $(datarootdir)/man
+localedir = $(datarootdir)/locale
+libdir = $(exec_prefix)/lib
+psdir = $(docdir)
+pdfdir = $(docdir)
+dvidir = $(docdir)
+htmldir = $(docdir)
+infodir = $(datarootdir)/info
+docdir = $(datarootdir)/doc/$(PACKAGE)
+oldincludedir = $(DESTDIR)/usr/include
+includedir = $(SDKROOT)$(prefix)/include
+runstatedir = $(localstatedir)/run
+localstatedir = $(prefix)/var
+sharedstatedir = $(prefix)/com
+sysconfdir = $(prefix)/etc
+datadir = $(datarootdir)
+datarootdir = $(prefix)/share
+libexecdir = $(exec_prefix)/libexec
+sbindir = $(exec_prefix)/sbin
+bindir = $(exec_prefix)/bin
+archdir = $(rubyarchdir)
+
+
+CC_WRAPPER =
+CC = clang
+CXX = clang++ -std=gnu++11
+LIBRUBY = $(LIBRUBY_A)
+LIBRUBY_A = lib$(RUBY_SO_NAME)-static.a
+LIBRUBYARG_SHARED =
+LIBRUBYARG_STATIC = -l$(RUBY_SO_NAME)-static -framework CoreFoundation $(MAINLIBS)
+empty =
+OUTFLAG = -o $(empty)
+COUTFLAG = -o $(empty)
+CSRCFLAG = $(empty)
+
+RUBY_EXTCONF_H =
+cflags = $(hardenflags) -fdeclspec $(optflags) $(debugflags) $(warnflags)
+cxxflags =
+optflags = -O3 -fno-fast-math
+debugflags = -ggdb3
+warnflags = -Wall -Wextra -Wextra-tokens -Wdeprecated-declarations -Wdivision-by-zero -Wdiv-by-zero -Wimplicit-function-declaration -Wimplicit-int -Wpointer-arith -Wshorten-64-to-32 -Wwrite-strings -Wold-style-definition -Wmissing-noreturn -Wno-cast-function-type -Wno-constant-logical-operand -Wno-long-long -Wno-missing-field-initializers -Wno-overlength-strings -Wno-parentheses-equality -Wno-self-assign -Wno-tautological-compare -Wno-unused-parameter -Wno-unused-value -Wunused-variable -Wmisleading-indentation -Wundef
+cppflags =
+CCDLFLAGS = -fno-common
+CFLAGS = $(CCDLFLAGS) $(cflags) -pipe $(ARCH_FLAG)
+INCFLAGS = -I. -I$(arch_hdrdir) -I$(hdrdir)/ruby/backward -I$(hdrdir) -I$(srcdir)
+DEFS =
+CPPFLAGS = -DHAVE_BUILTIN___BUILTIN_CLZ -DHAVE_BUILTIN___BUILTIN_CLZL -DHAVE_BUILTIN___BUILTIN_CLZLL -DHAVE_FLOAT_H -DHAVE_MATH_H -DHAVE_STDBOOL_H -DHAVE_STDLIB_H -DHAVE_RUBY_ATOMIC_H -DHAVE_RUBY_INTERNAL_HAS_BUILTIN_H -DHAVE_RUBY_INTERNAL_STATIC_ASSERT_H -DHAVE_RB_COMPLEX_REAL -DHAVE_RB_COMPLEX_IMAG -DHAVE_RB_OPTS_EXCEPTION_P -DHAVE_RB_CATEGORY_WARN -DHAVE_CONST_RB_WARN_CATEGORY_DEPRECATED -DHAVE_CONST_RUBY_TYPED_EMBEDDABLE -I/opt/homebrew/opt/readline/include -I/opt/homebrew/opt/libyaml/include -I/opt/homebrew/opt/gdbm/include -D_XOPEN_SOURCE -D_DARWIN_C_SOURCE -D_DARWIN_UNLIMITED_SELECT -D_REENTRANT $(DEFS) $(cppflags)
+CXXFLAGS = $(CCDLFLAGS) -fdeclspec $(ARCH_FLAG)
+ldflags = -L. -fstack-protector-strong -L/opt/homebrew/Cellar/readline/8.2.13/lib -L/opt/homebrew/Cellar/libyaml/0.2.5/lib -L/opt/homebrew/Cellar/gdbm/1.24/lib
+dldflags = -L/opt/homebrew/Cellar/readline/8.2.13/lib -L/opt/homebrew/Cellar/libyaml/0.2.5/lib -L/opt/homebrew/Cellar/gdbm/1.24/lib -Wl,-undefined,dynamic_lookup -bundle_loader '$(BUILTRUBY)'
+ARCH_FLAG = -arch arm64
+DLDFLAGS = $(ldflags) $(dldflags) $(ARCH_FLAG)
+LDSHARED = $(CC) -dynamic -bundle
+LDSHAREDXX = $(CXX) -dynamic -bundle
+POSTLINK = dsymutil $@ 2>/dev/null; { test -z '$(RUBY_CODESIGN)' || codesign -s '$(RUBY_CODESIGN)' $@; }
+AR = ar
+LD = ld
+EXEEXT =
+
+RUBY_INSTALL_NAME = $(RUBY_BASE_NAME)
+RUBY_SO_NAME = ruby.3.4
+RUBYW_INSTALL_NAME =
+RUBY_VERSION_NAME = $(RUBY_BASE_NAME)-$(ruby_version)
+RUBYW_BASE_NAME = rubyw
+RUBY_BASE_NAME = ruby
+
+arch = arm64-darwin24
+sitearch = $(arch)
+ruby_version = 3.4.0
+ruby = $(bindir)/$(RUBY_BASE_NAME)
+RUBY = $(ruby)
+BUILTRUBY = $(bindir)/$(RUBY_BASE_NAME)
+ruby_headers = $(hdrdir)/ruby.h $(hdrdir)/ruby/backward.h $(hdrdir)/ruby/ruby.h $(hdrdir)/ruby/defines.h $(hdrdir)/ruby/missing.h $(hdrdir)/ruby/intern.h $(hdrdir)/ruby/st.h $(hdrdir)/ruby/subst.h $(arch_hdrdir)/ruby/config.h
+
+RM = rm -f
+RM_RF = rm -fr
+RMDIRS = rmdir -p
+MAKEDIRS = mkdir -p
+INSTALL = /usr/bin/install -c
+INSTALL_PROG = $(INSTALL) -m 0755
+INSTALL_DATA = $(INSTALL) -m 644
+COPY = cp
+TOUCH = exit >
+
+#### End of system configuration section. ####
+
+preload =
+libpath = . $(libdir) /opt/homebrew/opt/readline/lib /opt/homebrew/opt/libyaml/lib /opt/homebrew/opt/gdbm/lib
+LIBPATH = -L. -L$(libdir) -L/opt/homebrew/opt/readline/lib -L/opt/homebrew/opt/libyaml/lib -L/opt/homebrew/opt/gdbm/lib
+DEFFILE =
+
+CLEANFILES = mkmf.log
+DISTCLEANFILES =
+DISTCLEANDIRS =
+
+extout =
+extout_prefix =
+target_prefix =
+LOCAL_LIBS =
+LIBS = -lpthread
+ORIG_SRCS = bigdecimal.c missing.c
+SRCS = $(ORIG_SRCS)
+OBJS = bigdecimal.o missing.o
+HDRS = $(srcdir)/bigdecimal.h $(srcdir)/bits.h $(srcdir)/div.h $(srcdir)/feature.h $(srcdir)/missing.h $(srcdir)/ntt.h $(srcdir)/static_assert.h
+LOCAL_HDRS =
+TARGET = bigdecimal
+TARGET_NAME = bigdecimal
+TARGET_ENTRY = Init_$(TARGET_NAME)
+DLLIB = $(TARGET).bundle
+EXTSTATIC =
+STATIC_LIB =
+
+TIMESTAMP_DIR = .
+BINDIR = $(bindir)
+RUBYCOMMONDIR = $(sitedir)$(target_prefix)
+RUBYLIBDIR = $(sitelibdir)$(target_prefix)
+RUBYARCHDIR = $(sitearchdir)$(target_prefix)
+HDRDIR = $(sitehdrdir)$(target_prefix)
+ARCHHDRDIR = $(sitearchhdrdir)$(target_prefix)
+TARGET_SO_DIR =
+TARGET_SO = $(TARGET_SO_DIR)$(DLLIB)
+CLEANLIBS = $(TARGET_SO) $(TARGET_SO:=.dSYM)
+CLEANOBJS = $(OBJS) *.bak
+TARGET_SO_DIR_TIMESTAMP = $(TIMESTAMP_DIR)/.sitearchdir.time
+BIGDECIMAL_RB = $(srcdir)/../../lib/bigdecimal.rb
+
+all: $(DLLIB)
+static: $(STATIC_LIB)
+.PHONY: all install static install-so install-rb
+.PHONY: clean clean-so clean-static clean-rb
+
+clean-static::
+clean-rb-default::
+clean-rb::
+clean-so::
+clean: clean-so clean-static clean-rb-default clean-rb
+ -$(Q)$(RM_RF) $(CLEANLIBS) $(CLEANOBJS) $(CLEANFILES) .*.time
+
+distclean-rb-default::
+distclean-rb::
+distclean-so::
+distclean-static::
+distclean: clean distclean-so distclean-static distclean-rb-default distclean-rb
+ -$(Q)$(RM) Makefile $(RUBY_EXTCONF_H) conftest.* mkmf.log
+ -$(Q)$(RM) core ruby$(EXEEXT) *~ $(DISTCLEANFILES)
+ -$(Q)$(RMDIRS) $(DISTCLEANDIRS) 2> /dev/null || true
+
+realclean: distclean
+install: install-so install-rb
+
+install-so: $(DLLIB) $(TARGET_SO_DIR_TIMESTAMP)
+ $(INSTALL_PROG) $(DLLIB) $(RUBYARCHDIR)
+clean-static::
+ -$(Q)$(RM) $(STATIC_LIB)
+install-rb: pre-install-rb do-install-rb install-rb-default
+install-rb-default: pre-install-rb-default do-install-rb-default
+pre-install-rb: Makefile
+pre-install-rb-default: Makefile
+do-install-rb:
+do-install-rb-default:
+pre-install-rb-default:
+ @$(NULLCMD)
+$(TARGET_SO_DIR_TIMESTAMP):
+ $(Q) $(MAKEDIRS) $(@D) $(RUBYARCHDIR)
+ $(Q) $(TOUCH) $@
+
+site-install: site-install-so site-install-rb
+site-install-so: install-so
+site-install-rb: install-rb
+
+.SUFFIXES: .c .m .cc .mm .cxx .cpp .o .S
+
+.cc.o:
+ $(ECHO) compiling $(<)
+ $(Q) $(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -c $(CSRCFLAG)$<
+
+.cc.S:
+ $(ECHO) translating $(<)
+ $(Q) $(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -S $(CSRCFLAG)$<
+
+.mm.o:
+ $(ECHO) compiling $(<)
+ $(Q) $(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -c $(CSRCFLAG)$<
+
+.mm.S:
+ $(ECHO) translating $(<)
+ $(Q) $(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -S $(CSRCFLAG)$<
+
+.cxx.o:
+ $(ECHO) compiling $(<)
+ $(Q) $(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -c $(CSRCFLAG)$<
+
+.cxx.S:
+ $(ECHO) translating $(<)
+ $(Q) $(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -S $(CSRCFLAG)$<
+
+.cpp.o:
+ $(ECHO) compiling $(<)
+ $(Q) $(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -c $(CSRCFLAG)$<
+
+.cpp.S:
+ $(ECHO) translating $(<)
+ $(Q) $(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -S $(CSRCFLAG)$<
+
+.c.o:
+ $(ECHO) compiling $(<)
+ $(Q) $(CC) $(INCFLAGS) $(CPPFLAGS) $(CFLAGS) $(COUTFLAG)$@ -c $(CSRCFLAG)$<
+
+.c.S:
+ $(ECHO) translating $(<)
+ $(Q) $(CC) $(INCFLAGS) $(CPPFLAGS) $(CFLAGS) $(COUTFLAG)$@ -S $(CSRCFLAG)$<
+
+.m.o:
+ $(ECHO) compiling $(<)
+ $(Q) $(CC) $(INCFLAGS) $(CPPFLAGS) $(CFLAGS) $(COUTFLAG)$@ -c $(CSRCFLAG)$<
+
+.m.S:
+ $(ECHO) translating $(<)
+ $(Q) $(CC) $(INCFLAGS) $(CPPFLAGS) $(CFLAGS) $(COUTFLAG)$@ -S $(CSRCFLAG)$<
+
+$(TARGET_SO): $(OBJS) Makefile
+ $(ECHO) linking shared-object $(DLLIB)
+ -$(Q)$(RM) $(@)
+ $(Q) $(LDSHARED) -o $@ $(OBJS) $(LIBPATH) $(DLDFLAGS) $(LOCAL_LIBS) $(LIBS)
+ $(Q) $(POSTLINK)
+
+
+
+$(OBJS): $(HDRS) $(ruby_headers)
diff --git a/vendor/bundle/ruby/3.4.0/gems/bigdecimal-4.1.2/ext/bigdecimal/bigdecimal.c b/vendor/bundle/ruby/3.4.0/gems/bigdecimal-4.1.2/ext/bigdecimal/bigdecimal.c
new file mode 100644
index 0000000..182d66f
--- /dev/null
+++ b/vendor/bundle/ruby/3.4.0/gems/bigdecimal-4.1.2/ext/bigdecimal/bigdecimal.c
@@ -0,0 +1,6207 @@
+/*
+ *
+ * Ruby BigDecimal(Variable decimal precision) extension library.
+ *
+ * Copyright(C) 2002 by Shigeo Kobayashi(shigeo@tinyforest.gr.jp)
+ *
+ */
+
+/* #define BIGDECIMAL_DEBUG 1 */
+
+#include "bigdecimal.h"
+#include "ruby/util.h"
+
+#ifndef BIGDECIMAL_DEBUG
+# undef NDEBUG
+# define NDEBUG
+#endif
+#include <assert.h>
+
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <math.h>
+
+#ifdef HAVE_IEEEFP_H
+#include <ieeefp.h>
+#endif
+
+#include "bits.h"
+#include "ntt.h"
+#include "div.h"
+#include "static_assert.h"
+
+#define BIGDECIMAL_VERSION "4.1.2"
+
+/* Make sure VPMULT_BATCH_SIZE*BASE*BASE does not overflow DECDIG_DBL */
+#define VPMULT_BATCH_SIZE 16
+#define NTT_MULTIPLICATION_THRESHOLD 450
+#define NEWTON_RAPHSON_DIVISION_THRESHOLD 100
+#define SIGNED_VALUE_MAX INTPTR_MAX
+#define SIGNED_VALUE_MIN INTPTR_MIN
+#define MUL_OVERFLOW_SIGNED_VALUE_P(a, b) MUL_OVERFLOW_SIGNED_INTEGER_P(a, b, SIGNED_VALUE_MIN, SIGNED_VALUE_MAX)
+#define ADD_OVERFLOW_SIGNED_VALUE_P(a, b) ADD_OVERFLOW_SIGNED_INTEGER_P(a, b, SIGNED_VALUE_MIN, SIGNED_VALUE_MAX)
+
+/* max_value = 0.9999_9999_9999E[exponent], exponent <= SIGNED_VALUE_MAX */
+#define VP_EXPONENT_MAX (SIGNED_VALUE_MAX / BASE_FIG)
+/* min_value = 0.0001_0000_0000E[exponent], exponent-(BASE_FIG-1) >= SIGNED_VALUE_MIN */
+#define VP_EXPONENT_MIN ((SIGNED_VALUE_MIN + BASE_FIG - 1) / BASE_FIG)
+#define EXPONENT_MAX (VP_EXPONENT_MAX * BASE_FIG)
+#define EXPONENT_MIN (VP_EXPONENT_MIN * BASE_FIG - (BASE_FIG - 1))
+
+VALUE rb_cBigDecimal;
+
+static ID id_BigDecimal_exception_mode;
+static ID id_BigDecimal_rounding_mode;
+static ID id_BigDecimal_precision_limit;
+
+static ID id_up;
+static ID id_down;
+static ID id_truncate;
+static ID id_half_up;
+static ID id_default;
+static ID id_half_down;
+static ID id_half_even;
+static ID id_banker;
+static ID id_ceiling;
+static ID id_ceil;
+static ID id_floor;
+static ID id_to_r;
+static ID id_eq;
+static ID id_half;
+
+#define RBD_NUM_ROUNDING_MODES 11
+
+static struct {
+ ID id;
+ uint8_t mode;
+} rbd_rounding_modes[RBD_NUM_ROUNDING_MODES];
+
+static inline BDVALUE
+bdvalue_nonnullable(NULLABLE_BDVALUE v)
+{
+ assert(v.real_or_null != NULL);
+ return (BDVALUE) { v.bigdecimal_or_nil, v.real_or_null };
+}
+
+static inline NULLABLE_BDVALUE
+bdvalue_nullable(BDVALUE v)
+{
+ return (NULLABLE_BDVALUE) { v.bigdecimal, v.real };
+}
+
+#define BASE_FIG BIGDECIMAL_COMPONENT_FIGURES
+#define BASE BIGDECIMAL_BASE
+
+#define HALF_BASE (BASE/2)
+#define BASE1 (BASE/10)
+
+#ifndef MAYBE_UNUSED
+# define MAYBE_UNUSED(x) x
+#endif
+
+#define BIGDECIMAL_POSITIVE_P(bd) ((bd)->sign > 0)
+#define BIGDECIMAL_NEGATIVE_P(bd) ((bd)->sign < 0)
+
+/*
+ * ================== Memory allocation ============================
+ */
+
+#ifdef BIGDECIMAL_DEBUG
+static size_t rbd_allocation_count = 0; /* Memory allocation counter */
+static inline void
+atomic_allocation_count_inc(void)
+{
+ RUBY_ATOMIC_SIZE_INC(rbd_allocation_count);
+}
+static inline void
+atomic_allocation_count_dec_nounderflow(void)
+{
+ if (rbd_allocation_count == 0) return;
+ RUBY_ATOMIC_SIZE_DEC(rbd_allocation_count);
+}
+static void
+check_allocation_count_nonzero(void)
+{
+ if (rbd_allocation_count != 0) return;
+ rb_bug("[bigdecimal][rbd_free_struct] Too many memory free calls");
+}
+#else
+# define atomic_allocation_count_inc() /* nothing */
+# define atomic_allocation_count_dec_nounderflow() /* nothing */
+# define check_allocation_count_nonzero() /* nothing */
+#endif /* BIGDECIMAL_DEBUG */
+
+/* VpMult VpDivd helpers */
+#define VPMULT_RESULT_PREC(a, b) (a->Prec + b->Prec)
+/* To calculate VpDivd with n-digits precision, quotient needs n+2*BASE_FIG-1 digits space */
+/* In the worst precision case 0001_1111_1111 / 9999 = 0000_0001_1112, there are 2*BASE_FIG-1 leading zeros */
+#define VPDIVD_QUO_DIGITS(required_digits) ((required_digits) + 2 * BASE_FIG - 1)
+/* Required r.MaxPrec for calculating VpDivd(c, r, a, b) */
+#define VPDIVD_REM_PREC(a, b, c) Max(a->Prec, b->Prec + c->MaxPrec - 1)
+
+static NULLABLE_BDVALUE
+CreateFromString(const char *str, VALUE klass, bool strict_p, bool raise_exception);
+
+PUREFUNC(static inline size_t rbd_struct_size(size_t const));
+
+static inline size_t
+rbd_struct_size(size_t const internal_digits)
+{
+ size_t const frac_len = (internal_digits == 0) ? 1 : internal_digits;
+ return offsetof(Real, frac) + frac_len * sizeof(DECDIG);
+}
+
+/*
+ * ================== Ruby Interface part ==========================
+ */
+#define DoSomeOne(x,y,f) rb_num_coerce_bin(x,y,f)
+
+/*
+ * VP routines used in BigDecimal part
+ */
+static unsigned short VpGetException(void);
+static void VpSetException(unsigned short f);
+static void VpCheckException(Real *p, bool always);
+static VALUE CheckGetValue(BDVALUE v);
+static void VpInternalRound(Real *c, size_t ixDigit, DECDIG vPrev, DECDIG v);
+static int VpLimitRound(Real *c, size_t ixDigit);
+static int VPrint(FILE *fp,const char *cntl_chr,Real *a);
+
+/*
+ * **** BigDecimal part ****
+ */
+
+static VALUE BigDecimal_nan(void);
+static VALUE BigDecimal_positive_infinity(void);
+static VALUE BigDecimal_negative_infinity(void);
+static VALUE BigDecimal_positive_zero(void);
+static VALUE BigDecimal_negative_zero(void);
+static VALUE BigDecimal_addsub_with_coerce(VALUE self, VALUE r, size_t prec, int operation);
+static VALUE BigDecimal_mult_with_coerce(VALUE self, VALUE r, size_t prec);
+
+#ifndef HAVE_RB_EXT_RACTOR_SAFE
+# undef RUBY_TYPED_FROZEN_SHAREABLE
+# define RUBY_TYPED_FROZEN_SHAREABLE 0
+#endif
+
+#ifdef RUBY_TYPED_EMBEDDABLE
+# define HAVE_RUBY_TYPED_EMBEDDABLE 1
+#else
+# ifdef HAVE_CONST_RUBY_TYPED_EMBEDDABLE
+# define RUBY_TYPED_EMBEDDABLE RUBY_TYPED_EMBEDDABLE
+# define HAVE_RUBY_TYPED_EMBEDDABLE 1
+# else
+# define RUBY_TYPED_EMBEDDABLE 0
+# endif
+#endif
+
+static size_t
+BigDecimal_memsize(const void *ptr)
+{
+#ifdef HAVE_RUBY_TYPED_EMBEDDABLE
+ return 0; // Entirely embedded
+#else
+ const Real *pv = ptr;
+ return (sizeof(*pv) + pv->MaxPrec * sizeof(DECDIG));
+#endif
+}
+
+static const rb_data_type_t BigDecimal_data_type = {
+ .wrap_struct_name = "BigDecimal",
+ .function = {
+ .dmark = 0,
+ .dfree = RUBY_DEFAULT_FREE,
+ .dsize = BigDecimal_memsize,
+ },
+ .flags = RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_FROZEN_SHAREABLE | RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_EMBEDDABLE,
+};
+
+static VALUE
+BigDecimal_allocate(size_t const internal_digits)
+{
+ const size_t size = rbd_struct_size(internal_digits);
+ VALUE bd = rb_data_typed_object_zalloc(rb_cBigDecimal, size, &BigDecimal_data_type);
+ Real *vp;
+ TypedData_Get_Struct(bd, Real, &BigDecimal_data_type, vp);
+ vp->MaxPrec = internal_digits;
+ RB_OBJ_FREEZE(bd);
+ return bd;
+}
+
+static VALUE
+BigDecimal_allocate_decimal_digits(size_t const decimal_digits)
+{
+ return BigDecimal_allocate(roomof(decimal_digits, BASE_FIG));
+}
+
+static Real *
+VpPtr(VALUE obj)
+{
+ Real *vp;
+ TypedData_Get_Struct(obj, Real, &BigDecimal_data_type, vp);
+ return vp;
+}
+
+MAYBE_UNUSED(static inline BDVALUE rbd_allocate_struct_zero_wrap(int sign, size_t const digits));
+#define NewZeroWrap rbd_allocate_struct_zero_wrap
+static BDVALUE
+rbd_allocate_struct_zero_wrap(int sign, size_t const digits)
+{
+ VALUE obj = BigDecimal_allocate_decimal_digits(digits);
+ Real *real = VpPtr(obj);
+ VpSetZero(real, sign);
+ return (BDVALUE) { obj, real };
+}
+
+static inline int
+is_kind_of_BigDecimal(VALUE const v)
+{
+ return rb_typeddata_is_kind_of(v, &BigDecimal_data_type);
+}
+
+NORETURN(static void cannot_be_coerced_into_BigDecimal(VALUE, VALUE));
+
+static void
+cannot_be_coerced_into_BigDecimal(VALUE exc_class, VALUE v)
+{
+ VALUE str;
+
+ if (rb_special_const_p(v)) {
+ str = rb_inspect(v);
+ }
+ else {
+ str = rb_class_name(rb_obj_class(v));
+ }
+
+ str = rb_str_cat2(rb_str_dup(str), " can't be coerced into BigDecimal");
+ rb_exc_raise(rb_exc_new3(exc_class, str));
+}
+
+static inline VALUE BigDecimal_div2(VALUE, VALUE, VALUE);
+static VALUE rb_inum_convert_to_BigDecimal(VALUE val);
+static VALUE rb_float_convert_to_BigDecimal(VALUE val, size_t digs, int raise_exception);
+static VALUE rb_rational_convert_to_BigDecimal(VALUE val, size_t digs, int raise_exception);
+static VALUE rb_cstr_convert_to_BigDecimal(const char *c_str, int raise_exception);
+static VALUE rb_convert_to_BigDecimal(VALUE val, size_t digs, int raise_exception);
+
+static NULLABLE_BDVALUE
+GetBDValueWithPrecInternal(VALUE v, size_t prec, int must)
+{
+ switch(TYPE(v)) {
+ case T_FLOAT:
+ v = rb_float_convert_to_BigDecimal(v, 0, true);
+ break;
+
+ case T_RATIONAL:
+ v = rb_rational_convert_to_BigDecimal(v, prec, true);
+ break;
+
+ case T_DATA:
+ if (!is_kind_of_BigDecimal(v)) {
+ goto SomeOneMayDoIt;
+ }
+ break;
+
+ case T_FIXNUM:
+ case T_BIGNUM: {
+ v = rb_inum_convert_to_BigDecimal(v);
+ break;
+ }
+
+ default:
+ goto SomeOneMayDoIt;
+ }
+
+ Real *vp = VpPtr(v);
+ return (NULLABLE_BDVALUE) { v, vp };
+
+SomeOneMayDoIt:
+ if (must) {
+ cannot_be_coerced_into_BigDecimal(rb_eTypeError, v);
+ }
+ return (NULLABLE_BDVALUE) { Qnil, NULL }; /* NULL means to coerce */
+}
+
+static inline NULLABLE_BDVALUE
+GetBDValueWithPrec(VALUE v, size_t prec)
+{
+ return GetBDValueWithPrecInternal(v, prec, 0);
+}
+
+
+static inline BDVALUE
+GetBDValueWithPrecMust(VALUE v, size_t prec)
+{
+ return bdvalue_nonnullable(GetBDValueWithPrecInternal(v, prec, 1));
+}
+
+// self must be a receiver of BigDecimal instance method or a gc guarded BigDecimal object.
+static inline Real*
+GetSelfVpValue(VALUE self)
+{
+ return GetBDValueWithPrecMust(self, 0).real;
+}
+
+static inline BDVALUE
+GetBDValueMust(VALUE v)
+{
+ return GetBDValueWithPrecMust(v, 0);
+}
+
+/* call-seq:
+ * BigDecimal.double_fig -> integer
+ *
+ * Returns the number of digits a Float object is allowed to have;
+ * the result is system-dependent:
+ *
+ * BigDecimal.double_fig # => 16
+ *
+ */
+static inline VALUE
+BigDecimal_double_fig(VALUE self)
+{
+ return INT2FIX(BIGDECIMAL_DOUBLE_FIGURES);
+}
+
+static void
+VpCountPrecisionAndScale(Real *p, ssize_t *out_precision, ssize_t *out_scale)
+{
+ if (out_precision == NULL && out_scale == NULL)
+ return;
+ if (VpIsZero(p) || !VpIsDef(p)) {
+ zero:
+ if (out_precision) *out_precision = 0;
+ if (out_scale) *out_scale = 0;
+ return;
+ }
+
+ DECDIG x;
+
+ ssize_t n = p->Prec; /* The length of frac without zeros. */
+ while (n > 0 && p->frac[n-1] == 0) --n;
+ if (n == 0) goto zero;
+
+ int nlz = BASE_FIG;
+ for (x = p->frac[0]; x > 0; x /= 10) --nlz;
+
+ int ntz = 0;
+ for (x = p->frac[n-1]; x > 0 && x % 10 == 0; x /= 10) ++ntz;
+
+ /*
+ * Calculate the precision and the scale
+ * -------------------------------------
+ *
+ * The most significant digit is frac[0], and the least significant digit
+ * is frac[Prec-1]. When the exponent is zero, the decimal point is
+ * located just before frac[0].
+ *
+ * When the exponent is negative, the decimal point moves to leftward.
+ * In this case, the precision can be calculated by
+ *
+ * precision = BASE_FIG * (-exponent + n) - ntz,
+ *
+ * and the scale is the same as precision.
+ *
+ * 0 . 0000 0000 | frac[0] ... frac[n-1] |
+ * |<----------| exponent == -2 |
+ * |---------------------------------->| precision
+ * |---------------------------------->| scale
+ *
+ *
+ * Conversely, when the exponent is positive, the decimal point moves to
+ * rightward. In this case, the scale equals to
+ *
+ * BASE_FIG * (n - exponent) - ntz.
+ *
+ * the precision equals to
+ *
+ * scale + BASE_FIG * exponent - nlz.
+ *
+ * | frac[0] frac[1] . frac[2] ... frac[n-1] |
+ * |---------------->| exponent == 2 |
+ * | |---------------------->| scale
+ * |---------------------------------------->| precision
+ */
+
+ ssize_t ex = p->exponent;
+
+ /* Count the number of decimal digits before frac[1]. */
+ ssize_t n_digits_head = BASE_FIG;
+ if (ex < 0) {
+ n_digits_head += (-ex) * BASE_FIG; /* The number of leading zeros before frac[0]. */
+ ex = 0;
+ }
+ else if (ex > 0) {
+ /* Count the number of decimal digits without the leading zeros in
+ * the most significant digit in the integral part.
+ */
+ n_digits_head -= nlz; /* Make the number of digits */
+ }
+
+ if (out_precision) {
+ ssize_t precision = n_digits_head;
+
+ /* Count the number of decimal digits after frac[0]. */
+ if (ex > (ssize_t)n) {
+ /* In this case the number is an integer with some trailing zeros. */
+ precision += (ex - 1) * BASE_FIG;
+ }
+ else if (n > 0) {
+ precision += (n - 1) * BASE_FIG;
+
+ if (ex < (ssize_t)n) {
+ precision -= ntz;
+ }
+ }
+
+ *out_precision = precision;
+ }
+
+ if (out_scale) {
+ ssize_t scale = 0;
+
+ if (p->exponent < 0) {
+ scale = n_digits_head + (n - 1) * BASE_FIG - ntz;
+ }
+ else if (n > p->exponent) {
+ scale = (n - p->exponent) * BASE_FIG - ntz;
+ }
+
+ *out_scale = scale;
+ }
+}
+
+static void
+BigDecimal_count_precision_and_scale(VALUE self, ssize_t *out_precision, ssize_t *out_scale)
+{
+ BDVALUE v = GetBDValueMust(self);
+ VpCountPrecisionAndScale(v.real, out_precision, out_scale);
+ RB_GC_GUARD(v.bigdecimal);
+}
+
+/*
+ * call-seq:
+ * precision -> integer
+ *
+ * Returns the number of decimal digits in +self+:
+ *
+ * BigDecimal("0").precision # => 0
+ * BigDecimal("1").precision # => 1
+ * BigDecimal("1.1").precision # => 2
+ * BigDecimal("3.1415").precision # => 5
+ * BigDecimal("-1e20").precision # => 21
+ * BigDecimal("1e-20").precision # => 20
+ * BigDecimal("Infinity").precision # => 0
+ * BigDecimal("-Infinity").precision # => 0
+ * BigDecimal("NaN").precision # => 0
+ *
+ */
+static VALUE
+BigDecimal_precision(VALUE self)
+{
+ ssize_t precision;
+ BigDecimal_count_precision_and_scale(self, &precision, NULL);
+ return SSIZET2NUM(precision);
+}
+
+/*
+ * call-seq:
+ * scale -> integer
+ *
+ * Returns the number of decimal digits following the decimal digits in +self+.
+ *
+ * BigDecimal("0").scale # => 0
+ * BigDecimal("1").scale # => 0
+ * BigDecimal("1.1").scale # => 1
+ * BigDecimal("3.1415").scale # => 4
+ * BigDecimal("-1e20").scale # => 0
+ * BigDecimal("1e-20").scale # => 20
+ * BigDecimal("Infinity").scale # => 0
+ * BigDecimal("-Infinity").scale # => 0
+ * BigDecimal("NaN").scale # => 0
+ */
+static VALUE
+BigDecimal_scale(VALUE self)
+{
+ ssize_t scale;
+ BigDecimal_count_precision_and_scale(self, NULL, &scale);
+ return SSIZET2NUM(scale);
+}
+
+/*
+ * call-seq:
+ * precision_scale -> [integer, integer]
+ *
+ * Returns a 2-length array; the first item is the result of
+ * BigDecimal#precision and the second one is of BigDecimal#scale.
+ *
+ * See BigDecimal#precision.
+ * See BigDecimal#scale.
+ */
+static VALUE
+BigDecimal_precision_scale(VALUE self)
+{
+ ssize_t precision, scale;
+ BigDecimal_count_precision_and_scale(self, &precision, &scale);
+ return rb_assoc_new(SSIZET2NUM(precision), SSIZET2NUM(scale));
+}
+
+/*
+ * call-seq:
+ * n_significant_digits -> integer
+ *
+ * Returns the number of decimal significant digits in +self+.
+ *
+ * BigDecimal("0").n_significant_digits # => 0
+ * BigDecimal("1").n_significant_digits # => 1
+ * BigDecimal("1.1").n_significant_digits # => 2
+ * BigDecimal("3.1415").n_significant_digits # => 5
+ * BigDecimal("-1e20").n_significant_digits # => 1
+ * BigDecimal("1e-20").n_significant_digits # => 1
+ * BigDecimal("Infinity").n_significant_digits # => 0
+ * BigDecimal("-Infinity").n_significant_digits # => 0
+ * BigDecimal("NaN").n_significant_digits # => 0
+ */
+static VALUE
+BigDecimal_n_significant_digits(VALUE self)
+{
+ BDVALUE v = GetBDValueMust(self);
+ if (VpIsZero(v.real) || !VpIsDef(v.real)) {
+ return INT2FIX(0);
+ }
+
+ ssize_t n = v.real->Prec; /* The length of frac without trailing zeros. */
+ for (n = v.real->Prec; n > 0 && v.real->frac[n-1] == 0; --n);
+ if (n == 0) return INT2FIX(0);
+
+ DECDIG x;
+ int nlz = BASE_FIG;
+ for (x = v.real->frac[0]; x > 0; x /= 10) --nlz;
+
+ int ntz = 0;
+ for (x = v.real->frac[n-1]; x > 0 && x % 10 == 0; x /= 10) ++ntz;
+
+ RB_GC_GUARD(v.bigdecimal);
+ ssize_t n_significant_digits = BASE_FIG*n - nlz - ntz;
+ return SSIZET2NUM(n_significant_digits);
+}
+
+/*
+ * call-seq:
+ * hash -> integer
+ *
+ * Returns the integer hash value for +self+.
+ *
+ * Two instances of \BigDecimal have the same hash value if and only if
+ * they have equal:
+ *
+ * - Sign.
+ * - Fractional part.
+ * - Exponent.
+ *
+ */
+static VALUE
+BigDecimal_hash(VALUE self)
+{
+ BDVALUE v = GetBDValueMust(self);
+ st_index_t hash = (st_index_t)v.real->sign;
+ /* hash!=2: the case for 0(1),NaN(0) or +-Infinity(3) is sign itself */
+ if(hash == 2 || hash == (st_index_t)-2) {
+ hash ^= rb_memhash(v.real->frac, sizeof(DECDIG)*v.real->Prec);
+ hash += v.real->exponent;
+ }
+ RB_GC_GUARD(v.bigdecimal);
+ return ST2FIX(hash);
+}
+
+/*
+ * call-seq:
+ * _dump -> string
+ *
+ * Returns a string representing the marshalling of +self+.
+ * See module Marshal.
+ *
+ * inf = BigDecimal('Infinity') # => Infinity
+ * dumped = inf._dump # => "9:Infinity"
+ * BigDecimal._load(dumped) # => Infinity
+ *
+ */
+static VALUE
+BigDecimal_dump(int argc, VALUE *argv, VALUE self)
+{
+ BDVALUE v;
+ char *psz;
+ VALUE dummy;
+ volatile VALUE dump;
+ size_t len;
+
+ rb_scan_args(argc, argv, "01", &dummy);
+ v = GetBDValueMust(self);
+ dump = rb_str_new(0, VpNumOfChars(v.real, "E")+50);
+ psz = RSTRING_PTR(dump);
+ snprintf(psz, RSTRING_LEN(dump), "%"PRIuSIZE":", v.real->Prec*VpBaseFig());
+ len = strlen(psz);
+ VpToString(v.real, psz+len, RSTRING_LEN(dump)-len, 0, 0);
+ rb_str_resize(dump, strlen(psz));
+
+ RB_GC_GUARD(v.bigdecimal);
+ return dump;
+}
+
+/*
+ * Internal method used to provide marshalling support. See the Marshal module.
+ */
+static VALUE
+BigDecimal_load(VALUE self, VALUE str)
+{
+ BDVALUE v;
+ unsigned char *pch;
+ unsigned char ch;
+
+ pch = (unsigned char *)StringValueCStr(str);
+ /* First skip max prec. Don't trust the value. */
+ while((*pch) != (unsigned char)'\0' && (ch = *pch++) != (unsigned char)':') {
+ if(!ISDIGIT(ch)) {
+ rb_raise(rb_eTypeError, "load failed: invalid character in the marshaled string");
+ }
+ }
+ v = bdvalue_nonnullable(CreateFromString((char *)pch, self, true, true));
+ return CheckGetValue(v);
+}
+
+static unsigned short
+check_rounding_mode_option(VALUE const opts)
+{
+ VALUE mode;
+ char const *s;
+ long l;
+
+ assert(RB_TYPE_P(opts, T_HASH));
+
+ if (NIL_P(opts))
+ goto no_opt;
+
+ mode = rb_hash_lookup2(opts, ID2SYM(id_half), Qundef);
+ if (mode == Qundef || NIL_P(mode))
+ goto no_opt;
+
+ if (SYMBOL_P(mode))
+ mode = rb_sym2str(mode);
+ else if (!RB_TYPE_P(mode, T_STRING)) {
+ VALUE str_mode = rb_check_string_type(mode);
+ if (NIL_P(str_mode))
+ goto invalid;
+ mode = str_mode;
+ }
+ s = RSTRING_PTR(mode);
+ l = RSTRING_LEN(mode);
+ switch (l) {
+ case 2:
+ if (strncasecmp(s, "up", 2) == 0)
+ return VP_ROUND_HALF_UP;
+ break;
+ case 4:
+ if (strncasecmp(s, "even", 4) == 0)
+ return VP_ROUND_HALF_EVEN;
+ else if (strncasecmp(s, "down", 4) == 0)
+ return VP_ROUND_HALF_DOWN;
+ break;
+ default:
+ break;
+ }
+
+ invalid:
+ rb_raise(rb_eArgError, "invalid rounding mode (%"PRIsVALUE")", mode);
+
+ no_opt:
+ return VpGetRoundMode();
+}
+
+static unsigned short
+check_rounding_mode(VALUE const v)
+{
+ unsigned short sw;
+ ID id;
+ if (RB_TYPE_P(v, T_SYMBOL)) {
+ int i;
+ id = SYM2ID(v);
+ for (i = 0; i < RBD_NUM_ROUNDING_MODES; ++i) {
+ if (rbd_rounding_modes[i].id == id) {
+ return rbd_rounding_modes[i].mode;
+ }
+ }
+ rb_raise(rb_eArgError, "invalid rounding mode (%"PRIsVALUE")", v);
+ }
+ else {
+ sw = NUM2USHORT(v);
+ if (!VpIsRoundMode(sw)) {
+ rb_raise(rb_eArgError, "invalid rounding mode (%"PRIsVALUE")", v);
+ }
+ return sw;
+ }
+}
+
+/* call-seq:
+ * BigDecimal.mode(mode, setting = nil) -> integer
+ *
+ * Returns an integer representing the mode settings
+ * for exception handling and rounding.
+ *
+ * These modes control exception handling:
+ *
+ * - \BigDecimal::EXCEPTION_NaN.
+ * - \BigDecimal::EXCEPTION_INFINITY.
+ * - \BigDecimal::EXCEPTION_UNDERFLOW.
+ * - \BigDecimal::EXCEPTION_OVERFLOW.
+ * - \BigDecimal::EXCEPTION_ZERODIVIDE.
+ * - \BigDecimal::EXCEPTION_ALL.
+ *
+ * Values for +setting+ for exception handling:
+ *
+ * - +true+: sets the given +mode+ to +true+.
+ * - +false+: sets the given +mode+ to +false+.
+ * - +nil+: does not modify the mode settings.
+ *
+ * You can use method BigDecimal.save_exception_mode
+ * to temporarily change, and then automatically restore, exception modes.
+ *
+ * For clarity, some examples below begin by setting all
+ * exception modes to +false+.
+ *
+ * This mode controls the way rounding is to be performed:
+ *
+ * - \BigDecimal::ROUND_MODE
+ *
+ * You can use method BigDecimal.save_rounding_mode
+ * to temporarily change, and then automatically restore, the rounding mode.
+ *
+ * <b>NaNs</b>
+ *
+ * Mode \BigDecimal::EXCEPTION_NaN controls behavior
+ * when a \BigDecimal NaN is created.
+ *
+ * Settings:
+ *
+ * - +false+ (default): Returns <tt>BigDecimal('NaN')</tt>.
+ * - +true+: Raises FloatDomainError.
+ *
+ * Examples:
+ *
+ * BigDecimal.mode(BigDecimal::EXCEPTION_ALL, false) # => 0
+ * BigDecimal('NaN') # => NaN
+ * BigDecimal.mode(BigDecimal::EXCEPTION_NaN, true) # => 2
+ * BigDecimal('NaN') # Raises FloatDomainError
+ *
+ * <b>Infinities</b>
+ *
+ * Mode \BigDecimal::EXCEPTION_INFINITY controls behavior
+ * when a \BigDecimal Infinity or -Infinity is created.
+ * Settings:
+ *
+ * - +false+ (default): Returns <tt>BigDecimal('Infinity')</tt>
+ * or <tt>BigDecimal('-Infinity')</tt>.
+ * - +true+: Raises FloatDomainError.
+ *
+ * Examples:
+ *
+ * BigDecimal.mode(BigDecimal::EXCEPTION_ALL, false) # => 0
+ * BigDecimal('Infinity') # => Infinity
+ * BigDecimal('-Infinity') # => -Infinity
+ * BigDecimal.mode(BigDecimal::EXCEPTION_INFINITY, true) # => 1
+ * BigDecimal('Infinity') # Raises FloatDomainError
+ * BigDecimal('-Infinity') # Raises FloatDomainError
+ *
+ * <b>Underflow</b>
+ *
+ * Mode \BigDecimal::EXCEPTION_UNDERFLOW controls behavior
+ * when a \BigDecimal underflow occurs.
+ * Settings:
+ *
+ * - +false+ (default): Returns <tt>BigDecimal('0')</tt>
+ * or <tt>BigDecimal('-Infinity')</tt>.
+ * - +true+: Raises FloatDomainError.
+ *
+ * Examples:
+ *
+ * BigDecimal.mode(BigDecimal::EXCEPTION_ALL, false) # => 0
+ * def flow_under
+ * x = BigDecimal('0.1')
+ * 100.times { x *= x }
+ * end
+ * flow_under # => 100
+ * BigDecimal.mode(BigDecimal::EXCEPTION_UNDERFLOW, true) # => 4
+ * flow_under # Raises FloatDomainError
+ *
+ * <b>Overflow</b>
+ *
+ * Mode \BigDecimal::EXCEPTION_OVERFLOW controls behavior
+ * when a \BigDecimal overflow occurs.
+ * Settings:
+ *
+ * - +false+ (default): Returns <tt>BigDecimal('Infinity')</tt>
+ * or <tt>BigDecimal('-Infinity')</tt>.
+ * - +true+: Raises FloatDomainError.
+ *
+ * Examples:
+ *
+ * BigDecimal.mode(BigDecimal::EXCEPTION_ALL, false) # => 0
+ * def flow_over
+ * x = BigDecimal('10')
+ * 100.times { x *= x }
+ * end
+ * flow_over # => 100
+ * BigDecimal.mode(BigDecimal::EXCEPTION_OVERFLOW, true) # => 1
+ * flow_over # Raises FloatDomainError
+ *
+ * <b>Zero Division</b>
+ *
+ * Mode \BigDecimal::EXCEPTION_ZERODIVIDE controls behavior
+ * when a zero-division occurs.
+ * Settings:
+ *
+ * - +false+ (default): Returns <tt>BigDecimal('Infinity')</tt>
+ * or <tt>BigDecimal('-Infinity')</tt>.
+ * - +true+: Raises FloatDomainError.
+ *
+ * Examples:
+ *
+ * BigDecimal.mode(BigDecimal::EXCEPTION_ALL, false) # => 0
+ * one = BigDecimal('1')
+ * zero = BigDecimal('0')
+ * one / zero # => Infinity
+ * BigDecimal.mode(BigDecimal::EXCEPTION_ZERODIVIDE, true) # => 16
+ * one / zero # Raises FloatDomainError
+ *
+ * <b>All Exceptions</b>
+ *
+ * Mode \BigDecimal::EXCEPTION_ALL controls all of the above:
+ *
+ * BigDecimal.mode(BigDecimal::EXCEPTION_ALL, false) # => 0
+ * BigDecimal.mode(BigDecimal::EXCEPTION_ALL, true) # => 23
+ *
+ * <b>Rounding</b>
+ *
+ * Mode \BigDecimal::ROUND_MODE controls the way rounding is to be performed;
+ * its +setting+ values are:
+ *
+ * - +ROUND_UP+: Round away from zero.
+ * Aliased as +:up+.
+ * - +ROUND_DOWN+: Round toward zero.
+ * Aliased as +:down+ and +:truncate+.
+ * - +ROUND_HALF_UP+: Round toward the nearest neighbor;
+ * if the neighbors are equidistant, round away from zero.
+ * Aliased as +:half_up+ and +:default+.
+ * - +ROUND_HALF_DOWN+: Round toward the nearest neighbor;
+ * if the neighbors are equidistant, round toward zero.
+ * Aliased as +:half_down+.
+ * - +ROUND_HALF_EVEN+ (Banker's rounding): Round toward the nearest neighbor;
+ * if the neighbors are equidistant, round toward the even neighbor.
+ * Aliased as +:half_even+ and +:banker+.
+ * - +ROUND_CEILING+: Round toward positive infinity.
+ * Aliased as +:ceiling+ and +:ceil+.
+ * - +ROUND_FLOOR+: Round toward negative infinity.
+ * Aliased as +:floor:+.
+ *
+ */
+static VALUE
+BigDecimal_mode(int argc, VALUE *argv, VALUE self)
+{
+ VALUE which;
+ VALUE val;
+ unsigned long f,fo;
+
+ rb_scan_args(argc, argv, "11", &which, &val);
+ f = (unsigned long)NUM2INT(which);
+
+ if (f & VP_EXCEPTION_ALL) {
+ /* Exception mode setting */
+ fo = VpGetException();
+ if (val == Qnil) return INT2FIX(fo);
+ if (val != Qfalse && val!=Qtrue) {
+ rb_raise(rb_eArgError, "second argument must be true or false");
+ return Qnil; /* Not reached */
+ }
+ if (f & VP_EXCEPTION_INFINITY) {
+ VpSetException((unsigned short)((val == Qtrue) ? (fo | VP_EXCEPTION_INFINITY) :
+ (fo & (~VP_EXCEPTION_INFINITY))));
+ }
+ fo = VpGetException();
+ if (f & VP_EXCEPTION_NaN) {
+ VpSetException((unsigned short)((val == Qtrue) ? (fo | VP_EXCEPTION_NaN) :
+ (fo & (~VP_EXCEPTION_NaN))));
+ }
+ fo = VpGetException();
+ if (f & VP_EXCEPTION_UNDERFLOW) {
+ VpSetException((unsigned short)((val == Qtrue) ? (fo | VP_EXCEPTION_UNDERFLOW) :
+ (fo & (~VP_EXCEPTION_UNDERFLOW))));
+ }
+ fo = VpGetException();
+ if(f & VP_EXCEPTION_ZERODIVIDE) {
+ VpSetException((unsigned short)((val == Qtrue) ? (fo | VP_EXCEPTION_ZERODIVIDE) :
+ (fo & (~VP_EXCEPTION_ZERODIVIDE))));
+ }
+ fo = VpGetException();
+ return INT2FIX(fo);
+ }
+ if (VP_ROUND_MODE == f) {
+ /* Rounding mode setting */
+ unsigned short sw;
+ fo = VpGetRoundMode();
+ if (NIL_P(val)) return INT2FIX(fo);
+ sw = check_rounding_mode(val);
+ fo = VpSetRoundMode(sw);
+ return INT2FIX(fo);
+ }
+ rb_raise(rb_eTypeError, "first argument for BigDecimal.mode invalid");
+ return Qnil;
+}
+
+static size_t
+GetAddSubPrec(Real *a, Real *b)
+{
+ if (VpIsZero(a) || VpIsZero(b)) return Max(a->Prec, b->Prec);
+ ssize_t min_a = a->exponent - a->Prec;
+ ssize_t min_b = b->exponent - b->Prec;
+ return Max(a->exponent, b->exponent) - Min(min_a, min_b);
+}
+
+static inline SIGNED_VALUE
+check_int_precision(VALUE v)
+{
+ SIGNED_VALUE n;
+#if SIZEOF_VALUE <= SIZEOF_LONG
+ n = (SIGNED_VALUE)NUM2LONG(v);
+#elif SIZEOF_VALUE <= SIZEOF_LONG_LONG
+ n = (SIGNED_VALUE)NUM2LL(v);
+#else
+# error SIZEOF_VALUE is too large
+#endif
+ if (n < 0) {
+ rb_raise(rb_eArgError, "negative precision");
+ }
+ return n;
+}
+
+static NULLABLE_BDVALUE
+CreateFromString(const char *str, VALUE klass, bool strict_p, bool raise_exception)
+{
+ return VpAlloc(str, strict_p, raise_exception);
+}
+
+void
+VpMemCopy(Real *pv, Real const* const x)
+{
+ pv->MaxPrec = x->MaxPrec;
+ pv->Prec = x->Prec;
+ pv->exponent = x->exponent;
+ pv->sign = x->sign;
+ pv->flag = x->flag;
+ MEMCPY(pv->frac, x->frac, DECDIG, pv->MaxPrec);
+}
+
+/* Returns True if the value is Not a Number. */
+static VALUE
+BigDecimal_IsNaN(VALUE self)
+{
+ Real *p = GetSelfVpValue(self);
+ if (VpIsNaN(p)) return Qtrue;
+ return Qfalse;
+}
+
+/* Returns nil, -1, or +1 depending on whether the value is finite,
+ * -Infinity, or +Infinity.
+ */
+static VALUE
+BigDecimal_IsInfinite(VALUE self)
+{
+ Real *p = GetSelfVpValue(self);
+ if (VpIsPosInf(p)) return INT2FIX(1);
+ if (VpIsNegInf(p)) return INT2FIX(-1);
+ return Qnil;
+}
+
+/* Returns True if the value is finite (not NaN or infinite). */
+static VALUE
+BigDecimal_IsFinite(VALUE self)
+{
+ Real *p = GetSelfVpValue(self);
+ if (VpIsNaN(p)) return Qfalse;
+ if (VpIsInf(p)) return Qfalse;
+ return Qtrue;
+}
+
+static void
+BigDecimal_check_num(Real *p)
+{
+ VpCheckException(p, true);
+}
+
+/* Returns the value as an Integer.
+ *
+ * If the BigDecimal is infinity or NaN, raises FloatDomainError.
+ */
+static VALUE
+BigDecimal_to_i(VALUE self)
+{
+ BDVALUE v;
+ VALUE ret;
+
+ v = GetBDValueMust(self);
+ BigDecimal_check_num(v.real);
+
+ if (v.real->exponent <= 0) return INT2FIX(0);
+ if (v.real->exponent == 1) {
+ ret = LONG2NUM((long)(VpGetSign(v.real) * (DECDIG_DBL_SIGNED)v.real->frac[0]));
+ }
+ else {
+ VALUE fix = (ssize_t)v.real->Prec > v.real->exponent ? BigDecimal_fix(self) : self;
+ VALUE digits = RARRAY_AREF(BigDecimal_split(fix), 1);
+ ssize_t dpower = VpExponent10(v.real) - (ssize_t)RSTRING_LEN(digits);
+ ret = rb_funcall(digits, rb_intern("to_i"), 0);
+
+ if (BIGDECIMAL_NEGATIVE_P(v.real)) {
+ ret = rb_funcall(ret, '*', 1, INT2FIX(-1));
+ }
+ if (dpower) {
+ VALUE pow10 = rb_funcall(INT2FIX(10), rb_intern("**"), 1, SSIZET2NUM(dpower));
+ // In Ruby < 3.4, int**int may return Float::INFINITY
+ if (RB_TYPE_P(pow10, T_FLOAT)) rb_raise(rb_eFloatDomainError, "Infinity");
+
+ ret = rb_funcall(ret, '*', 1, pow10);
+ }
+ }
+
+ RB_GC_GUARD(v.bigdecimal);
+ return ret;
+}
+
+/* Returns a new Float object having approximately the same value as the
+ * BigDecimal number. Normal accuracy limits and built-in errors of binary
+ * Float arithmetic apply.
+ */
+static VALUE
+BigDecimal_to_f(VALUE self)
+{
+ double d;
+ SIGNED_VALUE e;
+ char *buf;
+ volatile VALUE str;
+ BDVALUE v = GetBDValueMust(self);
+ bool negative = BIGDECIMAL_NEGATIVE_P(v.real);
+
+ if (VpVtoD(&d, &e, v.real) != 1)
+ return rb_float_new(d);
+ if (e > (SIGNED_VALUE)(DBL_MAX_10_EXP+BASE_FIG))
+ goto overflow;
+ if (e < (SIGNED_VALUE)(DBL_MIN_10_EXP-DBL_DIG))
+ goto underflow;
+
+ str = rb_str_new(0, VpNumOfChars(v.real, "E"));
+ buf = RSTRING_PTR(str);
+ VpToString(v.real, buf, RSTRING_LEN(str), 0, 0);
+
+ RB_GC_GUARD(v.bigdecimal);
+
+ errno = 0;
+ d = strtod(buf, 0);
+ if (errno == ERANGE) {
+ if (d == 0.0) goto underflow;
+ if (fabs(d) >= HUGE_VAL) goto overflow;
+ }
+ return rb_float_new(d);
+
+overflow:
+ VpException(VP_EXCEPTION_OVERFLOW, "BigDecimal to Float conversion", 0);
+ if (negative)
+ return rb_float_new(VpGetDoubleNegInf());
+ else
+ return rb_float_new(VpGetDoublePosInf());
+
+underflow:
+ VpException(VP_EXCEPTION_UNDERFLOW, "BigDecimal to Float conversion", 0);
+ if (negative)
+ return rb_float_new(-0.0);
+ else
+ return rb_float_new(0.0);
+}
+
+
+/* Converts a BigDecimal to a Rational.
+ */
+static VALUE
+BigDecimal_to_r(VALUE self)
+{
+ BDVALUE v;
+ ssize_t sign, power, denomi_power;
+ VALUE a, digits, numerator;
+
+ v = GetBDValueMust(self);
+ BigDecimal_check_num(v.real);
+ sign = VpGetSign(v.real);
+ power = VpExponent10(v.real);
+ RB_GC_GUARD(v.bigdecimal);
+
+ a = BigDecimal_split(self);
+ digits = RARRAY_AREF(a, 1);
+ denomi_power = power - RSTRING_LEN(digits);
+ numerator = rb_funcall(digits, rb_intern("to_i"), 0);
+
+ if (sign < 0) {
+ numerator = rb_funcall(numerator, '*', 1, INT2FIX(-1));
+ }
+ if (denomi_power < 0) {
+ return rb_Rational(numerator,
+ rb_funcall(INT2FIX(10), rb_intern("**"), 1,
+ INT2FIX(-denomi_power)));
+ }
+ else {
+ return rb_Rational1(rb_funcall(numerator, '*', 1,
+ rb_funcall(INT2FIX(10), rb_intern("**"), 1,
+ INT2FIX(denomi_power))));
+ }
+}
+
+static size_t
+GetCoercePrec(Real *a, size_t prec)
+{
+ if (prec == 0) prec = a->Prec * BASE_FIG;
+ if (prec < 2 * BIGDECIMAL_DOUBLE_FIGURES) prec = 2 * BIGDECIMAL_DOUBLE_FIGURES;
+ return prec;
+}
+
+/* The coerce method provides support for Ruby type coercion. It is not
+ * enabled by default.
+ *
+ * This means that binary operations like + * / or - can often be performed
+ * on a BigDecimal and an object of another type, if the other object can
+ * be coerced into a BigDecimal value.
+ *
+ * e.g.
+ * a = BigDecimal("1.0")
+ * b = a / 2.0 #=> 0.5
+ *
+ * Note that coercing a String to a BigDecimal is not supported by default;
+ * it requires a special compile-time option when building Ruby.
+ */
+static VALUE
+BigDecimal_coerce(VALUE self, VALUE other)
+{
+ Real* pv = VpPtr(self);
+ BDVALUE b = GetBDValueWithPrecMust(other, GetCoercePrec(pv, 0));
+ return rb_assoc_new(CheckGetValue(b), self);
+}
+
+/*
+ * call-seq:
+ * +big_decimal -> self
+ *
+ * Returns +self+:
+ *
+ * +BigDecimal(5) # => 0.5e1
+ * +BigDecimal(-5) # => -0.5e1
+ *
+ */
+
+static VALUE
+BigDecimal_uplus(VALUE self)
+{
+ return self;
+}
+
+static bool
+is_coerceable_to_BigDecimal(VALUE r)
+{
+ return is_kind_of_BigDecimal(r) ||
+ RB_INTEGER_TYPE_P(r) ||
+ RB_TYPE_P(r, T_FLOAT) ||
+ RB_TYPE_P(r, T_RATIONAL);
+}
+
+ /*
+ * call-seq:
+ * self + value -> bigdecimal
+ *
+ * Returns the \BigDecimal sum of +self+ and +value+:
+ *
+ * b = BigDecimal('111111.111') # => 0.111111111e6
+ * b + 2 # => 0.111113111e6
+ * b + 2.0 # => 0.111113111e6
+ * b + Rational(2, 1) # => 0.111113111e6
+ * b + Complex(2, 0) # => (0.111113111e6+0i)
+ *
+ * See the {Note About Precision}[BigDecimal.html#class-BigDecimal-label-A+Note+About+Precision].
+ *
+ */
+
+static VALUE
+BigDecimal_add(VALUE self, VALUE r)
+{
+ if (!is_coerceable_to_BigDecimal(r)) return DoSomeOne(self, r, '+');
+ return BigDecimal_addsub_with_coerce(self, r, 0, +1);
+}
+
+static VALUE
+BigDecimal_addsub_with_coerce(VALUE self, VALUE r, size_t prec, int operation)
+{
+ BDVALUE a, b, c;
+ size_t mx;
+
+ a = GetBDValueMust(self);
+ b = GetBDValueWithPrecMust(r, GetCoercePrec(a.real, prec));
+
+ if (VpIsNaN(a.real)) return CheckGetValue(a);
+ if (VpIsNaN(b.real)) return CheckGetValue(b);
+
+ if (VpIsInf(a.real) || VpIsInf(b.real)) {
+ c = NewZeroWrap(1, BASE_FIG);
+ VpAddSub(c.real, a.real, b.real, operation);
+ }
+ else {
+
+ // Optimization when exponent difference is large
+ // (1.234e+1000).add(5.678e-1000, 10) == (1.234e+1000).add(0.1e+990, 10) in every rounding mode
+ if (prec && !VpIsZero(a.real) && !VpIsZero(b.real)) {
+ size_t precRoom = roomof(prec, BASE_FIG);
+ if (a.real->exponent - (ssize_t)Max(a.real->Prec, precRoom) - 1 > b.real->exponent) {
+ BDVALUE b2 = NewZeroWrap(1, BASE_FIG);
+ VpSetOne(b2.real)
+ VpSetSign(b2.real, b.real->sign);
+ b2.real->exponent = a.real->exponent - (ssize_t)Max(a.real->Prec, precRoom) - 1;
+ b = b2;
+ } else if (b.real->exponent - (ssize_t)Max(b.real->Prec, precRoom) - 1 > a.real->exponent) {
+ BDVALUE a2 = NewZeroWrap(1, BASE_FIG);
+ VpSetOne(a2.real)
+ VpSetSign(a2.real, a.real->sign);
+ a2.real->exponent = b.real->exponent - (ssize_t)Max(b.real->Prec, precRoom) - 1;
+ a = a2;
+ }
+ }
+
+ mx = GetAddSubPrec(a.real, b.real);
+ c = NewZeroWrap(1, (mx + 1) * BASE_FIG);
+ size_t pl = VpGetPrecLimit();
+ if (prec) VpSetPrecLimit(prec);
+ // Let VpAddSub round the result
+ VpAddSub(c.real, a.real, b.real, operation);
+ if (prec) VpSetPrecLimit(pl);
+ }
+
+ RB_GC_GUARD(a.bigdecimal);
+ RB_GC_GUARD(b.bigdecimal);
+ return CheckGetValue(c);
+}
+
+ /*
+ * call-seq:
+ * self - value -> bigdecimal
+ *
+ * Returns the \BigDecimal difference of +self+ and +value+:
+ *
+ * b = BigDecimal('333333.333') # => 0.333333333e6
+ * b - 2 # => 0.333331333e6
+ * b - 2.0 # => 0.333331333e6
+ * b - Rational(2, 1) # => 0.333331333e6
+ * b - Complex(2, 0) # => (0.333331333e6+0i)
+ *
+ * See the {Note About Precision}[BigDecimal.html#class-BigDecimal-label-A+Note+About+Precision].
+ *
+ */
+static VALUE
+BigDecimal_sub(VALUE self, VALUE r)
+{
+ if (!is_coerceable_to_BigDecimal(r)) return DoSomeOne(self, r, '-');
+ return BigDecimal_addsub_with_coerce(self, r, 0, -1);
+}
+
+static VALUE
+BigDecimalCmp(VALUE self, VALUE r,char op)
+{
+ SIGNED_VALUE e;
+ BDVALUE a = GetBDValueMust(self);
+ NULLABLE_BDVALUE b = GetBDValueWithPrec(r, GetCoercePrec(a.real, 0));
+
+ if (b.real_or_null == NULL) {
+ ID f = 0;
+
+ switch (op) {
+ case '*':
+ return rb_num_coerce_cmp(self, r, rb_intern("<=>"));
+
+ case '=':
+ return RTEST(rb_num_coerce_cmp(self, r, rb_intern("=="))) ? Qtrue : Qfalse;
+
+ case 'G':
+ f = rb_intern(">=");
+ break;
+
+ case 'L':
+ f = rb_intern("<=");
+ break;
+
+ case '>':
+ /* fall through */
+ case '<':
+ f = (ID)op;
+ break;
+
+ default:
+ break;
+ }
+ return rb_num_coerce_relop(self, r, f);
+ }
+ e = VpComp(a.real, b.real_or_null);
+
+ RB_GC_GUARD(a.bigdecimal);
+ RB_GC_GUARD(b.bigdecimal_or_nil);
+
+ if (e == 999)
+ return (op == '*') ? Qnil : Qfalse;
+ switch (op) {
+ case '*':
+ return INT2FIX(e); /* any op */
+
+ case '=':
+ if (e == 0) return Qtrue;
+ return Qfalse;
+
+ case 'G':
+ if (e >= 0) return Qtrue;
+ return Qfalse;
+
+ case '>':
+ if (e > 0) return Qtrue;
+ return Qfalse;
+
+ case 'L':
+ if (e <= 0) return Qtrue;
+ return Qfalse;
+
+ case '<':
+ if (e < 0) return Qtrue;
+ return Qfalse;
+
+ default:
+ break;
+ }
+
+ rb_bug("Undefined operation in BigDecimalCmp()");
+
+ UNREACHABLE;
+}
+
+/* Returns True if the value is zero. */
+static VALUE
+BigDecimal_zero(VALUE self)
+{
+ Real *a = GetSelfVpValue(self);
+ return VpIsZero(a) ? Qtrue : Qfalse;
+}
+
+/* Returns self if the value is non-zero, nil otherwise. */
+static VALUE
+BigDecimal_nonzero(VALUE self)
+{
+ Real *a = GetSelfVpValue(self);
+ return VpIsZero(a) ? Qnil : self;
+}
+
+/* The comparison operator.
+ * a <=> b is 0 if a == b, 1 if a > b, -1 if a < b.
+ */
+static VALUE
+BigDecimal_comp(VALUE self, VALUE r)
+{
+ return BigDecimalCmp(self, r, '*');
+}
+
+/*
+ * Tests for value equality; returns true if the values are equal.
+ *
+ * The == and === operators and the eql? method have the same implementation
+ * for BigDecimal.
+ *
+ * Values may be coerced to perform the comparison:
+ *
+ * BigDecimal('1.0') == 1.0 #=> true
+ */
+static VALUE
+BigDecimal_eq(VALUE self, VALUE r)
+{
+ return BigDecimalCmp(self, r, '=');
+}
+
+/* call-seq:
+ * self < other -> true or false
+ *
+ * Returns +true+ if +self+ is less than +other+, +false+ otherwise:
+ *
+ * b = BigDecimal('1.5') # => 0.15e1
+ * b < 2 # => true
+ * b < 2.0 # => true
+ * b < Rational(2, 1) # => true
+ * b < 1.5 # => false
+ *
+ * Raises an exception if the comparison cannot be made.
+ *
+ */
+static VALUE
+BigDecimal_lt(VALUE self, VALUE r)
+{
+ return BigDecimalCmp(self, r, '<');
+}
+
+/* call-seq:
+ * self <= other -> true or false
+ *
+ * Returns +true+ if +self+ is less or equal to than +other+, +false+ otherwise:
+ *
+ * b = BigDecimal('1.5') # => 0.15e1
+ * b <= 2 # => true
+ * b <= 2.0 # => true
+ * b <= Rational(2, 1) # => true
+ * b <= 1.5 # => true
+ * b < 1 # => false
+ *
+ * Raises an exception if the comparison cannot be made.
+ *
+ */
+static VALUE
+BigDecimal_le(VALUE self, VALUE r)
+{
+ return BigDecimalCmp(self, r, 'L');
+}
+
+/* call-seq:
+ * self > other -> true or false
+ *
+ * Returns +true+ if +self+ is greater than +other+, +false+ otherwise:
+ *
+ * b = BigDecimal('1.5')
+ * b > 1 # => true
+ * b > 1.0 # => true
+ * b > Rational(1, 1) # => true
+ * b > 2 # => false
+ *
+ * Raises an exception if the comparison cannot be made.
+ *
+ */
+static VALUE
+BigDecimal_gt(VALUE self, VALUE r)
+{
+ return BigDecimalCmp(self, r, '>');
+}
+
+/* call-seq:
+ * self >= other -> true or false
+ *
+ * Returns +true+ if +self+ is greater than or equal to +other+, +false+ otherwise:
+ *
+ * b = BigDecimal('1.5')
+ * b >= 1 # => true
+ * b >= 1.0 # => true
+ * b >= Rational(1, 1) # => true
+ * b >= 1.5 # => true
+ * b > 2 # => false
+ *
+ * Raises an exception if the comparison cannot be made.
+ *
+ */
+static VALUE
+BigDecimal_ge(VALUE self, VALUE r)
+{
+ return BigDecimalCmp(self, r, 'G');
+}
+
+/*
+ * call-seq:
+ * -self -> bigdecimal
+ *
+ * Returns the \BigDecimal negation of self:
+ *
+ * b0 = BigDecimal('1.5')
+ * b1 = -b0 # => -0.15e1
+ * b2 = -b1 # => 0.15e1
+ *
+ */
+
+static VALUE
+BigDecimal_neg(VALUE self)
+{
+ BDVALUE a = GetBDValueMust(self);
+ BDVALUE c = NewZeroWrap(1, a.real->Prec * BASE_FIG);
+ VpAsgn(c.real, a.real, -10);
+ RB_GC_GUARD(a.bigdecimal);
+ return CheckGetValue(c);
+}
+
+/*
+ * call-seq:
+ * a * b -> bigdecimal
+ *
+ * Multiply by the specified value.
+ *
+ * The result precision will be the precision of the sum of each precision.
+ *
+ * See BigDecimal#mult.
+ */
+static VALUE
+BigDecimal_mult(VALUE self, VALUE r)
+{
+ if (!is_coerceable_to_BigDecimal(r)) return DoSomeOne(self, r, '*');
+ return BigDecimal_mult_with_coerce(self, r, 0);
+}
+
+static VALUE
+BigDecimal_mult_with_coerce(VALUE self, VALUE r, size_t prec)
+{
+ BDVALUE a, b, c;
+
+ a = GetBDValueMust(self);
+ b = GetBDValueWithPrecMust(r, GetCoercePrec(a.real, prec));
+
+ c = NewZeroWrap(1, VPMULT_RESULT_PREC(a.real, b.real) * BASE_FIG);
+ VpMult(c.real, a.real, b.real);
+ if (prec) {
+ VpLeftRound(c.real, VpGetRoundMode(), prec);
+ }
+ else {
+ VpLimitRound(c.real, 0);
+ }
+
+ RB_GC_GUARD(a.bigdecimal);
+ RB_GC_GUARD(b.bigdecimal);
+ return CheckGetValue(c);
+}
+
+static bool BigDecimal_DoDivmod(VALUE self, VALUE r, NULLABLE_BDVALUE *div, NULLABLE_BDVALUE *mod, bool truncate);
+
+/* call-seq:
+ * a / b -> bigdecimal
+ *
+ * Divide by the specified value.
+ *
+ * The result precision will be the precision of the larger operand,
+ * but its minimum is 2*Float::DIG.
+ *
+ * See BigDecimal#div.
+ * See BigDecimal#quo.
+ */
+static VALUE
+BigDecimal_div(VALUE self, VALUE r)
+/* For c = self/r: with round operation */
+{
+ if (!is_coerceable_to_BigDecimal(r)) return DoSomeOne(self, r, '/');
+ return BigDecimal_div2(self, r, INT2FIX(0));
+}
+
+static VALUE BigDecimal_round(int argc, VALUE *argv, VALUE self);
+
+/* call-seq:
+ * quo(value) -> bigdecimal
+ * quo(value, digits) -> bigdecimal
+ *
+ * Divide by the specified value.
+ *
+ * digits:: If specified and less than the number of significant digits of
+ * the result, the result is rounded to the given number of digits,
+ * according to the rounding mode indicated by BigDecimal.mode.
+ *
+ * If digits is 0 or omitted, the result is the same as for the
+ * / operator.
+ *
+ * See BigDecimal#/.
+ * See BigDecimal#div.
+ */
+static VALUE
+BigDecimal_quo(int argc, VALUE *argv, VALUE self)
+{
+ VALUE value, digits, result;
+ SIGNED_VALUE n = -1;
+
+ argc = rb_scan_args(argc, argv, "11", &value, &digits);
+ if (argc > 1) {
+ n = check_int_precision(digits);
+ }
+
+ if (n > 0) {
+ result = BigDecimal_div2(self, value, digits);
+ }
+ else {
+ result = BigDecimal_div(self, value);
+ }
+
+ return result;
+}
+
+/*
+ * %: mod = a%b = a - (a.to_f/b).floor * b
+ * div = (a.to_f/b).floor
+ * In truncate mode, use truncate instead of floor.
+ */
+static bool
+BigDecimal_DoDivmod(VALUE self, VALUE r, NULLABLE_BDVALUE *div, NULLABLE_BDVALUE *mod, bool truncate)
+{
+ BDVALUE a, b, dv, md, res;
+ NULLABLE_BDVALUE b2;
+ ssize_t a_exponent, b_exponent;
+ size_t mx, rx, pl;
+
+ a = GetBDValueMust(self);
+
+ b2 = GetBDValueWithPrec(r, GetCoercePrec(a.real, 0));
+ if (!b2.real_or_null) return false;
+ b = bdvalue_nonnullable(b2);
+
+ if (VpIsNaN(a.real) || VpIsNaN(b.real) || (VpIsInf(a.real) && VpIsInf(b.real))) {
+ VALUE nan = BigDecimal_nan();
+ *div = *mod = (NULLABLE_BDVALUE) { nan, VpPtr(nan) };
+ goto Done;
+ }
+ if (VpIsZero(b.real)) {
+ rb_raise(rb_eZeroDivError, "divided by 0");
+ }
+ if (VpIsInf(a.real)) {
+ if (VpGetSign(a.real) == VpGetSign(b.real)) {
+ VALUE inf = BigDecimal_positive_infinity();
+ *div = (NULLABLE_BDVALUE) { inf, VpPtr(inf) };
+ }
+ else {
+ VALUE inf = BigDecimal_negative_infinity();
+ *div = (NULLABLE_BDVALUE) { inf, VpPtr(inf) };
+ }
+ VALUE nan = BigDecimal_nan();
+ *mod = (NULLABLE_BDVALUE) { nan, VpPtr(nan) };
+ goto Done;
+ }
+ if (VpIsZero(a.real)) {
+ VALUE zero = BigDecimal_positive_zero();
+ *div = (NULLABLE_BDVALUE) { zero, VpPtr(zero) };
+ *mod = bdvalue_nullable(a);
+ goto Done;
+ }
+ if (VpIsInf(b.real)) {
+ if (!truncate && VpGetSign(a.real) * VpGetSign(b.real) < 0) {
+ BDVALUE minus_one = NewZeroWrap(1, BASE_FIG);
+ VpSetOne(minus_one.real);
+ VpSetSign(minus_one.real, -1);
+ RB_GC_GUARD(minus_one.bigdecimal);
+ *div = bdvalue_nullable(minus_one);
+ *mod = bdvalue_nullable(b);
+ } else {
+ VALUE zero = BigDecimal_positive_zero();
+ *div = (NULLABLE_BDVALUE) { zero, VpPtr(zero) };
+ *mod = bdvalue_nullable(a);
+ }
+ goto Done;
+ }
+
+ a_exponent = VpExponent10(a.real);
+ b_exponent = VpExponent10(b.real);
+ mx = a_exponent > b_exponent ? a_exponent - b_exponent + 1 : 1;
+ dv = NewZeroWrap(1, VPDIVD_QUO_DIGITS(mx));
+
+ /* res is reused for VpDivd remainder and VpMult result */
+ rx = VPDIVD_REM_PREC(a.real, b.real, dv.real);
+ mx = VPMULT_RESULT_PREC(dv.real, b.real);
+ res = NewZeroWrap(1, Max(rx, mx) * BASE_FIG);
+ /* AddSub needs one more prec */
+ md = NewZeroWrap(1, (res.real->MaxPrec + 1) * BASE_FIG);
+
+ VpDivd(dv.real, res.real, a.real, b.real);
+ VpMidRound(dv.real, VP_ROUND_DOWN, 0);
+ VpMult(res.real, dv.real, b.real);
+ pl = VpGetPrecLimit();
+ VpSetPrecLimit(0);
+ VpAddSub(md.real, a.real, res.real, -1);
+ VpSetPrecLimit(pl);
+
+ if (!truncate && !VpIsZero(md.real) && (VpGetSign(a.real) * VpGetSign(b.real) < 0)) {
+ /* result adjustment for negative case */
+ BDVALUE dv2 = NewZeroWrap(1, (dv.real->MaxPrec + 1) * BASE_FIG);
+ BDVALUE md2 = NewZeroWrap(1, (GetAddSubPrec(md.real, b.real) + 1) * BASE_FIG);
+ VpSetPrecLimit(0);
+ VpAddSub(dv2.real, dv.real, VpOne(), -1);
+ VpAddSub(md2.real, md.real, b.real, 1);
+ VpSetPrecLimit(pl);
+ *div = bdvalue_nullable(dv2);
+ *mod = bdvalue_nullable(md2);
+ RB_GC_GUARD(dv2.bigdecimal);
+ RB_GC_GUARD(md2.bigdecimal);
+ }
+ else {
+ *div = bdvalue_nullable(dv);
+ *mod = bdvalue_nullable(md);
+ }
+
+Done:
+ RB_GC_GUARD(a.bigdecimal);
+ RB_GC_GUARD(b.bigdecimal);
+ RB_GC_GUARD(dv.bigdecimal);
+ RB_GC_GUARD(md.bigdecimal);
+ RB_GC_GUARD(res.bigdecimal);
+ return true;
+}
+
+/* call-seq:
+ * a % b
+ * a.modulo(b)
+ *
+ * Returns the modulus from dividing by b.
+ *
+ * See BigDecimal#divmod.
+ */
+static VALUE
+BigDecimal_mod(VALUE self, VALUE r) /* %: a%b = a - (a.to_f/b).floor * b */
+{
+ NULLABLE_BDVALUE div, mod;
+
+ if (BigDecimal_DoDivmod(self, r, &div, &mod, false)) {
+ return CheckGetValue(bdvalue_nonnullable(mod));
+ }
+ return DoSomeOne(self, r, '%');
+}
+
+/* call-seq:
+ * remainder(value)
+ *
+ * Returns the remainder from dividing by the value.
+ *
+ * x.remainder(y) means x-y*(x/y).truncate
+ */
+static VALUE
+BigDecimal_remainder(VALUE self, VALUE r) /* remainder */
+{
+ NULLABLE_BDVALUE div, mod = { Qnil, NULL };
+
+ if (BigDecimal_DoDivmod(self, r, &div, &mod, true)) {
+ return CheckGetValue(bdvalue_nonnullable(mod));
+ }
+ return DoSomeOne(self, r, rb_intern("remainder"));
+}
+
+/* call-seq:
+ * divmod(value)
+ *
+ * Divides by the specified value, and returns the quotient and modulus
+ * as BigDecimal numbers. The quotient is rounded towards negative infinity.
+ *
+ * For example:
+ *
+ * require 'bigdecimal'
+ *
+ * a = BigDecimal("42")
+ * b = BigDecimal("9")
+ *
+ * q, m = a.divmod(b)
+ *
+ * c = q * b + m
+ *
+ * a == c #=> true
+ *
+ * The quotient q is (a/b).floor, and the modulus is the amount that must be
+ * added to q * b to get a.
+ */
+static VALUE
+BigDecimal_divmod(VALUE self, VALUE r)
+{
+ NULLABLE_BDVALUE div, mod;
+
+ if (BigDecimal_DoDivmod(self, r, &div, &mod, false)) {
+ return rb_assoc_new(BigDecimal_to_i(CheckGetValue(bdvalue_nonnullable(div))), CheckGetValue(bdvalue_nonnullable(mod)));
+ }
+ return DoSomeOne(self,r,rb_intern("divmod"));
+}
+
+/*
+ * Do the same manner as Float#div when n is nil.
+ * Do the same manner as BigDecimal#quo when n is 0.
+ */
+static inline VALUE
+BigDecimal_div2(VALUE self, VALUE b, VALUE n)
+{
+ SIGNED_VALUE ix;
+ BDVALUE av, bv, cv, res;
+
+ if (NIL_P(n)) { /* div in Float sense */
+ NULLABLE_BDVALUE div;
+ NULLABLE_BDVALUE mod;
+ if (BigDecimal_DoDivmod(self, b, &div, &mod, false)) {
+ return BigDecimal_to_i(CheckGetValue(bdvalue_nonnullable(div)));
+ }
+ return DoSomeOne(self, b, rb_intern("div"));
+ }
+
+ /* div in BigDecimal sense */
+ ix = check_int_precision(n);
+
+ av = GetBDValueMust(self);
+ bv = GetBDValueWithPrecMust(b, GetCoercePrec(av.real, ix));
+
+ if (ix == 0) {
+ ssize_t a_prec, b_prec, limit = VpGetPrecLimit();
+ VpCountPrecisionAndScale(av.real, &a_prec, NULL);
+ VpCountPrecisionAndScale(bv.real, &b_prec, NULL);
+ ix = ((a_prec > b_prec) ? a_prec : b_prec) + BIGDECIMAL_DOUBLE_FIGURES;
+ if (2 * BIGDECIMAL_DOUBLE_FIGURES > ix)
+ ix = 2 * BIGDECIMAL_DOUBLE_FIGURES;
+ if (limit && limit < ix) ix = limit;
+ }
+
+ // Needs to calculate 1 extra digit for rounding.
+ cv = NewZeroWrap(1, VPDIVD_QUO_DIGITS(ix + 1));
+ res = NewZeroWrap(1, VPDIVD_REM_PREC(av.real, bv.real, cv.real) * BASE_FIG);
+ VpDivd(cv.real, res.real, av.real, bv.real);
+
+ if (!VpIsZero(res.real)) {
+ // Remainder value affects rounding result.
+ // ROUND_UP cv = 0.1e0 with idx=10 will be:
+ // 0.1e0 if remainder == 0
+ // 0.1000000001e0 if remainder != 0
+ size_t idx = roomof(ix, BASE_FIG);
+ while (cv.real->Prec <= idx) cv.real->frac[cv.real->Prec++] = 0;
+ if (cv.real->frac[idx] == 0 || cv.real->frac[idx] == HALF_BASE) cv.real->frac[idx]++;
+ }
+ VpLeftRound(cv.real, VpGetRoundMode(), ix);
+
+ RB_GC_GUARD(av.bigdecimal);
+ RB_GC_GUARD(bv.bigdecimal);
+ RB_GC_GUARD(res.bigdecimal);
+ return CheckGetValue(cv);
+}
+
+ /*
+ * Document-method: BigDecimal#div
+ *
+ * call-seq:
+ * div(value) -> integer
+ * div(value, digits) -> bigdecimal or integer
+ *
+ * Divide by the specified value.
+ *
+ * digits:: If specified and less than the number of significant digits of the
+ * result, the result is rounded to that number of digits, according
+ * to BigDecimal.mode.
+ *
+ * If digits is 0, the result is the same as for the / operator
+ * or #quo.
+ *
+ * If digits is not specified, the result is an integer,
+ * by analogy with Float#div; see also BigDecimal#divmod.
+ *
+ * See BigDecimal#/.
+ * See BigDecimal#quo.
+ *
+ * Examples:
+ *
+ * a = BigDecimal("4")
+ * b = BigDecimal("3")
+ *
+ * a.div(b, 3) # => 0.133e1
+ *
+ * a.div(b, 0) # => 0.1333333333333333333e1
+ * a / b # => 0.1333333333333333333e1
+ * a.quo(b) # => 0.1333333333333333333e1
+ *
+ * a.div(b) # => 1
+ */
+static VALUE
+BigDecimal_div3(int argc, VALUE *argv, VALUE self)
+{
+ VALUE b,n;
+
+ rb_scan_args(argc, argv, "11", &b, &n);
+
+ return BigDecimal_div2(self, b, n);
+}
+
+ /*
+ * call-seq:
+ * add(value, ndigits) -> new_bigdecimal
+ *
+ * Returns the \BigDecimal sum of +self+ and +value+
+ * with a precision of +ndigits+ decimal digits.
+ *
+ * When +ndigits+ is less than the number of significant digits
+ * in the sum, the sum is rounded to that number of digits,
+ * according to the current rounding mode; see BigDecimal.mode.
+ *
+ * Examples:
+ *
+ * # Set the rounding mode.
+ * BigDecimal.mode(BigDecimal::ROUND_MODE, :half_up)
+ * b = BigDecimal('111111.111')
+ * b.add(1, 0) # => 0.111112111e6
+ * b.add(1, 3) # => 0.111e6
+ * b.add(1, 6) # => 0.111112e6
+ * b.add(1, 15) # => 0.111112111e6
+ * b.add(1.0, 15) # => 0.111112111e6
+ * b.add(Rational(1, 1), 15) # => 0.111112111e6
+ *
+ */
+
+static VALUE
+BigDecimal_add2(VALUE self, VALUE b, VALUE n)
+{
+ return BigDecimal_addsub_with_coerce(self, b, check_int_precision(n), +1);
+}
+
+/* call-seq:
+ * sub(value, digits) -> bigdecimal
+ *
+ * Subtract the specified value.
+ *
+ * e.g.
+ * c = a.sub(b,n)
+ *
+ * digits:: If specified and less than the number of significant digits of the
+ * result, the result is rounded to that number of digits, according
+ * to BigDecimal.mode.
+ *
+ */
+static VALUE
+BigDecimal_sub2(VALUE self, VALUE b, VALUE n)
+{
+ return BigDecimal_addsub_with_coerce(self, b, check_int_precision(n), -1);
+}
+
+ /*
+ * call-seq:
+ * mult(other, ndigits) -> bigdecimal
+ *
+ * Returns the \BigDecimal product of +self+ and +value+
+ * with a precision of +ndigits+ decimal digits.
+ *
+ * When +ndigits+ is less than the number of significant digits
+ * in the sum, the sum is rounded to that number of digits,
+ * according to the current rounding mode; see BigDecimal.mode.
+ *
+ * Examples:
+ *
+ * # Set the rounding mode.
+ * BigDecimal.mode(BigDecimal::ROUND_MODE, :half_up)
+ * b = BigDecimal('555555.555')
+ * b.mult(3, 0) # => 0.1666666665e7
+ * b.mult(3, 3) # => 0.167e7
+ * b.mult(3, 6) # => 0.166667e7
+ * b.mult(3, 15) # => 0.1666666665e7
+ * b.mult(3.0, 0) # => 0.1666666665e7
+ * b.mult(Rational(3, 1), 0) # => 0.1666666665e7
+ * b.mult(Complex(3, 0), 0) # => (0.1666666665e7+0.0i)
+ *
+ */
+
+static VALUE
+BigDecimal_mult2(VALUE self, VALUE b, VALUE n)
+{
+ return BigDecimal_mult_with_coerce(self, b, check_int_precision(n));
+}
+
+/*
+ * call-seq:
+ * abs -> bigdecimal
+ *
+ * Returns the \BigDecimal absolute value of +self+:
+ *
+ * BigDecimal('5').abs # => 0.5e1
+ * BigDecimal('-3').abs # => 0.3e1
+ *
+ */
+
+static VALUE
+BigDecimal_abs(VALUE self)
+{
+ BDVALUE a = GetBDValueMust(self);
+ BDVALUE c = NewZeroWrap(1, a.real->Prec * BASE_FIG);
+ VpAsgn(c.real, a.real, 10);
+ VpChangeSign(c.real, 1);
+ RB_GC_GUARD(a.bigdecimal);
+ return CheckGetValue(c);
+}
+
+/* Return the integer part of the number, as a BigDecimal.
+ */
+static VALUE
+BigDecimal_fix(VALUE self)
+{
+ BDVALUE a = GetBDValueMust(self);
+ BDVALUE c = NewZeroWrap(1, (a.real->Prec + 1) * BASE_FIG);
+ VpActiveRound(c.real, a.real, VP_ROUND_DOWN, 0); /* 0: round off */
+ RB_GC_GUARD(a.bigdecimal);
+ return CheckGetValue(c);
+}
+
+/* call-seq:
+ * round(n, mode)
+ *
+ * Round to the nearest integer (by default), returning the result as a
+ * BigDecimal if n is specified and positive, or as an Integer if it isn't.
+ *
+ * BigDecimal('3.14159').round #=> 3
+ * BigDecimal('8.7').round #=> 9
+ * BigDecimal('-9.9').round #=> -10
+ *
+ * BigDecimal('3.14159').round(2).class.name #=> "BigDecimal"
+ * BigDecimal('3.14159').round.class.name #=> "Integer"
+ * BigDecimal('3.14159').round(0).class.name #=> "Integer"
+ *
+ * If n is specified and positive, the fractional part of the result has no
+ * more than that many digits.
+ *
+ * If n is specified and negative, at least that many digits to the left of the
+ * decimal point will be 0 in the result, and return value will be an Integer.
+ *
+ * BigDecimal('3.14159').round(3) #=> 3.142
+ * BigDecimal('13345.234').round(-2) #=> 13300
+ *
+ * The value of the optional mode argument can be used to determine how
+ * rounding is performed; see BigDecimal.mode.
+ */
+static VALUE
+BigDecimal_round(int argc, VALUE *argv, VALUE self)
+{
+ BDVALUE c, a;
+ int iLoc = 0;
+ VALUE vLoc;
+ VALUE vRound;
+ int round_to_int = 0;
+ size_t mx;
+
+ unsigned short sw = VpGetRoundMode();
+
+ switch (rb_scan_args(argc, argv, "02", &vLoc, &vRound)) {
+ case 0:
+ iLoc = 0;
+ round_to_int = 1;
+ break;
+ case 1:
+ if (RB_TYPE_P(vLoc, T_HASH)) {
+ sw = check_rounding_mode_option(vLoc);
+ }
+ else {
+ iLoc = NUM2INT(vLoc);
+ if (iLoc < 1) round_to_int = 1;
+ }
+ break;
+ case 2:
+ iLoc = NUM2INT(vLoc);
+ if (RB_TYPE_P(vRound, T_HASH)) {
+ sw = check_rounding_mode_option(vRound);
+ }
+ else {
+ sw = check_rounding_mode(vRound);
+ }
+ break;
+ default:
+ break;
+ }
+
+ a = GetBDValueMust(self);
+ mx = (a.real->Prec + 1) * BASE_FIG;
+ c = NewZeroWrap(1, mx);
+
+ VpActiveRound(c.real, a.real, sw, iLoc);
+
+ RB_GC_GUARD(a.bigdecimal);
+
+ if (round_to_int) {
+ return BigDecimal_to_i(CheckGetValue(c));
+ }
+ return CheckGetValue(c);
+}
+
+static VALUE
+BigDecimal_truncate_floor_ceil(int argc, VALUE *argv, VALUE self, unsigned short rounding_mode)
+{
+ BDVALUE c, a;
+ int iLoc;
+ VALUE vLoc;
+ size_t mx;
+
+ if (rb_scan_args(argc, argv, "01", &vLoc) == 0) {
+ iLoc = 0;
+ }
+ else {
+ iLoc = NUM2INT(vLoc);
+ }
+
+ a = GetBDValueMust(self);
+ mx = (a.real->Prec + 1) * BASE_FIG;
+ c = NewZeroWrap(1, mx);
+ VpActiveRound(c.real, a.real, rounding_mode, iLoc);
+
+ RB_GC_GUARD(a.bigdecimal);
+
+ if (argc == 0) {
+ return BigDecimal_to_i(CheckGetValue(c));
+ }
+ return CheckGetValue(c);
+}
+
+/* call-seq:
+ * truncate(n)
+ *
+ * Truncate to the nearest integer (by default), returning the result as a
+ * BigDecimal.
+ *
+ * BigDecimal('3.14159').truncate #=> 3
+ * BigDecimal('8.7').truncate #=> 8
+ * BigDecimal('-9.9').truncate #=> -9
+ *
+ * If n is specified and positive, the fractional part of the result has no
+ * more than that many digits.
+ *
+ * If n is specified and negative, at least that many digits to the left of the
+ * decimal point will be 0 in the result.
+ *
+ * BigDecimal('3.14159').truncate(3) #=> 3.141
+ * BigDecimal('13345.234').truncate(-2) #=> 13300.0
+ */
+static VALUE
+BigDecimal_truncate(int argc, VALUE *argv, VALUE self)
+{
+ return BigDecimal_truncate_floor_ceil(argc, argv, self, VP_ROUND_DOWN);
+}
+
+/* Return the fractional part of the number, as a BigDecimal.
+ */
+static VALUE
+BigDecimal_frac(VALUE self)
+{
+ BDVALUE a = GetBDValueMust(self);
+ BDVALUE c = NewZeroWrap(1, (a.real->Prec + 1) * BASE_FIG);
+ VpFrac(c.real, a.real);
+ RB_GC_GUARD(a.bigdecimal);
+ return CheckGetValue(c);
+}
+
+/* call-seq:
+ * floor(n)
+ *
+ * Return the largest integer less than or equal to the value, as a BigDecimal.
+ *
+ * BigDecimal('3.14159').floor #=> 3
+ * BigDecimal('-9.1').floor #=> -10
+ *
+ * If n is specified and positive, the fractional part of the result has no
+ * more than that many digits.
+ *
+ * If n is specified and negative, at least that
+ * many digits to the left of the decimal point will be 0 in the result.
+ *
+ * BigDecimal('3.14159').floor(3) #=> 3.141
+ * BigDecimal('13345.234').floor(-2) #=> 13300.0
+ */
+static VALUE
+BigDecimal_floor(int argc, VALUE *argv, VALUE self)
+{
+ return BigDecimal_truncate_floor_ceil(argc, argv, self, VP_ROUND_FLOOR);
+}
+
+/* call-seq:
+ * ceil(n)
+ *
+ * Return the smallest integer greater than or equal to the value, as a BigDecimal.
+ *
+ * BigDecimal('3.14159').ceil #=> 4
+ * BigDecimal('-9.1').ceil #=> -9
+ *
+ * If n is specified and positive, the fractional part of the result has no
+ * more than that many digits.
+ *
+ * If n is specified and negative, at least that
+ * many digits to the left of the decimal point will be 0 in the result.
+ *
+ * BigDecimal('3.14159').ceil(3) #=> 3.142
+ * BigDecimal('13345.234').ceil(-2) #=> 13400.0
+ */
+static VALUE
+BigDecimal_ceil(int argc, VALUE *argv, VALUE self)
+{
+ return BigDecimal_truncate_floor_ceil(argc, argv, self, VP_ROUND_CEIL);
+}
+
+/* call-seq:
+ * to_s(s)
+ *
+ * Converts the value to a string.
+ *
+ * The default format looks like 0.xxxxEnn.
+ *
+ * The optional parameter s consists of either an integer; or an optional '+'
+ * or ' ', followed by an optional number, followed by an optional 'E' or 'F'.
+ *
+ * If there is a '+' at the start of s, positive values are returned with
+ * a leading '+'.
+ *
+ * A space at the start of s returns positive values with a leading space.
+ *
+ * If s contains a number, a space is inserted after each group of that many
+ * digits, starting from '.' and counting outwards.
+ *
+ * If s ends with an 'E', scientific notation (0.xxxxEnn) is used.
+ *
+ * If s ends with an 'F', conventional floating point notation is used.
+ *
+ * Examples:
+ *
+ * BigDecimal('-1234567890123.45678901234567890').to_s('5F')
+ * #=> '-123 45678 90123.45678 90123 45678 9'
+ *
+ * BigDecimal('1234567890123.45678901234567890').to_s('+8F')
+ * #=> '+12345 67890123.45678901 23456789'
+ *
+ * BigDecimal('1234567890123.45678901234567890').to_s(' F')
+ * #=> ' 1234567890123.4567890123456789'
+ */
+static VALUE
+BigDecimal_to_s(int argc, VALUE *argv, VALUE self)
+{
+ int fmt = 0; /* 0: E format, 1: F format */
+ int fPlus = 0; /* 0: default, 1: set ' ' before digits, 2: set '+' before digits. */
+ BDVALUE v;
+ volatile VALUE str;
+ char *psz;
+ char ch;
+ size_t nc, mc = 0;
+ SIGNED_VALUE m;
+ VALUE f;
+
+ v = GetBDValueMust(self);
+
+ if (rb_scan_args(argc, argv, "01", &f) == 1) {
+ if (RB_TYPE_P(f, T_STRING)) {
+ psz = StringValueCStr(f);
+ if (*psz == ' ') {
+ fPlus = 1;
+ psz++;
+ }
+ else if (*psz == '+') {
+ fPlus = 2;
+ psz++;
+ }
+ while ((ch = *psz++) != 0) {
+ if (ISSPACE(ch)) {
+ continue;
+ }
+ if (!ISDIGIT(ch)) {
+ if (ch == 'F' || ch == 'f') {
+ fmt = 1; /* F format */
+ }
+ break;
+ }
+ mc = mc*10 + ch - '0';
+ }
+ }
+ else {
+ m = NUM2INT(f);
+ if (m <= 0) {
+ rb_raise(rb_eArgError, "argument must be positive");
+ }
+ mc = (size_t)m;
+ }
+ }
+ if (fmt) {
+ nc = VpNumOfChars(v.real, "F");
+ }
+ else {
+ nc = VpNumOfChars(v.real, "E");
+ }
+ if (mc > 0) {
+ nc += (nc + mc - 1) / mc + 1;
+ }
+
+ str = rb_usascii_str_new(0, nc);
+ psz = RSTRING_PTR(str);
+
+ if (fmt) {
+ VpToFString(v.real, psz, RSTRING_LEN(str), mc, fPlus);
+ }
+ else {
+ VpToString (v.real, psz, RSTRING_LEN(str), mc, fPlus);
+ }
+ rb_str_resize(str, strlen(psz));
+
+ RB_GC_GUARD(v.bigdecimal);
+ return str;
+}
+
+/* Splits a BigDecimal number into four parts, returned as an array of values.
+ *
+ * The first value represents the sign of the BigDecimal, and is -1 or 1, or 0
+ * if the BigDecimal is Not a Number.
+ *
+ * The second value is a string representing the significant digits of the
+ * BigDecimal, with no leading zeros.
+ *
+ * The third value is the base used for arithmetic (currently always 10) as an
+ * Integer.
+ *
+ * The fourth value is an Integer exponent.
+ *
+ * If the BigDecimal can be represented as 0.xxxxxx*10**n, then xxxxxx is the
+ * string of significant digits with no leading zeros, and n is the exponent.
+ *
+ * From these values, you can translate a BigDecimal to a float as follows:
+ *
+ * sign, significant_digits, base, exponent = a.split
+ * f = sign * "0.#{significant_digits}".to_f * (base ** exponent)
+ *
+ * (Note that the to_f method is provided as a more convenient way to translate
+ * a BigDecimal to a Float.)
+ */
+static VALUE
+BigDecimal_split(VALUE self)
+{
+ BDVALUE v;
+ VALUE obj,str;
+ ssize_t e, s;
+ char *psz1;
+
+ v = GetBDValueMust(self);
+ str = rb_str_new(0, VpNumOfChars(v.real, "E"));
+ psz1 = RSTRING_PTR(str);
+ VpSzMantissa(v.real, psz1, RSTRING_LEN(str));
+ s = 1;
+ if(psz1[0] == '-') {
+ size_t len = strlen(psz1 + 1);
+
+ memmove(psz1, psz1 + 1, len);
+ psz1[len] = '\0';
+ s = -1;
+ }
+ if (psz1[0] == 'N') s = 0; /* NaN */
+ e = VpExponent10(v.real);
+ obj = rb_ary_new2(4);
+ rb_ary_push(obj, INT2FIX(s));
+ rb_ary_push(obj, str);
+ rb_str_resize(str, strlen(psz1));
+ rb_ary_push(obj, INT2FIX(10));
+ rb_ary_push(obj, SSIZET2NUM(e));
+
+ RB_GC_GUARD(v.bigdecimal);
+ return obj;
+}
+
+/* Returns the exponent of the BigDecimal number, as an Integer.
+ *
+ * If the number can be represented as 0.xxxxxx*10**n where xxxxxx is a string
+ * of digits with no leading zeros, then n is the exponent.
+ */
+static VALUE
+BigDecimal_exponent(VALUE self)
+{
+ ssize_t e = VpExponent10(GetSelfVpValue(self));
+ return SSIZET2NUM(e);
+}
+
+/* Returns a string representation of self.
+ *
+ * BigDecimal("1234.5678").inspect
+ * #=> "0.12345678e4"
+ */
+static VALUE
+BigDecimal_inspect(VALUE self)
+{
+ BDVALUE v;
+ volatile VALUE str;
+ size_t nc;
+
+ v = GetBDValueMust(self);
+ nc = VpNumOfChars(v.real, "E");
+
+ str = rb_str_new(0, nc);
+ VpToString(v.real, RSTRING_PTR(str), RSTRING_LEN(str), 0, 0);
+ rb_str_resize(str, strlen(RSTRING_PTR(str)));
+
+ RB_GC_GUARD(v.bigdecimal);
+ return str;
+}
+
+/* Returns self * 10**v without changing the precision.
+ * This method is currently for internal use.
+ *
+ * BigDecimal("0.123e10")._decimal_shift(20) #=> "0.123e30"
+ * BigDecimal("0.123e10")._decimal_shift(-20) #=> "0.123e-10"
+ */
+static VALUE
+BigDecimal_decimal_shift(VALUE self, VALUE v)
+{
+ BDVALUE a, c;
+ ssize_t shift, exponentShift;
+ bool shiftDown;
+ size_t prec;
+ DECDIG ex, iex;
+
+ a = GetBDValueMust(self);
+ shift = NUM2SSIZET(rb_to_int(v));
+
+ if (VpIsZero(a.real) || VpIsNaN(a.real) || VpIsInf(a.real) || shift == 0) return CheckGetValue(a);
+
+ exponentShift = shift > 0 ? shift / BASE_FIG : (shift + 1) / BASE_FIG - 1;
+ shift -= exponentShift * BASE_FIG;
+ ex = 1;
+ for (int i = 0; i < shift; i++) ex *= 10;
+ shiftDown = a.real->frac[0] * (DECDIG_DBL)ex >= BASE;
+ iex = BASE / ex;
+
+ prec = a.real->Prec + shiftDown;
+ c = NewZeroWrap(1, prec * BASE_FIG);
+ if (shift == 0) {
+ VpAsgn(c.real, a.real, 10);
+ } else if (shiftDown) {
+ DECDIG carry = 0;
+ exponentShift++;
+ for (size_t i = 0; i < a.real->Prec; i++) {
+ DECDIG v = a.real->frac[i];
+ c.real->frac[i] = carry * ex + v / iex;
+ carry = v % iex;
+ }
+ c.real->frac[a.real->Prec] = carry * ex;
+ } else {
+ DECDIG carry = 0;
+ for (ssize_t i = a.real->Prec - 1; i >= 0; i--) {
+ DECDIG v = a.real->frac[i];
+ c.real->frac[i] = v % iex * ex + carry;
+ carry = v / iex;
+ }
+ }
+ while (c.real->frac[prec - 1] == 0) prec--;
+ c.real->Prec = prec;
+ c.real->sign = a.real->sign;
+ c.real->exponent = a.real->exponent;
+ AddExponent(c.real, exponentShift);
+ RB_GC_GUARD(a.bigdecimal);
+ return CheckGetValue(c);
+}
+
+inline static int
+is_zero(VALUE x)
+{
+ VALUE num;
+
+ switch (TYPE(x)) {
+ case T_FIXNUM:
+ return FIX2LONG(x) == 0;
+
+ case T_BIGNUM:
+ return Qfalse;
+
+ case T_RATIONAL:
+ num = rb_rational_num(x);
+ return FIXNUM_P(num) && FIX2LONG(num) == 0;
+
+ default:
+ break;
+ }
+
+ return RTEST(rb_funcall(x, id_eq, 1, INT2FIX(0)));
+}
+
+/* :nodoc: */
+static VALUE
+BigDecimal_clone(VALUE self)
+{
+ return self;
+}
+
+#ifdef HAVE_RB_OPTS_EXCEPTION_P
+int rb_opts_exception_p(VALUE opts, int default_value);
+#define opts_exception_p(opts) rb_opts_exception_p((opts), 1)
+#else
+static int
+opts_exception_p(VALUE opts)
+{
+ static ID kwds[1];
+ VALUE exception;
+ if (!kwds[0]) {
+ kwds[0] = rb_intern_const("exception");
+ }
+ if (!rb_get_kwargs(opts, kwds, 0, 1, &exception)) return 1;
+ switch (exception) {
+ case Qtrue: case Qfalse:
+ break;
+ default:
+ rb_raise(rb_eArgError, "true or false is expected as exception: %+"PRIsVALUE,
+ exception);
+ }
+ return exception != Qfalse;
+}
+#endif
+
+static VALUE
+check_exception(VALUE bd)
+{
+ assert(is_kind_of_BigDecimal(bd));
+
+ VpCheckException(VpPtr(bd), false);
+
+ return bd;
+}
+
+static VALUE
+rb_uint64_convert_to_BigDecimal(uint64_t uval)
+{
+ VALUE bd;
+ Real *vp;
+ if (uval == 0) {
+ bd = BigDecimal_allocate(1);
+ vp = VpPtr(bd);
+ vp->Prec = 1;
+ vp->exponent = 1;
+ VpSetZero(vp, 1);
+ vp->frac[0] = 0;
+ }
+ else if (uval < BASE) {
+ bd = BigDecimal_allocate(1);
+ vp = VpPtr(bd);
+ vp->Prec = 1;
+ vp->exponent = 1;
+ VpSetSign(vp, 1);
+ vp->frac[0] = (DECDIG)uval;
+ }
+ else {
+ DECDIG buf[BIGDECIMAL_INT64_MAX_LENGTH] = {0,};
+ DECDIG r = uval % BASE;
+ size_t len = 0, ntz = 0;
+ if (r == 0) {
+ // Count and skip trailing zeros
+ for (; r == 0 && uval > 0; ++ntz) {
+ uval /= BASE;
+ r = uval % BASE;
+ }
+ }
+ for (; uval > 0; ++len) {
+ // Store digits
+ buf[BIGDECIMAL_INT64_MAX_LENGTH - len - 1] = r;
+ uval /= BASE;
+ r = uval % BASE;
+ }
+
+ const size_t exp = len + ntz;
+ bd = BigDecimal_allocate(len);
+ vp = VpPtr(bd);
+ vp->Prec = len;
+ vp->exponent = exp;
+ VpSetSign(vp, 1);
+ MEMCPY(vp->frac, buf + BIGDECIMAL_INT64_MAX_LENGTH - len, DECDIG, len);
+ }
+
+ return bd;
+}
+
+static VALUE
+rb_int64_convert_to_BigDecimal(int64_t ival)
+{
+ const uint64_t uval = (ival < 0) ? (((uint64_t)-(ival+1))+1) : (uint64_t)ival;
+ VALUE bd = rb_uint64_convert_to_BigDecimal(uval);
+ if (ival < 0) {
+ Real *vp = VpPtr(bd);
+ VpSetSign(vp, -1);
+ }
+ return bd;
+}
+
+static VALUE
+rb_big_convert_to_BigDecimal(VALUE val)
+{
+ assert(RB_TYPE_P(val, T_BIGNUM));
+
+ int leading_zeros;
+ size_t size = rb_absint_size(val, &leading_zeros);
+ int sign = FIX2INT(rb_big_cmp(val, INT2FIX(0)));
+ if (sign < 0 && leading_zeros == 0) {
+ size += 1;
+ }
+ if (size <= sizeof(long)) {
+ if (sign < 0) {
+ return rb_int64_convert_to_BigDecimal(NUM2LONG(val));
+ }
+ else {
+ return rb_uint64_convert_to_BigDecimal(NUM2ULONG(val));
+ }
+ }
+#if defined(SIZEOF_LONG_LONG) && SIZEOF_LONG < SIZEOF_LONG_LONG
+ else if (size <= sizeof(LONG_LONG)) {
+ if (sign < 0) {
+ return rb_int64_convert_to_BigDecimal(NUM2LL(val));
+ }
+ else {
+ return rb_uint64_convert_to_BigDecimal(NUM2ULL(val));
+ }
+ }
+#endif
+ else {
+ VALUE str = rb_big2str(val, 10);
+ BDVALUE v = bdvalue_nonnullable(CreateFromString(
+ RSTRING_PTR(str),
+ rb_cBigDecimal,
+ true,
+ true
+ ));
+ RB_GC_GUARD(str);
+ return CheckGetValue(v);
+ }
+}
+
+static VALUE
+rb_inum_convert_to_BigDecimal(VALUE val)
+{
+ assert(RB_INTEGER_TYPE_P(val));
+ if (FIXNUM_P(val)) {
+ return rb_int64_convert_to_BigDecimal(FIX2LONG(val));
+ }
+ else {
+ return rb_big_convert_to_BigDecimal(val);
+ }
+}
+
+static VALUE
+rb_float_convert_to_BigDecimal(VALUE val, size_t digs, int raise_exception)
+{
+ assert(RB_FLOAT_TYPE_P(val));
+
+ double d = RFLOAT_VALUE(val);
+
+ if (isnan(d)) {
+ VALUE obj = BigDecimal_nan();
+ return check_exception(obj);
+ }
+ else if (isinf(d)) {
+ VALUE obj;
+ if (d > 0) {
+ obj = BigDecimal_positive_infinity();
+ }
+ else {
+ obj = BigDecimal_negative_infinity();
+ }
+ return check_exception(obj);
+ }
+ else if (d == 0.0) {
+ if (1/d < 0.0) {
+ return BigDecimal_negative_zero();
+ }
+ else {
+ return BigDecimal_positive_zero();
+ }
+ }
+
+ if (digs == SIZE_MAX) {
+ digs = 0;
+ }
+ else if (digs > BIGDECIMAL_DOUBLE_FIGURES) {
+ if (!raise_exception)
+ return Qnil;
+ rb_raise(rb_eArgError, "precision too large.");
+ }
+
+ /* Use the same logic in flo_to_s to convert a float to a decimal string */
+ char buf[BIGDECIMAL_DOUBLE_FIGURES + BASE_FIG + 2 + 1]; /* sizeof(buf) == 28 in the typical case */
+ int decpt, negative_p;
+ char *e;
+ const int mode = digs == 0 ? 0 : 2;
+ char *p = BigDecimal_dtoa(d, mode, (int)digs, &decpt, &negative_p, &e);
+ int len10 = (int)(e - p);
+ if (len10 > BIGDECIMAL_DOUBLE_FIGURES) {
+ /* TODO: Presumably, rounding should be done here. */
+ len10 = BIGDECIMAL_DOUBLE_FIGURES;
+ }
+ memcpy(buf, p, len10);
+ free(p);
+
+ VALUE inum;
+ size_t RB_UNUSED_VAR(prec) = 0;
+ SIGNED_VALUE exp = 0;
+ if (decpt > 0) {
+ if (decpt < len10) {
+ /*
+ * len10 |---------------|
+ * : |-------| frac_len10 = len10 - decpt
+ * decpt |-------| |--| ntz10 = BASE_FIG - frac_len10 % BASE_FIG
+ * : : :
+ * 00 dd dddd.dddd dd 00
+ * prec |-----.----.----.-----| prec = exp + roomof(frac_len, BASE_FIG)
+ * exp |-----.----| exp = roomof(decpt, BASE_FIG)
+ */
+ const size_t frac_len10 = len10 - decpt;
+ const size_t ntz10 = BASE_FIG - frac_len10 % BASE_FIG;
+ memset(buf + len10, '0', ntz10);
+ buf[len10 + ntz10] = '\0';
+ inum = rb_cstr_to_inum(buf, 10, false);
+
+ exp = roomof(decpt, BASE_FIG);
+ prec = exp + roomof(frac_len10, BASE_FIG);
+ }
+ else {
+ /*
+ * decpt |-----------------------|
+ * len10 |----------| :
+ * : |------------| exp10
+ * : : :
+ * 00 dd dddd dd 00 0000 0000.0
+ * : : : :
+ * : |--| ntz10 = exp10 % BASE_FIG
+ * prec |-----.----.-----| :
+ * : |----.----| exp10 / BASE_FIG
+ * exp |-----.----.-----.----.----|
+ */
+ const size_t exp10 = decpt - len10;
+ const size_t ntz10 = exp10 % BASE_FIG;
+
+ memset(buf + len10, '0', ntz10);
+ buf[len10 + ntz10] = '\0';
+ inum = rb_cstr_to_inum(buf, 10, false);
+
+ prec = roomof(len10 + ntz10, BASE_FIG);
+ exp = prec + exp10 / BASE_FIG;
+ }
+ }
+ else if (decpt == 0) {
+ /*
+ * len10 |------------|
+ * : :
+ * 0.dddd dddd dd 00
+ * : : :
+ * : |--| ntz10 = prec * BASE_FIG - len10
+ * prec |----.----.-----| roomof(len10, BASE_FIG)
+ */
+ prec = roomof(len10, BASE_FIG);
+ const size_t ntz10 = prec * BASE_FIG - len10;
+
+ memset(buf + len10, '0', ntz10);
+ buf[len10 + ntz10] = '\0';
+ inum = rb_cstr_to_inum(buf, 10, false);
+ }
+ else {
+ /*
+ * len10 |---------------|
+ * : :
+ * decpt |-------| |--| ntz10 = prec * BASE_FIG - nlz10 - len10
+ * : : :
+ * 0.0000 00 dd dddd dddd dd 00
+ * : : :
+ * nlz10 |--| : decpt % BASE_FIG
+ * prec |-----.----.----.-----| roomof(decpt + len10, BASE_FIG) - exp
+ * exp |----| decpt / BASE_FIG
+ */
+ decpt = -decpt;
+
+ const size_t nlz10 = decpt % BASE_FIG;
+ exp = decpt / BASE_FIG;
+ prec = roomof(decpt + len10, BASE_FIG) - exp;
+ const size_t ntz10 = prec * BASE_FIG - nlz10 - len10;
+
+ if (nlz10 > 0) {
+ memmove(buf + nlz10, buf, len10);
+ memset(buf, '0', nlz10);
+ }
+ memset(buf + nlz10 + len10, '0', ntz10);
+ buf[nlz10 + len10 + ntz10] = '\0';
+ inum = rb_cstr_to_inum(buf, 10, false);
+
+ exp = -exp;
+ }
+
+ VALUE bd = rb_inum_convert_to_BigDecimal(inum);
+ Real *vp = VpPtr(bd);
+ assert(vp->Prec == prec);
+ vp->exponent = exp;
+
+ if (negative_p) VpSetSign(vp, -1);
+ return bd;
+}
+
+static VALUE
+rb_rational_convert_to_BigDecimal(VALUE val, size_t digs, int raise_exception)
+{
+ assert(RB_TYPE_P(val, T_RATIONAL));
+
+ if (digs == SIZE_MAX) {
+ if (!raise_exception)
+ return Qnil;
+ rb_raise(rb_eArgError,
+ "can't omit precision for a %"PRIsVALUE".",
+ CLASS_OF(val));
+ }
+
+ VALUE num = rb_inum_convert_to_BigDecimal(rb_rational_num(val));
+ VALUE d = BigDecimal_div2(num, rb_rational_den(val), SIZET2NUM(digs));
+ return d;
+}
+
+static VALUE
+rb_cstr_convert_to_BigDecimal(const char *c_str, int raise_exception)
+{
+ NULLABLE_BDVALUE v = CreateFromString(c_str, rb_cBigDecimal, true, raise_exception);
+ if (v.bigdecimal_or_nil == Qnil) return Qnil;
+ return CheckGetValue(bdvalue_nonnullable(v));
+}
+
+static inline VALUE
+rb_str_convert_to_BigDecimal(VALUE val, int raise_exception)
+{
+ const char *c_str = StringValueCStr(val);
+ return rb_cstr_convert_to_BigDecimal(c_str, raise_exception);
+}
+
+static VALUE
+rb_convert_to_BigDecimal(VALUE val, size_t digs, int raise_exception)
+{
+ switch (val) {
+ case Qnil:
+ case Qtrue:
+ case Qfalse:
+ if (raise_exception) {
+ const char *cname = NIL_P(val) ? "nil" :
+ val == Qtrue ? "true" :
+ val == Qfalse ? "false" :
+ NULL;
+ rb_raise(rb_eTypeError,
+ "can't convert %s into BigDecimal", cname);
+ }
+ return Qnil;
+
+ default:
+ break;
+ }
+
+ if (is_kind_of_BigDecimal(val)) {
+ if (digs == SIZE_MAX)
+ return check_exception(val);
+
+ Real *vp = VpPtr(val);
+
+ VALUE copy = BigDecimal_allocate(vp->MaxPrec);
+ Real *vp_copy = VpPtr(copy);
+
+ VpMemCopy(vp_copy, vp);
+
+ RB_GC_GUARD(val);
+
+ /* TODO: rounding */
+ return check_exception(copy);
+ }
+ else if (RB_INTEGER_TYPE_P(val)) {
+ return rb_inum_convert_to_BigDecimal(val);
+ }
+ else if (RB_FLOAT_TYPE_P(val)) {
+ return rb_float_convert_to_BigDecimal(val, digs, raise_exception);
+ }
+ else if (RB_TYPE_P(val, T_RATIONAL)) {
+ return rb_rational_convert_to_BigDecimal(val, digs, raise_exception);
+ }
+ else if (RB_TYPE_P(val, T_COMPLEX)) {
+ VALUE im = rb_complex_imag(val);
+ if (!is_zero(im)) {
+ /* TODO: handle raise_exception */
+ rb_raise(rb_eArgError,
+ "Unable to make a BigDecimal from non-zero imaginary number");
+ }
+ return rb_convert_to_BigDecimal(rb_complex_real(val), digs, raise_exception);
+ }
+ else if (RB_TYPE_P(val, T_STRING)) {
+ return rb_str_convert_to_BigDecimal(val, raise_exception);
+ }
+
+ /* TODO: chheck to_d */
+ /* TODO: chheck to_int */
+
+ VALUE str = rb_check_convert_type(val, T_STRING, "String", "to_str");
+ if (!RB_TYPE_P(str, T_STRING)) {
+ if (raise_exception) {
+ rb_raise(rb_eTypeError,
+ "can't convert %"PRIsVALUE" into BigDecimal", rb_obj_class(val));
+ }
+ return Qnil;
+ }
+ return rb_str_convert_to_BigDecimal(str, raise_exception);
+}
+
+/* call-seq:
+ * BigDecimal(value, exception: true) -> bigdecimal
+ * BigDecimal(value, ndigits, exception: true) -> bigdecimal
+ *
+ * Returns the \BigDecimal converted from +value+
+ * with a precision of +ndigits+ decimal digits.
+ *
+ * When +ndigits+ is less than the number of significant digits
+ * in the value, the result is rounded to that number of digits,
+ * according to the current rounding mode; see BigDecimal.mode.
+ *
+ * When +ndigits+ is 0, the number of digits to correctly represent a float number
+ * is determined automatically.
+ *
+ * Returns +value+ converted to a \BigDecimal, depending on the type of +value+:
+ *
+ * - Integer, Float, Rational, Complex, or BigDecimal: converted directly:
+ *
+ * # Integer, Complex, Float, or BigDecimal value does not require ndigits; ignored if given.
+ * BigDecimal(2) # => 0.2e1
+ * BigDecimal(Complex(2, 0)) # => 0.2e1
+ * BigDecimal(BigDecimal(2)) # => 0.2e1
+ * BigDecimal(2.0) # => 0.2e1
+ * # Rational value requires ndigits.
+ * BigDecimal(Rational(2, 1), 0) # => 0.2e1
+ *
+ * - String: converted by parsing if it contains an integer or floating-point literal;
+ * leading and trailing whitespace is ignored:
+ *
+ * # String does not require ndigits; ignored if given.
+ * BigDecimal('2') # => 0.2e1
+ * BigDecimal('2.0') # => 0.2e1
+ * BigDecimal('0.2e1') # => 0.2e1
+ * BigDecimal(' 2.0 ') # => 0.2e1
+ *
+ * - Other type that responds to method <tt>:to_str</tt>:
+ * first converted to a string, then converted to a \BigDecimal, as above.
+ *
+ * - Other type:
+ *
+ * - Raises an exception if keyword argument +exception+ is +true+.
+ * - Returns +nil+ if keyword argument +exception+ is +false+.
+ *
+ * Raises an exception if +value+ evaluates to a Float
+ * and +digits+ is larger than Float::DIG + 1.
+ *
+ */
+static VALUE
+f_BigDecimal(int argc, VALUE *argv, VALUE self)
+{
+ VALUE val, digs_v, opts = Qnil;
+ argc = rb_scan_args(argc, argv, "11:", &val, &digs_v, &opts);
+ int exception = opts_exception_p(opts);
+
+ size_t digs = SIZE_MAX; /* this means digs is omitted */
+ if (argc > 1) {
+ digs_v = rb_to_int(digs_v);
+ if (FIXNUM_P(digs_v)) {
+ long n = FIX2LONG(digs_v);
+ if (n < 0)
+ goto negative_digs;
+ digs = (size_t)n;
+ }
+ else {
+ if (RBIGNUM_NEGATIVE_P(digs_v)) {
+ negative_digs:
+ if (!exception)
+ return Qnil;
+ rb_raise(rb_eArgError, "negative precision");
+ }
+ digs = NUM2SIZET(digs_v);
+ }
+ }
+
+ return rb_convert_to_BigDecimal(val, digs, exception);
+}
+
+/* call-seq:
+ * BigDecimal.interpret_loosely(string) -> bigdecimal
+ *
+ * Returns the +BigDecimal+ converted loosely from +string+.
+ */
+
+static VALUE
+BigDecimal_s_interpret_loosely(VALUE klass, VALUE str)
+{
+ char const *c_str = StringValueCStr(str);
+ NULLABLE_BDVALUE v = CreateFromString(c_str, klass, false, true);
+ if (v.bigdecimal_or_nil == Qnil)
+ return Qnil;
+ else
+ return CheckGetValue(bdvalue_nonnullable(v));
+}
+
+ /*
+ * call-seq:
+ * BigDecimal.limit(digits)
+ *
+ * Limit the number of significant digits in newly created BigDecimal
+ * numbers to the specified value. Rounding is performed as necessary,
+ * as specified by BigDecimal.mode.
+ *
+ * A limit of 0, the default, means no upper limit.
+ *
+ * The limit specified by this method takes less priority over any limit
+ * specified to instance methods such as ceil, floor, truncate, or round.
+ */
+static VALUE
+BigDecimal_limit(int argc, VALUE *argv, VALUE self)
+{
+ VALUE nFig;
+ VALUE nCur = SIZET2NUM(VpGetPrecLimit());
+
+ if (rb_scan_args(argc, argv, "01", &nFig) == 1) {
+ int nf;
+ if (NIL_P(nFig)) return nCur;
+ nf = NUM2INT(nFig);
+ if (nf < 0) {
+ rb_raise(rb_eArgError, "argument must be positive");
+ }
+ VpSetPrecLimit(nf);
+ }
+ return nCur;
+}
+
+/* Returns the sign of the value.
+ *
+ * Returns a positive value if > 0, a negative value if < 0.
+ * It behaves the same with zeros -
+ * it returns a positive value for a positive zero (BigDecimal('0')) and
+ * a negative value for a negative zero (BigDecimal('-0')).
+ *
+ * The specific value returned indicates the type and sign of the BigDecimal,
+ * as follows:
+ *
+ * BigDecimal::SIGN_NaN:: value is Not a Number
+ * BigDecimal::SIGN_POSITIVE_ZERO:: value is +0
+ * BigDecimal::SIGN_NEGATIVE_ZERO:: value is -0
+ * BigDecimal::SIGN_POSITIVE_INFINITE:: value is +Infinity
+ * BigDecimal::SIGN_NEGATIVE_INFINITE:: value is -Infinity
+ * BigDecimal::SIGN_POSITIVE_FINITE:: value is positive
+ * BigDecimal::SIGN_NEGATIVE_FINITE:: value is negative
+ */
+static VALUE
+BigDecimal_sign(VALUE self)
+{ /* sign */
+ int s = GetSelfVpValue(self)->sign;
+ return INT2FIX(s);
+}
+
+/*
+ * call-seq: BigDecimal.save_exception_mode { ... }
+ *
+ * Execute the provided block, but preserve the exception mode
+ *
+ * BigDecimal.save_exception_mode do
+ * BigDecimal.mode(BigDecimal::EXCEPTION_OVERFLOW, false)
+ * BigDecimal.mode(BigDecimal::EXCEPTION_NaN, false)
+ *
+ * BigDecimal(BigDecimal('Infinity'))
+ * BigDecimal(BigDecimal('-Infinity'))
+ * BigDecimal(BigDecimal('NaN'))
+ * end
+ *
+ * For use with the BigDecimal::EXCEPTION_*
+ *
+ * See BigDecimal.mode
+ */
+static VALUE
+BigDecimal_save_exception_mode(VALUE self)
+{
+ unsigned short const exception_mode = VpGetException();
+ int state;
+ VALUE ret = rb_protect(rb_yield, Qnil, &state);
+ VpSetException(exception_mode);
+ if (state) rb_jump_tag(state);
+ return ret;
+}
+
+/*
+ * call-seq: BigDecimal.save_rounding_mode { ... }
+ *
+ * Execute the provided block, but preserve the rounding mode
+ *
+ * BigDecimal.save_rounding_mode do
+ * BigDecimal.mode(BigDecimal::ROUND_MODE, :up)
+ * puts BigDecimal.mode(BigDecimal::ROUND_MODE)
+ * end
+ *
+ * For use with the BigDecimal::ROUND_*
+ *
+ * See BigDecimal.mode
+ */
+static VALUE
+BigDecimal_save_rounding_mode(VALUE self)
+{
+ unsigned short const round_mode = VpGetRoundMode();
+ int state;
+ VALUE ret = rb_protect(rb_yield, Qnil, &state);
+ VpSetRoundMode(round_mode);
+ if (state) rb_jump_tag(state);
+ return ret;
+}
+
+/*
+ * call-seq: BigDecimal.save_limit { ... }
+ *
+ * Execute the provided block, but preserve the precision limit
+ *
+ * BigDecimal.limit(100)
+ * puts BigDecimal.limit
+ * BigDecimal.save_limit do
+ * BigDecimal.limit(200)
+ * puts BigDecimal.limit
+ * end
+ * puts BigDecimal.limit
+ *
+ */
+static VALUE
+BigDecimal_save_limit(VALUE self)
+{
+ size_t const limit = VpGetPrecLimit();
+ int state;
+ VALUE ret = rb_protect(rb_yield, Qnil, &state);
+ VpSetPrecLimit(limit);
+ if (state) rb_jump_tag(state);
+ return ret;
+}
+
+static VALUE BIGDECIMAL_NAN = Qnil;
+
+static VALUE
+BigDecimal_nan(void)
+{
+ return BIGDECIMAL_NAN;
+}
+
+static VALUE BIGDECIMAL_POSITIVE_INFINITY = Qnil;
+
+static VALUE
+BigDecimal_positive_infinity(void)
+{
+ return BIGDECIMAL_POSITIVE_INFINITY;
+}
+
+static VALUE BIGDECIMAL_NEGATIVE_INFINITY = Qnil;
+
+static VALUE
+BigDecimal_negative_infinity(void)
+{
+ return BIGDECIMAL_NEGATIVE_INFINITY;
+}
+
+static VALUE BIGDECIMAL_POSITIVE_ZERO = Qnil;
+
+static VALUE
+BigDecimal_positive_zero(void)
+{
+ return BIGDECIMAL_POSITIVE_ZERO;
+}
+
+static VALUE BIGDECIMAL_NEGATIVE_ZERO = Qnil;
+
+static VALUE
+BigDecimal_negative_zero(void)
+{
+ return BIGDECIMAL_NEGATIVE_ZERO;
+}
+
+static inline VALUE
+BigDecimal_literal(const char *str)
+{
+ VALUE arg = rb_str_new_cstr(str);
+ VALUE val = f_BigDecimal(1, &arg, rb_cBigDecimal);
+ rb_gc_register_mark_object(val);
+ return val;
+}
+
+#define BIGDECIMAL_LITERAL(var, val) (BIGDECIMAL_ ## var = BigDecimal_literal(#val))
+
+#ifdef BIGDECIMAL_USE_VP_TEST_METHODS
+VALUE
+BigDecimal_vpdivd_generic(VALUE self, VALUE r, VALUE cprec, void (*vpdivd_func)(Real*, Real*, Real*, Real*)) {
+ BDVALUE a, b, c, d;
+ size_t cn = NUM2INT(cprec);
+ a = GetBDValueMust(self);
+ b = GetBDValueMust(r);
+ c = NewZeroWrap(1, cn * BASE_FIG);
+ d = NewZeroWrap(1, VPDIVD_REM_PREC(a.real, b.real, c.real) * BASE_FIG);
+ vpdivd_func(c.real, d.real, a.real, b.real);
+ RB_GC_GUARD(a.bigdecimal);
+ RB_GC_GUARD(b.bigdecimal);
+ return rb_assoc_new(c.bigdecimal, d.bigdecimal);
+}
+
+void
+VpDivdNormal(Real *c, Real *r, Real *a, Real *b) {
+ VpDivd(c, r, a, b);
+}
+
+VALUE
+BigDecimal_vpdivd(VALUE self, VALUE r, VALUE cprec) {
+ return BigDecimal_vpdivd_generic(self, r, cprec, VpDivdNormal);
+}
+
+VALUE
+BigDecimal_vpdivd_newton(VALUE self, VALUE r, VALUE cprec) {
+ return BigDecimal_vpdivd_generic(self, r, cprec, VpDivdNewton);
+}
+
+VALUE
+BigDecimal_newton_raphson_inverse(VALUE self, VALUE prec) {
+ return newton_raphson_inverse(self, NUM2SIZET(prec));
+}
+
+VALUE
+BigDecimal_vpmult(VALUE self, VALUE v) {
+ BDVALUE a,b,c;
+ a = GetBDValueMust(self);
+ b = GetBDValueMust(v);
+ c = NewZeroWrap(1, VPMULT_RESULT_PREC(a.real, b.real) * BASE_FIG);
+ VpMult(c.real, a.real, b.real);
+ RB_GC_GUARD(a.bigdecimal);
+ RB_GC_GUARD(b.bigdecimal);
+ return c.bigdecimal;
+}
+
+VALUE
+BigDecimal_nttmult(VALUE self, VALUE v) {
+ BDVALUE a,b,c;
+ a = GetBDValueMust(self);
+ b = GetBDValueMust(v);
+ c = NewZeroWrap(1, VPMULT_RESULT_PREC(a.real, b.real) * BASE_FIG);
+ ntt_multiply(a.real->Prec, b.real->Prec, a.real->frac, b.real->frac, c.real->frac);
+ VpSetSign(c.real, a.real->sign * b.real->sign);
+ c.real->exponent = a.real->exponent + b.real->exponent;
+ c.real->Prec = a.real->Prec + b.real->Prec;
+ VpNmlz(c.real);
+ RB_GC_GUARD(a.bigdecimal);
+ RB_GC_GUARD(b.bigdecimal);
+ return c.bigdecimal;
+}
+
+#endif /* BIGDECIMAL_USE_VP_TEST_METHODS */
+
+/* Document-class: BigDecimal
+ * BigDecimal provides arbitrary-precision floating point decimal arithmetic.
+ *
+ * == Introduction
+ *
+ * Ruby provides built-in support for arbitrary precision integer arithmetic.
+ *
+ * For example:
+ *
+ * 42**13 #=> 1265437718438866624512
+ *
+ * BigDecimal provides similar support for very large or very accurate floating
+ * point numbers.
+ *
+ * Decimal arithmetic is also useful for general calculation, because it
+ * provides the correct answers people expect--whereas normal binary floating
+ * point arithmetic often introduces subtle errors because of the conversion
+ * between base 10 and base 2.
+ *
+ * For example, try:
+ *
+ * sum = 0
+ * 10_000.times do
+ * sum = sum + 0.0001
+ * end
+ * print sum #=> 0.9999999999999062
+ *
+ * and contrast with the output from:
+ *
+ * require 'bigdecimal'
+ *
+ * sum = BigDecimal("0")
+ * 10_000.times do
+ * sum = sum + BigDecimal("0.0001")
+ * end
+ * print sum #=> 0.1E1
+ *
+ * Similarly:
+ *
+ * (BigDecimal("1.2") - BigDecimal("1.0")) == BigDecimal("0.2") #=> true
+ *
+ * (1.2 - 1.0) == 0.2 #=> false
+ *
+ * == A Note About Precision
+ *
+ * For a calculation using a \BigDecimal and another +value+,
+ * the precision of the result depends on the type of +value+:
+ *
+ * - If +value+ is a \Float,
+ * the precision is Float::DIG + 1.
+ * - If +value+ is a \Rational, the precision is larger than Float::DIG + 1.
+ * - If +value+ is a \BigDecimal, the precision is +value+'s precision in the
+ * internal representation, which is platform-dependent.
+ * - If +value+ is other object, the precision is determined by the result of +BigDecimal(value)+.
+ *
+ * == Special features of accurate decimal arithmetic
+ *
+ * Because BigDecimal is more accurate than normal binary floating point
+ * arithmetic, it requires some special values.
+ *
+ * === Infinity
+ *
+ * BigDecimal sometimes needs to return infinity, for example if you divide
+ * a value by zero.
+ *
+ * BigDecimal("1.0") / BigDecimal("0.0") #=> Infinity
+ * BigDecimal("-1.0") / BigDecimal("0.0") #=> -Infinity
+ *
+ * You can represent infinite numbers to BigDecimal using the strings
+ * <code>'Infinity'</code>, <code>'+Infinity'</code> and
+ * <code>'-Infinity'</code> (case-sensitive)
+ *
+ * === Not a Number
+ *
+ * When a computation results in an undefined value, the special value +NaN+
+ * (for 'not a number') is returned.
+ *
+ * Example:
+ *
+ * BigDecimal("0.0") / BigDecimal("0.0") #=> NaN
+ *
+ * You can also create undefined values.
+ *
+ * NaN is never considered to be the same as any other value, even NaN itself:
+ *
+ * n = BigDecimal('NaN')
+ * n == 0.0 #=> false
+ * n == n #=> false
+ *
+ * === Positive and negative zero
+ *
+ * If a computation results in a value which is too small to be represented as
+ * a BigDecimal within the currently specified limits of precision, zero must
+ * be returned.
+ *
+ * If the value which is too small to be represented is negative, a BigDecimal
+ * value of negative zero is returned.
+ *
+ * BigDecimal("1.0") / BigDecimal("-Infinity") #=> -0.0
+ *
+ * If the value is positive, a value of positive zero is returned.
+ *
+ * BigDecimal("1.0") / BigDecimal("Infinity") #=> 0.0
+ *
+ * (See BigDecimal.mode for how to specify limits of precision.)
+ *
+ * Note that +-0.0+ and +0.0+ are considered to be the same for the purposes of
+ * comparison.
+ *
+ * Note also that in mathematics, there is no particular concept of negative
+ * or positive zero; true mathematical zero has no sign.
+ *
+ * == bigdecimal/util
+ *
+ * When you require +bigdecimal/util+, the #to_d method will be
+ * available on BigDecimal and the native Integer, Float, Rational,
+ * String, Complex, and NilClass classes:
+ *
+ * require 'bigdecimal/util'
+ *
+ * 42.to_d # => 0.42e2
+ * 0.5.to_d # => 0.5e0
+ * (2/3r).to_d(3) # => 0.667e0
+ * "0.5".to_d # => 0.5e0
+ * Complex(0.1234567, 0).to_d(4) # => 0.1235e0
+ * nil.to_d # => 0.0
+ *
+ * == Methods for Working with \JSON
+ *
+ * - {::json_create}[https://docs.ruby-lang.org/en/master/BigDecimal.html#method-c-json_create]:
+ * Returns a new \BigDecimal object constructed from the given object.
+ * - {#as_json}[https://docs.ruby-lang.org/en/master/BigDecimal.html#method-i-as_json]:
+ * Returns a 2-element hash representing +self+.
+ * - {#to_json}[https://docs.ruby-lang.org/en/master/BigDecimal.html#method-i-to_json]:
+ * Returns a \JSON string representing +self+.
+ *
+ * These methods are provided by the {JSON gem}[https://github.com/flori/json]. To make these methods available:
+ *
+ * require 'json/add/bigdecimal'
+ *
+ * * == License
+ *
+ * Copyright (C) 2002 by Shigeo Kobayashi <shigeo@tinyforest.gr.jp>.
+ *
+ * BigDecimal is released under the Ruby and 2-clause BSD licenses.
+ * See LICENSE.txt for details.
+ *
+ * Maintained by mrkn <mrkn@mrkn.jp> and ruby-core members.
+ *
+ * Documented by zzak <zachary@zacharyscott.net>, mathew <meta@pobox.com>, and
+ * many other contributors.
+ */
+void
+Init_bigdecimal(void)
+{
+#ifdef HAVE_RB_EXT_RACTOR_SAFE
+ rb_ext_ractor_safe(true);
+#endif
+
+ id_BigDecimal_exception_mode = rb_intern_const("BigDecimal.exception_mode");
+ id_BigDecimal_rounding_mode = rb_intern_const("BigDecimal.rounding_mode");
+ id_BigDecimal_precision_limit = rb_intern_const("BigDecimal.precision_limit");
+
+ /* Initialize VP routines */
+ VpInit(0UL);
+
+ /* Class and method registration */
+ rb_cBigDecimal = rb_define_class("BigDecimal", rb_cNumeric);
+
+ /* Global function */
+ rb_define_global_function("BigDecimal", f_BigDecimal, -1);
+
+ /* Class methods */
+ rb_undef_alloc_func(rb_cBigDecimal);
+ rb_undef_method(CLASS_OF(rb_cBigDecimal), "new");
+ rb_define_singleton_method(rb_cBigDecimal, "interpret_loosely", BigDecimal_s_interpret_loosely, 1);
+ rb_define_singleton_method(rb_cBigDecimal, "mode", BigDecimal_mode, -1);
+ rb_define_singleton_method(rb_cBigDecimal, "limit", BigDecimal_limit, -1);
+ rb_define_singleton_method(rb_cBigDecimal, "double_fig", BigDecimal_double_fig, 0);
+ rb_define_singleton_method(rb_cBigDecimal, "_load", BigDecimal_load, 1);
+
+ rb_define_singleton_method(rb_cBigDecimal, "save_exception_mode", BigDecimal_save_exception_mode, 0);
+ rb_define_singleton_method(rb_cBigDecimal, "save_rounding_mode", BigDecimal_save_rounding_mode, 0);
+ rb_define_singleton_method(rb_cBigDecimal, "save_limit", BigDecimal_save_limit, 0);
+
+ /* Constants definition */
+
+ /*
+ * The version of bigdecimal library
+ */
+ rb_define_const(rb_cBigDecimal, "VERSION", rb_str_new2(BIGDECIMAL_VERSION));
+
+ /*
+ * Base value used in internal calculations. On a 32 bit system, BASE
+ * is 10000, indicating that calculation is done in groups of 4 digits.
+ * (If it were larger, BASE**2 wouldn't fit in 32 bits, so you couldn't
+ * guarantee that two groups could always be multiplied together without
+ * overflow.)
+ */
+ rb_define_const(rb_cBigDecimal, "BASE", INT2FIX((SIGNED_VALUE)BASE));
+
+ /* Exceptions */
+
+ /*
+ * 0xff: Determines whether overflow, underflow or zero divide result in
+ * an exception being thrown. See BigDecimal.mode.
+ */
+ rb_define_const(rb_cBigDecimal, "EXCEPTION_ALL", INT2FIX(VP_EXCEPTION_ALL));
+
+ /*
+ * 0x02: Determines what happens when the result of a computation is not a
+ * number (NaN). See BigDecimal.mode.
+ */
+ rb_define_const(rb_cBigDecimal, "EXCEPTION_NaN", INT2FIX(VP_EXCEPTION_NaN));
+
+ /*
+ * 0x01: Determines what happens when the result of a computation is
+ * infinity. See BigDecimal.mode.
+ */
+ rb_define_const(rb_cBigDecimal, "EXCEPTION_INFINITY", INT2FIX(VP_EXCEPTION_INFINITY));
+
+ /*
+ * 0x04: Determines what happens when the result of a computation is an
+ * underflow (a result too small to be represented). See BigDecimal.mode.
+ */
+ rb_define_const(rb_cBigDecimal, "EXCEPTION_UNDERFLOW", INT2FIX(VP_EXCEPTION_UNDERFLOW));
+
+ /*
+ * 0x01: Determines what happens when the result of a computation is an
+ * overflow (a result too large to be represented). See BigDecimal.mode.
+ */
+ rb_define_const(rb_cBigDecimal, "EXCEPTION_OVERFLOW", INT2FIX(VP_EXCEPTION_OVERFLOW));
+
+ /*
+ * 0x10: Determines what happens when a division by zero is performed.
+ * See BigDecimal.mode.
+ */
+ rb_define_const(rb_cBigDecimal, "EXCEPTION_ZERODIVIDE", INT2FIX(VP_EXCEPTION_ZERODIVIDE));
+
+ /*
+ * 0x100: Determines what happens when a result must be rounded in order to
+ * fit in the appropriate number of significant digits. See
+ * BigDecimal.mode.
+ */
+ rb_define_const(rb_cBigDecimal, "ROUND_MODE", INT2FIX(VP_ROUND_MODE));
+
+ /* 1: Indicates that values should be rounded away from zero. See
+ * BigDecimal.mode.
+ */
+ rb_define_const(rb_cBigDecimal, "ROUND_UP", INT2FIX(VP_ROUND_UP));
+
+ /* 2: Indicates that values should be rounded towards zero. See
+ * BigDecimal.mode.
+ */
+ rb_define_const(rb_cBigDecimal, "ROUND_DOWN", INT2FIX(VP_ROUND_DOWN));
+
+ /* 3: Indicates that digits >= 5 should be rounded up, others rounded down.
+ * See BigDecimal.mode. */
+ rb_define_const(rb_cBigDecimal, "ROUND_HALF_UP", INT2FIX(VP_ROUND_HALF_UP));
+
+ /* 4: Indicates that digits >= 6 should be rounded up, others rounded down.
+ * See BigDecimal.mode.
+ */
+ rb_define_const(rb_cBigDecimal, "ROUND_HALF_DOWN", INT2FIX(VP_ROUND_HALF_DOWN));
+ /* 5: Round towards +Infinity. See BigDecimal.mode. */
+ rb_define_const(rb_cBigDecimal, "ROUND_CEILING", INT2FIX(VP_ROUND_CEIL));
+
+ /* 6: Round towards -Infinity. See BigDecimal.mode. */
+ rb_define_const(rb_cBigDecimal, "ROUND_FLOOR", INT2FIX(VP_ROUND_FLOOR));
+
+ /* 7: Round towards the even neighbor. See BigDecimal.mode. */
+ rb_define_const(rb_cBigDecimal, "ROUND_HALF_EVEN", INT2FIX(VP_ROUND_HALF_EVEN));
+
+ /* 0: Indicates that a value is not a number. See BigDecimal.sign. */
+ rb_define_const(rb_cBigDecimal, "SIGN_NaN", INT2FIX(VP_SIGN_NaN));
+
+ /* 1: Indicates that a value is +0. See BigDecimal.sign. */
+ rb_define_const(rb_cBigDecimal, "SIGN_POSITIVE_ZERO", INT2FIX(VP_SIGN_POSITIVE_ZERO));
+
+ /* -1: Indicates that a value is -0. See BigDecimal.sign. */
+ rb_define_const(rb_cBigDecimal, "SIGN_NEGATIVE_ZERO", INT2FIX(VP_SIGN_NEGATIVE_ZERO));
+
+ /* 2: Indicates that a value is positive and finite. See BigDecimal.sign. */
+ rb_define_const(rb_cBigDecimal, "SIGN_POSITIVE_FINITE", INT2FIX(VP_SIGN_POSITIVE_FINITE));
+
+ /* -2: Indicates that a value is negative and finite. See BigDecimal.sign. */
+ rb_define_const(rb_cBigDecimal, "SIGN_NEGATIVE_FINITE", INT2FIX(VP_SIGN_NEGATIVE_FINITE));
+
+ /* 3: Indicates that a value is positive and infinite. See BigDecimal.sign. */
+ rb_define_const(rb_cBigDecimal, "SIGN_POSITIVE_INFINITE", INT2FIX(VP_SIGN_POSITIVE_INFINITE));
+
+ /* -3: Indicates that a value is negative and infinite. See BigDecimal.sign. */
+ rb_define_const(rb_cBigDecimal, "SIGN_NEGATIVE_INFINITE", INT2FIX(VP_SIGN_NEGATIVE_INFINITE));
+
+ /* Positive zero value. */
+ BIGDECIMAL_LITERAL(POSITIVE_ZERO, +0);
+
+ /* Negative zero value. */
+ BIGDECIMAL_LITERAL(NEGATIVE_ZERO, -0);
+
+ /* Positive infinity[rdoc-ref:BigDecimal@Infinity] value. */
+ rb_define_const(rb_cBigDecimal, "INFINITY", BIGDECIMAL_LITERAL(POSITIVE_INFINITY, +Infinity));
+
+ /* Negative infinity value. */
+ BIGDECIMAL_LITERAL(NEGATIVE_INFINITY, -Infinity);
+
+ /* '{Not a Number}[rdoc-ref:BigDecimal@Not+a+Number]' value. */
+ rb_define_const(rb_cBigDecimal, "NAN", BIGDECIMAL_LITERAL(NAN, NaN));
+
+ /* instance methods */
+ rb_define_method(rb_cBigDecimal, "precision", BigDecimal_precision, 0);
+ rb_define_method(rb_cBigDecimal, "scale", BigDecimal_scale, 0);
+ rb_define_method(rb_cBigDecimal, "precision_scale", BigDecimal_precision_scale, 0);
+ rb_define_method(rb_cBigDecimal, "n_significant_digits", BigDecimal_n_significant_digits, 0);
+
+ rb_define_method(rb_cBigDecimal, "add", BigDecimal_add2, 2);
+ rb_define_method(rb_cBigDecimal, "sub", BigDecimal_sub2, 2);
+ rb_define_method(rb_cBigDecimal, "mult", BigDecimal_mult2, 2);
+ rb_define_method(rb_cBigDecimal, "div", BigDecimal_div3, -1);
+ rb_define_method(rb_cBigDecimal, "hash", BigDecimal_hash, 0);
+ rb_define_method(rb_cBigDecimal, "to_s", BigDecimal_to_s, -1);
+ rb_define_method(rb_cBigDecimal, "to_i", BigDecimal_to_i, 0);
+ rb_define_method(rb_cBigDecimal, "to_int", BigDecimal_to_i, 0);
+ rb_define_method(rb_cBigDecimal, "to_r", BigDecimal_to_r, 0);
+ rb_define_method(rb_cBigDecimal, "split", BigDecimal_split, 0);
+ rb_define_method(rb_cBigDecimal, "+", BigDecimal_add, 1);
+ rb_define_method(rb_cBigDecimal, "-", BigDecimal_sub, 1);
+ rb_define_method(rb_cBigDecimal, "+@", BigDecimal_uplus, 0);
+ rb_define_method(rb_cBigDecimal, "-@", BigDecimal_neg, 0);
+ rb_define_method(rb_cBigDecimal, "*", BigDecimal_mult, 1);
+ rb_define_method(rb_cBigDecimal, "/", BigDecimal_div, 1);
+ rb_define_method(rb_cBigDecimal, "quo", BigDecimal_quo, -1);
+ rb_define_method(rb_cBigDecimal, "%", BigDecimal_mod, 1);
+ rb_define_method(rb_cBigDecimal, "modulo", BigDecimal_mod, 1);
+ rb_define_method(rb_cBigDecimal, "remainder", BigDecimal_remainder, 1);
+ rb_define_method(rb_cBigDecimal, "divmod", BigDecimal_divmod, 1);
+ rb_define_method(rb_cBigDecimal, "clone", BigDecimal_clone, 0);
+ rb_define_method(rb_cBigDecimal, "dup", BigDecimal_clone, 0);
+ rb_define_method(rb_cBigDecimal, "to_f", BigDecimal_to_f, 0);
+ rb_define_method(rb_cBigDecimal, "abs", BigDecimal_abs, 0);
+ rb_define_method(rb_cBigDecimal, "fix", BigDecimal_fix, 0);
+ rb_define_method(rb_cBigDecimal, "round", BigDecimal_round, -1);
+ rb_define_method(rb_cBigDecimal, "frac", BigDecimal_frac, 0);
+ rb_define_method(rb_cBigDecimal, "floor", BigDecimal_floor, -1);
+ rb_define_method(rb_cBigDecimal, "ceil", BigDecimal_ceil, -1);
+ rb_define_method(rb_cBigDecimal, "<=>", BigDecimal_comp, 1);
+ rb_define_method(rb_cBigDecimal, "==", BigDecimal_eq, 1);
+ rb_define_method(rb_cBigDecimal, "===", BigDecimal_eq, 1);
+ rb_define_method(rb_cBigDecimal, "eql?", BigDecimal_eq, 1);
+ rb_define_method(rb_cBigDecimal, "<", BigDecimal_lt, 1);
+ rb_define_method(rb_cBigDecimal, "<=", BigDecimal_le, 1);
+ rb_define_method(rb_cBigDecimal, ">", BigDecimal_gt, 1);
+ rb_define_method(rb_cBigDecimal, ">=", BigDecimal_ge, 1);
+ rb_define_method(rb_cBigDecimal, "zero?", BigDecimal_zero, 0);
+ rb_define_method(rb_cBigDecimal, "nonzero?", BigDecimal_nonzero, 0);
+ rb_define_method(rb_cBigDecimal, "coerce", BigDecimal_coerce, 1);
+ rb_define_method(rb_cBigDecimal, "inspect", BigDecimal_inspect, 0);
+ rb_define_method(rb_cBigDecimal, "exponent", BigDecimal_exponent, 0);
+ rb_define_method(rb_cBigDecimal, "sign", BigDecimal_sign, 0);
+ rb_define_method(rb_cBigDecimal, "nan?", BigDecimal_IsNaN, 0);
+ rb_define_method(rb_cBigDecimal, "infinite?", BigDecimal_IsInfinite, 0);
+ rb_define_method(rb_cBigDecimal, "finite?", BigDecimal_IsFinite, 0);
+ rb_define_method(rb_cBigDecimal, "truncate", BigDecimal_truncate, -1);
+ rb_define_method(rb_cBigDecimal, "_decimal_shift", BigDecimal_decimal_shift, 1);
+ rb_define_method(rb_cBigDecimal, "_dump", BigDecimal_dump, -1);
+
+#ifdef BIGDECIMAL_USE_VP_TEST_METHODS
+ rb_define_method(rb_cBigDecimal, "vpdivd", BigDecimal_vpdivd, 2);
+ rb_define_method(rb_cBigDecimal, "vpdivd_newton", BigDecimal_vpdivd_newton, 2);
+ rb_define_method(rb_cBigDecimal, "newton_raphson_inverse", BigDecimal_newton_raphson_inverse, 1);
+ rb_define_method(rb_cBigDecimal, "vpmult", BigDecimal_vpmult, 1);
+ rb_define_method(rb_cBigDecimal, "nttmult", BigDecimal_nttmult, 1);
+#endif /* BIGDECIMAL_USE_VP_TEST_METHODS */
+
+#define ROUNDING_MODE(i, name, value) \
+ id_##name = rb_intern_const(#name); \
+ rbd_rounding_modes[i].id = id_##name; \
+ rbd_rounding_modes[i].mode = value;
+
+ ROUNDING_MODE(0, up, RBD_ROUND_UP);
+ ROUNDING_MODE(1, down, RBD_ROUND_DOWN);
+ ROUNDING_MODE(2, half_up, RBD_ROUND_HALF_UP);
+ ROUNDING_MODE(3, half_down, RBD_ROUND_HALF_DOWN);
+ ROUNDING_MODE(4, ceil, RBD_ROUND_CEIL);
+ ROUNDING_MODE(5, floor, RBD_ROUND_FLOOR);
+ ROUNDING_MODE(6, half_even, RBD_ROUND_HALF_EVEN);
+
+ ROUNDING_MODE(7, default, RBD_ROUND_DEFAULT);
+ ROUNDING_MODE(8, truncate, RBD_ROUND_TRUNCATE);
+ ROUNDING_MODE(9, banker, RBD_ROUND_BANKER);
+ ROUNDING_MODE(10, ceiling, RBD_ROUND_CEILING);
+
+#undef ROUNDING_MODE
+
+ id_to_r = rb_intern_const("to_r");
+ id_eq = rb_intern_const("==");
+ id_half = rb_intern_const("half");
+
+ (void)VPrint; /* suppress unused warning */
+}
+
+/*
+ *
+ * ============================================================================
+ *
+ * vp_ routines begin from here.
+ *
+ * ============================================================================
+ *
+ */
+#ifdef BIGDECIMAL_DEBUG
+static int gfDebug = 1; /* Debug switch */
+#endif /* BIGDECIMAL_DEBUG */
+
+static VALUE VpConstOne; /* constant 1.0 */
+
+enum op_sw {
+ OP_SW_ADD = 1, /* + */
+ OP_SW_SUB, /* - */
+ OP_SW_MULT, /* * */
+ OP_SW_DIV /* / */
+};
+
+static int VpIsDefOP(Real *c, Real *a, Real *b, enum op_sw sw);
+static DECDIG VpAddAbs(Real *a,Real *b,Real *c);
+static DECDIG VpSubAbs(Real *a,Real *b,Real *c);
+static size_t VpSetPTR(Real *a, Real *b, Real *c, size_t *a_pos, size_t *b_pos, size_t *c_pos, DECDIG *av, DECDIG *bv);
+static void VpFormatSt(char *psz, size_t fFmt);
+static int VpRdup(Real *m, size_t ind_m);
+
+#ifdef BIGDECIMAL_DEBUG
+# ifdef HAVE_RB_EXT_RACTOR_SAFE
+# error Need to make rewiting gnAlloc atomic
+# endif
+static int gnAlloc = 0; /* Memory allocation counter */
+#endif /* BIGDECIMAL_DEBUG */
+
+/*
+ * EXCEPTION Handling.
+ */
+
+#define bigdecimal_set_thread_local_exception_mode(mode) \
+ rb_thread_local_aset( \
+ rb_thread_current(), \
+ id_BigDecimal_exception_mode, \
+ INT2FIX((int)(mode)) \
+ )
+
+static unsigned short
+VpGetException (void)
+{
+ VALUE const vmode = rb_thread_local_aref(
+ rb_thread_current(),
+ id_BigDecimal_exception_mode
+ );
+
+ if (NIL_P(vmode)) {
+ bigdecimal_set_thread_local_exception_mode(BIGDECIMAL_EXCEPTION_MODE_DEFAULT);
+ return BIGDECIMAL_EXCEPTION_MODE_DEFAULT;
+ }
+
+ return NUM2USHORT(vmode);
+}
+
+static void
+VpSetException(unsigned short f)
+{
+ bigdecimal_set_thread_local_exception_mode(f);
+}
+
+static void
+VpCheckException(Real *p, bool always)
+{
+ if (VpIsNaN(p)) {
+ VpException(VP_EXCEPTION_NaN, "Computation results in 'NaN' (Not a Number)", always);
+ }
+ else if (VpIsPosInf(p)) {
+ VpException(VP_EXCEPTION_INFINITY, "Computation results in 'Infinity'", always);
+ }
+ else if (VpIsNegInf(p)) {
+ VpException(VP_EXCEPTION_INFINITY, "Computation results in '-Infinity'", always);
+ }
+}
+
+static VALUE
+CheckGetValue(BDVALUE v)
+{
+ VpCheckException(v.real, false);
+ return v.bigdecimal;
+}
+
+/*
+ * Precision limit.
+ */
+
+#define bigdecimal_set_thread_local_precision_limit(limit) \
+ rb_thread_local_aset( \
+ rb_thread_current(), \
+ id_BigDecimal_precision_limit, \
+ SIZET2NUM(limit) \
+ )
+#define BIGDECIMAL_PRECISION_LIMIT_DEFAULT ((size_t)0)
+
+/* These 2 functions added at v1.1.7 */
+VP_EXPORT size_t
+VpGetPrecLimit(void)
+{
+ VALUE const vlimit = rb_thread_local_aref(
+ rb_thread_current(),
+ id_BigDecimal_precision_limit
+ );
+
+ if (NIL_P(vlimit)) {
+ bigdecimal_set_thread_local_precision_limit(BIGDECIMAL_PRECISION_LIMIT_DEFAULT);
+ return BIGDECIMAL_PRECISION_LIMIT_DEFAULT;
+ }
+
+ return NUM2SIZET(vlimit);
+}
+
+VP_EXPORT void
+VpSetPrecLimit(size_t n)
+{
+ bigdecimal_set_thread_local_precision_limit(n);
+}
+
+/*
+ * Rounding mode.
+ */
+
+#define bigdecimal_set_thread_local_rounding_mode(mode) \
+ rb_thread_local_aset( \
+ rb_thread_current(), \
+ id_BigDecimal_rounding_mode, \
+ INT2FIX((int)(mode)) \
+ )
+
+VP_EXPORT unsigned short
+VpGetRoundMode(void)
+{
+ VALUE const vmode = rb_thread_local_aref(
+ rb_thread_current(),
+ id_BigDecimal_rounding_mode
+ );
+
+ if (NIL_P(vmode)) {
+ bigdecimal_set_thread_local_rounding_mode(BIGDECIMAL_ROUNDING_MODE_DEFAULT);
+ return BIGDECIMAL_ROUNDING_MODE_DEFAULT;
+ }
+
+ return NUM2USHORT(vmode);
+}
+
+VP_EXPORT int
+VpIsRoundMode(unsigned short n)
+{
+ switch (n) {
+ case VP_ROUND_UP:
+ case VP_ROUND_DOWN:
+ case VP_ROUND_HALF_UP:
+ case VP_ROUND_HALF_DOWN:
+ case VP_ROUND_CEIL:
+ case VP_ROUND_FLOOR:
+ case VP_ROUND_HALF_EVEN:
+ return 1;
+
+ default:
+ return 0;
+ }
+}
+
+VP_EXPORT unsigned short
+VpSetRoundMode(unsigned short n)
+{
+ if (VpIsRoundMode(n)) {
+ bigdecimal_set_thread_local_rounding_mode(n);
+ return n;
+ }
+
+ return VpGetRoundMode();
+}
+
+/*
+ * 0.0 & 1.0 generator
+ * These gZero_..... and gOne_..... can be any name
+ * referenced from nowhere except Zero() and One().
+ * gZero_..... and gOne_..... must have global scope
+ * (to let the compiler know they may be changed in outside
+ * (... but not actually..)).
+ */
+volatile const double gOne_ABCED9B4_CE73__00400511F31D = 1.0;
+
+static double
+One(void)
+{
+ return gOne_ABCED9B4_CE73__00400511F31D;
+}
+
+/*
+ ----------------------------------------------------------------
+ Value of sign in Real structure is reserved for future use.
+ short sign;
+ ==0 : NaN
+ 1 : Positive zero
+ -1 : Negative zero
+ 2 : Positive number
+ -2 : Negative number
+ 3 : Positive infinite number
+ -3 : Negative infinite number
+ ----------------------------------------------------------------
+*/
+
+VP_EXPORT double
+VpGetDoubleNaN(void) /* Returns the value of NaN */
+{
+ return nan("");
+}
+
+VP_EXPORT double
+VpGetDoublePosInf(void) /* Returns the value of +Infinity */
+{
+ return HUGE_VAL;
+}
+
+VP_EXPORT double
+VpGetDoubleNegInf(void) /* Returns the value of -Infinity */
+{
+ return -HUGE_VAL;
+}
+
+VP_EXPORT double
+VpGetDoubleNegZero(void) /* Returns the value of -0 */
+{
+ static double nzero = 1000.0;
+ if (nzero != 0.0) nzero = (One()/VpGetDoubleNegInf());
+ return nzero;
+}
+
+VP_EXPORT int
+VpException(unsigned short f, const char *str,int always)
+{
+ unsigned short const exception_mode = VpGetException();
+
+ if (f == VP_EXCEPTION_OP) always = 1;
+
+ if (always || (exception_mode & f)) {
+ switch(f) {
+ /* case VP_EXCEPTION_OVERFLOW: */
+ case VP_EXCEPTION_ZERODIVIDE:
+ case VP_EXCEPTION_INFINITY:
+ case VP_EXCEPTION_NaN:
+ case VP_EXCEPTION_UNDERFLOW:
+ case VP_EXCEPTION_OP:
+ rb_raise(rb_eFloatDomainError, "%s", str);
+ break;
+ default:
+ rb_fatal("%s", str);
+ }
+ }
+ return 0; /* 0 Means VpException() raised no exception */
+}
+
+/* Throw exception or returns 0,when resulting c is Inf or NaN */
+/* sw=1:+ 2:- 3:* 4:/ */
+static int
+VpIsDefOP(Real *c, Real *a, Real *b, enum op_sw sw)
+{
+ if (VpIsNaN(a) || VpIsNaN(b)) {
+ /* at least a or b is NaN */
+ VpSetNaN(c);
+ goto NaN;
+ }
+
+ if (VpIsInf(a)) {
+ if (VpIsInf(b)) {
+ switch(sw) {
+ case OP_SW_ADD: /* + */
+ if (VpGetSign(a) == VpGetSign(b)) {
+ VpSetInf(c, VpGetSign(a));
+ goto Inf;
+ }
+ else {
+ VpSetNaN(c);
+ goto NaN;
+ }
+ case OP_SW_SUB: /* - */
+ if (VpGetSign(a) != VpGetSign(b)) {
+ VpSetInf(c, VpGetSign(a));
+ goto Inf;
+ }
+ else {
+ VpSetNaN(c);
+ goto NaN;
+ }
+ case OP_SW_MULT: /* * */
+ VpSetInf(c, VpGetSign(a)*VpGetSign(b));
+ goto Inf;
+ case OP_SW_DIV: /* / */
+ VpSetNaN(c);
+ goto NaN;
+ }
+ VpSetNaN(c);
+ goto NaN;
+ }
+ /* Inf op Finite */
+ switch(sw) {
+ case OP_SW_ADD: /* + */
+ case OP_SW_SUB: /* - */
+ VpSetInf(c, VpGetSign(a));
+ break;
+ case OP_SW_MULT: /* * */
+ if (VpIsZero(b)) {
+ VpSetNaN(c);
+ goto NaN;
+ }
+ VpSetInf(c, VpGetSign(a)*VpGetSign(b));
+ break;
+ case OP_SW_DIV: /* / */
+ VpSetInf(c, VpGetSign(a)*VpGetSign(b));
+ }
+ goto Inf;
+ }
+
+ if (VpIsInf(b)) {
+ switch(sw) {
+ case OP_SW_ADD: /* + */
+ VpSetInf(c, VpGetSign(b));
+ break;
+ case OP_SW_SUB: /* - */
+ VpSetInf(c, -VpGetSign(b));
+ break;
+ case OP_SW_MULT: /* * */
+ if (VpIsZero(a)) {
+ VpSetNaN(c);
+ goto NaN;
+ }
+ VpSetInf(c, VpGetSign(a)*VpGetSign(b));
+ break;
+ case OP_SW_DIV: /* / */
+ VpSetZero(c, VpGetSign(a)*VpGetSign(b));
+ }
+ goto Inf;
+ }
+ return 1; /* Results OK */
+
+Inf:
+ if (VpIsPosInf(c)) {
+ return VpException(VP_EXCEPTION_INFINITY, "Computation results to 'Infinity'", 0);
+ }
+ else {
+ return VpException(VP_EXCEPTION_INFINITY, "Computation results to '-Infinity'", 0);
+ }
+
+NaN:
+ return VpException(VP_EXCEPTION_NaN, "Computation results to 'NaN'", 0);
+}
+
+/*
+ ----------------------------------------------------------------
+*/
+
+/*
+ * returns number of chars needed to represent vp in specified format.
+ */
+VP_EXPORT size_t
+VpNumOfChars(Real *vp,const char *pszFmt)
+{
+ SIGNED_VALUE ex;
+ size_t nc;
+
+ if (vp == NULL) return BASE_FIG*2+6;
+ if (!VpIsDef(vp)) return 32; /* not sure,may be OK */
+
+ switch(*pszFmt) {
+ case 'F':
+ nc = BASE_FIG*(vp->Prec + 1)+2;
+ ex = vp->exponent;
+ if (ex < 0) {
+ nc += BASE_FIG*(size_t)(-ex);
+ }
+ else {
+ if ((size_t)ex > vp->Prec) {
+ nc += BASE_FIG*((size_t)ex - vp->Prec);
+ }
+ }
+ break;
+ case 'E':
+ /* fall through */
+ default:
+ nc = BASE_FIG * vp->Prec + 25; /* "-0."(3) + digits_chars + "e-"(2) + 64bit_exponent_chars(19) + null(1) */
+ }
+ return nc;
+}
+
+/*
+ * Initializer for Vp routines and constants used.
+ * [Input]
+ * BaseVal: Base value(assigned to BASE) for Vp calculation.
+ * It must be the form BaseVal=10**n.(n=1,2,3,...)
+ * If Base <= 0L,then the BASE will be calculated so
+ * that BASE is as large as possible satisfying the
+ * relation MaxVal <= BASE*(BASE+1). Where the value
+ * MaxVal is the largest value which can be represented
+ * by one DECDIG word in the computer used.
+ *
+ * [Returns]
+ * BIGDECIMAL_DOUBLE_FIGURES ... OK
+ */
+VP_EXPORT size_t
+VpInit(DECDIG BaseVal)
+{
+ /* Setup +/- Inf NaN -0 */
+ VpGetDoubleNegZero();
+
+ /* Const 1.0 */
+ rb_global_variable(&VpConstOne);
+ VpConstOne = NewZeroWrap(1, 1).bigdecimal;
+ VpSetOne(VpPtr(VpConstOne));
+
+#ifdef BIGDECIMAL_DEBUG
+ gnAlloc = 0;
+#endif /* BIGDECIMAL_DEBUG */
+
+ return BIGDECIMAL_DOUBLE_FIGURES;
+}
+
+VP_EXPORT Real *
+VpOne(void)
+{
+ return VpPtr(VpConstOne);
+}
+
+/* If exponent overflows,then raise exception or returns 0 */
+static int
+AddExponent(Real *a, SIGNED_VALUE n)
+{
+ SIGNED_VALUE e = a->exponent;
+ SIGNED_VALUE m = e+n;
+ if (e > 0 && n > 0) {
+ if (n > VP_EXPONENT_MAX - e) goto overflow;
+ } else if (e < 0 && n < 0) {
+ if (n < VP_EXPONENT_MIN - e) goto underflow;
+ } else if (m > VP_EXPONENT_MAX) {
+ goto overflow;
+ } else if (m < VP_EXPONENT_MIN) {
+ goto underflow;
+ }
+ a->exponent = m;
+ return 1;
+
+/* Overflow/Underflow ==> Raise exception or returns 0 */
+underflow:
+ VpSetZero(a, VpGetSign(a));
+ return VpException(VP_EXCEPTION_UNDERFLOW, "Exponent underflow", 0);
+
+overflow:
+ VpSetInf(a, VpGetSign(a));
+ return VpException(VP_EXCEPTION_OVERFLOW, "Exponent overflow", 0);
+}
+
+NULLABLE_BDVALUE
+bigdecimal_parse_special_string(const char *str)
+{
+ static const struct {
+ const char *str;
+ size_t len;
+ int sign;
+ } table[] = {
+ { SZ_INF, sizeof(SZ_INF) - 1, VP_SIGN_POSITIVE_INFINITE },
+ { SZ_PINF, sizeof(SZ_PINF) - 1, VP_SIGN_POSITIVE_INFINITE },
+ { SZ_NINF, sizeof(SZ_NINF) - 1, VP_SIGN_NEGATIVE_INFINITE },
+ { SZ_NaN, sizeof(SZ_NaN) - 1, VP_SIGN_NaN }
+ };
+ static const size_t table_length = sizeof(table) / sizeof(table[0]);
+ size_t i;
+
+ for (i = 0; i < table_length; ++i) {
+ const char *p;
+ if (strncmp(str, table[i].str, table[i].len) != 0) {
+ continue;
+ }
+
+ p = str + table[i].len;
+ while (*p && ISSPACE(*p)) ++p;
+ if (*p == '\0') {
+ VALUE obj = BigDecimal_allocate(1);
+ Real *vp = VpPtr(obj);
+ switch (table[i].sign) {
+ default:
+ UNREACHABLE;
+ return (NULLABLE_BDVALUE) { Qnil, NULL };
+ case VP_SIGN_POSITIVE_INFINITE:
+ VpSetPosInf(vp);
+ break;
+ case VP_SIGN_NEGATIVE_INFINITE:
+ VpSetNegInf(vp);
+ break;
+ case VP_SIGN_NaN:
+ VpSetNaN(vp);
+ break;
+ }
+ return (NULLABLE_BDVALUE) { obj, vp };
+ }
+ }
+
+ return (NULLABLE_BDVALUE) { Qnil, NULL };
+}
+
+/*
+ * Allocates variable.
+ * [Input]
+ * szVal ... The value assigned(char).
+ *
+ * [Returns]
+ * NULLABLE_BDVALUE to the newly allocated variable.
+ * Null is returned if memory allocation failed, or any error occured.
+ */
+VP_EXPORT NULLABLE_BDVALUE
+VpAlloc(const char *szVal, int strict_p, int exc)
+{
+ const char *orig_szVal = szVal;
+ size_t i, j, ni, ipf, nf, ipe, ne, exp_seen, nalloc;
+ char v, *psz;
+ int sign=1;
+ VALUE buf;
+
+ /* Skipping leading spaces */
+ while (ISSPACE(*szVal)) szVal++;
+
+ /* Check on Inf & NaN */
+ NULLABLE_BDVALUE special_bd = bigdecimal_parse_special_string(szVal);
+ if (special_bd.real_or_null != NULL) {
+ return special_bd;
+ }
+
+ /* Skip leading `#`.
+ * It used to be a mark to indicate that an extra MaxPrec should be allocated,
+ * but now it has no effect.
+ */
+ if (*szVal == '#') ++szVal;
+
+ /* Scanning digits */
+
+ /* A buffer for keeping scanned digits */
+ buf = rb_str_tmp_new(strlen(szVal) + 1);
+ psz = RSTRING_PTR(buf);
+
+ /* cursor: i for psz, and j for szVal */
+ i = j = 0;
+
+ /* Scanning: sign part */
+ v = psz[i] = szVal[j];
+ if ((v == '-') || (v == '+')) {
+ sign = -(v == '-');
+ ++i;
+ ++j;
+ }
+
+ /* Scanning: integer part */
+ ni = 0; /* number of digits in the integer part */
+ while ((v = psz[i] = szVal[j]) != '\0') {
+ if (!strict_p && ISSPACE(v)) {
+ v = psz[i] = '\0';
+ break;
+ }
+ if (v == '_') {
+ if (ni > 0) {
+ v = szVal[j+1];
+ if (v == '\0' || ISSPACE(v) || ISDIGIT(v)) {
+ ++j;
+ continue;
+ }
+ if (!strict_p) {
+ v = psz[i] = '\0';
+ break;
+ }
+ }
+ goto invalid_value;
+ }
+ if (!ISDIGIT(v)) {
+ break;
+ }
+ ++ni;
+ ++i;
+ ++j;
+ }
+
+ /* Scanning: fractional part */
+ nf = 0; /* number of digits in the fractional part */
+ ne = 0; /* number of digits in the exponential part */
+ ipf = 0; /* index of the beginning of the fractional part */
+ ipe = 0; /* index of the beginning of the exponential part */
+ exp_seen = 0;
+
+ if (v != '\0') {
+ /* Scanning fractional part */
+ if ((psz[i] = szVal[j]) == '.') {
+ ++i;
+ ++j;
+ ipf = i;
+ while ((v = psz[i] = szVal[j]) != '\0') {
+ if (!strict_p && ISSPACE(v)) {
+ v = psz[i] = '\0';
+ break;
+ }
+ if (v == '_') {
+ if (nf > 0 && ISDIGIT(szVal[j+1])) {
+ ++j;
+ continue;
+ }
+ if (!strict_p) {
+ v = psz[i] = '\0';
+ break;
+ }
+ goto invalid_value;
+ }
+ if (!ISDIGIT(v)) break;
+ ++i;
+ ++j;
+ ++nf;
+ }
+ }
+
+ /* Scanning exponential part */
+ if (v != '\0') {
+ switch ((psz[i] = szVal[j])) {
+ case '\0':
+ break;
+ case 'e': case 'E':
+ case 'd': case 'D':
+ exp_seen = 1;
+ ++i;
+ ++j;
+ ipe = i;
+ v = psz[i] = szVal[j];
+ if ((v == '-') || (v == '+')) {
+ ++i;
+ ++j;
+ }
+ while ((v = psz[i] = szVal[j]) != '\0') {
+ if (!strict_p && ISSPACE(v)) {
+ v = psz[i] = '\0';
+ break;
+ }
+ if (v == '_') {
+ if (ne > 0 && ISDIGIT(szVal[j+1])) {
+ ++j;
+ continue;
+ }
+ if (!strict_p) {
+ v = psz[i] = '\0';
+ if (ne == 0) {
+ exp_seen = 0;
+ }
+ break;
+ }
+ goto invalid_value;
+ }
+ if (!ISDIGIT(v)) break;
+ ++i;
+ ++j;
+ ++ne;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+ if (v != '\0') {
+ /* Scanning trailing spaces */
+ while (ISSPACE(szVal[j])) ++j;
+
+ /* Invalid character */
+ if (szVal[j] && strict_p) {
+ goto invalid_value;
+ }
+ }
+ }
+
+ psz[i] = '\0';
+
+ if (strict_p && ((ni == 0 && nf == 0) || (exp_seen && ne == 0))) {
+ VALUE str;
+ invalid_value:
+ if (!strict_p) {
+ BDVALUE res = rbd_allocate_struct_zero_wrap(1, 1);
+ return (NULLABLE_BDVALUE) { res.bigdecimal, res.real };
+ }
+ if (!exc) {
+ return (NULLABLE_BDVALUE) { Qnil, NULL };
+ }
+ str = rb_str_new2(orig_szVal);
+ rb_raise(rb_eArgError, "invalid value for BigDecimal(): \"%"PRIsVALUE"\"", str);
+ }
+
+ nalloc = (ni + nf + BASE_FIG - 1) / BASE_FIG + 1; /* set effective allocation */
+ /* units for szVal[] */
+ VALUE obj = BigDecimal_allocate(nalloc);
+ Real *vp = VpPtr(obj);
+ VpSetZero(vp, sign);
+ VpCtoV(vp, psz, ni, psz + ipf, nf, psz + ipe, ne);
+ rb_str_resize(buf, 0);
+ return (NULLABLE_BDVALUE) { obj, vp };
+}
+
+/*
+ * Assignment(c=a).
+ * [Input]
+ * a ... RHSV
+ * isw ... switch for assignment.
+ * c = a when isw > 0
+ * c = -a when isw < 0
+ * if c->MaxPrec < a->Prec,then round operation
+ * will be performed.
+ * [Output]
+ * c ... LHSV
+ */
+VP_EXPORT size_t
+VpAsgn(Real *c, Real *a, int isw)
+{
+ size_t n;
+ if (VpIsNaN(a)) {
+ VpSetNaN(c);
+ return 0;
+ }
+ if (VpIsInf(a)) {
+ VpSetInf(c, isw * VpGetSign(a));
+ return 0;
+ }
+
+ /* check if the RHS is zero */
+ if (!VpIsZero(a)) {
+ c->exponent = a->exponent; /* store exponent */
+ VpSetSign(c, isw * VpGetSign(a)); /* set sign */
+ n = (a->Prec < c->MaxPrec) ? (a->Prec) : (c->MaxPrec);
+ c->Prec = n;
+ memcpy(c->frac, a->frac, n * sizeof(DECDIG));
+ /* Needs round ? */
+ if (isw != 10 && isw != -10) {
+ /* Not in ActiveRound */
+ if(c->Prec < a->Prec) {
+ VpInternalRound(c, n, (n>0) ? a->frac[n-1] : 0, a->frac[n]);
+ }
+ else {
+ VpLimitRound(c,0);
+ }
+ }
+ }
+ else {
+ /* The value of 'a' is zero. */
+ VpSetZero(c, isw * VpGetSign(a));
+ return 1;
+ }
+ return c->Prec * BASE_FIG;
+}
+
+/*
+ * c = a + b when operation = 1 or 2
+ * c = a - b when operation = -1 or -2.
+ * Returns number of significant digits of c
+ */
+VP_EXPORT size_t
+VpAddSub(Real *c, Real *a, Real *b, int operation)
+{
+ short sw, isw, sign;
+ Real *a_ptr, *b_ptr;
+ size_t n, na, nb, i;
+ DECDIG mrv;
+
+ if (!VpIsDefOP(c, a, b, (operation > 0) ? OP_SW_ADD : OP_SW_SUB)) return 0; /* No significant digits */
+
+ /* check if a or b is zero */
+ if (VpIsZero(a)) {
+ /* a is zero,then assign b to c */
+ if (!VpIsZero(b)) {
+ VpAsgn(c, b, operation);
+ }
+ else {
+ /* Both a and b are zero. */
+ if (VpGetSign(a) < 0 && operation * VpGetSign(b) < 0) {
+ /* -0 -0 */
+ VpSetZero(c, -1);
+ }
+ else {
+ VpSetZero(c, 1);
+ }
+ return 1; /* 0: 1 significant digits */
+ }
+ return c->Prec * BASE_FIG;
+ }
+ if (VpIsZero(b)) {
+ /* b is zero,then assign a to c. */
+ VpAsgn(c, a, 1);
+ return c->Prec*BASE_FIG;
+ }
+
+ if (operation < 0) sw = -1;
+ else sw = 1;
+
+ /* compare absolute value. As a result,|a_ptr|>=|b_ptr| */
+ if (a->exponent > b->exponent) {
+ a_ptr = a;
+ b_ptr = b;
+ } /* |a|>|b| */
+ else if (a->exponent < b->exponent) {
+ a_ptr = b;
+ b_ptr = a;
+ } /* |a|<|b| */
+ else {
+ /* Exponent part of a and b is the same,then compare fraction */
+ /* part */
+ na = a->Prec;
+ nb = b->Prec;
+ n = Min(na, nb);
+ for (i=0; i < n; ++i) {
+ if (a->frac[i] > b->frac[i]) {
+ a_ptr = a;
+ b_ptr = b;
+ goto end_if;
+ }
+ else if (a->frac[i] < b->frac[i]) {
+ a_ptr = b;
+ b_ptr = a;
+ goto end_if;
+ }
+ }
+ if (na > nb) {
+ a_ptr = a;
+ b_ptr = b;
+ goto end_if;
+ }
+ else if (na < nb) {
+ a_ptr = b;
+ b_ptr = a;
+ goto end_if;
+ }
+ /* |a| == |b| */
+ if (VpGetSign(a) + sw *VpGetSign(b) == 0) {
+ VpSetZero(c, 1); /* abs(a)=abs(b) and operation = '-' */
+ return c->Prec * BASE_FIG;
+ }
+ a_ptr = a;
+ b_ptr = b;
+ }
+
+end_if:
+ isw = VpGetSign(a) + sw *VpGetSign(b);
+ /*
+ * isw = 0 ...( 1)+(-1),( 1)-( 1),(-1)+(1),(-1)-(-1)
+ * = 2 ...( 1)+( 1),( 1)-(-1)
+ * =-2 ...(-1)+(-1),(-1)-( 1)
+ * If isw==0, then c =(Sign a_ptr)(|a_ptr|-|b_ptr|)
+ * else c =(Sign ofisw)(|a_ptr|+|b_ptr|)
+ */
+ if (isw) { /* addition */
+ VpSetSign(c, 1);
+ mrv = VpAddAbs(a_ptr, b_ptr, c);
+ sign = isw / 2;
+ }
+ else { /* subtraction */
+ VpSetSign(c, 1);
+ mrv = VpSubAbs(a_ptr, b_ptr, c);
+ sign = a_ptr == a ? VpGetSign(a) : VpGetSign(a_ptr) * sw;
+ }
+ if (VpIsInf(c)) {
+ VpSetInf(c, sign);
+ }
+ else {
+ VpSetSign(c, sign);
+ VpInternalRound(c, 0, (c->Prec > 0) ? c->frac[c->Prec-1] : 0, mrv);
+ }
+
+ return c->Prec * BASE_FIG;
+}
+
+/*
+ * Addition of two values with variable precision
+ * a and b assuming abs(a)>abs(b).
+ * c = abs(a) + abs(b) ; where |a|>=|b|
+ */
+static DECDIG
+VpAddAbs(Real *a, Real *b, Real *c)
+{
+ size_t word_shift;
+ size_t ap;
+ size_t bp;
+ size_t cp;
+ size_t a_pos;
+ size_t b_pos, b_pos_with_word_shift;
+ size_t c_pos;
+ DECDIG av, bv, carry, mrv;
+
+ word_shift = VpSetPTR(a, b, c, &ap, &bp, &cp, &av, &bv);
+ a_pos = ap;
+ b_pos = bp;
+ c_pos = cp;
+
+ if (word_shift == (size_t)-1L) return 0; /* Overflow */
+ if (b_pos == (size_t)-1L) goto Assign_a;
+
+ mrv = av + bv; /* Most right val. Used for round. */
+
+ /* Just assign the last few digits of b to c because a has no */
+ /* corresponding digits to be added. */
+ if (b_pos > 0) {
+ while (b_pos > 0 && b_pos + word_shift > a_pos) {
+ c->frac[--c_pos] = b->frac[--b_pos];
+ }
+ }
+ if (b_pos == 0 && word_shift > a_pos) {
+ while (word_shift-- > a_pos) {
+ c->frac[--c_pos] = 0;
+ }
+ }
+
+ /* Just assign the last few digits of a to c because b has no */
+ /* corresponding digits to be added. */
+ b_pos_with_word_shift = b_pos + word_shift;
+ while (a_pos > b_pos_with_word_shift) {
+ c->frac[--c_pos] = a->frac[--a_pos];
+ }
+ carry = 0; /* set first carry be zero */
+
+ /* Now perform addition until every digits of b will be */
+ /* exhausted. */
+ while (b_pos > 0) {
+ c->frac[--c_pos] = a->frac[--a_pos] + b->frac[--b_pos] + carry;
+ if (c->frac[c_pos] >= BASE) {
+ c->frac[c_pos] -= BASE;
+ carry = 1;
+ }
+ else {
+ carry = 0;
+ }
+ }
+
+ /* Just assign the first few digits of a with considering */
+ /* the carry obtained so far because b has been exhausted. */
+ while (a_pos > 0) {
+ c->frac[--c_pos] = a->frac[--a_pos] + carry;
+ if (c->frac[c_pos] >= BASE) {
+ c->frac[c_pos] -= BASE;
+ carry = 1;
+ }
+ else {
+ carry = 0;
+ }
+ }
+ if (c_pos) c->frac[c_pos - 1] += carry;
+ goto Exit;
+
+Assign_a:
+ VpAsgn(c, a, 1);
+ mrv = 0;
+
+Exit:
+
+ return mrv;
+}
+
+/*
+ * c = abs(a) - abs(b)
+ */
+static DECDIG
+VpSubAbs(Real *a, Real *b, Real *c)
+{
+ size_t word_shift;
+ size_t ap;
+ size_t bp;
+ size_t cp;
+ size_t a_pos;
+ size_t b_pos, b_pos_with_word_shift;
+ size_t c_pos;
+ DECDIG av, bv, borrow, mrv;
+
+ word_shift = VpSetPTR(a, b, c, &ap, &bp, &cp, &av, &bv);
+ a_pos = ap;
+ b_pos = bp;
+ c_pos = cp;
+ if (word_shift == (size_t)-1L) return 0; /* Overflow */
+ if (b_pos == (size_t)-1L) goto Assign_a;
+
+ if (av >= bv) {
+ mrv = av - bv;
+ borrow = 0;
+ }
+ else {
+ mrv = 0;
+ borrow = 1;
+ }
+
+ /* Just assign the values which are the BASE subtracted by */
+ /* each of the last few digits of the b because the a has no */
+ /* corresponding digits to be subtracted. */
+ if (b_pos + word_shift > a_pos) {
+ while (b_pos > 0 && b_pos + word_shift > a_pos) {
+ c->frac[--c_pos] = BASE - b->frac[--b_pos] - borrow;
+ borrow = 1;
+ }
+ if (b_pos == 0) {
+ while (word_shift > a_pos) {
+ --word_shift;
+ c->frac[--c_pos] = BASE - borrow;
+ borrow = 1;
+ }
+ }
+ }
+ /* Just assign the last few digits of a to c because b has no */
+ /* corresponding digits to subtract. */
+
+ b_pos_with_word_shift = b_pos + word_shift;
+ while (a_pos > b_pos_with_word_shift) {
+ c->frac[--c_pos] = a->frac[--a_pos];
+ }
+
+ /* Now perform subtraction until every digits of b will be */
+ /* exhausted. */
+ while (b_pos > 0) {
+ --c_pos;
+ if (a->frac[--a_pos] < b->frac[--b_pos] + borrow) {
+ c->frac[c_pos] = BASE + a->frac[a_pos] - b->frac[b_pos] - borrow;
+ borrow = 1;
+ }
+ else {
+ c->frac[c_pos] = a->frac[a_pos] - b->frac[b_pos] - borrow;
+ borrow = 0;
+ }
+ }
+
+ /* Just assign the first few digits of a with considering */
+ /* the borrow obtained so far because b has been exhausted. */
+ while (a_pos > 0) {
+ --c_pos;
+ if (a->frac[--a_pos] < borrow) {
+ c->frac[c_pos] = BASE + a->frac[a_pos] - borrow;
+ borrow = 1;
+ }
+ else {
+ c->frac[c_pos] = a->frac[a_pos] - borrow;
+ borrow = 0;
+ }
+ }
+ if (c_pos) c->frac[c_pos - 1] -= borrow;
+ goto Exit;
+
+Assign_a:
+ VpAsgn(c, a, 1);
+ mrv = 0;
+
+Exit:
+ return mrv;
+}
+
+/*
+ * Note: If(av+bv)>= HALF_BASE,then 1 will be added to the least significant
+ * digit of c(In case of addition).
+ * ------------------------- figure of output -----------------------------------
+ * a = xxxxxxxxxxx
+ * b = xxxxxxxxxx
+ * c =xxxxxxxxxxxxxxx
+ * word_shift = | |
+ * right_word = | | (Total digits in RHSV)
+ * left_word = | | (Total digits in LHSV)
+ * a_pos = |
+ * b_pos = |
+ * c_pos = |
+ */
+static size_t
+VpSetPTR(Real *a, Real *b, Real *c, size_t *a_pos, size_t *b_pos, size_t *c_pos, DECDIG *av, DECDIG *bv)
+{
+ size_t left_word, right_word, word_shift;
+
+ size_t const round_limit = (VpGetPrecLimit() + BASE_FIG - 1) / BASE_FIG;
+
+ assert(a->exponent >= b->exponent);
+
+ c->frac[0] = 0;
+ *av = *bv = 0;
+
+ word_shift = (a->exponent - b->exponent);
+ left_word = b->Prec + word_shift;
+ right_word = Max(a->Prec, left_word);
+ left_word = c->MaxPrec - 1; /* -1 ... prepare for round up */
+
+ /*
+ * check if 'round' is needed.
+ */
+ if (right_word > left_word) { /* round ? */
+ /*---------------------------------
+ * Actual size of a = xxxxxxAxx
+ * Actual size of b = xxxBxxxxx
+ * Max. size of c = xxxxxx
+ * Round off = |-----|
+ * c_pos = |
+ * right_word = |
+ * a_pos = |
+ */
+ *c_pos = right_word = left_word + 1; /* Set resulting precision */
+ /* be equal to that of c */
+ if (a->Prec >= c->MaxPrec) {
+ /*
+ * a = xxxxxxAxxx
+ * c = xxxxxx
+ * a_pos = |
+ */
+ *a_pos = left_word;
+ if (*a_pos <= round_limit) {
+ *av = a->frac[*a_pos]; /* av is 'A' shown in above. */
+ }
+ }
+ else {
+ /*
+ * a = xxxxxxx
+ * c = xxxxxxxxxx
+ * a_pos = |
+ */
+ *a_pos = a->Prec;
+ }
+ if (b->Prec + word_shift >= c->MaxPrec) {
+ /*
+ * a = xxxxxxxxx
+ * b = xxxxxxxBxxx
+ * c = xxxxxxxxxxx
+ * b_pos = |
+ */
+ if (c->MaxPrec >= word_shift + 1) {
+ *b_pos = c->MaxPrec - word_shift - 1;
+ if (*b_pos + word_shift <= round_limit) {
+ *bv = b->frac[*b_pos];
+ }
+ }
+ else {
+ *b_pos = -1L;
+ }
+ }
+ else {
+ /*
+ * a = xxxxxxxxxxxxxxxx
+ * b = xxxxxx
+ * c = xxxxxxxxxxxxx
+ * b_pos = |
+ */
+ *b_pos = b->Prec;
+ }
+ }
+ else { /* The MaxPrec of c - 1 > The Prec of a + b */
+ /*
+ * a = xxxxxxx
+ * b = xxxxxx
+ * c = xxxxxxxxxxx
+ * c_pos = |
+ */
+ *b_pos = b->Prec;
+ *a_pos = a->Prec;
+ *c_pos = right_word + 1;
+ }
+ c->Prec = *c_pos;
+ c->exponent = a->exponent;
+ if (!AddExponent(c, 1)) return (size_t)-1L;
+ return word_shift;
+}
+
+/*
+ * Return number of significant digits
+ * c = a * b , Where a = a0a1a2 ... an
+ * b = b0b1b2 ... bm
+ * c = c0c1c2 ... cl
+ * a0 a1 ... an * bm
+ * a0 a1 ... an * bm-1
+ * . . .
+ * . . .
+ * a0 a1 .... an * b0
+ * +_____________________________
+ * c0 c1 c2 ...... cl
+ */
+VP_EXPORT size_t
+VpMult(Real *c, Real *a, Real *b)
+{
+ ssize_t a_batch_max, b_batch_max;
+ DECDIG_DBL batch[VPMULT_BATCH_SIZE * 2 - 1];
+
+ if (!VpIsDefOP(c, a, b, OP_SW_MULT)) return 0; /* No significant digit */
+
+ if (VpIsZero(a) || VpIsZero(b)) {
+ /* at least a or b is zero */
+ VpSetZero(c, VpGetSign(a) * VpGetSign(b));
+ return 1; /* 0: 1 significant digit */
+ }
+
+ if (VpIsOne(a)) {
+ VpAsgn(c, b, 10 * VpGetSign(a));
+ goto Exit;
+ }
+ if (VpIsOne(b)) {
+ VpAsgn(c, a, 10 * VpGetSign(b));
+ goto Exit;
+ }
+ if (b->Prec > a->Prec) {
+ /* Adjust so that digits(a)>digits(b) */
+ Real *w = a;
+ a = b;
+ b = w;
+ }
+
+ /* set LHSV c info */
+
+ c->exponent = a->exponent; /* set exponent */
+ VpSetSign(c, VpGetSign(a) * VpGetSign(b)); /* set sign */
+ if (!AddExponent(c, b->exponent)) return 0;
+
+ if (b->Prec >= NTT_MULTIPLICATION_THRESHOLD) {
+ ntt_multiply(a->Prec, b->Prec, a->frac, b->frac, c->frac);
+ c->Prec = a->Prec + b->Prec;
+ goto Cleanup;
+ }
+
+ c->Prec = a->Prec + b->Prec; /* set precision */
+ memset(c->frac, 0, c->Prec * sizeof(DECDIG)); /* Initialize c */
+
+ // Process VPMULT_BATCH_SIZE decdigits at a time to reduce the number of carry operations.
+ a_batch_max = (a->Prec - 1) / VPMULT_BATCH_SIZE;
+ b_batch_max = (b->Prec - 1) / VPMULT_BATCH_SIZE;
+ for (ssize_t ibatch = a_batch_max; ibatch >= 0; ibatch--) {
+ int isize = ibatch == a_batch_max ? (a->Prec - 1) % VPMULT_BATCH_SIZE + 1 : VPMULT_BATCH_SIZE;
+ for (ssize_t jbatch = b_batch_max; jbatch >= 0; jbatch--) {
+ int jsize = jbatch == b_batch_max ? (b->Prec - 1) % VPMULT_BATCH_SIZE + 1 : VPMULT_BATCH_SIZE;
+ memset(batch, 0, (isize + jsize - 1) * sizeof(DECDIG_DBL));
+
+ // Perform multiplication without carry calculation.
+ // BASE * BASE * VPMULT_BATCH_SIZE < 2**64 should be satisfied so that
+ // DECDIG_DBL can hold the intermediate sum without overflow.
+ for (int i = 0; i < isize; i++) {
+ for (int j = 0; j < jsize; j++) {
+ batch[i + j] += (DECDIG_DBL)a->frac[ibatch * VPMULT_BATCH_SIZE + i] * b->frac[jbatch * VPMULT_BATCH_SIZE + j];
+ }
+ }
+
+ // Add the batch result to c with carry calculation.
+ DECDIG_DBL carry = 0;
+ for (int k = isize + jsize - 2; k >= 0; k--) {
+ size_t l = (ibatch + jbatch) * VPMULT_BATCH_SIZE + k + 1;
+ DECDIG_DBL s = c->frac[l] + batch[k] + carry;
+ c->frac[l] = (DECDIG)(s % BASE);
+ carry = (DECDIG_DBL)(s / BASE);
+ }
+
+ // Adding carry may exceed BASE, but it won't cause overflow of DECDIG.
+ // Exceeded value will be resolved in the carry operation of next (ibatch + jbatch - 1) batch.
+ // WARNING: This safety strongly relies on the current nested loop execution order.
+ c->frac[(ibatch + jbatch) * VPMULT_BATCH_SIZE] += (DECDIG)carry;
+ }
+ }
+
+Cleanup:
+ VpNmlz(c);
+
+Exit:
+ return c->Prec*BASE_FIG;
+}
+
+/*
+ * c = a / b, remainder = r
+ * XXXX_YYYY_ZZZZ / 0001 = XXXX_YYYY_ZZZZ
+ * XXXX_YYYY_ZZZZ / 1111 = 000X_000Y_000Z
+ * 00XX_XXYY_YYZZ / 1000 = 0000_0XXX_XYYY
+ * 0001_0000_0000 / 9999 = 0000_0001_0001
+ */
+VP_EXPORT size_t
+VpDivd(Real *c, Real *r, Real *a, Real *b)
+{
+ size_t word_a, word_b, word_c, word_r;
+ size_t i, n, ind_a, ind_b, ind_c, ind_r;
+ size_t nLoop;
+ DECDIG_DBL q, b1, b1p1, b1b2, b1b2p1, r1r2;
+ DECDIG borrow1, borrow2;
+ DECDIG_DBL qb;
+
+ VpSetNaN(r);
+ if (!VpIsDefOP(c, a, b, OP_SW_DIV)) goto Exit;
+ if (VpIsZero(a) && VpIsZero(b)) {
+ VpSetNaN(c);
+ return VpException(VP_EXCEPTION_NaN, "Computation results to 'NaN'", 0);
+ }
+ if (VpIsZero(b)) {
+ VpSetInf(c, VpGetSign(a) * VpGetSign(b));
+ return VpException(VP_EXCEPTION_ZERODIVIDE, "Divide by zero", 0);
+ }
+ if (VpIsZero(a)) {
+ /* numerator a is zero */
+ VpSetZero(c, VpGetSign(a) * VpGetSign(b));
+ VpSetZero(r, VpGetSign(a) * VpGetSign(b));
+ goto Exit;
+ }
+
+ word_a = a->Prec;
+ word_b = b->Prec;
+ word_c = c->MaxPrec;
+ word_r = r->MaxPrec;
+
+ if (word_a > word_r || word_b + word_c - 2 >= word_r) goto space_error;
+
+ if (word_c >= NEWTON_RAPHSON_DIVISION_THRESHOLD && word_b >= NEWTON_RAPHSON_DIVISION_THRESHOLD) {
+ VpDivdNewton(c, r, a, b);
+ goto Exit;
+ }
+
+ for (i = 0; i < word_a; ++i) r->frac[i] = a->frac[i];
+ for (i = word_a; i < word_r; ++i) r->frac[i] = 0;
+ for (i = 0; i < word_c; ++i) c->frac[i] = 0;
+
+ /* initial procedure */
+ b1 = b1p1 = b->frac[0];
+ if (b->Prec <= 1) {
+ b1b2p1 = b1b2 = b1p1 * BASE;
+ }
+ else {
+ b1p1 = b1 + 1;
+ b1b2p1 = b1b2 = b1 * BASE + b->frac[1];
+ if (b->Prec > 2) ++b1b2p1;
+ }
+
+ /* */
+ /* loop start */
+ nLoop = Min(word_c, word_r);
+ ind_c = 0;
+ while (ind_c < nLoop) {
+ if (r->frac[ind_c] == 0) {
+ ++ind_c;
+ continue;
+ }
+ r1r2 = (DECDIG_DBL)r->frac[ind_c] * BASE + (ind_c + 1 < word_r ? r->frac[ind_c + 1] : 0);
+ if (r1r2 == b1b2) {
+ /* The first two word digits is the same */
+ ind_b = 2;
+ ind_a = ind_c + 2;
+ while (ind_b < word_b) {
+ if (r->frac[ind_a] < b->frac[ind_b]) goto div_b1p1;
+ if (r->frac[ind_a] > b->frac[ind_b]) break;
+ ++ind_a;
+ ++ind_b;
+ }
+ /* The first few word digits of r and b is the same and */
+ /* the first different word digit of w is greater than that */
+ /* of b, so quotient is 1. */
+ q = 1;
+ ++c->frac[ind_c];
+ ind_r = b->Prec + ind_c - 1;
+ goto sub_mult;
+ }
+ /* The first two word digits is not the same, */
+ /* then compare magnitude, and divide actually. */
+ if (r1r2 >= b1b2p1) {
+ q = r1r2 / b1b2p1; /* q == (DECDIG)q */
+ c->frac[ind_c] += (DECDIG)q;
+ ind_r = b->Prec + ind_c - 1;
+ goto sub_mult;
+ }
+
+div_b1p1:
+ if (ind_c + 1 >= word_c) goto out_side;
+ q = r1r2 / b1p1; /* q == (DECDIG)q */
+ c->frac[ind_c + 1] += (DECDIG)q;
+ ind_r = b->Prec + ind_c;
+
+sub_mult:
+ borrow1 = borrow2 = 0;
+ ind_b = word_b - 1;
+ if (ind_r >= word_r) goto space_error;
+ n = ind_b;
+ for (i = 0; i <= n; ++i) {
+ /* now, perform r = r - q * b */
+ qb = q * b->frac[ind_b];
+ if (qb < BASE) borrow1 = 0;
+ else {
+ borrow1 = (DECDIG)(qb / BASE);
+ qb -= (DECDIG_DBL)borrow1 * BASE; /* get qb < BASE */
+ }
+ if(r->frac[ind_r] < qb) {
+ r->frac[ind_r] += (DECDIG)(BASE - qb);
+ borrow2 = borrow2 + borrow1 + 1;
+ }
+ else {
+ r->frac[ind_r] -= (DECDIG)qb;
+ borrow2 += borrow1;
+ }
+ if (borrow2) {
+ if(r->frac[ind_r - 1] < borrow2) {
+ r->frac[ind_r - 1] += (BASE - borrow2);
+ borrow2 = 1;
+ }
+ else {
+ r->frac[ind_r - 1] -= borrow2;
+ borrow2 = 0;
+ }
+ }
+ --ind_r;
+ --ind_b;
+ }
+
+ r->frac[ind_r] -= borrow2;
+ }
+ /* End of operation, now final arrangement */
+out_side:
+ c->Prec = word_c;
+ c->exponent = a->exponent;
+ VpSetSign(c, VpGetSign(a) * VpGetSign(b));
+ if (!AddExponent(c, 1)) return 0;
+ if (!AddExponent(c, -(b->exponent))) return 0;
+
+ VpNmlz(c); /* normalize c */
+ r->Prec = word_r;
+ r->exponent = a->exponent;
+ VpSetSign(r, VpGetSign(a));
+ VpNmlz(r); /* normalize r(remainder) */
+ goto Exit;
+
+space_error:
+ rb_bug("ERROR(VpDivd): space for remainder too small.");
+
+Exit:
+ return c->Prec * BASE_FIG;
+}
+
+/*
+ * Input a = 00000xxxxxxxx En(5 preceding zeros)
+ * Output a = xxxxxxxx En-5
+ */
+static int
+VpNmlz(Real *a)
+{
+ size_t ind_a, i;
+
+ if (!VpIsDef(a)) goto NoVal;
+ if (VpIsZero(a)) goto NoVal;
+
+ ind_a = a->Prec;
+ while (ind_a--) {
+ if (a->frac[ind_a]) {
+ a->Prec = ind_a + 1;
+ i = 0;
+ while (a->frac[i] == 0) ++i; /* skip the first few zeros */
+ if (i) {
+ a->Prec -= i;
+ if (!AddExponent(a, -(SIGNED_VALUE)i)) return 0;
+ memmove(&a->frac[0], &a->frac[i], a->Prec*sizeof(DECDIG));
+ }
+ return 1;
+ }
+ }
+ /* a is zero(no non-zero digit) */
+ VpSetZero(a, VpGetSign(a));
+ return 0;
+
+NoVal:
+ a->frac[0] = 0;
+ a->Prec = 1;
+ return 0;
+}
+
+/*
+ * VpComp = 0 ... if a=b,
+ * Pos ... a>b,
+ * Neg ... a<b.
+ * 999 ... result undefined(NaN)
+ */
+VP_EXPORT int
+VpComp(Real *a, Real *b)
+{
+ int val;
+ size_t mx, ind;
+ int e;
+ val = 0;
+ if (VpIsNaN(a) || VpIsNaN(b)) return 999;
+ if (!VpIsDef(a)) {
+ if (!VpIsDef(b)) e = a->sign - b->sign;
+ else e = a->sign;
+
+ if (e > 0) return 1;
+ else if (e < 0) return -1;
+ else return 0;
+ }
+ if (!VpIsDef(b)) {
+ e = -b->sign;
+ if (e > 0) return 1;
+ else return -1;
+ }
+ /* Zero check */
+ if (VpIsZero(a)) {
+ if (VpIsZero(b)) return 0; /* both zero */
+ val = -VpGetSign(b);
+ goto Exit;
+ }
+ if (VpIsZero(b)) {
+ val = VpGetSign(a);
+ goto Exit;
+ }
+
+ /* compare sign */
+ if (VpGetSign(a) > VpGetSign(b)) {
+ val = 1; /* a>b */
+ goto Exit;
+ }
+ if (VpGetSign(a) < VpGetSign(b)) {
+ val = -1; /* a<b */
+ goto Exit;
+ }
+
+ /* a and b have same sign, && sign!=0,then compare exponent */
+ if (a->exponent > b->exponent) {
+ val = VpGetSign(a);
+ goto Exit;
+ }
+ if (a->exponent < b->exponent) {
+ val = -VpGetSign(b);
+ goto Exit;
+ }
+
+ /* a and b have same exponent, then compare their significand. */
+ mx = (a->Prec < b->Prec) ? a->Prec : b->Prec;
+ ind = 0;
+ while (ind < mx) {
+ if (a->frac[ind] > b->frac[ind]) {
+ val = VpGetSign(a);
+ goto Exit;
+ }
+ if (a->frac[ind] < b->frac[ind]) {
+ val = -VpGetSign(b);
+ goto Exit;
+ }
+ ++ind;
+ }
+ if (a->Prec > b->Prec) {
+ val = VpGetSign(a);
+ }
+ else if (a->Prec < b->Prec) {
+ val = -VpGetSign(b);
+ }
+
+Exit:
+ if (val > 1) val = 1;
+ else if (val < -1) val = -1;
+
+ return (int)val;
+}
+
+/*
+ * cntl_chr ... ASCIIZ Character, print control characters
+ * Available control codes:
+ * % ... VP variable. To print '%', use '%%'.
+ * \n ... new line
+ * \b ... backspace
+ * \t ... tab
+ * Note: % must not appear more than once
+ * a ... VP variable to be printed
+ */
+static int
+VPrint(FILE *fp, const char *cntl_chr, Real *a)
+{
+ size_t i, j, nc, nd, ZeroSup, sep = 10;
+ DECDIG m, e, nn;
+
+ j = 0;
+ nd = nc = 0; /* nd : number of digits in fraction part(every 10 digits, */
+ /* nd<=10). */
+ /* nc : number of characters printed */
+ ZeroSup = 1; /* Flag not to print the leading zeros as 0.00xxxxEnn */
+ while (*(cntl_chr + j)) {
+ if (*(cntl_chr + j) == '%' && *(cntl_chr + j + 1) != '%') {
+ nc = 0;
+ if (VpIsNaN(a)) {
+ fprintf(fp, SZ_NaN);
+ nc += 8;
+ }
+ else if (VpIsPosInf(a)) {
+ fprintf(fp, SZ_INF);
+ nc += 8;
+ }
+ else if (VpIsNegInf(a)) {
+ fprintf(fp, SZ_NINF);
+ nc += 9;
+ }
+ else if (!VpIsZero(a)) {
+ if (BIGDECIMAL_NEGATIVE_P(a)) {
+ fprintf(fp, "-");
+ ++nc;
+ }
+ nc += fprintf(fp, "0.");
+ switch (*(cntl_chr + j + 1)) {
+ default:
+ break;
+
+ case '0': case 'z':
+ ZeroSup = 0;
+ ++j;
+ sep = cntl_chr[j] == 'z' ? BIGDECIMAL_COMPONENT_FIGURES : 10;
+ break;
+ }
+ for (i = 0; i < a->Prec; ++i) {
+ m = BASE1;
+ e = a->frac[i];
+ while (m) {
+ nn = e / m;
+ if (!ZeroSup || nn) {
+ nc += fprintf(fp, "%lu", (unsigned long)nn); /* The leading zero(s) */
+ /* as 0.00xx will not */
+ /* be printed. */
+ ++nd;
+ ZeroSup = 0; /* Set to print succeeding zeros */
+ }
+ if (nd >= sep) { /* print ' ' after every 10 digits */
+ nd = 0;
+ nc += fprintf(fp, " ");
+ }
+ e = e - nn * m;
+ m /= 10;
+ }
+ }
+ nc += fprintf(fp, "E%"PRIdSIZE, VpExponent10(a));
+ nc += fprintf(fp, " (%"PRIdVALUE", %"PRIuSIZE", %"PRIuSIZE")", a->exponent, a->Prec, a->MaxPrec);
+ }
+ else {
+ nc += fprintf(fp, "0.0");
+ }
+ }
+ else {
+ ++nc;
+ if (*(cntl_chr + j) == '\\') {
+ switch (*(cntl_chr + j + 1)) {
+ case 'n':
+ fprintf(fp, "\n");
+ ++j;
+ break;
+ case 't':
+ fprintf(fp, "\t");
+ ++j;
+ break;
+ case 'b':
+ fprintf(fp, "\n");
+ ++j;
+ break;
+ default:
+ fprintf(fp, "%c", *(cntl_chr + j));
+ break;
+ }
+ }
+ else {
+ fprintf(fp, "%c", *(cntl_chr + j));
+ if (*(cntl_chr + j) == '%') ++j;
+ }
+ }
+ j++;
+ }
+
+ return (int)nc;
+}
+
+static void
+VpFormatSt(char *psz, size_t fFmt)
+{
+ size_t iend, idig = 0, iexp = 0, nspaces;
+ char *p;
+
+ if (fFmt == 0) return;
+
+ iend = strlen(psz);
+
+ if ((p = strchr(psz, '.'))) {
+ idig = (p - psz) + 1;
+ }
+ if ((p = strchr(psz, 'E')) || (p = strchr(psz, 'e'))) {
+ iexp = p - psz;
+ }
+ if (idig == 0 || idig > iexp) return;
+
+ nspaces = (iexp - idig - 1) / fFmt;
+ p = psz + iend + 1;
+ for (size_t i = nspaces; i > 0; i--) {
+ char *src = psz + idig + i * fFmt;
+ char *dst = psz + idig + i * (fFmt + 1);
+ memmove(dst, src, p - src);
+ dst[-1] = ' ';
+ p = src;
+ }
+}
+
+VP_EXPORT ssize_t
+VpExponent10(Real *a)
+{
+ ssize_t ex;
+ size_t n;
+
+ if (!VpHasVal(a)) return 0;
+
+ ex = a->exponent * (ssize_t)BASE_FIG;
+ n = BASE1;
+ while ((a->frac[0] / n) == 0) {
+ --ex;
+ n /= 10;
+ }
+ return ex;
+}
+
+VP_EXPORT void
+VpSzMantissa(Real *a, char *buf, size_t buflen)
+{
+ size_t i, n, ZeroSup;
+ DECDIG_DBL m, e, nn;
+
+ if (VpIsNaN(a)) {
+ snprintf(buf, buflen, SZ_NaN);
+ return;
+ }
+ if (VpIsPosInf(a)) {
+ snprintf(buf, buflen, SZ_INF);
+ return;
+ }
+ if (VpIsNegInf(a)) {
+ snprintf(buf, buflen, SZ_NINF);
+ return;
+ }
+
+ ZeroSup = 1; /* Flag not to print the leading zeros as 0.00xxxxEnn */
+ if (!VpIsZero(a)) {
+ if (BIGDECIMAL_NEGATIVE_P(a)) *buf++ = '-';
+ n = a->Prec;
+ for (i = 0; i < n; ++i) {
+ m = BASE1;
+ e = a->frac[i];
+ while (m) {
+ nn = e / m;
+ if (!ZeroSup || nn) {
+ *buf = (char)('0' + nn);
+ buf++;
+ /* as 0.00xx will be ignored. */
+ ZeroSup = 0; /* Set to print succeeding zeros */
+ }
+ e = e - nn * m;
+ m /= 10;
+ }
+ }
+ *buf = 0;
+ while (buf[-1] == '0') *(--buf) = 0;
+ }
+ else {
+ if (VpIsPosZero(a)) snprintf(buf, buflen, "0");
+ else snprintf(buf, buflen, "-0");
+ }
+}
+
+VP_EXPORT int
+VpToSpecialString(Real *a, char *buf, size_t buflen, int fPlus)
+/* fPlus = 0: default, 1: set ' ' before digits, 2: set '+' before digits. */
+{
+ if (VpIsNaN(a)) {
+ snprintf(buf, buflen, SZ_NaN);
+ return 1;
+ }
+
+ if (VpIsPosInf(a)) {
+ if (fPlus == 1) {
+ *buf++ = ' ';
+ }
+ else if (fPlus == 2) {
+ *buf++ = '+';
+ }
+ snprintf(buf, buflen, SZ_INF);
+ return 1;
+ }
+ if (VpIsNegInf(a)) {
+ snprintf(buf, buflen, SZ_NINF);
+ return 1;
+ }
+ if (VpIsZero(a)) {
+ if (VpIsPosZero(a)) {
+ if (fPlus == 1) snprintf(buf, buflen, " 0.0");
+ else if (fPlus == 2) snprintf(buf, buflen, "+0.0");
+ else snprintf(buf, buflen, "0.0");
+ }
+ else snprintf(buf, buflen, "-0.0");
+ return 1;
+ }
+ return 0;
+}
+
+#define ULLTOA_BUFFER_SIZE 20
+static size_t Vp_ulltoa(unsigned long long number, char *buf)
+{
+ static const char digits[] = "0123456789";
+ char* tmp = buf;
+
+ do *tmp-- = digits[number % 10]; while (number /= 10);
+ return buf - tmp;
+}
+
+VP_EXPORT void
+VpToString(Real *a, char *buf, size_t buflen, size_t fFmt, int fPlus)
+/* fPlus = 0: default, 1: set ' ' before digits, 2: set '+' before digits. */
+{
+ char ulltoa_buf[ULLTOA_BUFFER_SIZE];
+ char *ulltoa_buf_end = ulltoa_buf + ULLTOA_BUFFER_SIZE;
+ size_t i, n, ZeroSup;
+ DECDIG shift, m, e, nn;
+ char *p = buf;
+ size_t plen = buflen;
+ ssize_t ex;
+
+ if (VpToSpecialString(a, buf, buflen, fPlus)) return;
+
+ ZeroSup = 1; /* Flag not to print the leading zeros as 0.00xxxxEnn */
+
+#define ADVANCE(n) do { \
+ if (plen < n) goto overflow; \
+ p += n; \
+ plen -= n; \
+} while (0)
+
+ if (BIGDECIMAL_NEGATIVE_P(a)) {
+ *p = '-';
+ ADVANCE(1);
+ }
+ else if (fPlus == 1) {
+ *p = ' ';
+ ADVANCE(1);
+ }
+ else if (fPlus == 2) {
+ *p = '+';
+ ADVANCE(1);
+ }
+
+ *p = '0'; ADVANCE(1);
+ *p = '.'; ADVANCE(1);
+
+ n = a->Prec;
+ for (i = 0; i < n; ++i) {
+ m = BASE1;
+ e = a->frac[i];
+ while (m) {
+ nn = e / m;
+ if (!ZeroSup || nn) {
+ *p = (char)('0' + nn);
+ ADVANCE(1);
+
+ /* as 0.00xx will be ignored. */
+ ZeroSup = 0; /* Set to print succeeding zeros */
+ }
+ e = e - nn * m;
+ m /= 10;
+ }
+ }
+
+ ex = a->exponent * (ssize_t)BASE_FIG;
+ shift = BASE1;
+ while (a->frac[0] / shift == 0) {
+ --ex;
+ shift /= 10;
+ }
+ while (p - 1 > buf && p[-1] == '0') {
+ *(--p) = '\0';
+ ++plen;
+ }
+ *p = 'e';
+ ADVANCE(1);
+
+ if (ex < 0) {
+ *p = '-';
+ ADVANCE(1);
+ ex = -ex;
+ }
+
+ size_t ex_n = Vp_ulltoa(ex, ulltoa_buf_end - 1);
+ if (ex_n > plen) goto overflow;
+ MEMCPY(p, ulltoa_buf_end - ex_n, char, ex_n);
+ ADVANCE(ex_n);
+ *p = '\0';
+ ADVANCE(1);
+
+ if (fFmt) VpFormatSt(buf, fFmt);
+
+ overflow:
+ return;
+#undef ADVANCE
+}
+
+VP_EXPORT void
+VpToFString(Real *a, char *buf, size_t buflen, size_t fFmt, int fPlus)
+/* fPlus = 0: default, 1: set ' ' before digits, 2: set '+' before digits. */
+{
+ size_t i, n;
+ DECDIG m, e;
+ char *p = buf;
+ size_t plen = buflen, delim = fFmt;
+ ssize_t ex;
+
+ if (VpToSpecialString(a, buf, buflen, fPlus)) return;
+
+#define APPEND(c, group) do { \
+ if (plen < 1) goto overflow; \
+ if (group && delim == 0) { \
+ *p = ' '; \
+ p += 1; \
+ plen -= 1; \
+ } \
+ if (plen < 1) goto overflow; \
+ *p = c; \
+ p += 1; \
+ plen -= 1; \
+ if (group) delim = (delim + 1) % fFmt; \
+} while (0)
+
+
+ if (BIGDECIMAL_NEGATIVE_P(a)) {
+ APPEND('-', false);
+ }
+ else if (fPlus == 1) {
+ APPEND(' ', false);
+ }
+ else if (fPlus == 2) {
+ APPEND('+', false);
+ }
+
+ n = a->Prec;
+ ex = a->exponent;
+ if (ex <= 0) {
+ APPEND('0', false);
+ APPEND('.', false);
+ }
+ while (ex < 0) {
+ for (i=0; i < BASE_FIG; ++i) {
+ APPEND('0', fFmt > 0);
+ }
+ ++ex;
+ }
+
+ for (i = 0; i < n; ++i) {
+ m = BASE1;
+ e = a->frac[i];
+ if (i == 0 && ex > 0) {
+ for (delim = 0; e / m == 0; delim++) {
+ m /= 10;
+ }
+ if (fFmt > 0) {
+ delim = 2*fFmt - (ex * BASE_FIG - delim) % fFmt;
+ }
+ }
+ while (m && (e || (i < n - 1) || ex > 0)) {
+ APPEND((char)(e / m + '0'), fFmt > 0);
+ e %= m;
+ m /= 10;
+ }
+ if (--ex == 0) {
+ APPEND('.', false);
+ delim = fFmt;
+ }
+ }
+
+ while (ex > 0) {
+ for (i=0; i < BASE_FIG; ++i) {
+ APPEND('0', fFmt > 0);
+ }
+ if (--ex == 0) {
+ APPEND('.', false);
+ }
+ }
+
+ *p = '\0';
+ if (p - 1 > buf && p[-1] == '.') {
+ snprintf(p, plen, "0");
+ }
+
+ overflow:
+ return;
+#undef APPEND
+}
+
+/*
+ * [Output]
+ * a[] ... variable to be assigned the value.
+ * [Input]
+ * int_chr[] ... integer part(may include '+/-').
+ * ni ... number of characters in int_chr[],not including '+/-'.
+ * frac[] ... fraction part.
+ * nf ... number of characters in frac[].
+ * exp_chr[] ... exponent part(including '+/-').
+ * ne ... number of characters in exp_chr[],not including '+/-'.
+ */
+VP_EXPORT int
+VpCtoV(Real *a, const char *int_chr, size_t ni, const char *frac, size_t nf, const char *exp_chr, size_t ne)
+{
+ size_t i, j, ind_a, ma, mi, me;
+ SIGNED_VALUE e;
+ int sign, signe, exponent_overflow;
+
+ /* get exponent part */
+ e = 0;
+ ma = a->MaxPrec;
+ mi = ni;
+ me = ne;
+ signe = 1;
+ exponent_overflow = 0;
+ memset(a->frac, 0, ma * sizeof(DECDIG));
+ if (ne > 0) {
+ i = 0;
+ if (exp_chr[0] == '-') {
+ signe = -1;
+ ++i;
+ ++me;
+ }
+ else if (exp_chr[0] == '+') {
+ ++i;
+ ++me;
+ }
+ while (i < me) {
+ int dig = exp_chr[i] - '0';
+ if (MUL_OVERFLOW_SIGNED_VALUE_P(e, 10) ||
+ ADD_OVERFLOW_SIGNED_VALUE_P(e * 10, signe * dig)) {
+ exponent_overflow = 1;
+ break;
+ }
+ e = e * 10 + signe * dig;
+ ++i;
+ }
+ }
+
+ /* get integer part */
+ i = 0;
+ sign = 1;
+ if (1 /*ni >= 0*/) {
+ if (int_chr[0] == '-') {
+ sign = -1;
+ ++i;
+ ++mi;
+ }
+ else if (int_chr[0] == '+') {
+ ++i;
+ ++mi;
+ }
+ }
+ /* skip leading zeros in integer part */
+ while (i < mi && int_chr[i] == '0') {
+ ++i;
+ --ni;
+ }
+
+ /* set actual exponent size. */
+ if (ADD_OVERFLOW_SIGNED_VALUE_P(e, (SIGNED_VALUE)ni)) {
+ exponent_overflow = 1;
+ } else {
+ e += ni;
+ }
+
+ /* Adjust the exponent so that it is the multiple of BASE_FIG. */
+ j = (BASE_FIG - e % BASE_FIG) % BASE_FIG;
+ if (ADD_OVERFLOW_SIGNED_VALUE_P(e, (SIGNED_VALUE)j)) {
+ exponent_overflow = 1;
+ } else {
+ e += j;
+ }
+
+ if (exponent_overflow || e < EXPONENT_MIN || e > EXPONENT_MAX) {
+ int zero = 1;
+ for ( ; i < mi && zero; i++) zero = int_chr[i] == '0';
+ for (i = 0; i < nf && zero; i++) zero = frac[i] == '0';
+ if (!zero && e > 0) {
+ VpSetInf(a, sign);
+ VpException(VP_EXCEPTION_INFINITY, "exponent overflow",0);
+ }
+ else VpSetZero(a, sign);
+ return 1;
+ }
+
+ ind_a = 0;
+ while (i < mi) {
+ a->frac[ind_a] = 0;
+ while (j < BASE_FIG && i < mi) {
+ a->frac[ind_a] = a->frac[ind_a] * 10 + int_chr[i] - '0';
+ ++j;
+ ++i;
+ }
+ if (i < mi) {
+ ++ind_a;
+ if (ind_a >= ma) goto over_flow;
+ j = 0;
+ }
+ }
+
+ /* get fraction part */
+
+ i = 0;
+ while (i < nf) {
+ while (j < BASE_FIG && i < nf) {
+ a->frac[ind_a] = a->frac[ind_a] * 10 + frac[i] - '0';
+ ++j;
+ ++i;
+ }
+ if (i < nf) {
+ ++ind_a;
+ if (ind_a >= ma) goto over_flow;
+ j = 0;
+ }
+ }
+ goto Final;
+
+over_flow:
+ rb_warn("Conversion from String to BigDecimal overflow (last few digits discarded).");
+
+Final:
+ if (ind_a >= ma) ind_a = ma - 1;
+ while (j < BASE_FIG) {
+ a->frac[ind_a] = a->frac[ind_a] * 10;
+ ++j;
+ }
+ a->Prec = ind_a + 1;
+ a->exponent = e / (SIGNED_VALUE)BASE_FIG;
+ VpSetSign(a, sign);
+ VpNmlz(a);
+ return 1;
+}
+
+/*
+ * [Input]
+ * *m ... Real
+ * [Output]
+ * *d ... fraction part of m(d = 0.xxxxxxx). where # of 'x's is fig.
+ * *e ... exponent of m.
+ * BIGDECIMAL_DOUBLE_FIGURES ... Number of digits in a double variable.
+ *
+ * m -> d*10**e, 0<d<BASE
+ * [Returns]
+ * 0 ... Zero
+ * 1 ... Normal
+ * 2 ... Infinity
+ * -1 ... NaN
+ */
+VP_EXPORT int
+VpVtoD(double *d, SIGNED_VALUE *e, Real *m)
+{
+ size_t ind_m, mm, fig;
+ double div;
+ int f = 1;
+
+ if (VpIsNaN(m)) {
+ *d = VpGetDoubleNaN();
+ *e = 0;
+ f = -1; /* NaN */
+ goto Exit;
+ }
+ else if (VpIsPosZero(m)) {
+ *d = 0.0;
+ *e = 0;
+ f = 0;
+ goto Exit;
+ }
+ else if (VpIsNegZero(m)) {
+ *d = VpGetDoubleNegZero();
+ *e = 0;
+ f = 0;
+ goto Exit;
+ }
+ else if (VpIsPosInf(m)) {
+ *d = VpGetDoublePosInf();
+ *e = 0;
+ f = 2;
+ goto Exit;
+ }
+ else if (VpIsNegInf(m)) {
+ *d = VpGetDoubleNegInf();
+ *e = 0;
+ f = 2;
+ goto Exit;
+ }
+ /* Normal number */
+ fig = roomof(BIGDECIMAL_DOUBLE_FIGURES, BASE_FIG);
+ ind_m = 0;
+ mm = Min(fig, m->Prec);
+ *d = 0.0;
+ div = 1.;
+ while (ind_m < mm) {
+ div /= (double)BASE;
+ *d = *d + (double)m->frac[ind_m++] * div;
+ }
+ *e = m->exponent * (SIGNED_VALUE)BASE_FIG;
+ *d *= VpGetSign(m);
+
+Exit:
+ return f;
+}
+
+/*
+ * Round relatively from the decimal point.
+ * f: rounding mode
+ * nf: digit location to round from the decimal point.
+ */
+VP_EXPORT int
+VpMidRound(Real *y, unsigned short f, ssize_t nf)
+{
+ /* fracf: any positive digit under rounding position? */
+ /* fracf_1further: any positive digits under one further than the rounding position? */
+ /* exptoadd: number of digits needed to compensate negative nf */
+ int fracf, fracf_1further;
+ ssize_t n,i,ix,ioffset, exptoadd;
+ DECDIG v, shifter;
+ DECDIG div;
+
+ nf += y->exponent * (ssize_t)BASE_FIG;
+ exptoadd=0;
+ if (nf < 0) {
+ /* rounding position too left(large). */
+ if (f != VP_ROUND_CEIL && f != VP_ROUND_FLOOR) {
+ VpSetZero(y, VpGetSign(y)); /* truncate everything */
+ return 0;
+ }
+ exptoadd = -nf;
+ nf = 0;
+ }
+
+ ix = nf / (ssize_t)BASE_FIG;
+ if ((size_t)ix >= y->Prec) return 0; /* rounding position too right(small). */
+ v = y->frac[ix];
+
+ ioffset = nf - ix*(ssize_t)BASE_FIG;
+ n = (ssize_t)BASE_FIG - ioffset - 1;
+ for (shifter = 1, i = 0; i < n; ++i) shifter *= 10;
+
+ /* so the representation used (in y->frac) is an array of DECDIG, where
+ each DECDIG contains a value between 0 and BASE-1, consisting of BASE_FIG
+ decimal places.
+
+ (that numbers of decimal places are typed as ssize_t is somewhat confusing)
+
+ nf is now position (in decimal places) of the digit from the start of
+ the array.
+
+ ix is the position (in DECDIGs) of the DECDIG containing the decimal digit,
+ from the start of the array.
+
+ v is the value of this DECDIG
+
+ ioffset is the number of extra decimal places along of this decimal digit
+ within v.
+
+ n is the number of decimal digits remaining within v after this decimal digit
+ shifter is 10**n,
+
+ v % shifter are the remaining digits within v
+ v % (shifter * 10) are the digit together with the remaining digits within v
+ v / shifter are the digit's predecessors together with the digit
+ div = v / shifter / 10 is just the digit's precessors
+ (v / shifter) - div*10 is just the digit, which is what v ends up being reassigned to.
+ */
+
+ fracf = (v % (shifter * 10) > 0);
+ fracf_1further = ((v % shifter) > 0);
+
+ v /= shifter;
+ div = v / 10;
+ v = v - div*10;
+ /* now v is just the digit required.
+ now fracf is whether the digit or any of the remaining digits within v are non-zero
+ now fracf_1further is whether any of the remaining digits within v are non-zero
+ */
+
+ /* now check all the remaining DECDIGs for zero-ness a whole DECDIG at a time.
+ if we spot any non-zeroness, that means that we found a positive digit under
+ rounding position, and we also found a positive digit under one further than
+ the rounding position, so both searches (to see if any such non-zero digit exists)
+ can stop */
+
+ for (i = ix + 1; (size_t)i < y->Prec; i++) {
+ if (y->frac[i] % BASE) {
+ fracf = fracf_1further = 1;
+ break;
+ }
+ }
+
+ /* now fracf = does any positive digit exist under the rounding position?
+ now fracf_1further = does any positive digit exist under one further than the
+ rounding position?
+ now v = the first digit under the rounding position */
+
+ /* drop digits after pointed digit */
+ memset(y->frac + ix + 1, 0, (y->Prec - (ix + 1)) * sizeof(DECDIG));
+
+ switch (f) {
+ case VP_ROUND_DOWN: /* Truncate */
+ break;
+ case VP_ROUND_UP: /* Roundup */
+ if (fracf) ++div;
+ break;
+ case VP_ROUND_HALF_UP:
+ if (v>=5) ++div;
+ break;
+ case VP_ROUND_HALF_DOWN:
+ if (v > 5 || (v == 5 && fracf_1further)) ++div;
+ break;
+ case VP_ROUND_CEIL:
+ if (fracf && BIGDECIMAL_POSITIVE_P(y)) ++div;
+ break;
+ case VP_ROUND_FLOOR:
+ if (fracf && BIGDECIMAL_NEGATIVE_P(y)) ++div;
+ break;
+ case VP_ROUND_HALF_EVEN: /* Banker's rounding */
+ if (v > 5) ++div;
+ else if (v == 5) {
+ if (fracf_1further) {
+ ++div;
+ }
+ else {
+ if (ioffset == 0) {
+ /* v is the first decimal digit of its DECDIG;
+ need to grab the previous DECDIG if present
+ to check for evenness of the previous decimal
+ digit (which is same as that of the DECDIG since
+ base 10 has a factor of 2) */
+ if (ix && (y->frac[ix-1] % 2)) ++div;
+ }
+ else {
+ if (div % 2) ++div;
+ }
+ }
+ }
+ break;
+ }
+ for (i = 0; i <= n; ++i) div *= 10;
+ if (div >= BASE) {
+ if (ix) {
+ y->frac[ix] = 0;
+ VpRdup(y, ix);
+ }
+ else {
+ short s = VpGetSign(y);
+ SIGNED_VALUE e = y->exponent;
+ VpSetOne(y);
+ VpSetSign(y, s);
+ y->exponent = e + 1;
+ }
+ }
+ else {
+ y->frac[ix] = div;
+ VpNmlz(y);
+ }
+ if (exptoadd > 0) {
+ y->exponent += (SIGNED_VALUE)(exptoadd / BASE_FIG);
+ exptoadd %= (ssize_t)BASE_FIG;
+ for (i = 0; i < exptoadd; i++) {
+ y->frac[0] *= 10;
+ if (y->frac[0] >= BASE) {
+ y->frac[0] /= BASE;
+ y->exponent++;
+ }
+ }
+ }
+ return 1;
+}
+
+VP_EXPORT int
+VpLeftRound(Real *y, unsigned short f, ssize_t nf)
+/*
+ * Round from the left hand side of the digits.
+ */
+{
+ DECDIG v;
+ if (!VpHasVal(y)) return 0; /* Unable to round */
+ v = y->frac[0];
+ nf -= y->exponent * (ssize_t)BASE_FIG;
+ while ((v /= 10) != 0) nf--;
+ nf += (ssize_t)BASE_FIG-1;
+ return VpMidRound(y, f, nf);
+}
+
+VP_EXPORT int
+VpActiveRound(Real *y, Real *x, unsigned short f, ssize_t nf)
+{
+ /* First,assign whole value in truncation mode */
+ if (VpAsgn(y, x, 10) <= 1) return 0; /* Zero,NaN,or Infinity */
+ return VpMidRound(y, f, nf);
+}
+
+static int
+VpLimitRound(Real *c, size_t ixDigit)
+{
+ size_t ix = VpGetPrecLimit();
+ if (!VpNmlz(c)) return -1;
+ if (!ix) return 0;
+ if (!ixDigit) ixDigit = c->Prec-1;
+ if ((ix + BASE_FIG - 1) / BASE_FIG > ixDigit + 1) return 0;
+ return VpLeftRound(c, VpGetRoundMode(), (ssize_t)ix);
+}
+
+/* If I understand correctly, this is only ever used to round off the final decimal
+ digit of precision */
+static void
+VpInternalRound(Real *c, size_t ixDigit, DECDIG vPrev, DECDIG v)
+{
+ int f = 0;
+
+ unsigned short const rounding_mode = VpGetRoundMode();
+
+ if (VpLimitRound(c, ixDigit)) return;
+ if (!v) return;
+
+ v /= BASE1;
+ switch (rounding_mode) {
+ case VP_ROUND_DOWN:
+ break;
+ case VP_ROUND_UP:
+ if (v) f = 1;
+ break;
+ case VP_ROUND_HALF_UP:
+ if (v >= 5) f = 1;
+ break;
+ case VP_ROUND_HALF_DOWN:
+ /* this is ok - because this is the last digit of precision,
+ the case where v == 5 and some further digits are nonzero
+ will never occur */
+ if (v >= 6) f = 1;
+ break;
+ case VP_ROUND_CEIL:
+ if (v && BIGDECIMAL_POSITIVE_P(c)) f = 1;
+ break;
+ case VP_ROUND_FLOOR:
+ if (v && BIGDECIMAL_NEGATIVE_P(c)) f = 1;
+ break;
+ case VP_ROUND_HALF_EVEN: /* Banker's rounding */
+ /* as per VP_ROUND_HALF_DOWN, because this is the last digit of precision,
+ there is no case to worry about where v == 5 and some further digits are nonzero */
+ if (v > 5) f = 1;
+ else if (v == 5 && vPrev % 2) f = 1;
+ break;
+ }
+ if (f) {
+ VpRdup(c, ixDigit);
+ VpNmlz(c);
+ }
+}
+
+/*
+ * Rounds up m(plus one to final digit of m).
+ */
+static int
+VpRdup(Real *m, size_t ind_m)
+{
+ DECDIG carry;
+
+ if (!ind_m) ind_m = m->Prec;
+
+ carry = 1;
+ while (carry > 0 && ind_m--) {
+ m->frac[ind_m] += carry;
+ if (m->frac[ind_m] >= BASE) m->frac[ind_m] -= BASE;
+ else carry = 0;
+ }
+ if (carry > 0) { /* Overflow,count exponent and set fraction part be 1 */
+ if (!AddExponent(m, 1)) return 0;
+ m->Prec = m->frac[0] = 1;
+ }
+ else {
+ VpNmlz(m);
+ }
+ return 1;
+}
+
+/*
+ * y = x - fix(x)
+ */
+VP_EXPORT void
+VpFrac(Real *y, Real *x)
+{
+ size_t my, ind_y, ind_x;
+
+ if (!VpHasVal(x)) {
+ VpAsgn(y, x, 10);
+ goto Exit;
+ }
+
+ if (x->exponent > 0 && (size_t)x->exponent >= x->Prec) {
+ VpSetZero(y, VpGetSign(x));
+ goto Exit;
+ }
+ else if (x->exponent <= 0) {
+ VpAsgn(y, x, 10);
+ goto Exit;
+ }
+
+ /* satisfy: x->exponent > 0 */
+
+ y->Prec = x->Prec - (size_t)x->exponent;
+ y->Prec = Min(y->Prec, y->MaxPrec);
+ y->exponent = 0;
+ VpSetSign(y, VpGetSign(x));
+ ind_y = 0;
+ my = y->Prec;
+ ind_x = x->exponent;
+ while (ind_y < my) {
+ y->frac[ind_y] = x->frac[ind_x];
+ ++ind_y;
+ ++ind_x;
+ }
+ VpNmlz(y);
+
+Exit:
+ return;
+}
+
+#ifdef BIGDECIMAL_DEBUG
+int
+VpVarCheck(Real * v)
+/*
+ * Checks the validity of the Real variable v.
+ * [Input]
+ * v ... Real *, variable to be checked.
+ * [Returns]
+ * 0 ... correct v.
+ * other ... error
+ */
+{
+ size_t i;
+
+ if (v->MaxPrec == 0) {
+ printf("ERROR(VpVarCheck): Illegal Max. Precision(=%"PRIuSIZE")\n",
+ v->MaxPrec);
+ return 1;
+ }
+ if (v->Prec == 0 || v->Prec > v->MaxPrec) {
+ printf("ERROR(VpVarCheck): Illegal Precision(=%"PRIuSIZE")\n", v->Prec);
+ printf(" Max. Prec.=%"PRIuSIZE"\n", v->MaxPrec);
+ return 2;
+ }
+ for (i = 0; i < v->Prec; ++i) {
+ if (v->frac[i] >= BASE) {
+ printf("ERROR(VpVarCheck): Illegal fraction\n");
+ printf(" Frac[%"PRIuSIZE"]=%"PRIuDECDIG"\n", i, v->frac[i]);
+ printf(" Prec. =%"PRIuSIZE"\n", v->Prec);
+ printf(" Exp. =%"PRIdVALUE"\n", v->exponent);
+ printf(" BASE =%"PRIuDECDIG"\n", BASE);
+ return 3;
+ }
+ }
+ return 0;
+}
+#endif /* BIGDECIMAL_DEBUG */
diff --git a/vendor/bundle/ruby/3.4.0/gems/bigdecimal-4.1.2/ext/bigdecimal/bigdecimal.h b/vendor/bundle/ruby/3.4.0/gems/bigdecimal-4.1.2/ext/bigdecimal/bigdecimal.h
new file mode 100644
index 0000000..faa6626
--- /dev/null
+++ b/vendor/bundle/ruby/3.4.0/gems/bigdecimal-4.1.2/ext/bigdecimal/bigdecimal.h
@@ -0,0 +1,298 @@
+/*
+ *
+ * Ruby BigDecimal(Variable decimal precision) extension library.
+ *
+ * Copyright(C) 2002 by Shigeo Kobayashi(shigeo@tinyforest.gr.jp)
+ *
+ */
+
+#ifndef RUBY_BIG_DECIMAL_H
+#define RUBY_BIG_DECIMAL_H 1
+
+#define RUBY_NO_OLD_COMPATIBILITY
+#include "ruby/ruby.h"
+#include "missing.h"
+
+#ifdef HAVE_FLOAT_H
+# include <float.h>
+#endif
+
+#define DECDIG uint32_t
+#define DECDIG_DBL uint64_t
+#define DECDIG_DBL_SIGNED int64_t
+#define SIZEOF_DECDIG 4
+#define PRI_DECDIG_PREFIX ""
+#ifdef PRI_LL_PREFIX
+# define PRI_DECDIG_DBL_PREFIX PRI_LL_PREFIX
+#else
+# define PRI_DECDIG_DBL_PREFIX "l"
+#endif
+
+#define PRIdDECDIG PRI_DECDIG_PREFIX"d"
+#define PRIiDECDIG PRI_DECDIG_PREFIX"i"
+#define PRIoDECDIG PRI_DECDIG_PREFIX"o"
+#define PRIuDECDIG PRI_DECDIG_PREFIX"u"
+#define PRIxDECDIG PRI_DECDIG_PREFIX"x"
+#define PRIXDECDIG PRI_DECDIG_PREFIX"X"
+
+#define PRIdDECDIG_DBL PRI_DECDIG_DBL_PREFIX"d"
+#define PRIiDECDIG_DBL PRI_DECDIG_DBL_PREFIX"i"
+#define PRIoDECDIG_DBL PRI_DECDIG_DBL_PREFIX"o"
+#define PRIuDECDIG_DBL PRI_DECDIG_DBL_PREFIX"u"
+#define PRIxDECDIG_DBL PRI_DECDIG_DBL_PREFIX"x"
+#define PRIXDECDIG_DBL PRI_DECDIG_DBL_PREFIX"X"
+
+#define BIGDECIMAL_BASE ((DECDIG)1000000000U)
+#define BIGDECIMAL_COMPONENT_FIGURES 9
+/*
+ * The number of components required for a 64-bit integer.
+ *
+ * INT64_MAX: 9_223372036_854775807
+ * UINT64_MAX: 18_446744073_709551615
+ */
+#define BIGDECIMAL_INT64_MAX_LENGTH 3
+
+#define BIGDECIMAL_DOUBLE_FIGURES (1+DBL_DIG)
+
+#if defined(__cplusplus)
+extern "C" {
+#if 0
+} /* satisfy cc-mode */
+#endif
+#endif
+
+extern VALUE rb_cBigDecimal;
+
+/*
+ * NaN & Infinity
+ */
+#define SZ_NaN "NaN"
+#define SZ_INF "Infinity"
+#define SZ_PINF "+Infinity"
+#define SZ_NINF "-Infinity"
+
+/*
+ * #define VP_EXPORT other than static to let VP_ routines
+ * be called from outside of this module.
+ */
+#define VP_EXPORT static
+
+/* Exception mode */
+#define VP_EXCEPTION_ALL ((unsigned short)0x00FF)
+#define VP_EXCEPTION_INFINITY ((unsigned short)0x0001)
+#define VP_EXCEPTION_NaN ((unsigned short)0x0002)
+#define VP_EXCEPTION_UNDERFLOW ((unsigned short)0x0004)
+#define VP_EXCEPTION_OVERFLOW ((unsigned short)0x0001) /* 0x0008) */
+#define VP_EXCEPTION_ZERODIVIDE ((unsigned short)0x0010)
+
+/* Following 2 exceptions can't controlled by user */
+#define VP_EXCEPTION_OP ((unsigned short)0x0020)
+
+#define BIGDECIMAL_EXCEPTION_MODE_DEFAULT 0U
+
+/* This is used in BigDecimal#mode */
+#define VP_ROUND_MODE ((unsigned short)0x0100)
+
+/* Rounding mode */
+#define VP_ROUND_UP RBD_ROUND_UP
+#define VP_ROUND_DOWN RBD_ROUND_DOWN
+#define VP_ROUND_HALF_UP RBD_ROUND_HALF_UP
+#define VP_ROUND_HALF_DOWN RBD_ROUND_HALF_DOWN
+#define VP_ROUND_CEIL RBD_ROUND_CEIL
+#define VP_ROUND_FLOOR RBD_ROUND_FLOOR
+#define VP_ROUND_HALF_EVEN RBD_ROUND_HALF_EVEN
+
+enum rbd_rounding_mode {
+ RBD_ROUND_UP = 1,
+ RBD_ROUND_DOWN = 2,
+ RBD_ROUND_HALF_UP = 3,
+ RBD_ROUND_HALF_DOWN = 4,
+ RBD_ROUND_CEIL = 5,
+ RBD_ROUND_FLOOR = 6,
+ RBD_ROUND_HALF_EVEN = 7,
+
+ RBD_ROUND_DEFAULT = RBD_ROUND_HALF_UP,
+ RBD_ROUND_TRUNCATE = RBD_ROUND_DOWN,
+ RBD_ROUND_BANKER = RBD_ROUND_HALF_EVEN,
+ RBD_ROUND_CEILING = RBD_ROUND_CEIL
+};
+
+#define BIGDECIMAL_ROUNDING_MODE_DEFAULT VP_ROUND_HALF_UP
+
+/* Sign flag */
+#define VP_SIGN_NaN 0 /* NaN */
+#define VP_SIGN_POSITIVE_ZERO 1 /* Positive zero */
+#define VP_SIGN_NEGATIVE_ZERO -1 /* Negative zero */
+#define VP_SIGN_POSITIVE_FINITE 2 /* Positive finite number */
+#define VP_SIGN_NEGATIVE_FINITE -2 /* Negative finite number */
+#define VP_SIGN_POSITIVE_INFINITE 3 /* Positive infinite number */
+#define VP_SIGN_NEGATIVE_INFINITE -3 /* Negative infinite number */
+
+/* The size of fraction part array */
+#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)
+#define FLEXIBLE_ARRAY_SIZE /* */
+#elif defined(__GNUC__) && !defined(__STRICT_ANSI__)
+#define FLEXIBLE_ARRAY_SIZE 0
+#else
+#define FLEXIBLE_ARRAY_SIZE 1
+#endif
+
+/*
+ * VP representation
+ * r = 0.xxxxxxxxx *BASE**exponent
+ */
+typedef struct {
+ size_t MaxPrec; /* Maximum precision size */
+ /* This is the actual size of frac[] */
+ /*(frac[0] to frac[MaxPrec] are available). */
+ size_t Prec; /* Current precision size. */
+ /* This indicates how much the */
+ /* array frac[] is actually used. */
+ SIGNED_VALUE exponent; /* Exponent part. */
+ short sign; /* Attributes of the value. */
+ /*
+ * ==0 : NaN
+ * 1 : Positive zero
+ * -1 : Negative zero
+ * 2 : Positive number
+ * -2 : Negative number
+ * 3 : Positive infinite number
+ * -3 : Negative infinite number
+ */
+ short flag; /* Not used in vp_routines,space for user. */
+ DECDIG frac[FLEXIBLE_ARRAY_SIZE]; /* Array of fraction part. */
+} Real;
+
+typedef struct {
+ VALUE bigdecimal;
+ Real *real;
+} BDVALUE;
+
+typedef struct {
+ VALUE bigdecimal_or_nil;
+ Real *real_or_null;
+} NULLABLE_BDVALUE;
+
+/*
+ * ------------------
+ * EXPORTables.
+ * ------------------
+ */
+
+#define VpBaseFig() BIGDECIMAL_COMPONENT_FIGURES
+
+/* Zero,Inf,NaN (isinf(),isnan() used to check) */
+VP_EXPORT double VpGetDoubleNaN(void);
+VP_EXPORT double VpGetDoublePosInf(void);
+VP_EXPORT double VpGetDoubleNegInf(void);
+VP_EXPORT double VpGetDoubleNegZero(void);
+
+/* These 2 functions added at v1.1.7 */
+VP_EXPORT size_t VpGetPrecLimit(void);
+VP_EXPORT void VpSetPrecLimit(size_t n);
+
+/* Round mode */
+VP_EXPORT int VpIsRoundMode(unsigned short n);
+VP_EXPORT unsigned short VpGetRoundMode(void);
+VP_EXPORT unsigned short VpSetRoundMode(unsigned short n);
+
+VP_EXPORT int VpException(unsigned short f,const char *str,int always);
+VP_EXPORT size_t VpNumOfChars(Real *vp,const char *pszFmt);
+VP_EXPORT size_t VpInit(DECDIG BaseVal);
+VP_EXPORT NULLABLE_BDVALUE VpAlloc(const char *szVal, int strict_p, int exc);
+VP_EXPORT size_t VpAsgn(Real *c, Real *a, int isw);
+VP_EXPORT size_t VpAddSub(Real *c,Real *a,Real *b,int operation);
+VP_EXPORT size_t VpMult(Real *c,Real *a,Real *b);
+VP_EXPORT size_t VpDivd(Real *c,Real *r,Real *a,Real *b);
+VP_EXPORT int VpNmlz(Real *a);
+VP_EXPORT int VpComp(Real *a,Real *b);
+VP_EXPORT ssize_t VpExponent10(Real *a);
+VP_EXPORT void VpSzMantissa(Real *a, char *buf, size_t bufsize);
+VP_EXPORT int VpToSpecialString(Real *a, char *buf, size_t bufsize, int fPlus);
+VP_EXPORT void VpToString(Real *a, char *buf, size_t bufsize, size_t fFmt, int fPlus);
+VP_EXPORT void VpToFString(Real *a, char *buf, size_t bufsize, size_t fFmt, int fPlus);
+VP_EXPORT int VpCtoV(Real *a, const char *int_chr, size_t ni, const char *frac, size_t nf, const char *exp_chr, size_t ne);
+VP_EXPORT int VpVtoD(double *d, SIGNED_VALUE *e, Real *m);
+VP_EXPORT int VpActiveRound(Real *y, Real *x, unsigned short f, ssize_t il);
+VP_EXPORT int VpMidRound(Real *y, unsigned short f, ssize_t nf);
+VP_EXPORT int VpLeftRound(Real *y, unsigned short f, ssize_t nf);
+VP_EXPORT void VpFrac(Real *y, Real *x);
+VP_EXPORT int AddExponent(Real *a, SIGNED_VALUE n);
+
+/* VP constants */
+VP_EXPORT Real *VpOne(void);
+
+/*
+ * **** BigDecimal part ****
+ */
+VP_EXPORT VALUE BigDecimal_lt(VALUE self, VALUE r);
+VP_EXPORT VALUE BigDecimal_ge(VALUE self, VALUE r);
+VP_EXPORT VALUE BigDecimal_exponent(VALUE self);
+VP_EXPORT VALUE BigDecimal_fix(VALUE self);
+VP_EXPORT VALUE BigDecimal_frac(VALUE self);
+VP_EXPORT VALUE BigDecimal_add(VALUE self, VALUE b);
+VP_EXPORT VALUE BigDecimal_sub(VALUE self, VALUE b);
+VP_EXPORT VALUE BigDecimal_mult(VALUE self, VALUE b);
+VP_EXPORT VALUE BigDecimal_add2(VALUE self, VALUE b, VALUE n);
+VP_EXPORT VALUE BigDecimal_sub2(VALUE self, VALUE b, VALUE n);
+VP_EXPORT VALUE BigDecimal_mult2(VALUE self, VALUE b, VALUE n);
+VP_EXPORT VALUE BigDecimal_split(VALUE self);
+VP_EXPORT VALUE BigDecimal_decimal_shift(VALUE self, VALUE v);
+VP_EXPORT inline BDVALUE GetBDValueMust(VALUE v);
+VP_EXPORT inline BDVALUE rbd_allocate_struct_zero_wrap(int sign, size_t const digits);
+#define NewZeroWrap rbd_allocate_struct_zero_wrap
+
+/*
+ * ------------------
+ * MACRO definitions.
+ * ------------------
+ */
+#define Abs(a) (((a)>= 0)?(a):(-(a)))
+#define Max(a, b) (((a)>(b))?(a):(b))
+#define Min(a, b) (((a)>(b))?(b):(a))
+
+/* Sign */
+
+/* VpGetSign(a) returns 1,-1 if a>0,a<0 respectively */
+#define VpGetSign(a) (((a)->sign>0)?1:(-1))
+/* Change sign of a to a>0,a<0 if s = 1,-1 respectively */
+#define VpChangeSign(a,s) {if((s)>0) (a)->sign=(short)Abs((ssize_t)(a)->sign);else (a)->sign=-(short)Abs((ssize_t)(a)->sign);}
+/* Sets sign of a to a>0,a<0 if s = 1,-1 respectively */
+#define VpSetSign(a,s) {if((s)>0) (a)->sign=(short)VP_SIGN_POSITIVE_FINITE;else (a)->sign=(short)VP_SIGN_NEGATIVE_FINITE;}
+
+/* 1 */
+#define VpSetOne(a) {(a)->Prec=(a)->exponent=(a)->frac[0]=1;(a)->sign=VP_SIGN_POSITIVE_FINITE;}
+
+/* ZEROs */
+#define VpIsPosZero(a) ((a)->sign==VP_SIGN_POSITIVE_ZERO)
+#define VpIsNegZero(a) ((a)->sign==VP_SIGN_NEGATIVE_ZERO)
+#define VpIsZero(a) (VpIsPosZero(a) || VpIsNegZero(a))
+#define VpSetPosZero(a) ((a)->frac[0]=0,(a)->Prec=1,(a)->sign=VP_SIGN_POSITIVE_ZERO)
+#define VpSetNegZero(a) ((a)->frac[0]=0,(a)->Prec=1,(a)->sign=VP_SIGN_NEGATIVE_ZERO)
+#define VpSetZero(a,s) (void)(((s)>0)?VpSetPosZero(a):VpSetNegZero(a))
+
+/* NaN */
+#define VpIsNaN(a) ((a)->sign==VP_SIGN_NaN)
+#define VpSetNaN(a) ((a)->frac[0]=0,(a)->Prec=1,(a)->sign=VP_SIGN_NaN)
+
+/* Infinity */
+#define VpIsPosInf(a) ((a)->sign==VP_SIGN_POSITIVE_INFINITE)
+#define VpIsNegInf(a) ((a)->sign==VP_SIGN_NEGATIVE_INFINITE)
+#define VpIsInf(a) (VpIsPosInf(a) || VpIsNegInf(a))
+#define VpIsDef(a) ( !(VpIsNaN(a)||VpIsInf(a)) )
+#define VpSetPosInf(a) ((a)->frac[0]=0,(a)->Prec=1,(a)->sign=VP_SIGN_POSITIVE_INFINITE)
+#define VpSetNegInf(a) ((a)->frac[0]=0,(a)->Prec=1,(a)->sign=VP_SIGN_NEGATIVE_INFINITE)
+#define VpSetInf(a,s) (void)(((s)>0)?VpSetPosInf(a):VpSetNegInf(a))
+#define VpHasVal(a) (a->frac[0])
+#define VpIsOne(a) ((a->Prec==1)&&(a->frac[0]==1)&&(a->exponent==1))
+#ifdef BIGDECIMAL_DEBUG
+int VpVarCheck(Real * v);
+#endif /* BIGDECIMAL_DEBUG */
+
+#if defined(__cplusplus)
+#if 0
+{ /* satisfy cc-mode */
+#endif
+} /* extern "C" { */
+#endif
+#endif /* RUBY_BIG_DECIMAL_H */
diff --git a/vendor/bundle/ruby/3.4.0/gems/bigdecimal-4.1.2/ext/bigdecimal/bits.h b/vendor/bundle/ruby/3.4.0/gems/bigdecimal-4.1.2/ext/bigdecimal/bits.h
new file mode 100644
index 0000000..66efce4
--- /dev/null
+++ b/vendor/bundle/ruby/3.4.0/gems/bigdecimal-4.1.2/ext/bigdecimal/bits.h
@@ -0,0 +1,144 @@
+#ifndef BIGDECIMAL_BITS_H
+#define BIGDECIMAL_BITS_H
+
+#include "feature.h"
+#include "static_assert.h"
+
+#if defined(__x86_64__) && defined(HAVE_X86INTRIN_H)
+# include <x86intrin.h> /* for _lzcnt_u64, etc. */
+#elif defined(_MSC_VER) && defined(HAVE_INTRIN_H)
+# include <intrin.h> /* for the following intrinsics */
+#endif
+
+#if defined(_MSC_VER) && defined(__AVX2__)
+# pragma intrinsic(__lzcnt)
+# pragma intrinsic(__lzcnt64)
+#endif
+
+#define numberof(array) ((int)(sizeof(array) / sizeof((array)[0])))
+#define roomof(x, y) (((x) + (y) - 1) / (y))
+#define type_roomof(x, y) roomof(sizeof(x), sizeof(y))
+
+#define MUL_OVERFLOW_SIGNED_INTEGER_P(a, b, min, max) ( \
+ (a) == 0 ? 0 : \
+ (a) == -1 ? (b) < -(max) : \
+ (a) > 0 ? \
+ ((b) > 0 ? (max) / (a) < (b) : (min) / (a) > (b)) : \
+ ((b) > 0 ? (min) / (a) < (b) : (max) / (a) > (b)))
+
+#define ADD_OVERFLOW_SIGNED_INTEGER_P(a, b, min, max) ( \
+ ((a) > 0) == ((b) > 0) && ((a) > 0 ? (max) - (a) < (b) : (min) - (a) > (b)))
+
+#ifdef HAVE_UINT128_T
+# define bit_length(x) \
+ (unsigned int) \
+ (sizeof(x) <= sizeof(int32_t) ? 32 - nlz_int32((uint32_t)(x)) : \
+ sizeof(x) <= sizeof(int64_t) ? 64 - nlz_int64((uint64_t)(x)) : \
+ 128 - nlz_int128((uint128_t)(x)))
+#else
+# define bit_length(x) \
+ (unsigned int) \
+ (sizeof(x) <= sizeof(int32_t) ? 32 - nlz_int32((uint32_t)(x)) : \
+ 64 - nlz_int64((uint64_t)(x)))
+#endif
+
+static inline unsigned nlz_int32(uint32_t x);
+static inline unsigned nlz_int64(uint64_t x);
+#ifdef HAVE_UINT128_T
+static inline unsigned nlz_int128(uint128_t x);
+#endif
+
+static inline unsigned int
+nlz_int32(uint32_t x)
+{
+#if defined(_MSC_VER) && defined(__AVX2__) && defined(HAVE___LZCNT)
+ /* Note: It seems there is no such thing like __LZCNT__ predefined in MSVC.
+ * AMD CPUs have had this instruction for decades (since K10) but for
+ * Intel, Haswell is the oldest one. We need to use __AVX2__ for maximum
+ * safety. */
+ return (unsigned int)__lzcnt(x);
+
+#elif defined(__x86_64__) && defined(__LZCNT__) && defined(HAVE__LZCNT_U32)
+ return (unsigned int)_lzcnt_u32(x);
+
+#elif defined(_MSC_VER) && defined(HAVE__BITSCANREVERSE)
+ unsigned long r;
+ return _BitScanReverse(&r, x) ? (31 - (int)r) : 32;
+
+#elif __has_builtin(__builtin_clz)
+ STATIC_ASSERT(sizeof_int, sizeof(int) * CHAR_BIT == 32);
+ return x ? (unsigned int)__builtin_clz(x) : 32;
+
+#else
+ uint32_t y;
+ unsigned n = 32;
+ y = x >> 16; if (y) {n -= 16; x = y;}
+ y = x >> 8; if (y) {n -= 8; x = y;}
+ y = x >> 4; if (y) {n -= 4; x = y;}
+ y = x >> 2; if (y) {n -= 2; x = y;}
+ y = x >> 1; if (y) {return n - 2;}
+ return (unsigned int)(n - x);
+#endif
+}
+
+static inline unsigned int
+nlz_int64(uint64_t x)
+{
+#if defined(_MSC_VER) && defined(__AVX2__) && defined(HAVE___LZCNT64)
+ return (unsigned int)__lzcnt64(x);
+
+#elif defined(__x86_64__) && defined(__LZCNT__) && defined(HAVE__LZCNT_U64)
+ return (unsigned int)_lzcnt_u64(x);
+
+#elif defined(_WIN64) && defined(_MSC_VER) && defined(HAVE__BITSCANREVERSE64)
+ unsigned long r;
+ return _BitScanReverse64(&r, x) ? (63u - (unsigned int)r) : 64;
+
+#elif __has_builtin(__builtin_clzl) && __has_builtin(__builtin_clzll) && !(defined(__sun) && defined(__sparc))
+ if (x == 0) {
+ return 64;
+ }
+ else if (sizeof(long) * CHAR_BIT == 64) {
+ return (unsigned int)__builtin_clzl((unsigned long)x);
+ }
+ else if (sizeof(long long) * CHAR_BIT == 64) {
+ return (unsigned int)__builtin_clzll((unsigned long long)x);
+ }
+ else {
+ /* :FIXME: Is there a way to make this branch a compile-time error? */
+ __builtin_unreachable();
+ }
+
+#else
+ uint64_t y;
+ unsigned int n = 64;
+ y = x >> 32; if (y) {n -= 32; x = y;}
+ y = x >> 16; if (y) {n -= 16; x = y;}
+ y = x >> 8; if (y) {n -= 8; x = y;}
+ y = x >> 4; if (y) {n -= 4; x = y;}
+ y = x >> 2; if (y) {n -= 2; x = y;}
+ y = x >> 1; if (y) {return n - 2;}
+ return (unsigned int)(n - x);
+
+#endif
+}
+
+#ifdef HAVE_UINT128_T
+static inline unsigned int
+nlz_int128(uint128_t x)
+{
+ uint64_t y = (uint64_t)(x >> 64);
+
+ if (x == 0) {
+ return 128;
+ }
+ else if (y == 0) {
+ return (unsigned int)nlz_int64(x) + 64;
+ }
+ else {
+ return (unsigned int)nlz_int64(y);
+ }
+}
+#endif
+
+#endif /* BIGDECIMAL_BITS_H */
diff --git a/vendor/bundle/ruby/3.4.0/gems/bigdecimal-4.1.2/ext/bigdecimal/div.h b/vendor/bundle/ruby/3.4.0/gems/bigdecimal-4.1.2/ext/bigdecimal/div.h
new file mode 100644
index 0000000..310a8b2
--- /dev/null
+++ b/vendor/bundle/ruby/3.4.0/gems/bigdecimal-4.1.2/ext/bigdecimal/div.h
@@ -0,0 +1,192 @@
+// Calculate the inverse of x using the Newton-Raphson method.
+static VALUE
+newton_raphson_inverse(VALUE x, size_t prec) {
+ BDVALUE bdone = NewZeroWrap(1, 1);
+ VpSetOne(bdone.real);
+ VALUE one = bdone.bigdecimal;
+
+ // Initial approximation in 2 digits
+ BDVALUE bdx = GetBDValueMust(x);
+ BDVALUE inv0 = NewZeroWrap(1, 2 * BIGDECIMAL_COMPONENT_FIGURES);
+ VpSetOne(inv0.real);
+ DECDIG_DBL numerator = (DECDIG_DBL)BIGDECIMAL_BASE * 100;
+ DECDIG_DBL denominator = (DECDIG_DBL)bdx.real->frac[0] * 100 + (DECDIG_DBL)(bdx.real->Prec >= 2 ? bdx.real->frac[1] : 0) * 100 / BIGDECIMAL_BASE;
+ inv0.real->frac[0] = (DECDIG)(numerator / denominator);
+ inv0.real->frac[1] = (DECDIG)((numerator % denominator) * (BIGDECIMAL_BASE / 100) / denominator * 100);
+ inv0.real->Prec = 2;
+ inv0.real->exponent = 1 - bdx.real->exponent;
+ VpNmlz(inv0.real);
+ RB_GC_GUARD(bdx.bigdecimal);
+ VALUE inv = inv0.bigdecimal;
+
+ int bl = 1;
+ while (((size_t)1 << bl) < prec) bl++;
+
+ for (int i = bl; i >= 0; i--) {
+ size_t n = (prec >> i) + 2;
+ if (n > prec) n = prec;
+ // Newton-Raphson iteration: inv_next = inv + inv * (1 - x * inv)
+ VALUE one_minus_x_inv = BigDecimal_sub2(
+ one,
+ BigDecimal_mult(BigDecimal_mult2(x, one, SIZET2NUM(n + 1)), inv),
+ SIZET2NUM(SIZET2NUM(n / 2))
+ );
+ inv = BigDecimal_add2(
+ inv,
+ BigDecimal_mult(inv, one_minus_x_inv),
+ SIZET2NUM(n)
+ );
+ }
+ return inv;
+}
+
+// Calculates divmod by multiplying approximate reciprocal of y
+static void
+divmod_by_inv_mul(VALUE x, VALUE y, VALUE inv, VALUE *res_div, VALUE *res_mod) {
+ VALUE div = BigDecimal_fix(BigDecimal_mult(x, inv));
+ VALUE mod = BigDecimal_sub(x, BigDecimal_mult(div, y));
+ while (RTEST(BigDecimal_lt(mod, INT2FIX(0)))) {
+ mod = BigDecimal_add(mod, y);
+ div = BigDecimal_sub(div, INT2FIX(1));
+ }
+ while (RTEST(BigDecimal_ge(mod, y))) {
+ mod = BigDecimal_sub(mod, y);
+ div = BigDecimal_add(div, INT2FIX(1));
+ }
+ *res_div = div;
+ *res_mod = mod;
+}
+
+static void
+slice_copy(DECDIG *dest, Real *src, size_t rshift, size_t length) {
+ ssize_t start = src->exponent - (ssize_t)rshift - (ssize_t)length;
+ if (start >= (ssize_t)src->Prec) return;
+ if (start < 0) {
+ dest -= start;
+ length -= (size_t)(-start);
+ start = 0;
+ }
+ size_t max_length = (size_t)((ssize_t)src->Prec - start);
+ memcpy(dest, src->frac + start, Min(length, max_length) * sizeof(DECDIG));
+}
+
+/* Calculates divmod using Newton-Raphson method.
+ * x and y must be a BigDecimal representing an integer value.
+ *
+ * To calculate with low cost, we need to split x into blocks and perform divmod for each block.
+ * x_digits = remaining_digits(<= y_digits) + block_digits * num_blocks
+ *
+ * Example:
+ * xxx_xxxxx_xxxxx_xxxxx(18 digits) / yyyyy(5 digits)
+ * remaining_digits = 3, block_digits = 5, num_blocks = 3
+ * repeating xxxxx_xxxxxx.divmod(yyyyy) calculation 3 times.
+ *
+ * In each divmod step, dividend is at most (y_digits + block_digits) digits and divisor is y_digits digits.
+ * Reciprocal of y needs block_digits + 1 precision.
+ */
+static void
+divmod_newton(VALUE x, VALUE y, VALUE *div_out, VALUE *mod_out) {
+ size_t x_digits = NUM2SIZET(BigDecimal_exponent(x));
+ size_t y_digits = NUM2SIZET(BigDecimal_exponent(y));
+ if (x_digits <= y_digits) x_digits = y_digits + 1;
+
+ size_t n = x_digits / y_digits;
+ size_t block_figs = (x_digits - y_digits) / n / BIGDECIMAL_COMPONENT_FIGURES + 1;
+ size_t block_digits = block_figs * BIGDECIMAL_COMPONENT_FIGURES;
+ size_t num_blocks = (x_digits - y_digits + block_digits - 1) / block_digits;
+ size_t y_figs = (y_digits - 1) / BIGDECIMAL_COMPONENT_FIGURES + 1;
+ VALUE yinv = newton_raphson_inverse(y, block_digits + 1);
+
+ BDVALUE divident = NewZeroWrap(1, BIGDECIMAL_COMPONENT_FIGURES * (y_figs + block_figs));
+ BDVALUE div_result = NewZeroWrap(1, BIGDECIMAL_COMPONENT_FIGURES * (num_blocks * block_figs + 1));
+ BDVALUE bdx = GetBDValueMust(x);
+
+ VALUE mod = BigDecimal_fix(BigDecimal_decimal_shift(x, SSIZET2NUM(-(ssize_t)(num_blocks * block_digits))));
+ for (ssize_t i = (ssize_t)(num_blocks - 1); i >= 0; i--) {
+ memset(divident.real->frac, 0, (y_figs + block_figs) * sizeof(DECDIG));
+
+ BDVALUE bdmod = GetBDValueMust(mod);
+ slice_copy(divident.real->frac, bdmod.real, 0, y_figs);
+ slice_copy(divident.real->frac + y_figs, bdx.real, (size_t)i * block_figs, block_figs);
+ RB_GC_GUARD(bdmod.bigdecimal);
+
+ VpSetSign(divident.real, 1);
+ divident.real->exponent = (ssize_t)(y_figs + block_figs);
+ divident.real->Prec = y_figs + block_figs;
+ VpNmlz(divident.real);
+
+ VALUE div;
+ divmod_by_inv_mul(divident.bigdecimal, y, yinv, &div, &mod);
+ BDVALUE bddiv = GetBDValueMust(div);
+ slice_copy(div_result.real->frac + (num_blocks - (size_t)i - 1) * block_figs, bddiv.real, 0, block_figs + 1);
+ RB_GC_GUARD(bddiv.bigdecimal);
+ }
+ VpSetSign(div_result.real, 1);
+ div_result.real->exponent = (ssize_t)(num_blocks * block_figs + 1);
+ div_result.real->Prec = num_blocks * block_figs + 1;
+ VpNmlz(div_result.real);
+ RB_GC_GUARD(bdx.bigdecimal);
+ RB_GC_GUARD(divident.bigdecimal);
+ RB_GC_GUARD(div_result.bigdecimal);
+ *div_out = div_result.bigdecimal;
+ *mod_out = mod;
+}
+
+static VALUE
+VpDivdNewtonInner(VALUE args_ptr)
+{
+ Real **args = (Real**)args_ptr;
+ Real *c = args[0], *r = args[1], *a = args[2], *b = args[3];
+ BDVALUE a2, b2, c2, r2;
+ VALUE div, mod, a2_frac = Qnil;
+ size_t div_prec = c->MaxPrec - 1;
+ size_t base_prec = b->Prec;
+
+ a2 = NewZeroWrap(1, a->Prec * BIGDECIMAL_COMPONENT_FIGURES);
+ b2 = NewZeroWrap(1, b->Prec * BIGDECIMAL_COMPONENT_FIGURES);
+ VpAsgn(a2.real, a, 1);
+ VpAsgn(b2.real, b, 1);
+ VpSetSign(a2.real, 1);
+ VpSetSign(b2.real, 1);
+ a2.real->exponent = (ssize_t)(base_prec + div_prec);
+ b2.real->exponent = (ssize_t)base_prec;
+
+ if ((ssize_t)a2.real->Prec > a2.real->exponent) {
+ a2_frac = BigDecimal_frac(a2.bigdecimal);
+ VpMidRound(a2.real, VP_ROUND_DOWN, 0);
+ }
+ divmod_newton(a2.bigdecimal, b2.bigdecimal, &div, &mod);
+ if (a2_frac != Qnil) mod = BigDecimal_add(mod, a2_frac);
+
+ c2 = GetBDValueMust(div);
+ r2 = GetBDValueMust(mod);
+ VpAsgn(c, c2.real, VpGetSign(a) * VpGetSign(b));
+ VpAsgn(r, r2.real, VpGetSign(a));
+ AddExponent(c, a->exponent);
+ AddExponent(c, -b->exponent);
+ AddExponent(c, -(ssize_t)div_prec);
+ AddExponent(r, a->exponent);
+ AddExponent(r, -(ssize_t)(base_prec + div_prec));
+ RB_GC_GUARD(a2.bigdecimal);
+ RB_GC_GUARD(a2.bigdecimal);
+ RB_GC_GUARD(c2.bigdecimal);
+ RB_GC_GUARD(r2.bigdecimal);
+ return Qnil;
+}
+
+static VALUE
+ensure_restore_prec_limit(VALUE limit)
+{
+ VpSetPrecLimit(NUM2SIZET(limit));
+ return Qnil;
+}
+
+static void
+VpDivdNewton(Real *c, Real *r, Real *a, Real *b)
+{
+ Real *args[4] = {c, r, a, b};
+ size_t pl = VpGetPrecLimit();
+ VpSetPrecLimit(0);
+ // Ensure restoring prec limit because some methods used in VpDivdNewtonInner may raise an exception
+ rb_ensure(VpDivdNewtonInner, (VALUE)args, ensure_restore_prec_limit, SIZET2NUM(pl));
+}
diff --git a/vendor/bundle/ruby/3.4.0/gems/bigdecimal-4.1.2/ext/bigdecimal/extconf.rb b/vendor/bundle/ruby/3.4.0/gems/bigdecimal-4.1.2/ext/bigdecimal/extconf.rb
new file mode 100644
index 0000000..0b4baca
--- /dev/null
+++ b/vendor/bundle/ruby/3.4.0/gems/bigdecimal-4.1.2/ext/bigdecimal/extconf.rb
@@ -0,0 +1,63 @@
+# frozen_string_literal: true
+require 'mkmf'
+
+def have_builtin_func(name, check_expr, opt = "", &b)
+ checking_for checking_message(name.funcall_style, nil, opt) do
+ if try_compile(<<SRC, opt, &b)
+int foo;
+int main() { #{check_expr}; return 0; }
+SRC
+ $defs.push(format("-DHAVE_BUILTIN_%s", name.tr_cpp))
+ true
+ else
+ false
+ end
+ end
+end
+
+have_builtin_func("__builtin_clz", "__builtin_clz(0)")
+have_builtin_func("__builtin_clzl", "__builtin_clzl(0)")
+have_builtin_func("__builtin_clzll", "__builtin_clzll(0)")
+
+have_header("float.h")
+have_header("math.h")
+have_header("stdbool.h")
+have_header("stdlib.h")
+
+if have_header("x86intrin.h")
+ have_func("_lzcnt_u32", "x86intrin.h")
+ have_func("_lzcnt_u64", "x86intrin.h")
+end
+
+if have_header("intrin.h")
+ have_func("__lzcnt", "intrin.h")
+ have_func("__lzcnt64", "intrin.h")
+ have_func("_BitScanReverse", "intrin.h")
+ have_func("_BitScanReverse64", "intrin.h")
+end
+
+have_header("ruby/atomic.h")
+have_header("ruby/internal/has/builtin.h")
+have_header("ruby/internal/static_assert.h")
+
+have_func("rb_complex_real", "ruby.h")
+have_func("rb_complex_imag", "ruby.h")
+have_func("rb_opts_exception_p", "ruby.h")
+have_func("rb_category_warn", "ruby.h")
+have_const("RB_WARN_CATEGORY_DEPRECATED", "ruby.h")
+
+if RUBY_ENGINE == "ruby"
+ have_const("RUBY_TYPED_EMBEDDABLE", "ruby.h") # RUBY_VERSION >= 3.3
+end
+
+if File.file?(File.expand_path('../lib/bigdecimal.rb', __FILE__))
+ bigdecimal_rb = "$(srcdir)/lib/bigdecimal.rb"
+else
+ bigdecimal_rb = "$(srcdir)/../../lib/bigdecimal.rb"
+end
+
+$defs.push '-DBIGDECIMAL_USE_VP_TEST_METHODS' if ENV['BIGDECIMAL_USE_VP_TEST_METHODS'] == 'true'
+
+create_makefile('bigdecimal') {|mf|
+ mf << "BIGDECIMAL_RB = #{bigdecimal_rb}\n"
+}
diff --git a/vendor/bundle/ruby/3.4.0/gems/bigdecimal-4.1.2/ext/bigdecimal/feature.h b/vendor/bundle/ruby/3.4.0/gems/bigdecimal-4.1.2/ext/bigdecimal/feature.h
new file mode 100644
index 0000000..f628514
--- /dev/null
+++ b/vendor/bundle/ruby/3.4.0/gems/bigdecimal-4.1.2/ext/bigdecimal/feature.h
@@ -0,0 +1,68 @@
+#ifndef BIGDECIMAL_HAS_FEATURE_H
+#define BIGDECIMAL_HAS_FEATURE_H
+
+/* ======== __has_feature ======== */
+
+#ifndef __has_feature
+# define __has_feature(_) 0
+#endif
+
+/* ======== __has_extension ======== */
+
+#ifndef __has_extension
+# define __has_extension __has_feature
+#endif
+
+/* ======== __has_builtin ======== */
+
+#ifdef HAVE_RUBY_INTERNAL_HAS_BUILTIN_H
+# include <ruby/internal/has/builtin.h>
+#endif
+
+#ifdef RBIMPL_HAS_BUILTIN
+# define BIGDECIMAL_HAS_BUILTIN(...) RBIMPL_HAS_BUILTIN(__VA_ARGS__)
+
+#else
+# /* The following section is copied from CRuby's builtin.h */
+#
+# ifdef __has_builtin
+# if defined(__INTEL_COMPILER)
+# /* :TODO: Intel C Compiler has __has_builtin (since 19.1 maybe?), and is
+# * reportedly broken. We have to skip them. However the situation can
+# * change. They might improve someday. We need to revisit here later. */
+# elif defined(__GNUC__) && ! __has_builtin(__builtin_alloca)
+# /* FreeBSD's <sys/cdefs.h> defines its own *broken* version of
+# * __has_builtin. Cygwin copied that content to be a victim of the
+# * broken-ness. We don't take them into account. */
+# else
+# define HAVE___HAS_BUILTIN 1
+# endif
+# endif
+#
+# if defined(HAVE___HAS_BUILTIN)
+# define BIGDECIMAL_HAS_BUILTIN(_) __has_builtin(_)
+#
+# elif defined(__GNUC__)
+# define BIGDECIMAL_HAS_BUILTIN(_) BIGDECIMAL_HAS_BUILTIN_ ## _
+# if defined(__GNUC__) && (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 6))
+# define BIGDECIMAL_HAS_BUILTIN___builtin_clz 1
+# define BIGDECIMAL_HAS_BUILTIN___builtin_clzl 1
+# else
+# define BIGDECIMAL_HAS_BUILTIN___builtin_clz 0
+# define BIGDECIMAL_HAS_BUILTIN___builtin_clzl 0
+# endif
+# elif defined(_MSC_VER)
+# define BIGDECIMAL_HAS_BUILTIN(_) 0
+#
+# else
+# define BIGDECIMAL_HAS_BUILTIN(_) BIGDECIMAL_HAS_BUILTIN_ ## _
+# define BIGDECIMAL_HAS_BUILTIN___builtin_clz HAVE_BUILTIN___BUILTIN_CLZ
+# define BIGDECIMAL_HAS_BUILTIN___builtin_clzl HAVE_BUILTIN___BUILTIN_CLZL
+# endif
+#endif /* RBIMPL_HAS_BUILTIN */
+
+#ifndef __has_builtin
+# define __has_builtin(...) BIGDECIMAL_HAS_BUILTIN(__VA_ARGS__)
+#endif
+
+#endif /* BIGDECIMAL_HAS_FEATURE_H */
diff --git a/vendor/bundle/ruby/3.4.0/gems/bigdecimal-4.1.2/ext/bigdecimal/missing.c b/vendor/bundle/ruby/3.4.0/gems/bigdecimal-4.1.2/ext/bigdecimal/missing.c
new file mode 100644
index 0000000..1454c28
--- /dev/null
+++ b/vendor/bundle/ruby/3.4.0/gems/bigdecimal-4.1.2/ext/bigdecimal/missing.c
@@ -0,0 +1,28 @@
+#include <ruby/ruby.h>
+
+#ifdef HAVE_RUBY_ATOMIC_H
+# include <ruby/atomic.h>
+#endif
+
+#ifdef RUBY_ATOMIC_PTR_CAS
+# define ATOMIC_PTR_CAS(var, old, new) RUBY_ATOMIC_PTR_CAS(var, old, new)
+#endif
+
+#if defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6))
+/* GCC warns about unknown sanitizer, which is annoying. */
+# undef NO_SANITIZE
+# define NO_SANITIZE(x, y) \
+ _Pragma("GCC diagnostic push") \
+ _Pragma("GCC diagnostic ignored \"-Wattributes\"") \
+ __attribute__((__no_sanitize__(x))) y; \
+ _Pragma("GCC diagnostic pop") \
+ y
+#endif
+
+#undef strtod
+#define strtod BigDecimal_strtod
+#undef dtoa
+#define dtoa BigDecimal_dtoa
+#undef hdtoa
+#define hdtoa BigDecimal_hdtoa
+#include "missing/dtoa.c"
diff --git a/vendor/bundle/ruby/3.4.0/gems/bigdecimal-4.1.2/ext/bigdecimal/missing.h b/vendor/bundle/ruby/3.4.0/gems/bigdecimal-4.1.2/ext/bigdecimal/missing.h
new file mode 100644
index 0000000..437d5bf
--- /dev/null
+++ b/vendor/bundle/ruby/3.4.0/gems/bigdecimal-4.1.2/ext/bigdecimal/missing.h
@@ -0,0 +1,106 @@
+#ifndef MISSING_H
+#define MISSING_H 1
+
+#if defined(__cplusplus)
+extern "C" {
+#if 0
+} /* satisfy cc-mode */
+#endif
+#endif
+
+#ifndef RB_UNUSED_VAR
+# if defined(_MSC_VER) && _MSC_VER >= 1911
+# define RB_UNUSED_VAR(x) x [[maybe_unused]]
+
+# elif defined(__has_cpp_attribute) && __has_cpp_attribute(maybe_unused)
+# define RB_UNUSED_VAR(x) x [[maybe_unused]]
+
+# elif defined(__has_c_attribute) && __has_c_attribute(maybe_unused)
+# define RB_UNUSED_VAR(x) x [[maybe_unused]]
+
+# elif defined(__GNUC__)
+# define RB_UNUSED_VAR(x) x __attribute__ ((unused))
+
+# else
+# define RB_UNUSED_VAR(x) x
+# endif
+#endif /* RB_UNUSED_VAR */
+
+#if defined(_MSC_VER) && _MSC_VER >= 1310
+# define HAVE___ASSUME 1
+
+#elif defined(__INTEL_COMPILER) && __INTEL_COMPILER >= 1300
+# define HAVE___ASSUME 1
+#endif
+
+#ifndef UNREACHABLE
+# if __has_builtin(__builtin_unreachable)
+# define UNREACHABLE __builtin_unreachable()
+
+# elif defined(HAVE___ASSUME)
+# define UNREACHABLE __assume(0)
+
+# else
+# define UNREACHABLE /* unreachable */
+# endif
+#endif /* UNREACHABLE */
+
+/* bool */
+
+#ifndef __bool_true_false_are_defined
+# include <stdbool.h>
+#endif
+
+/* dtoa */
+char *BigDecimal_dtoa(double d_, int mode, int ndigits, int *decpt, int *sign, char **rve);
+
+/* complex */
+
+#ifndef HAVE_RB_COMPLEX_REAL
+static inline VALUE
+rb_complex_real_fallback(VALUE cmp)
+{
+#ifdef RCOMPLEX
+ return RCOMPLEX(cmp)->real;
+#else
+ return rb_funcall(cmp, rb_intern("real"), 0);
+#endif
+}
+#define rb_complex_real rb_complex_real_fallback
+#endif
+
+#ifndef HAVE_RB_COMPLEX_IMAG
+static inline VALUE
+rb_complex_imag_fallback(VALUE cmp)
+{
+# ifdef RCOMPLEX
+ return RCOMPLEX(cmp)->imag;
+# else
+ return rb_funcall(cmp, rb_intern("imag"), 0);
+# endif
+}
+#define rb_complex_imag rb_complex_imag_fallback
+#endif
+
+/* st */
+
+#ifndef ST2FIX
+# undef RB_ST2FIX
+# define RB_ST2FIX(h) LONG2FIX((long)(h))
+# define ST2FIX(h) RB_ST2FIX(h)
+#endif
+
+/* warning */
+
+#if !defined(HAVE_RB_CATEGORY_WARN) || !defined(HAVE_CONST_RB_WARN_CATEGORY_DEPRECATED)
+# define rb_category_warn(category, ...) rb_warn(__VA_ARGS__)
+#endif
+
+#if defined(__cplusplus)
+#if 0
+{ /* satisfy cc-mode */
+#endif
+} /* extern "C" { */
+#endif
+
+#endif /* MISSING_H */
diff --git a/vendor/bundle/ruby/3.4.0/gems/bigdecimal-4.1.2/ext/bigdecimal/missing/dtoa.c b/vendor/bundle/ruby/3.4.0/gems/bigdecimal-4.1.2/ext/bigdecimal/missing/dtoa.c
new file mode 100644
index 0000000..ba8cd46
--- /dev/null
+++ b/vendor/bundle/ruby/3.4.0/gems/bigdecimal-4.1.2/ext/bigdecimal/missing/dtoa.c
@@ -0,0 +1,3509 @@
+/****************************************************************
+ *
+ * The author of this software is David M. Gay.
+ *
+ * Copyright (c) 1991, 2000, 2001 by Lucent Technologies.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ *
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY. IN PARTICULAR, NEITHER THE AUTHOR NOR LUCENT MAKES ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ *
+ ***************************************************************/
+
+/* Please send bug reports to David M. Gay (dmg at acm dot org,
+ * with " at " changed at "@" and " dot " changed to "."). */
+
+/* On a machine with IEEE extended-precision registers, it is
+ * necessary to specify double-precision (53-bit) rounding precision
+ * before invoking strtod or dtoa. If the machine uses (the equivalent
+ * of) Intel 80x87 arithmetic, the call
+ * _control87(PC_53, MCW_PC);
+ * does this with many compilers. Whether this or another call is
+ * appropriate depends on the compiler; for this to work, it may be
+ * necessary to #include "float.h" or another system-dependent header
+ * file.
+ */
+
+/* strtod for IEEE-, VAX-, and IBM-arithmetic machines.
+ *
+ * This strtod returns a nearest machine number to the input decimal
+ * string (or sets errno to ERANGE). With IEEE arithmetic, ties are
+ * broken by the IEEE round-even rule. Otherwise ties are broken by
+ * biased rounding (add half and chop).
+ *
+ * Inspired loosely by William D. Clinger's paper "How to Read Floating
+ * Point Numbers Accurately" [Proc. ACM SIGPLAN '90, pp. 92-101].
+ *
+ * Modifications:
+ *
+ * 1. We only require IEEE, IBM, or VAX double-precision
+ * arithmetic (not IEEE double-extended).
+ * 2. We get by with floating-point arithmetic in a case that
+ * Clinger missed -- when we're computing d * 10^n
+ * for a small integer d and the integer n is not too
+ * much larger than 22 (the maximum integer k for which
+ * we can represent 10^k exactly), we may be able to
+ * compute (d*10^k) * 10^(e-k) with just one roundoff.
+ * 3. Rather than a bit-at-a-time adjustment of the binary
+ * result in the hard case, we use floating-point
+ * arithmetic to determine the adjustment to within
+ * one bit; only in really hard cases do we need to
+ * compute a second residual.
+ * 4. Because of 3., we don't need a large table of powers of 10
+ * for ten-to-e (just some small tables, e.g. of 10^k
+ * for 0 <= k <= 22).
+ */
+
+/*
+ * #define IEEE_LITTLE_ENDIAN for IEEE-arithmetic machines where the least
+ * significant byte has the lowest address.
+ * #define IEEE_BIG_ENDIAN for IEEE-arithmetic machines where the most
+ * significant byte has the lowest address.
+ * #define Long int on machines with 32-bit ints and 64-bit longs.
+ * #define IBM for IBM mainframe-style floating-point arithmetic.
+ * #define VAX for VAX-style floating-point arithmetic (D_floating).
+ * #define No_leftright to omit left-right logic in fast floating-point
+ * computation of dtoa.
+ * #define Honor_FLT_ROUNDS if FLT_ROUNDS can assume the values 2 or 3
+ * and strtod and dtoa should round accordingly.
+ * #define Check_FLT_ROUNDS if FLT_ROUNDS can assume the values 2 or 3
+ * and Honor_FLT_ROUNDS is not #defined.
+ * #define RND_PRODQUOT to use rnd_prod and rnd_quot (assembly routines
+ * that use extended-precision instructions to compute rounded
+ * products and quotients) with IBM.
+ * #define ROUND_BIASED for IEEE-format with biased rounding.
+ * #define Inaccurate_Divide for IEEE-format with correctly rounded
+ * products but inaccurate quotients, e.g., for Intel i860.
+ * #define NO_LONG_LONG on machines that do not have a "long long"
+ * integer type (of >= 64 bits). On such machines, you can
+ * #define Just_16 to store 16 bits per 32-bit Long when doing
+ * high-precision integer arithmetic. Whether this speeds things
+ * up or slows things down depends on the machine and the number
+ * being converted. If long long is available and the name is
+ * something other than "long long", #define Llong to be the name,
+ * and if "unsigned Llong" does not work as an unsigned version of
+ * Llong, #define #ULLong to be the corresponding unsigned type.
+ * #define KR_headers for old-style C function headers.
+ * #define Bad_float_h if your system lacks a float.h or if it does not
+ * define some or all of DBL_DIG, DBL_MAX_10_EXP, DBL_MAX_EXP,
+ * FLT_RADIX, FLT_ROUNDS, and DBL_MAX.
+ * #define MALLOC your_malloc, where your_malloc(n) acts like malloc(n)
+ * if memory is available and otherwise does something you deem
+ * appropriate. If MALLOC is undefined, malloc will be invoked
+ * directly -- and assumed always to succeed.
+ * #define INFNAN_CHECK on IEEE systems to cause strtod to check for
+ * Infinity and NaN (case insensitively). On some systems (e.g.,
+ * some HP systems), it may be necessary to #define NAN_WORD0
+ * appropriately -- to the most significant word of a quiet NaN.
+ * (On HP Series 700/800 machines, -DNAN_WORD0=0x7ff40000 works.)
+ * When INFNAN_CHECK is #defined and No_Hex_NaN is not #defined,
+ * strtod also accepts (case insensitively) strings of the form
+ * NaN(x), where x is a string of hexadecimal digits and spaces;
+ * if there is only one string of hexadecimal digits, it is taken
+ * for the 52 fraction bits of the resulting NaN; if there are two
+ * or more strings of hex digits, the first is for the high 20 bits,
+ * the second and subsequent for the low 32 bits, with intervening
+ * white space ignored; but if this results in none of the 52
+ * fraction bits being on (an IEEE Infinity symbol), then NAN_WORD0
+ * and NAN_WORD1 are used instead.
+ * #define MULTIPLE_THREADS if the system offers preemptively scheduled
+ * multiple threads. In this case, you must provide (or suitably
+ * #define) two locks, acquired by ACQUIRE_DTOA_LOCK(n) and freed
+ * by FREE_DTOA_LOCK(n) for n = 0 or 1. (The second lock, accessed
+ * in pow5mult, ensures lazy evaluation of only one copy of high
+ * powers of 5; omitting this lock would introduce a small
+ * probability of wasting memory, but would otherwise be harmless.)
+ * You must also invoke freedtoa(s) to free the value s returned by
+ * dtoa. You may do so whether or not MULTIPLE_THREADS is #defined.
+ * #define NO_IEEE_Scale to disable new (Feb. 1997) logic in strtod that
+ * avoids underflows on inputs whose result does not underflow.
+ * If you #define NO_IEEE_Scale on a machine that uses IEEE-format
+ * floating-point numbers and flushes underflows to zero rather
+ * than implementing gradual underflow, then you must also #define
+ * Sudden_Underflow.
+ * #define YES_ALIAS to permit aliasing certain double values with
+ * arrays of ULongs. This leads to slightly better code with
+ * some compilers and was always used prior to 19990916, but it
+ * is not strictly legal and can cause trouble with aggressively
+ * optimizing compilers (e.g., gcc 2.95.1 under -O2).
+ * #define USE_LOCALE to use the current locale's decimal_point value.
+ * #define SET_INEXACT if IEEE arithmetic is being used and extra
+ * computation should be done to set the inexact flag when the
+ * result is inexact and avoid setting inexact when the result
+ * is exact. In this case, dtoa.c must be compiled in
+ * an environment, perhaps provided by #include "dtoa.c" in a
+ * suitable wrapper, that defines two functions,
+ * int get_inexact(void);
+ * void clear_inexact(void);
+ * such that get_inexact() returns a nonzero value if the
+ * inexact bit is already set, and clear_inexact() sets the
+ * inexact bit to 0. When SET_INEXACT is #defined, strtod
+ * also does extra computations to set the underflow and overflow
+ * flags when appropriate (i.e., when the result is tiny and
+ * inexact or when it is a numeric value rounded to +-infinity).
+ * #define NO_ERRNO if strtod should not assign errno = ERANGE when
+ * the result overflows to +-Infinity or underflows to 0.
+ */
+
+#ifdef WORDS_BIGENDIAN
+#define IEEE_BIG_ENDIAN
+#else
+#define IEEE_LITTLE_ENDIAN
+#endif
+
+#ifdef __vax__
+#define VAX
+#undef IEEE_BIG_ENDIAN
+#undef IEEE_LITTLE_ENDIAN
+#endif
+
+#if defined(__arm__) && !defined(__VFP_FP__)
+#define IEEE_BIG_ENDIAN
+#undef IEEE_LITTLE_ENDIAN
+#endif
+
+#undef Long
+#undef ULong
+
+#include <assert.h>
+#include <limits.h>
+#include <stddef.h>
+#include <stdint.h>
+
+#if (INT_MAX >> 30) && !(INT_MAX >> 31)
+#define Long int
+#define ULong unsigned int
+#elif (LONG_MAX >> 30) && !(LONG_MAX >> 31)
+#define Long long int
+#define ULong unsigned long int
+#else
+#error No 32bit integer
+#endif
+
+#if defined(HAVE_LONG_LONG) && (HAVE_LONG_LONG)
+#define Llong LONG_LONG
+#else
+#define NO_LONG_LONG
+#endif
+
+#ifdef DEBUG
+#include <stdio.h>
+#define Bug(x) {fprintf(stderr, "%s\n", (x)); exit(EXIT_FAILURE);}
+#endif
+
+#ifndef ISDIGIT
+#include <ctype.h>
+#define ISDIGIT(c) isdigit(c)
+#endif
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifdef USE_LOCALE
+#include <locale.h>
+#endif
+
+#if defined(HAVE_STDCKDINT_H) || !defined(__has_include)
+#elif __has_include(<stdckdint.h>)
+# define HAVE_STDCKDINT_H 1
+#endif
+#ifdef HAVE_STDCKDINT_H
+# include <stdckdint.h>
+#endif
+
+#if !defined(ckd_add)
+static inline int /* bool */
+ckd_add(int *result, int x, int y)
+{
+ if (x < 0) {
+ if (y < INT_MIN - x) return 1;
+ }
+ else if (x > 0) {
+ if (y > INT_MAX - x) return 1;
+ }
+ *result = x + y;
+ return 0;
+}
+#endif
+
+#ifdef MALLOC
+extern void *MALLOC(size_t);
+#else
+#define MALLOC malloc
+#endif
+#ifdef FREE
+extern void FREE(void*);
+#else
+#define FREE free
+#endif
+#ifndef NO_SANITIZE
+#define NO_SANITIZE(x, y) y
+#endif
+
+#undef IEEE_Arith
+#undef Avoid_Underflow
+#ifdef IEEE_BIG_ENDIAN
+#define IEEE_Arith
+#endif
+#ifdef IEEE_LITTLE_ENDIAN
+#define IEEE_Arith
+#endif
+
+#ifdef Bad_float_h
+
+#ifdef IEEE_Arith
+#define DBL_DIG 15
+#define DBL_MAX_10_EXP 308
+#define DBL_MAX_EXP 1024
+#define FLT_RADIX 2
+#endif /*IEEE_Arith*/
+
+#ifdef IBM
+#define DBL_DIG 16
+#define DBL_MAX_10_EXP 75
+#define DBL_MAX_EXP 63
+#define FLT_RADIX 16
+#define DBL_MAX 7.2370055773322621e+75
+#endif
+
+#ifdef VAX
+#define DBL_DIG 16
+#define DBL_MAX_10_EXP 38
+#define DBL_MAX_EXP 127
+#define FLT_RADIX 2
+#define DBL_MAX 1.7014118346046923e+38
+#endif
+
+#ifndef LONG_MAX
+#define LONG_MAX 2147483647
+#endif
+
+#else /* ifndef Bad_float_h */
+#include <float.h>
+#endif /* Bad_float_h */
+
+#include <math.h>
+
+#ifdef __cplusplus
+extern "C" {
+#if 0
+} /* satisfy cc-mode */
+#endif
+#endif
+
+#ifndef hexdigit
+static const char hexdigit[] = "0123456789abcdef0123456789ABCDEF";
+#endif
+
+#if defined(IEEE_LITTLE_ENDIAN) + defined(IEEE_BIG_ENDIAN) + defined(VAX) + defined(IBM) != 1
+Exactly one of IEEE_LITTLE_ENDIAN, IEEE_BIG_ENDIAN, VAX, or IBM should be defined.
+#endif
+
+typedef union { double d; ULong L[2]; } U;
+
+#ifdef YES_ALIAS
+typedef double double_u;
+# define dval(x) (x)
+# ifdef IEEE_LITTLE_ENDIAN
+# define word0(x) (((ULong *)&(x))[1])
+# define word1(x) (((ULong *)&(x))[0])
+# else
+# define word0(x) (((ULong *)&(x))[0])
+# define word1(x) (((ULong *)&(x))[1])
+# endif
+#else
+typedef U double_u;
+# ifdef IEEE_LITTLE_ENDIAN
+# define word0(x) ((x).L[1])
+# define word1(x) ((x).L[0])
+# else
+# define word0(x) ((x).L[0])
+# define word1(x) ((x).L[1])
+# endif
+# define dval(x) ((x).d)
+#endif
+
+/* The following definition of Storeinc is appropriate for MIPS processors.
+ * An alternative that might be better on some machines is
+ * #define Storeinc(a,b,c) (*a++ = b << 16 | c & 0xffff)
+ */
+#if defined(IEEE_LITTLE_ENDIAN) + defined(VAX) + defined(__arm__)
+#define Storeinc(a,b,c) (((unsigned short *)(a))[1] = (unsigned short)(b), \
+((unsigned short *)(a))[0] = (unsigned short)(c), (a)++)
+#else
+#define Storeinc(a,b,c) (((unsigned short *)(a))[0] = (unsigned short)(b), \
+((unsigned short *)(a))[1] = (unsigned short)(c), (a)++)
+#endif
+
+/* #define P DBL_MANT_DIG */
+/* Ten_pmax = floor(P*log(2)/log(5)) */
+/* Bletch = (highest power of 2 < DBL_MAX_10_EXP) / 16 */
+/* Quick_max = floor((P-1)*log(FLT_RADIX)/log(10) - 1) */
+/* Int_max = floor(P*log(FLT_RADIX)/log(10) - 1) */
+
+#ifdef IEEE_Arith
+#define Exp_shift 20
+#define Exp_shift1 20
+#define Exp_msk1 0x100000
+#define Exp_msk11 0x100000
+#define Exp_mask 0x7ff00000
+#define P 53
+#define Bias 1023
+#define Emin (-1022)
+#define Exp_1 0x3ff00000
+#define Exp_11 0x3ff00000
+#define Ebits 11
+#define Frac_mask 0xfffff
+#define Frac_mask1 0xfffff
+#define Ten_pmax 22
+#define Bletch 0x10
+#define Bndry_mask 0xfffff
+#define Bndry_mask1 0xfffff
+#define LSB 1
+#define Sign_bit 0x80000000
+#define Log2P 1
+#define Tiny0 0
+#define Tiny1 1
+#define Quick_max 14
+#define Int_max 14
+#ifndef NO_IEEE_Scale
+#define Avoid_Underflow
+#ifdef Flush_Denorm /* debugging option */
+#undef Sudden_Underflow
+#endif
+#endif
+
+#ifndef Flt_Rounds
+#ifdef FLT_ROUNDS
+#define Flt_Rounds FLT_ROUNDS
+#else
+#define Flt_Rounds 1
+#endif
+#endif /*Flt_Rounds*/
+
+#ifdef Honor_FLT_ROUNDS
+#define Rounding rounding
+#undef Check_FLT_ROUNDS
+#define Check_FLT_ROUNDS
+#else
+#define Rounding Flt_Rounds
+#endif
+
+#else /* ifndef IEEE_Arith */
+#undef Check_FLT_ROUNDS
+#undef Honor_FLT_ROUNDS
+#undef SET_INEXACT
+#undef Sudden_Underflow
+#define Sudden_Underflow
+#ifdef IBM
+#undef Flt_Rounds
+#define Flt_Rounds 0
+#define Exp_shift 24
+#define Exp_shift1 24
+#define Exp_msk1 0x1000000
+#define Exp_msk11 0x1000000
+#define Exp_mask 0x7f000000
+#define P 14
+#define Bias 65
+#define Exp_1 0x41000000
+#define Exp_11 0x41000000
+#define Ebits 8 /* exponent has 7 bits, but 8 is the right value in b2d */
+#define Frac_mask 0xffffff
+#define Frac_mask1 0xffffff
+#define Bletch 4
+#define Ten_pmax 22
+#define Bndry_mask 0xefffff
+#define Bndry_mask1 0xffffff
+#define LSB 1
+#define Sign_bit 0x80000000
+#define Log2P 4
+#define Tiny0 0x100000
+#define Tiny1 0
+#define Quick_max 14
+#define Int_max 15
+#else /* VAX */
+#undef Flt_Rounds
+#define Flt_Rounds 1
+#define Exp_shift 23
+#define Exp_shift1 7
+#define Exp_msk1 0x80
+#define Exp_msk11 0x800000
+#define Exp_mask 0x7f80
+#define P 56
+#define Bias 129
+#define Exp_1 0x40800000
+#define Exp_11 0x4080
+#define Ebits 8
+#define Frac_mask 0x7fffff
+#define Frac_mask1 0xffff007f
+#define Ten_pmax 24
+#define Bletch 2
+#define Bndry_mask 0xffff007f
+#define Bndry_mask1 0xffff007f
+#define LSB 0x10000
+#define Sign_bit 0x8000
+#define Log2P 1
+#define Tiny0 0x80
+#define Tiny1 0
+#define Quick_max 15
+#define Int_max 15
+#endif /* IBM, VAX */
+#endif /* IEEE_Arith */
+
+#ifndef IEEE_Arith
+#define ROUND_BIASED
+#endif
+
+#ifdef RND_PRODQUOT
+#define rounded_product(a,b) ((a) = rnd_prod((a), (b)))
+#define rounded_quotient(a,b) ((a) = rnd_quot((a), (b)))
+extern double rnd_prod(double, double), rnd_quot(double, double);
+#else
+#define rounded_product(a,b) ((a) *= (b))
+#define rounded_quotient(a,b) ((a) /= (b))
+#endif
+
+#define Big0 (Frac_mask1 | Exp_msk1*(DBL_MAX_EXP+Bias-1))
+#define Big1 0xffffffff
+
+#ifndef Pack_32
+#define Pack_32
+#endif
+
+#define FFFFFFFF 0xffffffffUL
+
+#ifdef NO_LONG_LONG
+#undef ULLong
+#ifdef Just_16
+#undef Pack_32
+/* When Pack_32 is not defined, we store 16 bits per 32-bit Long.
+ * This makes some inner loops simpler and sometimes saves work
+ * during multiplications, but it often seems to make things slightly
+ * slower. Hence the default is now to store 32 bits per Long.
+ */
+#endif
+#else /* long long available */
+#ifndef Llong
+#define Llong long long
+#endif
+#ifndef ULLong
+#define ULLong unsigned Llong
+#endif
+#endif /* NO_LONG_LONG */
+
+#define MULTIPLE_THREADS 1
+
+#ifndef MULTIPLE_THREADS
+#define ACQUIRE_DTOA_LOCK(n) /*nothing*/
+#define FREE_DTOA_LOCK(n) /*nothing*/
+#else
+#define ACQUIRE_DTOA_LOCK(n) /*unused right now*/
+#define FREE_DTOA_LOCK(n) /*unused right now*/
+#endif
+
+#ifndef ATOMIC_PTR_CAS
+#define ATOMIC_PTR_CAS(var, old, new) ((var) = (new), (void *)(old))
+#endif
+#ifndef LIKELY
+#define LIKELY(x) (x)
+#endif
+#ifndef UNLIKELY
+#define UNLIKELY(x) (x)
+#endif
+#ifndef ASSUME
+#define ASSUME(x) (void)(x)
+#endif
+
+#define Kmax 15
+
+struct Bigint {
+ struct Bigint *next;
+ int k, maxwds, sign, wds;
+ ULong x[1];
+};
+
+typedef struct Bigint Bigint;
+
+static Bigint *
+Balloc(int k)
+{
+ int x;
+ Bigint *rv;
+
+ x = 1 << k;
+ rv = (Bigint *)MALLOC(sizeof(Bigint) + (x-1)*sizeof(ULong));
+ if (!rv) return NULL;
+ rv->k = k;
+ rv->maxwds = x;
+ rv->sign = rv->wds = 0;
+ return rv;
+}
+
+static void
+Bclear(Bigint **vp)
+{
+ Bigint *v = *vp;
+ *vp = NULL;
+ if (v) FREE(v);
+}
+#define Bfree(v) Bclear(&(v))
+
+#define Bcopy(x,y) memcpy((char *)&(x)->sign, (char *)&(y)->sign, \
+(y)->wds*sizeof(Long) + 2*sizeof(int))
+
+static Bigint *
+multadd(Bigint *b, int m, int a) /* multiply by m and add a */
+{
+ int i, wds;
+ ULong *x;
+#ifdef ULLong
+ ULLong carry, y;
+#else
+ ULong carry, y;
+#ifdef Pack_32
+ ULong xi, z;
+#endif
+#endif
+ Bigint *b1;
+
+ wds = b->wds;
+ x = b->x;
+ i = 0;
+ carry = a;
+ do {
+#ifdef ULLong
+ y = *x * (ULLong)m + carry;
+ carry = y >> 32;
+ *x++ = (ULong)(y & FFFFFFFF);
+#else
+#ifdef Pack_32
+ xi = *x;
+ y = (xi & 0xffff) * m + carry;
+ z = (xi >> 16) * m + (y >> 16);
+ carry = z >> 16;
+ *x++ = (z << 16) + (y & 0xffff);
+#else
+ y = *x * m + carry;
+ carry = y >> 16;
+ *x++ = y & 0xffff;
+#endif
+#endif
+ } while (++i < wds);
+ if (carry) {
+ if (wds >= b->maxwds) {
+ b1 = Balloc(b->k+1);
+ if (!b1) {
+ Bfree(b);
+ return NULL;
+ }
+ Bcopy(b1, b);
+ Bfree(b);
+ b = b1;
+ }
+ b->x[wds++] = (ULong)carry;
+ b->wds = wds;
+ }
+ return b;
+}
+
+static Bigint *
+s2b(const char *s, int nd0, int nd, ULong y9)
+{
+ Bigint *b;
+ int i, k;
+ Long x, y;
+
+ x = (nd + 8) / 9;
+ for (k = 0, y = 1; x > y; y <<= 1, k++) ;
+#ifdef Pack_32
+ b = Balloc(k);
+ if (!b) return NULL;
+ b->x[0] = y9;
+ b->wds = 1;
+#else
+ b = Balloc(k+1);
+ if (!b) return NULL;
+ b->x[0] = y9 & 0xffff;
+ b->wds = (b->x[1] = y9 >> 16) ? 2 : 1;
+#endif
+
+ i = 9;
+ if (9 < nd0) {
+ s += 9;
+ do {
+ b = multadd(b, 10, *s++ - '0');
+ if (!b) return NULL;
+ } while (++i < nd0);
+ s++;
+ }
+ else
+ s += 10;
+ for (; i < nd; i++) {
+ b = multadd(b, 10, *s++ - '0');
+ if (!b) return NULL;
+ }
+ return b;
+}
+
+static int
+hi0bits(register ULong x)
+{
+ register int k = 0;
+
+ if (!(x & 0xffff0000)) {
+ k = 16;
+ x <<= 16;
+ }
+ if (!(x & 0xff000000)) {
+ k += 8;
+ x <<= 8;
+ }
+ if (!(x & 0xf0000000)) {
+ k += 4;
+ x <<= 4;
+ }
+ if (!(x & 0xc0000000)) {
+ k += 2;
+ x <<= 2;
+ }
+ if (!(x & 0x80000000)) {
+ k++;
+ if (!(x & 0x40000000))
+ return 32;
+ }
+ return k;
+}
+
+static int
+lo0bits(ULong *y)
+{
+ register int k;
+ register ULong x = *y;
+
+ if (x & 7) {
+ if (x & 1)
+ return 0;
+ if (x & 2) {
+ *y = x >> 1;
+ return 1;
+ }
+ *y = x >> 2;
+ return 2;
+ }
+ k = 0;
+ if (!(x & 0xffff)) {
+ k = 16;
+ x >>= 16;
+ }
+ if (!(x & 0xff)) {
+ k += 8;
+ x >>= 8;
+ }
+ if (!(x & 0xf)) {
+ k += 4;
+ x >>= 4;
+ }
+ if (!(x & 0x3)) {
+ k += 2;
+ x >>= 2;
+ }
+ if (!(x & 1)) {
+ k++;
+ x >>= 1;
+ if (!x)
+ return 32;
+ }
+ *y = x;
+ return k;
+}
+
+static Bigint *
+i2b(int i)
+{
+ Bigint *b;
+
+ b = Balloc(1);
+ if (!b) return NULL;
+ b->x[0] = i;
+ b->wds = 1;
+ return b;
+}
+
+#define Bzero_p(b) (!(b)->x[0] && (b)->wds <= 1)
+
+static Bigint *
+mult(Bigint *a, Bigint *b)
+{
+ Bigint *c;
+ int k, wa, wb, wc;
+ ULong *x, *xa, *xae, *xb, *xbe, *xc, *xc0;
+ ULong y;
+#ifdef ULLong
+ ULLong carry, z;
+#else
+ ULong carry, z;
+#ifdef Pack_32
+ ULong z2;
+#endif
+#endif
+
+ if (Bzero_p(a) || Bzero_p(b)) {
+ c = Balloc(0);
+ if (!c) return NULL;
+ c->wds = 1;
+ c->x[0] = 0;
+ return c;
+ }
+
+ if (a->wds < b->wds) {
+ c = a;
+ a = b;
+ b = c;
+ }
+ k = a->k;
+ wa = a->wds;
+ wb = b->wds;
+ wc = wa + wb;
+ if (wc > a->maxwds)
+ k++;
+ c = Balloc(k);
+ if (!c) return NULL;
+ for (x = c->x, xa = x + wc; x < xa; x++)
+ *x = 0;
+ xa = a->x;
+ xae = xa + wa;
+ xb = b->x;
+ xbe = xb + wb;
+ xc0 = c->x;
+#ifdef ULLong
+ for (; xb < xbe; xc0++) {
+ if ((y = *xb++) != 0) {
+ x = xa;
+ xc = xc0;
+ carry = 0;
+ do {
+ z = *x++ * (ULLong)y + *xc + carry;
+ carry = z >> 32;
+ *xc++ = (ULong)(z & FFFFFFFF);
+ } while (x < xae);
+ *xc = (ULong)carry;
+ }
+ }
+#else
+#ifdef Pack_32
+ for (; xb < xbe; xb++, xc0++) {
+ if ((y = *xb & 0xffff) != 0) {
+ x = xa;
+ xc = xc0;
+ carry = 0;
+ do {
+ z = (*x & 0xffff) * y + (*xc & 0xffff) + carry;
+ carry = z >> 16;
+ z2 = (*x++ >> 16) * y + (*xc >> 16) + carry;
+ carry = z2 >> 16;
+ Storeinc(xc, z2, z);
+ } while (x < xae);
+ *xc = (ULong)carry;
+ }
+ if ((y = *xb >> 16) != 0) {
+ x = xa;
+ xc = xc0;
+ carry = 0;
+ z2 = *xc;
+ do {
+ z = (*x & 0xffff) * y + (*xc >> 16) + carry;
+ carry = z >> 16;
+ Storeinc(xc, z, z2);
+ z2 = (*x++ >> 16) * y + (*xc & 0xffff) + carry;
+ carry = z2 >> 16;
+ } while (x < xae);
+ *xc = z2;
+ }
+ }
+#else
+ for (; xb < xbe; xc0++) {
+ if (y = *xb++) {
+ x = xa;
+ xc = xc0;
+ carry = 0;
+ do {
+ z = *x++ * y + *xc + carry;
+ carry = z >> 16;
+ *xc++ = z & 0xffff;
+ } while (x < xae);
+ *xc = (ULong)carry;
+ }
+ }
+#endif
+#endif
+ for (xc0 = c->x, xc = xc0 + wc; wc > 0 && !*--xc; --wc) ;
+ c->wds = wc;
+ return c;
+}
+
+static Bigint *p5s;
+
+static Bigint *
+pow5mult(Bigint *b, int k)
+{
+ Bigint *b1, *p5, *p51;
+ int i;
+ static const int p05[3] = { 5, 25, 125 };
+
+ if ((i = k & 3) != 0) {
+ b = multadd(b, p05[i-1], 0);
+ if (!b) return NULL;
+ }
+
+#define b_cache(var, addr, new_expr) \
+ if ((var = addr) != 0) {} else { \
+ Bigint *tmp = 0; \
+ ACQUIRE_DTOA_LOCK(1); \
+ if (!(var = addr) && (var = (new_expr)) != 0) { \
+ var->next = 0; \
+ tmp = ATOMIC_PTR_CAS(addr, NULL, var); \
+ } \
+ FREE_DTOA_LOCK(1); \
+ if (UNLIKELY(tmp)) { \
+ Bfree(var); \
+ var = tmp; \
+ } \
+ else if (!var) { \
+ Bfree(b); \
+ return NULL; \
+ } \
+ }
+
+ if (!(k >>= 2))
+ return b;
+ /* first time */
+ b_cache(p5, p5s, i2b(625));
+ for (;;) {
+ if (k & 1) {
+ b1 = mult(b, p5);
+ Bfree(b);
+ b = b1;
+ if (!b) return NULL;
+ }
+ if (!(k >>= 1))
+ break;
+ b_cache(p51, p5->next, mult(p5, p5));
+ p5 = p51;
+ }
+ return b;
+}
+
+static Bigint *
+lshift(Bigint *b, int k)
+{
+ int i, k1, n, n1;
+ Bigint *b1;
+ ULong *x, *x1, *xe, z;
+
+ if (!k || Bzero_p(b)) return b;
+
+#ifdef Pack_32
+ n = k >> 5;
+#else
+ n = k >> 4;
+#endif
+ k1 = b->k;
+ n1 = n + b->wds + 1;
+ for (i = b->maxwds; n1 > i; i <<= 1)
+ k1++;
+ b1 = Balloc(k1);
+ if (!b1) {
+ Bfree(b);
+ return NULL;
+ }
+ x1 = b1->x;
+ for (i = 0; i < n; i++)
+ *x1++ = 0;
+ x = b->x;
+ xe = x + b->wds;
+#ifdef Pack_32
+ if (k &= 0x1f) {
+ k1 = 32 - k;
+ z = 0;
+ do {
+ *x1++ = *x << k | z;
+ z = *x++ >> k1;
+ } while (x < xe);
+ if ((*x1 = z) != 0)
+ ++n1;
+ }
+#else
+ if (k &= 0xf) {
+ k1 = 16 - k;
+ z = 0;
+ do {
+ *x1++ = *x << k & 0xffff | z;
+ z = *x++ >> k1;
+ } while (x < xe);
+ if (*x1 = z)
+ ++n1;
+ }
+#endif
+ else
+ do {
+ *x1++ = *x++;
+ } while (x < xe);
+ b1->wds = n1 - 1;
+ Bfree(b);
+ return b1;
+}
+
+static int
+cmp(Bigint *a, Bigint *b)
+{
+ ULong *xa, *xa0, *xb, *xb0;
+ int i, j;
+
+ i = a->wds;
+ j = b->wds;
+#ifdef DEBUG
+ if (i > 1 && !a->x[i-1])
+ Bug("cmp called with a->x[a->wds-1] == 0");
+ if (j > 1 && !b->x[j-1])
+ Bug("cmp called with b->x[b->wds-1] == 0");
+#endif
+ if (i -= j)
+ return i;
+ xa0 = a->x;
+ xa = xa0 + j;
+ xb0 = b->x;
+ xb = xb0 + j;
+ for (;;) {
+ if (*--xa != *--xb)
+ return *xa < *xb ? -1 : 1;
+ if (xa <= xa0)
+ break;
+ }
+ return 0;
+}
+
+NO_SANITIZE("unsigned-integer-overflow", static Bigint * diff(Bigint *a, Bigint *b));
+static Bigint *
+diff(Bigint *a, Bigint *b)
+{
+ Bigint *c;
+ int i, wa, wb;
+ ULong *xa, *xae, *xb, *xbe, *xc;
+#ifdef ULLong
+ ULLong borrow, y;
+#else
+ ULong borrow, y;
+#ifdef Pack_32
+ ULong z;
+#endif
+#endif
+
+ i = cmp(a,b);
+ if (!i) {
+ c = Balloc(0);
+ if (!c) return NULL;
+ c->wds = 1;
+ c->x[0] = 0;
+ return c;
+ }
+ if (i < 0) {
+ c = a;
+ a = b;
+ b = c;
+ i = 1;
+ }
+ else
+ i = 0;
+ c = Balloc(a->k);
+ if (!c) return NULL;
+ c->sign = i;
+ wa = a->wds;
+ xa = a->x;
+ xae = xa + wa;
+ wb = b->wds;
+ xb = b->x;
+ xbe = xb + wb;
+ xc = c->x;
+ borrow = 0;
+#ifdef ULLong
+ do {
+ y = (ULLong)*xa++ - *xb++ - borrow;
+ borrow = y >> 32 & (ULong)1;
+ *xc++ = (ULong)(y & FFFFFFFF);
+ } while (xb < xbe);
+ while (xa < xae) {
+ y = *xa++ - borrow;
+ borrow = y >> 32 & (ULong)1;
+ *xc++ = (ULong)(y & FFFFFFFF);
+ }
+#else
+#ifdef Pack_32
+ do {
+ y = (*xa & 0xffff) - (*xb & 0xffff) - borrow;
+ borrow = (y & 0x10000) >> 16;
+ z = (*xa++ >> 16) - (*xb++ >> 16) - borrow;
+ borrow = (z & 0x10000) >> 16;
+ Storeinc(xc, z, y);
+ } while (xb < xbe);
+ while (xa < xae) {
+ y = (*xa & 0xffff) - borrow;
+ borrow = (y & 0x10000) >> 16;
+ z = (*xa++ >> 16) - borrow;
+ borrow = (z & 0x10000) >> 16;
+ Storeinc(xc, z, y);
+ }
+#else
+ do {
+ y = *xa++ - *xb++ - borrow;
+ borrow = (y & 0x10000) >> 16;
+ *xc++ = y & 0xffff;
+ } while (xb < xbe);
+ while (xa < xae) {
+ y = *xa++ - borrow;
+ borrow = (y & 0x10000) >> 16;
+ *xc++ = y & 0xffff;
+ }
+#endif
+#endif
+ while (!*--xc)
+ wa--;
+ c->wds = wa;
+ return c;
+}
+
+static double
+ulp(double x_)
+{
+ register Long L;
+ double_u x, a;
+ dval(x) = x_;
+
+ L = (word0(x) & Exp_mask) - (P-1)*Exp_msk1;
+#ifndef Avoid_Underflow
+#ifndef Sudden_Underflow
+ if (L > 0) {
+#endif
+#endif
+#ifdef IBM
+ L |= Exp_msk1 >> 4;
+#endif
+ word0(a) = L;
+ word1(a) = 0;
+#ifndef Avoid_Underflow
+#ifndef Sudden_Underflow
+ }
+ else {
+ L = -L >> Exp_shift;
+ if (L < Exp_shift) {
+ word0(a) = 0x80000 >> L;
+ word1(a) = 0;
+ }
+ else {
+ word0(a) = 0;
+ L -= Exp_shift;
+ word1(a) = L >= 31 ? 1 : 1 << 31 - L;
+ }
+ }
+#endif
+#endif
+ return dval(a);
+}
+
+static double
+b2d(Bigint *a, int *e)
+{
+ ULong *xa, *xa0, w, y, z;
+ int k;
+ double_u d;
+#ifdef VAX
+ ULong d0, d1;
+#else
+#define d0 word0(d)
+#define d1 word1(d)
+#endif
+
+ xa0 = a->x;
+ xa = xa0 + a->wds;
+ y = *--xa;
+#ifdef DEBUG
+ if (!y) Bug("zero y in b2d");
+#endif
+ k = hi0bits(y);
+ *e = 32 - k;
+#ifdef Pack_32
+ if (k < Ebits) {
+ d0 = Exp_1 | y >> (Ebits - k);
+ w = xa > xa0 ? *--xa : 0;
+ d1 = y << ((32-Ebits) + k) | w >> (Ebits - k);
+ goto ret_d;
+ }
+ z = xa > xa0 ? *--xa : 0;
+ if (k -= Ebits) {
+ d0 = Exp_1 | y << k | z >> (32 - k);
+ y = xa > xa0 ? *--xa : 0;
+ d1 = z << k | y >> (32 - k);
+ }
+ else {
+ d0 = Exp_1 | y;
+ d1 = z;
+ }
+#else
+ if (k < Ebits + 16) {
+ z = xa > xa0 ? *--xa : 0;
+ d0 = Exp_1 | y << k - Ebits | z >> Ebits + 16 - k;
+ w = xa > xa0 ? *--xa : 0;
+ y = xa > xa0 ? *--xa : 0;
+ d1 = z << k + 16 - Ebits | w << k - Ebits | y >> 16 + Ebits - k;
+ goto ret_d;
+ }
+ z = xa > xa0 ? *--xa : 0;
+ w = xa > xa0 ? *--xa : 0;
+ k -= Ebits + 16;
+ d0 = Exp_1 | y << k + 16 | z << k | w >> 16 - k;
+ y = xa > xa0 ? *--xa : 0;
+ d1 = w << k + 16 | y << k;
+#endif
+ret_d:
+#ifdef VAX
+ word0(d) = d0 >> 16 | d0 << 16;
+ word1(d) = d1 >> 16 | d1 << 16;
+#else
+#undef d0
+#undef d1
+#endif
+ return dval(d);
+}
+
+static Bigint *
+d2b(double d_, int *e, int *bits)
+{
+ double_u d;
+ Bigint *b;
+ int de, k;
+ ULong *x, y, z;
+#ifndef Sudden_Underflow
+ int i;
+#endif
+#ifdef VAX
+ ULong d0, d1;
+#endif
+ dval(d) = d_;
+#ifdef VAX
+ d0 = word0(d) >> 16 | word0(d) << 16;
+ d1 = word1(d) >> 16 | word1(d) << 16;
+#else
+#define d0 word0(d)
+#define d1 word1(d)
+#endif
+
+#ifdef Pack_32
+ b = Balloc(1);
+#else
+ b = Balloc(2);
+#endif
+ if (!b) return NULL;
+ x = b->x;
+
+ z = d0 & Frac_mask;
+ d0 &= 0x7fffffff; /* clear sign bit, which we ignore */
+#ifdef Sudden_Underflow
+ de = (int)(d0 >> Exp_shift);
+#ifndef IBM
+ z |= Exp_msk11;
+#endif
+#else
+ if ((de = (int)(d0 >> Exp_shift)) != 0)
+ z |= Exp_msk1;
+#endif
+#ifdef Pack_32
+ if ((y = d1) != 0) {
+ if ((k = lo0bits(&y)) != 0) {
+ x[0] = y | z << (32 - k);
+ z >>= k;
+ }
+ else
+ x[0] = y;
+#ifndef Sudden_Underflow
+ i =
+#endif
+ b->wds = (x[1] = z) ? 2 : 1;
+ }
+ else {
+#ifdef DEBUG
+ if (!z)
+ Bug("Zero passed to d2b");
+#endif
+ k = lo0bits(&z);
+ x[0] = z;
+#ifndef Sudden_Underflow
+ i =
+#endif
+ b->wds = 1;
+ k += 32;
+ }
+#else
+ if (y = d1) {
+ if (k = lo0bits(&y))
+ if (k >= 16) {
+ x[0] = y | z << 32 - k & 0xffff;
+ x[1] = z >> k - 16 & 0xffff;
+ x[2] = z >> k;
+ i = 2;
+ }
+ else {
+ x[0] = y & 0xffff;
+ x[1] = y >> 16 | z << 16 - k & 0xffff;
+ x[2] = z >> k & 0xffff;
+ x[3] = z >> k+16;
+ i = 3;
+ }
+ else {
+ x[0] = y & 0xffff;
+ x[1] = y >> 16;
+ x[2] = z & 0xffff;
+ x[3] = z >> 16;
+ i = 3;
+ }
+ }
+ else {
+#ifdef DEBUG
+ if (!z)
+ Bug("Zero passed to d2b");
+#endif
+ k = lo0bits(&z);
+ if (k >= 16) {
+ x[0] = z;
+ i = 0;
+ }
+ else {
+ x[0] = z & 0xffff;
+ x[1] = z >> 16;
+ i = 1;
+ }
+ k += 32;
+ }
+ while (!x[i])
+ --i;
+ b->wds = i + 1;
+#endif
+#ifndef Sudden_Underflow
+ if (de) {
+#endif
+#ifdef IBM
+ *e = (de - Bias - (P-1) << 2) + k;
+ *bits = 4*P + 8 - k - hi0bits(word0(d) & Frac_mask);
+#else
+ *e = de - Bias - (P-1) + k;
+ *bits = P - k;
+#endif
+#ifndef Sudden_Underflow
+ }
+ else {
+ *e = de - Bias - (P-1) + 1 + k;
+#ifdef Pack_32
+ *bits = 32*i - hi0bits(x[i-1]);
+#else
+ *bits = (i+2)*16 - hi0bits(x[i]);
+#endif
+ }
+#endif
+ return b;
+}
+#undef d0
+#undef d1
+
+static double
+ratio(Bigint *a, Bigint *b)
+{
+ double_u da, db;
+ int k, ka, kb;
+
+ dval(da) = b2d(a, &ka);
+ dval(db) = b2d(b, &kb);
+#ifdef Pack_32
+ k = ka - kb + 32*(a->wds - b->wds);
+#else
+ k = ka - kb + 16*(a->wds - b->wds);
+#endif
+#ifdef IBM
+ if (k > 0) {
+ word0(da) += (k >> 2)*Exp_msk1;
+ if (k &= 3)
+ dval(da) *= 1 << k;
+ }
+ else {
+ k = -k;
+ word0(db) += (k >> 2)*Exp_msk1;
+ if (k &= 3)
+ dval(db) *= 1 << k;
+ }
+#else
+ if (k > 0)
+ word0(da) += k*Exp_msk1;
+ else {
+ k = -k;
+ word0(db) += k*Exp_msk1;
+ }
+#endif
+ return dval(da) / dval(db);
+}
+
+static const double
+tens[] = {
+ 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9,
+ 1e10, 1e11, 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19,
+ 1e20, 1e21, 1e22
+#ifdef VAX
+ , 1e23, 1e24
+#endif
+};
+
+static const double
+#ifdef IEEE_Arith
+bigtens[] = { 1e16, 1e32, 1e64, 1e128, 1e256 };
+static const double tinytens[] = { 1e-16, 1e-32, 1e-64, 1e-128,
+#ifdef Avoid_Underflow
+ 9007199254740992.*9007199254740992.e-256
+ /* = 2^106 * 1e-53 */
+#else
+ 1e-256
+#endif
+};
+/* The factor of 2^53 in tinytens[4] helps us avoid setting the underflow */
+/* flag unnecessarily. It leads to a song and dance at the end of strtod. */
+#define Scale_Bit 0x10
+#define n_bigtens 5
+#else
+#ifdef IBM
+bigtens[] = { 1e16, 1e32, 1e64 };
+static const double tinytens[] = { 1e-16, 1e-32, 1e-64 };
+#define n_bigtens 3
+#else
+bigtens[] = { 1e16, 1e32 };
+static const double tinytens[] = { 1e-16, 1e-32 };
+#define n_bigtens 2
+#endif
+#endif
+
+#ifndef IEEE_Arith
+#undef INFNAN_CHECK
+#endif
+
+#ifdef INFNAN_CHECK
+
+#ifndef NAN_WORD0
+#define NAN_WORD0 0x7ff80000
+#endif
+
+#ifndef NAN_WORD1
+#define NAN_WORD1 0
+#endif
+
+static int
+match(const char **sp, char *t)
+{
+ int c, d;
+ const char *s = *sp;
+
+ while (d = *t++) {
+ if ((c = *++s) >= 'A' && c <= 'Z')
+ c += 'a' - 'A';
+ if (c != d)
+ return 0;
+ }
+ *sp = s + 1;
+ return 1;
+}
+
+#ifndef No_Hex_NaN
+static void
+hexnan(double *rvp, const char **sp)
+{
+ ULong c, x[2];
+ const char *s;
+ int havedig, udx0, xshift;
+
+ x[0] = x[1] = 0;
+ havedig = xshift = 0;
+ udx0 = 1;
+ s = *sp;
+ while (c = *(const unsigned char*)++s) {
+ if (c >= '0' && c <= '9')
+ c -= '0';
+ else if (c >= 'a' && c <= 'f')
+ c += 10 - 'a';
+ else if (c >= 'A' && c <= 'F')
+ c += 10 - 'A';
+ else if (c <= ' ') {
+ if (udx0 && havedig) {
+ udx0 = 0;
+ xshift = 1;
+ }
+ continue;
+ }
+ else if (/*(*/ c == ')' && havedig) {
+ *sp = s + 1;
+ break;
+ }
+ else
+ return; /* invalid form: don't change *sp */
+ havedig = 1;
+ if (xshift) {
+ xshift = 0;
+ x[0] = x[1];
+ x[1] = 0;
+ }
+ if (udx0)
+ x[0] = (x[0] << 4) | (x[1] >> 28);
+ x[1] = (x[1] << 4) | c;
+ }
+ if ((x[0] &= 0xfffff) || x[1]) {
+ word0(*rvp) = Exp_mask | x[0];
+ word1(*rvp) = x[1];
+ }
+}
+#endif /*No_Hex_NaN*/
+#endif /* INFNAN_CHECK */
+
+NO_SANITIZE("unsigned-integer-overflow", double strtod(const char *s00, char **se));
+double
+strtod(const char *s00, char **se)
+{
+#ifdef Avoid_Underflow
+ int scale;
+#endif
+ int bb2, bb5, bbe, bd2, bd5, bbbits, bs2, c, dsign,
+ e, e1, esign, i, j, k, nd, nd0, nf, nz, nz0, sign;
+ const char *s, *s0, *s1;
+ double aadj, adj;
+ double_u aadj1, rv, rv0;
+ Long L;
+ ULong y, z;
+ Bigint *bb, *bb1, *bd, *bd0, *bs, *delta;
+#ifdef SET_INEXACT
+ int inexact, oldinexact;
+#endif
+#ifdef Honor_FLT_ROUNDS
+ int rounding;
+#endif
+#ifdef USE_LOCALE
+ const char *s2;
+#endif
+
+ errno = 0;
+ sign = nz0 = nz = 0;
+ dval(rv) = 0.;
+ for (s = s00;;s++)
+ switch (*s) {
+ case '-':
+ sign = 1;
+ /* no break */
+ case '+':
+ if (*++s)
+ goto break2;
+ /* no break */
+ case 0:
+ goto ret0;
+ case '\t':
+ case '\n':
+ case '\v':
+ case '\f':
+ case '\r':
+ case ' ':
+ continue;
+ default:
+ goto break2;
+ }
+break2:
+ if (*s == '0') {
+ if (s[1] == 'x' || s[1] == 'X') {
+ s0 = ++s;
+ adj = 0;
+ aadj = 1.0;
+ nd0 = -4;
+
+ if (!*++s || (!(s1 = strchr(hexdigit, *s)) && *s != '.')) goto ret0;
+ if (*s == '0') {
+ while (*++s == '0');
+ if (!*s) goto ret;
+ s1 = strchr(hexdigit, *s);
+ }
+ if (s1 != NULL) {
+ do {
+ adj += aadj * ((s1 - hexdigit) & 15);
+ nd0 += 4;
+ aadj /= 16;
+ } while (*++s && (s1 = strchr(hexdigit, *s)));
+ }
+
+ if ((*s == '.') && *++s && (s1 = strchr(hexdigit, *s))) {
+ if (nd0 < 0) {
+ while (*s == '0') {
+ s++;
+ nd0 -= 4;
+ }
+ }
+ for (; *s && (s1 = strchr(hexdigit, *s)); ++s) {
+ adj += aadj * ((s1 - hexdigit) & 15);
+ if ((aadj /= 16) == 0.0) {
+ while (*++s && strchr(hexdigit, *s));
+ break;
+ }
+ }
+ }
+
+ if (*s == 'P' || *s == 'p') {
+ dsign = 0x2C - *++s; /* +: 2B, -: 2D */
+ if (abs(dsign) == 1) s++;
+ else dsign = 1;
+
+ nd = 0;
+ c = *s;
+ if (c < '0' || '9' < c) goto ret0;
+ do {
+ nd *= 10;
+ nd += c;
+ nd -= '0';
+ c = *++s;
+ /* Float("0x0."+("0"*267)+"1fp2095") */
+ if (nd + dsign * nd0 > 2095) {
+ while ('0' <= c && c <= '9') c = *++s;
+ break;
+ }
+ } while ('0' <= c && c <= '9');
+ nd0 += nd * dsign;
+ }
+ dval(rv) = ldexp(adj, nd0);
+ goto ret;
+ }
+ nz0 = 1;
+ while (*++s == '0') ;
+ if (!*s)
+ goto ret;
+ }
+ s0 = s;
+ y = z = 0;
+ for (nd = nf = 0; (c = *s) >= '0' && c <= '9'; nd++, s++)
+ if (nd < 9)
+ y = 10*y + c - '0';
+ else if (nd < DBL_DIG + 2)
+ z = 10*z + c - '0';
+ nd0 = nd;
+#ifdef USE_LOCALE
+ s1 = localeconv()->decimal_point;
+ if (c == *s1) {
+ c = '.';
+ if (*++s1) {
+ s2 = s;
+ for (;;) {
+ if (*++s2 != *s1) {
+ c = 0;
+ break;
+ }
+ if (!*++s1) {
+ s = s2;
+ break;
+ }
+ }
+ }
+ }
+#endif
+ if (c == '.') {
+ c = *++s;
+ if (!ISDIGIT(c))
+ goto dig_done;
+ if (!nd) {
+ for (; c == '0'; c = *++s)
+ nz++;
+ if (c > '0' && c <= '9') {
+ s0 = s;
+ nf += nz;
+ nz = 0;
+ goto have_dig;
+ }
+ goto dig_done;
+ }
+ for (; c >= '0' && c <= '9'; c = *++s) {
+have_dig:
+ nz++;
+ if (nd > DBL_DIG * 4) {
+ continue;
+ }
+ if (c -= '0') {
+ nf += nz;
+ for (i = 1; i < nz; i++)
+ if (nd++ < 9)
+ y *= 10;
+ else if (nd <= DBL_DIG + 2)
+ z *= 10;
+ if (nd++ < 9)
+ y = 10*y + c;
+ else if (nd <= DBL_DIG + 2)
+ z = 10*z + c;
+ nz = 0;
+ }
+ }
+ }
+dig_done:
+ e = 0;
+ if (c == 'e' || c == 'E') {
+ if (!nd && !nz && !nz0) {
+ goto ret0;
+ }
+ s00 = s;
+ esign = 0;
+ switch (c = *++s) {
+ case '-':
+ esign = 1;
+ case '+':
+ c = *++s;
+ }
+ if (c >= '0' && c <= '9') {
+ while (c == '0')
+ c = *++s;
+ if (c > '0' && c <= '9') {
+ L = c - '0';
+ s1 = s;
+ while ((c = *++s) >= '0' && c <= '9')
+ L = 10*L + c - '0';
+ if (s - s1 > 8 || L > 19999)
+ /* Avoid confusion from exponents
+ * so large that e might overflow.
+ */
+ e = 19999; /* safe for 16 bit ints */
+ else
+ e = (int)L;
+ if (esign)
+ e = -e;
+ }
+ else
+ e = 0;
+ }
+ else
+ s = s00;
+ }
+ if (!nd) {
+ if (!nz && !nz0) {
+#ifdef INFNAN_CHECK
+ /* Check for Nan and Infinity */
+ switch (c) {
+ case 'i':
+ case 'I':
+ if (match(&s,"nf")) {
+ --s;
+ if (!match(&s,"inity"))
+ ++s;
+ word0(rv) = 0x7ff00000;
+ word1(rv) = 0;
+ goto ret;
+ }
+ break;
+ case 'n':
+ case 'N':
+ if (match(&s, "an")) {
+ word0(rv) = NAN_WORD0;
+ word1(rv) = NAN_WORD1;
+#ifndef No_Hex_NaN
+ if (*s == '(') /*)*/
+ hexnan(&rv, &s);
+#endif
+ goto ret;
+ }
+ }
+#endif /* INFNAN_CHECK */
+ret0:
+ s = s00;
+ sign = 0;
+ }
+ goto ret;
+ }
+ e1 = e -= nf;
+
+ /* Now we have nd0 digits, starting at s0, followed by a
+ * decimal point, followed by nd-nd0 digits. The number we're
+ * after is the integer represented by those digits times
+ * 10**e */
+
+ if (!nd0)
+ nd0 = nd;
+ k = nd < DBL_DIG + 2 ? nd : DBL_DIG + 2;
+ dval(rv) = y;
+ if (k > 9) {
+#ifdef SET_INEXACT
+ if (k > DBL_DIG)
+ oldinexact = get_inexact();
+#endif
+ dval(rv) = tens[k - 9] * dval(rv) + z;
+ }
+ bd0 = bb = bd = bs = delta = 0;
+ if (nd <= DBL_DIG
+#ifndef RND_PRODQUOT
+#ifndef Honor_FLT_ROUNDS
+ && Flt_Rounds == 1
+#endif
+#endif
+ ) {
+ if (!e)
+ goto ret;
+ if (e > 0) {
+ if (e <= Ten_pmax) {
+#ifdef VAX
+ goto vax_ovfl_check;
+#else
+#ifdef Honor_FLT_ROUNDS
+ /* round correctly FLT_ROUNDS = 2 or 3 */
+ if (sign) {
+ dval(rv) = -dval(rv);
+ sign = 0;
+ }
+#endif
+ /* rv = */ rounded_product(dval(rv), tens[e]);
+ goto ret;
+#endif
+ }
+ i = DBL_DIG - nd;
+ if (e <= Ten_pmax + i) {
+ /* A fancier test would sometimes let us do
+ * this for larger i values.
+ */
+#ifdef Honor_FLT_ROUNDS
+ /* round correctly FLT_ROUNDS = 2 or 3 */
+ if (sign) {
+ dval(rv) = -dval(rv);
+ sign = 0;
+ }
+#endif
+ e -= i;
+ dval(rv) *= tens[i];
+#ifdef VAX
+ /* VAX exponent range is so narrow we must
+ * worry about overflow here...
+ */
+vax_ovfl_check:
+ word0(rv) -= P*Exp_msk1;
+ /* rv = */ rounded_product(dval(rv), tens[e]);
+ if ((word0(rv) & Exp_mask)
+ > Exp_msk1*(DBL_MAX_EXP+Bias-1-P))
+ goto ovfl;
+ word0(rv) += P*Exp_msk1;
+#else
+ /* rv = */ rounded_product(dval(rv), tens[e]);
+#endif
+ goto ret;
+ }
+ }
+#ifndef Inaccurate_Divide
+ else if (e >= -Ten_pmax) {
+#ifdef Honor_FLT_ROUNDS
+ /* round correctly FLT_ROUNDS = 2 or 3 */
+ if (sign) {
+ dval(rv) = -dval(rv);
+ sign = 0;
+ }
+#endif
+ /* rv = */ rounded_quotient(dval(rv), tens[-e]);
+ goto ret;
+ }
+#endif
+ }
+ e1 += nd - k;
+
+#ifdef IEEE_Arith
+#ifdef SET_INEXACT
+ inexact = 1;
+ if (k <= DBL_DIG)
+ oldinexact = get_inexact();
+#endif
+#ifdef Avoid_Underflow
+ scale = 0;
+#endif
+#ifdef Honor_FLT_ROUNDS
+ if ((rounding = Flt_Rounds) >= 2) {
+ if (sign)
+ rounding = rounding == 2 ? 0 : 2;
+ else
+ if (rounding != 2)
+ rounding = 0;
+ }
+#endif
+#endif /*IEEE_Arith*/
+
+ /* Get starting approximation = rv * 10**e1 */
+
+ if (e1 > 0) {
+ if ((i = e1 & 15) != 0)
+ dval(rv) *= tens[i];
+ if (e1 &= ~15) {
+ if (e1 > DBL_MAX_10_EXP) {
+ovfl:
+#ifndef NO_ERRNO
+ errno = ERANGE;
+#endif
+ /* Can't trust HUGE_VAL */
+#ifdef IEEE_Arith
+#ifdef Honor_FLT_ROUNDS
+ switch (rounding) {
+ case 0: /* toward 0 */
+ case 3: /* toward -infinity */
+ word0(rv) = Big0;
+ word1(rv) = Big1;
+ break;
+ default:
+ word0(rv) = Exp_mask;
+ word1(rv) = 0;
+ }
+#else /*Honor_FLT_ROUNDS*/
+ word0(rv) = Exp_mask;
+ word1(rv) = 0;
+#endif /*Honor_FLT_ROUNDS*/
+#ifdef SET_INEXACT
+ /* set overflow bit */
+ dval(rv0) = 1e300;
+ dval(rv0) *= dval(rv0);
+#endif
+#else /*IEEE_Arith*/
+ word0(rv) = Big0;
+ word1(rv) = Big1;
+#endif /*IEEE_Arith*/
+ if (bd0)
+ goto retfree;
+ goto ret;
+ }
+ e1 >>= 4;
+ for (j = 0; e1 > 1; j++, e1 >>= 1)
+ if (e1 & 1)
+ dval(rv) *= bigtens[j];
+ /* The last multiplication could overflow. */
+ word0(rv) -= P*Exp_msk1;
+ dval(rv) *= bigtens[j];
+ if ((z = word0(rv) & Exp_mask)
+ > Exp_msk1*(DBL_MAX_EXP+Bias-P))
+ goto ovfl;
+ if (z > Exp_msk1*(DBL_MAX_EXP+Bias-1-P)) {
+ /* set to largest number */
+ /* (Can't trust DBL_MAX) */
+ word0(rv) = Big0;
+ word1(rv) = Big1;
+ }
+ else
+ word0(rv) += P*Exp_msk1;
+ }
+ }
+ else if (e1 < 0) {
+ e1 = -e1;
+ if ((i = e1 & 15) != 0)
+ dval(rv) /= tens[i];
+ if (e1 >>= 4) {
+ if (e1 >= 1 << n_bigtens)
+ goto undfl;
+#ifdef Avoid_Underflow
+ if (e1 & Scale_Bit)
+ scale = 2*P;
+ for (j = 0; e1 > 0; j++, e1 >>= 1)
+ if (e1 & 1)
+ dval(rv) *= tinytens[j];
+ if (scale && (j = 2*P + 1 - ((word0(rv) & Exp_mask)
+ >> Exp_shift)) > 0) {
+ /* scaled rv is denormal; zap j low bits */
+ if (j >= 32) {
+ word1(rv) = 0;
+ if (j >= 53)
+ word0(rv) = (P+2)*Exp_msk1;
+ else
+ word0(rv) &= 0xffffffff << (j-32);
+ }
+ else
+ word1(rv) &= 0xffffffff << j;
+ }
+#else
+ for (j = 0; e1 > 1; j++, e1 >>= 1)
+ if (e1 & 1)
+ dval(rv) *= tinytens[j];
+ /* The last multiplication could underflow. */
+ dval(rv0) = dval(rv);
+ dval(rv) *= tinytens[j];
+ if (!dval(rv)) {
+ dval(rv) = 2.*dval(rv0);
+ dval(rv) *= tinytens[j];
+#endif
+ if (!dval(rv)) {
+undfl:
+ dval(rv) = 0.;
+#ifndef NO_ERRNO
+ errno = ERANGE;
+#endif
+ if (bd0)
+ goto retfree;
+ goto ret;
+ }
+#ifndef Avoid_Underflow
+ word0(rv) = Tiny0;
+ word1(rv) = Tiny1;
+ /* The refinement below will clean
+ * this approximation up.
+ */
+ }
+#endif
+ }
+ }
+
+ /* Now the hard part -- adjusting rv to the correct value.*/
+
+ /* Put digits into bd: true value = bd * 10^e */
+
+ bd0 = s2b(s0, nd0, nd, y);
+ if (!bd0) goto ret;
+
+ for (;;) {
+ bd = Balloc(bd0->k);
+ if (!bd) goto retfree;
+ Bcopy(bd, bd0);
+ bb = d2b(dval(rv), &bbe, &bbbits); /* rv = bb * 2^bbe */
+ if (!bb) goto retfree;
+ bs = i2b(1);
+ if (!bs) goto retfree;
+
+ if (e >= 0) {
+ bb2 = bb5 = 0;
+ bd2 = bd5 = e;
+ }
+ else {
+ bb2 = bb5 = -e;
+ bd2 = bd5 = 0;
+ }
+ if (bbe >= 0)
+ bb2 += bbe;
+ else
+ bd2 -= bbe;
+ bs2 = bb2;
+#ifdef Honor_FLT_ROUNDS
+ if (rounding != 1)
+ bs2++;
+#endif
+#ifdef Avoid_Underflow
+ j = bbe - scale;
+ i = j + bbbits - 1; /* logb(rv) */
+ if (i < Emin) /* denormal */
+ j += P - Emin;
+ else
+ j = P + 1 - bbbits;
+#else /*Avoid_Underflow*/
+#ifdef Sudden_Underflow
+#ifdef IBM
+ j = 1 + 4*P - 3 - bbbits + ((bbe + bbbits - 1) & 3);
+#else
+ j = P + 1 - bbbits;
+#endif
+#else /*Sudden_Underflow*/
+ j = bbe;
+ i = j + bbbits - 1; /* logb(rv) */
+ if (i < Emin) /* denormal */
+ j += P - Emin;
+ else
+ j = P + 1 - bbbits;
+#endif /*Sudden_Underflow*/
+#endif /*Avoid_Underflow*/
+ bb2 += j;
+ bd2 += j;
+#ifdef Avoid_Underflow
+ bd2 += scale;
+#endif
+ i = bb2 < bd2 ? bb2 : bd2;
+ if (i > bs2)
+ i = bs2;
+ if (i > 0) {
+ bb2 -= i;
+ bd2 -= i;
+ bs2 -= i;
+ }
+ if (bb5 > 0) {
+ bs = pow5mult(bs, bb5);
+ if (!bs) goto retfree;
+ bb1 = mult(bs, bb);
+ Bfree(bb);
+ bb = bb1;
+ if (!bb) goto retfree;
+ }
+ if (bb2 > 0) {
+ bb = lshift(bb, bb2);
+ if (!bb) goto retfree;
+ }
+ if (bd5 > 0) {
+ bd = pow5mult(bd, bd5);
+ if (!bd) goto retfree;
+ }
+ if (bd2 > 0) {
+ bd = lshift(bd, bd2);
+ if (!bd) goto retfree;
+ }
+ if (bs2 > 0) {
+ bs = lshift(bs, bs2);
+ if (!bs) goto retfree;
+ }
+ delta = diff(bb, bd);
+ if (!delta) goto retfree;
+ dsign = delta->sign;
+ delta->sign = 0;
+ i = cmp(delta, bs);
+#ifdef Honor_FLT_ROUNDS
+ if (rounding != 1) {
+ if (i < 0) {
+ /* Error is less than an ulp */
+ if (!delta->x[0] && delta->wds <= 1) {
+ /* exact */
+#ifdef SET_INEXACT
+ inexact = 0;
+#endif
+ break;
+ }
+ if (rounding) {
+ if (dsign) {
+ adj = 1.;
+ goto apply_adj;
+ }
+ }
+ else if (!dsign) {
+ adj = -1.;
+ if (!word1(rv)
+ && !(word0(rv) & Frac_mask)) {
+ y = word0(rv) & Exp_mask;
+#ifdef Avoid_Underflow
+ if (!scale || y > 2*P*Exp_msk1)
+#else
+ if (y)
+#endif
+ {
+ delta = lshift(delta,Log2P);
+ if (!delta) goto nomem;
+ if (cmp(delta, bs) <= 0)
+ adj = -0.5;
+ }
+ }
+apply_adj:
+#ifdef Avoid_Underflow
+ if (scale && (y = word0(rv) & Exp_mask)
+ <= 2*P*Exp_msk1)
+ word0(adj) += (2*P+1)*Exp_msk1 - y;
+#else
+#ifdef Sudden_Underflow
+ if ((word0(rv) & Exp_mask) <=
+ P*Exp_msk1) {
+ word0(rv) += P*Exp_msk1;
+ dval(rv) += adj*ulp(dval(rv));
+ word0(rv) -= P*Exp_msk1;
+ }
+ else
+#endif /*Sudden_Underflow*/
+#endif /*Avoid_Underflow*/
+ dval(rv) += adj*ulp(dval(rv));
+ }
+ break;
+ }
+ adj = ratio(delta, bs);
+ if (adj < 1.)
+ adj = 1.;
+ if (adj <= 0x7ffffffe) {
+ /* adj = rounding ? ceil(adj) : floor(adj); */
+ y = adj;
+ if (y != adj) {
+ if (!((rounding>>1) ^ dsign))
+ y++;
+ adj = y;
+ }
+ }
+#ifdef Avoid_Underflow
+ if (scale && (y = word0(rv) & Exp_mask) <= 2*P*Exp_msk1)
+ word0(adj) += (2*P+1)*Exp_msk1 - y;
+#else
+#ifdef Sudden_Underflow
+ if ((word0(rv) & Exp_mask) <= P*Exp_msk1) {
+ word0(rv) += P*Exp_msk1;
+ adj *= ulp(dval(rv));
+ if (dsign)
+ dval(rv) += adj;
+ else
+ dval(rv) -= adj;
+ word0(rv) -= P*Exp_msk1;
+ goto cont;
+ }
+#endif /*Sudden_Underflow*/
+#endif /*Avoid_Underflow*/
+ adj *= ulp(dval(rv));
+ if (dsign)
+ dval(rv) += adj;
+ else
+ dval(rv) -= adj;
+ goto cont;
+ }
+#endif /*Honor_FLT_ROUNDS*/
+
+ if (i < 0) {
+ /* Error is less than half an ulp -- check for
+ * special case of mantissa a power of two.
+ */
+ if (dsign || word1(rv) || word0(rv) & Bndry_mask
+#ifdef IEEE_Arith
+#ifdef Avoid_Underflow
+ || (word0(rv) & Exp_mask) <= (2*P+1)*Exp_msk1
+#else
+ || (word0(rv) & Exp_mask) <= Exp_msk1
+#endif
+#endif
+ ) {
+#ifdef SET_INEXACT
+ if (!delta->x[0] && delta->wds <= 1)
+ inexact = 0;
+#endif
+ break;
+ }
+ if (!delta->x[0] && delta->wds <= 1) {
+ /* exact result */
+#ifdef SET_INEXACT
+ inexact = 0;
+#endif
+ break;
+ }
+ delta = lshift(delta,Log2P);
+ if (!delta) goto retfree;
+ if (cmp(delta, bs) > 0)
+ goto drop_down;
+ break;
+ }
+ if (i == 0) {
+ /* exactly half-way between */
+ if (dsign) {
+ if ((word0(rv) & Bndry_mask1) == Bndry_mask1
+ && word1(rv) == (
+#ifdef Avoid_Underflow
+ (scale && (y = word0(rv) & Exp_mask) <= 2*P*Exp_msk1)
+ ? (0xffffffff & (0xffffffff << (2*P+1-(y>>Exp_shift)))) :
+#endif
+ 0xffffffff)) {
+ /*boundary case -- increment exponent*/
+ word0(rv) = (word0(rv) & Exp_mask)
+ + Exp_msk1
+#ifdef IBM
+ | Exp_msk1 >> 4
+#endif
+ ;
+ word1(rv) = 0;
+#ifdef Avoid_Underflow
+ dsign = 0;
+#endif
+ break;
+ }
+ }
+ else if (!(word0(rv) & Bndry_mask) && !word1(rv)) {
+drop_down:
+ /* boundary case -- decrement exponent */
+#ifdef Sudden_Underflow /*{{*/
+ L = word0(rv) & Exp_mask;
+#ifdef IBM
+ if (L < Exp_msk1)
+#else
+#ifdef Avoid_Underflow
+ if (L <= (scale ? (2*P+1)*Exp_msk1 : Exp_msk1))
+#else
+ if (L <= Exp_msk1)
+#endif /*Avoid_Underflow*/
+#endif /*IBM*/
+ goto undfl;
+ L -= Exp_msk1;
+#else /*Sudden_Underflow}{*/
+#ifdef Avoid_Underflow
+ if (scale) {
+ L = word0(rv) & Exp_mask;
+ if (L <= (2*P+1)*Exp_msk1) {
+ if (L > (P+2)*Exp_msk1)
+ /* round even ==> */
+ /* accept rv */
+ break;
+ /* rv = smallest denormal */
+ goto undfl;
+ }
+ }
+#endif /*Avoid_Underflow*/
+ L = (word0(rv) & Exp_mask) - Exp_msk1;
+#endif /*Sudden_Underflow}}*/
+ word0(rv) = L | Bndry_mask1;
+ word1(rv) = 0xffffffff;
+#ifdef IBM
+ goto cont;
+#else
+ break;
+#endif
+ }
+#ifndef ROUND_BIASED
+ if (!(word1(rv) & LSB))
+ break;
+#endif
+ if (dsign)
+ dval(rv) += ulp(dval(rv));
+#ifndef ROUND_BIASED
+ else {
+ dval(rv) -= ulp(dval(rv));
+#ifndef Sudden_Underflow
+ if (!dval(rv))
+ goto undfl;
+#endif
+ }
+#ifdef Avoid_Underflow
+ dsign = 1 - dsign;
+#endif
+#endif
+ break;
+ }
+ if ((aadj = ratio(delta, bs)) <= 2.) {
+ if (dsign)
+ aadj = dval(aadj1) = 1.;
+ else if (word1(rv) || word0(rv) & Bndry_mask) {
+#ifndef Sudden_Underflow
+ if (word1(rv) == Tiny1 && !word0(rv))
+ goto undfl;
+#endif
+ aadj = 1.;
+ dval(aadj1) = -1.;
+ }
+ else {
+ /* special case -- power of FLT_RADIX to be */
+ /* rounded down... */
+
+ if (aadj < 2./FLT_RADIX)
+ aadj = 1./FLT_RADIX;
+ else
+ aadj *= 0.5;
+ dval(aadj1) = -aadj;
+ }
+ }
+ else {
+ aadj *= 0.5;
+ dval(aadj1) = dsign ? aadj : -aadj;
+#ifdef Check_FLT_ROUNDS
+ switch (Rounding) {
+ case 2: /* towards +infinity */
+ dval(aadj1) -= 0.5;
+ break;
+ case 0: /* towards 0 */
+ case 3: /* towards -infinity */
+ dval(aadj1) += 0.5;
+ }
+#else
+ if (Flt_Rounds == 0)
+ dval(aadj1) += 0.5;
+#endif /*Check_FLT_ROUNDS*/
+ }
+ y = word0(rv) & Exp_mask;
+
+ /* Check for overflow */
+
+ if (y == Exp_msk1*(DBL_MAX_EXP+Bias-1)) {
+ dval(rv0) = dval(rv);
+ word0(rv) -= P*Exp_msk1;
+ adj = dval(aadj1) * ulp(dval(rv));
+ dval(rv) += adj;
+ if ((word0(rv) & Exp_mask) >=
+ Exp_msk1*(DBL_MAX_EXP+Bias-P)) {
+ if (word0(rv0) == Big0 && word1(rv0) == Big1)
+ goto ovfl;
+ word0(rv) = Big0;
+ word1(rv) = Big1;
+ goto cont;
+ }
+ else
+ word0(rv) += P*Exp_msk1;
+ }
+ else {
+#ifdef Avoid_Underflow
+ if (scale && y <= 2*P*Exp_msk1) {
+ if (aadj <= 0x7fffffff) {
+ if ((z = (int)aadj) <= 0)
+ z = 1;
+ aadj = z;
+ dval(aadj1) = dsign ? aadj : -aadj;
+ }
+ word0(aadj1) += (2*P+1)*Exp_msk1 - y;
+ }
+ adj = dval(aadj1) * ulp(dval(rv));
+ dval(rv) += adj;
+#else
+#ifdef Sudden_Underflow
+ if ((word0(rv) & Exp_mask) <= P*Exp_msk1) {
+ dval(rv0) = dval(rv);
+ word0(rv) += P*Exp_msk1;
+ adj = dval(aadj1) * ulp(dval(rv));
+ dval(rv) += adj;
+#ifdef IBM
+ if ((word0(rv) & Exp_mask) < P*Exp_msk1)
+#else
+ if ((word0(rv) & Exp_mask) <= P*Exp_msk1)
+#endif
+ {
+ if (word0(rv0) == Tiny0 && word1(rv0) == Tiny1)
+ goto undfl;
+ word0(rv) = Tiny0;
+ word1(rv) = Tiny1;
+ goto cont;
+ }
+ else
+ word0(rv) -= P*Exp_msk1;
+ }
+ else {
+ adj = dval(aadj1) * ulp(dval(rv));
+ dval(rv) += adj;
+ }
+#else /*Sudden_Underflow*/
+ /* Compute adj so that the IEEE rounding rules will
+ * correctly round rv + adj in some half-way cases.
+ * If rv * ulp(rv) is denormalized (i.e.,
+ * y <= (P-1)*Exp_msk1), we must adjust aadj to avoid
+ * trouble from bits lost to denormalization;
+ * example: 1.2e-307 .
+ */
+ if (y <= (P-1)*Exp_msk1 && aadj > 1.) {
+ dval(aadj1) = (double)(int)(aadj + 0.5);
+ if (!dsign)
+ dval(aadj1) = -dval(aadj1);
+ }
+ adj = dval(aadj1) * ulp(dval(rv));
+ dval(rv) += adj;
+#endif /*Sudden_Underflow*/
+#endif /*Avoid_Underflow*/
+ }
+ z = word0(rv) & Exp_mask;
+#ifndef SET_INEXACT
+#ifdef Avoid_Underflow
+ if (!scale)
+#endif
+ if (y == z) {
+ /* Can we stop now? */
+ L = (Long)aadj;
+ aadj -= L;
+ /* The tolerances below are conservative. */
+ if (dsign || word1(rv) || word0(rv) & Bndry_mask) {
+ if (aadj < .4999999 || aadj > .5000001)
+ break;
+ }
+ else if (aadj < .4999999/FLT_RADIX)
+ break;
+ }
+#endif
+cont:
+ Bfree(bb);
+ Bfree(bd);
+ Bfree(bs);
+ Bfree(delta);
+ }
+#ifdef SET_INEXACT
+ if (inexact) {
+ if (!oldinexact) {
+ word0(rv0) = Exp_1 + (70 << Exp_shift);
+ word1(rv0) = 0;
+ dval(rv0) += 1.;
+ }
+ }
+ else if (!oldinexact)
+ clear_inexact();
+#endif
+#ifdef Avoid_Underflow
+ if (scale) {
+ word0(rv0) = Exp_1 - 2*P*Exp_msk1;
+ word1(rv0) = 0;
+ dval(rv) *= dval(rv0);
+#ifndef NO_ERRNO
+ /* try to avoid the bug of testing an 8087 register value */
+ if (word0(rv) == 0 && word1(rv) == 0)
+ errno = ERANGE;
+#endif
+ }
+#endif /* Avoid_Underflow */
+#ifdef SET_INEXACT
+ if (inexact && !(word0(rv) & Exp_mask)) {
+ /* set underflow bit */
+ dval(rv0) = 1e-300;
+ dval(rv0) *= dval(rv0);
+ }
+#endif
+retfree:
+ Bfree(bb);
+ Bfree(bd);
+ Bfree(bs);
+ Bfree(bd0);
+ Bfree(delta);
+ret:
+ if (se)
+ *se = (char *)s;
+ return sign ? -dval(rv) : dval(rv);
+}
+
+NO_SANITIZE("unsigned-integer-overflow", static int quorem(Bigint *b, Bigint *S));
+static int
+quorem(Bigint *b, Bigint *S)
+{
+ int n;
+ ULong *bx, *bxe, q, *sx, *sxe;
+#ifdef ULLong
+ ULLong borrow, carry, y, ys;
+#else
+ ULong borrow, carry, y, ys;
+#ifdef Pack_32
+ ULong si, z, zs;
+#endif
+#endif
+
+ n = S->wds;
+#ifdef DEBUG
+ /*debug*/ if (b->wds > n)
+ /*debug*/ Bug("oversize b in quorem");
+#endif
+ if (b->wds < n)
+ return 0;
+ sx = S->x;
+ sxe = sx + --n;
+ bx = b->x;
+ bxe = bx + n;
+ q = *bxe / (*sxe + 1); /* ensure q <= true quotient */
+#ifdef DEBUG
+ /*debug*/ if (q > 9)
+ /*debug*/ Bug("oversized quotient in quorem");
+#endif
+ if (q) {
+ borrow = 0;
+ carry = 0;
+ do {
+#ifdef ULLong
+ ys = *sx++ * (ULLong)q + carry;
+ carry = ys >> 32;
+ y = *bx - (ys & FFFFFFFF) - borrow;
+ borrow = y >> 32 & (ULong)1;
+ *bx++ = (ULong)(y & FFFFFFFF);
+#else
+#ifdef Pack_32
+ si = *sx++;
+ ys = (si & 0xffff) * q + carry;
+ zs = (si >> 16) * q + (ys >> 16);
+ carry = zs >> 16;
+ y = (*bx & 0xffff) - (ys & 0xffff) - borrow;
+ borrow = (y & 0x10000) >> 16;
+ z = (*bx >> 16) - (zs & 0xffff) - borrow;
+ borrow = (z & 0x10000) >> 16;
+ Storeinc(bx, z, y);
+#else
+ ys = *sx++ * q + carry;
+ carry = ys >> 16;
+ y = *bx - (ys & 0xffff) - borrow;
+ borrow = (y & 0x10000) >> 16;
+ *bx++ = y & 0xffff;
+#endif
+#endif
+ } while (sx <= sxe);
+ if (!*bxe) {
+ bx = b->x;
+ while (--bxe > bx && !*bxe)
+ --n;
+ b->wds = n;
+ }
+ }
+ if (cmp(b, S) >= 0) {
+ q++;
+ borrow = 0;
+ carry = 0;
+ bx = b->x;
+ sx = S->x;
+ do {
+#ifdef ULLong
+ ys = *sx++ + carry;
+ carry = ys >> 32;
+ y = *bx - (ys & FFFFFFFF) - borrow;
+ borrow = y >> 32 & (ULong)1;
+ *bx++ = (ULong)(y & FFFFFFFF);
+#else
+#ifdef Pack_32
+ si = *sx++;
+ ys = (si & 0xffff) + carry;
+ zs = (si >> 16) + (ys >> 16);
+ carry = zs >> 16;
+ y = (*bx & 0xffff) - (ys & 0xffff) - borrow;
+ borrow = (y & 0x10000) >> 16;
+ z = (*bx >> 16) - (zs & 0xffff) - borrow;
+ borrow = (z & 0x10000) >> 16;
+ Storeinc(bx, z, y);
+#else
+ ys = *sx++ + carry;
+ carry = ys >> 16;
+ y = *bx - (ys & 0xffff) - borrow;
+ borrow = (y & 0x10000) >> 16;
+ *bx++ = y & 0xffff;
+#endif
+#endif
+ } while (sx <= sxe);
+ bx = b->x;
+ bxe = bx + n;
+ if (!*bxe) {
+ while (--bxe > bx && !*bxe)
+ --n;
+ b->wds = n;
+ }
+ }
+ return q;
+}
+
+#ifndef MULTIPLE_THREADS
+static char *dtoa_result;
+#endif
+
+#ifndef MULTIPLE_THREADS
+static char *
+rv_alloc(int i)
+{
+ return dtoa_result = MALLOC(i);
+}
+#else
+#define rv_alloc(i) MALLOC(i)
+#endif
+
+static char *
+nrv_alloc(const char *s, char **rve, size_t n)
+{
+ char *rv, *t;
+
+ t = rv = rv_alloc(n);
+ if (!rv) return NULL;
+ while ((*t = *s++) != 0) t++;
+ if (rve)
+ *rve = t;
+ return rv;
+}
+
+#define rv_strdup(s, rve) nrv_alloc((s), (rve), strlen(s)+1)
+
+#ifndef MULTIPLE_THREADS
+/* freedtoa(s) must be used to free values s returned by dtoa
+ * when MULTIPLE_THREADS is #defined. It should be used in all cases,
+ * but for consistency with earlier versions of dtoa, it is optional
+ * when MULTIPLE_THREADS is not defined.
+ */
+
+static void
+freedtoa(char *s)
+{
+ FREE(s);
+}
+#endif
+
+static const char INFSTR[] = "Infinity";
+static const char NANSTR[] = "NaN";
+static const char ZEROSTR[] = "0";
+
+/* dtoa for IEEE arithmetic (dmg): convert double to ASCII string.
+ *
+ * Inspired by "How to Print Floating-Point Numbers Accurately" by
+ * Guy L. Steele, Jr. and Jon L. White [Proc. ACM SIGPLAN '90, pp. 112-126].
+ *
+ * Modifications:
+ * 1. Rather than iterating, we use a simple numeric overestimate
+ * to determine k = floor(log10(d)). We scale relevant
+ * quantities using O(log2(k)) rather than O(k) multiplications.
+ * 2. For some modes > 2 (corresponding to ecvt and fcvt), we don't
+ * try to generate digits strictly left to right. Instead, we
+ * compute with fewer bits and propagate the carry if necessary
+ * when rounding the final digit up. This is often faster.
+ * 3. Under the assumption that input will be rounded nearest,
+ * mode 0 renders 1e23 as 1e23 rather than 9.999999999999999e22.
+ * That is, we allow equality in stopping tests when the
+ * round-nearest rule will give the same floating-point value
+ * as would satisfaction of the stopping test with strict
+ * inequality.
+ * 4. We remove common factors of powers of 2 from relevant
+ * quantities.
+ * 5. When converting floating-point integers less than 1e16,
+ * we use floating-point arithmetic rather than resorting
+ * to multiple-precision integers.
+ * 6. When asked to produce fewer than 15 digits, we first try
+ * to get by with floating-point arithmetic; we resort to
+ * multiple-precision integer arithmetic only if we cannot
+ * guarantee that the floating-point calculation has given
+ * the correctly rounded result. For k requested digits and
+ * "uniformly" distributed input, the probability is
+ * something like 10^(k-15) that we must resort to the Long
+ * calculation.
+ */
+
+char *
+dtoa(double d_, int mode, int ndigits, int *decpt, int *sign, char **rve)
+{
+ /* Arguments ndigits, decpt, sign are similar to those
+ of ecvt and fcvt; trailing zeros are suppressed from
+ the returned string. If not null, *rve is set to point
+ to the end of the return value. If d is +-Infinity or NaN,
+ then *decpt is set to 9999.
+
+ mode:
+ 0 ==> shortest string that yields d when read in
+ and rounded to nearest.
+ 1 ==> like 0, but with Steele & White stopping rule;
+ e.g. with IEEE P754 arithmetic , mode 0 gives
+ 1e23 whereas mode 1 gives 9.999999999999999e22.
+ 2 ==> max(1,ndigits) significant digits. This gives a
+ return value similar to that of ecvt, except
+ that trailing zeros are suppressed.
+ 3 ==> through ndigits past the decimal point. This
+ gives a return value similar to that from fcvt,
+ except that trailing zeros are suppressed, and
+ ndigits can be negative.
+ 4,5 ==> similar to 2 and 3, respectively, but (in
+ round-nearest mode) with the tests of mode 0 to
+ possibly return a shorter string that rounds to d.
+ With IEEE arithmetic and compilation with
+ -DHonor_FLT_ROUNDS, modes 4 and 5 behave the same
+ as modes 2 and 3 when FLT_ROUNDS != 1.
+ 6-9 ==> Debugging modes similar to mode - 4: don't try
+ fast floating-point estimate (if applicable).
+
+ Values of mode other than 0-9 are treated as mode 0.
+
+ Sufficient space is allocated to the return value
+ to hold the suppressed trailing zeros.
+ */
+
+ int bbits, b2, b5, be, dig, i, ieps, ilim, ilim0, ilim1,
+ j, j1, k, k0, k_check, leftright, m2, m5, s2, s5,
+ spec_case, try_quick, half = 0;
+ Long L;
+#ifndef Sudden_Underflow
+ int denorm;
+ ULong x;
+#endif
+ Bigint *b, *b1, *delta, *mlo = 0, *mhi = 0, *S;
+ double ds;
+ double_u d, d2, eps;
+ char *s, *s0;
+#ifdef Honor_FLT_ROUNDS
+ int rounding;
+#endif
+#ifdef SET_INEXACT
+ int inexact, oldinexact;
+#endif
+
+ dval(d) = d_;
+
+#ifndef MULTIPLE_THREADS
+ if (dtoa_result) {
+ freedtoa(dtoa_result);
+ dtoa_result = 0;
+ }
+#endif
+
+ if (word0(d) & Sign_bit) {
+ /* set sign for everything, including 0's and NaNs */
+ *sign = 1;
+ word0(d) &= ~Sign_bit; /* clear sign bit */
+ }
+ else
+ *sign = 0;
+
+#if defined(IEEE_Arith) + defined(VAX)
+#ifdef IEEE_Arith
+ if ((word0(d) & Exp_mask) == Exp_mask)
+#else
+ if (word0(d) == 0x8000)
+#endif
+ {
+ /* Infinity or NaN */
+ *decpt = 9999;
+#ifdef IEEE_Arith
+ if (!word1(d) && !(word0(d) & 0xfffff))
+ return rv_strdup(INFSTR, rve);
+#endif
+ return rv_strdup(NANSTR, rve);
+ }
+#endif
+#ifdef IBM
+ dval(d) += 0; /* normalize */
+#endif
+ if (!dval(d)) {
+ *decpt = 1;
+ return rv_strdup(ZEROSTR, rve);
+ }
+
+#ifdef SET_INEXACT
+ try_quick = oldinexact = get_inexact();
+ inexact = 1;
+#endif
+#ifdef Honor_FLT_ROUNDS
+ if ((rounding = Flt_Rounds) >= 2) {
+ if (*sign)
+ rounding = rounding == 2 ? 0 : 2;
+ else
+ if (rounding != 2)
+ rounding = 0;
+ }
+#endif
+
+ b = d2b(dval(d), &be, &bbits);
+ if (!b) return NULL;
+#ifdef Sudden_Underflow
+ i = (int)(word0(d) >> Exp_shift1 & (Exp_mask>>Exp_shift1));
+#else
+ if ((i = (int)(word0(d) >> Exp_shift1 & (Exp_mask>>Exp_shift1))) != 0) {
+#endif
+ dval(d2) = dval(d);
+ word0(d2) &= Frac_mask1;
+ word0(d2) |= Exp_11;
+#ifdef IBM
+ if (j = 11 - hi0bits(word0(d2) & Frac_mask))
+ dval(d2) /= 1 << j;
+#endif
+
+ /* log(x) ~=~ log(1.5) + (x-1.5)/1.5
+ * log10(x) = log(x) / log(10)
+ * ~=~ log(1.5)/log(10) + (x-1.5)/(1.5*log(10))
+ * log10(d) = (i-Bias)*log(2)/log(10) + log10(d2)
+ *
+ * This suggests computing an approximation k to log10(d) by
+ *
+ * k = (i - Bias)*0.301029995663981
+ * + ( (d2-1.5)*0.289529654602168 + 0.176091259055681 );
+ *
+ * We want k to be too large rather than too small.
+ * The error in the first-order Taylor series approximation
+ * is in our favor, so we just round up the constant enough
+ * to compensate for any error in the multiplication of
+ * (i - Bias) by 0.301029995663981; since |i - Bias| <= 1077,
+ * and 1077 * 0.30103 * 2^-52 ~=~ 7.2e-14,
+ * adding 1e-13 to the constant term more than suffices.
+ * Hence we adjust the constant term to 0.1760912590558.
+ * (We could get a more accurate k by invoking log10,
+ * but this is probably not worthwhile.)
+ */
+
+ i -= Bias;
+#ifdef IBM
+ i <<= 2;
+ i += j;
+#endif
+#ifndef Sudden_Underflow
+ denorm = 0;
+ }
+ else {
+ /* d is denormalized */
+
+ i = bbits + be + (Bias + (P-1) - 1);
+ x = i > 32 ? word0(d) << (64 - i) | word1(d) >> (i - 32)
+ : word1(d) << (32 - i);
+ dval(d2) = x;
+ word0(d2) -= 31*Exp_msk1; /* adjust exponent */
+ i -= (Bias + (P-1) - 1) + 1;
+ denorm = 1;
+ }
+#endif
+ ds = (dval(d2)-1.5)*0.289529654602168 + 0.1760912590558 + i*0.301029995663981;
+ k = (int)ds;
+ if (ds < 0. && ds != k)
+ k--; /* want k = floor(ds) */
+ k_check = 1;
+ if (k >= 0 && k <= Ten_pmax) {
+ if (dval(d) < tens[k])
+ k--;
+ k_check = 0;
+ }
+ j = bbits - i - 1;
+ if (j >= 0) {
+ b2 = 0;
+ s2 = j;
+ }
+ else {
+ b2 = -j;
+ s2 = 0;
+ }
+ if (k >= 0) {
+ b5 = 0;
+ s5 = k;
+ s2 += k;
+ }
+ else {
+ b2 -= k;
+ b5 = -k;
+ s5 = 0;
+ }
+ if (mode < 0 || mode > 9)
+ mode = 0;
+
+#ifndef SET_INEXACT
+#ifdef Check_FLT_ROUNDS
+ try_quick = Rounding == 1;
+#else
+ try_quick = 1;
+#endif
+#endif /*SET_INEXACT*/
+
+ if (mode > 5) {
+ mode -= 4;
+ try_quick = 0;
+ }
+ leftright = 1;
+ ilim = ilim1 = -1;
+ switch (mode) {
+ case 0:
+ case 1:
+ i = 18;
+ ndigits = 0;
+ break;
+ case 2:
+ leftright = 0;
+ /* no break */
+ case 4:
+ if (ndigits <= 0)
+ ndigits = 1;
+ ilim = ilim1 = i = ndigits;
+ break;
+ case 3:
+ leftright = 0;
+ /* no break */
+ case 5:
+ if (ckd_add(&i, ndigits, k + 1)) { /* k + 1 should be safe */
+ Bfree(b);
+ return NULL;
+ }
+ ilim = i;
+ ilim1 = i - 1;
+ if (i <= 0)
+ i = 1;
+ }
+ s = s0 = rv_alloc(i+1);
+ if (!s) {
+ Bfree(b);
+ return NULL;
+ }
+
+#ifdef Honor_FLT_ROUNDS
+ if (mode > 1 && rounding != 1)
+ leftright = 0;
+#endif
+
+ if (ilim >= 0 && ilim <= Quick_max && try_quick) {
+
+ /* Try to get by with floating-point arithmetic. */
+
+ i = 0;
+ dval(d2) = dval(d);
+ k0 = k;
+ ilim0 = ilim;
+ ieps = 2; /* conservative */
+ if (k > 0) {
+ ds = tens[k&0xf];
+ j = k >> 4;
+ if (j & Bletch) {
+ /* prevent overflows */
+ j &= Bletch - 1;
+ dval(d) /= bigtens[n_bigtens-1];
+ ieps++;
+ }
+ for (; j; j >>= 1, i++)
+ if (j & 1) {
+ ieps++;
+ ds *= bigtens[i];
+ }
+ dval(d) /= ds;
+ }
+ else if ((j1 = -k) != 0) {
+ dval(d) *= tens[j1 & 0xf];
+ for (j = j1 >> 4; j; j >>= 1, i++)
+ if (j & 1) {
+ ieps++;
+ dval(d) *= bigtens[i];
+ }
+ }
+ if (k_check && dval(d) < 1. && ilim > 0) {
+ if (ilim1 <= 0)
+ goto fast_failed;
+ ilim = ilim1;
+ k--;
+ dval(d) *= 10.;
+ ieps++;
+ }
+ dval(eps) = ieps*dval(d) + 7.;
+ word0(eps) -= (P-1)*Exp_msk1;
+ if (ilim == 0) {
+ S = mhi = 0;
+ dval(d) -= 5.;
+ if (dval(d) > dval(eps))
+ goto one_digit;
+ if (dval(d) < -dval(eps))
+ goto no_digits;
+ goto fast_failed;
+ }
+#ifndef No_leftright
+ if (leftright) {
+ /* Use Steele & White method of only
+ * generating digits needed.
+ */
+ dval(eps) = 0.5/tens[ilim-1] - dval(eps);
+ for (i = 0;;) {
+ L = (int)dval(d);
+ dval(d) -= L;
+ *s++ = '0' + (int)L;
+ if (dval(d) < dval(eps))
+ goto ret1;
+ if (1. - dval(d) < dval(eps))
+ goto bump_up;
+ if (++i >= ilim)
+ break;
+ dval(eps) *= 10.;
+ dval(d) *= 10.;
+ }
+ }
+ else {
+#endif
+ /* Generate ilim digits, then fix them up. */
+ dval(eps) *= tens[ilim-1];
+ for (i = 1;; i++, dval(d) *= 10.) {
+ L = (Long)(dval(d));
+ if (!(dval(d) -= L))
+ ilim = i;
+ *s++ = '0' + (int)L;
+ if (i == ilim) {
+ if (dval(d) > 0.5 + dval(eps))
+ goto bump_up;
+ else if (dval(d) < 0.5 - dval(eps)) {
+ while (*--s == '0') ;
+ s++;
+ goto ret1;
+ }
+ half = 1;
+ if ((*(s-1) - '0') & 1) {
+ goto bump_up;
+ }
+ break;
+ }
+ }
+#ifndef No_leftright
+ }
+#endif
+fast_failed:
+ s = s0;
+ dval(d) = dval(d2);
+ k = k0;
+ ilim = ilim0;
+ }
+
+ /* Do we have a "small" integer? */
+
+ if (be >= 0 && k <= Int_max) {
+ /* Yes. */
+ ds = tens[k];
+ if (ndigits < 0 && ilim <= 0) {
+ S = mhi = 0;
+ if (ilim < 0 || dval(d) <= 5*ds)
+ goto no_digits;
+ goto one_digit;
+ }
+ for (i = 1;; i++, dval(d) *= 10.) {
+ L = (Long)(dval(d) / ds);
+ dval(d) -= L*ds;
+#ifdef Check_FLT_ROUNDS
+ /* If FLT_ROUNDS == 2, L will usually be high by 1 */
+ if (dval(d) < 0) {
+ L--;
+ dval(d) += ds;
+ }
+#endif
+ *s++ = '0' + (int)L;
+ if (!dval(d)) {
+#ifdef SET_INEXACT
+ inexact = 0;
+#endif
+ break;
+ }
+ if (i == ilim) {
+#ifdef Honor_FLT_ROUNDS
+ if (mode > 1)
+ switch (rounding) {
+ case 0: goto ret1;
+ case 2: goto bump_up;
+ }
+#endif
+ dval(d) += dval(d);
+ if (dval(d) > ds || (dval(d) == ds && (L & 1))) {
+bump_up:
+ while (*--s == '9')
+ if (s == s0) {
+ k++;
+ *s = '0';
+ break;
+ }
+ ++*s++;
+ }
+ break;
+ }
+ }
+ goto ret1;
+ }
+
+ m2 = b2;
+ m5 = b5;
+ if (leftright) {
+ i =
+#ifndef Sudden_Underflow
+ denorm ? be + (Bias + (P-1) - 1 + 1) :
+#endif
+#ifdef IBM
+ 1 + 4*P - 3 - bbits + ((bbits + be - 1) & 3);
+#else
+ 1 + P - bbits;
+#endif
+ b2 += i;
+ s2 += i;
+ mhi = i2b(1);
+ if (!mhi) goto nomem;
+ }
+ if (m2 > 0 && s2 > 0) {
+ i = m2 < s2 ? m2 : s2;
+ b2 -= i;
+ m2 -= i;
+ s2 -= i;
+ }
+ if (b5 > 0) {
+ if (leftright) {
+ if (m5 > 0) {
+ mhi = pow5mult(mhi, m5);
+ if (!mhi) goto nomem;
+ b1 = mult(mhi, b);
+ Bfree(b);
+ b = b1;
+ if (!b) goto nomem;
+ }
+ if ((j = b5 - m5) != 0) {
+ b = pow5mult(b, j);
+ if (!b) goto nomem;
+ }
+ }
+ else {
+ b = pow5mult(b, b5);
+ if (!b) goto nomem;
+ }
+ }
+ S = i2b(1);
+ if (!S) goto nomem;
+ if (s5 > 0) {
+ S = pow5mult(S, s5);
+ if (!S) goto nomem;
+ }
+
+ /* Check for special case that d is a normalized power of 2. */
+
+ spec_case = 0;
+ if ((mode < 2 || leftright)
+#ifdef Honor_FLT_ROUNDS
+ && rounding == 1
+#endif
+ ) {
+ if (!word1(d) && !(word0(d) & Bndry_mask)
+#ifndef Sudden_Underflow
+ && word0(d) & (Exp_mask & ~Exp_msk1)
+#endif
+ ) {
+ /* The special case */
+ b2 += Log2P;
+ s2 += Log2P;
+ spec_case = 1;
+ }
+ }
+
+ /* Arrange for convenient computation of quotients:
+ * shift left if necessary so divisor has 4 leading 0 bits.
+ *
+ * Perhaps we should just compute leading 28 bits of S once
+ * and for all and pass them and a shift to quorem, so it
+ * can do shifts and ors to compute the numerator for q.
+ */
+#ifdef Pack_32
+ if ((i = ((s5 ? 32 - hi0bits(S->x[S->wds-1]) : 1) + s2) & 0x1f) != 0)
+ i = 32 - i;
+#else
+ if ((i = ((s5 ? 32 - hi0bits(S->x[S->wds-1]) : 1) + s2) & 0xf) != 0)
+ i = 16 - i;
+#endif
+ if (i > 4) {
+ i -= 4;
+ b2 += i;
+ m2 += i;
+ s2 += i;
+ }
+ else if (i < 4) {
+ i += 28;
+ b2 += i;
+ m2 += i;
+ s2 += i;
+ }
+ if (b2 > 0) {
+ b = lshift(b, b2);
+ if (!b) goto nomem;
+ }
+ if (s2 > 0) {
+ S = lshift(S, s2);
+ if (!S) goto nomem;
+ }
+ if (k_check) {
+ if (cmp(b,S) < 0) {
+ k--;
+ b = multadd(b, 10, 0); /* we botched the k estimate */
+ if (!b) goto nomem;
+ if (leftright) {
+ mhi = multadd(mhi, 10, 0);
+ if (!mhi) goto nomem;
+ }
+ ilim = ilim1;
+ }
+ }
+ if (ilim <= 0 && (mode == 3 || mode == 5)) {
+ if (ilim < 0 || cmp(b,S = multadd(S,5,0)) <= 0) {
+ /* no digits, fcvt style */
+no_digits:
+ k = -1 - ndigits;
+ goto ret;
+ }
+one_digit:
+ *s++ = '1';
+ k++;
+ goto ret;
+ }
+ if (leftright) {
+ if (m2 > 0) {
+ mhi = lshift(mhi, m2);
+ if (!mhi) goto nomem;
+ }
+
+ /* Compute mlo -- check for special case
+ * that d is a normalized power of 2.
+ */
+
+ mlo = mhi;
+ if (spec_case) {
+ mhi = Balloc(mhi->k);
+ if (!mhi) goto nomem;
+ Bcopy(mhi, mlo);
+ mhi = lshift(mhi, Log2P);
+ if (!mhi) goto nomem;
+ }
+
+ for (i = 1;;i++) {
+ dig = quorem(b,S) + '0';
+ /* Do we yet have the shortest decimal string
+ * that will round to d?
+ */
+ j = cmp(b, mlo);
+ delta = diff(S, mhi);
+ if (!delta) goto nomem;
+ j1 = delta->sign ? 1 : cmp(b, delta);
+ Bfree(delta);
+#ifndef ROUND_BIASED
+ if (j1 == 0 && mode != 1 && !(word1(d) & 1)
+#ifdef Honor_FLT_ROUNDS
+ && rounding >= 1
+#endif
+ ) {
+ if (dig == '9')
+ goto round_9_up;
+ if (j > 0)
+ dig++;
+#ifdef SET_INEXACT
+ else if (!b->x[0] && b->wds <= 1)
+ inexact = 0;
+#endif
+ *s++ = dig;
+ goto ret;
+ }
+#endif
+ if (j < 0 || (j == 0 && mode != 1
+#ifndef ROUND_BIASED
+ && !(word1(d) & 1)
+#endif
+ )) {
+ if (!b->x[0] && b->wds <= 1) {
+#ifdef SET_INEXACT
+ inexact = 0;
+#endif
+ goto accept_dig;
+ }
+#ifdef Honor_FLT_ROUNDS
+ if (mode > 1)
+ switch (rounding) {
+ case 0: goto accept_dig;
+ case 2: goto keep_dig;
+ }
+#endif /*Honor_FLT_ROUNDS*/
+ if (j1 > 0) {
+ b = lshift(b, 1);
+ if (!b) goto nomem;
+ j1 = cmp(b, S);
+ if ((j1 > 0 || (j1 == 0 && (dig & 1))) && dig++ == '9')
+ goto round_9_up;
+ }
+accept_dig:
+ *s++ = dig;
+ goto ret;
+ }
+ if (j1 > 0) {
+#ifdef Honor_FLT_ROUNDS
+ if (!rounding)
+ goto accept_dig;
+#endif
+ if (dig == '9') { /* possible if i == 1 */
+round_9_up:
+ *s++ = '9';
+ goto roundoff;
+ }
+ *s++ = dig + 1;
+ goto ret;
+ }
+#ifdef Honor_FLT_ROUNDS
+keep_dig:
+#endif
+ *s++ = dig;
+ if (i == ilim)
+ break;
+ b = multadd(b, 10, 0);
+ if (!b) goto nomem;
+ if (mlo == mhi) {
+ mlo = mhi = multadd(mhi, 10, 0);
+ if (!mlo) goto nomem;
+ }
+ else {
+ mlo = multadd(mlo, 10, 0);
+ if (!mlo) goto nomem;
+ mhi = multadd(mhi, 10, 0);
+ if (!mhi) goto nomem;
+ }
+ }
+ }
+ else
+ for (i = 1;; i++) {
+ *s++ = dig = quorem(b,S) + '0';
+ if (!b->x[0] && b->wds <= 1) {
+#ifdef SET_INEXACT
+ inexact = 0;
+#endif
+ goto ret;
+ }
+ if (i >= ilim)
+ break;
+ b = multadd(b, 10, 0);
+ if (!b) goto nomem;
+ }
+
+ /* Round off last digit */
+
+#ifdef Honor_FLT_ROUNDS
+ switch (rounding) {
+ case 0: goto trimzeros;
+ case 2: goto roundoff;
+ }
+#endif
+ b = lshift(b, 1);
+ if (!b) goto nomem;
+ j = cmp(b, S);
+ if (j > 0 || (j == 0 && (dig & 1))) {
+ roundoff:
+ while (*--s == '9')
+ if (s == s0) {
+ k++;
+ *s++ = '1';
+ goto ret;
+ }
+ if (!half || (*s - '0') & 1)
+ ++*s;
+ }
+ else {
+ while (*--s == '0') ;
+ }
+ s++;
+ret:
+ Bfree(S);
+ if (mhi) {
+ if (mlo && mlo != mhi)
+ Bfree(mlo);
+ Bfree(mhi);
+ }
+ret1:
+#ifdef SET_INEXACT
+ if (inexact) {
+ if (!oldinexact) {
+ word0(d) = Exp_1 + (70 << Exp_shift);
+ word1(d) = 0;
+ dval(d) += 1.;
+ }
+ }
+ else if (!oldinexact)
+ clear_inexact();
+#endif
+ Bfree(b);
+ *s = 0;
+ *decpt = k + 1;
+ if (rve)
+ *rve = s;
+ return s0;
+ nomem:
+ if (S) Bfree(S);
+ if (mhi) {
+ if (mlo && mlo != mhi)
+ Bfree(mlo);
+ Bfree(mhi);
+ }
+ if (b) Bfree(b);
+ FREE(s0);
+ return NULL;
+}
+
+/*-
+ * Copyright (c) 2004-2008 David Schultz <das@FreeBSD.ORG>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#define DBL_MANH_SIZE 20
+#define DBL_MANL_SIZE 32
+#define DBL_ADJ (DBL_MAX_EXP - 2)
+#define SIGFIGS ((DBL_MANT_DIG + 3) / 4 + 1)
+#define dexp_get(u) ((int)(word0(u) >> Exp_shift) & ~Exp_msk1)
+#define dexp_set(u,v) (word0(u) = (((int)(word0(u)) & ~Exp_mask) | ((v) << Exp_shift)))
+#define dmanh_get(u) ((uint32_t)(word0(u) & Frac_mask))
+#define dmanl_get(u) ((uint32_t)word1(u))
+
+
+/*
+ * This procedure converts a double-precision number in IEEE format
+ * into a string of hexadecimal digits and an exponent of 2. Its
+ * behavior is bug-for-bug compatible with dtoa() in mode 2, with the
+ * following exceptions:
+ *
+ * - An ndigits < 0 causes it to use as many digits as necessary to
+ * represent the number exactly.
+ * - The additional xdigs argument should point to either the string
+ * "0123456789ABCDEF" or the string "0123456789abcdef", depending on
+ * which case is desired.
+ * - This routine does not repeat dtoa's mistake of setting decpt
+ * to 9999 in the case of an infinity or NaN. INT_MAX is used
+ * for this purpose instead.
+ *
+ * Note that the C99 standard does not specify what the leading digit
+ * should be for non-zero numbers. For instance, 0x1.3p3 is the same
+ * as 0x2.6p2 is the same as 0x4.cp3. This implementation always makes
+ * the leading digit a 1. This ensures that the exponent printed is the
+ * actual base-2 exponent, i.e., ilogb(d).
+ *
+ * Inputs: d, xdigs, ndigits
+ * Outputs: decpt, sign, rve
+ */
+char *
+hdtoa(double d, const char *xdigs, int ndigits, int *decpt, int *sign, char **rve)
+{
+ U u;
+ char *s, *s0;
+ int bufsize;
+ uint32_t manh, manl;
+
+ u.d = d;
+ if (word0(u) & Sign_bit) {
+ /* set sign for everything, including 0's and NaNs */
+ *sign = 1;
+ word0(u) &= ~Sign_bit; /* clear sign bit */
+ }
+ else
+ *sign = 0;
+
+ if (isinf(d)) { /* FP_INFINITE */
+ *decpt = INT_MAX;
+ return rv_strdup(INFSTR, rve);
+ }
+ else if (isnan(d)) { /* FP_NAN */
+ *decpt = INT_MAX;
+ return rv_strdup(NANSTR, rve);
+ }
+ else if (d == 0.0) { /* FP_ZERO */
+ *decpt = 1;
+ return rv_strdup(ZEROSTR, rve);
+ }
+ else if (dexp_get(u)) { /* FP_NORMAL */
+ *decpt = dexp_get(u) - DBL_ADJ;
+ }
+ else { /* FP_SUBNORMAL */
+ u.d *= 5.363123171977039e+154 /* 0x1p514 */;
+ *decpt = dexp_get(u) - (514 + DBL_ADJ);
+ }
+
+ if (ndigits == 0) /* dtoa() compatibility */
+ ndigits = 1;
+
+ /*
+ * If ndigits < 0, we are expected to auto-size, so we allocate
+ * enough space for all the digits.
+ */
+ bufsize = (ndigits > 0) ? ndigits : SIGFIGS;
+ s0 = rv_alloc(bufsize+1);
+ if (!s0) return NULL;
+
+ /* Round to the desired number of digits. */
+ if (SIGFIGS > ndigits && ndigits > 0) {
+ float redux = 1.0f;
+ int offset = 4 * ndigits + DBL_MAX_EXP - 4 - DBL_MANT_DIG;
+ dexp_set(u, offset);
+ u.d += redux;
+ u.d -= redux;
+ *decpt += dexp_get(u) - offset;
+ }
+
+ manh = dmanh_get(u);
+ manl = dmanl_get(u);
+ *s0 = '1';
+ for (s = s0 + 1; s < s0 + bufsize; s++) {
+ *s = xdigs[(manh >> (DBL_MANH_SIZE - 4)) & 0xf];
+ manh = (manh << 4) | (manl >> (DBL_MANL_SIZE - 4));
+ manl <<= 4;
+ }
+
+ /* If ndigits < 0, we are expected to auto-size the precision. */
+ if (ndigits < 0) {
+ for (ndigits = SIGFIGS; s0[ndigits - 1] == '0'; ndigits--)
+ ;
+ }
+
+ s = s0 + ndigits;
+ *s = '\0';
+ if (rve != NULL)
+ *rve = s;
+ return (s0);
+}
+
+#ifdef __cplusplus
+#if 0
+{ /* satisfy cc-mode */
+#endif
+}
+#endif
diff --git a/vendor/bundle/ruby/3.4.0/gems/bigdecimal-4.1.2/ext/bigdecimal/ntt.h b/vendor/bundle/ruby/3.4.0/gems/bigdecimal-4.1.2/ext/bigdecimal/ntt.h
new file mode 100644
index 0000000..bbd8376
--- /dev/null
+++ b/vendor/bundle/ruby/3.4.0/gems/bigdecimal-4.1.2/ext/bigdecimal/ntt.h
@@ -0,0 +1,191 @@
+// NTT (Number Theoretic Transform) implementation for BigDecimal multiplication
+
+#define NTT_PRIMITIVE_ROOT 17
+#define NTT_PRIME_BASE1 24
+#define NTT_PRIME_BASE2 26
+#define NTT_PRIME_BASE3 29
+#define NTT_PRIME_SHIFT 27
+#define NTT_PRIME1 (((uint32_t)NTT_PRIME_BASE1 << NTT_PRIME_SHIFT) | 1)
+#define NTT_PRIME2 (((uint32_t)NTT_PRIME_BASE2 << NTT_PRIME_SHIFT) | 1)
+#define NTT_PRIME3 (((uint32_t)NTT_PRIME_BASE3 << NTT_PRIME_SHIFT) | 1)
+#define MAX_NTT32_BITS 27
+#define NTT_DECDIG_BASE 1000000000
+
+// Calculates base**ex % mod
+static uint32_t
+mod_pow(uint32_t base, uint32_t ex, uint32_t mod) {
+ uint32_t res = 1;
+ uint32_t bit = 1;
+ while (true) {
+ if (ex & bit) {
+ ex ^= bit;
+ res = ((uint64_t)res * base) % mod;
+ }
+ if (!ex) break;
+ base = ((uint64_t)base * base) % mod;
+ bit <<= 1;
+ }
+ return res;
+}
+
+// Recursively performs butterfly operations of NTT
+static void
+ntt_recursive(int size_bits, uint32_t *input, uint32_t *output, uint32_t *tmp, int depth, uint32_t r, uint32_t prime) {
+ if (depth > 0) {
+ ntt_recursive(size_bits, input, tmp, output, depth - 1, ((uint64_t)r * r) % prime, prime);
+ } else {
+ tmp = input;
+ }
+ uint32_t size_half = (uint32_t)1 << (size_bits - 1);
+ uint32_t stride = (uint32_t)1 << (size_bits - depth - 1);
+ uint32_t n = size_half / stride;
+ uint32_t rn = 1, rm = prime - 1;
+ for (uint32_t i = 0; i < n; i++) {
+ uint32_t *aptr = tmp + i * 2 * stride;
+ uint32_t *bptr = aptr + stride;
+ uint32_t *out1 = output + stride * i;
+ uint32_t *out2 = out1 + size_half;
+ for (uint32_t k = 0; k < stride; k++) {
+ uint32_t a = aptr[k], b = bptr[k];
+ out1[k] = (a + (uint64_t)rn * b) % prime;
+ out2[k] = (a + (uint64_t)rm * b) % prime;
+ }
+ rn = ((uint64_t)rn * r) % prime;
+ rm = ((uint64_t)rm * r) % prime;
+ }
+}
+
+/* Perform NTT on input array.
+ * base, shift: Represent the prime number as (base << shift | 1)
+ * r_base: Primitive root of unity modulo prime
+ * size_bits: log2 of the size of the input array. Should be less or equal to shift
+ * input: input array of size (1 << size_bits)
+ */
+static void
+ntt(int size_bits, uint32_t *input, uint32_t *output, uint32_t *tmp, int r_base, int base, int shift, int dir) {
+ uint32_t size = (uint32_t)1 << size_bits;
+ uint32_t prime = ((uint32_t)base << shift) | 1;
+
+ // rmax**(1 << shift) % prime == 1
+ // r**size % prime == 1
+ uint32_t rmax = mod_pow((uint32_t)r_base, (uint32_t)base, prime);
+ uint32_t r = mod_pow(rmax, (uint32_t)1 << (shift - size_bits), prime);
+
+ if (dir < 0) r = mod_pow(r, prime - 2, prime);
+ ntt_recursive(size_bits, input, output, tmp, size_bits - 1, r, prime);
+ if (dir < 0) {
+ uint32_t n_inv = mod_pow((uint32_t)size, prime - 2, prime);
+ for (uint32_t i = 0; i < size; i++) {
+ output[i] = ((uint64_t)output[i] * n_inv) % prime;
+ }
+ }
+}
+
+/* Calculate c that satisfies: c % PRIME1 == mod1 && c % PRIME2 == mod2 && c % PRIME3 == mod3
+ * c = (mod1 * 35002755423056150739595925972 + mod2 * 14584479687667766215746868453 + mod3 * 37919651490985126265126719818) % (PRIME1 * PRIME2 * PRIME3)
+ * Assume c <= 999999999**2*(1<<27)
+ */
+static inline void
+mod_restore_prime_24_26_29_shift_27(uint32_t mod1, uint32_t mod2, uint32_t mod3, uint32_t *digits) {
+ // Use mixed radix notation to eliminate modulo by PRIME1 * PRIME2 * PRIME3
+ // [DIG0, DIG1, DIG2] = DIG0 + DIG1 * PRIME1 + DIG2 * PRIME1 * PRIME2
+ // DIG0: 0...PRIME1, DIG1: 0...PRIME2, DIG2: 0...PRIME3
+ // 35002755423056150739595925972 = [1, 3489660916, 3113851359]
+ // 14584479687667766215746868453 = [0, 13, 1297437912]
+ // 37919651490985126265126719818 = [0, 0, 3373338954]
+ uint64_t c0 = mod1;
+ uint64_t c1 = (uint64_t)mod2 * 13 + (uint64_t)mod1 * 3489660916;
+ uint64_t c2 = (uint64_t)mod3 * 3373338954 % NTT_PRIME3 + (uint64_t)mod2 * 1297437912 % NTT_PRIME3 + (uint64_t)mod1 * 3113851359 % NTT_PRIME3;
+ c2 += c1 / NTT_PRIME2;
+ c1 %= NTT_PRIME2;
+ c2 %= NTT_PRIME3;
+ // Base conversion. c fits in 3 digits.
+ c1 += c2 % NTT_DECDIG_BASE * NTT_PRIME2;
+ c0 += c1 % NTT_DECDIG_BASE * NTT_PRIME1;
+ c1 /= NTT_DECDIG_BASE;
+ digits[0] = c0 % NTT_DECDIG_BASE;
+ c0 /= NTT_DECDIG_BASE;
+ c1 += c2 / NTT_DECDIG_BASE % NTT_DECDIG_BASE * NTT_PRIME2;
+ c0 += c1 % NTT_DECDIG_BASE * NTT_PRIME1;
+ c1 /= NTT_DECDIG_BASE;
+ digits[1] = c0 % NTT_DECDIG_BASE;
+ digits[2] = (uint32_t)(c0 / NTT_DECDIG_BASE + c1 % NTT_DECDIG_BASE * NTT_PRIME1);
+}
+
+/*
+ * NTT multiplication
+ * Uses three NTTs with mod (24 << 27 | 1), (26 << 27 | 1), and (29 << 27 | 1)
+ */
+static void
+ntt_multiply(size_t a_size, size_t b_size, uint32_t *a, uint32_t *b, uint32_t *c) {
+ if (a_size < b_size) {
+ ntt_multiply(b_size, a_size, b, a, c);
+ return;
+ }
+
+ int ntt_size_bits = (int)bit_length(b_size - 1) + 1;
+ if (ntt_size_bits > MAX_NTT32_BITS) {
+ rb_raise(rb_eArgError, "Multiply size too large");
+ }
+
+ // To calculate large_a * small_b faster, split into several batches.
+ uint32_t ntt_size = (uint32_t)1 << ntt_size_bits;
+ uint32_t batch_size = ntt_size - (uint32_t)b_size;
+ uint32_t batch_count = (uint32_t)((a_size + batch_size - 1) / batch_size);
+
+ uint32_t *mem = ruby_xcalloc(ntt_size * 9, sizeof(uint32_t));
+ uint32_t *ntt1 = mem;
+ uint32_t *ntt2 = mem + ntt_size;
+ uint32_t *ntt3 = mem + ntt_size * 2;
+ uint32_t *tmp1 = mem + ntt_size * 3;
+ uint32_t *tmp2 = mem + ntt_size * 4;
+ uint32_t *tmp3 = mem + ntt_size * 5;
+ uint32_t *conv1 = mem + ntt_size * 6;
+ uint32_t *conv2 = mem + ntt_size * 7;
+ uint32_t *conv3 = mem + ntt_size * 8;
+
+ // Calculate NTT for b in three primes. Result is reused for each batch of a.
+ memcpy(tmp1, b, b_size * sizeof(uint32_t));
+ memset(tmp1 + b_size, 0, (ntt_size - b_size) * sizeof(uint32_t));
+ ntt(ntt_size_bits, tmp1, ntt1, tmp2, NTT_PRIMITIVE_ROOT, NTT_PRIME_BASE1, NTT_PRIME_SHIFT, +1);
+ ntt(ntt_size_bits, tmp1, ntt2, tmp2, NTT_PRIMITIVE_ROOT, NTT_PRIME_BASE2, NTT_PRIME_SHIFT, +1);
+ ntt(ntt_size_bits, tmp1, ntt3, tmp2, NTT_PRIMITIVE_ROOT, NTT_PRIME_BASE3, NTT_PRIME_SHIFT, +1);
+
+ memset(c, 0, (a_size + b_size) * sizeof(uint32_t));
+ for (uint32_t idx = 0; idx < batch_count; idx++) {
+ uint32_t len = idx == batch_count - 1 ? (uint32_t)a_size - idx * batch_size : batch_size;
+ memcpy(tmp1, a + idx * batch_size, len * sizeof(uint32_t));
+ memset(tmp1 + len, 0, (ntt_size - len) * sizeof(uint32_t));
+ // Calculate convolution for this batch in three primes
+ ntt(ntt_size_bits, tmp1, tmp2, tmp3, NTT_PRIMITIVE_ROOT, NTT_PRIME_BASE1, NTT_PRIME_SHIFT, +1);
+ for (uint32_t i = 0; i < ntt_size; i++) tmp2[i] = ((uint64_t)tmp2[i] * ntt1[i]) % NTT_PRIME1;
+ ntt(ntt_size_bits, tmp2, conv1, tmp3, NTT_PRIMITIVE_ROOT, NTT_PRIME_BASE1, NTT_PRIME_SHIFT, -1);
+ ntt(ntt_size_bits, tmp1, tmp2, tmp3, NTT_PRIMITIVE_ROOT, NTT_PRIME_BASE2, NTT_PRIME_SHIFT, +1);
+ for (uint32_t i = 0; i < ntt_size; i++) tmp2[i] = ((uint64_t)tmp2[i] * ntt2[i]) % NTT_PRIME2;
+ ntt(ntt_size_bits, tmp2, conv2, tmp3, NTT_PRIMITIVE_ROOT, NTT_PRIME_BASE2, NTT_PRIME_SHIFT, -1);
+ ntt(ntt_size_bits, tmp1, tmp2, tmp3, NTT_PRIMITIVE_ROOT, NTT_PRIME_BASE3, NTT_PRIME_SHIFT, +1);
+ for (uint32_t i = 0; i < ntt_size; i++) tmp2[i] = ((uint64_t)tmp2[i] * ntt3[i]) % NTT_PRIME3;
+ ntt(ntt_size_bits, tmp2, conv3, tmp3, NTT_PRIMITIVE_ROOT, NTT_PRIME_BASE3, NTT_PRIME_SHIFT, -1);
+
+ // Restore the original convolution value from three convolutions calculated in three primes.
+ // Each convolution value is maximum 999999999**2*(1<<27)/2
+ for (uint32_t i = 0; i < ntt_size; i++) {
+ uint32_t dig[3];
+ mod_restore_prime_24_26_29_shift_27(conv1[i], conv2[i], conv3[i], dig);
+ // Maximum values of dig[0], dig[1], and dig[2] are 999999999, 999999999 and 67108863 respectively
+ // Maximum overlapped sum (considering overlaps between 2 batches) is less than 4134217722
+ // so this sum doesn't overflow uint32_t.
+ for (int j = 0; j < 3; j++) {
+ // Index check: if dig[j] is non-zero, assign index is within valid range.
+ if (dig[j]) c[idx * batch_size + i + 1 - (uint32_t)j] += dig[j];
+ }
+ }
+ }
+ uint32_t carry = 0;
+ for (int32_t i = (int32_t)(a_size + b_size - 1); i >= 0; i--) {
+ uint32_t v = c[i] + carry;
+ c[i] = v % NTT_DECDIG_BASE;
+ carry = v / NTT_DECDIG_BASE;
+ }
+ ruby_xfree(mem);
+}
diff --git a/vendor/bundle/ruby/3.4.0/gems/bigdecimal-4.1.2/ext/bigdecimal/static_assert.h b/vendor/bundle/ruby/3.4.0/gems/bigdecimal-4.1.2/ext/bigdecimal/static_assert.h
new file mode 100644
index 0000000..9295729
--- /dev/null
+++ b/vendor/bundle/ruby/3.4.0/gems/bigdecimal-4.1.2/ext/bigdecimal/static_assert.h
@@ -0,0 +1,54 @@
+#ifndef BIGDECIMAL_STATIC_ASSERT_H
+#define BIGDECIMAL_STATIC_ASSERT_H
+
+#include "feature.h"
+
+#ifdef HAVE_RUBY_INTERNAL_STATIC_ASSERT_H
+# include <ruby/internal/static_assert.h>
+#endif
+
+#ifdef RBIMPL_STATIC_ASSERT
+# define STATIC_ASSERT RBIMPL_STATIC_ASSERT
+#endif
+
+#ifndef STATIC_ASSERT
+# /* The following section is copied from CRuby's static_assert.h */
+
+# if defined(__cplusplus) && defined(__cpp_static_assert)
+# /* https://isocpp.org/std/standing-documents/sd-6-sg10-feature-test-recommendations */
+# define BIGDECIMAL_STATIC_ASSERT0 static_assert
+
+# elif defined(__cplusplus) && defined(_MSC_VER) && _MSC_VER >= 1600
+# define BIGDECIMAL_STATIC_ASSERT0 static_assert
+
+# elif defined(__INTEL_CXX11_MODE__)
+# define BIGDECIMAL_STATIC_ASSERT0 static_assert
+
+# elif defined(__cplusplus) && __cplusplus >= 201103L
+# define BIGDECIMAL_STATIC_ASSERT0 static_assert
+
+# elif defined(__cplusplus) && __has_extension(cxx_static_assert)
+# define BIGDECIMAL_STATIC_ASSERT0 __extension__ static_assert
+
+# elif defined(__STDC_VERSION__) && __has_extension(c_static_assert)
+# define BIGDECIMAL_STATIC_ASSERT0 __extension__ _Static_assert
+
+# elif defined(__STDC_VERSION__) && defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6))
+# define BIGDECIMAL_STATIC_ASSERT0 __extension__ _Static_assert
+#endif
+
+# if defined(__DOXYGEN__)
+# define STATIC_ASSERT static_assert
+
+# elif defined(BIGDECIMAL_STATIC_ASSERT0)
+# define STATIC_ASSERT(name, expr) \
+ BIGDECIMAL_STATIC_ASSERT0(expr, #name ": " #expr)
+
+# else
+# define STATIC_ASSERT(name, expr) \
+ typedef int static_assert_ ## name ## _check[1 - 2 * !(expr)]
+# endif
+#endif /* STATIC_ASSERT */
+
+
+#endif /* BIGDECIMAL_STATIC_ASSERT_H */