Skip to content

Commit 4385bbd

Browse files
committed
Implement BigMath.log2 and BigMath.log10
1 parent 90b6c04 commit 4385bbd

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
#
@@ -500,6 +502,56 @@ def atanh(x, prec)
500502
(BigMath.log(x + 1, prec) - BigMath.log(1 - x, prec)).div(2, prec)
501503
end
502504

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

test/bigdecimal/test_bigmath.rb

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

0 commit comments

Comments
 (0)