📄 logmath.java
字号:
* the equality above, generalized for the case of any log base. This * function is contructed as a table lookup. * * @param index * the index into the addTable * * @return the value pointed to by index * * @throws IllegalArgumentException */ private final float addTable(float index) throws IllegalArgumentException { if (useAddTable) { // int intIndex = (int) Math.rint(index); int intIndex = (int) (index + 0.5); // When adding two numbers, the highest one should be // preserved, and therefore the difference should always // be positive. if (0 <= intIndex) { if (intIndex < theAddTable.length) { return theAddTable[intIndex]; } else { return 0.0f; } } else { throw new IllegalArgumentException("addTable index has " + "to be negative"); } } else { return addTableActualComputation(index); } } /** * Returns the difference between two numbers when the arguments and the * result are in log. * * <p> * That is, it returns log(a - b) given log(a) and log(b) * </p> * * <p> * Implementation is less efficient than add(), since we're less likely to * use this function, provided for completeness. Notice however that the * result only makes sense if the minuend is higher than the subtrahend. * Otherwise, we should return the log of a negative number. * </p> * * <p> * It implements the subtraction as: * </p> * * <p> * <b>log(a - b) = log(a) + log(1 - exp(log(b) - log(a))) </b> * </p> * * <p> * No need to check for underflow/overflow. * </p> * * @param logMinuend * value in log domain (i.e. log(minuend)) to be subtracted * from * @param logSubtrahend * value in log domain (i.e. log(subtrahend)) that is being * subtracted * * @return difference between minuend and the subtrahend in the log domain * * @throws IllegalArgumentException * * <p> * This is a very slow way to do this, but this method should rarely be * used. * </p> */ public final float subtractAsLinear(float logMinuend, float logSubtrahend) throws IllegalArgumentException { double logInnerSummation; if (logMinuend < logSubtrahend) { throw new IllegalArgumentException("Subtraction results in log " + "of a negative number: " + logMinuend + " - " + logSubtrahend); } logInnerSummation = 1.0; logInnerSummation -= logToLinear(logSubtrahend - logMinuend); return logMinuend + linearToLog(logInnerSummation); } /** * Converts the source, which is assumed to be a log value whose base is * sourceBase, to a log value whose base is resultBase. Possible values for * both the source and result bases include Math.E, 10.0, * LogMath.getLogBase(). If a source or result base is not supported, an * IllegalArgumentException will be thrown. * * <p> * It takes advantage of the relation: * </p> * * <p> * <b>log_a(b) = log_c(b) / lob_c(a) </b> * </p> * * <p> * or: * </p> * * <p> * <b>log_a(b) = log_c(b) * lob_a(c) </b> * </p> * * <p> * where <b>log_a(b) </b> is logarithm of <b>b </b> base <b>a </b> etc. * </p> * * @param logSource * log value whose base is sourceBase * @param sourceBase * the base of the log the source * @param resultBase * the base to convert the source log to * * @throws IllegalArgumentException */ // [[[ TODO: This is slow, but it probably doesn't need // to be too fast ]]] // [ EBG: it can be made more efficient if one of the bases is // Math.E. So maybe we should consider two functions logToLn and // lnToLog instead of a generic function like this?? // public static float logToLog(float logSource, float sourceBase, float resultBase) throws IllegalArgumentException { if ((sourceBase <= 0) || (resultBase <= 0)) { throw new IllegalArgumentException("Trying to take log of " + " non-positive number: " + sourceBase + " or " + resultBase); } if (logSource == logZero) { return logZero; } float lnSourceBase = (float) Math.log(sourceBase); float lnResultBase = (float) Math.log(resultBase); return (logSource * lnSourceBase / lnResultBase); } /** * Converts the source, which is a number in base Math.E, to a log value * which base is the LogBase of this LogMath. * * @param logSource * the number in base Math.E to convert */ public final float lnToLog(float logSource) { if (logSource == logZero) { return logZero; } return (logSource * inverseNaturalLogBase); } /** * Converts the source, which is a number in base 10, to a log value which * base is the LogBase of this LogMath. * * @param logSource * the number in base Math.E to convert */ public final float log10ToLog(float logSource) { if (logSource == logZero) { return logZero; } return logToLog(logSource, 10.0f, logBase); } /** * Converts the source, whose base is the LogBase of this LogMath, to a log * value which is a number in base Math.E. * * @param logSource * the number to convert to base Math.E */ public final float logToLn(float logSource) { if (logSource == logZero) { return logZero; } return logSource * naturalLogBase; } /** * Converts the value from linear scale to log scale. The log scale numbers * are limited by the range of the type float. The linear scale numbers can * be any double value. * * @param linearValue * the value to be converted to log scale * * @return the value in log scale * * @throws IllegalArgumentException * */ public final float linearToLog(double linearValue) throws IllegalArgumentException { double returnValue; if (linearValue < 0.0) { throw new IllegalArgumentException( "linearToLog: param must be >= 0: " + linearValue); } else if (linearValue == 0.0) { // [EBG] Shouldn't the comparison above be something like // linearValue < "epsilon"? Is it ever going to be 0.0? return getLogZero(); } else { returnValue = Math.log(linearValue) * inverseNaturalLogBase; if (returnValue > Float.MAX_VALUE) { return Float.MAX_VALUE; } else { if (returnValue < -Float.MAX_VALUE) { return -Float.MAX_VALUE; } else { return (float) returnValue; } } } } /** * Converts the value from log scale to linear scale. * * @param logValue * the value to be converted to the linear scale * * @return the value in the linear scale */ public final double logToLinear(float logValue) { // return Math.pow(logBase, logValue); double returnValue; if (logValue < minLogValue) { returnValue = 0.0; } else if (logValue > maxLogValue) { returnValue = Double.MAX_VALUE; } else { returnValue = Math.exp(logToLn(logValue)); } return returnValue; } /** * Returns the zero value in the log domain * * @return zero value in the log domain */ public final static float getLogZero() { return logZero; } /** * Returns the one value in the log domain * * @return one value in the log domain */ public final static float getLogOne() { return logOne; } /** * Returns the actual log base. */ public final float getLogBase() { return logBase; } /** * Returns the log (base 10) of value * * @param value * the value to take the log of * * @return the log (base 10) of value */ // [ EBG: Shouldn't we be using something like logToLog(value, base, 10) // for this? ] public static float log10(float value) { return (float) (0.4342944819 * java.lang.Math.log(value)); // If you want to get rid of the constant: // return ((1.0f / Math.log(10.0f)) * Math.log(value)); }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -