@@ -563,13 +563,23 @@ def expm1(x, prec)
563563 if x < -1
564564 # log10(exp(x)) = x * log10(e)
565565 lg_e = 0.4342944819032518
566- exp_prec = prec + ( lg_e * x ) . ceil + 2
566+ exp_prec = prec + ( lg_e * x ) . ceil + BigDecimal . double_fig
567567 elsif x < 1
568- exp_prec = prec - x . exponent + 2
568+ exp_prec = prec - x . exponent + BigDecimal . double_fig
569569 else
570570 exp_prec = prec
571571 end
572- exp_prec > 0 ? exp ( x , exp_prec ) . sub ( 1 , prec ) : BigDecimal ( -1 )
572+
573+ return BigDecimal ( -1 ) if exp_prec <= 0
574+
575+ exp = exp ( x , exp_prec )
576+
577+ if exp . exponent > prec + BigDecimal . double_fig
578+ # Workaroudn for https://github.com/ruby/bigdecimal/issues/464
579+ exp
580+ else
581+ exp . sub ( 1 , prec )
582+ end
573583 end
574584
575585 # erf(decimal, numeric) -> BigDecimal
@@ -596,7 +606,12 @@ def erf(x, prec)
596606 log10_erfc = -xf ** 2 / Math . log ( 10 ) - Math . log10 ( xf * Math ::PI ** 0.5 )
597607 erfc_prec = [ prec + log10_erfc . ceil , 1 ] . max
598608 erfc = _erfc_asymptotic ( x , erfc_prec )
599- return BigDecimal ( 1 ) . sub ( erfc , prec ) if erfc
609+ if erfc
610+ # Workaround for https://github.com/ruby/bigdecimal/issues/464
611+ return BigDecimal ( 1 ) if erfc . exponent < -prec - BigDecimal . double_fig
612+
613+ return BigDecimal ( 1 ) . sub ( erfc , prec )
614+ end
600615 end
601616
602617 prec2 = prec + BigDecimal . double_fig
@@ -623,7 +638,7 @@ def erfc(x, prec)
623638 x = BigDecimal ::Internal . coerce_to_bigdecimal ( x , prec , :erfc )
624639 return BigDecimal ::Internal . nan_computation_result if x . nan?
625640 return BigDecimal ( 1 - x . infinite? ) if x . infinite?
626- return BigDecimal ( 1 ) . sub ( erf ( x , prec ) , prec ) if x < 0
641+ return BigDecimal ( 1 ) . sub ( erf ( x , prec + BigDecimal . double_fig ) , prec ) if x < 0
627642 return BigDecimal ( 0 ) if x > 5000000000 # erfc(5000000000) < 1e-10000000000000000000 (underflow)
628643
629644 if x >= 8
@@ -714,12 +729,12 @@ def gamma(x, prec)
714729 x = BigDecimal ::Internal . coerce_to_bigdecimal ( x , prec , :gamma )
715730 prec2 = prec + BigDecimal . double_fig
716731 if x < 0.5
717- raise Math ::DomainError 'Numerical argument is out of domain - gamma' if x . frac . zero?
732+ raise Math ::DomainError , 'Numerical argument is out of domain - gamma' if x . frac . zero?
718733
719734 # Euler's reflection formula: gamma(z) * gamma(1-z) = pi/sin(pi*z)
720735 pi = PI ( prec2 )
721736 sin = _sinpix ( x , pi , prec2 )
722- return pi . div ( gamma ( 1 - x , prec ) . mult ( sin , prec2 ) , prec )
737+ return pi . div ( gamma ( 1 - x , prec2 ) . mult ( sin , prec2 ) , prec )
723738 elsif x . frac . zero? && x < 1000 * prec
724739 return _gamma_positive_integer ( x , prec2 ) . mult ( 1 , prec )
725740 end
@@ -747,7 +762,7 @@ def lgamma(x, prec)
747762 # Euler's reflection formula: gamma(z) * gamma(1-z) = pi/sin(pi*z)
748763 pi = PI ( prec2 )
749764 sin = _sinpix ( x , pi , prec2 )
750- log_gamma = BigMath . log ( pi , prec2 ) . sub ( lgamma ( 1 - x , prec ) . first + BigMath . log ( sin . abs , prec2 ) , prec )
765+ log_gamma = BigMath . log ( pi , prec2 ) . sub ( lgamma ( 1 - x , prec2 ) . first + BigMath . log ( sin . abs , prec2 ) , prec )
751766 [ log_gamma , sin > 0 ? 1 : -1 ]
752767 elsif x . frac . zero? && x < 1000 * prec
753768 log_gamma = BigMath . log ( _gamma_positive_integer ( x , prec2 ) , prec )
0 commit comments