Skip to content

Commit fc36408

Browse files
committed
Implement BigMath.log2 and BigMath.log10
1 parent 11d0084 commit fc36408

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
#
@@ -470,6 +472,56 @@ def atanh(x, prec)
470472
(BigMath.log(x + 1, prec) - BigMath.log(1 - x, prec)).div(2, prec)
471473
end
472474

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

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)