MATH-1416: Merge changes from feature-MATH-1416

This commit is contained in:
Ray DeCampo 2017-09-16 13:38:40 -04:00
commit eafb16c711
15 changed files with 0 additions and 3670 deletions

View File

@ -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();
}
}

View File

@ -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;
}
}

View File

@ -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);
}
}

View File

@ -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;
}
}
}

View File

@ -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());
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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 &lt; 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 &lt; 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 &ge; 2
* @return list of prime factors of n
* @throws MathIllegalArgumentException if n &lt; 2.
*/
public static List<Integer> primeFactors(int n) {
if (n < 2) {
throw new MathIllegalArgumentException(LocalizedFormats.NUMBER_TOO_SMALL, n, 2);
}
return SmallPrimes.trialDivision(n);
}
}

View File

@ -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 &gt; 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 &ge; 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
}
}

View File

@ -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;

View File

@ -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]"));
}
}

View File

@ -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);
}
}
}

View File

@ -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));
}
}

View File

@ -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));
}
}

View File

@ -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());
}
}
}