Skip to content

Commit 30c6755

Browse files
tompngmrkn
andauthored
Implement BigMath.frexp and ldexp with exponent of 10 (#448)
* 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 * Apply suggestion from @mrkn Co-authored-by: Kenta Murata <3959+mrkn@users.noreply.github.com> --------- Co-authored-by: Kenta Murata <3959+mrkn@users.noreply.github.com>
1 parent 80d66c9 commit 30c6755

File tree

3 files changed

+58
-0
lines changed

3 files changed

+58
-0
lines changed

lib/bigdecimal/math.rb

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@
2828
# erfc(x, prec)
2929
# gamma(x, prec)
3030
# lgamma(x, prec)
31+
# frexp(x)
32+
# ldexp(x, exponent)
3133
# PI (prec)
3234
# E (prec) == exp(1.0,prec)
3335
#
@@ -856,6 +858,36 @@ def lgamma(x, prec)
856858
sign * sin(x.mult(pi, prec), prec)
857859
end
858860

861+
# call-seq:
862+
# frexp(x) -> [BigDecimal, Integer]
863+
#
864+
# Decomposes +x+ into a normalized fraction and an integral power of ten.
865+
#
866+
# BigMath.frexp(BigDecimal(123.456))
867+
# #=> [0.123456e0, 3]
868+
#
869+
def frexp(x)
870+
x = BigDecimal::Internal.coerce_to_bigdecimal(x, 0, :frexp)
871+
return [x, 0] unless x.finite?
872+
873+
exponent = x.exponent
874+
[x._decimal_shift(-exponent), exponent]
875+
end
876+
877+
# call-seq:
878+
# ldexp(fraction, exponent) -> BigDecimal
879+
#
880+
# Inverse of +frexp+.
881+
# Returns the value of fraction * 10**exponent.
882+
#
883+
# BigMath.ldexp(BigDecimal("0.123456e0"), 3)
884+
# #=> 0.123456e3
885+
#
886+
def ldexp(x, exponent)
887+
x = BigDecimal::Internal.coerce_to_bigdecimal(x, 0, :ldexp)
888+
x.finite? ? x._decimal_shift(exponent) : x
889+
end
890+
859891
# call-seq:
860892
# PI(numeric) -> BigDecimal
861893
#

test/bigdecimal/test_bigmath.rb

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -585,4 +585,28 @@ def test_lgamma
585585
assert_converge_in_precision {|n| lgamma(BigDecimal('-3.143580888349980058694358781820227899566'), n).first }
586586
assert_converge_in_precision {|n| lgamma(BigDecimal('-4.991544640560047722345260122806465721667'), n).first }
587587
end
588+
589+
def test_frexp
590+
BigDecimal.save_limit do
591+
BigDecimal.limit(3)
592+
assert_equal([BigDecimal("-0.123456"), 10], BigMath.frexp(BigDecimal("-0.123456e10")))
593+
assert_equal([BigDecimal("0.123456"), -10], BigMath.frexp(BigDecimal("0.123456e-10")))
594+
assert_equal([BigDecimal("0.123456789"), 9], BigMath.frexp(123456789))
595+
assert_equal([BigDecimal(0), 0], BigMath.frexp(BigDecimal(0)))
596+
assert_equal([BigDecimal::NAN, 0], BigMath.frexp(BigDecimal::NAN))
597+
assert_equal([BigDecimal::INFINITY, 0], BigMath.frexp(BigDecimal::INFINITY))
598+
end
599+
end
600+
601+
def test_ldexp
602+
BigDecimal.save_limit do
603+
BigDecimal.limit(3)
604+
assert_equal(BigDecimal("-0.123456e10"), BigMath.ldexp(BigDecimal("-0.123456"), 10))
605+
assert_equal(BigDecimal("0.123456e20"), BigMath.ldexp(BigDecimal("0.123456e10"), 10.9))
606+
assert_equal(BigDecimal("0.123456e-10"), BigMath.ldexp(BigDecimal("0.123456"), -10))
607+
assert_equal(BigDecimal("0.123456789e19"), BigMath.ldexp(123456789, 10))
608+
assert(BigMath.ldexp(BigDecimal::NAN, 10).nan?)
609+
assert_equal(BigDecimal::INFINITY, BigMath.ldexp(BigDecimal::INFINITY, 10))
610+
end
611+
end
588612
end

test/bigdecimal/test_jruby.rb

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,8 @@ def test_bigmath
7575
assert_in_delta(Math.erfc(10), BigMath.erfc(BigDecimal(10), N))
7676
assert_in_delta(Math.gamma(0.5), BigMath.gamma(BigDecimal('0.5'), N))
7777
assert_in_delta(Math.lgamma(0.5).first, BigMath.lgamma(BigDecimal('0.5'), N).first)
78+
assert_equal([BigDecimal('0.123'), 4], BigMath.frexp(BigDecimal('0.123e4')))
79+
assert_equal(BigDecimal('12.3e4'), BigMath.ldexp(BigDecimal('12.3'), 4))
7880
assert_in_delta(Math::PI, BigMath.PI(N))
7981
assert_in_delta(Math::E, BigMath.E(N))
8082
end

0 commit comments

Comments
 (0)