Skip to content

Commit 1a93b02

Browse files
committed
Implement BigMath.log2 and BigMath.log10
1 parent 9eb0fa8 commit 1a93b02

File tree

2 files changed

+88
-0
lines changed

2 files changed

+88
-0
lines changed

lib/bigdecimal/math.rb

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@
2020
# asinh(x, prec)
2121
# acosh(x, prec)
2222
# atanh(x, prec)
23+
# log2 (x, prec)
24+
# log10(x, prec)
2325
# PI (prec)
2426
# E (prec) == exp(1.0,prec)
2527
#
@@ -485,6 +487,56 @@ def atanh(x, prec)
485487
(BigMath.log(x + 1, prec) - BigMath.log(1 - x, prec)) / 2
486488
end
487489

490+
# call-seq:
491+
# BigMath.log2(decimal, numeric) -> BigDecimal
492+
#
493+
# Computes the base 2 logarithm of +decimal+ to the specified number of
494+
# digits of precision, +numeric+.
495+
#
496+
# If +decimal+ is zero or negative, raises Math::DomainError.
497+
#
498+
# If +decimal+ is positive infinity, returns Infinity.
499+
#
500+
# If +decimal+ is NaN, returns NaN.
501+
#
502+
# BigMath.log2(BigDecimal('3'), 16).to_s
503+
# #=> "0.158496250072115618145373894394782e1"
504+
#
505+
def log2(x, prec)
506+
raise ArgumentError, "Zero or negative precision for log2" if prec <= 0
507+
return BigDecimal::NAN if x.nan?
508+
return BigDecimal::INFINITY if x.infinite? == 1
509+
510+
prec2 = prec + BigDecimal.double_fig * 3 / 2
511+
v = BigMath.log(x, prec2).div(BigMath.log(BigDecimal(2), prec2), prec2)
512+
v.round(prec + BigDecimal.double_fig - (v.exponent < 0 ? v.exponent : 0), BigDecimal::ROUND_HALF_UP)
513+
end
514+
515+
# call-seq:
516+
# BigMath.log10(decimal, numeric) -> BigDecimal
517+
#
518+
# Computes the base 10 logarithm of +decimal+ to the specified number of
519+
# digits of precision, +numeric+.
520+
#
521+
# If +decimal+ is zero or negative, raises Math::DomainError.
522+
#
523+
# If +decimal+ is positive infinity, returns Infinity.
524+
#
525+
# If +decimal+ is NaN, returns NaN.
526+
#
527+
# BigMath.log10(BigDecimal('3'), 16).to_s
528+
# #=> "0.47712125471966243729502790325512e0"
529+
#
530+
def log10(x, prec)
531+
raise ArgumentError, "Zero or negative precision for log10" if prec <= 0
532+
return BigDecimal::NAN if x.nan?
533+
return BigDecimal::INFINITY if x.infinite? == 1
534+
535+
prec2 = prec + BigDecimal.double_fig * 3 / 2
536+
v = BigMath.log(x, prec2).div(BigMath.log(BigDecimal(10), prec2), prec2)
537+
v.round(prec + BigDecimal.double_fig - (v.exponent < 0 ? v.exponent : 0), BigDecimal::ROUND_HALF_UP)
538+
end
539+
488540
# call-seq:
489541
# PI(numeric) -> BigDecimal
490542
#

test/bigdecimal/test_bigmath.rb

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -286,4 +286,40 @@ def test_log
286286
end
287287
SRC
288288
end
289+
290+
def test_log2
291+
assert_raise(Math::DomainError) { log2(BigDecimal("0"), N) }
292+
assert_raise(Math::DomainError) { log2(BigDecimal("-1"), N) }
293+
assert_raise(Math::DomainError) { log2(MINF, N) }
294+
assert_equal(PINF, log2(PINF, N))
295+
assert_in_epsilon(BigDecimal("1.5849625007211561814537389439478165087598144076924810604557526545410982277943585625222804749180882420909806624750592"),
296+
log2(BigDecimal("3"), 100), BigDecimal("1e-100"))
297+
assert_relative_precision {|n| log2(BigDecimal("3"), n) }
298+
assert_relative_precision {|n| log2(BigDecimal("3e20"), n) }
299+
assert_relative_precision {|n| log2(BigDecimal("1e-20") + 1, n) }
300+
[BigDecimal::ROUND_UP, BigDecimal::ROUND_DOWN].each do |round_mode|
301+
BigDecimal.mode(BigDecimal::ROUND_MODE, round_mode)
302+
[0, 1, 2, 11, 123].each do |n|
303+
assert_equal(n, log2(BigDecimal(2**n), N))
304+
end
305+
end
306+
end
307+
308+
def test_log10
309+
assert_raise(Math::DomainError) { log10(BigDecimal("0"), N) }
310+
assert_raise(Math::DomainError) { log10(BigDecimal("-1"), N) }
311+
assert_raise(Math::DomainError) { log10(MINF, N) }
312+
assert_equal(PINF, log10(PINF, N))
313+
assert_in_epsilon(BigDecimal("0.4771212547196624372950279032551153092001288641906958648298656403052291527836611230429683556476163015104646927682520"),
314+
log10(BigDecimal("3"), 100), BigDecimal("1e-100"))
315+
assert_relative_precision {|n| log10(BigDecimal("3"), n) }
316+
assert_relative_precision {|n| log10(BigDecimal("3e20"), n) }
317+
assert_relative_precision {|n| log10(BigDecimal("1e-20") + 1, n) }
318+
[BigDecimal::ROUND_UP, BigDecimal::ROUND_DOWN].each do |round_mode|
319+
BigDecimal.mode(BigDecimal::ROUND_MODE, round_mode)
320+
[0, 1, 2, 11, 123].each do |n|
321+
assert_equal(n, log10(BigDecimal(10**n), N))
322+
end
323+
end
324+
end
289325
end

0 commit comments

Comments
 (0)