Skip to content

Commit 78d5122

Browse files
committed
Implement BigMath.log2 and BigMath.log10
1 parent 965efea commit 78d5122

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
#
@@ -473,6 +475,56 @@ def atanh(x, prec)
473475
(BigMath.log(x + 1, prec) - BigMath.log(1 - x, prec)).div(2, prec)
474476
end
475477

478+
# call-seq:
479+
# BigMath.log2(decimal, numeric) -> BigDecimal
480+
#
481+
# Computes the base 2 logarithm of +decimal+ to the specified number of
482+
# digits of precision, +numeric+.
483+
#
484+
# If +decimal+ is zero or negative, raises Math::DomainError.
485+
#
486+
# If +decimal+ is positive infinity, returns Infinity.
487+
#
488+
# If +decimal+ is NaN, returns NaN.
489+
#
490+
# BigMath.log2(BigDecimal('3'), 16).to_s
491+
# #=> "0.158496250072115618145373894394782e1"
492+
#
493+
def log2(x, prec)
494+
raise ArgumentError, "Zero or negative precision for log2" if prec <= 0
495+
return BigDecimal::NAN if x.nan?
496+
return BigDecimal::INFINITY if x.infinite? == 1
497+
498+
prec2 = prec + BigDecimal.double_fig * 3 / 2
499+
v = BigMath.log(x, prec2).div(BigMath.log(BigDecimal(2), prec2), prec2)
500+
v.round(prec + BigDecimal.double_fig - (v.exponent < 0 ? v.exponent : 0), BigDecimal::ROUND_HALF_UP)
501+
end
502+
503+
# call-seq:
504+
# BigMath.log10(decimal, numeric) -> BigDecimal
505+
#
506+
# Computes the base 10 logarithm of +decimal+ to the specified number of
507+
# digits of precision, +numeric+.
508+
#
509+
# If +decimal+ is zero or negative, raises Math::DomainError.
510+
#
511+
# If +decimal+ is positive infinity, returns Infinity.
512+
#
513+
# If +decimal+ is NaN, returns NaN.
514+
#
515+
# BigMath.log10(BigDecimal('3'), 16).to_s
516+
# #=> "0.47712125471966243729502790325512e0"
517+
#
518+
def log10(x, prec)
519+
raise ArgumentError, "Zero or negative precision for log10" if prec <= 0
520+
return BigDecimal::NAN if x.nan?
521+
return BigDecimal::INFINITY if x.infinite? == 1
522+
523+
prec2 = prec + BigDecimal.double_fig * 3 / 2
524+
v = BigMath.log(x, prec2).div(BigMath.log(BigDecimal(10), prec2), prec2)
525+
v.round(prec + BigDecimal.double_fig - (v.exponent < 0 ? v.exponent : 0), BigDecimal::ROUND_HALF_UP)
526+
end
527+
476528
# call-seq:
477529
# PI(numeric) -> BigDecimal
478530
#

test/bigdecimal/test_bigmath.rb

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -309,4 +309,40 @@ def test_log
309309
end
310310
SRC
311311
end
312+
313+
def test_log2
314+
assert_raise(Math::DomainError) { log2(BigDecimal("0"), N) }
315+
assert_raise(Math::DomainError) { log2(BigDecimal("-1"), N) }
316+
assert_raise(Math::DomainError) { log2(MINF, N) }
317+
assert_equal(PINF, log2(PINF, N))
318+
assert_in_epsilon(BigDecimal("1.5849625007211561814537389439478165087598144076924810604557526545410982277943585625222804749180882420909806624750592"),
319+
log2(BigDecimal("3"), 100), BigDecimal("1e-100"))
320+
assert_relative_precision {|n| log2(BigDecimal("3"), n) }
321+
assert_relative_precision {|n| log2(BigDecimal("3e20"), n) }
322+
assert_relative_precision {|n| log2(BigDecimal("1e-20") + 1, n) }
323+
[BigDecimal::ROUND_UP, BigDecimal::ROUND_DOWN].each do |round_mode|
324+
BigDecimal.mode(BigDecimal::ROUND_MODE, round_mode)
325+
[0, 1, 2, 11, 123].each do |n|
326+
assert_equal(n, log2(BigDecimal(2**n), N))
327+
end
328+
end
329+
end
330+
331+
def test_log10
332+
assert_raise(Math::DomainError) { log10(BigDecimal("0"), N) }
333+
assert_raise(Math::DomainError) { log10(BigDecimal("-1"), N) }
334+
assert_raise(Math::DomainError) { log10(MINF, N) }
335+
assert_equal(PINF, log10(PINF, N))
336+
assert_in_epsilon(BigDecimal("0.4771212547196624372950279032551153092001288641906958648298656403052291527836611230429683556476163015104646927682520"),
337+
log10(BigDecimal("3"), 100), BigDecimal("1e-100"))
338+
assert_relative_precision {|n| log10(BigDecimal("3"), n) }
339+
assert_relative_precision {|n| log10(BigDecimal("3e20"), n) }
340+
assert_relative_precision {|n| log10(BigDecimal("1e-20") + 1, n) }
341+
[BigDecimal::ROUND_UP, BigDecimal::ROUND_DOWN].each do |round_mode|
342+
BigDecimal.mode(BigDecimal::ROUND_MODE, round_mode)
343+
[0, 1, 2, 11, 123].each do |n|
344+
assert_equal(n, log10(BigDecimal(10**n), N))
345+
end
346+
end
347+
end
312348
end

0 commit comments

Comments
 (0)