@@ -230,7 +230,10 @@ T ibeta_power_terms(T a,
230230 T agh = static_cast <T>(a + Lanczos::g () - 0 .5f );
231231 T bgh = static_cast <T>(b + Lanczos::g () - 0 .5f );
232232 T cgh = static_cast <T>(c + Lanczos::g () - 0 .5f );
233- result = Lanczos::lanczos_sum_expG_scaled (c) / (Lanczos::lanczos_sum_expG_scaled (a) * Lanczos::lanczos_sum_expG_scaled (b));
233+ if ((a < tools::min_value<T>()) || (b < tools::min_value<T>()))
234+ result = 0 ; // denominator overflows in this case
235+ else
236+ result = Lanczos::lanczos_sum_expG_scaled (c) / (Lanczos::lanczos_sum_expG_scaled (a) * Lanczos::lanczos_sum_expG_scaled (b));
234237 result *= prefix;
235238 // combine with the leftover terms from the Lanczos approximation:
236239 result *= sqrt (bgh / boost::math::constants::e<T>());
@@ -389,14 +392,15 @@ T ibeta_power_terms(T a,
389392 }
390393 else
391394 {
392- T p1 = pow (b1, a / b);
395+ // This protects against spurious overflow in a/b:
396+ T p1 = (b1 < 1 ) && (b < 1 ) && (tools::max_value<T>() * b < a) ? static_cast <T>(0 ) : static_cast <T>(pow (b1, a / b));
393397 T l3 = (p1 != 0 ) && (b2 != 0 ) ? (log (p1) + log (b2)) * b : tools::max_value<T>(); // arbitrary large value if the logs would fail!
394398 if ((l3 < tools::log_max_value<T>())
395399 && (l3 > tools::log_min_value<T>()))
396400 {
397401 result *= pow (p1 * b2, b);
398402 }
399- else
403+ else if (result != 0 ) // we can elude the calculation below if we're already going to be zero
400404 {
401405 l2 += l1 + log (result);
402406 if (l2 >= tools::log_max_value<T>())
@@ -656,7 +660,10 @@ T ibeta_series(T a, T b, T x, T s0, const Lanczos&, bool normalised, T* p_deriva
656660 T agh = static_cast <T>(a + Lanczos::g () - 0 .5f );
657661 T bgh = static_cast <T>(b + Lanczos::g () - 0 .5f );
658662 T cgh = static_cast <T>(c + Lanczos::g () - 0 .5f );
659- result = Lanczos::lanczos_sum_expG_scaled (c) / (Lanczos::lanczos_sum_expG_scaled (a) * Lanczos::lanczos_sum_expG_scaled (b));
663+ if ((a < tools::min_value<T>()) || (b < tools::min_value<T>()))
664+ result = 0 ; // denorms cause overflow in the Lanzos series, result will be zero anyway
665+ else
666+ result = Lanczos::lanczos_sum_expG_scaled (c) / (Lanczos::lanczos_sum_expG_scaled (a) * Lanczos::lanczos_sum_expG_scaled (b));
660667
661668 if (!(boost::math::isfinite)(result))
662669 result = 0 ;
@@ -689,10 +696,13 @@ T ibeta_series(T a, T b, T x, T s0, const Lanczos&, bool normalised, T* p_deriva
689696 //
690697 // Oh dear, we need logs, and this *will* cancel:
691698 //
692- result = log (result) + l1 + l2 + (log (agh) - 1 ) / 2 ;
693- if (p_derivative)
694- *p_derivative = exp (result + b * log (y));
695- result = exp (result);
699+ if (result != 0 ) // elude calculation when result will be zero.
700+ {
701+ result = log (result) + l1 + l2 + (log (agh) - 1 ) / 2 ;
702+ if (p_derivative)
703+ *p_derivative = exp (result + b * log (y));
704+ result = exp (result);
705+ }
696706 }
697707 }
698708 else
0 commit comments