[ 
https://issues.apache.org/jira/browse/NUMBERS-182?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
 ]

Alex Herbert updated NUMBERS-182:
---------------------------------
    Description: 
LogBeta computes the log of the beta function using a log of a computation 
using the Gamma function when the arguments are small (a < 1). The code 
includes a comment that this is more accurate than using LogGamma:
{code:java}
// The original NSWC implementation was
//   LogGamma.value(a) + (LogGamma.value(b) - LogGamma.value(a + b));
// but the following command turned out to be more accurate.
return Math.log(Gamma.value(a) * Gamma.value(b) /
                Gamma.value(a + b)); {code}
However Gamma(z) -> 1/z when z -> 0. Thus this can overflow, e.g. this test 
fails:
{code:java}
@Test
void testTinyAB() {
    double a = 1.0e-155;
    double b = 1.5e-155;
    double beta = 2.5 / 1.5 * 1e155;
    Assertions.assertEquals(Math.log(beta), LogBeta.value(a, b));
} {code}
This can be fixed by checking for overflow and reverting to the original NSWC 
implementation:
{code:java}
final double beta = Gamma.value(a) * Gamma.value(b) / Gamma.value(a + b);
if (Double.isFinite(beta)) {
    return Math.log(beta);
}
return LogGamma.value(a) + (LogGamma.value(b) - LogGamma.value(a + b)); {code}

  was:
LogBeta computes the log of the beta function using a log of a computation 
using the Gamma function when the arguments are small (a < 1). The code 
includes a comment that this is more accurate than using LogGamma:
{code:java}
// The original NSWC implementation was
//   LogGamma.value(a) + (LogGamma.value(b) - LogGamma.value(a + b));
// but the following command turned out to be more accurate.
return Math.log(Gamma.value(a) * Gamma.value(b) /
                Gamma.value(a + b)); {code}
However Gamma(x) -> 1/x when x -> 0. Thus this can overflow, e.g. this test 
fails:
{code:java}
@Test
void testTinyAB() {
    double a = 1.0e-155;
    double b = 1.5e-155;
    double beta = 2.5 / 1.5 * 1e155;
    Assertions.assertEquals(Math.log(beta), LogBeta.value(a, b));
} {code}
This can be fixed by checking for overflow and reverting to the original NSWC 
implementation:
{code:java}
final double beta = Gamma.value(a) * Gamma.value(b) / Gamma.value(a + b);
if (Double.isFinite(beta)) {
    return Math.log(beta);
}
return LogGamma.value(a) + (LogGamma.value(b) - LogGamma.value(a + b)); {code}


> LogBeta overflows for tiny arguments
> ------------------------------------
>
>                 Key: NUMBERS-182
>                 URL: https://issues.apache.org/jira/browse/NUMBERS-182
>             Project: Commons Numbers
>          Issue Type: Bug
>          Components: gamma
>    Affects Versions: 1.0
>            Reporter: Alex Herbert
>            Priority: Trivial
>             Fix For: 1.1
>
>
> LogBeta computes the log of the beta function using a log of a computation 
> using the Gamma function when the arguments are small (a < 1). The code 
> includes a comment that this is more accurate than using LogGamma:
> {code:java}
> // The original NSWC implementation was
> //   LogGamma.value(a) + (LogGamma.value(b) - LogGamma.value(a + b));
> // but the following command turned out to be more accurate.
> return Math.log(Gamma.value(a) * Gamma.value(b) /
>                 Gamma.value(a + b)); {code}
> However Gamma(z) -> 1/z when z -> 0. Thus this can overflow, e.g. this test 
> fails:
> {code:java}
> @Test
> void testTinyAB() {
>     double a = 1.0e-155;
>     double b = 1.5e-155;
>     double beta = 2.5 / 1.5 * 1e155;
>     Assertions.assertEquals(Math.log(beta), LogBeta.value(a, b));
> } {code}
> This can be fixed by checking for overflow and reverting to the original NSWC 
> implementation:
> {code:java}
> final double beta = Gamma.value(a) * Gamma.value(b) / Gamma.value(a + b);
> if (Double.isFinite(beta)) {
>     return Math.log(beta);
> }
> return LogGamma.value(a) + (LogGamma.value(b) - LogGamma.value(a + b)); {code}



--
This message was sent by Atlassian Jira
(v8.20.1#820001)

Reply via email to