MATH-1416: Merge changes from feature-MATH-1416
This commit is contained in:
commit
eafb16c711
|
@ -1,465 +0,0 @@
|
|||
/*
|
||||
* 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
|
||||
*
|
||||
* http://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.
|
||||
*/
|
||||
|
||||
package org.apache.commons.math4.complex;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import org.apache.commons.math4.exception.DimensionMismatchException;
|
||||
import org.apache.commons.math4.exception.ZeroException;
|
||||
import org.apache.commons.math4.exception.util.LocalizedFormats;
|
||||
import org.apache.commons.math4.util.FastMath;
|
||||
import org.apache.commons.math4.util.MathUtils;
|
||||
import org.apache.commons.numbers.core.Precision;
|
||||
|
||||
/**
|
||||
* This class implements <a href="http://mathworld.wolfram.com/Quaternion.html">
|
||||
* quaternions</a> (Hamilton's hypercomplex numbers).
|
||||
* <br>
|
||||
* Instance of this class are guaranteed to be immutable.
|
||||
*
|
||||
* @since 3.1
|
||||
*/
|
||||
public final class Quaternion implements Serializable {
|
||||
/** Identity quaternion. */
|
||||
public static final Quaternion IDENTITY = new Quaternion(1, 0, 0, 0);
|
||||
/** Zero quaternion. */
|
||||
public static final Quaternion ZERO = new Quaternion(0, 0, 0, 0);
|
||||
/** i */
|
||||
public static final Quaternion I = new Quaternion(0, 1, 0, 0);
|
||||
/** j */
|
||||
public static final Quaternion J = new Quaternion(0, 0, 1, 0);
|
||||
/** k */
|
||||
public static final Quaternion K = new Quaternion(0, 0, 0, 1);
|
||||
|
||||
/** Serializable version identifier. */
|
||||
private static final long serialVersionUID = 20092012L;
|
||||
|
||||
/** First component (scalar part). */
|
||||
private final double q0;
|
||||
/** Second component (first vector part). */
|
||||
private final double q1;
|
||||
/** Third component (second vector part). */
|
||||
private final double q2;
|
||||
/** Fourth component (third vector part). */
|
||||
private final double q3;
|
||||
|
||||
/**
|
||||
* Builds a quaternion from its components.
|
||||
*
|
||||
* @param a Scalar component.
|
||||
* @param b First vector component.
|
||||
* @param c Second vector component.
|
||||
* @param d Third vector component.
|
||||
*/
|
||||
public Quaternion(final double a,
|
||||
final double b,
|
||||
final double c,
|
||||
final double d) {
|
||||
this.q0 = a;
|
||||
this.q1 = b;
|
||||
this.q2 = c;
|
||||
this.q3 = d;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds a quaternion from scalar and vector parts.
|
||||
*
|
||||
* @param scalar Scalar part of the quaternion.
|
||||
* @param v Components of the vector part of the quaternion.
|
||||
*
|
||||
* @throws DimensionMismatchException if the array length is not 3.
|
||||
*/
|
||||
public Quaternion(final double scalar,
|
||||
final double[] v)
|
||||
throws DimensionMismatchException {
|
||||
if (v.length != 3) {
|
||||
throw new DimensionMismatchException(v.length, 3);
|
||||
}
|
||||
this.q0 = scalar;
|
||||
this.q1 = v[0];
|
||||
this.q2 = v[1];
|
||||
this.q3 = v[2];
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds a pure quaternion from a vector (assuming that the scalar
|
||||
* part is zero).
|
||||
*
|
||||
* @param v Components of the vector part of the pure quaternion.
|
||||
*/
|
||||
public Quaternion(final double[] v) {
|
||||
this(0, v);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the conjugate quaternion of the instance.
|
||||
*
|
||||
* @return the conjugate quaternion
|
||||
*/
|
||||
public Quaternion getConjugate() {
|
||||
return new Quaternion(q0, -q1, -q2, -q3);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Hamilton product of two quaternions.
|
||||
*
|
||||
* @param q1 First quaternion.
|
||||
* @param q2 Second quaternion.
|
||||
* @return the product {@code q1} and {@code q2}, in that order.
|
||||
*/
|
||||
public static Quaternion multiply(final Quaternion q1, final Quaternion q2) {
|
||||
// Components of the first quaternion.
|
||||
final double q1a = q1.getQ0();
|
||||
final double q1b = q1.getQ1();
|
||||
final double q1c = q1.getQ2();
|
||||
final double q1d = q1.getQ3();
|
||||
|
||||
// Components of the second quaternion.
|
||||
final double q2a = q2.getQ0();
|
||||
final double q2b = q2.getQ1();
|
||||
final double q2c = q2.getQ2();
|
||||
final double q2d = q2.getQ3();
|
||||
|
||||
// Components of the product.
|
||||
final double w = q1a * q2a - q1b * q2b - q1c * q2c - q1d * q2d;
|
||||
final double x = q1a * q2b + q1b * q2a + q1c * q2d - q1d * q2c;
|
||||
final double y = q1a * q2c - q1b * q2d + q1c * q2a + q1d * q2b;
|
||||
final double z = q1a * q2d + q1b * q2c - q1c * q2b + q1d * q2a;
|
||||
|
||||
return new Quaternion(w, x, y, z);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Hamilton product of the instance by a quaternion.
|
||||
*
|
||||
* @param q Quaternion.
|
||||
* @return the product of this instance with {@code q}, in that order.
|
||||
*/
|
||||
public Quaternion multiply(final Quaternion q) {
|
||||
return multiply(this, q);
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes the sum of two quaternions.
|
||||
*
|
||||
* @param q1 Quaternion.
|
||||
* @param q2 Quaternion.
|
||||
* @return the sum of {@code q1} and {@code q2}.
|
||||
*/
|
||||
public static Quaternion add(final Quaternion q1,
|
||||
final Quaternion q2) {
|
||||
return new Quaternion(q1.getQ0() + q2.getQ0(),
|
||||
q1.getQ1() + q2.getQ1(),
|
||||
q1.getQ2() + q2.getQ2(),
|
||||
q1.getQ3() + q2.getQ3());
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes the sum of the instance and another quaternion.
|
||||
*
|
||||
* @param q Quaternion.
|
||||
* @return the sum of this instance and {@code q}
|
||||
*/
|
||||
public Quaternion add(final Quaternion q) {
|
||||
return add(this, q);
|
||||
}
|
||||
|
||||
/**
|
||||
* Subtracts two quaternions.
|
||||
*
|
||||
* @param q1 First Quaternion.
|
||||
* @param q2 Second quaternion.
|
||||
* @return the difference between {@code q1} and {@code q2}.
|
||||
*/
|
||||
public static Quaternion subtract(final Quaternion q1,
|
||||
final Quaternion q2) {
|
||||
return new Quaternion(q1.getQ0() - q2.getQ0(),
|
||||
q1.getQ1() - q2.getQ1(),
|
||||
q1.getQ2() - q2.getQ2(),
|
||||
q1.getQ3() - q2.getQ3());
|
||||
}
|
||||
|
||||
/**
|
||||
* Subtracts a quaternion from the instance.
|
||||
*
|
||||
* @param q Quaternion.
|
||||
* @return the difference between this instance and {@code q}.
|
||||
*/
|
||||
public Quaternion subtract(final Quaternion q) {
|
||||
return subtract(this, q);
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes the dot-product of two quaternions.
|
||||
*
|
||||
* @param q1 Quaternion.
|
||||
* @param q2 Quaternion.
|
||||
* @return the dot product of {@code q1} and {@code q2}.
|
||||
*/
|
||||
public static double dotProduct(final Quaternion q1,
|
||||
final Quaternion q2) {
|
||||
return q1.getQ0() * q2.getQ0() +
|
||||
q1.getQ1() * q2.getQ1() +
|
||||
q1.getQ2() * q2.getQ2() +
|
||||
q1.getQ3() * q2.getQ3();
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes the dot-product of the instance by a quaternion.
|
||||
*
|
||||
* @param q Quaternion.
|
||||
* @return the dot product of this instance and {@code q}.
|
||||
*/
|
||||
public double dotProduct(final Quaternion q) {
|
||||
return dotProduct(this, q);
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes the norm of the quaternion.
|
||||
*
|
||||
* @return the norm.
|
||||
*/
|
||||
public double getNorm() {
|
||||
return FastMath.sqrt(q0 * q0 +
|
||||
q1 * q1 +
|
||||
q2 * q2 +
|
||||
q3 * q3);
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes the normalized quaternion (the versor of the instance).
|
||||
* The norm of the quaternion must not be zero.
|
||||
*
|
||||
* @return a normalized quaternion.
|
||||
* @throws ZeroException if the norm of the quaternion is zero.
|
||||
*/
|
||||
public Quaternion normalize() {
|
||||
final double norm = getNorm();
|
||||
|
||||
if (norm < Precision.SAFE_MIN) {
|
||||
throw new ZeroException(LocalizedFormats.NORM, norm);
|
||||
}
|
||||
|
||||
return new Quaternion(q0 / norm,
|
||||
q1 / norm,
|
||||
q2 / norm,
|
||||
q3 / norm);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(Object other) {
|
||||
if (this == other) {
|
||||
return true;
|
||||
}
|
||||
if (other instanceof Quaternion) {
|
||||
final Quaternion q = (Quaternion) other;
|
||||
return q0 == q.getQ0() &&
|
||||
q1 == q.getQ1() &&
|
||||
q2 == q.getQ2() &&
|
||||
q3 == q.getQ3();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
// "Effective Java" (second edition, p. 47).
|
||||
int result = 17;
|
||||
for (double comp : new double[] { q0, q1, q2, q3 }) {
|
||||
final int c = MathUtils.hash(comp);
|
||||
result = 31 * result + c;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether this instance is equal to another quaternion
|
||||
* within a given tolerance.
|
||||
*
|
||||
* @param q Quaternion with which to compare the current quaternion.
|
||||
* @param eps Tolerance.
|
||||
* @return {@code true} if the each of the components are equal
|
||||
* within the allowed absolute error.
|
||||
*/
|
||||
public boolean equals(final Quaternion q,
|
||||
final double eps) {
|
||||
return Precision.equals(q0, q.getQ0(), eps) &&
|
||||
Precision.equals(q1, q.getQ1(), eps) &&
|
||||
Precision.equals(q2, q.getQ2(), eps) &&
|
||||
Precision.equals(q3, q.getQ3(), eps);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the instance is a unit quaternion within a given
|
||||
* tolerance.
|
||||
*
|
||||
* @param eps Tolerance (absolute error).
|
||||
* @return {@code true} if the norm is 1 within the given tolerance,
|
||||
* {@code false} otherwise
|
||||
*/
|
||||
public boolean isUnitQuaternion(double eps) {
|
||||
return Precision.equals(getNorm(), 1d, eps);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the instance is a pure quaternion within a given
|
||||
* tolerance.
|
||||
*
|
||||
* @param eps Tolerance (absolute error).
|
||||
* @return {@code true} if the scalar part of the quaternion is zero.
|
||||
*/
|
||||
public boolean isPureQuaternion(double eps) {
|
||||
return FastMath.abs(getQ0()) <= eps;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the polar form of the quaternion.
|
||||
*
|
||||
* @return the unit quaternion with positive scalar part.
|
||||
*/
|
||||
public Quaternion getPositivePolarForm() {
|
||||
if (getQ0() < 0) {
|
||||
final Quaternion unitQ = normalize();
|
||||
// The quaternion of rotation (normalized quaternion) q and -q
|
||||
// are equivalent (i.e. represent the same rotation).
|
||||
return new Quaternion(-unitQ.getQ0(),
|
||||
-unitQ.getQ1(),
|
||||
-unitQ.getQ2(),
|
||||
-unitQ.getQ3());
|
||||
} else {
|
||||
return this.normalize();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the inverse of this instance.
|
||||
* The norm of the quaternion must not be zero.
|
||||
*
|
||||
* @return the inverse.
|
||||
* @throws ZeroException if the norm (squared) of the quaternion is zero.
|
||||
*/
|
||||
public Quaternion getInverse() {
|
||||
final double squareNorm = q0 * q0 + q1 * q1 + q2 * q2 + q3 * q3;
|
||||
if (squareNorm < Precision.SAFE_MIN) {
|
||||
throw new ZeroException(LocalizedFormats.NORM, squareNorm);
|
||||
}
|
||||
|
||||
return new Quaternion(q0 / squareNorm,
|
||||
-q1 / squareNorm,
|
||||
-q2 / squareNorm,
|
||||
-q3 / squareNorm);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the first component of the quaternion (scalar part).
|
||||
*
|
||||
* @return the scalar part.
|
||||
*/
|
||||
public double getQ0() {
|
||||
return q0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the second component of the quaternion (first component
|
||||
* of the vector part).
|
||||
*
|
||||
* @return the first component of the vector part.
|
||||
*/
|
||||
public double getQ1() {
|
||||
return q1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the third component of the quaternion (second component
|
||||
* of the vector part).
|
||||
*
|
||||
* @return the second component of the vector part.
|
||||
*/
|
||||
public double getQ2() {
|
||||
return q2;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the fourth component of the quaternion (third component
|
||||
* of the vector part).
|
||||
*
|
||||
* @return the third component of the vector part.
|
||||
*/
|
||||
public double getQ3() {
|
||||
return q3;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the scalar part of the quaternion.
|
||||
*
|
||||
* @return the scalar part.
|
||||
* @see #getQ0()
|
||||
*/
|
||||
public double getScalarPart() {
|
||||
return getQ0();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the three components of the vector part of the quaternion.
|
||||
*
|
||||
* @return the vector part.
|
||||
* @see #getQ1()
|
||||
* @see #getQ2()
|
||||
* @see #getQ3()
|
||||
*/
|
||||
public double[] getVectorPart() {
|
||||
return new double[] { getQ1(), getQ2(), getQ3() };
|
||||
}
|
||||
|
||||
/**
|
||||
* Multiplies the instance by a scalar.
|
||||
*
|
||||
* @param alpha Scalar factor.
|
||||
* @return a scaled quaternion.
|
||||
*/
|
||||
public Quaternion multiply(final double alpha) {
|
||||
return new Quaternion(alpha * q0,
|
||||
alpha * q1,
|
||||
alpha * q2,
|
||||
alpha * q3);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
final String sp = " ";
|
||||
final StringBuilder s = new StringBuilder();
|
||||
s.append("[")
|
||||
.append(q0).append(sp)
|
||||
.append(q1).append(sp)
|
||||
.append(q2).append(sp)
|
||||
.append(q3)
|
||||
.append("]");
|
||||
|
||||
return s.toString();
|
||||
}
|
||||
}
|
|
@ -1,218 +0,0 @@
|
|||
/*
|
||||
* 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
|
||||
*
|
||||
* http://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.
|
||||
*/
|
||||
package org.apache.commons.math4.complex;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import org.apache.commons.math4.exception.MathIllegalArgumentException;
|
||||
import org.apache.commons.math4.exception.MathIllegalStateException;
|
||||
import org.apache.commons.math4.exception.OutOfRangeException;
|
||||
import org.apache.commons.math4.exception.ZeroException;
|
||||
import org.apache.commons.math4.exception.util.LocalizedFormats;
|
||||
import org.apache.commons.math4.util.FastMath;
|
||||
|
||||
/**
|
||||
* A helper class for the computation and caching of the {@code n}-th roots of
|
||||
* unity.
|
||||
*
|
||||
* @since 3.0
|
||||
*/
|
||||
public class RootsOfUnity implements Serializable {
|
||||
|
||||
/** Serializable version id. */
|
||||
private static final long serialVersionUID = 20120201L;
|
||||
|
||||
/** Number of roots of unity. */
|
||||
private int omegaCount;
|
||||
|
||||
/** Real part of the roots. */
|
||||
private double[] omegaReal;
|
||||
|
||||
/**
|
||||
* Imaginary part of the {@code n}-th roots of unity, for positive values
|
||||
* of {@code n}. In this array, the roots are stored in counter-clockwise
|
||||
* order.
|
||||
*/
|
||||
private double[] omegaImaginaryCounterClockwise;
|
||||
|
||||
/**
|
||||
* Imaginary part of the {@code n}-th roots of unity, for negative values
|
||||
* of {@code n}. In this array, the roots are stored in clockwise order.
|
||||
*/
|
||||
private double[] omegaImaginaryClockwise;
|
||||
|
||||
/**
|
||||
* {@code true} if {@link #computeRoots(int)} was called with a positive
|
||||
* value of its argument {@code n}. In this case, counter-clockwise ordering
|
||||
* of the roots of unity should be used.
|
||||
*/
|
||||
private boolean isCounterClockWise;
|
||||
|
||||
/**
|
||||
* Build an engine for computing the {@code n}-th roots of unity.
|
||||
*/
|
||||
public RootsOfUnity() {
|
||||
|
||||
omegaCount = 0;
|
||||
omegaReal = null;
|
||||
omegaImaginaryCounterClockwise = null;
|
||||
omegaImaginaryClockwise = null;
|
||||
isCounterClockWise = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@code true} if {@link #computeRoots(int)} was called with a
|
||||
* positive value of its argument {@code n}. If {@code true}, then
|
||||
* counter-clockwise ordering of the roots of unity should be used.
|
||||
*
|
||||
* @return {@code true} if the roots of unity are stored in
|
||||
* counter-clockwise order
|
||||
* @throws MathIllegalStateException if no roots of unity have been computed
|
||||
* yet
|
||||
*/
|
||||
public synchronized boolean isCounterClockWise()
|
||||
throws MathIllegalStateException {
|
||||
|
||||
if (omegaCount == 0) {
|
||||
throw new MathIllegalStateException(
|
||||
LocalizedFormats.ROOTS_OF_UNITY_NOT_COMPUTED_YET);
|
||||
}
|
||||
return isCounterClockWise;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Computes the {@code n}-th roots of unity. The roots are stored in
|
||||
* {@code omega[]}, such that {@code omega[k] = w ^ k}, where
|
||||
* {@code k = 0, ..., n - 1}, {@code w = exp(2 * pi * i / n)} and
|
||||
* {@code i = sqrt(-1)}.
|
||||
* </p>
|
||||
* <p>
|
||||
* Note that {@code n} can be positive of negative
|
||||
* </p>
|
||||
* <ul>
|
||||
* <li>{@code abs(n)} is always the number of roots of unity.</li>
|
||||
* <li>If {@code n > 0}, then the roots are stored in counter-clockwise order.</li>
|
||||
* <li>If {@code n < 0}, then the roots are stored in clockwise order.
|
||||
* </ul>
|
||||
*
|
||||
* @param n the (signed) number of roots of unity to be computed
|
||||
* @throws ZeroException if {@code n = 0}
|
||||
*/
|
||||
public synchronized void computeRoots(int n) throws ZeroException {
|
||||
|
||||
if (n == 0) {
|
||||
throw new ZeroException(
|
||||
LocalizedFormats.CANNOT_COMPUTE_0TH_ROOT_OF_UNITY);
|
||||
}
|
||||
|
||||
isCounterClockWise = n > 0;
|
||||
|
||||
// avoid repetitive calculations
|
||||
final int absN = FastMath.abs(n);
|
||||
|
||||
if (absN == omegaCount) {
|
||||
return;
|
||||
}
|
||||
|
||||
// calculate everything from scratch
|
||||
final double t = 2.0 * FastMath.PI / absN;
|
||||
final double cosT = FastMath.cos(t);
|
||||
final double sinT = FastMath.sin(t);
|
||||
omegaReal = new double[absN];
|
||||
omegaImaginaryCounterClockwise = new double[absN];
|
||||
omegaImaginaryClockwise = new double[absN];
|
||||
omegaReal[0] = 1.0;
|
||||
omegaImaginaryCounterClockwise[0] = 0.0;
|
||||
omegaImaginaryClockwise[0] = 0.0;
|
||||
for (int i = 1; i < absN; i++) {
|
||||
omegaReal[i] = omegaReal[i - 1] * cosT -
|
||||
omegaImaginaryCounterClockwise[i - 1] * sinT;
|
||||
omegaImaginaryCounterClockwise[i] = omegaReal[i - 1] * sinT +
|
||||
omegaImaginaryCounterClockwise[i - 1] * cosT;
|
||||
omegaImaginaryClockwise[i] = -omegaImaginaryCounterClockwise[i];
|
||||
}
|
||||
omegaCount = absN;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the real part of the {@code k}-th {@code n}-th root of unity.
|
||||
*
|
||||
* @param k index of the {@code n}-th root of unity
|
||||
* @return real part of the {@code k}-th {@code n}-th root of unity
|
||||
* @throws MathIllegalStateException if no roots of unity have been
|
||||
* computed yet
|
||||
* @throws MathIllegalArgumentException if {@code k} is out of range
|
||||
*/
|
||||
public synchronized double getReal(int k)
|
||||
throws MathIllegalStateException, MathIllegalArgumentException {
|
||||
|
||||
if (omegaCount == 0) {
|
||||
throw new MathIllegalStateException(
|
||||
LocalizedFormats.ROOTS_OF_UNITY_NOT_COMPUTED_YET);
|
||||
}
|
||||
if ((k < 0) || (k >= omegaCount)) {
|
||||
throw new OutOfRangeException(
|
||||
LocalizedFormats.OUT_OF_RANGE_ROOT_OF_UNITY_INDEX,
|
||||
Integer.valueOf(k),
|
||||
Integer.valueOf(0),
|
||||
Integer.valueOf(omegaCount - 1));
|
||||
}
|
||||
|
||||
return omegaReal[k];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the imaginary part of the {@code k}-th {@code n}-th root of unity.
|
||||
*
|
||||
* @param k index of the {@code n}-th root of unity
|
||||
* @return imaginary part of the {@code k}-th {@code n}-th root of unity
|
||||
* @throws MathIllegalStateException if no roots of unity have been
|
||||
* computed yet
|
||||
* @throws OutOfRangeException if {@code k} is out of range
|
||||
*/
|
||||
public synchronized double getImaginary(int k)
|
||||
throws MathIllegalStateException, OutOfRangeException {
|
||||
|
||||
if (omegaCount == 0) {
|
||||
throw new MathIllegalStateException(
|
||||
LocalizedFormats.ROOTS_OF_UNITY_NOT_COMPUTED_YET);
|
||||
}
|
||||
if ((k < 0) || (k >= omegaCount)) {
|
||||
throw new OutOfRangeException(
|
||||
LocalizedFormats.OUT_OF_RANGE_ROOT_OF_UNITY_INDEX,
|
||||
Integer.valueOf(k),
|
||||
Integer.valueOf(0),
|
||||
Integer.valueOf(omegaCount - 1));
|
||||
}
|
||||
|
||||
return isCounterClockWise ? omegaImaginaryCounterClockwise[k] :
|
||||
omegaImaginaryClockwise[k];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of roots of unity currently stored. If
|
||||
* {@link #computeRoots(int)} was called with {@code n}, then this method
|
||||
* returns {@code abs(n)}. If no roots of unity have been computed yet, this
|
||||
* method returns 0.
|
||||
*
|
||||
* @return the number of roots of unity currently stored
|
||||
*/
|
||||
public synchronized int getNumberOfRoots() {
|
||||
return omegaCount;
|
||||
}
|
||||
}
|
|
@ -1,209 +0,0 @@
|
|||
/*
|
||||
* 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
|
||||
*
|
||||
* http://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.
|
||||
*/
|
||||
|
||||
package org.apache.commons.math4.fraction;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.text.FieldPosition;
|
||||
import java.text.NumberFormat;
|
||||
import java.text.ParsePosition;
|
||||
import java.util.Locale;
|
||||
|
||||
import org.apache.commons.math4.exception.NullArgumentException;
|
||||
import org.apache.commons.math4.exception.util.LocalizedFormats;
|
||||
|
||||
/**
|
||||
* Common part shared by both {@link FractionFormat} and {@link BigFractionFormat}.
|
||||
* @since 2.0
|
||||
*/
|
||||
public abstract class AbstractFormat extends NumberFormat implements Serializable {
|
||||
|
||||
/** Serializable version identifier. */
|
||||
private static final long serialVersionUID = -6981118387974191891L;
|
||||
|
||||
/** The format used for the denominator. */
|
||||
private NumberFormat denominatorFormat;
|
||||
|
||||
/** The format used for the numerator. */
|
||||
private NumberFormat numeratorFormat;
|
||||
|
||||
/**
|
||||
* Create an improper formatting instance with the default number format
|
||||
* for the numerator and denominator.
|
||||
*/
|
||||
protected AbstractFormat() {
|
||||
this(getDefaultNumberFormat());
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an improper formatting instance with a custom number format for
|
||||
* both the numerator and denominator.
|
||||
* @param format the custom format for both the numerator and denominator.
|
||||
*/
|
||||
protected AbstractFormat(final NumberFormat format) {
|
||||
this(format, (NumberFormat) format.clone());
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an improper formatting instance with a custom number format for
|
||||
* the numerator and a custom number format for the denominator.
|
||||
* @param numeratorFormat the custom format for the numerator.
|
||||
* @param denominatorFormat the custom format for the denominator.
|
||||
*/
|
||||
protected AbstractFormat(final NumberFormat numeratorFormat,
|
||||
final NumberFormat denominatorFormat) {
|
||||
this.numeratorFormat = numeratorFormat;
|
||||
this.denominatorFormat = denominatorFormat;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a default number format. The default number format is based on
|
||||
* {@link NumberFormat#getNumberInstance(java.util.Locale)}. The only
|
||||
* customization is the maximum number of BigFraction digits, which is set to 0.
|
||||
* @return the default number format.
|
||||
*/
|
||||
protected static NumberFormat getDefaultNumberFormat() {
|
||||
return getDefaultNumberFormat(Locale.getDefault());
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a default number format. The default number format is based on
|
||||
* {@link NumberFormat#getNumberInstance(java.util.Locale)}. The only
|
||||
* customization is the maximum number of BigFraction digits, which is set to 0.
|
||||
* @param locale the specific locale used by the format.
|
||||
* @return the default number format specific to the given locale.
|
||||
*/
|
||||
protected static NumberFormat getDefaultNumberFormat(final Locale locale) {
|
||||
final NumberFormat nf = NumberFormat.getNumberInstance(locale);
|
||||
nf.setMaximumFractionDigits(0);
|
||||
nf.setParseIntegerOnly(true);
|
||||
return nf;
|
||||
}
|
||||
|
||||
/**
|
||||
* Access the denominator format.
|
||||
* @return the denominator format.
|
||||
*/
|
||||
public NumberFormat getDenominatorFormat() {
|
||||
return denominatorFormat;
|
||||
}
|
||||
|
||||
/**
|
||||
* Access the numerator format.
|
||||
* @return the numerator format.
|
||||
*/
|
||||
public NumberFormat getNumeratorFormat() {
|
||||
return numeratorFormat;
|
||||
}
|
||||
|
||||
/**
|
||||
* Modify the denominator format.
|
||||
* @param format the new denominator format value.
|
||||
* @throws NullArgumentException if {@code format} is {@code null}.
|
||||
*/
|
||||
public void setDenominatorFormat(final NumberFormat format) {
|
||||
if (format == null) {
|
||||
throw new NullArgumentException(LocalizedFormats.DENOMINATOR_FORMAT);
|
||||
}
|
||||
this.denominatorFormat = format;
|
||||
}
|
||||
|
||||
/**
|
||||
* Modify the numerator format.
|
||||
* @param format the new numerator format value.
|
||||
* @throws NullArgumentException if {@code format} is {@code null}.
|
||||
*/
|
||||
public void setNumeratorFormat(final NumberFormat format) {
|
||||
if (format == null) {
|
||||
throw new NullArgumentException(LocalizedFormats.NUMERATOR_FORMAT);
|
||||
}
|
||||
this.numeratorFormat = format;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses <code>source</code> until a non-whitespace character is found.
|
||||
* @param source the string to parse
|
||||
* @param pos input/output parsing parameter. On output, <code>pos</code>
|
||||
* holds the index of the next non-whitespace character.
|
||||
*/
|
||||
protected static void parseAndIgnoreWhitespace(final String source,
|
||||
final ParsePosition pos) {
|
||||
parseNextCharacter(source, pos);
|
||||
pos.setIndex(pos.getIndex() - 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses <code>source</code> until a non-whitespace character is found.
|
||||
* @param source the string to parse
|
||||
* @param pos input/output parsing parameter.
|
||||
* @return the first non-whitespace character.
|
||||
*/
|
||||
protected static char parseNextCharacter(final String source,
|
||||
final ParsePosition pos) {
|
||||
int index = pos.getIndex();
|
||||
final int n = source.length();
|
||||
char ret = 0;
|
||||
|
||||
if (index < n) {
|
||||
char c;
|
||||
do {
|
||||
c = source.charAt(index++);
|
||||
} while (Character.isWhitespace(c) && index < n);
|
||||
pos.setIndex(index);
|
||||
|
||||
if (index < n) {
|
||||
ret = c;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats a double value as a fraction and appends the result to a StringBuffer.
|
||||
*
|
||||
* @param value the double value to format
|
||||
* @param buffer StringBuffer to append to
|
||||
* @param position On input: an alignment field, if desired. On output: the
|
||||
* offsets of the alignment field
|
||||
* @return a reference to the appended buffer
|
||||
* @see #format(Object, StringBuffer, FieldPosition)
|
||||
*/
|
||||
@Override
|
||||
public StringBuffer format(final double value,
|
||||
final StringBuffer buffer, final FieldPosition position) {
|
||||
return format(Double.valueOf(value), buffer, position);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Formats a long value as a fraction and appends the result to a StringBuffer.
|
||||
*
|
||||
* @param value the long value to format
|
||||
* @param buffer StringBuffer to append to
|
||||
* @param position On input: an alignment field, if desired. On output: the
|
||||
* offsets of the alignment field
|
||||
* @return a reference to the appended buffer
|
||||
* @see #format(Object, StringBuffer, FieldPosition)
|
||||
*/
|
||||
@Override
|
||||
public StringBuffer format(final long value,
|
||||
final StringBuffer buffer, final FieldPosition position) {
|
||||
return format(Long.valueOf(value), buffer, position);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,287 +0,0 @@
|
|||
/*
|
||||
* 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
|
||||
*
|
||||
* http://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.
|
||||
*/
|
||||
|
||||
package org.apache.commons.math4.fraction;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.math.BigInteger;
|
||||
import java.text.FieldPosition;
|
||||
import java.text.NumberFormat;
|
||||
import java.text.ParsePosition;
|
||||
import java.util.Locale;
|
||||
|
||||
import org.apache.commons.math4.exception.MathIllegalArgumentException;
|
||||
import org.apache.commons.math4.exception.MathParseException;
|
||||
import org.apache.commons.math4.exception.util.LocalizedFormats;
|
||||
|
||||
/**
|
||||
* Formats a BigFraction number in proper format or improper format.
|
||||
* <p>
|
||||
* The number format for each of the whole number, numerator and,
|
||||
* denominator can be configured.
|
||||
* </p>
|
||||
*
|
||||
* @since 2.0
|
||||
*/
|
||||
public class BigFractionFormat extends AbstractFormat implements Serializable {
|
||||
|
||||
/** Serializable version identifier */
|
||||
private static final long serialVersionUID = -2932167925527338976L;
|
||||
|
||||
/**
|
||||
* Create an improper formatting instance with the default number format
|
||||
* for the numerator and denominator.
|
||||
*/
|
||||
public BigFractionFormat() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an improper formatting instance with a custom number format for
|
||||
* both the numerator and denominator.
|
||||
* @param format the custom format for both the numerator and denominator.
|
||||
*/
|
||||
public BigFractionFormat(final NumberFormat format) {
|
||||
super(format);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an improper formatting instance with a custom number format for
|
||||
* the numerator and a custom number format for the denominator.
|
||||
* @param numeratorFormat the custom format for the numerator.
|
||||
* @param denominatorFormat the custom format for the denominator.
|
||||
*/
|
||||
public BigFractionFormat(final NumberFormat numeratorFormat,
|
||||
final NumberFormat denominatorFormat) {
|
||||
super(numeratorFormat, denominatorFormat);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the set of locales for which complex formats are available. This
|
||||
* is the same set as the {@link NumberFormat} set.
|
||||
* @return available complex format locales.
|
||||
*/
|
||||
public static Locale[] getAvailableLocales() {
|
||||
return NumberFormat.getAvailableLocales();
|
||||
}
|
||||
|
||||
/**
|
||||
* This static method calls formatBigFraction() on a default instance of
|
||||
* BigFractionFormat.
|
||||
*
|
||||
* @param f BigFraction object to format
|
||||
* @return A formatted BigFraction in proper form.
|
||||
*/
|
||||
public static String formatBigFraction(final BigFraction f) {
|
||||
return getImproperInstance().format(f);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the default complex format for the current locale.
|
||||
* @return the default complex format.
|
||||
*/
|
||||
public static BigFractionFormat getImproperInstance() {
|
||||
return getImproperInstance(Locale.getDefault());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the default complex format for the given locale.
|
||||
* @param locale the specific locale used by the format.
|
||||
* @return the complex format specific to the given locale.
|
||||
*/
|
||||
public static BigFractionFormat getImproperInstance(final Locale locale) {
|
||||
return new BigFractionFormat(getDefaultNumberFormat(locale));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the default complex format for the current locale.
|
||||
* @return the default complex format.
|
||||
*/
|
||||
public static BigFractionFormat getProperInstance() {
|
||||
return getProperInstance(Locale.getDefault());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the default complex format for the given locale.
|
||||
* @param locale the specific locale used by the format.
|
||||
* @return the complex format specific to the given locale.
|
||||
*/
|
||||
public static BigFractionFormat getProperInstance(final Locale locale) {
|
||||
return new ProperBigFractionFormat(getDefaultNumberFormat(locale));
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats a {@link BigFraction} object to produce a string. The BigFraction is
|
||||
* output in improper format.
|
||||
*
|
||||
* @param BigFraction the object to format.
|
||||
* @param toAppendTo where the text is to be appended
|
||||
* @param pos On input: an alignment field, if desired. On output: the
|
||||
* offsets of the alignment field
|
||||
* @return the value passed in as toAppendTo.
|
||||
*/
|
||||
public StringBuffer format(final BigFraction BigFraction,
|
||||
final StringBuffer toAppendTo, final FieldPosition pos) {
|
||||
|
||||
pos.setBeginIndex(0);
|
||||
pos.setEndIndex(0);
|
||||
|
||||
getNumeratorFormat().format(BigFraction.getNumerator(), toAppendTo, pos);
|
||||
toAppendTo.append(" / ");
|
||||
getDenominatorFormat().format(BigFraction.getDenominator(), toAppendTo, pos);
|
||||
|
||||
return toAppendTo;
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats an object and appends the result to a StringBuffer.
|
||||
* <code>obj</code> must be either a {@link BigFraction} object or a
|
||||
* {@link BigInteger} object or a {@link Number} object. Any other type of
|
||||
* object will result in an {@link IllegalArgumentException} being thrown.
|
||||
*
|
||||
* @param obj the object to format.
|
||||
* @param toAppendTo where the text is to be appended
|
||||
* @param pos On input: an alignment field, if desired. On output: the
|
||||
* offsets of the alignment field
|
||||
* @return the value passed in as toAppendTo.
|
||||
* @see java.text.Format#format(java.lang.Object, java.lang.StringBuffer, java.text.FieldPosition)
|
||||
* @throws MathIllegalArgumentException if <code>obj</code> is not a valid type.
|
||||
*/
|
||||
@Override
|
||||
public StringBuffer format(final Object obj,
|
||||
final StringBuffer toAppendTo, final FieldPosition pos) {
|
||||
|
||||
final StringBuffer ret;
|
||||
if (obj instanceof BigFraction) {
|
||||
ret = format((BigFraction) obj, toAppendTo, pos);
|
||||
} else if (obj instanceof BigInteger) {
|
||||
ret = format(new BigFraction((BigInteger) obj), toAppendTo, pos);
|
||||
} else if (obj instanceof Number) {
|
||||
ret = format(new BigFraction(((Number) obj).doubleValue()),
|
||||
toAppendTo, pos);
|
||||
} else {
|
||||
throw new MathIllegalArgumentException(LocalizedFormats.CANNOT_FORMAT_OBJECT_TO_FRACTION);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a string to produce a {@link BigFraction} object.
|
||||
* @param source the string to parse
|
||||
* @return the parsed {@link BigFraction} object.
|
||||
* @exception MathParseException if the beginning of the specified string
|
||||
* cannot be parsed.
|
||||
*/
|
||||
@Override
|
||||
public BigFraction parse(final String source) throws MathParseException {
|
||||
final ParsePosition parsePosition = new ParsePosition(0);
|
||||
final BigFraction result = parse(source, parsePosition);
|
||||
if (parsePosition.getIndex() == 0) {
|
||||
throw new MathParseException(source, parsePosition.getErrorIndex(), BigFraction.class);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a string to produce a {@link BigFraction} object.
|
||||
* This method expects the string to be formatted as an improper BigFraction.
|
||||
* @param source the string to parse
|
||||
* @param pos input/output parsing parameter.
|
||||
* @return the parsed {@link BigFraction} object.
|
||||
*/
|
||||
@Override
|
||||
public BigFraction parse(final String source, final ParsePosition pos) {
|
||||
final int initialIndex = pos.getIndex();
|
||||
|
||||
// parse whitespace
|
||||
parseAndIgnoreWhitespace(source, pos);
|
||||
|
||||
// parse numerator
|
||||
final BigInteger num = parseNextBigInteger(source, pos);
|
||||
if (num == null) {
|
||||
// invalid integer number
|
||||
// set index back to initial, error index should already be set
|
||||
// character examined.
|
||||
pos.setIndex(initialIndex);
|
||||
return null;
|
||||
}
|
||||
|
||||
// parse '/'
|
||||
final int startIndex = pos.getIndex();
|
||||
final char c = parseNextCharacter(source, pos);
|
||||
switch (c) {
|
||||
case 0 :
|
||||
// no '/'
|
||||
// return num as a BigFraction
|
||||
return new BigFraction(num);
|
||||
case '/' :
|
||||
// found '/', continue parsing denominator
|
||||
break;
|
||||
default :
|
||||
// invalid '/'
|
||||
// set index back to initial, error index should be the last
|
||||
// character examined.
|
||||
pos.setIndex(initialIndex);
|
||||
pos.setErrorIndex(startIndex);
|
||||
return null;
|
||||
}
|
||||
|
||||
// parse whitespace
|
||||
parseAndIgnoreWhitespace(source, pos);
|
||||
|
||||
// parse denominator
|
||||
final BigInteger den = parseNextBigInteger(source, pos);
|
||||
if (den == null) {
|
||||
// invalid integer number
|
||||
// set index back to initial, error index should already be set
|
||||
// character examined.
|
||||
pos.setIndex(initialIndex);
|
||||
return null;
|
||||
}
|
||||
|
||||
return new BigFraction(num, den);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a string to produce a <code>BigInteger</code>.
|
||||
* @param source the string to parse
|
||||
* @param pos input/output parsing parameter.
|
||||
* @return a parsed <code>BigInteger</code> or null if string does not
|
||||
* contain a BigInteger at the specified position
|
||||
*/
|
||||
protected BigInteger parseNextBigInteger(final String source,
|
||||
final ParsePosition pos) {
|
||||
|
||||
final int start = pos.getIndex();
|
||||
int end = (source.charAt(start) == '-') ? (start + 1) : start;
|
||||
while((end < source.length()) &&
|
||||
Character.isDigit(source.charAt(end))) {
|
||||
++end;
|
||||
}
|
||||
|
||||
try {
|
||||
BigInteger n = new BigInteger(source.substring(start, end));
|
||||
pos.setIndex(end);
|
||||
return n;
|
||||
} catch (NumberFormatException nfe) {
|
||||
pos.setErrorIndex(start);
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -1,264 +0,0 @@
|
|||
/*
|
||||
* 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
|
||||
*
|
||||
* http://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.
|
||||
*/
|
||||
|
||||
package org.apache.commons.math4.fraction;
|
||||
|
||||
import java.text.FieldPosition;
|
||||
import java.text.NumberFormat;
|
||||
import java.text.ParsePosition;
|
||||
import java.util.Locale;
|
||||
|
||||
import org.apache.commons.math4.exception.MathIllegalArgumentException;
|
||||
import org.apache.commons.math4.exception.MathParseException;
|
||||
import org.apache.commons.math4.exception.util.LocalizedFormats;
|
||||
|
||||
/**
|
||||
* Formats a Fraction number in proper format or improper format. The number
|
||||
* format for each of the whole number, numerator and, denominator can be
|
||||
* configured.
|
||||
*
|
||||
* @since 1.1
|
||||
*/
|
||||
public class FractionFormat extends AbstractFormat {
|
||||
|
||||
/** Serializable version identifier */
|
||||
private static final long serialVersionUID = 3008655719530972611L;
|
||||
|
||||
/**
|
||||
* Create an improper formatting instance with the default number format
|
||||
* for the numerator and denominator.
|
||||
*/
|
||||
public FractionFormat() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an improper formatting instance with a custom number format for
|
||||
* both the numerator and denominator.
|
||||
* @param format the custom format for both the numerator and denominator.
|
||||
*/
|
||||
public FractionFormat(final NumberFormat format) {
|
||||
super(format);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an improper formatting instance with a custom number format for
|
||||
* the numerator and a custom number format for the denominator.
|
||||
* @param numeratorFormat the custom format for the numerator.
|
||||
* @param denominatorFormat the custom format for the denominator.
|
||||
*/
|
||||
public FractionFormat(final NumberFormat numeratorFormat,
|
||||
final NumberFormat denominatorFormat) {
|
||||
super(numeratorFormat, denominatorFormat);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the set of locales for which complex formats are available. This
|
||||
* is the same set as the {@link NumberFormat} set.
|
||||
* @return available complex format locales.
|
||||
*/
|
||||
public static Locale[] getAvailableLocales() {
|
||||
return NumberFormat.getAvailableLocales();
|
||||
}
|
||||
|
||||
/**
|
||||
* This static method calls formatFraction() on a default instance of
|
||||
* FractionFormat.
|
||||
*
|
||||
* @param f Fraction object to format
|
||||
* @return a formatted fraction in proper form.
|
||||
*/
|
||||
public static String formatFraction(Fraction f) {
|
||||
return getImproperInstance().format(f);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the default complex format for the current locale.
|
||||
* @return the default complex format.
|
||||
*/
|
||||
public static FractionFormat getImproperInstance() {
|
||||
return getImproperInstance(Locale.getDefault());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the default complex format for the given locale.
|
||||
* @param locale the specific locale used by the format.
|
||||
* @return the complex format specific to the given locale.
|
||||
*/
|
||||
public static FractionFormat getImproperInstance(final Locale locale) {
|
||||
return new FractionFormat(getDefaultNumberFormat(locale));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the default complex format for the current locale.
|
||||
* @return the default complex format.
|
||||
*/
|
||||
public static FractionFormat getProperInstance() {
|
||||
return getProperInstance(Locale.getDefault());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the default complex format for the given locale.
|
||||
* @param locale the specific locale used by the format.
|
||||
* @return the complex format specific to the given locale.
|
||||
*/
|
||||
public static FractionFormat getProperInstance(final Locale locale) {
|
||||
return new ProperFractionFormat(getDefaultNumberFormat(locale));
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a default number format. The default number format is based on
|
||||
* {@link NumberFormat#getNumberInstance(java.util.Locale)} with the only
|
||||
* customizing is the maximum number of fraction digits, which is set to 0.
|
||||
* @return the default number format.
|
||||
*/
|
||||
protected static NumberFormat getDefaultNumberFormat() {
|
||||
return getDefaultNumberFormat(Locale.getDefault());
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats a {@link Fraction} object to produce a string. The fraction is
|
||||
* output in improper format.
|
||||
*
|
||||
* @param fraction the object to format.
|
||||
* @param toAppendTo where the text is to be appended
|
||||
* @param pos On input: an alignment field, if desired. On output: the
|
||||
* offsets of the alignment field
|
||||
* @return the value passed in as toAppendTo.
|
||||
*/
|
||||
public StringBuffer format(final Fraction fraction,
|
||||
final StringBuffer toAppendTo, final FieldPosition pos) {
|
||||
|
||||
pos.setBeginIndex(0);
|
||||
pos.setEndIndex(0);
|
||||
|
||||
getNumeratorFormat().format(fraction.getNumerator(), toAppendTo, pos);
|
||||
toAppendTo.append(" / ");
|
||||
getDenominatorFormat().format(fraction.getDenominator(), toAppendTo,
|
||||
pos);
|
||||
|
||||
return toAppendTo;
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats an object and appends the result to a StringBuffer. <code>obj</code> must be either a
|
||||
* {@link Fraction} object or a {@link Number} object. Any other type of
|
||||
* object will result in an {@link IllegalArgumentException} being thrown.
|
||||
*
|
||||
* @param obj the object to format.
|
||||
* @param toAppendTo where the text is to be appended
|
||||
* @param pos On input: an alignment field, if desired. On output: the
|
||||
* offsets of the alignment field
|
||||
* @return the value passed in as toAppendTo.
|
||||
* @see java.text.Format#format(java.lang.Object, java.lang.StringBuffer, java.text.FieldPosition)
|
||||
* @throws FractionConversionException if the number cannot be converted to a fraction
|
||||
* @throws MathIllegalArgumentException if <code>obj</code> is not a valid type.
|
||||
*/
|
||||
@Override
|
||||
public StringBuffer format(final Object obj,
|
||||
final StringBuffer toAppendTo, final FieldPosition pos)
|
||||
throws FractionConversionException, MathIllegalArgumentException {
|
||||
StringBuffer ret = null;
|
||||
|
||||
if (obj instanceof Fraction) {
|
||||
ret = format((Fraction) obj, toAppendTo, pos);
|
||||
} else if (obj instanceof Number) {
|
||||
ret = format(new Fraction(((Number) obj).doubleValue()), toAppendTo, pos);
|
||||
} else {
|
||||
throw new MathIllegalArgumentException(LocalizedFormats.CANNOT_FORMAT_OBJECT_TO_FRACTION);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a string to produce a {@link Fraction} object.
|
||||
* @param source the string to parse
|
||||
* @return the parsed {@link Fraction} object.
|
||||
* @exception MathParseException if the beginning of the specified string
|
||||
* cannot be parsed.
|
||||
*/
|
||||
@Override
|
||||
public Fraction parse(final String source) throws MathParseException {
|
||||
final ParsePosition parsePosition = new ParsePosition(0);
|
||||
final Fraction result = parse(source, parsePosition);
|
||||
if (parsePosition.getIndex() == 0) {
|
||||
throw new MathParseException(source, parsePosition.getErrorIndex(), Fraction.class);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a string to produce a {@link Fraction} object. This method
|
||||
* expects the string to be formatted as an improper fraction.
|
||||
* @param source the string to parse
|
||||
* @param pos input/output parsing parameter.
|
||||
* @return the parsed {@link Fraction} object.
|
||||
*/
|
||||
@Override
|
||||
public Fraction parse(final String source, final ParsePosition pos) {
|
||||
final int initialIndex = pos.getIndex();
|
||||
|
||||
// parse whitespace
|
||||
parseAndIgnoreWhitespace(source, pos);
|
||||
|
||||
// parse numerator
|
||||
final Number num = getNumeratorFormat().parse(source, pos);
|
||||
if (num == null) {
|
||||
// invalid integer number
|
||||
// set index back to initial, error index should already be set
|
||||
// character examined.
|
||||
pos.setIndex(initialIndex);
|
||||
return null;
|
||||
}
|
||||
|
||||
// parse '/'
|
||||
final int startIndex = pos.getIndex();
|
||||
final char c = parseNextCharacter(source, pos);
|
||||
switch (c) {
|
||||
case 0 :
|
||||
// no '/'
|
||||
// return num as a fraction
|
||||
return new Fraction(num.intValue(), 1);
|
||||
case '/' :
|
||||
// found '/', continue parsing denominator
|
||||
break;
|
||||
default :
|
||||
// invalid '/'
|
||||
// set index back to initial, error index should be the last
|
||||
// character examined.
|
||||
pos.setIndex(initialIndex);
|
||||
pos.setErrorIndex(startIndex);
|
||||
return null;
|
||||
}
|
||||
|
||||
// parse whitespace
|
||||
parseAndIgnoreWhitespace(source, pos);
|
||||
|
||||
// parse denominator
|
||||
final Number den = getDenominatorFormat().parse(source, pos);
|
||||
if (den == null) {
|
||||
// invalid integer number
|
||||
// set index back to initial, error index should already be set
|
||||
// character examined.
|
||||
pos.setIndex(initialIndex);
|
||||
return null;
|
||||
}
|
||||
|
||||
return new Fraction(num.intValue(), den.intValue());
|
||||
}
|
||||
|
||||
}
|
|
@ -1,238 +0,0 @@
|
|||
/*
|
||||
* 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
|
||||
*
|
||||
* http://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.
|
||||
*/
|
||||
package org.apache.commons.math4.fraction;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.text.FieldPosition;
|
||||
import java.text.NumberFormat;
|
||||
import java.text.ParsePosition;
|
||||
|
||||
import org.apache.commons.math4.exception.NullArgumentException;
|
||||
import org.apache.commons.math4.exception.util.LocalizedFormats;
|
||||
|
||||
/**
|
||||
* Formats a BigFraction number in proper format. The number format for each of
|
||||
* the whole number, numerator and, denominator can be configured.
|
||||
* <p>
|
||||
* Minus signs are only allowed in the whole number part - i.e.,
|
||||
* "-3 1/2" is legitimate and denotes -7/2, but "-3 -1/2" is invalid and
|
||||
* will result in a <code>ParseException</code>.</p>
|
||||
*
|
||||
* @since 1.1
|
||||
*/
|
||||
public class ProperBigFractionFormat extends BigFractionFormat {
|
||||
|
||||
/** Serializable version identifier */
|
||||
private static final long serialVersionUID = -6337346779577272307L;
|
||||
|
||||
/** The format used for the whole number. */
|
||||
private NumberFormat wholeFormat;
|
||||
|
||||
/**
|
||||
* Create a proper formatting instance with the default number format for
|
||||
* the whole, numerator, and denominator.
|
||||
*/
|
||||
public ProperBigFractionFormat() {
|
||||
this(getDefaultNumberFormat());
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a proper formatting instance with a custom number format for the
|
||||
* whole, numerator, and denominator.
|
||||
* @param format the custom format for the whole, numerator, and
|
||||
* denominator.
|
||||
*/
|
||||
public ProperBigFractionFormat(final NumberFormat format) {
|
||||
this(format, (NumberFormat)format.clone(), (NumberFormat)format.clone());
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a proper formatting instance with a custom number format for each
|
||||
* of the whole, numerator, and denominator.
|
||||
* @param wholeFormat the custom format for the whole.
|
||||
* @param numeratorFormat the custom format for the numerator.
|
||||
* @param denominatorFormat the custom format for the denominator.
|
||||
*/
|
||||
public ProperBigFractionFormat(final NumberFormat wholeFormat,
|
||||
final NumberFormat numeratorFormat,
|
||||
final NumberFormat denominatorFormat) {
|
||||
super(numeratorFormat, denominatorFormat);
|
||||
setWholeFormat(wholeFormat);
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats a {@link BigFraction} object to produce a string. The BigFraction
|
||||
* is output in proper format.
|
||||
*
|
||||
* @param fraction the object to format.
|
||||
* @param toAppendTo where the text is to be appended
|
||||
* @param pos On input: an alignment field, if desired. On output: the
|
||||
* offsets of the alignment field
|
||||
* @return the value passed in as toAppendTo.
|
||||
*/
|
||||
@Override
|
||||
public StringBuffer format(final BigFraction fraction,
|
||||
final StringBuffer toAppendTo, final FieldPosition pos) {
|
||||
|
||||
pos.setBeginIndex(0);
|
||||
pos.setEndIndex(0);
|
||||
|
||||
BigInteger num = fraction.getNumerator();
|
||||
BigInteger den = fraction.getDenominator();
|
||||
BigInteger whole = num.divide(den);
|
||||
num = num.remainder(den);
|
||||
|
||||
if (!BigInteger.ZERO.equals(whole)) {
|
||||
getWholeFormat().format(whole, toAppendTo, pos);
|
||||
toAppendTo.append(' ');
|
||||
if (num.compareTo(BigInteger.ZERO) < 0) {
|
||||
num = num.negate();
|
||||
}
|
||||
}
|
||||
getNumeratorFormat().format(num, toAppendTo, pos);
|
||||
toAppendTo.append(" / ");
|
||||
getDenominatorFormat().format(den, toAppendTo, pos);
|
||||
|
||||
return toAppendTo;
|
||||
}
|
||||
|
||||
/**
|
||||
* Access the whole format.
|
||||
* @return the whole format.
|
||||
*/
|
||||
public NumberFormat getWholeFormat() {
|
||||
return wholeFormat;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a string to produce a {@link BigFraction} object. This method
|
||||
* expects the string to be formatted as a proper BigFraction.
|
||||
* <p>
|
||||
* Minus signs are only allowed in the whole number part - i.e.,
|
||||
* "-3 1/2" is legitimate and denotes -7/2, but "-3 -1/2" is invalid and
|
||||
* will result in a <code>ParseException</code>.</p>
|
||||
*
|
||||
* @param source the string to parse
|
||||
* @param pos input/ouput parsing parameter.
|
||||
* @return the parsed {@link BigFraction} object.
|
||||
*/
|
||||
@Override
|
||||
public BigFraction parse(final String source, final ParsePosition pos) {
|
||||
// try to parse improper BigFraction
|
||||
BigFraction ret = super.parse(source, pos);
|
||||
if (ret != null) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
final int initialIndex = pos.getIndex();
|
||||
|
||||
// parse whitespace
|
||||
parseAndIgnoreWhitespace(source, pos);
|
||||
|
||||
// parse whole
|
||||
BigInteger whole = parseNextBigInteger(source, pos);
|
||||
if (whole == null) {
|
||||
// invalid integer number
|
||||
// set index back to initial, error index should already be set
|
||||
// character examined.
|
||||
pos.setIndex(initialIndex);
|
||||
return null;
|
||||
}
|
||||
|
||||
// parse whitespace
|
||||
parseAndIgnoreWhitespace(source, pos);
|
||||
|
||||
// parse numerator
|
||||
BigInteger num = parseNextBigInteger(source, pos);
|
||||
if (num == null) {
|
||||
// invalid integer number
|
||||
// set index back to initial, error index should already be set
|
||||
// character examined.
|
||||
pos.setIndex(initialIndex);
|
||||
return null;
|
||||
}
|
||||
|
||||
if (num.compareTo(BigInteger.ZERO) < 0) {
|
||||
// minus signs should be leading, invalid expression
|
||||
pos.setIndex(initialIndex);
|
||||
return null;
|
||||
}
|
||||
|
||||
// parse '/'
|
||||
final int startIndex = pos.getIndex();
|
||||
final char c = parseNextCharacter(source, pos);
|
||||
switch (c) {
|
||||
case 0 :
|
||||
// no '/'
|
||||
// return num as a BigFraction
|
||||
return new BigFraction(num);
|
||||
case '/' :
|
||||
// found '/', continue parsing denominator
|
||||
break;
|
||||
default :
|
||||
// invalid '/'
|
||||
// set index back to initial, error index should be the last
|
||||
// character examined.
|
||||
pos.setIndex(initialIndex);
|
||||
pos.setErrorIndex(startIndex);
|
||||
return null;
|
||||
}
|
||||
|
||||
// parse whitespace
|
||||
parseAndIgnoreWhitespace(source, pos);
|
||||
|
||||
// parse denominator
|
||||
final BigInteger den = parseNextBigInteger(source, pos);
|
||||
if (den == null) {
|
||||
// invalid integer number
|
||||
// set index back to initial, error index should already be set
|
||||
// character examined.
|
||||
pos.setIndex(initialIndex);
|
||||
return null;
|
||||
}
|
||||
|
||||
if (den.compareTo(BigInteger.ZERO) < 0) {
|
||||
// minus signs must be leading, invalid
|
||||
pos.setIndex(initialIndex);
|
||||
return null;
|
||||
}
|
||||
|
||||
boolean wholeIsNeg = whole.compareTo(BigInteger.ZERO) < 0;
|
||||
if (wholeIsNeg) {
|
||||
whole = whole.negate();
|
||||
}
|
||||
num = whole.multiply(den).add(num);
|
||||
if (wholeIsNeg) {
|
||||
num = num.negate();
|
||||
}
|
||||
|
||||
return new BigFraction(num, den);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Modify the whole format.
|
||||
* @param format The new whole format value.
|
||||
* @throws NullArgumentException if {@code format} is {@code null}.
|
||||
*/
|
||||
public void setWholeFormat(final NumberFormat format) {
|
||||
if (format == null) {
|
||||
throw new NullArgumentException(LocalizedFormats.WHOLE_FORMAT);
|
||||
}
|
||||
this.wholeFormat = format;
|
||||
}
|
||||
}
|
|
@ -1,231 +0,0 @@
|
|||
/*
|
||||
* 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
|
||||
*
|
||||
* http://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.
|
||||
*/
|
||||
package org.apache.commons.math4.fraction;
|
||||
|
||||
import java.text.FieldPosition;
|
||||
import java.text.NumberFormat;
|
||||
import java.text.ParsePosition;
|
||||
|
||||
import org.apache.commons.math4.exception.NullArgumentException;
|
||||
import org.apache.commons.math4.exception.util.LocalizedFormats;
|
||||
import org.apache.commons.math4.util.FastMath;
|
||||
import org.apache.commons.math4.util.MathUtils;
|
||||
|
||||
/**
|
||||
* Formats a Fraction number in proper format. The number format for each of
|
||||
* the whole number, numerator and, denominator can be configured.
|
||||
* <p>
|
||||
* Minus signs are only allowed in the whole number part - i.e.,
|
||||
* "-3 1/2" is legitimate and denotes -7/2, but "-3 -1/2" is invalid and
|
||||
* will result in a <code>ParseException</code>.</p>
|
||||
*
|
||||
* @since 1.1
|
||||
*/
|
||||
public class ProperFractionFormat extends FractionFormat {
|
||||
|
||||
/** Serializable version identifier */
|
||||
private static final long serialVersionUID = 760934726031766749L;
|
||||
|
||||
/** The format used for the whole number. */
|
||||
private NumberFormat wholeFormat;
|
||||
|
||||
/**
|
||||
* Create a proper formatting instance with the default number format for
|
||||
* the whole, numerator, and denominator.
|
||||
*/
|
||||
public ProperFractionFormat() {
|
||||
this(getDefaultNumberFormat());
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a proper formatting instance with a custom number format for the
|
||||
* whole, numerator, and denominator.
|
||||
* @param format the custom format for the whole, numerator, and
|
||||
* denominator.
|
||||
*/
|
||||
public ProperFractionFormat(NumberFormat format) {
|
||||
this(format, (NumberFormat)format.clone(), (NumberFormat)format.clone());
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a proper formatting instance with a custom number format for each
|
||||
* of the whole, numerator, and denominator.
|
||||
* @param wholeFormat the custom format for the whole.
|
||||
* @param numeratorFormat the custom format for the numerator.
|
||||
* @param denominatorFormat the custom format for the denominator.
|
||||
*/
|
||||
public ProperFractionFormat(NumberFormat wholeFormat,
|
||||
NumberFormat numeratorFormat,
|
||||
NumberFormat denominatorFormat)
|
||||
{
|
||||
super(numeratorFormat, denominatorFormat);
|
||||
setWholeFormat(wholeFormat);
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats a {@link Fraction} object to produce a string. The fraction
|
||||
* is output in proper format.
|
||||
*
|
||||
* @param fraction the object to format.
|
||||
* @param toAppendTo where the text is to be appended
|
||||
* @param pos On input: an alignment field, if desired. On output: the
|
||||
* offsets of the alignment field
|
||||
* @return the value passed in as toAppendTo.
|
||||
*/
|
||||
@Override
|
||||
public StringBuffer format(Fraction fraction, StringBuffer toAppendTo,
|
||||
FieldPosition pos) {
|
||||
|
||||
pos.setBeginIndex(0);
|
||||
pos.setEndIndex(0);
|
||||
|
||||
int num = fraction.getNumerator();
|
||||
int den = fraction.getDenominator();
|
||||
int whole = num / den;
|
||||
num %= den;
|
||||
|
||||
if (whole != 0) {
|
||||
getWholeFormat().format(whole, toAppendTo, pos);
|
||||
toAppendTo.append(' ');
|
||||
num = FastMath.abs(num);
|
||||
}
|
||||
getNumeratorFormat().format(num, toAppendTo, pos);
|
||||
toAppendTo.append(" / ");
|
||||
getDenominatorFormat().format(den, toAppendTo, pos);
|
||||
|
||||
return toAppendTo;
|
||||
}
|
||||
|
||||
/**
|
||||
* Access the whole format.
|
||||
* @return the whole format.
|
||||
*/
|
||||
public NumberFormat getWholeFormat() {
|
||||
return wholeFormat;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a string to produce a {@link Fraction} object. This method
|
||||
* expects the string to be formatted as a proper fraction.
|
||||
* <p>
|
||||
* Minus signs are only allowed in the whole number part - i.e.,
|
||||
* "-3 1/2" is legitimate and denotes -7/2, but "-3 -1/2" is invalid and
|
||||
* will result in a <code>ParseException</code>.</p>
|
||||
*
|
||||
* @param source the string to parse
|
||||
* @param pos input/ouput parsing parameter.
|
||||
* @return the parsed {@link Fraction} object.
|
||||
*/
|
||||
@Override
|
||||
public Fraction parse(String source, ParsePosition pos) {
|
||||
// try to parse improper fraction
|
||||
Fraction ret = super.parse(source, pos);
|
||||
if (ret != null) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
int initialIndex = pos.getIndex();
|
||||
|
||||
// parse whitespace
|
||||
parseAndIgnoreWhitespace(source, pos);
|
||||
|
||||
// parse whole
|
||||
Number whole = getWholeFormat().parse(source, pos);
|
||||
if (whole == null) {
|
||||
// invalid integer number
|
||||
// set index back to initial, error index should already be set
|
||||
// character examined.
|
||||
pos.setIndex(initialIndex);
|
||||
return null;
|
||||
}
|
||||
|
||||
// parse whitespace
|
||||
parseAndIgnoreWhitespace(source, pos);
|
||||
|
||||
// parse numerator
|
||||
Number num = getNumeratorFormat().parse(source, pos);
|
||||
if (num == null) {
|
||||
// invalid integer number
|
||||
// set index back to initial, error index should already be set
|
||||
// character examined.
|
||||
pos.setIndex(initialIndex);
|
||||
return null;
|
||||
}
|
||||
|
||||
if (num.intValue() < 0) {
|
||||
// minus signs should be leading, invalid expression
|
||||
pos.setIndex(initialIndex);
|
||||
return null;
|
||||
}
|
||||
|
||||
// parse '/'
|
||||
int startIndex = pos.getIndex();
|
||||
char c = parseNextCharacter(source, pos);
|
||||
switch (c) {
|
||||
case 0 :
|
||||
// no '/'
|
||||
// return num as a fraction
|
||||
return new Fraction(num.intValue(), 1);
|
||||
case '/' :
|
||||
// found '/', continue parsing denominator
|
||||
break;
|
||||
default :
|
||||
// invalid '/'
|
||||
// set index back to initial, error index should be the last
|
||||
// character examined.
|
||||
pos.setIndex(initialIndex);
|
||||
pos.setErrorIndex(startIndex);
|
||||
return null;
|
||||
}
|
||||
|
||||
// parse whitespace
|
||||
parseAndIgnoreWhitespace(source, pos);
|
||||
|
||||
// parse denominator
|
||||
Number den = getDenominatorFormat().parse(source, pos);
|
||||
if (den == null) {
|
||||
// invalid integer number
|
||||
// set index back to initial, error index should already be set
|
||||
// character examined.
|
||||
pos.setIndex(initialIndex);
|
||||
return null;
|
||||
}
|
||||
|
||||
if (den.intValue() < 0) {
|
||||
// minus signs must be leading, invalid
|
||||
pos.setIndex(initialIndex);
|
||||
return null;
|
||||
}
|
||||
|
||||
int w = whole.intValue();
|
||||
int n = num.intValue();
|
||||
int d = den.intValue();
|
||||
return new Fraction(((FastMath.abs(w) * d) + n) * MathUtils.copySign(1, w), d);
|
||||
}
|
||||
|
||||
/**
|
||||
* Modify the whole format.
|
||||
* @param format The new whole format value.
|
||||
* @throws NullArgumentException if {@code format} is {@code null}.
|
||||
*/
|
||||
public void setWholeFormat(NumberFormat format) {
|
||||
if (format == null) {
|
||||
throw new NullArgumentException(LocalizedFormats.WHOLE_FORMAT);
|
||||
}
|
||||
this.wholeFormat = format;
|
||||
}
|
||||
}
|
|
@ -1,126 +0,0 @@
|
|||
/*
|
||||
* 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
|
||||
*
|
||||
* http://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.
|
||||
*/
|
||||
package org.apache.commons.math4.primes;
|
||||
|
||||
import org.apache.commons.math4.exception.MathIllegalArgumentException;
|
||||
import org.apache.commons.math4.exception.util.LocalizedFormats;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
|
||||
/**
|
||||
* Methods related to prime numbers in the range of <code>int</code>:
|
||||
* <ul>
|
||||
* <li>primality test</li>
|
||||
* <li>prime number generation</li>
|
||||
* <li>factorization</li>
|
||||
* </ul>
|
||||
*
|
||||
* @since 3.2
|
||||
*/
|
||||
public class Primes {
|
||||
|
||||
/**
|
||||
* Hide utility class.
|
||||
*/
|
||||
private Primes() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Primality test: tells if the argument is a (provable) prime or not.
|
||||
* <p>
|
||||
* It uses the Miller-Rabin probabilistic test in such a way that a result is guaranteed:
|
||||
* it uses the firsts prime numbers as successive base (see Handbook of applied cryptography
|
||||
* by Menezes, table 4.1).
|
||||
*
|
||||
* @param n number to test.
|
||||
* @return true if n is prime. (All numbers < 2 return false).
|
||||
*/
|
||||
public static boolean isPrime(int n) {
|
||||
if (n < 2) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int p : SmallPrimes.PRIMES) {
|
||||
if (0 == (n % p)) {
|
||||
return n == p;
|
||||
}
|
||||
}
|
||||
return SmallPrimes.millerRabinPrimeTest(n);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the smallest prime greater than or equal to n.
|
||||
*
|
||||
* @param n a positive number.
|
||||
* @return the smallest prime greater than or equal to n.
|
||||
* @throws MathIllegalArgumentException if n < 0.
|
||||
*/
|
||||
public static int nextPrime(int n) {
|
||||
if (n < 0) {
|
||||
throw new MathIllegalArgumentException(LocalizedFormats.NUMBER_TOO_SMALL, n, 0);
|
||||
}
|
||||
if (n == 2) {
|
||||
return 2;
|
||||
}
|
||||
n |= 1;//make sure n is odd
|
||||
if (n == 1) {
|
||||
return 2;
|
||||
}
|
||||
|
||||
if (isPrime(n)) {
|
||||
return n;
|
||||
}
|
||||
|
||||
// prepare entry in the +2, +4 loop:
|
||||
// n should not be a multiple of 3
|
||||
final int rem = n % 3;
|
||||
if (0 == rem) { // if n % 3 == 0
|
||||
n += 2; // n % 3 == 2
|
||||
} else if (1 == rem) { // if n % 3 == 1
|
||||
// if (isPrime(n)) return n;
|
||||
n += 4; // n % 3 == 2
|
||||
}
|
||||
while (true) { // this loop skips all multiple of 3
|
||||
if (isPrime(n)) {
|
||||
return n;
|
||||
}
|
||||
n += 2; // n % 3 == 1
|
||||
if (isPrime(n)) {
|
||||
return n;
|
||||
}
|
||||
n += 4; // n % 3 == 2
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Prime factors decomposition
|
||||
*
|
||||
* @param n number to factorize: must be ≥ 2
|
||||
* @return list of prime factors of n
|
||||
* @throws MathIllegalArgumentException if n < 2.
|
||||
*/
|
||||
public static List<Integer> primeFactors(int n) {
|
||||
|
||||
if (n < 2) {
|
||||
throw new MathIllegalArgumentException(LocalizedFormats.NUMBER_TOO_SMALL, n, 2);
|
||||
}
|
||||
return SmallPrimes.trialDivision(n);
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -1,188 +0,0 @@
|
|||
/*
|
||||
* 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
|
||||
*
|
||||
* http://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.
|
||||
*/
|
||||
package org.apache.commons.math4.primes;
|
||||
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.commons.math4.util.FastMath;
|
||||
|
||||
/**
|
||||
* Utility methods to work on primes within the <code>int</code> range.
|
||||
* @since 3.2
|
||||
*/
|
||||
class SmallPrimes {
|
||||
|
||||
/**
|
||||
* The first 512 prime numbers.
|
||||
* <p>
|
||||
* It contains all primes smaller or equal to the cubic square of Integer.MAX_VALUE.
|
||||
* As a result, <code>int</code> numbers which are not reduced by those primes are guaranteed
|
||||
* to be either prime or semi prime.
|
||||
*/
|
||||
public static final int[] PRIMES = {2,
|
||||
3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73,
|
||||
79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179,
|
||||
181, 191, 193, 197, 199, 211, 223, 227, 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 283,
|
||||
293, 307, 311, 313, 317, 331, 337, 347, 349, 353, 359, 367, 373, 379, 383, 389, 397, 401, 409, 419,
|
||||
421, 431, 433, 439, 443, 449, 457, 461, 463, 467, 479, 487, 491, 499, 503, 509, 521, 523, 541, 547,
|
||||
557, 563, 569, 571, 577, 587, 593, 599, 601, 607, 613, 617, 619, 631, 641, 643, 647, 653, 659, 661,
|
||||
673, 677, 683, 691, 701, 709, 719, 727, 733, 739, 743, 751, 757, 761, 769, 773, 787, 797, 809, 811,
|
||||
821, 823, 827, 829, 839, 853, 857, 859, 863, 877, 881, 883, 887, 907, 911, 919, 929, 937, 941, 947,
|
||||
953, 967, 971, 977, 983, 991, 997, 1009, 1013, 1019, 1021, 1031, 1033, 1039, 1049, 1051, 1061, 1063, 1069, 1087,
|
||||
1091, 1093, 1097, 1103, 1109, 1117, 1123, 1129, 1151, 1153, 1163, 1171, 1181, 1187, 1193, 1201, 1213, 1217, 1223, 1229,
|
||||
1231, 1237, 1249, 1259, 1277, 1279, 1283, 1289, 1291, 1297, 1301, 1303, 1307, 1319, 1321, 1327, 1361, 1367, 1373, 1381,
|
||||
1399, 1409, 1423, 1427, 1429, 1433, 1439, 1447, 1451, 1453, 1459, 1471, 1481, 1483, 1487, 1489, 1493, 1499, 1511, 1523,
|
||||
1531, 1543, 1549, 1553, 1559, 1567, 1571, 1579, 1583, 1597, 1601, 1607, 1609, 1613, 1619, 1621, 1627, 1637, 1657, 1663,
|
||||
1667, 1669, 1693, 1697, 1699, 1709, 1721, 1723, 1733, 1741, 1747, 1753, 1759, 1777, 1783, 1787, 1789, 1801, 1811, 1823,
|
||||
1831, 1847, 1861, 1867, 1871, 1873, 1877, 1879, 1889, 1901, 1907, 1913, 1931, 1933, 1949, 1951, 1973, 1979, 1987, 1993,
|
||||
1997, 1999, 2003, 2011, 2017, 2027, 2029, 2039, 2053, 2063, 2069, 2081, 2083, 2087, 2089, 2099, 2111, 2113, 2129, 2131,
|
||||
2137, 2141, 2143, 2153, 2161, 2179, 2203, 2207, 2213, 2221, 2237, 2239, 2243, 2251, 2267, 2269, 2273, 2281, 2287, 2293,
|
||||
2297, 2309, 2311, 2333, 2339, 2341, 2347, 2351, 2357, 2371, 2377, 2381, 2383, 2389, 2393, 2399, 2411, 2417, 2423, 2437,
|
||||
2441, 2447, 2459, 2467, 2473, 2477, 2503, 2521, 2531, 2539, 2543, 2549, 2551, 2557, 2579, 2591, 2593, 2609, 2617, 2621,
|
||||
2633, 2647, 2657, 2659, 2663, 2671, 2677, 2683, 2687, 2689, 2693, 2699, 2707, 2711, 2713, 2719, 2729, 2731, 2741, 2749,
|
||||
2753, 2767, 2777, 2789, 2791, 2797, 2801, 2803, 2819, 2833, 2837, 2843, 2851, 2857, 2861, 2879, 2887, 2897, 2903, 2909,
|
||||
2917, 2927, 2939, 2953, 2957, 2963, 2969, 2971, 2999, 3001, 3011, 3019, 3023, 3037, 3041, 3049, 3061, 3067, 3079, 3083,
|
||||
3089, 3109, 3119, 3121, 3137, 3163, 3167, 3169, 3181, 3187, 3191, 3203, 3209, 3217, 3221, 3229, 3251, 3253, 3257, 3259,
|
||||
3271, 3299, 3301, 3307, 3313, 3319, 3323, 3329, 3331, 3343, 3347, 3359, 3361, 3371, 3373, 3389, 3391, 3407, 3413, 3433,
|
||||
3449, 3457, 3461, 3463, 3467, 3469, 3491, 3499, 3511, 3517, 3527, 3529, 3533, 3539, 3541, 3547, 3557, 3559, 3571, 3581,
|
||||
3583, 3593, 3607, 3613, 3617, 3623, 3631, 3637, 3643, 3659, 3671};
|
||||
|
||||
/** The last number in PRIMES. */
|
||||
public static final int PRIMES_LAST = PRIMES[PRIMES.length - 1];
|
||||
|
||||
/**
|
||||
* Hide utility class.
|
||||
*/
|
||||
private SmallPrimes() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract small factors.
|
||||
* @param n the number to factor, must be > 0.
|
||||
* @param factors the list where to add the factors.
|
||||
* @return the part of n which remains to be factored, it is either a prime or a semi-prime
|
||||
*/
|
||||
public static int smallTrialDivision(int n, final List<Integer> factors) {
|
||||
for (int p : PRIMES) {
|
||||
while (0 == n % p) {
|
||||
n /= p;
|
||||
factors.add(p);
|
||||
}
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract factors in the range <code>PRIME_LAST+2</code> to <code>maxFactors</code>.
|
||||
* @param n the number to factorize, must be >= PRIME_LAST+2 and must not contain any factor below PRIME_LAST+2
|
||||
* @param maxFactor the upper bound of trial division: if it is reached, the method gives up and returns n.
|
||||
* @param factors the list where to add the factors.
|
||||
* @return n or 1 if factorization is completed.
|
||||
*/
|
||||
public static int boundedTrialDivision(int n, int maxFactor, List<Integer> factors) {
|
||||
int f = PRIMES_LAST + 2;
|
||||
// no check is done about n >= f
|
||||
while (f <= maxFactor) {
|
||||
if (0 == n % f) {
|
||||
n /= f;
|
||||
factors.add(f);
|
||||
break;
|
||||
}
|
||||
f += 4;
|
||||
if (0 == n % f) {
|
||||
n /= f;
|
||||
factors.add(f);
|
||||
break;
|
||||
}
|
||||
f += 2;
|
||||
}
|
||||
if (n != 1) {
|
||||
factors.add(n);
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
/**
|
||||
* Factorization by trial division.
|
||||
* @param n the number to factor
|
||||
* @return the list of prime factors of n
|
||||
*/
|
||||
public static List<Integer> trialDivision(int n){
|
||||
final List<Integer> factors = new ArrayList<>(32);
|
||||
n = smallTrialDivision(n, factors);
|
||||
if (1 == n) {
|
||||
return factors;
|
||||
}
|
||||
// here we are sure that n is either a prime or a semi prime
|
||||
final int bound = (int) FastMath.sqrt(n);
|
||||
boundedTrialDivision(n, bound, factors);
|
||||
return factors;
|
||||
}
|
||||
|
||||
/**
|
||||
* Miller-Rabin probabilistic primality test for int type, used in such a way that a result is always guaranteed.
|
||||
* <p>
|
||||
* It uses the prime numbers as successive base therefore it is guaranteed to be always correct.
|
||||
* (see Handbook of applied cryptography by Menezes, table 4.1)
|
||||
*
|
||||
* @param n number to test: an odd integer ≥ 3
|
||||
* @return true if n is prime. false if n is definitely composite.
|
||||
*/
|
||||
public static boolean millerRabinPrimeTest(final int n) {
|
||||
final int nMinus1 = n - 1;
|
||||
final int s = Integer.numberOfTrailingZeros(nMinus1);
|
||||
final int r = nMinus1 >> s;
|
||||
//r must be odd, it is not checked here
|
||||
int t = 1;
|
||||
if (n >= 2047) {
|
||||
t = 2;
|
||||
}
|
||||
if (n >= 1373653) {
|
||||
t = 3;
|
||||
}
|
||||
if (n >= 25326001) {
|
||||
t = 4;
|
||||
} // works up to 3.2 billion, int range stops at 2.7 so we are safe :-)
|
||||
BigInteger br = BigInteger.valueOf(r);
|
||||
BigInteger bn = BigInteger.valueOf(n);
|
||||
|
||||
for (int i = 0; i < t; i++) {
|
||||
BigInteger a = BigInteger.valueOf(SmallPrimes.PRIMES[i]);
|
||||
BigInteger bPow = a.modPow(br, bn);
|
||||
int y = bPow.intValue();
|
||||
if ((1 != y) && (y != nMinus1)) {
|
||||
int j = 1;
|
||||
while ((j <= s - 1) && (nMinus1 != y)) {
|
||||
long square = ((long) y) * y;
|
||||
y = (int) (square % n);
|
||||
if (1 == y) {
|
||||
return false;
|
||||
} // definitely composite
|
||||
j++;
|
||||
}
|
||||
if (nMinus1 != y) {
|
||||
return false;
|
||||
} // definitely composite
|
||||
}
|
||||
}
|
||||
return true; // definitely prime
|
||||
}
|
||||
}
|
||||
|
|
@ -1,20 +0,0 @@
|
|||
/*
|
||||
* 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
|
||||
*
|
||||
* http://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.
|
||||
*/
|
||||
/**
|
||||
* Methods related to prime numbers like primality test, factor decomposition.
|
||||
*/
|
||||
package org.apache.commons.math4.primes;
|
|
@ -1,459 +0,0 @@
|
|||
/*
|
||||
* 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
|
||||
*
|
||||
* http://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.
|
||||
*/
|
||||
package org.apache.commons.math4.complex;
|
||||
|
||||
import java.util.Random;
|
||||
|
||||
import org.apache.commons.math4.complex.Quaternion;
|
||||
import org.apache.commons.math4.exception.DimensionMismatchException;
|
||||
import org.apache.commons.math4.exception.ZeroException;
|
||||
import org.apache.commons.math4.geometry.euclidean.threed.Rotation;
|
||||
import org.apache.commons.math4.geometry.euclidean.threed.RotationConvention;
|
||||
import org.apache.commons.math4.geometry.euclidean.threed.Cartesian3D;
|
||||
import org.apache.commons.math4.util.FastMath;
|
||||
import org.junit.Test;
|
||||
import org.junit.Assert;
|
||||
|
||||
public class QuaternionTest {
|
||||
/** Epsilon for double comparison. */
|
||||
private static final double EPS = Math.ulp(1d);
|
||||
/** Epsilon for double comparison. */
|
||||
private static final double COMPARISON_EPS = 1e-14;
|
||||
|
||||
@Test
|
||||
public final void testAccessors1() {
|
||||
final double q0 = 2;
|
||||
final double q1 = 5.4;
|
||||
final double q2 = 17;
|
||||
final double q3 = 0.0005;
|
||||
final Quaternion q = new Quaternion(q0, q1, q2, q3);
|
||||
|
||||
Assert.assertEquals(q0, q.getQ0(), 0);
|
||||
Assert.assertEquals(q1, q.getQ1(), 0);
|
||||
Assert.assertEquals(q2, q.getQ2(), 0);
|
||||
Assert.assertEquals(q3, q.getQ3(), 0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public final void testAccessors2() {
|
||||
final double q0 = 2;
|
||||
final double q1 = 5.4;
|
||||
final double q2 = 17;
|
||||
final double q3 = 0.0005;
|
||||
final Quaternion q = new Quaternion(q0, q1, q2, q3);
|
||||
|
||||
final double sP = q.getScalarPart();
|
||||
final double[] vP = q.getVectorPart();
|
||||
|
||||
Assert.assertEquals(q0, sP, 0);
|
||||
Assert.assertEquals(q1, vP[0], 0);
|
||||
Assert.assertEquals(q2, vP[1], 0);
|
||||
Assert.assertEquals(q3, vP[2], 0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public final void testAccessors3() {
|
||||
final double q0 = 2;
|
||||
final double q1 = 5.4;
|
||||
final double q2 = 17;
|
||||
final double q3 = 0.0005;
|
||||
final Quaternion q = new Quaternion(q0, new double[] { q1, q2, q3 });
|
||||
|
||||
final double sP = q.getScalarPart();
|
||||
final double[] vP = q.getVectorPart();
|
||||
|
||||
Assert.assertEquals(q0, sP, 0);
|
||||
Assert.assertEquals(q1, vP[0], 0);
|
||||
Assert.assertEquals(q2, vP[1], 0);
|
||||
Assert.assertEquals(q3, vP[2], 0);
|
||||
}
|
||||
|
||||
@Test(expected=DimensionMismatchException.class)
|
||||
public void testWrongDimension() {
|
||||
new Quaternion(new double[] { 1, 2 });
|
||||
}
|
||||
|
||||
@Test
|
||||
public final void testConjugate() {
|
||||
final double q0 = 2;
|
||||
final double q1 = 5.4;
|
||||
final double q2 = 17;
|
||||
final double q3 = 0.0005;
|
||||
final Quaternion q = new Quaternion(q0, q1, q2, q3);
|
||||
|
||||
final Quaternion qConjugate = q.getConjugate();
|
||||
|
||||
Assert.assertEquals(q0, qConjugate.getQ0(), 0);
|
||||
Assert.assertEquals(-q1, qConjugate.getQ1(), 0);
|
||||
Assert.assertEquals(-q2, qConjugate.getQ2(), 0);
|
||||
Assert.assertEquals(-q3, qConjugate.getQ3(), 0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public final void testProductQuaternionQuaternion() {
|
||||
|
||||
// Case : analytic test case
|
||||
|
||||
final Quaternion qA = new Quaternion(1, 0.5, -3, 4);
|
||||
final Quaternion qB = new Quaternion(6, 2, 1, -9);
|
||||
final Quaternion qResult = Quaternion.multiply(qA, qB);
|
||||
|
||||
Assert.assertEquals(44, qResult.getQ0(), EPS);
|
||||
Assert.assertEquals(28, qResult.getQ1(), EPS);
|
||||
Assert.assertEquals(-4.5, qResult.getQ2(), EPS);
|
||||
Assert.assertEquals(21.5, qResult.getQ3(), EPS);
|
||||
|
||||
// comparison with the result given by the formula :
|
||||
// qResult = (scalarA * scalarB - vectorA . vectorB) + (scalarA * vectorB + scalarB * vectorA + vectorA ^
|
||||
// vectorB)
|
||||
|
||||
final Cartesian3D vectorA = new Cartesian3D(qA.getVectorPart());
|
||||
final Cartesian3D vectorB = new Cartesian3D(qB.getVectorPart());
|
||||
final Cartesian3D vectorResult = new Cartesian3D(qResult.getVectorPart());
|
||||
|
||||
final double scalarPartRef = qA.getScalarPart() * qB.getScalarPart() - Cartesian3D.dotProduct(vectorA, vectorB);
|
||||
|
||||
Assert.assertEquals(scalarPartRef, qResult.getScalarPart(), EPS);
|
||||
|
||||
final Cartesian3D vectorPartRef = ((vectorA.scalarMultiply(qB.getScalarPart())).add(vectorB.scalarMultiply(qA
|
||||
.getScalarPart()))).add(Cartesian3D.crossProduct(vectorA, vectorB));
|
||||
final double norm = (vectorResult.subtract(vectorPartRef)).getNorm();
|
||||
|
||||
Assert.assertEquals(0, norm, EPS);
|
||||
|
||||
// Conjugate of the product of two quaternions and product of their conjugates :
|
||||
// Conj(qA * qB) = Conj(qB) * Conj(qA)
|
||||
|
||||
final Quaternion conjugateOfProduct = qB.getConjugate().multiply(qA.getConjugate());
|
||||
final Quaternion productOfConjugate = (qA.multiply(qB)).getConjugate();
|
||||
|
||||
Assert.assertEquals(conjugateOfProduct.getQ0(), productOfConjugate.getQ0(), EPS);
|
||||
Assert.assertEquals(conjugateOfProduct.getQ1(), productOfConjugate.getQ1(), EPS);
|
||||
Assert.assertEquals(conjugateOfProduct.getQ2(), productOfConjugate.getQ2(), EPS);
|
||||
Assert.assertEquals(conjugateOfProduct.getQ3(), productOfConjugate.getQ3(), EPS);
|
||||
}
|
||||
|
||||
@Test
|
||||
public final void testProductQuaternionVector() {
|
||||
|
||||
// Case : Product between a vector and a quaternion : QxV
|
||||
|
||||
final Quaternion quaternion = new Quaternion(4, 7, -1, 2);
|
||||
final double[] vector = {2.0, 1.0, 3.0};
|
||||
final Quaternion qResultQxV = Quaternion.multiply(quaternion, new Quaternion(vector));
|
||||
|
||||
Assert.assertEquals(-19, qResultQxV.getQ0(), EPS);
|
||||
Assert.assertEquals(3, qResultQxV.getQ1(), EPS);
|
||||
Assert.assertEquals(-13, qResultQxV.getQ2(), EPS);
|
||||
Assert.assertEquals(21, qResultQxV.getQ3(), EPS);
|
||||
|
||||
// comparison with the result given by the formula :
|
||||
// qResult = (- vectorQ . vector) + (scalarQ * vector + vectorQ ^ vector)
|
||||
|
||||
final double[] vectorQ = quaternion.getVectorPart();
|
||||
final double[] vectorResultQxV = qResultQxV.getVectorPart();
|
||||
|
||||
final double scalarPartRefQxV = -Cartesian3D.dotProduct(new Cartesian3D(vectorQ), new Cartesian3D(vector));
|
||||
Assert.assertEquals(scalarPartRefQxV, qResultQxV.getScalarPart(), EPS);
|
||||
|
||||
final Cartesian3D vectorPartRefQxV = (new Cartesian3D(vector).scalarMultiply(quaternion.getScalarPart())).add(Cartesian3D
|
||||
.crossProduct(new Cartesian3D(vectorQ), new Cartesian3D(vector)));
|
||||
final double normQxV = (new Cartesian3D(vectorResultQxV).subtract(vectorPartRefQxV)).getNorm();
|
||||
Assert.assertEquals(0, normQxV, EPS);
|
||||
|
||||
// Case : Product between a vector and a quaternion : VxQ
|
||||
|
||||
final Quaternion qResultVxQ = Quaternion.multiply(new Quaternion(vector), quaternion);
|
||||
|
||||
Assert.assertEquals(-19, qResultVxQ.getQ0(), EPS);
|
||||
Assert.assertEquals(13, qResultVxQ.getQ1(), EPS);
|
||||
Assert.assertEquals(21, qResultVxQ.getQ2(), EPS);
|
||||
Assert.assertEquals(3, qResultVxQ.getQ3(), EPS);
|
||||
|
||||
final double[] vectorResultVxQ = qResultVxQ.getVectorPart();
|
||||
|
||||
// comparison with the result given by the formula :
|
||||
// qResult = (- vector . vectorQ) + (scalarQ * vector + vector ^ vectorQ)
|
||||
|
||||
final double scalarPartRefVxQ = -Cartesian3D.dotProduct(new Cartesian3D(vectorQ), new Cartesian3D(vector));
|
||||
Assert.assertEquals(scalarPartRefVxQ, qResultVxQ.getScalarPart(), EPS);
|
||||
|
||||
final Cartesian3D vectorPartRefVxQ = (new Cartesian3D(vector).scalarMultiply(quaternion.getScalarPart())).add(Cartesian3D
|
||||
.crossProduct(new Cartesian3D(vector), new Cartesian3D(vectorQ)));
|
||||
final double normVxQ = (new Cartesian3D(vectorResultVxQ).subtract(vectorPartRefVxQ)).getNorm();
|
||||
Assert.assertEquals(0, normVxQ, EPS);
|
||||
}
|
||||
|
||||
@Test
|
||||
public final void testDotProductQuaternionQuaternion() {
|
||||
// expected output
|
||||
final double expected = -6.;
|
||||
// inputs
|
||||
final Quaternion q1 = new Quaternion(1, 2, 2, 1);
|
||||
final Quaternion q2 = new Quaternion(3, -2, -1, -3);
|
||||
|
||||
final double actual1 = Quaternion.dotProduct(q1, q2);
|
||||
final double actual2 = q1.dotProduct(q2);
|
||||
|
||||
Assert.assertEquals(expected, actual1, EPS);
|
||||
Assert.assertEquals(expected, actual2, EPS);
|
||||
}
|
||||
|
||||
@Test
|
||||
public final void testScalarMultiplyDouble() {
|
||||
// expected outputs
|
||||
final double w = 1.6;
|
||||
final double x = -4.8;
|
||||
final double y = 11.20;
|
||||
final double z = 2.56;
|
||||
// inputs
|
||||
final Quaternion q1 = new Quaternion(0.5, -1.5, 3.5, 0.8);
|
||||
final double a = 3.2;
|
||||
|
||||
final Quaternion q = q1.multiply(a);
|
||||
|
||||
Assert.assertEquals(w, q.getQ0(), COMPARISON_EPS);
|
||||
Assert.assertEquals(x, q.getQ1(), COMPARISON_EPS);
|
||||
Assert.assertEquals(y, q.getQ2(), COMPARISON_EPS);
|
||||
Assert.assertEquals(z, q.getQ3(), COMPARISON_EPS);
|
||||
}
|
||||
|
||||
@Test
|
||||
public final void testAddQuaternionQuaternion() {
|
||||
// expected outputs
|
||||
final double w = 4;
|
||||
final double x = -1;
|
||||
final double y = 2;
|
||||
final double z = -4;
|
||||
// inputs
|
||||
final Quaternion q1 = new Quaternion(1., 2., -2., -1.);
|
||||
final Quaternion q2 = new Quaternion(3., -3., 4., -3.);
|
||||
|
||||
final Quaternion qa = Quaternion.add(q1, q2);
|
||||
final Quaternion qb = q1.add(q2);
|
||||
|
||||
Assert.assertEquals(w, qa.getQ0(), EPS);
|
||||
Assert.assertEquals(x, qa.getQ1(), EPS);
|
||||
Assert.assertEquals(y, qa.getQ2(), EPS);
|
||||
Assert.assertEquals(z, qa.getQ3(), EPS);
|
||||
|
||||
Assert.assertEquals(w, qb.getQ0(), EPS);
|
||||
Assert.assertEquals(x, qb.getQ1(), EPS);
|
||||
Assert.assertEquals(y, qb.getQ2(), EPS);
|
||||
Assert.assertEquals(z, qb.getQ3(), EPS);
|
||||
}
|
||||
|
||||
@Test
|
||||
public final void testSubtractQuaternionQuaternion() {
|
||||
// expected outputs
|
||||
final double w = -2.;
|
||||
final double x = 5.;
|
||||
final double y = -6.;
|
||||
final double z = 2.;
|
||||
// inputs
|
||||
final Quaternion q1 = new Quaternion(1., 2., -2., -1.);
|
||||
final Quaternion q2 = new Quaternion(3., -3., 4., -3.);
|
||||
|
||||
final Quaternion qa = Quaternion.subtract(q1, q2);
|
||||
final Quaternion qb = q1.subtract(q2);
|
||||
|
||||
Assert.assertEquals(w, qa.getQ0(), EPS);
|
||||
Assert.assertEquals(x, qa.getQ1(), EPS);
|
||||
Assert.assertEquals(y, qa.getQ2(), EPS);
|
||||
Assert.assertEquals(z, qa.getQ3(), EPS);
|
||||
|
||||
Assert.assertEquals(w, qb.getQ0(), EPS);
|
||||
Assert.assertEquals(x, qb.getQ1(), EPS);
|
||||
Assert.assertEquals(y, qb.getQ2(), EPS);
|
||||
Assert.assertEquals(z, qb.getQ3(), EPS);
|
||||
}
|
||||
|
||||
@Test
|
||||
public final void testNorm() {
|
||||
|
||||
final double q0 = 2;
|
||||
final double q1 = 1;
|
||||
final double q2 = -4;
|
||||
final double q3 = 3;
|
||||
final Quaternion q = new Quaternion(q0, q1, q2, q3);
|
||||
|
||||
final double norm = q.getNorm();
|
||||
|
||||
Assert.assertEquals(FastMath.sqrt(30), norm, 0);
|
||||
|
||||
final double normSquareRef = Quaternion.multiply(q, q.getConjugate()).getScalarPart();
|
||||
Assert.assertEquals(FastMath.sqrt(normSquareRef), norm, 0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public final void testNormalize() {
|
||||
|
||||
final Quaternion q = new Quaternion(2, 1, -4, -2);
|
||||
|
||||
final Quaternion versor = q.normalize();
|
||||
|
||||
Assert.assertEquals(2.0 / 5.0, versor.getQ0(), 0);
|
||||
Assert.assertEquals(1.0 / 5.0, versor.getQ1(), 0);
|
||||
Assert.assertEquals(-4.0 / 5.0, versor.getQ2(), 0);
|
||||
Assert.assertEquals(-2.0 / 5.0, versor.getQ3(), 0);
|
||||
|
||||
Assert.assertEquals(1, versor.getNorm(), 0);
|
||||
}
|
||||
|
||||
@Test(expected=ZeroException.class)
|
||||
public final void testNormalizeFail() {
|
||||
final Quaternion zeroQ = new Quaternion(0, 0, 0, 0);
|
||||
zeroQ.normalize();
|
||||
}
|
||||
|
||||
@Test
|
||||
public final void testObjectEquals() {
|
||||
final double one = 1;
|
||||
final Quaternion q1 = new Quaternion(one, one, one, one);
|
||||
Assert.assertTrue(q1.equals(q1));
|
||||
|
||||
final Quaternion q2 = new Quaternion(one, one, one, one);
|
||||
Assert.assertTrue(q2.equals(q1));
|
||||
|
||||
final Quaternion q3 = new Quaternion(one, FastMath.nextUp(one), one, one);
|
||||
Assert.assertFalse(q3.equals(q1));
|
||||
}
|
||||
|
||||
@Test
|
||||
public final void testQuaternionEquals() {
|
||||
final double inc = 1e-5;
|
||||
final Quaternion q1 = new Quaternion(2, 1, -4, -2);
|
||||
final Quaternion q2 = new Quaternion(q1.getQ0() + inc, q1.getQ1(), q1.getQ2(), q1.getQ3());
|
||||
final Quaternion q3 = new Quaternion(q1.getQ0(), q1.getQ1() + inc, q1.getQ2(), q1.getQ3());
|
||||
final Quaternion q4 = new Quaternion(q1.getQ0(), q1.getQ1(), q1.getQ2() + inc, q1.getQ3());
|
||||
final Quaternion q5 = new Quaternion(q1.getQ0(), q1.getQ1(), q1.getQ2(), q1.getQ3() + inc);
|
||||
|
||||
Assert.assertFalse(q1.equals(q2, 0.9 * inc));
|
||||
Assert.assertFalse(q1.equals(q3, 0.9 * inc));
|
||||
Assert.assertFalse(q1.equals(q4, 0.9 * inc));
|
||||
Assert.assertFalse(q1.equals(q5, 0.9 * inc));
|
||||
|
||||
Assert.assertTrue(q1.equals(q2, 1.1 * inc));
|
||||
Assert.assertTrue(q1.equals(q3, 1.1 * inc));
|
||||
Assert.assertTrue(q1.equals(q4, 1.1 * inc));
|
||||
Assert.assertTrue(q1.equals(q5, 1.1 * inc));
|
||||
}
|
||||
|
||||
@Test
|
||||
public final void testQuaternionEquals2() {
|
||||
final Quaternion q1 = new Quaternion(1, 4, 2, 3);
|
||||
final double gap = 1e-5;
|
||||
final Quaternion q2 = new Quaternion(1 + gap, 4 + gap, 2 + gap, 3 + gap);
|
||||
|
||||
Assert.assertTrue(q1.equals(q2, 10 * gap));
|
||||
Assert.assertFalse(q1.equals(q2, gap));
|
||||
Assert.assertFalse(q1.equals(q2, gap / 10));
|
||||
}
|
||||
|
||||
@Test
|
||||
public final void testIsUnitQuaternion() {
|
||||
final Random r = new Random(48);
|
||||
final int numberOfTrials = 1000;
|
||||
for (int i = 0; i < numberOfTrials; i++) {
|
||||
final Quaternion q1 = new Quaternion(r.nextDouble(), r.nextDouble(), r.nextDouble(), r.nextDouble());
|
||||
final Quaternion q2 = q1.normalize();
|
||||
Assert.assertTrue(q2.isUnitQuaternion(COMPARISON_EPS));
|
||||
}
|
||||
|
||||
final Quaternion q = new Quaternion(1, 1, 1, 1);
|
||||
Assert.assertFalse(q.isUnitQuaternion(COMPARISON_EPS));
|
||||
}
|
||||
|
||||
@Test
|
||||
public final void testIsPureQuaternion() {
|
||||
final Quaternion q1 = new Quaternion(0, 5, 4, 8);
|
||||
Assert.assertTrue(q1.isPureQuaternion(EPS));
|
||||
|
||||
final Quaternion q2 = new Quaternion(0 - EPS, 5, 4, 8);
|
||||
Assert.assertTrue(q2.isPureQuaternion(EPS));
|
||||
|
||||
final Quaternion q3 = new Quaternion(0 - 1.1 * EPS, 5, 4, 8);
|
||||
Assert.assertFalse(q3.isPureQuaternion(EPS));
|
||||
|
||||
final Random r = new Random(48);
|
||||
final double[] v = {r.nextDouble(), r.nextDouble(), r.nextDouble()};
|
||||
final Quaternion q4 = new Quaternion(v);
|
||||
Assert.assertTrue(q4.isPureQuaternion(0));
|
||||
|
||||
final Quaternion q5 = new Quaternion(0, v);
|
||||
Assert.assertTrue(q5.isPureQuaternion(0));
|
||||
}
|
||||
|
||||
@Test
|
||||
public final void testPolarForm() {
|
||||
final Random r = new Random(48);
|
||||
final int numberOfTrials = 1000;
|
||||
for (int i = 0; i < numberOfTrials; i++) {
|
||||
final Quaternion q = new Quaternion(2 * (r.nextDouble() - 0.5), 2 * (r.nextDouble() - 0.5),
|
||||
2 * (r.nextDouble() - 0.5), 2 * (r.nextDouble() - 0.5));
|
||||
final Quaternion qP = q.getPositivePolarForm();
|
||||
|
||||
Assert.assertTrue(qP.isUnitQuaternion(COMPARISON_EPS));
|
||||
Assert.assertTrue(qP.getQ0() >= 0);
|
||||
|
||||
final Rotation rot = new Rotation(q.getQ0(), q.getQ1(), q.getQ2(), q.getQ3(), true);
|
||||
final Rotation rotP = new Rotation(qP.getQ0(), qP.getQ1(), qP.getQ2(), qP.getQ3(), true);
|
||||
|
||||
Assert.assertEquals(rot.getAngle(), rotP.getAngle(), COMPARISON_EPS);
|
||||
Assert.assertEquals(rot.getAxis(RotationConvention.VECTOR_OPERATOR).getX(),
|
||||
rot.getAxis(RotationConvention.VECTOR_OPERATOR).getX(),
|
||||
COMPARISON_EPS);
|
||||
Assert.assertEquals(rot.getAxis(RotationConvention.VECTOR_OPERATOR).getY(),
|
||||
rot.getAxis(RotationConvention.VECTOR_OPERATOR).getY(),
|
||||
COMPARISON_EPS);
|
||||
Assert.assertEquals(rot.getAxis(RotationConvention.VECTOR_OPERATOR).getZ(),
|
||||
rot.getAxis(RotationConvention.VECTOR_OPERATOR).getZ(),
|
||||
COMPARISON_EPS);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public final void testGetInverse() {
|
||||
final Quaternion q = new Quaternion(1.5, 4, 2, -2.5);
|
||||
|
||||
final Quaternion inverseQ = q.getInverse();
|
||||
Assert.assertEquals(1.5 / 28.5, inverseQ.getQ0(), 0);
|
||||
Assert.assertEquals(-4.0 / 28.5, inverseQ.getQ1(), 0);
|
||||
Assert.assertEquals(-2.0 / 28.5, inverseQ.getQ2(), 0);
|
||||
Assert.assertEquals(2.5 / 28.5, inverseQ.getQ3(), 0);
|
||||
|
||||
final Quaternion product = Quaternion.multiply(inverseQ, q);
|
||||
Assert.assertEquals(1, product.getQ0(), EPS);
|
||||
Assert.assertEquals(0, product.getQ1(), EPS);
|
||||
Assert.assertEquals(0, product.getQ2(), EPS);
|
||||
Assert.assertEquals(0, product.getQ3(), EPS);
|
||||
|
||||
final Quaternion qNul = new Quaternion(0, 0, 0, 0);
|
||||
try {
|
||||
final Quaternion inverseQNul = qNul.getInverse();
|
||||
Assert.fail("expecting ZeroException but got : " + inverseQNul);
|
||||
} catch (ZeroException ex) {
|
||||
// expected
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public final void testToString() {
|
||||
final Quaternion q = new Quaternion(1, 2, 3, 4);
|
||||
Assert.assertTrue(q.toString().equals("[1.0 2.0 3.0 4.0]"));
|
||||
}
|
||||
}
|
|
@ -1,102 +0,0 @@
|
|||
/*
|
||||
* 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
|
||||
*
|
||||
* http://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.
|
||||
*/
|
||||
package org.apache.commons.math4.complex;
|
||||
|
||||
import org.apache.commons.math4.complex.RootsOfUnity;
|
||||
import org.apache.commons.math4.exception.MathIllegalStateException;
|
||||
import org.apache.commons.math4.exception.ZeroException;
|
||||
import org.apache.commons.math4.util.FastMath;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
|
||||
/**
|
||||
* Unit tests for the {@link RootsOfUnity} class.
|
||||
*
|
||||
*/
|
||||
public class RootsOfUnityTest {
|
||||
|
||||
@Test(expected = MathIllegalStateException.class)
|
||||
public void testMathIllegalState1() {
|
||||
final RootsOfUnity roots = new RootsOfUnity();
|
||||
roots.getReal(0);
|
||||
}
|
||||
|
||||
@Test(expected = MathIllegalStateException.class)
|
||||
public void testMathIllegalState2() {
|
||||
final RootsOfUnity roots = new RootsOfUnity();
|
||||
roots.getImaginary(0);
|
||||
}
|
||||
|
||||
@Test(expected = MathIllegalStateException.class)
|
||||
public void testMathIllegalState3() {
|
||||
final RootsOfUnity roots = new RootsOfUnity();
|
||||
roots.isCounterClockWise();
|
||||
}
|
||||
|
||||
@Test(expected = ZeroException.class)
|
||||
public void testZeroNumberOfRoots() {
|
||||
final RootsOfUnity roots = new RootsOfUnity();
|
||||
roots.computeRoots(0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetNumberOfRoots() {
|
||||
final RootsOfUnity roots = new RootsOfUnity();
|
||||
Assert.assertEquals("", 0, roots.getNumberOfRoots());
|
||||
roots.computeRoots(5);
|
||||
Assert.assertEquals("", 5, roots.getNumberOfRoots());
|
||||
/*
|
||||
* Testing -5 right after 5 is important, as the roots in this case are
|
||||
* not recomputed.
|
||||
*/
|
||||
roots.computeRoots(-5);
|
||||
Assert.assertEquals("", 5, roots.getNumberOfRoots());
|
||||
roots.computeRoots(6);
|
||||
Assert.assertEquals("", 6, roots.getNumberOfRoots());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testComputeRoots() {
|
||||
final RootsOfUnity roots = new RootsOfUnity();
|
||||
for (int n = -10; n < 11; n++) {
|
||||
/*
|
||||
* Testing -n right after n is important, as the roots in this case
|
||||
* are not recomputed.
|
||||
*/
|
||||
if (n != 0) {
|
||||
roots.computeRoots(n);
|
||||
doTestComputeRoots(roots);
|
||||
roots.computeRoots(-n);
|
||||
doTestComputeRoots(roots);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void doTestComputeRoots(final RootsOfUnity roots) {
|
||||
final int n = roots.isCounterClockWise() ? roots.getNumberOfRoots() :
|
||||
-roots.getNumberOfRoots();
|
||||
final double tol = 10 * Math.ulp(1.0);
|
||||
for (int k = 0; k < n; k++) {
|
||||
final double t = 2.0 * FastMath.PI * k / n;
|
||||
@SuppressWarnings("boxing")
|
||||
final String msg = String.format("n = %d, k = %d", n, k);
|
||||
Assert.assertEquals(msg, FastMath.cos(t), roots.getReal(k), tol);
|
||||
Assert.assertEquals(msg, FastMath.sin(t), roots.getImaginary(k), tol);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,335 +0,0 @@
|
|||
/*
|
||||
* 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
|
||||
*
|
||||
* http://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.
|
||||
*/
|
||||
|
||||
package org.apache.commons.math4.fraction;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.math.BigInteger;
|
||||
import java.text.NumberFormat;
|
||||
import java.util.Locale;
|
||||
|
||||
import org.apache.commons.math4.exception.MathParseException;
|
||||
import org.apache.commons.math4.fraction.BigFraction;
|
||||
import org.apache.commons.math4.fraction.BigFractionFormat;
|
||||
import org.apache.commons.math4.fraction.ProperBigFractionFormat;
|
||||
import org.apache.commons.math4.util.FastMath;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
|
||||
public class BigFractionFormatTest {
|
||||
|
||||
BigFractionFormat properFormat = null;
|
||||
BigFractionFormat improperFormat = null;
|
||||
|
||||
protected Locale getLocale() {
|
||||
return Locale.getDefault();
|
||||
}
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
properFormat = BigFractionFormat.getProperInstance(getLocale());
|
||||
improperFormat = BigFractionFormat.getImproperInstance(getLocale());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFormat() {
|
||||
BigFraction c = new BigFraction(1, 2);
|
||||
String expected = "1 / 2";
|
||||
|
||||
String actual = properFormat.format(c);
|
||||
Assert.assertEquals(expected, actual);
|
||||
|
||||
actual = improperFormat.format(c);
|
||||
Assert.assertEquals(expected, actual);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFormatNegative() {
|
||||
BigFraction c = new BigFraction(-1, 2);
|
||||
String expected = "-1 / 2";
|
||||
|
||||
String actual = properFormat.format(c);
|
||||
Assert.assertEquals(expected, actual);
|
||||
|
||||
actual = improperFormat.format(c);
|
||||
Assert.assertEquals(expected, actual);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFormatZero() {
|
||||
BigFraction c = new BigFraction(0, 1);
|
||||
String expected = "0 / 1";
|
||||
|
||||
String actual = properFormat.format(c);
|
||||
Assert.assertEquals(expected, actual);
|
||||
|
||||
actual = improperFormat.format(c);
|
||||
Assert.assertEquals(expected, actual);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFormatImproper() {
|
||||
BigFraction c = new BigFraction(5, 3);
|
||||
|
||||
String actual = properFormat.format(c);
|
||||
Assert.assertEquals("1 2 / 3", actual);
|
||||
|
||||
actual = improperFormat.format(c);
|
||||
Assert.assertEquals("5 / 3", actual);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFormatImproperNegative() {
|
||||
BigFraction c = new BigFraction(-5, 3);
|
||||
|
||||
String actual = properFormat.format(c);
|
||||
Assert.assertEquals("-1 2 / 3", actual);
|
||||
|
||||
actual = improperFormat.format(c);
|
||||
Assert.assertEquals("-5 / 3", actual);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParse() {
|
||||
String source = "1 / 2";
|
||||
|
||||
{
|
||||
BigFraction c = properFormat.parse(source);
|
||||
Assert.assertNotNull(c);
|
||||
Assert.assertEquals(BigInteger.ONE, c.getNumerator());
|
||||
Assert.assertEquals(BigInteger.valueOf(2l), c.getDenominator());
|
||||
|
||||
c = improperFormat.parse(source);
|
||||
Assert.assertNotNull(c);
|
||||
Assert.assertEquals(BigInteger.ONE, c.getNumerator());
|
||||
Assert.assertEquals(BigInteger.valueOf(2l), c.getDenominator());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParseInteger() {
|
||||
String source = "10";
|
||||
{
|
||||
BigFraction c = properFormat.parse(source);
|
||||
Assert.assertNotNull(c);
|
||||
Assert.assertEquals(BigInteger.TEN, c.getNumerator());
|
||||
Assert.assertEquals(BigInteger.ONE, c.getDenominator());
|
||||
}
|
||||
{
|
||||
BigFraction c = improperFormat.parse(source);
|
||||
Assert.assertNotNull(c);
|
||||
Assert.assertEquals(BigInteger.TEN, c.getNumerator());
|
||||
Assert.assertEquals(BigInteger.ONE, c.getDenominator());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParseInvalid() {
|
||||
String source = "a";
|
||||
String msg = "should not be able to parse '10 / a'.";
|
||||
try {
|
||||
properFormat.parse(source);
|
||||
Assert.fail(msg);
|
||||
} catch (MathParseException ex) {
|
||||
// success
|
||||
}
|
||||
try {
|
||||
improperFormat.parse(source);
|
||||
Assert.fail(msg);
|
||||
} catch (MathParseException ex) {
|
||||
// success
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParseInvalidDenominator() {
|
||||
String source = "10 / a";
|
||||
String msg = "should not be able to parse '10 / a'.";
|
||||
try {
|
||||
properFormat.parse(source);
|
||||
Assert.fail(msg);
|
||||
} catch (MathParseException ex) {
|
||||
// success
|
||||
}
|
||||
try {
|
||||
improperFormat.parse(source);
|
||||
Assert.fail(msg);
|
||||
} catch (MathParseException ex) {
|
||||
// success
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParseNegative() {
|
||||
|
||||
{
|
||||
String source = "-1 / 2";
|
||||
BigFraction c = properFormat.parse(source);
|
||||
Assert.assertNotNull(c);
|
||||
Assert.assertEquals(-1, c.getNumeratorAsInt());
|
||||
Assert.assertEquals(2, c.getDenominatorAsInt());
|
||||
|
||||
c = improperFormat.parse(source);
|
||||
Assert.assertNotNull(c);
|
||||
Assert.assertEquals(-1, c.getNumeratorAsInt());
|
||||
Assert.assertEquals(2, c.getDenominatorAsInt());
|
||||
|
||||
source = "1 / -2";
|
||||
c = properFormat.parse(source);
|
||||
Assert.assertNotNull(c);
|
||||
Assert.assertEquals(-1, c.getNumeratorAsInt());
|
||||
Assert.assertEquals(2, c.getDenominatorAsInt());
|
||||
|
||||
c = improperFormat.parse(source);
|
||||
Assert.assertNotNull(c);
|
||||
Assert.assertEquals(-1, c.getNumeratorAsInt());
|
||||
Assert.assertEquals(2, c.getDenominatorAsInt());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParseProper() {
|
||||
String source = "1 2 / 3";
|
||||
|
||||
{
|
||||
BigFraction c = properFormat.parse(source);
|
||||
Assert.assertNotNull(c);
|
||||
Assert.assertEquals(5, c.getNumeratorAsInt());
|
||||
Assert.assertEquals(3, c.getDenominatorAsInt());
|
||||
}
|
||||
|
||||
try {
|
||||
improperFormat.parse(source);
|
||||
Assert.fail("invalid improper fraction.");
|
||||
} catch (MathParseException ex) {
|
||||
// success
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParseProperNegative() {
|
||||
String source = "-1 2 / 3";
|
||||
{
|
||||
BigFraction c = properFormat.parse(source);
|
||||
Assert.assertNotNull(c);
|
||||
Assert.assertEquals(-5, c.getNumeratorAsInt());
|
||||
Assert.assertEquals(3, c.getDenominatorAsInt());
|
||||
}
|
||||
|
||||
try {
|
||||
improperFormat.parse(source);
|
||||
Assert.fail("invalid improper fraction.");
|
||||
} catch (MathParseException ex) {
|
||||
// success
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParseProperInvalidMinus() {
|
||||
String source = "2 -2 / 3";
|
||||
try {
|
||||
properFormat.parse(source);
|
||||
Assert.fail("invalid minus in improper fraction.");
|
||||
} catch (MathParseException ex) {
|
||||
// expected
|
||||
}
|
||||
source = "2 2 / -3";
|
||||
try {
|
||||
properFormat.parse(source);
|
||||
Assert.fail("invalid minus in improper fraction.");
|
||||
} catch (MathParseException ex) {
|
||||
// expected
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParseBig() {
|
||||
BigFraction f1 =
|
||||
improperFormat.parse("167213075789791382630275400487886041651764456874403" +
|
||||
" / " +
|
||||
"53225575123090058458126718248444563466137046489291");
|
||||
Assert.assertEquals(FastMath.PI, f1.doubleValue(), 0.0);
|
||||
BigFraction f2 =
|
||||
properFormat.parse("3 " +
|
||||
"7536350420521207255895245742552351253353317406530" +
|
||||
" / " +
|
||||
"53225575123090058458126718248444563466137046489291");
|
||||
Assert.assertEquals(FastMath.PI, f2.doubleValue(), 0.0);
|
||||
Assert.assertEquals(f1, f2);
|
||||
BigDecimal pi =
|
||||
new BigDecimal("3.141592653589793238462643383279502884197169399375105820974944592307816406286208998628034825342117068");
|
||||
Assert.assertEquals(pi, f1.bigDecimalValue(99, BigDecimal.ROUND_HALF_EVEN));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNumeratorFormat() {
|
||||
NumberFormat old = properFormat.getNumeratorFormat();
|
||||
NumberFormat nf = NumberFormat.getInstance();
|
||||
nf.setParseIntegerOnly(true);
|
||||
properFormat.setNumeratorFormat(nf);
|
||||
Assert.assertEquals(nf, properFormat.getNumeratorFormat());
|
||||
properFormat.setNumeratorFormat(old);
|
||||
|
||||
old = improperFormat.getNumeratorFormat();
|
||||
nf = NumberFormat.getInstance();
|
||||
nf.setParseIntegerOnly(true);
|
||||
improperFormat.setNumeratorFormat(nf);
|
||||
Assert.assertEquals(nf, improperFormat.getNumeratorFormat());
|
||||
improperFormat.setNumeratorFormat(old);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDenominatorFormat() {
|
||||
NumberFormat old = properFormat.getDenominatorFormat();
|
||||
NumberFormat nf = NumberFormat.getInstance();
|
||||
nf.setParseIntegerOnly(true);
|
||||
properFormat.setDenominatorFormat(nf);
|
||||
Assert.assertEquals(nf, properFormat.getDenominatorFormat());
|
||||
properFormat.setDenominatorFormat(old);
|
||||
|
||||
old = improperFormat.getDenominatorFormat();
|
||||
nf = NumberFormat.getInstance();
|
||||
nf.setParseIntegerOnly(true);
|
||||
improperFormat.setDenominatorFormat(nf);
|
||||
Assert.assertEquals(nf, improperFormat.getDenominatorFormat());
|
||||
improperFormat.setDenominatorFormat(old);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWholeFormat() {
|
||||
ProperBigFractionFormat format = (ProperBigFractionFormat)properFormat;
|
||||
|
||||
NumberFormat old = format.getWholeFormat();
|
||||
NumberFormat nf = NumberFormat.getInstance();
|
||||
nf.setParseIntegerOnly(true);
|
||||
format.setWholeFormat(nf);
|
||||
Assert.assertEquals(nf, format.getWholeFormat());
|
||||
format.setWholeFormat(old);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLongFormat() {
|
||||
Assert.assertEquals("10 / 1", improperFormat.format(10l));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDoubleFormat() {
|
||||
Assert.assertEquals("1 / 16", improperFormat.format(0.0625));
|
||||
}
|
||||
}
|
|
@ -1,354 +0,0 @@
|
|||
/*
|
||||
* 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
|
||||
*
|
||||
* http://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.
|
||||
*/
|
||||
|
||||
package org.apache.commons.math4.fraction;
|
||||
|
||||
import java.text.NumberFormat;
|
||||
import java.util.Locale;
|
||||
|
||||
import org.apache.commons.math4.exception.MathParseException;
|
||||
import org.apache.commons.math4.fraction.Fraction;
|
||||
import org.apache.commons.math4.fraction.FractionFormat;
|
||||
import org.apache.commons.math4.fraction.ProperFractionFormat;
|
||||
import org.apache.commons.math4.util.FastMath;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
|
||||
public class FractionFormatTest {
|
||||
|
||||
FractionFormat properFormat = null;
|
||||
FractionFormat improperFormat = null;
|
||||
|
||||
protected Locale getLocale() {
|
||||
return Locale.getDefault();
|
||||
}
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
properFormat = FractionFormat.getProperInstance(getLocale());
|
||||
improperFormat = FractionFormat.getImproperInstance(getLocale());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFormat() {
|
||||
Fraction c = new Fraction(1, 2);
|
||||
String expected = "1 / 2";
|
||||
|
||||
String actual = properFormat.format(c);
|
||||
Assert.assertEquals(expected, actual);
|
||||
|
||||
actual = improperFormat.format(c);
|
||||
Assert.assertEquals(expected, actual);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFormatNegative() {
|
||||
Fraction c = new Fraction(-1, 2);
|
||||
String expected = "-1 / 2";
|
||||
|
||||
String actual = properFormat.format(c);
|
||||
Assert.assertEquals(expected, actual);
|
||||
|
||||
actual = improperFormat.format(c);
|
||||
Assert.assertEquals(expected, actual);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFormatZero() {
|
||||
Fraction c = new Fraction(0, 1);
|
||||
String expected = "0 / 1";
|
||||
|
||||
String actual = properFormat.format(c);
|
||||
Assert.assertEquals(expected, actual);
|
||||
|
||||
actual = improperFormat.format(c);
|
||||
Assert.assertEquals(expected, actual);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFormatImproper() {
|
||||
Fraction c = new Fraction(5, 3);
|
||||
|
||||
String actual = properFormat.format(c);
|
||||
Assert.assertEquals("1 2 / 3", actual);
|
||||
|
||||
actual = improperFormat.format(c);
|
||||
Assert.assertEquals("5 / 3", actual);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFormatImproperNegative() {
|
||||
Fraction c = new Fraction(-5, 3);
|
||||
|
||||
String actual = properFormat.format(c);
|
||||
Assert.assertEquals("-1 2 / 3", actual);
|
||||
|
||||
actual = improperFormat.format(c);
|
||||
Assert.assertEquals("-5 / 3", actual);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParse() {
|
||||
String source = "1 / 2";
|
||||
|
||||
try {
|
||||
Fraction c = properFormat.parse(source);
|
||||
Assert.assertNotNull(c);
|
||||
Assert.assertEquals(1, c.getNumerator());
|
||||
Assert.assertEquals(2, c.getDenominator());
|
||||
|
||||
c = improperFormat.parse(source);
|
||||
Assert.assertNotNull(c);
|
||||
Assert.assertEquals(1, c.getNumerator());
|
||||
Assert.assertEquals(2, c.getDenominator());
|
||||
} catch (MathParseException ex) {
|
||||
Assert.fail(ex.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParseInteger() {
|
||||
String source = "10";
|
||||
{
|
||||
Fraction c = properFormat.parse(source);
|
||||
Assert.assertNotNull(c);
|
||||
Assert.assertEquals(10, c.getNumerator());
|
||||
Assert.assertEquals(1, c.getDenominator());
|
||||
}
|
||||
{
|
||||
Fraction c = improperFormat.parse(source);
|
||||
Assert.assertNotNull(c);
|
||||
Assert.assertEquals(10, c.getNumerator());
|
||||
Assert.assertEquals(1, c.getDenominator());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParseOne1() {
|
||||
String source = "1 / 1";
|
||||
Fraction c = properFormat.parse(source);
|
||||
Assert.assertNotNull(c);
|
||||
Assert.assertEquals(1, c.getNumerator());
|
||||
Assert.assertEquals(1, c.getDenominator());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParseOne2() {
|
||||
String source = "10 / 10";
|
||||
Fraction c = properFormat.parse(source);
|
||||
Assert.assertNotNull(c);
|
||||
Assert.assertEquals(1, c.getNumerator());
|
||||
Assert.assertEquals(1, c.getDenominator());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParseZero1() {
|
||||
String source = "0 / 1";
|
||||
Fraction c = properFormat.parse(source);
|
||||
Assert.assertNotNull(c);
|
||||
Assert.assertEquals(0, c.getNumerator());
|
||||
Assert.assertEquals(1, c.getDenominator());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParseZero2() {
|
||||
String source = "-0 / 1";
|
||||
Fraction c = properFormat.parse(source);
|
||||
Assert.assertNotNull(c);
|
||||
Assert.assertEquals(0, c.getNumerator());
|
||||
Assert.assertEquals(1, c.getDenominator());
|
||||
// This test shows that the sign is not preserved.
|
||||
Assert.assertEquals(Double.POSITIVE_INFINITY, 1d / c.doubleValue(), 0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParseInvalid() {
|
||||
String source = "a";
|
||||
String msg = "should not be able to parse '10 / a'.";
|
||||
try {
|
||||
properFormat.parse(source);
|
||||
Assert.fail(msg);
|
||||
} catch (MathParseException ex) {
|
||||
// success
|
||||
}
|
||||
try {
|
||||
improperFormat.parse(source);
|
||||
Assert.fail(msg);
|
||||
} catch (MathParseException ex) {
|
||||
// success
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParseInvalidDenominator() {
|
||||
String source = "10 / a";
|
||||
String msg = "should not be able to parse '10 / a'.";
|
||||
try {
|
||||
properFormat.parse(source);
|
||||
Assert.fail(msg);
|
||||
} catch (MathParseException ex) {
|
||||
// success
|
||||
}
|
||||
try {
|
||||
improperFormat.parse(source);
|
||||
Assert.fail(msg);
|
||||
} catch (MathParseException ex) {
|
||||
// success
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParseNegative() {
|
||||
|
||||
{
|
||||
String source = "-1 / 2";
|
||||
Fraction c = properFormat.parse(source);
|
||||
Assert.assertNotNull(c);
|
||||
Assert.assertEquals(-1, c.getNumerator());
|
||||
Assert.assertEquals(2, c.getDenominator());
|
||||
|
||||
c = improperFormat.parse(source);
|
||||
Assert.assertNotNull(c);
|
||||
Assert.assertEquals(-1, c.getNumerator());
|
||||
Assert.assertEquals(2, c.getDenominator());
|
||||
|
||||
source = "1 / -2";
|
||||
c = properFormat.parse(source);
|
||||
Assert.assertNotNull(c);
|
||||
Assert.assertEquals(-1, c.getNumerator());
|
||||
Assert.assertEquals(2, c.getDenominator());
|
||||
|
||||
c = improperFormat.parse(source);
|
||||
Assert.assertNotNull(c);
|
||||
Assert.assertEquals(-1, c.getNumerator());
|
||||
Assert.assertEquals(2, c.getDenominator());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParseProper() {
|
||||
String source = "1 2 / 3";
|
||||
|
||||
{
|
||||
Fraction c = properFormat.parse(source);
|
||||
Assert.assertNotNull(c);
|
||||
Assert.assertEquals(5, c.getNumerator());
|
||||
Assert.assertEquals(3, c.getDenominator());
|
||||
}
|
||||
|
||||
try {
|
||||
improperFormat.parse(source);
|
||||
Assert.fail("invalid improper fraction.");
|
||||
} catch (MathParseException ex) {
|
||||
// success
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParseProperNegative() {
|
||||
String source = "-1 2 / 3";
|
||||
{
|
||||
Fraction c = properFormat.parse(source);
|
||||
Assert.assertNotNull(c);
|
||||
Assert.assertEquals(-5, c.getNumerator());
|
||||
Assert.assertEquals(3, c.getDenominator());
|
||||
}
|
||||
|
||||
try {
|
||||
improperFormat.parse(source);
|
||||
Assert.fail("invalid improper fraction.");
|
||||
} catch (MathParseException ex) {
|
||||
// success
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParseProperInvalidMinus() {
|
||||
String source = "2 -2 / 3";
|
||||
try {
|
||||
properFormat.parse(source);
|
||||
Assert.fail("invalid minus in improper fraction.");
|
||||
} catch (MathParseException ex) {
|
||||
// expected
|
||||
}
|
||||
source = "2 2 / -3";
|
||||
try {
|
||||
properFormat.parse(source);
|
||||
Assert.fail("invalid minus in improper fraction.");
|
||||
} catch (MathParseException ex) {
|
||||
// expected
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNumeratorFormat() {
|
||||
NumberFormat old = properFormat.getNumeratorFormat();
|
||||
NumberFormat nf = NumberFormat.getInstance();
|
||||
nf.setParseIntegerOnly(true);
|
||||
properFormat.setNumeratorFormat(nf);
|
||||
Assert.assertEquals(nf, properFormat.getNumeratorFormat());
|
||||
properFormat.setNumeratorFormat(old);
|
||||
|
||||
old = improperFormat.getNumeratorFormat();
|
||||
nf = NumberFormat.getInstance();
|
||||
nf.setParseIntegerOnly(true);
|
||||
improperFormat.setNumeratorFormat(nf);
|
||||
Assert.assertEquals(nf, improperFormat.getNumeratorFormat());
|
||||
improperFormat.setNumeratorFormat(old);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDenominatorFormat() {
|
||||
NumberFormat old = properFormat.getDenominatorFormat();
|
||||
NumberFormat nf = NumberFormat.getInstance();
|
||||
nf.setParseIntegerOnly(true);
|
||||
properFormat.setDenominatorFormat(nf);
|
||||
Assert.assertEquals(nf, properFormat.getDenominatorFormat());
|
||||
properFormat.setDenominatorFormat(old);
|
||||
|
||||
old = improperFormat.getDenominatorFormat();
|
||||
nf = NumberFormat.getInstance();
|
||||
nf.setParseIntegerOnly(true);
|
||||
improperFormat.setDenominatorFormat(nf);
|
||||
Assert.assertEquals(nf, improperFormat.getDenominatorFormat());
|
||||
improperFormat.setDenominatorFormat(old);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWholeFormat() {
|
||||
ProperFractionFormat format = (ProperFractionFormat)properFormat;
|
||||
|
||||
NumberFormat old = format.getWholeFormat();
|
||||
NumberFormat nf = NumberFormat.getInstance();
|
||||
nf.setParseIntegerOnly(true);
|
||||
format.setWholeFormat(nf);
|
||||
Assert.assertEquals(nf, format.getWholeFormat());
|
||||
format.setWholeFormat(old);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLongFormat() {
|
||||
Assert.assertEquals("10 / 1", improperFormat.format(10l));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDoubleFormat() {
|
||||
Assert.assertEquals("355 / 113", improperFormat.format(FastMath.PI));
|
||||
}
|
||||
}
|
|
@ -1,174 +0,0 @@
|
|||
/*
|
||||
* 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
|
||||
*
|
||||
* http://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.
|
||||
*/
|
||||
package org.apache.commons.math4.primes;
|
||||
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.commons.math4.exception.MathIllegalArgumentException;
|
||||
import org.apache.commons.math4.exception.util.LocalizedFormats;
|
||||
import org.apache.commons.math4.primes.Primes;
|
||||
import org.apache.commons.math4.primes.SmallPrimes;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
public class PrimesTest {
|
||||
|
||||
public static final int[] PRIMES = {//primes here have been verified one by one using Dario Alejandro Alpern's tool, see http://www.alpertron.com.ar/ECM.HTM
|
||||
2,3,5,7,11,13,17,19,23,29,31,43,47,53,71,73,79,89,97,
|
||||
107,137,151,157,271,293,331,409,607,617,683,829,
|
||||
1049,1103,1229,1657,
|
||||
2039,2053,//around first boundary in miller-rabin
|
||||
2251,2389,2473,2699,3271,3389,3449,5653,6449,6869,9067,9091,
|
||||
11251,12433,12959,22961,41047,46337,65413,80803,91577,92693,
|
||||
118423,656519,795659,
|
||||
1373639,1373677,//around second boundary in miller-rabin
|
||||
588977,952381,
|
||||
1013041,1205999,2814001,
|
||||
22605091,
|
||||
25325981,25326023,//around third boundary in miller-rabin
|
||||
100000007,715827881,
|
||||
2147483647//Integer.MAX_VALUE
|
||||
};
|
||||
|
||||
public static final int[] NOT_PRIMES = {//composite chosen at random + particular values used in algorithms such as boundaries for millerRabin
|
||||
4,6,8,9,10,12,14,15,16,18,20,21,22,24,25,
|
||||
275,
|
||||
2037,2041,2045,2046,2047,2048,2049,2051,2055,//around first boundary in miller-rabin
|
||||
9095,
|
||||
463465,
|
||||
1373637,1373641,1373651,1373652,1373653,1373654,1373655,1373673,1373675,1373679,//around second boundary in miller-rabin
|
||||
25325979,25325983,25325993,25325997,25325999,25326001,25326003,25326007,25326009,25326011,25326021,25326025,//around third boundary in miller-rabin
|
||||
100000005,
|
||||
1073741341,1073741823,2147473649,2147483641,2147483643,2147483645,2147483646};
|
||||
|
||||
public static final int[] BELOW_2 = {
|
||||
Integer.MIN_VALUE,-1,0,1};
|
||||
|
||||
void assertPrimeFactorsException(int n, Throwable expected) {
|
||||
try {
|
||||
Primes.primeFactors(n);
|
||||
Assert.fail("Exception not thrown");
|
||||
} catch (Throwable e) {
|
||||
Assert.assertEquals(expected.getClass(), e.getClass());
|
||||
if (expected.getMessage() != null) {
|
||||
Assert.assertEquals(expected.getMessage(), e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
void assertNextPrimeException(int n, Throwable expected){
|
||||
try {
|
||||
Primes.nextPrime(n);
|
||||
Assert.fail("Exception not thrown");
|
||||
} catch(Throwable e) {
|
||||
Assert.assertEquals(expected.getClass(), e.getClass());
|
||||
if (expected.getMessage() != null) {
|
||||
Assert.assertEquals(expected.getMessage(), e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNextPrime() {
|
||||
|
||||
Assert.assertEquals(2, Primes.nextPrime(0));
|
||||
Assert.assertEquals(2, Primes.nextPrime(1));
|
||||
Assert.assertEquals(2, Primes.nextPrime(2));
|
||||
Assert.assertEquals(3, Primes.nextPrime(3));
|
||||
Assert.assertEquals(5, Primes.nextPrime(4));
|
||||
Assert.assertEquals(5, Primes.nextPrime(5));
|
||||
|
||||
for (int i = 0; i < SmallPrimes.PRIMES.length - 1; i++) {
|
||||
for (int j = SmallPrimes.PRIMES[i] + 1; j <= SmallPrimes.PRIMES[i + 1]; j++) {
|
||||
Assert.assertEquals(SmallPrimes.PRIMES[i+1], Primes.nextPrime(j));
|
||||
}
|
||||
}
|
||||
|
||||
Assert.assertEquals(25325981, Primes.nextPrime(25325981));
|
||||
for (int i = 25325981 + 1; i <= 25326023; i++) {
|
||||
Assert.assertEquals(25326023, Primes.nextPrime(i));
|
||||
}
|
||||
|
||||
Assert.assertEquals(Integer.MAX_VALUE, Primes.nextPrime(Integer.MAX_VALUE - 10));
|
||||
Assert.assertEquals(Integer.MAX_VALUE, Primes.nextPrime(Integer.MAX_VALUE - 1));
|
||||
Assert.assertEquals(Integer.MAX_VALUE, Primes.nextPrime(Integer.MAX_VALUE));
|
||||
|
||||
assertNextPrimeException(Integer.MIN_VALUE, new MathIllegalArgumentException(LocalizedFormats.NUMBER_TOO_SMALL,Integer.MIN_VALUE,0));
|
||||
assertNextPrimeException(-1, new MathIllegalArgumentException(LocalizedFormats.NUMBER_TOO_SMALL,-1,0));
|
||||
assertNextPrimeException(-13, new MathIllegalArgumentException(LocalizedFormats.NUMBER_TOO_SMALL,-13,0));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsPrime() throws Exception {
|
||||
for (int i : BELOW_2) {
|
||||
Assert.assertFalse(Primes.isPrime(i));
|
||||
}
|
||||
for (int i:NOT_PRIMES) {
|
||||
Assert.assertFalse(Primes.isPrime(i));
|
||||
}
|
||||
for (int i:PRIMES) {
|
||||
Assert.assertTrue(Primes.isPrime(i));
|
||||
}
|
||||
}
|
||||
|
||||
static int sum(List<Integer> numbers){
|
||||
int out = 0;
|
||||
for (int i:numbers) {
|
||||
out += i;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
static int product(List<Integer> numbers) {
|
||||
int out = 1;
|
||||
for (int i : numbers) {
|
||||
out *= i;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
static final HashSet<Integer> PRIMES_SET = new HashSet<>();
|
||||
static {
|
||||
for (int p : PRIMES) {
|
||||
PRIMES_SET.add(p);
|
||||
}
|
||||
}
|
||||
static void checkPrimeFactors(List<Integer> factors){
|
||||
for (int p : factors) {
|
||||
if (!PRIMES_SET.contains(p)) {
|
||||
Assert.fail("Not found in primes list: " + p);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPrimeFactors() throws Exception {
|
||||
for (int i : BELOW_2) {
|
||||
assertPrimeFactorsException(i, new MathIllegalArgumentException(LocalizedFormats.NUMBER_TOO_SMALL,i,2));
|
||||
}
|
||||
for (int i : NOT_PRIMES) {
|
||||
List<Integer> factors = Primes.primeFactors(i);
|
||||
checkPrimeFactors(factors);
|
||||
int prod = product(factors);
|
||||
Assert.assertEquals(i, prod);
|
||||
}
|
||||
for (int i : PRIMES) {
|
||||
List<Integer> factors = Primes.primeFactors(i);
|
||||
Assert.assertEquals(i, (int)factors.get(0));
|
||||
Assert.assertEquals(1, factors.size());
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue