summaryrefslogtreecommitdiff
path: root/ext/bigdecimal/bigdecimal.c
diff options
context:
space:
mode:
authormatz <matz@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2009-06-11 06:06:01 +0000
committermatz <matz@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2009-06-11 06:06:01 +0000
commit1e7898d76a90befec85074f9d580531cf64ee9be (patch)
tree9f2bf529de22a6ef97bc0720acc9e0f9cc80bff5 /ext/bigdecimal/bigdecimal.c
parent3bb5d07486b3d06224481b459be5e814fe082b7a (diff)
* ext/bigdecimal/bigdecimal.c (VpCtoV): big number should result
to infinite. backported from 1.9. * ext/bigdecimal/bigdecimal.c (VpIsRoundMode): rounding mode condition check updated. backported from 1.9. * ext/bigdecimal/bigdecimal.c (VpPower): should handle NaN and Inf. backported from 1.9. * ext/bigdecimal/bigdecimal.c (BigDecimal_DoDivmod): divmod should raise ZeroDivisionError. backported from 1.9. * ext/bigdecimal/bigdecimal.c (BigDecimal_mode): should check exception for VP_EXCEPTION_UNDERFLOW and VP_EXCEPTION_ZERODIVIDE. backported from 1.9. * ext/bigdecimal/bigdecimal.c (VpException): ditto. * ext/bigdecimal/bigdecimal.h (VP_EXCEPTION_ZERODIVIDE): new error code. backported from 1.9. * ext/bigdecimal/bigdecimal.c (BigDecimal_div2, BigDecimal_round, BigDecimal_truncate, BigDecimal_floor, BigDecimal_ceil): eagerly convert bigdecimal to integer. backported from 1.9. * ext/bigdecimal/bigdecimal.c (VpMult): free internal Real. backported from 1.9. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/branches/ruby_1_8@23664 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'ext/bigdecimal/bigdecimal.c')
-rw-r--r--ext/bigdecimal/bigdecimal.c80
1 files changed, 61 insertions, 19 deletions
diff --git a/ext/bigdecimal/bigdecimal.c b/ext/bigdecimal/bigdecimal.c
index 60751a84b7..0257ca50a7 100644
--- a/ext/bigdecimal/bigdecimal.c
+++ b/ext/bigdecimal/bigdecimal.c
@@ -22,7 +22,10 @@
#include <float.h>
#include <math.h>
#include "math.h"
-#include "version.h"
+
+#ifdef HAVE_IEEEFP_H
+#include <ieeefp.h>
+#endif
/* #define ENABLE_NUMERIC_STRING */
@@ -411,11 +414,22 @@ BigDecimal_mode(int argc, VALUE *argv, VALUE self)
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) {
@@ -956,7 +970,9 @@ BigDecimal_DoDivmod(VALUE self, VALUE r, Real **div, Real **mod)
if(VpIsNaN(a) || VpIsNaN(b)) goto NaN;
if(VpIsInf(a) || VpIsInf(b)) goto NaN;
- if(VpIsZero(b)) goto NaN;
+ if(VpIsZero(b)) {
+ rb_raise(rb_eZeroDivError, "divided by 0");
+ }
if(VpIsZero(a)) {
GUARD_OBJ(c,VpCreateRbObject(1, "0"));
GUARD_OBJ(d,VpCreateRbObject(1, "0"));
@@ -1113,7 +1129,7 @@ BigDecimal_div2(int argc, VALUE *argv, VALUE self)
Real *mod;
obj = BigDecimal_DoDivmod(self,b,&div,&mod);
if(obj!=(VALUE)0) return obj;
- return ToValue(div);
+ return BigDecimal_to_i(ToValue(div));
} else { /* div in BigDecimal sense */
U_LONG ix = (U_LONG)GetPositiveInt(n);
if(ix==0) return BigDecimal_div(self,b);
@@ -1311,6 +1327,9 @@ BigDecimal_round(int argc, VALUE *argv, VALUE self)
GUARD_OBJ(c,VpCreateRbObject(mx, "0"));
VpSetPrecLimit(pl);
VpActiveRound(c,a,sw,iLoc);
+ if (argc == 0) {
+ return BigDecimal_to_i(ToValue(c));
+ }
return ToValue(c);
}
@@ -1355,6 +1374,9 @@ BigDecimal_truncate(int argc, VALUE *argv, VALUE self)
GUARD_OBJ(c,VpCreateRbObject(mx, "0"));
VpSetPrecLimit(pl);
VpActiveRound(c,a,VP_ROUND_DOWN,iLoc); /* 0: truncate */
+ if (argc == 0) {
+ return BigDecimal_to_i(ToValue(c));
+ }
return ToValue(c);
}
@@ -1415,6 +1437,9 @@ BigDecimal_floor(int argc, VALUE *argv, VALUE self)
GUARD_OBJ(c,VpCreateRbObject(mx, "0"));
VpSetPrecLimit(pl);
VpActiveRound(c,a,VP_ROUND_FLOOR,iLoc);
+ if (argc == 0) {
+ return BigDecimal_to_i(ToValue(c));
+ }
return ToValue(c);
}
@@ -1459,6 +1484,9 @@ BigDecimal_ceil(int argc, VALUE *argv, VALUE self)
GUARD_OBJ(c,VpCreateRbObject(mx, "0"));
VpSetPrecLimit(pl);
VpActiveRound(c,a,VP_ROUND_CEIL,iLoc);
+ if (argc == 0) {
+ return BigDecimal_to_i(ToValue(c));
+ }
return ToValue(c);
}
@@ -1741,7 +1769,7 @@ BigDecimal_new(int argc, VALUE *argv, VALUE self)
*
* A limit of 0, the default, means no upper limit.
*
- * The limit specified by this method takes priority over any 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
@@ -1846,7 +1874,7 @@ Init_bigdecimal(void)
/*
* 0x01: Determines what happens when the result of a computation is an
- * underflow (a result too large to be represented). See BigDecimal.mode.
+ * overflow (a result too large to be represented). See BigDecimal.mode.
*/
rb_define_const(rb_cBigDecimal, "EXCEPTION_OVERFLOW",INT2FIX(VP_EXCEPTION_OVERFLOW));
@@ -2097,9 +2125,9 @@ VpGetRoundMode(void)
VP_EXPORT int
VpIsRoundMode(unsigned long n)
{
- if(n==VP_ROUND_UP || n!=VP_ROUND_DOWN ||
- n==VP_ROUND_HALF_UP || n!=VP_ROUND_HALF_DOWN ||
- n==VP_ROUND_CEIL || n!=VP_ROUND_FLOOR ||
+ if(n==VP_ROUND_UP || n==VP_ROUND_DOWN ||
+ n==VP_ROUND_HALF_UP || n==VP_ROUND_HALF_DOWN ||
+ n==VP_ROUND_CEIL || n==VP_ROUND_FLOOR ||
n==VP_ROUND_HALF_EVEN
) return 1;
return 0;
@@ -2219,18 +2247,12 @@ VpException(unsigned short f, const char *str,int always)
switch(f)
{
/*
- case VP_EXCEPTION_ZERODIVIDE:
case VP_EXCEPTION_OVERFLOW:
*/
+ case VP_EXCEPTION_ZERODIVIDE:
case VP_EXCEPTION_INFINITY:
- exc = rb_eFloatDomainError;
- goto raise;
case VP_EXCEPTION_NaN:
- exc = rb_eFloatDomainError;
- goto raise;
case VP_EXCEPTION_UNDERFLOW:
- exc = rb_eFloatDomainError;
- goto raise;
case VP_EXCEPTION_OP:
exc = rb_eFloatDomainError;
goto raise;
@@ -3168,7 +3190,10 @@ VpMult(Real *c, Real *a, Real *b)
/* set LHSV c info */
c->exponent = a->exponent; /* set exponent */
- if(!AddExponent(c,b->exponent)) return 0;
+ if(!AddExponent(c,b->exponent)) {
+ if(w) VpFree(c);
+ return 0;
+ }
VpSetSign(c,VpGetSign(a)*VpGetSign(b)); /* set sign */
Carry = 0;
nc = ind_c = MxIndAB;
@@ -3939,7 +3964,12 @@ VpCtoV(Real *a, const char *int_chr, U_LONG ni, const char *frac, U_LONG nf, con
es = e*((S_INT)BASE_FIG);
e = e * 10 + exp_chr[i] - '0';
if(es>e*((S_INT)BASE_FIG)) {
- return VpException(VP_EXCEPTION_INFINITY,"exponent overflow",0);
+ VpException(VP_EXCEPTION_INFINITY,"exponent overflow",0);
+ sign = 1;
+ if(int_chr[0] == '-') sign = -1;
+ if(signe > 0) VpSetInf(a, sign);
+ else VpSetZero(a, sign);
+ return 1;
}
++i;
}
@@ -4627,8 +4657,20 @@ VpPower(Real *y, Real *x, S_INT n)
}
goto Exit;
}
- if(!VpIsDef(x)) {
- VpSetNaN(y); /* Not sure !!! */
+ if(VpIsNaN(x)) {
+ VpSetNaN(y);
+ goto Exit;
+ }
+ if(VpIsInf(x)) {
+ if(n==0) {
+ VpSetOne(y);
+ goto Exit;
+ }
+ if(n>0) {
+ VpSetInf(y, (n%2==0 || VpIsPosInf(x)) ? 1 : -1);
+ goto Exit;
+ }
+ VpSetZero(y, (n%2==0 || VpIsPosInf(x)) ? 1 : -1);
goto Exit;
}