Skip to content

Commit fc43704

Browse files
committed
Implement BigMath.frexp and ldexp with exponent of 10
Math.frexp and ldexp calculates with exponent of 2, BigDecimal version of frexp and ldexp calculates with exponent of 10
1 parent 150d01d commit fc43704

File tree

3 files changed

+57
-0
lines changed

3 files changed

+57
-0
lines changed

lib/bigdecimal/math.rb

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@
2424
# log10(x, prec)
2525
# log1p(x, prec)
2626
# expm1(x, prec)
27+
# frexp(x)
28+
# ldexp(x, exponent)
2729
# PI (prec)
2830
# E (prec) == exp(1.0,prec)
2931
#
@@ -568,6 +570,35 @@ def expm1(x, prec)
568570
exp_prec > 0 ? exp(x, exp_prec).sub(1, prec) : BigDecimal(-1)
569571
end
570572

573+
# call-seq:
574+
# frexp(x) -> [BigDecimal, Integer]
575+
#
576+
# Decomposes +x+ into a normalized fraction and an integral power of ten.
577+
#
578+
# BigMath.frexp(BigDecimal(123.456))
579+
# #=> [0.123456e0, 3]
580+
#
581+
def frexp(x)
582+
x = BigDecimal::Internal.coerce_to_bigdecimal(x, 0, :frexp)
583+
return [x, 0] unless x.finite?
584+
585+
exponent = x.exponent
586+
[x._decimal_shift(-exponent), exponent]
587+
end
588+
589+
# call-seq:
590+
# ldexp(fraction, exponent) -> BigDecimal
591+
#
592+
# Inverse of +frexp+.
593+
# Returns the value of fraction * 10**exponent.
594+
#
595+
# BigMath.ldexp(BigDecimal("0.123456e0"), 3)
596+
# #=> 0.123456e3
597+
#
598+
def ldexp(x, exponent)
599+
x = BigDecimal::Internal.coerce_to_bigdecimal(x, 0, :frexp)
600+
x.finite? ? x._decimal_shift(exponent) : x
601+
end
571602

572603
# call-seq:
573604
# PI(numeric) -> BigDecimal

test/bigdecimal/test_bigmath.rb

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -469,4 +469,28 @@ def test_expm1
469469
assert_in_exact_precision(exp(BigDecimal("1.23e-10"), 120) - 1, expm1(BigDecimal("1.23e-10"), 100), 100)
470470
assert_in_exact_precision(exp(123, 120) - 1, expm1(BigDecimal("123"), 100), 100)
471471
end
472+
473+
def test_frexp
474+
BigDecimal.save_limit do
475+
BigDecimal.limit(3)
476+
assert_equal([BigDecimal("-0.123456"), 10], BigMath.frexp(BigDecimal("-0.123456e10")))
477+
assert_equal([BigDecimal("0.123456"), -10], BigMath.frexp(BigDecimal("0.123456e-10")))
478+
assert_equal([BigDecimal("0.123456789"), 9], BigMath.frexp(123456789))
479+
assert_equal([BigDecimal(0), 0], BigMath.frexp(BigDecimal(0)))
480+
assert_equal([BigDecimal::NAN, 0], BigMath.frexp(BigDecimal::NAN))
481+
assert_equal([BigDecimal::INFINITY, 0], BigMath.frexp(BigDecimal::INFINITY))
482+
end
483+
end
484+
485+
def test_ldexp
486+
BigDecimal.save_limit do
487+
BigDecimal.limit(3)
488+
assert_equal(BigDecimal("-0.123456e10"), BigMath.ldexp(BigDecimal("-0.123456"), 10))
489+
assert_equal(BigDecimal("0.123456e20"), BigMath.ldexp(BigDecimal("0.123456e10"), 10.9))
490+
assert_equal(BigDecimal("0.123456e-10"), BigMath.ldexp(BigDecimal("0.123456"), -10))
491+
assert_equal(BigDecimal("0.123456789e19"), BigMath.ldexp(123456789, 10))
492+
assert(BigMath.ldexp(BigDecimal::NAN, 10).nan?)
493+
assert_equal(BigDecimal::INFINITY, BigMath.ldexp(BigDecimal::INFINITY, 10))
494+
end
495+
end
472496
end

test/bigdecimal/test_jruby.rb

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,8 @@ def test_bigmath
7171
assert_in_delta(Math.log10(3), BigMath.log10(BigDecimal(3), N))
7272
assert_in_delta(Math.log1p(0.1), BigMath.log1p(BigDecimal('0.1'), N)) if defined? Math.log1p
7373
assert_in_delta(Math.expm1(0.1), BigMath.expm1(BigDecimal('0.1'), N)) if defined? Math.expm1
74+
assert_equal([BigDecimal('0.123'), 4], BigMath.frexp(BigDecimal('0.123e4')))
75+
assert_equal(BigDecimal('12.3e4'), BigMath.ldexp(BigDecimal('12.3'), 4))
7476
assert_in_delta(Math::PI, BigMath.PI(N))
7577
assert_in_delta(Math::E, BigMath.E(N))
7678
end

0 commit comments

Comments
 (0)