diff --git a/BREAKING-CHANGES.md b/BREAKING-CHANGES.md index 50801077f..5d01b9202 100644 --- a/BREAKING-CHANGES.md +++ b/BREAKING-CHANGES.md @@ -136,6 +136,22 @@ and the complex arcsine's real part moved two units away. A caller comparing a h result to a pinned string will see the last digits differ; a caller comparing to a tolerance will not. [#1338](https://github.com/asc-community/AngouriMath/issues/1338). +### A function of an inverse sine of `sqrt(1 + b x^2)` beside its derivative keeps the sign of x + +**A wrong answer, and answers where there were none.** `1/(asin(sqrt(1 + b x^2)) sqrt(1 + b x^2))` was +`sqrt(-b) ln(b asin(sqrt(1 + b x^2)))/b`, whose derivative is the integrand times the sign of x, so it was wrong for +every negative x. `asin(sqrt(1 + b x^2))^n/sqrt(1 + b x^2)` was declined, and so were the arccosine twins of both +(Rubi's 5.1.5 and 5.2.5). The ratio of the integrand to the inverse's derivative, `sqrt(-b x^2)/(b x)`, is constant +on each side of 0 and changes sign across it. It is now compared on each side with that side's value, where it was +compared everywhere with its value at one positive point +([#718](https://github.com/asc-community/AngouriMath/issues/718)). + +| Input | Was (2.5.0) | Now | +|---|---|---| +| `"1/(asin(sqrt(1+b*x^2))*sqrt(1+b*x^2))".ToEntity().Integrate("x")` | `sqrt(-b) * ln(b * arcsin(sqrt(1 + b * x ^ 2))) / b + C`, wrong for x < 0 | 120 characters, `sqrt(1 - (1 + b x^2))/(b x) ln(arcsin(sqrt(1 + b x^2)))` | +| `"asin(sqrt(1+b*x^2))^n/sqrt(1+b*x^2)".ToEntity().Integrate("x")` | `integral(...)` | 136 characters | +| `"acos(sqrt(1+b*x^2))^n/sqrt(1+b*x^2)".ToEntity().Integrate("x")` | `integral(...)` | 137 characters | + ### A rational evaluated at a higher precision than before has all of its digits **More digits where there were a hundred.** A rational kept its decimal value in the precision current when it was diff --git a/Sources/AngouriMath/Functions/Continuous/Integration/IndefiniteIntegralSolver.cs b/Sources/AngouriMath/Functions/Continuous/Integration/IndefiniteIntegralSolver.cs index d45ced639..079a84bee 100644 --- a/Sources/AngouriMath/Functions/Continuous/Integration/IndefiniteIntegralSolver.cs +++ b/Sources/AngouriMath/Functions/Continuous/Integration/IndefiniteIntegralSolver.cs @@ -29349,8 +29349,12 @@ static bool Through(Entity node, Entity.Variable x) // pinned: asking Simplify whether the derivative of the factor vanished took four seconds // on `sqrt(-a e^2/b - e^2 x^2)/(e sqrt(a + b x^2))`, and its square stayed a power of a // quotient of roots. A point it cannot tell at counts against it; the answer is checked too. + // Or on each side of 0 alone: `sqrt(-b x^2)/(b x)`, which `asin(sqrt(1 + b x^2))` beside + // `1/sqrt(1 + b x^2)` leaves, is constant where x keeps its sign and changes with it. bool HoldsItsValue(Entity factor) - => Functions.PartialFractions.HoldsAtSampledPoints(factor, factor.Substitute(x, Number.Rational.Create(3, 10)), x); + => Functions.PartialFractions.HoldsAtSampledPoints(factor, factor.Substitute(x, Number.Rational.Create(3, 10)), x) + || Functions.PartialFractions.HoldsAtSampledPoints(factor, factor.Substitute(x, Number.Rational.Create(3, 10)), x, new[] { "0.29", "1.43", "3.17" }) + && Functions.PartialFractions.HoldsAtSampledPoints(factor, factor.Substitute(x, Number.Rational.Create(-3, 10)), x, new[] { "-0.61", "-1.37", "-2.9" }); } /// diff --git a/Sources/Tests/UnitTests/Calculus/AFunctionOfAnInverseTimesItsDerivativeIntegralTest.cs b/Sources/Tests/UnitTests/Calculus/AFunctionOfAnInverseTimesItsDerivativeIntegralTest.cs index f8d13aba7..a00081bdb 100644 --- a/Sources/Tests/UnitTests/Calculus/AFunctionOfAnInverseTimesItsDerivativeIntegralTest.cs +++ b/Sources/Tests/UnitTests/Calculus/AFunctionOfAnInverseTimesItsDerivativeIntegralTest.cs @@ -57,5 +57,15 @@ public void IsAnsweredAndDifferentiatesBack(string integrand) DifferentiatesBack(integrand, ("a", 9), ("b", -1.25), ("c", 0.7), ("d", 1.4), ("k", 0.75), ("m", 2.5)); DifferentiatesBack(integrand, ("a", 7), ("b", -2), ("c", -0.5), ("d", 0.6), ("k", -0.3), ("m", 1.0 / 3)); } + + // A factor constant on each side of 0 and not across it: sqrt(-b x^2)/(b x). + [Theory] + [InlineData("asin(sqrt(1+b*x^2))^m/sqrt(1+b*x^2)")] + [InlineData("1/(acos(sqrt(1+b*x^2))*sqrt(1+b*x^2))")] + public void AFactorConstantOnEachSideOfZero(string integrand) + { + DifferentiatesBack(integrand, ("b", -0.1), ("m", 2.5)); + DifferentiatesBack(integrand, ("b", -0.15), ("m", 1.0 / 3)); + } } }