From 489cd853b846f5957936a14263181a7c5c45ca7f Mon Sep 17 00:00:00 2001 From: tompng Date: Fri, 6 Jun 2025 21:51:42 +0900 Subject: [PATCH] Remove back pointer from Real to VALUE ((Real*)x)->obj, a reference from DATA to VALUE, will be garbled after gc compaction. Real should not hold a reference to VALUE. --- ext/bigdecimal/bigdecimal.c | 895 +++++++++++++++-------------- ext/bigdecimal/bigdecimal.h | 5 - test/bigdecimal/test_bigdecimal.rb | 18 +- 3 files changed, 472 insertions(+), 446 deletions(-) diff --git a/ext/bigdecimal/bigdecimal.c b/ext/bigdecimal/bigdecimal.c index b4d29958..beedb7c2 100644 --- a/ext/bigdecimal/bigdecimal.c +++ b/ext/bigdecimal/bigdecimal.c @@ -68,6 +68,29 @@ static struct { uint8_t mode; } rbd_rounding_modes[RBD_NUM_ROUNDING_MODES]; +typedef struct { + VALUE bigdecimal; + Real *real; +} BDVALUE; + +typedef struct { + VALUE bigdecimal_or_nil; + Real *real_or_null; +} NULLABLE_BDVALUE; + +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 }; +} + /* MACRO's to guard objects from GC by keeping them in stack */ #ifdef RBIMPL_ATTR_MAYBE_UNUSED #define ENTER(n) RBIMPL_ATTR_MAYBE_UNUSED() volatile VALUE vStack[n];int iStack=0 @@ -75,8 +98,8 @@ static struct { #define ENTER(n) volatile VALUE RB_UNUSED_VAR(vStack[n]);int iStack=0 #endif #define PUSH(x) (vStack[iStack++] = (VALUE)(x)) -#define SAVE(p) PUSH((p)->obj) -#define GUARD_OBJ(p,y) ((p)=(y), SAVE(p)) +#define GUARD_OBJ(p, y) ((p)=(y), PUSH((p).bigdecimal)) +#define GUARD_OBJ_OR_NIL(p, y) ((p)=(y), PUSH((p).bigdecimal_or_nil)) #define BASE_FIG BIGDECIMAL_COMPONENT_FIGURES #define BASE BIGDECIMAL_BASE @@ -145,6 +168,9 @@ check_allocation_count_nonzero(void) # define check_allocation_count_nonzero() /* nothing */ #endif /* BIGDECIMAL_DEBUG */ +static NULLABLE_BDVALUE +CreateFromString(size_t mx, 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 @@ -190,18 +216,14 @@ rbd_allocate_struct_decimal_digits(size_t const decimal_digits, bool limit_preci static VALUE BigDecimal_wrap_struct(VALUE obj, Real *vp); -static Real * -rbd_reallocate_struct(Real *real, size_t const internal_digits) +static BDVALUE +rbd_reallocate_struct(BDVALUE value, size_t const internal_digits) { size_t const size = rbd_struct_size(internal_digits); - VALUE obj = real ? real->obj : 0; - Real *new_real = (Real *)ruby_xrealloc(real, size); + Real *new_real = (Real *)ruby_xrealloc(value.real, size); new_real->MaxPrec = internal_digits; - if (obj) { - new_real->obj = 0; - BigDecimal_wrap_struct(obj, new_real); - } - return new_real; + BigDecimal_wrap_struct(value.bigdecimal, new_real); + return (BDVALUE) { value.bigdecimal, new_real }; } static void @@ -277,7 +299,7 @@ rbd_allocate_struct_one_nolimit(int sign, size_t const digits) static unsigned short VpGetException(void); static void VpSetException(unsigned short f); static void VpCheckException(Real *p, bool always); -static VALUE VpCheckGetValue(Real *p); +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 Real *VpCopy(Real *pv, Real const* const x); @@ -319,58 +341,60 @@ static const rb_data_type_t BigDecimal_data_type = { #endif }; -static Real * +static NULLABLE_BDVALUE rbd_allocate_struct_zero_wrap_klass(VALUE klass, int sign, size_t const digits, bool limit_precision) { + VALUE obj = Qnil; Real *real = rbd_allocate_struct_zero(sign, digits, limit_precision); if (real != NULL) { - VALUE obj = TypedData_Wrap_Struct(klass, &BigDecimal_data_type, 0); + obj = TypedData_Wrap_Struct(klass, &BigDecimal_data_type, 0); BigDecimal_wrap_struct(obj, real); } - return real; + return (NULLABLE_BDVALUE) { obj, real }; } -MAYBE_UNUSED(static inline Real * rbd_allocate_struct_zero_limited_wrap(int sign, size_t const digits)); +MAYBE_UNUSED(static inline BDVALUE rbd_allocate_struct_zero_limited_wrap(int sign, size_t const digits)); #define NewZeroWrapLimited rbd_allocate_struct_zero_limited_wrap -static inline Real * +static inline BDVALUE rbd_allocate_struct_zero_limited_wrap(int sign, size_t const digits) { - return rbd_allocate_struct_zero_wrap_klass(rb_cBigDecimal, sign, digits, true); + return bdvalue_nonnullable(rbd_allocate_struct_zero_wrap_klass(rb_cBigDecimal, sign, digits, true)); } -MAYBE_UNUSED(static inline Real * rbd_allocate_struct_zero_nolimit_wrap(int sign, size_t const digits)); +MAYBE_UNUSED(static inline BDVALUE rbd_allocate_struct_zero_nolimit_wrap(int sign, size_t const digits)); #define NewZeroWrapNolimit rbd_allocate_struct_zero_nolimit_wrap -static inline Real * +static inline BDVALUE rbd_allocate_struct_zero_nolimit_wrap(int sign, size_t const digits) { - return rbd_allocate_struct_zero_wrap_klass(rb_cBigDecimal, sign, digits, false); + return bdvalue_nonnullable(rbd_allocate_struct_zero_wrap_klass(rb_cBigDecimal, sign, digits, false)); } -static Real * +static NULLABLE_BDVALUE rbd_allocate_struct_one_wrap_klass(VALUE klass, int sign, size_t const digits, bool limit_precision) { + VALUE obj = Qnil; Real *real = rbd_allocate_struct_one(sign, digits, limit_precision); if (real != NULL) { - VALUE obj = TypedData_Wrap_Struct(klass, &BigDecimal_data_type, 0); + obj = TypedData_Wrap_Struct(klass, &BigDecimal_data_type, 0); BigDecimal_wrap_struct(obj, real); } - return real; + return (NULLABLE_BDVALUE) { obj, real }; } -MAYBE_UNUSED(static inline Real * rbd_allocate_struct_one_limited_wrap(int sign, size_t const digits)); +MAYBE_UNUSED(static inline BDVALUE rbd_allocate_struct_one_limited_wrap(int sign, size_t const digits)); #define NewOneWrapLimited rbd_allocate_struct_one_limited_wrap -static inline Real * +static inline BDVALUE rbd_allocate_struct_one_limited_wrap(int sign, size_t const digits) { - return rbd_allocate_struct_one_wrap_klass(rb_cBigDecimal, sign, digits, true); + return bdvalue_nonnullable(rbd_allocate_struct_one_wrap_klass(rb_cBigDecimal, sign, digits, true)); } -MAYBE_UNUSED(static inline Real * rbd_allocate_struct_one_nolimit_wrap(int sign, size_t const digits)); +MAYBE_UNUSED(static inline BDVALUE rbd_allocate_struct_one_nolimit_wrap(int sign, size_t const digits)); #define NewOneWrapNolimit rbd_allocate_struct_one_nolimit_wrap -static inline Real * +static inline BDVALUE rbd_allocate_struct_one_nolimit_wrap(int sign, size_t const digits) { - return rbd_allocate_struct_one_wrap_klass(rb_cBigDecimal, sign, digits, false); + return bdvalue_nonnullable(rbd_allocate_struct_one_wrap_klass(rb_cBigDecimal, sign, digits, false)); } static inline int @@ -404,8 +428,8 @@ static VALUE rb_rational_convert_to_BigDecimal(VALUE val, size_t digs, int raise static VALUE rb_cstr_convert_to_BigDecimal(const char *c_str, size_t digs, int raise_exception); static VALUE rb_convert_to_BigDecimal(VALUE val, size_t digs, int raise_exception); -static Real* -GetVpValueWithPrec(VALUE v, long prec, int must) +static NULLABLE_BDVALUE +GetBDValueWithPrecInternal(VALUE v, long prec, int must) { const size_t digs = prec < 0 ? SIZE_MAX : (size_t)prec; @@ -452,19 +476,45 @@ GetVpValueWithPrec(VALUE v, long prec, int must) Real *vp; TypedData_Get_Struct(v, Real, &BigDecimal_data_type, vp); - return vp; + return (NULLABLE_BDVALUE) { v, vp }; SomeOneMayDoIt: if (must) { cannot_be_coerced_into_BigDecimal(rb_eTypeError, v); } - return NULL; /* NULL means to coerce */ + return (NULLABLE_BDVALUE) { Qnil, NULL }; /* NULL means to coerce */ +} + +static inline NULLABLE_BDVALUE +GetBDValueWithPrec(VALUE v, long prec) +{ + return GetBDValueWithPrecInternal(v, prec, 0); } + +static inline BDVALUE +GetBDValueWithPrecMust(VALUE v, long 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* -GetVpValue(VALUE v, int must) +GetSelfVpValue(VALUE self) +{ + return GetBDValueWithPrecMust(self, -1).real; +} + +static inline NULLABLE_BDVALUE +GetBDValue(VALUE v) { - return GetVpValueWithPrec(v, -1, must); + return GetBDValueWithPrec(v, -1); +} + +static inline BDVALUE +GetBDValueMust(VALUE v) +{ + return GetBDValueWithPrecMust(v, -1); } /* call-seq: @@ -499,16 +549,16 @@ static VALUE BigDecimal_prec(VALUE self) { ENTER(1); - Real *p; + BDVALUE v; VALUE obj; rb_category_warn(RB_WARN_CATEGORY_DEPRECATED, "BigDecimal#precs is deprecated and will be removed in the future; " "use BigDecimal#precision instead."); - GUARD_OBJ(p, GetVpValue(self, 1)); - obj = rb_assoc_new(SIZET2NUM(p->Prec*VpBaseFig()), - SIZET2NUM(p->MaxPrec*VpBaseFig())); + GUARD_OBJ(v, GetBDValueMust(self)); + obj = rb_assoc_new(SIZET2NUM(v.real->Prec*VpBaseFig()), + SIZET2NUM(v.real->MaxPrec*VpBaseFig())); return obj; } @@ -624,9 +674,9 @@ static void BigDecimal_count_precision_and_scale(VALUE self, ssize_t *out_precision, ssize_t *out_scale) { ENTER(1); - Real *p; - GUARD_OBJ(p, GetVpValue(self, 1)); - VpCountPrecisionAndScale(p, out_precision, out_scale); + BDVALUE v; + GUARD_OBJ(v, GetBDValueMust(self)); + VpCountPrecisionAndScale(v.real, out_precision, out_scale); } /* @@ -716,23 +766,22 @@ static VALUE BigDecimal_n_significant_digits(VALUE self) { ENTER(1); - - Real *p; - GUARD_OBJ(p, GetVpValue(self, 1)); - if (VpIsZero(p) || !VpIsDef(p)) { + BDVALUE v; + GUARD_OBJ(v, GetBDValueMust(self)); + if (VpIsZero(v.real) || !VpIsDef(v.real)) { return INT2FIX(0); } - ssize_t n = p->Prec; /* The length of frac without trailing zeros. */ - for (n = p->Prec; n > 0 && p->frac[n-1] == 0; --n); + 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 = p->frac[0]; x > 0; x /= 10) --nlz; + for (x = v.real->frac[0]; x > 0; x /= 10) --nlz; int ntz = 0; - for (x = p->frac[n-1]; x > 0 && x % 10 == 0; x /= 10) ++ntz; + for (x = v.real->frac[n-1]; x > 0 && x % 10 == 0; x /= 10) ++ntz; ssize_t n_significant_digits = BASE_FIG*n - nlz - ntz; return SSIZET2NUM(n_significant_digits); @@ -756,15 +805,15 @@ static VALUE BigDecimal_hash(VALUE self) { ENTER(1); - Real *p; + BDVALUE v; st_index_t hash; - GUARD_OBJ(p, GetVpValue(self, 1)); - hash = (st_index_t)p->sign; + GUARD_OBJ(v, GetBDValueMust(self)); + 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(p->frac, sizeof(DECDIG)*p->Prec); - hash += p->exponent; + hash ^= rb_memhash(v.real->frac, sizeof(DECDIG)*v.real->Prec); + hash += v.real->exponent; } return ST2FIX(hash); } @@ -785,19 +834,19 @@ static VALUE BigDecimal_dump(int argc, VALUE *argv, VALUE self) { ENTER(5); - Real *vp; + BDVALUE v; char *psz; VALUE dummy; volatile VALUE dump; size_t len; rb_scan_args(argc, argv, "01", &dummy); - GUARD_OBJ(vp,GetVpValue(self, 1)); - dump = rb_str_new(0, VpNumOfChars(vp, "E")+50); + GUARD_OBJ(v, GetBDValueMust(self)); + dump = rb_str_new(0, VpNumOfChars(v.real, "E")+50); psz = RSTRING_PTR(dump); - snprintf(psz, RSTRING_LEN(dump), "%"PRIuSIZE":", VpMaxPrec(vp)*VpBaseFig()); + snprintf(psz, RSTRING_LEN(dump), "%"PRIuSIZE":", VpMaxPrec(v.real)*VpBaseFig()); len = strlen(psz); - VpToString(vp, psz+len, RSTRING_LEN(dump)-len, 0, 0); + VpToString(v.real, psz+len, RSTRING_LEN(dump)-len, 0, 0); rb_str_resize(dump, strlen(psz)); return dump; } @@ -809,7 +858,7 @@ static VALUE BigDecimal_load(VALUE self, VALUE str) { ENTER(2); - Real *pv; + BDVALUE v; unsigned char *pch; unsigned char ch; unsigned long m=0; @@ -823,12 +872,12 @@ BigDecimal_load(VALUE self, VALUE str) m = m*10 + (unsigned long)(ch-'0'); } if (m > VpBaseFig()) m -= VpBaseFig(); - GUARD_OBJ(pv, VpNewRbClass(m, (char *)pch, self, true, true)); + GUARD_OBJ(v, bdvalue_nonnullable(CreateFromString(m, (char *)pch, self, true, true))); m /= VpBaseFig(); - if (m && pv->MaxPrec > m) { - pv->MaxPrec = m+1; + if (m && v.real->MaxPrec > m) { + v.real->MaxPrec = m+1; } - return VpCheckGetValue(pv); + return CheckGetValue(v); } static unsigned short @@ -1162,33 +1211,25 @@ BigDecimal_wrap_struct(VALUE obj, Real *vp) assert(is_kind_of_BigDecimal(obj)); assert(vp != NULL); - if (vp->obj == obj && RTYPEDDATA_DATA(obj) == vp) + if (RTYPEDDATA_DATA(obj) == vp) return obj; assert(RTYPEDDATA_DATA(obj) == NULL); - assert(vp->obj == 0); RTYPEDDATA_DATA(obj) = vp; - vp->obj = obj; RB_OBJ_FREEZE(obj); return obj; } -VP_EXPORT Real * -VpNewRbClass(size_t mx, const char *str, VALUE klass, bool strict_p, bool raise_exception) +static NULLABLE_BDVALUE +CreateFromString(size_t mx, const char *str, VALUE klass, bool strict_p, bool raise_exception) { VALUE obj = TypedData_Wrap_Struct(klass, &BigDecimal_data_type, 0); Real *pv = VpAlloc(mx, str, strict_p, raise_exception); if (!pv) - return NULL; + return (NULLABLE_BDVALUE) { Qnil, NULL }; BigDecimal_wrap_struct(obj, pv); - return pv; -} - -VP_EXPORT Real * -VpCreateRbObject(size_t mx, const char *str, bool raise_exception) -{ - return VpNewRbClass(mx, str, rb_cBigDecimal, true, raise_exception); + return (NULLABLE_BDVALUE) { obj, pv }; } static Real * @@ -1196,7 +1237,7 @@ VpCopy(Real *pv, Real const* const x) { assert(x != NULL); - pv = rbd_reallocate_struct(pv, x->MaxPrec); + pv = (Real *)ruby_xrealloc(pv, rbd_struct_size(x->MaxPrec)); pv->MaxPrec = x->MaxPrec; pv->Prec = x->Prec; pv->exponent = x->exponent; @@ -1211,7 +1252,7 @@ VpCopy(Real *pv, Real const* const x) static VALUE BigDecimal_IsNaN(VALUE self) { - Real *p = GetVpValue(self, 1); + Real *p = GetSelfVpValue(self); if (VpIsNaN(p)) return Qtrue; return Qfalse; } @@ -1222,7 +1263,7 @@ BigDecimal_IsNaN(VALUE self) static VALUE BigDecimal_IsInfinite(VALUE self) { - Real *p = GetVpValue(self, 1); + Real *p = GetSelfVpValue(self); if (VpIsPosInf(p)) return INT2FIX(1); if (VpIsNegInf(p)) return INT2FIX(-1); return Qnil; @@ -1232,7 +1273,7 @@ BigDecimal_IsInfinite(VALUE self) static VALUE BigDecimal_IsFinite(VALUE self) { - Real *p = GetVpValue(self, 1); + Real *p = GetSelfVpValue(self); if (VpIsNaN(p)) return Qfalse; if (VpIsInf(p)) return Qfalse; return Qtrue; @@ -1255,16 +1296,16 @@ BigDecimal_to_i(VALUE self) { ENTER(5); ssize_t e, nf; - Real *p; + BDVALUE v; - GUARD_OBJ(p, GetVpValue(self, 1)); - BigDecimal_check_num(p); + GUARD_OBJ(v, GetBDValueMust(self)); + BigDecimal_check_num(v.real); - e = VpExponent10(p); + e = VpExponent10(v.real); if (e <= 0) return INT2FIX(0); nf = VpBaseFig(); if (e <= nf) { - return LONG2NUM((long)(VpGetSign(p) * (DECDIG_DBL_SIGNED)p->frac[0])); + return LONG2NUM((long)(VpGetSign(v.real) * (DECDIG_DBL_SIGNED)v.real->frac[0])); } else { VALUE a = BigDecimal_split(self); @@ -1273,7 +1314,7 @@ BigDecimal_to_i(VALUE self) VALUE ret; ssize_t dpower = e - (ssize_t)RSTRING_LEN(digits); - if (BIGDECIMAL_NEGATIVE_P(p)) { + if (BIGDECIMAL_NEGATIVE_P(v.real)) { numerator = rb_funcall(numerator, '*', 1, INT2FIX(-1)); } if (dpower < 0) { @@ -1301,23 +1342,23 @@ static VALUE BigDecimal_to_f(VALUE self) { ENTER(1); - Real *p; + BDVALUE v; double d; SIGNED_VALUE e; char *buf; volatile VALUE str; - GUARD_OBJ(p, GetVpValue(self, 1)); - if (VpVtoD(&d, &e, p) != 1) + GUARD_OBJ(v, GetBDValueMust(self)); + 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-BASE_FIG)) goto underflow; - str = rb_str_new(0, VpNumOfChars(p, "E")); + str = rb_str_new(0, VpNumOfChars(v.real, "E")); buf = RSTRING_PTR(str); - VpToString(p, buf, RSTRING_LEN(str), 0, 0); + VpToString(v.real, buf, RSTRING_LEN(str), 0, 0); errno = 0; d = strtod(buf, 0); if (errno == ERANGE) { @@ -1328,14 +1369,14 @@ BigDecimal_to_f(VALUE self) overflow: VpException(VP_EXCEPTION_OVERFLOW, "BigDecimal to Float conversion", 0); - if (BIGDECIMAL_NEGATIVE_P(p)) + if (BIGDECIMAL_NEGATIVE_P(v.real)) return rb_float_new(VpGetDoubleNegInf()); else return rb_float_new(VpGetDoublePosInf()); underflow: VpException(VP_EXCEPTION_UNDERFLOW, "BigDecimal to Float conversion", 0); - if (BIGDECIMAL_NEGATIVE_P(p)) + if (BIGDECIMAL_NEGATIVE_P(v.real)) return rb_float_new(-0.0); else return rb_float_new(0.0); @@ -1347,15 +1388,15 @@ BigDecimal_to_f(VALUE self) static VALUE BigDecimal_to_r(VALUE self) { - Real *p; + BDVALUE v; ssize_t sign, power, denomi_power; VALUE a, digits, numerator; - p = GetVpValue(self, 1); - BigDecimal_check_num(p); + v = GetBDValueMust(self); + BigDecimal_check_num(v.real); - sign = VpGetSign(p); - power = VpExponent10(p); + sign = VpGetSign(v.real); + power = VpExponent10(v.real); a = BigDecimal_split(self); digits = RARRAY_AREF(a, 1); denomi_power = power - RSTRING_LEN(digits); @@ -1395,21 +1436,21 @@ BigDecimal_coerce(VALUE self, VALUE other) { ENTER(2); VALUE obj; - Real *b; + BDVALUE b; if (RB_TYPE_P(other, T_FLOAT)) { - GUARD_OBJ(b, GetVpValueWithPrec(other, 0, 1)); - obj = rb_assoc_new(VpCheckGetValue(b), self); + GUARD_OBJ(b, GetBDValueWithPrecMust(other, 0)); + obj = rb_assoc_new(CheckGetValue(b), self); } else { if (RB_TYPE_P(other, T_RATIONAL)) { Real* pv = DATA_PTR(self); - GUARD_OBJ(b, GetVpValueWithPrec(other, pv->Prec*VpBaseFig(), 1)); + GUARD_OBJ(b, GetBDValueWithPrecMust(other, pv->Prec*VpBaseFig())); } else { - GUARD_OBJ(b, GetVpValue(other, 1)); + GUARD_OBJ(b, GetBDValueMust(other)); } - obj = rb_assoc_new(b->obj, self); + obj = rb_assoc_new(b.bigdecimal, self); } return obj; @@ -1452,41 +1493,41 @@ static VALUE BigDecimal_add(VALUE self, VALUE r) { ENTER(5); - Real *c, *a, *b; + BDVALUE a, b, c; size_t mx; - GUARD_OBJ(a, GetVpValue(self, 1)); + GUARD_OBJ(a, GetBDValueMust(self)); if (RB_TYPE_P(r, T_FLOAT)) { - b = GetVpValueWithPrec(r, 0, 1); + GUARD_OBJ(b, GetBDValueWithPrecMust(r, 0)); } else if (RB_TYPE_P(r, T_RATIONAL)) { - b = GetVpValueWithPrec(r, a->Prec*VpBaseFig(), 1); + GUARD_OBJ(b, GetBDValueWithPrecMust(r, a.real->Prec*VpBaseFig())); } else { - b = GetVpValue(r, 0); + NULLABLE_BDVALUE b2; + GUARD_OBJ_OR_NIL(b2, GetBDValue(r)); + if (!b2.real_or_null) return DoSomeOne(self, r, '+'); + b = bdvalue_nonnullable(b2); } - if (!b) return DoSomeOne(self,r,'+'); - SAVE(b); - - if (VpIsNaN(b)) return b->obj; - if (VpIsNaN(a)) return a->obj; + if (VpIsNaN(b.real)) return b.bigdecimal; + if (VpIsNaN(a.real)) return a.bigdecimal; - mx = GetAddSubPrec(a, b); + mx = GetAddSubPrec(a.real, b.real); if (mx == (size_t)-1L) { GUARD_OBJ(c, NewZeroWrapLimited(1, VpBaseFig() + 1)); - VpAddSub(c, a, b, 1); + VpAddSub(c.real, a.real, b.real, 1); } else { GUARD_OBJ(c, NewZeroWrapLimited(1, mx * (VpBaseFig() + 1))); if (!mx) { - VpSetInf(c, VpGetSign(a)); + VpSetInf(c.real, VpGetSign(a.real)); } else { - VpAddSub(c, a, b, 1); + VpAddSub(c.real, a.real, b.real, 1); } } - return VpCheckGetValue(c); + return CheckGetValue(c); } /* @@ -1508,41 +1549,41 @@ static VALUE BigDecimal_sub(VALUE self, VALUE r) { ENTER(5); - Real *c, *a, *b; + BDVALUE a, b, c; size_t mx; - GUARD_OBJ(a, GetVpValue(self,1)); + GUARD_OBJ(a, GetBDValueMust(self)); if (RB_TYPE_P(r, T_FLOAT)) { - b = GetVpValueWithPrec(r, 0, 1); + GUARD_OBJ(b, GetBDValueWithPrecMust(r, 0)); } else if (RB_TYPE_P(r, T_RATIONAL)) { - b = GetVpValueWithPrec(r, a->Prec*VpBaseFig(), 1); + GUARD_OBJ(b, GetBDValueWithPrecMust(r, a.real->Prec*VpBaseFig())); } else { - b = GetVpValue(r,0); + NULLABLE_BDVALUE b2; + GUARD_OBJ_OR_NIL(b2, GetBDValue(r)); + if (!b2.real_or_null) return DoSomeOne(self, r, '-'); + b = bdvalue_nonnullable(b2); } - if (!b) return DoSomeOne(self,r,'-'); - SAVE(b); + if (VpIsNaN(b.real)) return b.bigdecimal; + if (VpIsNaN(a.real)) return a.bigdecimal; - if (VpIsNaN(b)) return b->obj; - if (VpIsNaN(a)) return a->obj; - - mx = GetAddSubPrec(a,b); + mx = GetAddSubPrec(a.real, b.real); if (mx == (size_t)-1L) { GUARD_OBJ(c, NewZeroWrapLimited(1, VpBaseFig() + 1)); - VpAddSub(c, a, b, -1); + VpAddSub(c.real, a.real, b.real, -1); } else { GUARD_OBJ(c, NewZeroWrapLimited(1, mx *(VpBaseFig() + 1))); if (!mx) { - VpSetInf(c,VpGetSign(a)); + VpSetInf(c.real, VpGetSign(a.real)); } else { - VpAddSub(c, a, b, -1); + VpAddSub(c.real, a.real, b.real, -1); } } - return VpCheckGetValue(c); + return CheckGetValue(c); } static VALUE @@ -1550,8 +1591,9 @@ BigDecimalCmp(VALUE self, VALUE r,char op) { ENTER(5); SIGNED_VALUE e; - Real *a, *b=0; - GUARD_OBJ(a, GetVpValue(self, 1)); + BDVALUE a; + NULLABLE_BDVALUE b = { Qnil, NULL }; + GUARD_OBJ(a, GetBDValueMust(self)); switch (TYPE(r)) { case T_DATA: if (!is_kind_of_BigDecimal(r)) break; @@ -1559,21 +1601,21 @@ BigDecimalCmp(VALUE self, VALUE r,char op) case T_FIXNUM: /* fall through */ case T_BIGNUM: - GUARD_OBJ(b, GetVpValue(r, 0)); + GUARD_OBJ_OR_NIL(b, GetBDValue(r)); break; case T_FLOAT: - GUARD_OBJ(b, GetVpValueWithPrec(r, 0, 0)); + GUARD_OBJ_OR_NIL(b, GetBDValueWithPrec(r, 0)); break; case T_RATIONAL: - GUARD_OBJ(b, GetVpValueWithPrec(r, a->Prec*VpBaseFig(), 0)); + GUARD_OBJ_OR_NIL(b, GetBDValueWithPrec(r, a.real->Prec*VpBaseFig())); break; default: break; } - if (b == NULL) { + if (b.real_or_null == NULL) { ID f = 0; switch (op) { @@ -1602,8 +1644,7 @@ BigDecimalCmp(VALUE self, VALUE r,char op) } return rb_num_coerce_relop(self, r, f); } - SAVE(b); - e = VpComp(a, b); + e = VpComp(a.real, b.real_or_null); if (e == 999) return (op == '*') ? Qnil : Qfalse; switch (op) { @@ -1643,7 +1684,7 @@ BigDecimalCmp(VALUE self, VALUE r,char op) static VALUE BigDecimal_zero(VALUE self) { - Real *a = GetVpValue(self, 1); + Real *a = GetSelfVpValue(self); return VpIsZero(a) ? Qtrue : Qfalse; } @@ -1651,7 +1692,7 @@ BigDecimal_zero(VALUE self) static VALUE BigDecimal_nonzero(VALUE self) { - Real *a = GetVpValue(self, 1); + Real *a = GetSelfVpValue(self); return VpIsZero(a) ? Qnil : self; } @@ -1778,11 +1819,11 @@ static VALUE BigDecimal_neg(VALUE self) { ENTER(5); - Real *c, *a; - GUARD_OBJ(a, GetVpValue(self, 1)); - GUARD_OBJ(c, NewZeroWrapLimited(1, a->Prec *(VpBaseFig() + 1))); - VpAsgn(c, a, -1); - return VpCheckGetValue(c); + BDVALUE c, a; + GUARD_OBJ(a, GetBDValueMust(self)); + GUARD_OBJ(c, NewZeroWrapLimited(1, a.real->Prec *(VpBaseFig() + 1))); + VpAsgn(c.real, a.real, -1); + return CheckGetValue(c); } /* @@ -1800,30 +1841,30 @@ static VALUE BigDecimal_mult(VALUE self, VALUE r) { ENTER(5); - Real *c, *a, *b; + BDVALUE a, b, c; size_t mx; - GUARD_OBJ(a, GetVpValue(self, 1)); + GUARD_OBJ(a, GetBDValueMust(self)); if (RB_TYPE_P(r, T_FLOAT)) { - b = GetVpValueWithPrec(r, 0, 1); + GUARD_OBJ(b, GetBDValueWithPrecMust(r, 0)); } else if (RB_TYPE_P(r, T_RATIONAL)) { - b = GetVpValueWithPrec(r, a->Prec*VpBaseFig(), 1); + GUARD_OBJ(b, GetBDValueWithPrecMust(r, a.real->Prec*VpBaseFig())); } else { - b = GetVpValue(r,0); + NULLABLE_BDVALUE b2; + GUARD_OBJ_OR_NIL(b2, GetBDValue(r)); + if (!b2.real_or_null) return DoSomeOne(self, r, '*'); + b = bdvalue_nonnullable(b2); } - if (!b) return DoSomeOne(self, r, '*'); - SAVE(b); - - mx = a->Prec + b->Prec; + mx = a.real->Prec + b.real->Prec; GUARD_OBJ(c, NewZeroWrapLimited(1, mx * (VpBaseFig() + 1))); - VpMult(c, a, b); - return VpCheckGetValue(c); + VpMult(c.real, a.real, b.real); + return CheckGetValue(c); } -static VALUE BigDecimal_DoDivmod(VALUE self, VALUE r, Real **div, Real **mod, bool truncate); +static VALUE BigDecimal_DoDivmod(VALUE self, VALUE r, NULLABLE_BDVALUE *div, NULLABLE_BDVALUE *mod, bool truncate); /* call-seq: * a / b -> bigdecimal @@ -1896,16 +1937,14 @@ BigDecimal_quo(int argc, VALUE *argv, VALUE self) * In truncate mode, use truncate instead of floor. */ static VALUE -BigDecimal_DoDivmod(VALUE self, VALUE r, Real **div, Real **mod, bool truncate) +BigDecimal_DoDivmod(VALUE self, VALUE r, NULLABLE_BDVALUE *div, NULLABLE_BDVALUE *mod, bool truncate) { ENTER(8); - Real *c=NULL, *d=NULL, *res=NULL; - Real *a, *b; + BDVALUE a, b, c, d, e, res; ssize_t a_prec, b_prec; size_t mx; - TypedData_Get_Struct(self, Real, &BigDecimal_data_type, a); - SAVE(a); + GUARD_OBJ(a, GetBDValueMust(self)); VALUE rr = r; if (is_kind_of_BigDecimal(rr)) { @@ -1918,44 +1957,42 @@ BigDecimal_DoDivmod(VALUE self, VALUE r, Real **div, Real **mod, bool truncate) rr = rb_float_convert_to_BigDecimal(r, 0, true); } else if (RB_TYPE_P(r, T_RATIONAL)) { - rr = rb_rational_convert_to_BigDecimal(r, a->Prec*BASE_FIG, true); + rr = rb_rational_convert_to_BigDecimal(r, a.real->Prec*BASE_FIG, true); } if (!is_kind_of_BigDecimal(rr)) { return Qfalse; } - TypedData_Get_Struct(rr, Real, &BigDecimal_data_type, b); - SAVE(b); + GUARD_OBJ(b, GetBDValueMust(rr)); - if (VpIsNaN(a) || VpIsNaN(b)) goto NaN; - if (VpIsInf(a) && VpIsInf(b)) goto NaN; - if (VpIsZero(b)) { + if (VpIsNaN(a.real) || VpIsNaN(b.real)) goto NaN; + if (VpIsInf(a.real) && VpIsInf(b.real)) goto NaN; + if (VpIsZero(b.real)) { rb_raise(rb_eZeroDivError, "divided by 0"); } - if (VpIsInf(a)) { - if (VpGetSign(a) == VpGetSign(b)) { + if (VpIsInf(a.real)) { + if (VpGetSign(a.real) == VpGetSign(b.real)) { VALUE inf = BigDecimal_positive_infinity(); - TypedData_Get_Struct(inf, Real, &BigDecimal_data_type, *div); + *div = (NULLABLE_BDVALUE) { inf, DATA_PTR(inf) }; } else { VALUE inf = BigDecimal_negative_infinity(); - TypedData_Get_Struct(inf, Real, &BigDecimal_data_type, *div); + *div = (NULLABLE_BDVALUE) { inf, DATA_PTR(inf) }; } VALUE nan = BigDecimal_nan(); - TypedData_Get_Struct(nan, Real, &BigDecimal_data_type, *mod); + *mod = (NULLABLE_BDVALUE) { nan, DATA_PTR(nan) }; return Qtrue; } - if (VpIsInf(b)) { + if (VpIsInf(b.real)) { VALUE zero = BigDecimal_positive_zero(); - TypedData_Get_Struct(zero, Real, &BigDecimal_data_type, *div); - *mod = a; + *div = (NULLABLE_BDVALUE) { zero, DATA_PTR(zero) }; + *mod = bdvalue_nullable(a); return Qtrue; } - if (VpIsZero(a)) { + if (VpIsZero(a.real)) { VALUE zero = BigDecimal_positive_zero(); - TypedData_Get_Struct(zero, Real, &BigDecimal_data_type, *div); - TypedData_Get_Struct(zero, Real, &BigDecimal_data_type, *mod); + *div = *mod = (NULLABLE_BDVALUE) { zero, DATA_PTR(zero) }; return Qtrue; } @@ -1970,36 +2007,35 @@ BigDecimal_DoDivmod(VALUE self, VALUE r, Real **div, Real **mod, bool truncate) GUARD_OBJ(c, NewZeroWrapLimited(1, mx + 2*BASE_FIG)); GUARD_OBJ(res, NewZeroWrapNolimit(1, mx*2 + 2*BASE_FIG)); - VpDivd(c, res, a, b); + VpDivd(c.real, res.real, a.real, b.real); - mx = c->Prec * BASE_FIG; + mx = c.real->Prec * BASE_FIG; GUARD_OBJ(d, NewZeroWrapLimited(1, mx)); - VpActiveRound(d, c, VP_ROUND_DOWN, 0); + VpActiveRound(d.real, c.real, VP_ROUND_DOWN, 0); - VpMult(res, d, b); - VpAddSub(c, a, res, -1); + VpMult(res.real, d.real, b.real); + VpAddSub(c.real, a.real, res.real, -1); - if (!truncate && !VpIsZero(c) && (VpGetSign(a) * VpGetSign(b) < 0)) { + if (!truncate && !VpIsZero(c.real) && (VpGetSign(a.real) * VpGetSign(b.real) < 0)) { /* result adjustment for negative case */ - res = rbd_reallocate_struct(res, d->MaxPrec); - res->MaxPrec = d->MaxPrec; - VpAddSub(res, d, VpOne(), -1); - GUARD_OBJ(d, NewZeroWrapLimited(1, GetAddSubPrec(c, b) * 2*BASE_FIG)); - VpAddSub(d, c, b, 1); - *div = res; - *mod = d; + res = rbd_reallocate_struct(res, d.real->MaxPrec); + res.real->MaxPrec = d.real->MaxPrec; + VpAddSub(res.real, d.real, VpOne(), -1); + GUARD_OBJ(e, NewZeroWrapLimited(1, GetAddSubPrec(c.real, b.real) * 2*BASE_FIG)); + VpAddSub(e.real, c.real, b.real, 1); + *div = bdvalue_nullable(res); + *mod = bdvalue_nullable(e); } else { - *div = d; - *mod = c; + *div = bdvalue_nullable(d); + *mod = bdvalue_nullable(c); } return Qtrue; NaN: { VALUE nan = BigDecimal_nan(); - TypedData_Get_Struct(nan, Real, &BigDecimal_data_type, *div); - TypedData_Get_Struct(nan, Real, &BigDecimal_data_type, *mod); + *div = *mod = (NULLABLE_BDVALUE) { nan, DATA_PTR(nan) }; } return Qtrue; } @@ -2015,12 +2051,10 @@ BigDecimal_DoDivmod(VALUE self, VALUE r, Real **div, Real **mod, bool truncate) static VALUE BigDecimal_mod(VALUE self, VALUE r) /* %: a%b = a - (a.to_f/b).floor * b */ { - ENTER(3); - Real *div = NULL, *mod = NULL; + NULLABLE_BDVALUE div, mod; if (BigDecimal_DoDivmod(self, r, &div, &mod, false)) { - SAVE(div); SAVE(mod); - return VpCheckGetValue(mod); + return CheckGetValue(bdvalue_nonnullable(mod)); } return DoSomeOne(self, r, '%'); } @@ -2035,12 +2069,10 @@ BigDecimal_mod(VALUE self, VALUE r) /* %: a%b = a - (a.to_f/b).floor * b */ static VALUE BigDecimal_remainder(VALUE self, VALUE r) /* remainder */ { - ENTER(3); - Real *div = NULL, *mod = NULL; + NULLABLE_BDVALUE div, mod = { Qnil, NULL }; if (BigDecimal_DoDivmod(self, r, &div, &mod, true)) { - SAVE(div); SAVE(mod); - return VpCheckGetValue(mod); + return CheckGetValue(bdvalue_nonnullable(mod)); } return DoSomeOne(self, r, rb_intern("remainder")); } @@ -2070,12 +2102,10 @@ BigDecimal_remainder(VALUE self, VALUE r) /* remainder */ static VALUE BigDecimal_divmod(VALUE self, VALUE r) { - ENTER(5); - Real *div = NULL, *mod = NULL; + NULLABLE_BDVALUE div, mod; if (BigDecimal_DoDivmod(self, r, &div, &mod, false)) { - SAVE(div); SAVE(mod); - return rb_assoc_new(VpCheckGetValue(div), VpCheckGetValue(mod)); + return rb_assoc_new(CheckGetValue(bdvalue_nonnullable(div)), CheckGetValue(bdvalue_nonnullable(mod))); } return DoSomeOne(self,r,rb_intern("divmod")); } @@ -2089,15 +2119,14 @@ BigDecimal_div2(VALUE self, VALUE b, VALUE n) { ENTER(5); SIGNED_VALUE ix; - Real *res = NULL; - Real *av = NULL, *bv = NULL, *cv = NULL; + BDVALUE av, bv, cv, res; size_t mx, pl; if (NIL_P(n)) { /* div in Float sense */ - Real *div = NULL; - Real *mod; + NULLABLE_BDVALUE div; + NULLABLE_BDVALUE mod; if (BigDecimal_DoDivmod(self, b, &div, &mod, false)) { - return BigDecimal_to_i(VpCheckGetValue(div)); + return BigDecimal_to_i(CheckGetValue(bdvalue_nonnullable(div))); } return DoSomeOne(self, b, rb_intern("div")); } @@ -2108,21 +2137,21 @@ BigDecimal_div2(VALUE self, VALUE b, VALUE n) pl = VpSetPrecLimit(0); if (ix == 0) ix = pl; - GUARD_OBJ(av, GetVpValue(self, 1)); + GUARD_OBJ(av, GetBDValueMust(self)); if (RB_FLOAT_TYPE_P(b) && ix > BIGDECIMAL_DOUBLE_FIGURES) { /* TODO: I want to refactor this precision control for a float value later * by introducing an implicit conversion function instead of - * GetVpValueWithPrec. */ - GUARD_OBJ(bv, GetVpValueWithPrec(b, BIGDECIMAL_DOUBLE_FIGURES, 1)); + * GetBDValueWithPrecMust. */ + GUARD_OBJ(bv, GetBDValueWithPrecMust(b, BIGDECIMAL_DOUBLE_FIGURES)); } else { - GUARD_OBJ(bv, GetVpValueWithPrec(b, ix, 1)); + GUARD_OBJ(bv, GetBDValueWithPrecMust(b, ix)); } if (ix == 0) { ssize_t a_prec, b_prec; - VpCountPrecisionAndScale(av, &a_prec, NULL); - VpCountPrecisionAndScale(bv, &b_prec, NULL); + 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; @@ -2131,22 +2160,22 @@ BigDecimal_div2(VALUE self, VALUE b, VALUE n) // VpDivd needs 2 extra DECDIGs. One more is needed for rounding. GUARD_OBJ(cv, NewZeroWrapLimited(1, ix + 3 * VpBaseFig())); - mx = bv->Prec + cv->MaxPrec - 1; - if (mx <= av->Prec) mx = av->Prec + 1; + mx = bv.real->Prec + cv.real->MaxPrec - 1; + if (mx <= av.real->Prec) mx = av.real->Prec + 1; GUARD_OBJ(res, NewZeroWrapNolimit(1, mx * VpBaseFig())); - VpDivd(cv, res, av, bv); + VpDivd(cv.real, res.real, av.real, bv.real); VpSetPrecLimit(pl); - if (!VpIsZero(res)) { + if (!VpIsZero(res.real)) { // Remainder value affects rounding result. // ROUND_UP cv = 0.1e0 with ix=10 will be: // 0.1e0 if remainder == 0 // 0.1000000001e0 if remainder != 0 size_t idx = roomof(ix, BASE_FIG); - while (cv->Prec <= idx) cv->frac[cv->Prec++] = 0; - if (cv->frac[idx] == 0 || cv->frac[idx] == HALF_BASE) cv->frac[idx]++; + 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, VpGetRoundMode(), ix); - return VpCheckGetValue(cv); + VpLeftRound(cv.real, VpGetRoundMode(), ix); + return CheckGetValue(cv); } /* @@ -2223,16 +2252,16 @@ static VALUE BigDecimal_add2(VALUE self, VALUE b, VALUE n) { ENTER(2); - Real *cv; + BDVALUE cv; SIGNED_VALUE mx = check_int_precision(n); if (mx == 0) return BigDecimal_add(self, b); else { size_t pl = VpSetPrecLimit(0); VALUE c = BigDecimal_add(self, b); VpSetPrecLimit(pl); - GUARD_OBJ(cv, GetVpValue(c, 1)); - VpLeftRound(cv, VpGetRoundMode(), mx); - return VpCheckGetValue(cv); + GUARD_OBJ(cv, GetBDValueMust(c)); + VpLeftRound(cv.real, VpGetRoundMode(), mx); + return CheckGetValue(cv); } } @@ -2253,16 +2282,16 @@ static VALUE BigDecimal_sub2(VALUE self, VALUE b, VALUE n) { ENTER(2); - Real *cv; + BDVALUE cv; SIGNED_VALUE mx = check_int_precision(n); if (mx == 0) return BigDecimal_sub(self, b); else { size_t pl = VpSetPrecLimit(0); VALUE c = BigDecimal_sub(self, b); VpSetPrecLimit(pl); - GUARD_OBJ(cv, GetVpValue(c, 1)); - VpLeftRound(cv, VpGetRoundMode(), mx); - return VpCheckGetValue(cv); + GUARD_OBJ(cv, GetBDValueMust(c)); + VpLeftRound(cv.real, VpGetRoundMode(), mx); + return CheckGetValue(cv); } } @@ -2296,16 +2325,16 @@ static VALUE BigDecimal_mult2(VALUE self, VALUE b, VALUE n) { ENTER(2); - Real *cv; + BDVALUE cv; SIGNED_VALUE mx = check_int_precision(n); if (mx == 0) return BigDecimal_mult(self, b); else { size_t pl = VpSetPrecLimit(0); VALUE c = BigDecimal_mult(self, b); VpSetPrecLimit(pl); - GUARD_OBJ(cv, GetVpValue(c, 1)); - VpLeftRound(cv, VpGetRoundMode(), mx); - return VpCheckGetValue(cv); + GUARD_OBJ(cv, GetBDValueMust(c)); + VpLeftRound(cv.real, VpGetRoundMode(), mx); + return CheckGetValue(cv); } } @@ -2324,15 +2353,15 @@ static VALUE BigDecimal_abs(VALUE self) { ENTER(5); - Real *c, *a; + BDVALUE c, a; size_t mx; - GUARD_OBJ(a, GetVpValue(self, 1)); - mx = a->Prec *(VpBaseFig() + 1); + GUARD_OBJ(a, GetBDValueMust(self)); + mx = a.real->Prec *(VpBaseFig() + 1); GUARD_OBJ(c, NewZeroWrapLimited(1, mx)); - VpAsgn(c, a, 1); - VpChangeSign(c, 1); - return VpCheckGetValue(c); + VpAsgn(c.real, a.real, 1); + VpChangeSign(c.real, 1); + return CheckGetValue(c); } /* call-seq: @@ -2346,18 +2375,18 @@ static VALUE BigDecimal_sqrt(VALUE self, VALUE nFig) { ENTER(5); - Real *c, *a; + BDVALUE c, a; size_t mx, n; - GUARD_OBJ(a, GetVpValue(self, 1)); - mx = a->Prec * (VpBaseFig() + 1); + GUARD_OBJ(a, GetBDValueMust(self)); + mx = a.real->Prec * (VpBaseFig() + 1); n = check_int_precision(nFig); n += VpDblFig() + VpBaseFig(); if (mx <= n) mx = n; GUARD_OBJ(c, NewZeroWrapLimited(1, mx)); - VpSqrt(c, a); - return VpCheckGetValue(c); + VpSqrt(c.real, a.real); + return CheckGetValue(c); } /* Return the integer part of the number, as a BigDecimal. @@ -2366,14 +2395,14 @@ static VALUE BigDecimal_fix(VALUE self) { ENTER(5); - Real *c, *a; + BDVALUE c, a; size_t mx; - GUARD_OBJ(a, GetVpValue(self, 1)); - mx = a->Prec *(VpBaseFig() + 1); + GUARD_OBJ(a, GetBDValueMust(self)); + mx = a.real->Prec *(VpBaseFig() + 1); GUARD_OBJ(c, NewZeroWrapLimited(1, mx)); - VpActiveRound(c, a, VP_ROUND_DOWN, 0); /* 0: round off */ - return VpCheckGetValue(c); + VpActiveRound(c.real, a.real, VP_ROUND_DOWN, 0); /* 0: round off */ + return CheckGetValue(c); } /* call-seq: @@ -2406,7 +2435,7 @@ static VALUE BigDecimal_round(int argc, VALUE *argv, VALUE self) { ENTER(5); - Real *c, *a; + BDVALUE c, a; int iLoc = 0; VALUE vLoc; VALUE vRound; @@ -2443,15 +2472,15 @@ BigDecimal_round(int argc, VALUE *argv, VALUE self) } pl = VpSetPrecLimit(0); - GUARD_OBJ(a, GetVpValue(self, 1)); - mx = a->Prec * (VpBaseFig() + 1); + GUARD_OBJ(a, GetBDValueMust(self)); + mx = a.real->Prec * (VpBaseFig() + 1); GUARD_OBJ(c, NewZeroWrapLimited(1, mx)); VpSetPrecLimit(pl); - VpActiveRound(c, a, sw, iLoc); + VpActiveRound(c.real, a.real, sw, iLoc); if (round_to_int) { - return BigDecimal_to_i(VpCheckGetValue(c)); + return BigDecimal_to_i(CheckGetValue(c)); } - return VpCheckGetValue(c); + return CheckGetValue(c); } /* call-seq: @@ -2477,7 +2506,7 @@ static VALUE BigDecimal_truncate(int argc, VALUE *argv, VALUE self) { ENTER(5); - Real *c, *a; + BDVALUE c, a; int iLoc; VALUE vLoc; size_t mx, pl = VpSetPrecLimit(0); @@ -2489,15 +2518,15 @@ BigDecimal_truncate(int argc, VALUE *argv, VALUE self) iLoc = NUM2INT(vLoc); } - GUARD_OBJ(a, GetVpValue(self, 1)); - mx = a->Prec * (VpBaseFig() + 1); + GUARD_OBJ(a, GetBDValueMust(self)); + mx = a.real->Prec * (VpBaseFig() + 1); GUARD_OBJ(c, NewZeroWrapLimited(1, mx)); VpSetPrecLimit(pl); - VpActiveRound(c, a, VP_ROUND_DOWN, iLoc); /* 0: truncate */ + VpActiveRound(c.real, a.real, VP_ROUND_DOWN, iLoc); /* 0: truncate */ if (argc == 0) { - return BigDecimal_to_i(VpCheckGetValue(c)); + return BigDecimal_to_i(CheckGetValue(c)); } - return VpCheckGetValue(c); + return CheckGetValue(c); } /* Return the fractional part of the number, as a BigDecimal. @@ -2506,14 +2535,14 @@ static VALUE BigDecimal_frac(VALUE self) { ENTER(5); - Real *c, *a; + BDVALUE c, a; size_t mx; - GUARD_OBJ(a, GetVpValue(self, 1)); - mx = a->Prec * (VpBaseFig() + 1); + GUARD_OBJ(a, GetBDValueMust(self)); + mx = a.real->Prec * (VpBaseFig() + 1); GUARD_OBJ(c, NewZeroWrapLimited(1, mx)); - VpFrac(c, a); - return VpCheckGetValue(c); + VpFrac(c.real, a.real); + return CheckGetValue(c); } /* call-seq: @@ -2537,7 +2566,7 @@ static VALUE BigDecimal_floor(int argc, VALUE *argv, VALUE self) { ENTER(5); - Real *c, *a; + BDVALUE c, a; int iLoc; VALUE vLoc; size_t mx, pl = VpSetPrecLimit(0); @@ -2549,18 +2578,18 @@ BigDecimal_floor(int argc, VALUE *argv, VALUE self) iLoc = NUM2INT(vLoc); } - GUARD_OBJ(a, GetVpValue(self, 1)); - mx = a->Prec * (VpBaseFig() + 1); + GUARD_OBJ(a, GetBDValueMust(self)); + mx = a.real->Prec * (VpBaseFig() + 1); GUARD_OBJ(c, NewZeroWrapLimited(1, mx)); VpSetPrecLimit(pl); - VpActiveRound(c, a, VP_ROUND_FLOOR, iLoc); + VpActiveRound(c.real, a.real, VP_ROUND_FLOOR, iLoc); #ifdef BIGDECIMAL_DEBUG VPrint(stderr, "floor: c=%\n", c); #endif if (argc == 0) { - return BigDecimal_to_i(VpCheckGetValue(c)); + return BigDecimal_to_i(CheckGetValue(c)); } - return VpCheckGetValue(c); + return CheckGetValue(c); } /* call-seq: @@ -2584,7 +2613,7 @@ static VALUE BigDecimal_ceil(int argc, VALUE *argv, VALUE self) { ENTER(5); - Real *c, *a; + BDVALUE c, a; int iLoc; VALUE vLoc; size_t mx, pl = VpSetPrecLimit(0); @@ -2595,15 +2624,15 @@ BigDecimal_ceil(int argc, VALUE *argv, VALUE self) iLoc = NUM2INT(vLoc); } - GUARD_OBJ(a, GetVpValue(self, 1)); - mx = a->Prec * (VpBaseFig() + 1); + GUARD_OBJ(a, GetBDValueMust(self)); + mx = a.real->Prec * (VpBaseFig() + 1); GUARD_OBJ(c, NewZeroWrapLimited(1, mx)); VpSetPrecLimit(pl); - VpActiveRound(c, a, VP_ROUND_CEIL, iLoc); + VpActiveRound(c.real, a.real, VP_ROUND_CEIL, iLoc); if (argc == 0) { - return BigDecimal_to_i(VpCheckGetValue(c)); + return BigDecimal_to_i(CheckGetValue(c)); } - return VpCheckGetValue(c); + return CheckGetValue(c); } /* call-seq: @@ -2645,7 +2674,7 @@ BigDecimal_to_s(int argc, VALUE *argv, VALUE self) ENTER(5); int fmt = 0; /* 0: E format, 1: F format */ int fPlus = 0; /* 0: default, 1: set ' ' before digits, 2: set '+' before digits. */ - Real *vp; + BDVALUE v; volatile VALUE str; char *psz; char ch; @@ -2653,7 +2682,7 @@ BigDecimal_to_s(int argc, VALUE *argv, VALUE self) SIGNED_VALUE m; VALUE f; - GUARD_OBJ(vp, GetVpValue(self, 1)); + GUARD_OBJ(v, GetBDValueMust(self)); if (rb_scan_args(argc, argv, "01", &f) == 1) { if (RB_TYPE_P(f, T_STRING)) { @@ -2688,10 +2717,10 @@ BigDecimal_to_s(int argc, VALUE *argv, VALUE self) } } if (fmt) { - nc = VpNumOfChars(vp, "F"); + nc = VpNumOfChars(v.real, "F"); } else { - nc = VpNumOfChars(vp, "E"); + nc = VpNumOfChars(v.real, "E"); } if (mc > 0) { nc += (nc + mc - 1) / mc + 1; @@ -2701,10 +2730,10 @@ BigDecimal_to_s(int argc, VALUE *argv, VALUE self) psz = RSTRING_PTR(str); if (fmt) { - VpToFString(vp, psz, RSTRING_LEN(str), mc, fPlus); + VpToFString(v.real, psz, RSTRING_LEN(str), mc, fPlus); } else { - VpToString (vp, psz, RSTRING_LEN(str), mc, fPlus); + VpToString (v.real, psz, RSTRING_LEN(str), mc, fPlus); } rb_str_resize(str, strlen(psz)); return str; @@ -2738,15 +2767,15 @@ static VALUE BigDecimal_split(VALUE self) { ENTER(5); - Real *vp; + BDVALUE v; VALUE obj,str; ssize_t e, s; char *psz1; - GUARD_OBJ(vp, GetVpValue(self, 1)); - str = rb_str_new(0, VpNumOfChars(vp, "E")); + GUARD_OBJ(v, GetBDValueMust(self)); + str = rb_str_new(0, VpNumOfChars(v.real, "E")); psz1 = RSTRING_PTR(str); - VpSzMantissa(vp, psz1, RSTRING_LEN(str)); + VpSzMantissa(v.real, psz1, RSTRING_LEN(str)); s = 1; if(psz1[0] == '-') { size_t len = strlen(psz1 + 1); @@ -2756,7 +2785,7 @@ BigDecimal_split(VALUE self) s = -1; } if (psz1[0] == 'N') s = 0; /* NaN */ - e = VpExponent10(vp); + e = VpExponent10(v.real); obj = rb_ary_new2(4); rb_ary_push(obj, INT2FIX(s)); rb_ary_push(obj, str); @@ -2774,7 +2803,7 @@ BigDecimal_split(VALUE self) static VALUE BigDecimal_exponent(VALUE self) { - ssize_t e = VpExponent10(GetVpValue(self, 1)); + ssize_t e = VpExponent10(GetSelfVpValue(self)); return SSIZET2NUM(e); } @@ -2787,15 +2816,15 @@ static VALUE BigDecimal_inspect(VALUE self) { ENTER(5); - Real *vp; + BDVALUE v; volatile VALUE str; size_t nc; - GUARD_OBJ(vp, GetVpValue(self, 1)); - nc = VpNumOfChars(vp, "E"); + GUARD_OBJ(v, GetBDValueMust(self)); + nc = VpNumOfChars(v.real, "E"); str = rb_str_new(0, nc); - VpToString(vp, RSTRING_PTR(str), RSTRING_LEN(str), 0, 0); + VpToString(v.real, RSTRING_PTR(str), RSTRING_LEN(str), 0, 0); rb_str_resize(str, strlen(RSTRING_PTR(str))); return str; } @@ -2899,19 +2928,18 @@ is_even(VALUE x) } static VALUE -bigdecimal_power_by_bigdecimal(Real const* x, Real const* exp, ssize_t const n) +bigdecimal_power_by_bigdecimal(BDVALUE x, BDVALUE exp, ssize_t const n) { VALUE log_x, multiplied, y; - volatile VALUE obj = exp->obj; - if (VpIsZero(exp)) { - return VpCheckGetValue(NewOneWrapLimited(1, n)); + if (VpIsZero(exp.real)) { + return CheckGetValue(NewOneWrapLimited(1, n)); } - log_x = BigMath_log(x->obj, SSIZET2NUM(n+1)); - multiplied = BigDecimal_mult2(exp->obj, log_x, SSIZET2NUM(n+1)); + log_x = BigMath_log(x.bigdecimal, SSIZET2NUM(n+1)); + multiplied = BigDecimal_mult2(exp.bigdecimal, log_x, SSIZET2NUM(n+1)); y = BigMath_exp(multiplied, SSIZET2NUM(n)); - RB_GC_GUARD(obj); + RB_GC_GUARD(exp.bigdecimal); return y; } @@ -2931,22 +2959,21 @@ BigDecimal_power(int argc, VALUE*argv, VALUE self) { ENTER(5); VALUE vexp, prec; - Real* exp = NULL; - Real *x, *y; + NULLABLE_BDVALUE exp = { Qnil, NULL }; + BDVALUE x, y; ssize_t mp, ma, n; SIGNED_VALUE int_exp; double d; rb_scan_args(argc, argv, "11", &vexp, &prec); - GUARD_OBJ(x, GetVpValue(self, 1)); - n = NIL_P(prec) ? (ssize_t)(x->Prec*VpBaseFig()) : NUM2SSIZET(prec); + GUARD_OBJ(x, GetBDValueMust(self)); + n = NIL_P(prec) ? (ssize_t)(x.real->Prec*VpBaseFig()) : NUM2SSIZET(prec); - if (VpIsNaN(x)) { + if (VpIsNaN(x.real)) { y = NewZeroWrapLimited(1, n); - VpSetNaN(y); - RB_GC_GUARD(y->obj); - return VpCheckGetValue(y); + VpSetNaN(y.real); + return CheckGetValue(y); } retry: @@ -2971,7 +2998,7 @@ BigDecimal_power(int argc, VALUE*argv, VALUE self) if (NIL_P(prec)) { n += BIGDECIMAL_DOUBLE_FIGURES; } - exp = GetVpValueWithPrec(vexp, 0, 1); + exp = bdvalue_nullable(GetBDValueWithPrecMust(vexp, 0)); break; case T_RATIONAL: @@ -2985,7 +3012,7 @@ BigDecimal_power(int argc, VALUE*argv, VALUE self) vexp = rb_rational_num(vexp); goto retry; } - exp = GetVpValueWithPrec(vexp, n, 1); + exp = bdvalue_nullable(GetBDValueWithPrecMust(vexp, n)); if (NIL_P(prec)) { n += n; } @@ -3000,10 +3027,10 @@ BigDecimal_power(int argc, VALUE*argv, VALUE self) goto retry; } if (NIL_P(prec)) { - GUARD_OBJ(y, GetVpValue(vexp, 1)); - n += y->Prec*VpBaseFig(); + GUARD_OBJ(y, GetBDValueMust(vexp)); + n += y.real->Prec*VpBaseFig(); } - exp = DATA_PTR(vexp); + GUARD_OBJ_OR_NIL(exp, bdvalue_nullable(GetBDValueMust(vexp))); break; } /* fall through */ @@ -3013,78 +3040,77 @@ BigDecimal_power(int argc, VALUE*argv, VALUE self) RB_OBJ_CLASSNAME(vexp)); } - if (VpIsZero(x)) { + if (VpIsZero(x.real)) { if (is_negative(vexp)) { y = NewZeroWrapNolimit(1, n); - if (BIGDECIMAL_NEGATIVE_P(x)) { + if (BIGDECIMAL_NEGATIVE_P(x.real)) { if (is_integer(vexp)) { if (is_even(vexp)) { /* (-0) ** (-even_integer) -> Infinity */ - VpSetPosInf(y); + VpSetPosInf(y.real); } else { /* (-0) ** (-odd_integer) -> -Infinity */ - VpSetNegInf(y); + VpSetNegInf(y.real); } } else { /* (-0) ** (-non_integer) -> Infinity */ - VpSetPosInf(y); + VpSetPosInf(y.real); } } else { /* (+0) ** (-num) -> Infinity */ - VpSetPosInf(y); + VpSetPosInf(y.real); } - RB_GC_GUARD(y->obj); - return VpCheckGetValue(y); + return CheckGetValue(y); } else if (is_zero(vexp)) { - return VpCheckGetValue(NewOneWrapLimited(1, n)); + return CheckGetValue(NewOneWrapLimited(1, n)); } else { - return VpCheckGetValue(NewZeroWrapLimited(1, n)); + return CheckGetValue(NewZeroWrapLimited(1, n)); } } if (is_zero(vexp)) { - return VpCheckGetValue(NewOneWrapLimited(1, n)); + return CheckGetValue(NewOneWrapLimited(1, n)); } else if (is_one(vexp)) { return self; } - if (VpIsInf(x)) { + if (VpIsInf(x.real)) { if (is_negative(vexp)) { - if (BIGDECIMAL_NEGATIVE_P(x)) { + if (BIGDECIMAL_NEGATIVE_P(x.real)) { if (is_integer(vexp)) { if (is_even(vexp)) { /* (-Infinity) ** (-even_integer) -> +0 */ - return VpCheckGetValue(NewZeroWrapLimited(1, n)); + return CheckGetValue(NewZeroWrapLimited(1, n)); } else { /* (-Infinity) ** (-odd_integer) -> -0 */ - return VpCheckGetValue(NewZeroWrapLimited(-1, n)); + return CheckGetValue(NewZeroWrapLimited(-1, n)); } } else { /* (-Infinity) ** (-non_integer) -> -0 */ - return VpCheckGetValue(NewZeroWrapLimited(-1, n)); + return CheckGetValue(NewZeroWrapLimited(-1, n)); } } else { - return VpCheckGetValue(NewZeroWrapLimited(1, n)); + return CheckGetValue(NewZeroWrapLimited(1, n)); } } else { y = NewZeroWrapLimited(1, n); - if (BIGDECIMAL_NEGATIVE_P(x)) { + if (BIGDECIMAL_NEGATIVE_P(x.real)) { if (is_integer(vexp)) { if (is_even(vexp)) { - VpSetPosInf(y); + VpSetPosInf(y.real); } else { - VpSetNegInf(y); + VpSetNegInf(y.real); } } else { @@ -3094,44 +3120,44 @@ BigDecimal_power(int argc, VALUE*argv, VALUE self) } } else { - VpSetPosInf(y); + VpSetPosInf(y.real); } - return VpCheckGetValue(y); + return CheckGetValue(y); } } - if (exp != NULL) { - return bigdecimal_power_by_bigdecimal(x, exp, n); + if (exp.real_or_null != NULL) { + return bigdecimal_power_by_bigdecimal(x, bdvalue_nonnullable(exp), n); } else if (RB_TYPE_P(vexp, T_BIGNUM)) { VALUE abs_value = BigDecimal_abs(self); if (is_one(abs_value)) { - return VpCheckGetValue(NewOneWrapLimited(is_even(vexp) ? 1 : VpGetSign(x), n)); + return CheckGetValue(NewOneWrapLimited(is_even(vexp) ? 1 : VpGetSign(x.real), n)); } else if (RTEST(rb_funcall(abs_value, '<', 1, INT2FIX(1)))) { if (is_negative(vexp)) { y = NewZeroWrapLimited(1, n); - VpSetInf(y, is_even(vexp) ? 1 : VpGetSign(x)); - return VpCheckGetValue(y); + VpSetInf(y.real, is_even(vexp) ? 1 : VpGetSign(x.real)); + return CheckGetValue(y); } - else if (BIGDECIMAL_NEGATIVE_P(x) && !is_even(vexp)) { - return VpCheckGetValue(NewZeroWrapLimited(-1, n)); + else if (BIGDECIMAL_NEGATIVE_P(x.real) && !is_even(vexp)) { + return CheckGetValue(NewZeroWrapLimited(-1, n)); } else { - return VpCheckGetValue(NewZeroWrapLimited(1, n)); + return CheckGetValue(NewZeroWrapLimited(1, n)); } } else { if (is_positive(vexp)) { y = NewZeroWrapLimited(1, n); - VpSetInf(y, is_even(vexp) ? 1 : VpGetSign(x)); - return VpCheckGetValue(y); + VpSetInf(y.real, is_even(vexp) ? 1 : VpGetSign(x.real)); + return CheckGetValue(y); } - else if (BIGDECIMAL_NEGATIVE_P(x) && !is_even(vexp)) { - return VpCheckGetValue(NewZeroWrapLimited(-1, n)); + else if (BIGDECIMAL_NEGATIVE_P(x.real) && !is_even(vexp)) { + return CheckGetValue(NewZeroWrapLimited(-1, n)); } else { - return VpCheckGetValue(NewZeroWrapLimited(1, n)); + return CheckGetValue(NewZeroWrapLimited(1, n)); } } } @@ -3141,18 +3167,18 @@ BigDecimal_power(int argc, VALUE*argv, VALUE self) if (ma < 0) ma = -ma; if (ma == 0) ma = 1; - if (VpIsDef(x)) { - mp = x->Prec * (VpBaseFig() + 1); + if (VpIsDef(x.real)) { + mp = x.real->Prec * (VpBaseFig() + 1); GUARD_OBJ(y, NewZeroWrapLimited(1, mp * (ma + 1))); } else { GUARD_OBJ(y, NewZeroWrapLimited(1, 1)); } - VpPowerByInt(y, x, int_exp); - if (!NIL_P(prec) && VpIsDef(y)) { - VpMidRound(y, VpGetRoundMode(), n); + VpPowerByInt(y.real, x.real, int_exp); + if (!NIL_P(prec) && VpIsDef(y.real)) { + VpMidRound(y.real, VpGetRoundMode(), n); } - return VpCheckGetValue(y); + return CheckGetValue(y); } /* call-seq: @@ -3185,7 +3211,7 @@ BigDecimal_initialize_copy(VALUE self, VALUE other) Real *x = rb_check_typeddata(other, &BigDecimal_data_type); if (self != other) { - DATA_PTR(self) = VpCopy(pv, x); + BigDecimal_wrap_struct(self, VpCopy(pv, x)); } return self; } @@ -3228,7 +3254,7 @@ check_exception(VALUE bd) Real *vp; TypedData_Get_Struct(bd, Real, &BigDecimal_data_type, vp); - VpCheckGetValue(vp); /* VpCheckGetValue performs exception check */ + VpCheckException(vp, false); return bd; } @@ -3329,10 +3355,15 @@ rb_big_convert_to_BigDecimal(VALUE val, RB_UNUSED_VAR(size_t digs), int raise_ex #endif else { VALUE str = rb_big2str(val, 10); - Real *vp = VpCreateRbObject(RSTRING_LEN(str) + BASE_FIG + 1, - RSTRING_PTR(str), true); + BDVALUE v = bdvalue_nonnullable(CreateFromString( + RSTRING_LEN(str) + BASE_FIG + 1, + RSTRING_PTR(str), + rb_cBigDecimal, + true, + true + )); RB_GC_GUARD(str); - return check_exception(vp->obj); + return CheckGetValue(v); } } @@ -3528,10 +3559,9 @@ rb_cstr_convert_to_BigDecimal(const char *c_str, size_t digs, int raise_exceptio if (digs == SIZE_MAX) digs = 0; - Real *vp = VpCreateRbObject(digs, c_str, raise_exception); - if (!vp) - return Qnil; - return VpCheckGetValue(vp); + NULLABLE_BDVALUE v = CreateFromString(digs, c_str, rb_cBigDecimal, true, raise_exception); + if (v.bigdecimal_or_nil == Qnil) return Qnil; + return CheckGetValue(bdvalue_nonnullable(v)); } static inline VALUE @@ -3573,7 +3603,7 @@ rb_convert_to_BigDecimal(VALUE val, size_t digs, int raise_exception) vp = VpCopy(NULL, vp); /* TODO: rounding */ BigDecimal_wrap_struct(copy, vp); - return VpCheckGetValue(vp); + return check_exception(copy); } else if (RB_INTEGER_TYPE_P(val)) { return rb_inum_convert_to_BigDecimal(val, digs, raise_exception); @@ -3698,11 +3728,11 @@ static VALUE BigDecimal_s_interpret_loosely(VALUE klass, VALUE str) { char const *c_str = StringValueCStr(str); - Real *vp = VpNewRbClass(0, c_str, klass, false, true); - if (!vp) + NULLABLE_BDVALUE v = CreateFromString(0, c_str, klass, false, true); + if (v.bigdecimal_or_nil == Qnil) return Qnil; else - return VpCheckGetValue(vp); + return CheckGetValue(bdvalue_nonnullable(v)); } /* @@ -3757,7 +3787,7 @@ BigDecimal_limit(int argc, VALUE *argv, VALUE self) static VALUE BigDecimal_sign(VALUE self) { /* sign */ - int s = GetVpValue(self, 1)->sign; + int s = GetSelfVpValue(self)->sign; return INT2FIX(s); } @@ -3854,7 +3884,8 @@ static VALUE BigMath_s_exp(VALUE klass, VALUE x, VALUE vprec) { ssize_t prec, n, i; - Real* vx = NULL; + BDVALUE vx; + NULLABLE_BDVALUE nullable_vx = { Qnil, NULL }; VALUE one, d, y; int negative = 0; int infinite = 0; @@ -3871,16 +3902,17 @@ BigMath_s_exp(VALUE klass, VALUE x, VALUE vprec) switch (TYPE(x)) { case T_DATA: if (!is_kind_of_BigDecimal(x)) break; - vx = DATA_PTR(x); - negative = BIGDECIMAL_NEGATIVE_P(vx); - infinite = VpIsPosInf(vx) || VpIsNegInf(vx); - nan = VpIsNaN(vx); + vx = GetBDValueMust(x); + nullable_vx = bdvalue_nullable(vx); + negative = BIGDECIMAL_NEGATIVE_P(vx.real); + infinite = VpIsPosInf(vx.real) || VpIsNegInf(vx.real); + nan = VpIsNaN(vx.real); break; case T_FIXNUM: /* fall through */ case T_BIGNUM: - vx = GetVpValue(x, 0); + nullable_vx = GetBDValue(x); break; case T_FLOAT: @@ -3889,12 +3921,12 @@ BigMath_s_exp(VALUE klass, VALUE x, VALUE vprec) infinite = isinf(flo); nan = isnan(flo); if (!infinite && !nan) { - vx = GetVpValueWithPrec(x, 0, 0); + nullable_vx = GetBDValueWithPrec(x, 0); } break; case T_RATIONAL: - vx = GetVpValueWithPrec(x, prec, 0); + nullable_vx = GetBDValueWithPrec(x, prec); break; default: @@ -3902,37 +3934,35 @@ BigMath_s_exp(VALUE klass, VALUE x, VALUE vprec) } if (infinite) { if (negative) { - return VpCheckGetValue(GetVpValueWithPrec(INT2FIX(0), prec, 1)); + return CheckGetValue(GetBDValueWithPrecMust(INT2FIX(0), prec)); } else { - Real* vy = NewZeroWrapNolimit(1, prec); - VpSetInf(vy, VP_SIGN_POSITIVE_INFINITE); - RB_GC_GUARD(vy->obj); - return VpCheckGetValue(vy); + BDVALUE y = NewZeroWrapNolimit(1, prec); + VpSetInf(y.real, VP_SIGN_POSITIVE_INFINITE); + return CheckGetValue(y); } } else if (nan) { - Real* vy = NewZeroWrapNolimit(1, prec); - VpSetNaN(vy); - RB_GC_GUARD(vy->obj); - return VpCheckGetValue(vy); + BDVALUE y = NewZeroWrapNolimit(1, prec); + VpSetNaN(y.real); + return CheckGetValue(y); } - else if (vx == NULL) { + else if (nullable_vx.real_or_null == NULL) { cannot_be_coerced_into_BigDecimal(rb_eArgError, x); } - x = vx->obj; + vx = bdvalue_nonnullable(nullable_vx); + x = vx.bigdecimal; n = prec + BIGDECIMAL_DOUBLE_FIGURES; - negative = BIGDECIMAL_NEGATIVE_P(vx); + negative = BIGDECIMAL_NEGATIVE_P(vx.real); if (negative) { VALUE x_zero = INT2NUM(1); VALUE x_copy = f_BigDecimal(1, &x_zero, klass); x = BigDecimal_initialize_copy(x_copy, x); - vx = DATA_PTR(x); - VpSetSign(vx, 1); + VpSetSign((Real*)DATA_PTR(x), 1); } - one = VpCheckGetValue(NewOneWrapLimited(1, 1)); + one = CheckGetValue(NewOneWrapLimited(1, 1)); y = one; d = y; i = 1; @@ -3988,7 +4018,8 @@ BigMath_s_log(VALUE klass, VALUE x, VALUE vprec) { ssize_t prec, n, i; SIGNED_VALUE expo; - Real* vx = NULL; + BDVALUE vx; + NULLABLE_BDVALUE nullable_vx = { Qnil, NULL }; VALUE vn, one, two, w, x2, y, d; int zero = 0; int negative = 0; @@ -4011,11 +4042,12 @@ BigMath_s_log(VALUE klass, VALUE x, VALUE vprec) switch (TYPE(x)) { case T_DATA: if (!is_kind_of_BigDecimal(x)) break; - vx = DATA_PTR(x); - zero = VpIsZero(vx); - negative = BIGDECIMAL_NEGATIVE_P(vx); - infinite = VpIsPosInf(vx) || VpIsNegInf(vx); - nan = VpIsNaN(vx); + vx = GetBDValueMust(x); + nullable_vx = bdvalue_nullable(vx); + zero = VpIsZero(vx.real); + negative = BIGDECIMAL_NEGATIVE_P(vx.real); + infinite = VpIsPosInf(vx.real) || VpIsNegInf(vx.real); + nan = VpIsNaN(vx.real); break; case T_FIXNUM: @@ -4030,7 +4062,7 @@ BigMath_s_log(VALUE klass, VALUE x, VALUE vprec) negative = i < 0; get_vp_value: if (zero || negative) break; - vx = GetVpValue(x, 0); + nullable_vx = GetBDValue(x); break; case T_FLOAT: @@ -4040,7 +4072,7 @@ BigMath_s_log(VALUE klass, VALUE x, VALUE vprec) infinite = isinf(flo); nan = isnan(flo); if (!zero && !negative && !infinite && !nan) { - vx = GetVpValueWithPrec(x, 0, 1); + nullable_vx = bdvalue_nullable(GetBDValueWithPrecMust(x, 0)); } break; @@ -4048,7 +4080,7 @@ BigMath_s_log(VALUE klass, VALUE x, VALUE vprec) zero = RRATIONAL_ZERO_P(x); negative = RRATIONAL_NEGATIVE_P(x); if (zero || negative) break; - vx = GetVpValueWithPrec(x, prec, 1); + nullable_vx = bdvalue_nullable(GetBDValueWithPrecMust(x, prec)); break; case T_COMPLEX: @@ -4059,36 +4091,35 @@ BigMath_s_log(VALUE klass, VALUE x, VALUE vprec) break; } if (infinite && !negative) { - Real *vy = NewZeroWrapNolimit(1, prec); - RB_GC_GUARD(vy->obj); - VpSetInf(vy, VP_SIGN_POSITIVE_INFINITE); - return VpCheckGetValue(vy); + BDVALUE y = NewZeroWrapNolimit(1, prec); + VpSetInf(y.real, VP_SIGN_POSITIVE_INFINITE); + return CheckGetValue(y); } else if (nan) { - Real* vy = NewZeroWrapNolimit(1, prec); - RB_GC_GUARD(vy->obj); - VpSetNaN(vy); - return VpCheckGetValue(vy); + BDVALUE y = NewZeroWrapNolimit(1, prec); + VpSetNaN(y.real); + return CheckGetValue(y); } else if (zero || negative) { rb_raise(rb_eMathDomainError, "Zero or negative argument for log"); } - else if (vx == NULL) { + else if (nullable_vx.real_or_null == NULL) { cannot_be_coerced_into_BigDecimal(rb_eArgError, x); } - x = VpCheckGetValue(vx); + vx = bdvalue_nonnullable(nullable_vx); + x = CheckGetValue(vx); - one = VpCheckGetValue(NewOneWrapLimited(1, 1)); - two = VpCheckGetValue(VpCreateRbObject(1, "2", true)); + one = CheckGetValue(NewOneWrapLimited(1, 1)); + two = CheckGetValue(bdvalue_nonnullable(CreateFromString(1, "2", rb_cBigDecimal, true, true))); n = prec + BIGDECIMAL_DOUBLE_FIGURES; vn = SSIZET2NUM(n); - expo = VpExponent10(vx); + expo = VpExponent10(vx.real); if (expo < 0 || expo >= 3) { char buf[DECIMAL_SIZE_OF_BITS(SIZEOF_VALUE * CHAR_BIT) + 4]; snprintf(buf, sizeof(buf), "1E%"PRIdVALUE, -expo); - x = BigDecimal_mult2(x, VpCheckGetValue(VpCreateRbObject(1, buf, true)), vn); + x = BigDecimal_mult2(x, CheckGetValue(bdvalue_nonnullable(CreateFromString(1, buf, rb_cBigDecimal, true, true))), vn); } else { expo = 0; @@ -4120,7 +4151,7 @@ BigMath_s_log(VALUE klass, VALUE x, VALUE vprec) if (expo != 0) { VALUE log10, vexpo, dy; log10 = BigMath_s_log(klass, INT2FIX(10), vprec); - vexpo = VpCheckGetValue(GetVpValue(SSIZET2NUM(expo), 1)); + vexpo = CheckGetValue(GetBDValueMust(SSIZET2NUM(expo))); dy = BigDecimal_mult(log10, vexpo); y = BigDecimal_add(y, dy); } @@ -4680,10 +4711,10 @@ VpCheckException(Real *p, bool always) } static VALUE -VpCheckGetValue(Real *p) +CheckGetValue(BDVALUE v) { - VpCheckException(p, false); - return p->obj; + VpCheckException(v.real, false); + return v.bigdecimal; } /* diff --git a/ext/bigdecimal/bigdecimal.h b/ext/bigdecimal/bigdecimal.h index 54fed811..7b7815be 100644 --- a/ext/bigdecimal/bigdecimal.h +++ b/ext/bigdecimal/bigdecimal.h @@ -167,7 +167,6 @@ enum rbd_rounding_mode { * r = 0.xxxxxxxxx *BASE**exponent */ typedef struct { - VALUE obj; /* Back pointer(VALUE) for Ruby object. */ size_t MaxPrec; /* Maximum precision size */ /* This is the actual size of frac[] */ /*(frac[0] to frac[MaxPrec] are available). */ @@ -195,10 +194,6 @@ typedef struct { * ------------------ */ -VP_EXPORT Real *VpNewRbClass(size_t mx, char const *str, VALUE klass, bool strict_p, bool raise_exception); - -VP_EXPORT Real *VpCreateRbObject(size_t mx, const char *str, bool raise_exception); - #define VpBaseFig() BIGDECIMAL_COMPONENT_FIGURES #define VpDblFig() BIGDECIMAL_DOUBLE_FIGURES #define VpBaseVal() BIGDECIMAL_BASE diff --git a/test/bigdecimal/test_bigdecimal.rb b/test/bigdecimal/test_bigdecimal.rb index 9a7c71b2..e14a9f0f 100644 --- a/test/bigdecimal/test_bigdecimal.rb +++ b/test/bigdecimal/test_bigdecimal.rb @@ -2382,10 +2382,10 @@ def test_gc_compaction_safe assert_equal(x.div(y), bx.div(by)) assert_equal(x.remainder(y), bx.remainder(by)) assert_equal(x.divmod(y), bx.divmod(by)) - # assert_equal([0, x], bx.divmod(inf)) - # assert_in_delta(x, bx.remainder(inf)) - # assert((nan + nan).nan?) - # assert((nan - nan).nan?) + assert_equal([0, x], bx.divmod(inf)) + assert_in_delta(x, bx.remainder(inf)) + assert((nan + nan).nan?) + assert((nan - nan).nan?) assert((nan * nan).nan?) assert((nan / nan).nan?) assert((nan % nan).nan?) @@ -2394,11 +2394,11 @@ def test_gc_compaction_safe assert((inf * inf).infinite?) assert((inf / inf).nan?) assert((inf % inf).nan?) - # assert_in_delta(Math.exp(x), BigMath.exp(bx, 10)) - # assert_in_delta(x**y, bx**by) - # assert_in_delta(x**y, bx.power(by, 10)) - # assert_in_delta(Math.exp(x), BigMath.exp(bx, 10)) - # assert_in_delta(Math.log(x), BigMath.log(bx, 10)) + assert_in_delta(Math.exp(x), BigMath.exp(bx, 10)) + assert_in_delta(x**y, bx**by) + assert_in_delta(x**y, bx.power(by, 10)) + assert_in_delta(Math.exp(x), BigMath.exp(bx, 10)) + assert_in_delta(Math.log(x), BigMath.log(bx, 10)) end; end