ruby-changes:17099
From: mrkn <ko1@a...>
Date: Thu, 26 Aug 2010 09:14:24 +0900 (JST)
Subject: [ruby-changes:17099] Ruby:r29099 (trunk): * ext/bigdecimal/bigdecimal.c (Init_bigdecimal, rmpd_set_thread_local_exception_mode, VpGetException, VpSetException): thread-local exception mode.
mrkn 2010-08-26 09:14:18 +0900 (Thu, 26 Aug 2010) New Revision: 29099 http://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=rev&revision=29099 Log: * ext/bigdecimal/bigdecimal.c (Init_bigdecimal, rmpd_set_thread_local_exception_mode, VpGetException, VpSetException): thread-local exception mode. * ext/bigdecimal/bigdecimal.c (Init_bigdecimal, rmpd_set_thread_local_precision_limit, VpGetPrecLimit, VpSetPrecLimit): thread-local precision limit. * ext/bigdecimal/bigdecimal.c (Init_bigdecimal, rmpd_set_thread_local_rounding_mode, VpGetRoundMode, VpSetRoundMode, VpException, VpInternalRound): thread-local rounding mode. * ext/bigdecimal/bigdecimal.c (BigDecimal_mode, BigDecimal_round, VpIsRoundMode, VpGetRoundMode, VpSetRoundMode, VpActiveRound, VpMidRound, VpLeftRound), ext/bigdecimal/bigdecimal.h: use unsigned short for rounding mode. * test/bigdecimal/test_bigdecimal.rb (test_mode): add test for setting rounding mode. * test/bigdecimal/test_bigdecimal.rb (test_thread_local_mode): add test for setting mode thread-locally. Modified files: trunk/ChangeLog trunk/ext/bigdecimal/bigdecimal.c trunk/ext/bigdecimal/bigdecimal.h trunk/test/bigdecimal/test_bigdecimal.rb Index: ChangeLog =================================================================== --- ChangeLog (revision 29098) +++ ChangeLog (revision 29099) @@ -1,3 +1,29 @@ +Tue Aug 26 09:11:40 2010 Kenta Murata <mrkn@m...> + + * ext/bigdecimal/bigdecimal.c (Init_bigdecimal, + rmpd_set_thread_local_exception_mode, VpGetException, + VpSetException): thread-local exception mode. + + * ext/bigdecimal/bigdecimal.c (Init_bigdecimal, + rmpd_set_thread_local_precision_limit, VpGetPrecLimit, + VpSetPrecLimit): thread-local precision limit. + + * ext/bigdecimal/bigdecimal.c (Init_bigdecimal, + rmpd_set_thread_local_rounding_mode, VpGetRoundMode, + VpSetRoundMode, VpException, VpInternalRound): + thread-local rounding mode. + + * ext/bigdecimal/bigdecimal.c (BigDecimal_mode, BigDecimal_round, + VpIsRoundMode, VpGetRoundMode, VpSetRoundMode, VpActiveRound, + VpMidRound, VpLeftRound), ext/bigdecimal/bigdecimal.h: + use unsigned short for rounding mode. + + * test/bigdecimal/test_bigdecimal.rb (test_mode): add test for + setting rounding mode. + + * test/bigdecimal/test_bigdecimal.rb (test_thread_local_mode): + add test for setting mode thread-locally. + Thu Aug 26 07:29:54 2010 Nobuyoshi Nakada <nobu@r...> * array.c (rb_ary_{shuffle_bang,sample}): use Random class object. Index: ext/bigdecimal/bigdecimal.c =================================================================== --- ext/bigdecimal/bigdecimal.c (revision 29098) +++ ext/bigdecimal/bigdecimal.c (revision 29099) @@ -32,6 +32,10 @@ VALUE rb_cBigDecimal; +static ID id_BigDecimal_exception_mode; +static ID id_BigDecimal_rounding_mode; +static ID id_BigDecimal_precision_limit; + /* MACRO's to guard objects from GC by keeping them in stack */ #define ENTER(n) volatile VALUE vStack[n];int iStack=0 #define PUSH(x) vStack[iStack++] = (unsigned long)(x); @@ -358,11 +362,11 @@ fo = VpGetRoundMode(); if(val==Qnil) return INT2FIX(fo); Check_Type(val, T_FIXNUM); - if(!VpIsRoundMode(FIX2INT(val))) { + if(!VpIsRoundMode((unsigned short)FIX2INT(val))) { rb_raise(rb_eTypeError, "invalid rounding mode"); return Qnil; } - fo = VpSetRoundMode((unsigned long)FIX2INT(val)); + fo = VpSetRoundMode((unsigned short)FIX2INT(val)); return INT2FIX(fo); } rb_raise(rb_eTypeError, "first argument for BigDecimal#mode invalid"); @@ -1279,7 +1283,7 @@ VALUE vRound; size_t mx, pl; - int sw = (int)VpGetRoundMode(); + unsigned short sw = VpGetRoundMode(); int na = rb_scan_args(argc,argv,"02",&vLoc,&vRound); switch(na) { @@ -1294,7 +1298,7 @@ Check_Type(vLoc, T_FIXNUM); iLoc = FIX2INT(vLoc); Check_Type(vRound, T_FIXNUM); - sw = FIX2INT(vRound); + sw = (unsigned short)FIX2INT(vRound); if(!VpIsRoundMode(sw)) { rb_raise(rb_eTypeError, "invalid rounding mode"); return Qnil; @@ -2086,6 +2090,10 @@ rb_define_method(rb_cBigDecimal, "finite?", BigDecimal_IsFinite, 0); rb_define_method(rb_cBigDecimal, "truncate", BigDecimal_truncate, -1); rb_define_method(rb_cBigDecimal, "_dump", BigDecimal_dump, -1); + + 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"); } /* @@ -2104,9 +2112,6 @@ #endif #endif /* BIGDECIMAL_DEBUG */ -static size_t gnPrecLimit = 0; /* Global upper limit of the precision newly allocated */ -static size_t gfRoundMode = VP_ROUND_HALF_UP; /* Mode for general rounding operation */ - static Real *VpConstOne; /* constant 1.0 */ static Real *VpPt5; /* constant 0.5 */ #define maxnr 100UL /* Maximum iterations for calcurating sqrt. */ @@ -2165,57 +2170,127 @@ /* * EXCEPTION Handling. */ -static unsigned short gfDoException = 0; /* Exception flag */ +#define rmpd_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) { - return gfDoException; + VALUE const vmode = rb_thread_local_aref( + rb_thread_current(), + id_BigDecimal_exception_mode + ); + + if (NIL_P(vmode)) { + rmpd_set_thread_local_exception_mode(RMPD_EXCEPTION_MODE_DEFAULT); + return RMPD_EXCEPTION_MODE_DEFAULT; + } + + return (unsigned short)FIX2UINT(vmode); } static void VpSetException(unsigned short f) { - gfDoException = f; + rmpd_set_thread_local_exception_mode(f); } +/* + * Precision limit. + */ + +#define rmpd_set_thread_local_precision_limit(limit) \ + rb_thread_local_aset( \ + rb_thread_current(), \ + id_BigDecimal_precision_limit, \ + SIZET2NUM(limit) \ + ) +#define RMPD_PRECISION_LIMIT_DEFAULT ((size_t)0) + /* These 2 functions added at v1.1.7 */ VP_EXPORT size_t VpGetPrecLimit(void) { - return gnPrecLimit; + VALUE const vlimit = rb_thread_local_aref( + rb_thread_current(), + id_BigDecimal_precision_limit + ); + + if (NIL_P(vlimit)) { + rmpd_set_thread_local_precision_limit(RMPD_PRECISION_LIMIT_DEFAULT); + return RMPD_PRECISION_LIMIT_DEFAULT; + } + + return NUM2SIZET(vlimit); } VP_EXPORT size_t VpSetPrecLimit(size_t n) { - size_t s = gnPrecLimit; - gnPrecLimit = n; + size_t const s = VpGetPrecLimit(); + rmpd_set_thread_local_precision_limit(n); return s; } -VP_EXPORT unsigned long +/* + * Rounding mode. + */ + +#define rmpd_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) { - return gfRoundMode; + VALUE const vmode = rb_thread_local_aref( + rb_thread_current(), + id_BigDecimal_rounding_mode + ); + + if (NIL_P(vmode)) { + rmpd_set_thread_local_rounding_mode(RMPD_ROUNDING_MODE_DEFAULT); + return RMPD_ROUNDING_MODE_DEFAULT; + } + + return (unsigned short)FIX2INT(vmode); } VP_EXPORT int -VpIsRoundMode(unsigned long n) +VpIsRoundMode(unsigned short 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 || - n==VP_ROUND_HALF_EVEN - ) return 1; - return 0; + 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 long -VpSetRoundMode(unsigned long n) +VP_EXPORT unsigned short +VpSetRoundMode(unsigned short n) { - if(VpIsRoundMode(n)) gfRoundMode = n; - return gfRoundMode; + if (VpIsRoundMode(n)) { + rmpd_set_thread_local_rounding_mode(n); + return n; + } + + return VpGetRoundMode(); } /* @@ -2300,10 +2375,11 @@ { VALUE exc; int fatal=0; + unsigned short const exception_mode = VpGetException(); if(f==VP_EXCEPTION_OP || f==VP_EXCEPTION_MEMORY) always = 1; - if(always||(gfDoException&f)) { + if (always || (exception_mode & f)) { switch(f) { /* @@ -4429,7 +4505,7 @@ * */ VP_EXPORT int -VpMidRound(Real *y, int f, ssize_t nf) +VpMidRound(Real *y, unsigned short f, ssize_t nf) /* * Round reletively from the decimal point. * f: rounding mode @@ -4539,7 +4615,7 @@ } VP_EXPORT int -VpLeftRound(Real *y, int f, ssize_t nf) +VpLeftRound(Real *y, unsigned short f, ssize_t nf) /* * Round from the left hand side of the digits. */ @@ -4554,7 +4630,7 @@ } VP_EXPORT int -VpActiveRound(Real *y, Real *x, int f, ssize_t nf) +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 */ @@ -4577,11 +4653,13 @@ { int f = 0; + unsigned short const rounding_mode = VpGetRoundMode(); + if(VpLimitRound(c,ixDigit)) return; if(!v) return; v /= BASE1; - switch(gfRoundMode) { + switch (rounding_mode) { case VP_ROUND_DOWN: break; case VP_ROUND_UP: Index: ext/bigdecimal/bigdecimal.h =================================================================== --- ext/bigdecimal/bigdecimal.h (revision 29098) +++ ext/bigdecimal/bigdecimal.h (revision 29099) @@ -98,6 +98,8 @@ #define VP_EXCEPTION_OP ((unsigned short)0x0020) #define VP_EXCEPTION_MEMORY ((unsigned short)0x0040) +#define RMPD_EXCEPTION_MODE_DEFAULT 0U + /* Computation mode */ #define VP_ROUND_MODE ((unsigned short)0x0100) #define VP_ROUND_UP 1 @@ -108,6 +110,8 @@ #define VP_ROUND_FLOOR 6 #define VP_ROUND_HALF_EVEN 7 +#define RMPD_ROUNDING_MODE_DEFAULT VP_ROUND_HALF_UP + #define VP_SIGN_NaN 0 /* NaN */ #define VP_SIGN_POSITIVE_ZERO 1 /* Positive zero */ #define VP_SIGN_NEGATIVE_ZERO -1 /* Negative zero */ @@ -176,9 +180,9 @@ VP_EXPORT size_t VpSetPrecLimit(size_t n); /* Round mode */ -VP_EXPORT int VpIsRoundMode(unsigned long n); -VP_EXPORT unsigned long VpGetRoundMode(void); -VP_EXPORT unsigned long VpSetRoundMode(unsigned long n); +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); #if 0 /* unused */ @@ -206,9 +210,9 @@ VP_EXPORT void VpItoV(Real *m,S_INT ival); #endif VP_EXPORT int VpSqrt(Real *y,Real *x); -VP_EXPORT int VpActiveRound(Real *y, Real *x, int f, ssize_t il); -VP_EXPORT int VpMidRound(Real *y, int f, ssize_t nf); -VP_EXPORT int VpLeftRound(Real *y, int f, ssize_t nf); +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 VpPower(Real *y, Real *x, SIGNED_VALUE n); Index: test/bigdecimal/test_bigdecimal.rb =================================================================== --- test/bigdecimal/test_bigdecimal.rb (revision 29098) +++ test/bigdecimal/test_bigdecimal.rb (revision 29099) @@ -1,5 +1,7 @@ require_relative "testbase" +require 'thread' + class TestBigDecimal < Test::Unit::TestCase include TestBigDecimalBase @@ -40,8 +42,41 @@ assert_raise(TypeError) { BigDecimal.mode(BigDecimal::EXCEPTION_ALL, 1) } assert_raise(TypeError) { BigDecimal.mode(BigDecimal::ROUND_MODE, 256) } assert_raise(TypeError) { BigDecimal.mode(0xf000, true) } + + begin + saved_mode = BigDecimal.mode(BigDecimal::ROUND_MODE) + + [ BigDecimal::ROUND_UP, + BigDecimal::ROUND_DOWN, + BigDecimal::ROUND_HALF_UP, + BigDecimal::ROUND_HALF_DOWN, + BigDecimal::ROUND_CEILING, + BigDecimal::ROUND_FLOOR, + BigDecimal::ROUND_HALF_EVEN, + ].each do |mode| + BigDecimal.mode(BigDecimal::ROUND_MODE, mode) + assert_equal(mode, BigDecimal.mode(BigDecimal::ROUND_MODE)) + end + ensure + BigDecimal.mode(BigDecimal::ROUND_MODE, saved_mode) + end end + def test_thread_local_mode + begin + saved_mode = BigDecimal.mode(BigDecimal::ROUND_MODE) + + BigDecimal.mode(BigDecimal::ROUND_MODE, BigDecimal::ROUND_UP) + Thread.start { + BigDecimal.mode(BigDecimal::ROUND_MODE, BigDecimal::ROUND_HALF_EVEN) + assert_equal(BigDecimal::ROUND_HALF_EVEN, BigDecimal.mode(BigDecimal::ROUND_MODE)) + }.join + assert_equal(BigDecimal::ROUND_UP, BigDecimal.mode(BigDecimal::ROUND_MODE)) + ensure + BigDecimal.mode(BigDecimal::ROUND_MODE, saved_mode) + end + end + def test_exception_nan _test_mode(BigDecimal::EXCEPTION_NaN) { BigDecimal.new("NaN") } end -- ML: ruby-changes@q... Info: http://www.atdot.net/~ko1/quickml/