Submitted by leonardr (Mon Oct 24 15:33:41 UTC 2005)
From the identity log(x*y) == log(x) + log(y) it follows that log(x*10^y) == log(x) + log(10^y). It also follows that log(10^y) == log(10) * y. Therefore, log(x*10^y) == log(x) + (log(10) * y).
This means the log of an arbitrarily large scientific-notation number can be calculated by taking the log of the fraction and the log of the power, both of which are very small by BigDecimal standards. Since BigDecimal addition and multiplication don't lose precision, the result is as precise as taking the log of the number without decomposing it.
A simple reimplementation of BigDecimal#log will use the existing implementation for small numbers, and decompose large numbers into their component parts.
require 'bigdecimal' require 'bigdecimal/math' require 'bigdecimal/util' module BigMath alias :_log :log def log(x, prec) raise ArgumentError, "Zero or negative argument for log" if x <= 0 || prec <= 0 return _log(x, prec) if x <= 10 return x if x.infinite? || x.nan? sign, fraction, power, exponent = x.split fraction = BigDecimal(".#{fraction}") power = power.to_s.to_d _log(fraction, prec) + (_log(power, prec) * exponent) end end
Comments | Current voting | ||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|
|
RCRchive copyright © David Alan Black, 2003-2005.
Powered by .
I agree with this change, but RCRs are more for changes in how Ruby itself works, rather than changes to how a method or two works. It would be better suited to posting on the ruby-core mailing list so that someone can patch it in.