Skip to content

Commit f29ba89

Browse files
committed
Implement BigMath.log2 and BigMath.log10
1 parent e00dd39 commit f29ba89

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
#
@@ -489,6 +491,56 @@ def atanh(x, prec)
489491
(BigMath.log(x + 1, prec) - BigMath.log(1 - x, prec)).div(2, prec)
490492
end
491493

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

test/bigdecimal/test_bigmath.rb

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

0 commit comments

Comments
 (0)