CalculusFieldElement.java
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
* This is not the original file distributed by the Apache Software Foundation
* It has been modified by the Hipparchus project
*/
package org.hipparchus;
import org.hipparchus.exception.MathIllegalArgumentException;
import org.hipparchus.util.FastMath;
import org.hipparchus.util.FieldSinCos;
import org.hipparchus.util.FieldSinhCosh;
import org.hipparchus.util.MathArrays;
/**
* Interface representing a <a href="http://mathworld.wolfram.com/Field.html">field</a>
* with calculus capabilities (sin, cos, ...).
* @param <T> the type of the field elements
* @see FieldElement
* @since 1.7
*/
public interface CalculusFieldElement<T extends FieldElement<T>> extends FieldElement<T> {
/** Get the Archimedes constant π.
* <p>
* Archimedes constant is the ratio of a circle's circumference to its diameter.
* </p>
* @return Archimedes constant π
* @since 2.0
*/
default T getPi() {
return newInstance(FastMath.PI);
}
/** Create an instance corresponding to a constant real value.
* @param value constant real value
* @return instance corresponding to a constant real value
*/
T newInstance(double value);
/** '+' operator.
* @param a right hand side parameter of the operator
* @return this+a
*/
default T add(double a) {
return add(newInstance(a));
}
/** '-' operator.
* @param a right hand side parameter of the operator
* @return this-a
*/
default T subtract(double a) {
return subtract(newInstance(a));
}
/** {@inheritDoc} */
@Override
default T subtract(T a) {
return add(a.negate());
}
/** '×' operator.
* @param a right hand side parameter of the operator
* @return this×a
*/
default T multiply(double a) {
return multiply(newInstance(a));
}
/** {@inheritDoc} */
@Override
default T multiply(int n) {
return multiply((double) n);
}
/** '÷' operator.
* @param a right hand side parameter of the operator
* @return this÷a
*/
default T divide(double a) {
return divide(newInstance(a));
}
/**
* Return the exponent of the instance, removing the bias.
* <p>
* For double numbers of the form 2<sup>x</sup>, the unbiased
* exponent is exactly x.
* </p>
* @return exponent for the instance, without bias
*/
default int getExponent() {
return FastMath.getExponent(getReal());
}
/**
* Multiply the instance by a power of 2.
* @param n power of 2
* @return this × 2<sup>n</sup>
*/
T scalb(int n);
/**
* Compute least significant bit (Unit in Last Position) for a number.
* @return ulp(this)
* @since 2.0
*/
default T ulp() {
return newInstance(FastMath.ulp(getReal()));
}
/**
* Returns the hypotenuse of a triangle with sides {@code this} and {@code y}
* - sqrt(<i>this</i><sup>2</sup> +<i>y</i><sup>2</sup>)
* avoiding intermediate overflow or underflow.
*
* <ul>
* <li> If either argument is infinite, then the result is positive infinity.</li>
* <li> else, if either argument is NaN then the result is NaN.</li>
* </ul>
*
* @param y a value
* @return sqrt(<i>this</i><sup>2</sup> +<i>y</i><sup>2</sup>)
* @exception MathIllegalArgumentException if number of free parameters or orders are inconsistent
*/
T hypot(T y)
throws MathIllegalArgumentException;
/** {@inheritDoc} */
@Override
default T divide(T a) {
return multiply(a.reciprocal());
}
/** Square root.
* @return square root of the instance
*/
default T sqrt() {
return rootN(2);
}
/** Cubic root.
* @return cubic root of the instance
*/
default T cbrt() {
return rootN(3);
}
/** N<sup>th</sup> root.
* @param n order of the root
* @return n<sup>th</sup> root of the instance
*/
default T rootN(int n) {
return pow(1. / n);
}
/** Compute this × this.
* @return a new element representing this × this
* @since 3.1
*/
default T square() {
return pow(2);
}
/** Power operation.
* @param p power to apply
* @return this<sup>p</sup>
*/
default T pow(double p) {
return pow(newInstance(p));
}
/** Integer power operation.
* @param n power to apply
* @return this<sup>n</sup>
*/
default T pow(int n) {
return pow((double) n);
}
/** Power operation.
* @param e exponent
* @return this<sup>e</sup>
* @exception MathIllegalArgumentException if number of free parameters or orders are inconsistent
*/
T pow(T e)
throws MathIllegalArgumentException;
/** Exponential.
* @return exponential of the instance
*/
T exp();
/** Exponential minus 1.
* @return exponential minus one of the instance
*/
T expm1();
/** Natural logarithm.
* @return logarithm of the instance
*/
T log();
/** Shifted natural logarithm.
* @return logarithm of one plus the instance
*/
T log1p();
/** Base 10 logarithm.
* @return base 10 logarithm of the instance
*/
T log10();
/** Cosine operation.
* @return cos(this)
*/
T cos();
/** Sine operation.
* @return sin(this)
*/
T sin();
/** Combined Sine and Cosine operation.
* @return [sin(this), cos(this)]
* @since 1.4
*/
default FieldSinCos<T> sinCos() {
return new FieldSinCos<>(sin(), cos());
}
/** Tangent operation.
* @return tan(this)
*/
default T tan() {
return sin().divide(cos());
}
/** Arc cosine operation.
* @return acos(this)
*/
T acos();
/** Arc sine operation.
* @return asin(this)
*/
T asin();
/** Arc tangent operation.
* @return atan(this)
*/
T atan();
/** Two arguments arc tangent operation.
* <p>
* Beware of the order or arguments! As this is based on a
* two-arguments functions, in order to be consistent with
* arguments order, the instance is the <em>first</em> argument
* and the single provided argument is the <em>second</em> argument.
* In order to be consistent with programming languages {@code atan2},
* this method computes {@code atan2(this, x)}, i.e. the instance
* represents the {@code y} argument and the {@code x} argument is
* the one passed as a single argument. This may seem confusing especially
* for users of Wolfram alpha, as this site is <em>not</em> consistent
* with programming languages {@code atan2} two-arguments arc tangent
* and puts {@code x} as its first argument.
* </p>
* @param x second argument of the arc tangent
* @return atan2(this, x)
* @exception MathIllegalArgumentException if number of free parameters or orders are inconsistent
*/
T atan2(T x)
throws MathIllegalArgumentException;
/** Hyperbolic cosine operation.
* @return cosh(this)
*/
T cosh();
/** Hyperbolic sine operation.
* @return sinh(this)
*/
T sinh();
/** Combined hyperbolic sine and cosine operation.
* @return [sinh(this), cosh(this)]
* @since 2.0
*/
default FieldSinhCosh<T> sinhCosh() {
return new FieldSinhCosh<>(sinh(), cosh());
}
/** Hyperbolic tangent operation.
* @return tanh(this)
*/
default T tanh() {
return sinh().divide(cosh());
}
/** Inverse hyperbolic cosine operation.
* @return acosh(this)
*/
T acosh();
/** Inverse hyperbolic sine operation.
* @return asin(this)
*/
T asinh();
/** Inverse hyperbolic tangent operation.
* @return atanh(this)
*/
T atanh();
/** Convert radians to degrees, with error of less than 0.5 ULP
* @return instance converted into degrees
*/
default T toDegrees() {
return multiply(FastMath.toDegrees(1.));
}
/** Convert degrees to radians, with error of less than 0.5 ULP
* @return instance converted into radians
*/
default T toRadians() {
return multiply(FastMath.toRadians(1.));
}
/**
* Compute a linear combination.
* @param a Factors.
* @param b Factors.
* @return <code>Σ<sub>i</sub> a<sub>i</sub> b<sub>i</sub></code>.
* @throws MathIllegalArgumentException if arrays dimensions don't match
*/
T linearCombination(T[] a, T[] b)
throws MathIllegalArgumentException;
/**
* Compute a linear combination.
* @param a Factors.
* @param b Factors.
* @return <code>Σ<sub>i</sub> a<sub>i</sub> b<sub>i</sub></code>.
* @throws MathIllegalArgumentException if arrays dimensions don't match
*/
default T linearCombination(double[] a, T[] b) throws MathIllegalArgumentException {
final T[] newInstances = MathArrays.buildArray(getField(), a.length);
for (int i = 0; i < a.length; i++) {
newInstances[i] = newInstance(a[i]);
}
return linearCombination(newInstances, b);
}
/**
* Compute a linear combination.
* @param a1 first factor of the first term
* @param b1 second factor of the first term
* @param a2 first factor of the second term
* @param b2 second factor of the second term
* @return a<sub>1</sub>×b<sub>1</sub> +
* a<sub>2</sub>×b<sub>2</sub>
* @see #linearCombination(FieldElement, FieldElement, FieldElement, FieldElement, FieldElement, FieldElement)
* @see #linearCombination(FieldElement, FieldElement, FieldElement, FieldElement, FieldElement, FieldElement, FieldElement, FieldElement)
*/
T linearCombination(T a1, T b1, T a2, T b2);
/**
* Compute a linear combination.
* @param a1 first factor of the first term
* @param b1 second factor of the first term
* @param a2 first factor of the second term
* @param b2 second factor of the second term
* @return a<sub>1</sub>×b<sub>1</sub> +
* a<sub>2</sub>×b<sub>2</sub>
* @see #linearCombination(double, FieldElement, double, FieldElement, double, FieldElement)
* @see #linearCombination(double, FieldElement, double, FieldElement, double, FieldElement, double, FieldElement)
*/
default T linearCombination(double a1, T b1, double a2, T b2) {
return linearCombination(newInstance(a1), b1, newInstance(a2), b2);
}
/**
* Compute a linear combination.
* @param a1 first factor of the first term
* @param b1 second factor of the first term
* @param a2 first factor of the second term
* @param b2 second factor of the second term
* @param a3 first factor of the third term
* @param b3 second factor of the third term
* @return a<sub>1</sub>×b<sub>1</sub> +
* a<sub>2</sub>×b<sub>2</sub> + a<sub>3</sub>×b<sub>3</sub>
* @see #linearCombination(FieldElement, FieldElement, FieldElement, FieldElement)
* @see #linearCombination(FieldElement, FieldElement, FieldElement, FieldElement, FieldElement, FieldElement, FieldElement, FieldElement)
*/
T linearCombination(T a1, T b1, T a2, T b2, T a3, T b3);
/**
* Compute a linear combination.
* @param a1 first factor of the first term
* @param b1 second factor of the first term
* @param a2 first factor of the second term
* @param b2 second factor of the second term
* @param a3 first factor of the third term
* @param b3 second factor of the third term
* @return a<sub>1</sub>×b<sub>1</sub> +
* a<sub>2</sub>×b<sub>2</sub> + a<sub>3</sub>×b<sub>3</sub>
* @see #linearCombination(double, FieldElement, double, FieldElement)
* @see #linearCombination(double, FieldElement, double, FieldElement, double, FieldElement, double, FieldElement)
*/
default T linearCombination(double a1, T b1, double a2, T b2, double a3, T b3) {
return linearCombination(newInstance(a1), b1, newInstance(a2), b2, newInstance(a3), b3);
}
/**
* Compute a linear combination.
* @param a1 first factor of the first term
* @param b1 second factor of the first term
* @param a2 first factor of the second term
* @param b2 second factor of the second term
* @param a3 first factor of the third term
* @param b3 second factor of the third term
* @param a4 first factor of the fourth term
* @param b4 second factor of the fourth term
* @return a<sub>1</sub>×b<sub>1</sub> +
* a<sub>2</sub>×b<sub>2</sub> + a<sub>3</sub>×b<sub>3</sub> +
* a<sub>4</sub>×b<sub>4</sub>
* @see #linearCombination(FieldElement, FieldElement, FieldElement, FieldElement)
* @see #linearCombination(FieldElement, FieldElement, FieldElement, FieldElement, FieldElement, FieldElement)
*/
T linearCombination(T a1, T b1, T a2, T b2, T a3, T b3, T a4, T b4);
/**
* Compute a linear combination.
* @param a1 first factor of the first term
* @param b1 second factor of the first term
* @param a2 first factor of the second term
* @param b2 second factor of the second term
* @param a3 first factor of the third term
* @param b3 second factor of the third term
* @param a4 first factor of the fourth term
* @param b4 second factor of the fourth term
* @return a<sub>1</sub>×b<sub>1</sub> +
* a<sub>2</sub>×b<sub>2</sub> + a<sub>3</sub>×b<sub>3</sub> +
* a<sub>4</sub>×b<sub>4</sub>
* @see #linearCombination(double, FieldElement, double, FieldElement)
* @see #linearCombination(double, FieldElement, double, FieldElement, double, FieldElement)
*/
default T linearCombination(double a1, T b1, double a2, T b2, double a3, T b3, double a4, T b4) {
return linearCombination(newInstance(a1), b1, newInstance(a2), b2, newInstance(a3), b3,
newInstance(a4), b4);
}
/** Get the smallest whole number larger than instance.
* @return ceil(this)
*/
default T ceil() {
return newInstance(FastMath.ceil(getReal()));
}
/** Get the largest whole number smaller than instance.
* @return floor(this)
*/
default T floor() {
return newInstance(FastMath.floor(getReal()));
}
/** Get the whole number that is the nearest to the instance, or the even one if x is exactly half way between two integers.
* @return a double number r such that r is an integer r - 0.5 ≤ this ≤ r + 0.5
*/
default T rint() {
return newInstance(FastMath.rint(getReal()));
}
/** IEEE remainder operator.
* @param a right hand side parameter of the operator
* @return this - n × a where n is the closest integer to this/a
*/
T remainder(double a);
/** IEEE remainder operator.
* @param a right hand side parameter of the operator
* @return this - n × a where n is the closest integer to this/a
*/
T remainder(T a);
/** Compute the sign of the instance.
* The sign is -1 for negative numbers, +1 for positive numbers and 0 otherwise,
* for Complex number, it is extended on the unit circle (equivalent to z/|z|,
* with special handling for 0 and NaN)
* @return -1.0, -0.0, +0.0, +1.0 or NaN depending on sign of a
*/
default T sign() {
return newInstance(FastMath.signum(getReal()));
}
/**
* Returns the instance with the sign of the argument.
* A NaN {@code sign} argument is treated as positive.
*
* @param sign the sign for the returned value
* @return the instance with the same sign as the {@code sign} argument
*/
T copySign(T sign);
/**
* Returns the instance with the sign of the argument.
* A NaN {@code sign} argument is treated as positive.
*
* @param sign the sign for the returned value
* @return the instance with the same sign as the {@code sign} argument
*/
default T copySign(double sign) {
return copySign(newInstance(sign));
}
/**
* Check if the instance is infinite.
* @return true if the instance is infinite
*/
default boolean isInfinite() {
return Double.isInfinite(getReal());
}
/**
* Check if the instance is finite (neither infinite nor NaN).
* @return true if the instance is finite (neither infinite nor NaN)
* @since 2.0
*/
default boolean isFinite() {
return Double.isFinite(getReal());
}
/**
* Check if the instance is Not a Number.
* @return true if the instance is Not a Number
*/
default boolean isNaN() {
return Double.isNaN(getReal());
}
/** norm.
* @return norm(this)
* @since 2.0
*/
default double norm() {
return abs().getReal();
}
/** absolute value.
* @return abs(this)
*/
T abs();
/** Get the closest long to instance real value.
* @return closest long to {@link #getReal()}
*/
default long round() {
return FastMath.round(getReal());
}
}