summaryrefslogtreecommitdiff
path: root/ext/bigdecimal
diff options
context:
space:
mode:
Diffstat (limited to 'ext/bigdecimal')
-rw-r--r--ext/bigdecimal/bigdecimal.c40
1 files changed, 21 insertions, 19 deletions
diff --git a/ext/bigdecimal/bigdecimal.c b/ext/bigdecimal/bigdecimal.c
index 72c7b34..5194615 100644
--- a/ext/bigdecimal/bigdecimal.c
+++ b/ext/bigdecimal/bigdecimal.c
@@ -199,6 +199,7 @@ cannot_be_coerced_into_BigDecimal(VALUE exc_class, VALUE v)
}
static inline VALUE BigDecimal_div2(VALUE, VALUE, VALUE);
+static VALUE rb_float_convert_to_BigDecimal(VALUE val, size_t digs, int raise_exception);
static Real*
GetVpValueWithPrec(VALUE v, long prec, int must)
@@ -208,27 +209,14 @@ GetVpValueWithPrec(VALUE v, long prec, int must)
VALUE num, bg;
char szD[128];
VALUE orig = Qundef;
- double d;
again:
switch(TYPE(v)) {
- case T_FLOAT:
- if (prec < 0) goto unable_to_coerce_without_prec;
- if (prec > (long)DBLE_FIG) goto SomeOneMayDoIt;
- d = RFLOAT_VALUE(v);
- if (!isfinite(d)) {
- pv = VpCreateRbObject(1, NULL, true);
- VpDtoV(pv, d);
- return pv;
- }
- if (d != 0.0) {
- v = rb_funcall(v, id_to_r, 0);
- goto again;
- }
- if (1/d < 0.0) {
- return VpCreateRbObject(prec, "-0", true);
- }
- return VpCreateRbObject(prec, "0", true);
+ case T_FLOAT: {
+ VALUE obj = rb_float_convert_to_BigDecimal(v, prec, must);
+ TypedData_Get_Struct(obj, Real, &BigDecimal_data_type, pv);
+ return pv;
+ }
case T_RATIONAL:
if (prec < 0) goto unable_to_coerce_without_prec;
@@ -2806,10 +2794,13 @@ rb_inum_convert_to_BigDecimal(VALUE val, RB_UNUSED_VAR(size_t digs), int raise_e
}
}
+static VALUE rb_rational_convert_to_BigDecimal(VALUE val, size_t digs, int raise_exception);
+
static VALUE
rb_float_convert_to_BigDecimal(VALUE val, size_t digs, int raise_exception)
{
double d = RFLOAT_VALUE(val);
+
if (!isfinite(d)) {
Real *vp = VpCreateRbObject(1, NULL, true); /* vp->obj is allocated */
VpDtoV(vp, d);
@@ -2829,7 +2820,18 @@ rb_float_convert_to_BigDecimal(VALUE val, size_t digs, int raise_exception)
rb_raise(rb_eArgError, "precision too large.");
}
- Real *vp = GetVpValueWithPrec(val, digs, 1);
+ if (d != 0.0) {
+ val = rb_funcall(val, id_to_r, 0);
+ return rb_rational_convert_to_BigDecimal(val, digs, raise_exception);
+ }
+
+ Real *vp;
+ if (1/d < 0.0) {
+ vp = VpCreateRbObject(digs, "-0", true);
+ }
+ else {
+ vp = VpCreateRbObject(digs, "0", true);
+ }
return check_exception(vp->obj);
}