如何用Apache Commons Math实现分式函数f(x)=(5x-2)/(1-3x)?
处理有理函数(分式多项式)的实现方案
要实现像$f(x) = \frac{5x - 2}{1 - 3x}$这样的分式函数,Apache Commons Math3已经提供了专门的类,无需从零实现:
1. 选用RationalFunction类
org.apache.commons.math3.analysis.polynomials.RationalFunction专门用于表示两个多项式的商(即有理函数),它和PolynomialFunction一样实现了UnivariateFunction接口,完全适配你现有的数值求导逻辑。
2. 改造求导类提升通用性
把Derivee方法的参数类型从PolynomialFunction改为通用的UnivariateFunction,这样既能兼容原有的多项式,也能支持有理函数,扩展性更强:
import org.apache.commons.math3.analysis.UnivariateFunction; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.Objects; public class Derivee { private static final Logger LOGGER = LoggerFactory.getLogger(Derivee.class); /** * Obtenir un nombre dérivé. * @param f Fonction. * @param x Valeur x0 où l'on veut le nombre dérivé. * @param h écart pour calculer la limite. * @return Nombre dérivé. * @throws IllegalArgumentException si h vaut zéro. */ public double getNombreDerive(UnivariateFunction f, double x, double h) { Objects.requireNonNull(f, "La fonction ne peut pas valoir null"); if (h == 0) { throw new IllegalArgumentException("L'écart pour calculer le nombre dérivé ne peut pas valoir zéro."); } double nombreDerive = (f.value(x + h) - f.value(x)) / h; if (LOGGER.isDebugEnabled()) { LOGGER.debug("Le nombre dérivé en {} est {} pour f(x) = {}, mesuré avec h = {}.", x, nombreDerive, f, h); } return nombreDerive; } }
3. 编写有理函数的测试用例
针对目标分式函数$\frac{5x - 2}{1 - 3x}$,分别构造分子、分母的多项式,再创建RationalFunction实例完成测试:
import org.apache.commons.math3.analysis.polynomials.PolynomialFunction; import org.apache.commons.math3.analysis.polynomials.RationalFunction; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.*; class DeriveeTest { @Test @DisplayName("nombres dérivés - polynôme") void nombresDerivesPolynome() { PolynomialFunction f = new PolynomialFunction(new double[] {-2.0, 5.0}); Derivee derivee = new Derivee(); assertEquals(5.0, derivee.getNombreDerive(f, 3.0, 0.5), 0.01, "Le nombre dérivé du polynôme n'est pas celui attendu"); assertThrows(IllegalArgumentException.class, () -> derivee.getNombreDerive(f, 3.0, 0), "Un h = 0 a été accepté : il aurait dû être refusé"); } @Test @DisplayName("nombres dérivés - fonction rationnelle") void nombresDerivesRationnelle() { // 分子多项式:5x - 2 → 系数数组为[-2.0, 5.0] PolynomialFunction numerator = new PolynomialFunction(new double[] {-2.0, 5.0}); // 分母多项式:1 - 3x → 系数数组为[1.0, -3.0] PolynomialFunction denominator = new PolynomialFunction(new double[] {1.0, -3.0}); // 创建有理函数实例 RationalFunction f = new RationalFunction(numerator, denominator); Derivee derivee = new Derivee(); // 理论导数计算:f'(x) = -1/(1-3x)²,x=0时结果为-1.0 double expectedDerivative = -1.0; assertEquals(expectedDerivative, derivee.getNombreDerive(f, 0.0, 0.001), 0.01, "Le nombre dérivé de la fonction rationnelle n'est pas celui attendu"); // 测试分母为0的点(x=1/3≈0.333),此时函数无定义,会抛出异常 assertThrows(ArithmeticException.class, () -> derivee.getNombreDerive(f, 1.0/3, 0.001), "Le point où le dénominateur est nul n'a pas déclenché d'exception"); } }
4. 运行效果说明
测试运行后会输出类似日志:
08:15:30.123 [main] DEBUG fr.ecoemploi.domain.utils.math.derivees.Derivee - Le nombre dérivé en 0.0 est -0.999000999000999 pour f(x) = (-2 + 5 x)/(1 - 3 x), mesuré avec h = 0.001.
由于采用的是数值向前差分法,结果与理论值会有微小误差,缩小h的取值(比如改为0.0001)可以降低误差。
内容的提问来源于stack exchange,提问作者Marc Le Bihan
相关产品推荐
相关产品推荐

