Skip to content

Commit

Permalink
(wip)
Browse files Browse the repository at this point in the history
  • Loading branch information
mrkn committed Nov 21, 2016
1 parent a23f433 commit 7ae4150
Show file tree
Hide file tree
Showing 2 changed files with 113 additions and 1 deletion.
51 changes: 50 additions & 1 deletion ext/bigdecimal/bigdecimal.c
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ static ID id_ceil;
static ID id_floor;
static ID id_to_r;
static ID id_eq;
static ID id_half;

/* MACRO's to guard objects from GC by keeping them in stack */
#define ENTER(n) volatile VALUE RB_UNUSED_VAR(vStack[n]);int iStack=0
Expand Down Expand Up @@ -440,12 +441,55 @@ BigDecimal_load(VALUE self, VALUE str)
return ToValue(pv);
}

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 noopt;

mode = rb_hash_lookup2(opts, ID2SYM(id_half), Qundef);
if (mode == Qundef)
goto noopt;

if (SYMBOL_P(mode))
mode = rb_sym2str(mode);
s = StringValueCStr(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_EVEN;
break;
default:
break;
}
rb_raise(rb_eArgError, "unknown rounding mode: %"PRIsVALUE, mode);

noopt:
return VpGetRoundMode();
}

static unsigned short
check_rounding_mode(VALUE const v)
{
unsigned short sw;
ID id;
switch (TYPE(v)) {
case T_HASH:
return VP_ROUND_HALF_UP;

case T_SYMBOL:
id = SYM2ID(v);
if (id == id_up)
Expand Down Expand Up @@ -1720,7 +1764,12 @@ BigDecimal_round(int argc, VALUE *argv, VALUE self)
iLoc = 0;
break;
case 1:
iLoc = NUM2INT(vLoc);
if (RB_TYPE_P(vLoc, T_HASH)) {
sw = check_rounding_mode(vLoc);
}
else {
iLoc = NUM2INT(vLoc);
}
break;
case 2:
iLoc = NUM2INT(vLoc);
Expand Down
63 changes: 63 additions & 0 deletions test/test_bigdecimal.rb
Original file line number Diff line number Diff line change
Expand Up @@ -903,6 +903,69 @@ def test_round
end
end

def test_round_half_even
assert_equal(BigDecimal('12.0'), BigDecimal('12.5').round(half: :even))
assert_equal(BigDecimal('14.0'), BigDecimal('13.5').round(half: :even))

assert_equal(BigDecimal('2.2'), BigDecimal('2.15').round(1, half: :even))
assert_equal(BigDecimal('2.2'), BigDecimal('2.25').round(1, half: :even))
assert_equal(BigDecimal('2.4'), BigDecimal('2.35').round(1, half: :even))

assert_equal(BigDecimal('-2.2'), BigDecimal('-2.15').round(1, half: :even))
assert_equal(BigDecimal('-2.2'), BigDecimal('-2.25').round(1, half: :even))
assert_equal(BigDecimal('-2.4'), BigDecimal('-2.35').round(1, half: :even))

assert_equal(BigDecimal('7.1364'), BigDecimal('7.13645').round(4, half: :even))
assert_equal(BigDecimal('7.1365'), BigDecimal('7.1364501').round(4, half: :even))
assert_equal(BigDecimal('7.1364'), BigDecimal('7.1364499').round(4, half: :even))

assert_equal(BigDecimal('-7.1364'), BigDecimal('-7.13645').round(4, half: :even))
assert_equal(BigDecimal('-7.1365'), BigDecimal('-7.1364501').round(4, half: :even))
assert_equal(BigDecimal('-7.1364'), BigDecimal('-7.1364499').round(4, half: :even))
end

def test_round_half_up
assert_equal(BigDecimal('13.0'), BigDecimal('12.5').round(half: :up))
assert_equal(BigDecimal('14.0'), BigDecimal('13.5').round(half: :up))

assert_equal(BigDecimal('2.2'), BigDecimal('2.15').round(1, half: :up))
assert_equal(BigDecimal('2.3'), BigDecimal('2.25').round(1, half: :up))
assert_equal(BigDecimal('2.4'), BigDecimal('2.35').round(1, half: :up))

assert_equal(BigDecimal('-2.2'), BigDecimal('-2.15').round(1, half: :up))
assert_equal(BigDecimal('-2.3'), BigDecimal('-2.25').round(1, half: :up))
assert_equal(BigDecimal('-2.4'), BigDecimal('-2.35').round(1, half: :up))

assert_equal(BigDecimal('7.1365'), BigDecimal('7.13645').round(4, half: :up))
assert_equal(BigDecimal('7.1365'), BigDecimal('7.1364501').round(4, half: :up))
assert_equal(BigDecimal('7.1364'), BigDecimal('7.1364499').round(4, half: :up))

assert_equal(BigDecimal('-7.1365'), BigDecimal('-7.13645').round(4, half: :up))
assert_equal(BigDecimal('-7.1365'), BigDecimal('-7.1364501').round(4, half: :up))
assert_equal(BigDecimal('-7.1364'), BigDecimal('-7.1364499').round(4, half: :up))
end

def test_round_half_down
assert_equal(BigDecimal('12.0'), BigDecimal('12.5').round(half: :down))
assert_equal(BigDecimal('13.0'), BigDecimal('13.5').round(half: :down))

assert_equal(BigDecimal('2.1'), BigDecimal('2.15').round(1, half: :down))
assert_equal(BigDecimal('2.2'), BigDecimal('2.25').round(1, half: :down))
assert_equal(BigDecimal('2.3'), BigDecimal('2.35').round(1, half: :down))

assert_equal(BigDecimal('-2.1'), BigDecimal('-2.15').round(1, half: :down))
assert_equal(BigDecimal('-2.2'), BigDecimal('-2.25').round(1, half: :down))
assert_equal(BigDecimal('-2.3'), BigDecimal('-2.35').round(1, half: :down))

assert_equal(BigDecimal('7.1364'), BigDecimal('7.13645').round(4, half: :down))
assert_equal(BigDecimal('7.1365'), BigDecimal('7.1364501').round(4, half: :down))
assert_equal(BigDecimal('7.1364'), BigDecimal('7.1364499').round(4, half: :down))

assert_equal(BigDecimal('-7.1364'), BigDecimal('-7.13645').round(4, half: :down))
assert_equal(BigDecimal('-7.1365'), BigDecimal('-7.1364501').round(4, half: :down))
assert_equal(BigDecimal('-7.1364'), BigDecimal('-7.1364499').round(4, half: :down))
end

def test_truncate
assert_equal(3, BigDecimal.new("3.14159").truncate)
assert_equal(8, BigDecimal.new("8.7").truncate)
Expand Down

0 comments on commit 7ae4150

Please sign in to comment.