You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by er...@apache.org on 2017/01/18 13:54:50 UTC
[11/16] commons-numbers git commit: Multimodule project setup.
http://git-wip-us.apache.org/repos/asf/commons-numbers/blob/c4541327/commons-numbers-complex/src/test/java/org/apache/commons/numbers/complex/TestUtils.java
----------------------------------------------------------------------
diff --git a/commons-numbers-complex/src/test/java/org/apache/commons/numbers/complex/TestUtils.java b/commons-numbers-complex/src/test/java/org/apache/commons/numbers/complex/TestUtils.java
new file mode 100644
index 0000000..70dc4c1
--- /dev/null
+++ b/commons-numbers-complex/src/test/java/org/apache/commons/numbers/complex/TestUtils.java
@@ -0,0 +1,409 @@
+/*
+ * 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.numbers.complex;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+
+import org.apache.commons.numbers.complex.Complex;
+
+import org.junit.Assert;
+
+/**
+ * Test utilities.
+ * TODO: Cleanup (remove unused and obsolete methods).
+ */
+public class TestUtils {
+ /**
+ * Collection of static methods used in math unit tests.
+ */
+ private TestUtils() {
+ super();
+ }
+
+ /**
+ * Verifies that expected and actual are within delta, or are both NaN or
+ * infinities of the same sign.
+ */
+ public static void assertEquals(double expected, double actual, double delta) {
+ Assert.assertEquals(null, expected, actual, delta);
+ }
+
+ /**
+ * Verifies that expected and actual are within delta, or are both NaN or
+ * infinities of the same sign.
+ */
+ public static void assertEquals(String msg, double expected, double actual, double delta) {
+ // check for NaN
+ if(Double.isNaN(expected)){
+ Assert.assertTrue("" + actual + " is not NaN.",
+ Double.isNaN(actual));
+ } else {
+ Assert.assertEquals(msg, expected, actual, delta);
+ }
+ }
+
+ /**
+ * Verifies that the two arguments are exactly the same, either
+ * both NaN or infinities of same sign, or identical floating point values.
+ */
+ public static void assertSame(double expected, double actual) {
+ Assert.assertEquals(expected, actual, 0);
+ }
+
+ /**
+ * Verifies that real and imaginary parts of the two complex arguments
+ * are exactly the same. Also ensures that NaN / infinite components match.
+ */
+ public static void assertSame(Complex expected, Complex actual) {
+ assertSame(expected.getReal(), actual.getReal());
+ assertSame(expected.getImaginary(), actual.getImaginary());
+ }
+
+ /**
+ * Verifies that real and imaginary parts of the two complex arguments
+ * differ by at most delta. Also ensures that NaN / infinite components match.
+ */
+ public static void assertEquals(Complex expected, Complex actual, double delta) {
+ Assert.assertEquals(expected.getReal(), actual.getReal(), delta);
+ Assert.assertEquals(expected.getImaginary(), actual.getImaginary(), delta);
+ }
+
+ /**
+ * Verifies that two double arrays have equal entries, up to tolerance
+ */
+ public static void assertEquals(double expected[], double observed[], double tolerance) {
+ assertEquals("Array comparison failure", expected, observed, tolerance);
+ }
+
+ /**
+ * Serializes an object to a bytes array and then recovers the object from the bytes array.
+ * Returns the deserialized object.
+ *
+ * @param o object to serialize and recover
+ * @return the recovered, deserialized object
+ */
+ public static Object serializeAndRecover(Object o) {
+ try {
+ // serialize the Object
+ ByteArrayOutputStream bos = new ByteArrayOutputStream();
+ ObjectOutputStream so = new ObjectOutputStream(bos);
+ so.writeObject(o);
+
+ // deserialize the Object
+ ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
+ ObjectInputStream si = new ObjectInputStream(bis);
+ return si.readObject();
+ } catch (IOException ioe) {
+ return null;
+ } catch (ClassNotFoundException cnfe) {
+ return null;
+ }
+ }
+
+ /**
+ * Verifies that serialization preserves equals and hashCode.
+ * Serializes the object, then recovers it and checks equals and hash code.
+ *
+ * @param object the object to serialize and recover
+ */
+ public static void checkSerializedEquality(Object object) {
+ Object object2 = serializeAndRecover(object);
+ Assert.assertEquals("Equals check", object, object2);
+ Assert.assertEquals("HashCode check", object.hashCode(), object2.hashCode());
+ }
+
+ /**
+ * Verifies that the relative error in actual vs. expected is less than or
+ * equal to relativeError. If expected is infinite or NaN, actual must be
+ * the same (NaN or infinity of the same sign).
+ *
+ * @param expected expected value
+ * @param actual observed value
+ * @param relativeError maximum allowable relative error
+ */
+ public static void assertRelativelyEquals(double expected, double actual,
+ double relativeError) {
+ assertRelativelyEquals(null, expected, actual, relativeError);
+ }
+
+ /**
+ * Verifies that the relative error in actual vs. expected is less than or
+ * equal to relativeError. If expected is infinite or NaN, actual must be
+ * the same (NaN or infinity of the same sign).
+ *
+ * @param msg message to return with failure
+ * @param expected expected value
+ * @param actual observed value
+ * @param relativeError maximum allowable relative error
+ */
+ public static void assertRelativelyEquals(String msg, double expected,
+ double actual, double relativeError) {
+ if (Double.isNaN(expected)) {
+ Assert.assertTrue(msg, Double.isNaN(actual));
+ } else if (Double.isNaN(actual)) {
+ Assert.assertTrue(msg, Double.isNaN(expected));
+ } else if (Double.isInfinite(actual) || Double.isInfinite(expected)) {
+ Assert.assertEquals(expected, actual, relativeError);
+ } else if (expected == 0.0) {
+ Assert.assertEquals(msg, actual, expected, relativeError);
+ } else {
+ double absError = Math.abs(expected) * relativeError;
+ Assert.assertEquals(msg, expected, actual, absError);
+ }
+ }
+
+ /**
+ * Fails iff values does not contain a number within epsilon of z.
+ *
+ * @param msg message to return with failure
+ * @param values complex array to search
+ * @param z value sought
+ * @param epsilon tolerance
+ */
+ public static void assertContains(String msg, Complex[] values,
+ Complex z, double epsilon) {
+ for (Complex value : values) {
+ if (Precision.equals(value.getReal(), z.getReal(), epsilon) &&
+ Precision.equals(value.getImaginary(), z.getImaginary(), epsilon)) {
+ return;
+ }
+ }
+ Assert.fail(msg + " Unable to find " + z);
+ }
+
+ /**
+ * Fails iff values does not contain a number within epsilon of z.
+ *
+ * @param values complex array to search
+ * @param z value sought
+ * @param epsilon tolerance
+ */
+ public static void assertContains(Complex[] values,
+ Complex z, double epsilon) {
+ assertContains(null, values, z, epsilon);
+ }
+
+ /**
+ * Fails iff values does not contain a number within epsilon of x.
+ *
+ * @param msg message to return with failure
+ * @param values double array to search
+ * @param x value sought
+ * @param epsilon tolerance
+ */
+ public static void assertContains(String msg, double[] values,
+ double x, double epsilon) {
+ for (double value : values) {
+ if (Precision.equals(value, x, epsilon)) {
+ return;
+ }
+ }
+ Assert.fail(msg + " Unable to find " + x);
+ }
+
+ /**
+ * Fails iff values does not contain a number within epsilon of x.
+ *
+ * @param values double array to search
+ * @param x value sought
+ * @param epsilon tolerance
+ */
+ public static void assertContains(double[] values, double x,
+ double epsilon) {
+ assertContains(null, values, x, epsilon);
+ }
+
+ /** verifies that two arrays are close (sup norm) */
+ public static void assertEquals(String msg, double[] expected, double[] observed, double tolerance) {
+ StringBuilder out = new StringBuilder(msg);
+ if (expected.length != observed.length) {
+ out.append("\n Arrays not same length. \n");
+ out.append("expected has length ");
+ out.append(expected.length);
+ out.append(" observed length = ");
+ out.append(observed.length);
+ Assert.fail(out.toString());
+ }
+ boolean failure = false;
+ for (int i=0; i < expected.length; i++) {
+ if (!equalsIncludingNaN(expected[i], observed[i], tolerance)) {
+ failure = true;
+ out.append("\n Elements at index ");
+ out.append(i);
+ out.append(" differ. ");
+ out.append(" expected = ");
+ out.append(expected[i]);
+ out.append(" observed = ");
+ out.append(observed[i]);
+ }
+ }
+ if (failure) {
+ Assert.fail(out.toString());
+ }
+ }
+
+ /** verifies that two arrays are close (sup norm) */
+ public static void assertEquals(String msg, float[] expected, float[] observed, float tolerance) {
+ StringBuilder out = new StringBuilder(msg);
+ if (expected.length != observed.length) {
+ out.append("\n Arrays not same length. \n");
+ out.append("expected has length ");
+ out.append(expected.length);
+ out.append(" observed length = ");
+ out.append(observed.length);
+ Assert.fail(out.toString());
+ }
+ boolean failure = false;
+ for (int i=0; i < expected.length; i++) {
+ if (!equalsIncludingNaN(expected[i], observed[i], tolerance)) {
+ failure = true;
+ out.append("\n Elements at index ");
+ out.append(i);
+ out.append(" differ. ");
+ out.append(" expected = ");
+ out.append(expected[i]);
+ out.append(" observed = ");
+ out.append(observed[i]);
+ }
+ }
+ if (failure) {
+ Assert.fail(out.toString());
+ }
+ }
+
+ /** verifies that two arrays are close (sup norm) */
+ public static void assertEquals(String msg, Complex[] expected, Complex[] observed, double tolerance) {
+ StringBuilder out = new StringBuilder(msg);
+ if (expected.length != observed.length) {
+ out.append("\n Arrays not same length. \n");
+ out.append("expected has length ");
+ out.append(expected.length);
+ out.append(" observed length = ");
+ out.append(observed.length);
+ Assert.fail(out.toString());
+ }
+ boolean failure = false;
+ for (int i=0; i < expected.length; i++) {
+ if (!equalsIncludingNaN(expected[i].getReal(), observed[i].getReal(), tolerance)) {
+ failure = true;
+ out.append("\n Real elements at index ");
+ out.append(i);
+ out.append(" differ. ");
+ out.append(" expected = ");
+ out.append(expected[i].getReal());
+ out.append(" observed = ");
+ out.append(observed[i].getReal());
+ }
+ if (!equalsIncludingNaN(expected[i].getImaginary(), observed[i].getImaginary(), tolerance)) {
+ failure = true;
+ out.append("\n Imaginary elements at index ");
+ out.append(i);
+ out.append(" differ. ");
+ out.append(" expected = ");
+ out.append(expected[i].getImaginary());
+ out.append(" observed = ");
+ out.append(observed[i].getImaginary());
+ }
+ }
+ if (failure) {
+ Assert.fail(out.toString());
+ }
+ }
+
+ /**
+ * Updates observed counts of values in quartiles.
+ * counts[0] <-> 1st quartile ... counts[3] <-> top quartile
+ */
+ public static void updateCounts(double value, long[] counts, double[] quartiles) {
+ if (value < quartiles[0]) {
+ counts[0]++;
+ } else if (value > quartiles[2]) {
+ counts[3]++;
+ } else if (value > quartiles[1]) {
+ counts[2]++;
+ } else {
+ counts[1]++;
+ }
+ }
+
+ /**
+ * Eliminates points with zero mass from densityPoints and densityValues parallel
+ * arrays. Returns the number of positive mass points and collapses the arrays so
+ * that the first <returned value> elements of the input arrays represent the positive
+ * mass points.
+ */
+ public static int eliminateZeroMassPoints(int[] densityPoints, double[] densityValues) {
+ int positiveMassCount = 0;
+ for (int i = 0; i < densityValues.length; i++) {
+ if (densityValues[i] > 0) {
+ positiveMassCount++;
+ }
+ }
+ if (positiveMassCount < densityValues.length) {
+ int[] newPoints = new int[positiveMassCount];
+ double[] newValues = new double[positiveMassCount];
+ int j = 0;
+ for (int i = 0; i < densityValues.length; i++) {
+ if (densityValues[i] > 0) {
+ newPoints[j] = densityPoints[i];
+ newValues[j] = densityValues[i];
+ j++;
+ }
+ }
+ System.arraycopy(newPoints,0,densityPoints,0,positiveMassCount);
+ System.arraycopy(newValues,0,densityValues,0,positiveMassCount);
+ }
+ return positiveMassCount;
+ }
+
+ /**
+ * Returns true if the arguments are both NaN, are equal or are within the range
+ * of allowed error (inclusive).
+ *
+ * @param x first value
+ * @param y second value
+ * @param eps the amount of absolute error to allow.
+ * @return {@code true} if the values are equal or within range of each other,
+ * or both are NaN.
+ * @since 2.2
+ */
+ private static boolean equalsIncludingNaN(double x, double y, double eps) {
+ return equalsIncludingNaN(x, y) || (Math.abs(y - x) <= eps);
+ }
+
+ /**
+ * Returns true if the arguments are both NaN or they are
+ * equal as defined by {@link #equals(double,double) equals(x, y, 1)}.
+ *
+ * @param x first value
+ * @param y second value
+ * @return {@code true} if the values are equal or both are NaN.
+ * @since 2.2
+ */
+ private static boolean equalsIncludingNaN(double x, double y) {
+ return (x != x || y != y) ? !(x != x ^ y != y) : Precision.equals(x, y, 1);
+ }
+
+
+}
+
+
http://git-wip-us.apache.org/repos/asf/commons-numbers/blob/c4541327/commons-numbers-core/LICENSE.txt
----------------------------------------------------------------------
diff --git a/commons-numbers-core/LICENSE.txt b/commons-numbers-core/LICENSE.txt
new file mode 100644
index 0000000..261eeb9
--- /dev/null
+++ b/commons-numbers-core/LICENSE.txt
@@ -0,0 +1,201 @@
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ Licensed 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.
http://git-wip-us.apache.org/repos/asf/commons-numbers/blob/c4541327/commons-numbers-core/NOTICE.txt
----------------------------------------------------------------------
diff --git a/commons-numbers-core/NOTICE.txt b/commons-numbers-core/NOTICE.txt
new file mode 100644
index 0000000..ea6ae07
--- /dev/null
+++ b/commons-numbers-core/NOTICE.txt
@@ -0,0 +1,6 @@
+Apache Commons Numbers
+Copyright 2001-2016 The Apache Software Foundation
+
+This product includes software developed at
+The Apache Software Foundation (http://www.apache.org/).
+
http://git-wip-us.apache.org/repos/asf/commons-numbers/blob/c4541327/commons-numbers-core/README.md
----------------------------------------------------------------------
diff --git a/commons-numbers-core/README.md b/commons-numbers-core/README.md
new file mode 100644
index 0000000..0701bed
--- /dev/null
+++ b/commons-numbers-core/README.md
@@ -0,0 +1,98 @@
+<!---
+ 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.
+-->
+<!---
+ +======================================================================+
+ |**** ****|
+ |**** THIS FILE IS GENERATED BY THE COMMONS BUILD PLUGIN ****|
+ |**** DO NOT EDIT DIRECTLY ****|
+ |**** ****|
+ +======================================================================+
+ | TEMPLATE FILE: readme-md-template.md |
+ | commons-build-plugin/trunk/src/main/resources/commons-xdoc-templates |
+ +======================================================================+
+ | |
+ | 1) Re-generate using: mvn commons:readme-md |
+ | |
+ | 2) Set the following properties in the component's pom: |
+ | - commons.componentid (required, alphabetic, lower case) |
+ | - commons.release.version (required) |
+ | |
+ | 3) Example Properties |
+ | |
+ | <properties> |
+ | <commons.componentid>math</commons.componentid> |
+ | <commons.release.version>1.2</commons.release.version> |
+ | </properties> |
+ | |
+ +======================================================================+
+--->
+Apache Commons Numbers Core
+===================
+
+Basic utilities.
+
+Documentation
+-------------
+
+More information can be found on the [homepage](https://commons.apache.org/proper/commons-numbers).
+The [JavaDoc](https://commons.apache.org/proper/commons-numbers/javadocs/api-release) can be browsed.
+Questions related to the usage of Apache Commons Numbers Core should be posted to the [user mailing list][ml].
+
+Where can I get the latest release?
+-----------------------------------
+You can download source and binaries from our [download page](https://commons.apache.org/proper/commons-numbers/download_numbers.cgi).
+
+Alternatively you can pull it from the central Maven repositories:
+
+```xml
+<dependency>
+ <groupId>org.apache.commons</groupId>
+ <artifactId>commons-numbers-core</artifactId>
+ <version>1.0</version>
+</dependency>
+```
+
+Contributing
+------------
+
+We accept PRs via github. The [developer mailing list][ml] is the main channel of communication for contributors.
+There are some guidelines which will make applying PRs easier for us:
++ No tabs! Please use spaces for indentation.
++ Respect the code style.
++ Create minimal diffs - disable on save actions like reformat source code or organize imports. If you feel the source code should be reformatted create a separate PR for this change.
++ Provide JUnit tests for your changes and make sure your changes don't break any existing tests by running ```mvn clean test```.
+
+If you plan to contribute on a regular basis, please consider filing a [contributor license agreement](https://www.apache.org/licenses/#clas).
+You can learn more about contributing via GitHub in our [contribution guidelines](CONTRIBUTING.md).
+
+License
+-------
+Code is under the [Apache Licence v2](https://www.apache.org/licenses/LICENSE-2.0.txt).
+
+Donations
+---------
+You like Apache Commons Numbers Core? Then [donate back to the ASF](https://www.apache.org/foundation/contributing.html) to support the development.
+
+Additional Resources
+--------------------
+
++ [Apache Commons Homepage](https://commons.apache.org/)
++ [Apache Bugtracker (JIRA)](https://issues.apache.org/jira/)
++ [Apache Commons Twitter Account](https://twitter.com/ApacheCommons)
++ #apachecommons IRC channel on freenode.org
+
+[ml]:https://commons.apache.org/mail-lists.html
http://git-wip-us.apache.org/repos/asf/commons-numbers/blob/c4541327/commons-numbers-core/pom.xml
----------------------------------------------------------------------
diff --git a/commons-numbers-core/pom.xml b/commons-numbers-core/pom.xml
new file mode 100644
index 0000000..39dbdcb
--- /dev/null
+++ b/commons-numbers-core/pom.xml
@@ -0,0 +1,46 @@
+<?xml version="1.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.
+-->
+<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
+ xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+ <modelVersion>4.0.0</modelVersion>
+
+ <parent>
+ <groupId>org.apache.commons</groupId>
+ <artifactId>commons-numbers-parent</artifactId>
+ <version>1.0-SNAPSHOT</version>
+ </parent>
+
+ <groupId>org.apache.commons</groupId>
+ <artifactId>commons-numbers-core</artifactId>
+ <version>1.0-SNAPSHOT</version>
+ <name>Apache Commons Numbers Core</name>
+
+ <description>Basic utilities.</description>
+
+ <properties>
+ <!-- This value must reflect the current name of the base package. -->
+ <commons.osgi.symbolicName>org.apache.commons.numbers.core</commons.osgi.symbolicName>
+ <!-- OSGi -->
+ <commons.osgi.export>org.apache.commons.numbers.core</commons.osgi.export>
+ <!-- Workaround to avoid duplicating config files. -->
+ <numbers.parent.dir>${basedir}/..</numbers.parent.dir>
+ </properties>
+
+
+</project>
http://git-wip-us.apache.org/repos/asf/commons-numbers/blob/c4541327/commons-numbers-core/src/main/java/org/apache/commons/numbers/core/Precision.java
----------------------------------------------------------------------
diff --git a/commons-numbers-core/src/main/java/org/apache/commons/numbers/core/Precision.java b/commons-numbers-core/src/main/java/org/apache/commons/numbers/core/Precision.java
new file mode 100644
index 0000000..e71e1e4
--- /dev/null
+++ b/commons-numbers-core/src/main/java/org/apache/commons/numbers/core/Precision.java
@@ -0,0 +1,598 @@
+/*
+ * 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.numbers.core;
+
+import java.math.BigDecimal;
+
+/**
+ * Utilities for comparing numbers.
+ */
+public class Precision {
+ /**
+ * <p>
+ * Largest double-precision floating-point number such that
+ * {@code 1 + EPSILON} is numerically equal to 1. This value is an upper
+ * bound on the relative error due to rounding real numbers to double
+ * precision floating-point numbers.
+ * </p>
+ * <p>
+ * In IEEE 754 arithmetic, this is 2<sup>-53</sup>.
+ * </p>
+ *
+ * @see <a href="http://en.wikipedia.org/wiki/Machine_epsilon">Machine epsilon</a>
+ */
+ public static final double EPSILON;
+
+ /**
+ * Safe minimum, such that {@code 1 / SAFE_MIN} does not overflow.
+ * In IEEE 754 arithmetic, this is also the smallest normalized
+ * number 2<sup>-1022</sup>.
+ */
+ public static final double SAFE_MIN;
+
+ /** Exponent offset in IEEE754 representation. */
+ private static final long EXPONENT_OFFSET = 1023l;
+
+ /** Offset to order signed double numbers lexicographically. */
+ private static final long SGN_MASK = 0x8000000000000000L;
+ /** Offset to order signed double numbers lexicographically. */
+ private static final int SGN_MASK_FLOAT = 0x80000000;
+ /** Positive zero. */
+ private static final double POSITIVE_ZERO = 0d;
+ /** Positive zero bits. */
+ private static final long POSITIVE_ZERO_DOUBLE_BITS = Double.doubleToRawLongBits(+0.0);
+ /** Negative zero bits. */
+ private static final long NEGATIVE_ZERO_DOUBLE_BITS = Double.doubleToRawLongBits(-0.0);
+ /** Positive zero bits. */
+ private static final int POSITIVE_ZERO_FLOAT_BITS = Float.floatToRawIntBits(+0.0f);
+ /** Negative zero bits. */
+ private static final int NEGATIVE_ZERO_FLOAT_BITS = Float.floatToRawIntBits(-0.0f);
+
+ static {
+ /*
+ * This was previously expressed as = 0x1.0p-53;
+ * However, OpenJDK (Sparc Solaris) cannot handle such small
+ * constants: MATH-721
+ */
+ EPSILON = Double.longBitsToDouble((EXPONENT_OFFSET - 53l) << 52);
+
+ /*
+ * This was previously expressed as = 0x1.0p-1022;
+ * However, OpenJDK (Sparc Solaris) cannot handle such small
+ * constants: MATH-721
+ */
+ SAFE_MIN = Double.longBitsToDouble((EXPONENT_OFFSET - 1022l) << 52);
+ }
+
+ /**
+ * Private constructor.
+ */
+ private Precision() {}
+
+ /**
+ * Compares two numbers given some amount of allowed error.
+ * The returned value is
+ * <ul>
+ * <li>
+ * 0 if {@link #equals(double,double,double) equals(x, y, eps)},
+ * </li>
+ * <li>
+ * negative if !{@link #equals(double,double,double) equals(x, y, eps)} and {@code x < y},
+ * </li>
+ * <li>
+ * positive if !{@link #equals(double,double,double) equals(x, y, eps)} and {@code x > y} or
+ * either argument is {@code NaN}.
+ * </li>
+ * </ul>
+ *
+ * @param x First value.
+ * @param y Second value.
+ * @param eps Allowed error when checking for equality.
+ * @return 0 if the value are considered equal, -1 if the first is smaller than
+ * the second, 1 is the first is larger than the second.
+ */
+ public static int compareTo(double x, double y, double eps) {
+ if (equals(x, y, eps)) {
+ return 0;
+ } else if (x < y) {
+ return -1;
+ }
+ return 1;
+ }
+
+ /**
+ * Compares two numbers given some amount of allowed error.
+ * Two float numbers are considered equal if there are {@code (maxUlps - 1)}
+ * (or fewer) floating point numbers between them, i.e. two adjacent floating
+ * point numbers are considered equal.
+ * Adapted from
+ * <a href="http://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/">
+ * Bruce Dawson</a>. Returns {@code false} if either of the arguments is NaN.
+ * The returned value is
+ * <ul>
+ * <li>
+ * zero if {@link #equals(double,double,int) equals(x, y, maxUlps)},
+ * </li>
+ * <li>
+ * negative if !{@link #equals(double,double,int) equals(x, y, maxUlps)} and {@code x < y},
+ * </li>
+ * <li>
+ * positive if !{@link #equals(double,double,int) equals(x, y, maxUlps)} and {@code x > y}
+ * or either argument is {@code NaN}.
+ * </li>
+ * </ul>
+ *
+ * @param x First value.
+ * @param y Second value.
+ * @param maxUlps {@code (maxUlps - 1)} is the number of floating point
+ * values between {@code x} and {@code y}.
+ * @return 0 if the value are considered equal, -1 if the first is smaller than
+ * the second, 1 is the first is larger than the second.
+ */
+ public static int compareTo(final double x, final double y, final int maxUlps) {
+ if (equals(x, y, maxUlps)) {
+ return 0;
+ } else if (x < y) {
+ return -1;
+ }
+ return 1;
+ }
+
+ /**
+ * Returns true iff they are equal as defined by
+ * {@link #equals(float,float,int) equals(x, y, 1)}.
+ *
+ * @param x first value
+ * @param y second value
+ * @return {@code true} if the values are equal.
+ */
+ public static boolean equals(float x, float y) {
+ return equals(x, y, 1);
+ }
+
+ /**
+ * Returns true if both arguments are NaN or they are
+ * equal as defined by {@link #equals(float,float) equals(x, y, 1)}.
+ *
+ * @param x first value
+ * @param y second value
+ * @return {@code true} if the values are equal or both are NaN.
+ */
+ public static boolean equalsIncludingNaN(float x, float y) {
+ return (x != x || y != y) ? !(x != x ^ y != y) : equals(x, y, 1);
+ }
+
+ /**
+ * Returns true if the arguments are equal or within the range of allowed
+ * error (inclusive). Returns {@code false} if either of the arguments
+ * is NaN.
+ *
+ * @param x first value
+ * @param y second value
+ * @param eps the amount of absolute error to allow.
+ * @return {@code true} if the values are equal or within range of each other.
+ */
+ public static boolean equals(float x, float y, float eps) {
+ return equals(x, y, 1) || Math.abs(y - x) <= eps;
+ }
+
+ /**
+ * Returns true if the arguments are both NaN, are equal, or are within the range
+ * of allowed error (inclusive).
+ *
+ * @param x first value
+ * @param y second value
+ * @param eps the amount of absolute error to allow.
+ * @return {@code true} if the values are equal or within range of each other,
+ * or both are NaN.
+ */
+ public static boolean equalsIncludingNaN(float x, float y, float eps) {
+ return equalsIncludingNaN(x, y) || (Math.abs(y - x) <= eps);
+ }
+
+ /**
+ * Returns true if the arguments are equal or within the range of allowed
+ * error (inclusive).
+ * Two float numbers are considered equal if there are {@code (maxUlps - 1)}
+ * (or fewer) floating point numbers between them, i.e. two adjacent floating
+ * point numbers are considered equal.
+ * Adapted from <a
+ * href="http://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/">
+ * Bruce Dawson</a>. Returns {@code false} if either of the arguments is NaN.
+ *
+ * @param x first value
+ * @param y second value
+ * @param maxUlps {@code (maxUlps - 1)} is the number of floating point
+ * values between {@code x} and {@code y}.
+ * @return {@code true} if there are fewer than {@code maxUlps} floating
+ * point values between {@code x} and {@code y}.
+ */
+ public static boolean equals(final float x, final float y, final int maxUlps) {
+
+ final int xInt = Float.floatToRawIntBits(x);
+ final int yInt = Float.floatToRawIntBits(y);
+
+ final boolean isEqual;
+ if (((xInt ^ yInt) & SGN_MASK_FLOAT) == 0) {
+ // number have same sign, there is no risk of overflow
+ isEqual = Math.abs(xInt - yInt) <= maxUlps;
+ } else {
+ // number have opposite signs, take care of overflow
+ final int deltaPlus;
+ final int deltaMinus;
+ if (xInt < yInt) {
+ deltaPlus = yInt - POSITIVE_ZERO_FLOAT_BITS;
+ deltaMinus = xInt - NEGATIVE_ZERO_FLOAT_BITS;
+ } else {
+ deltaPlus = xInt - POSITIVE_ZERO_FLOAT_BITS;
+ deltaMinus = yInt - NEGATIVE_ZERO_FLOAT_BITS;
+ }
+
+ if (deltaPlus > maxUlps) {
+ isEqual = false;
+ } else {
+ isEqual = deltaMinus <= (maxUlps - deltaPlus);
+ }
+
+ }
+
+ return isEqual && !Float.isNaN(x) && !Float.isNaN(y);
+
+ }
+
+ /**
+ * Returns true if the arguments are both NaN or if they are equal as defined
+ * by {@link #equals(float,float,int) equals(x, y, maxUlps)}.
+ *
+ * @param x first value
+ * @param y second value
+ * @param maxUlps {@code (maxUlps - 1)} is the number of floating point
+ * values between {@code x} and {@code y}.
+ * @return {@code true} if both arguments are NaN or if there are less than
+ * {@code maxUlps} floating point values between {@code x} and {@code y}.
+ */
+ public static boolean equalsIncludingNaN(float x, float y, int maxUlps) {
+ return (x != x || y != y) ? !(x != x ^ y != y) : equals(x, y, maxUlps);
+ }
+
+ /**
+ * Returns true iff they are equal as defined by
+ * {@link #equals(double,double,int) equals(x, y, 1)}.
+ *
+ * @param x first value
+ * @param y second value
+ * @return {@code true} if the values are equal.
+ */
+ public static boolean equals(double x, double y) {
+ return equals(x, y, 1);
+ }
+
+ /**
+ * Returns true if the arguments are both NaN or they are
+ * equal as defined by {@link #equals(double,double) equals(x, y, 1)}.
+ *
+ * @param x first value
+ * @param y second value
+ * @return {@code true} if the values are equal or both are NaN.
+ */
+ public static boolean equalsIncludingNaN(double x, double y) {
+ return (x != x || y != y) ? !(x != x ^ y != y) : equals(x, y, 1);
+ }
+
+ /**
+ * Returns {@code true} if there is no double value strictly between the
+ * arguments or the difference between them is within the range of allowed
+ * error (inclusive). Returns {@code false} if either of the arguments
+ * is NaN.
+ *
+ * @param x First value.
+ * @param y Second value.
+ * @param eps Amount of allowed absolute error.
+ * @return {@code true} if the values are two adjacent floating point
+ * numbers or they are within range of each other.
+ */
+ public static boolean equals(double x, double y, double eps) {
+ return equals(x, y, 1) || Math.abs(y - x) <= eps;
+ }
+
+ /**
+ * Returns {@code true} if there is no double value strictly between the
+ * arguments or the relative difference between them is less than or equal
+ * to the given tolerance. Returns {@code false} if either of the arguments
+ * is NaN.
+ *
+ * @param x First value.
+ * @param y Second value.
+ * @param eps Amount of allowed relative error.
+ * @return {@code true} if the values are two adjacent floating point
+ * numbers or they are within range of each other.
+ */
+ public static boolean equalsWithRelativeTolerance(double x, double y, double eps) {
+ if (equals(x, y, 1)) {
+ return true;
+ }
+
+ final double absoluteMax = Math.max(Math.abs(x), Math.abs(y));
+ final double relativeDifference = Math.abs((x - y) / absoluteMax);
+
+ return relativeDifference <= eps;
+ }
+
+ /**
+ * Returns true if the arguments are both NaN, are equal or are within the range
+ * of allowed error (inclusive).
+ *
+ * @param x first value
+ * @param y second value
+ * @param eps the amount of absolute error to allow.
+ * @return {@code true} if the values are equal or within range of each other,
+ * or both are NaN.
+ */
+ public static boolean equalsIncludingNaN(double x, double y, double eps) {
+ return equalsIncludingNaN(x, y) || (Math.abs(y - x) <= eps);
+ }
+
+ /**
+ * Returns true if the arguments are equal or within the range of allowed
+ * error (inclusive).
+ * <p>
+ * Two float numbers are considered equal if there are {@code (maxUlps - 1)}
+ * (or fewer) floating point numbers between them, i.e. two adjacent
+ * floating point numbers are considered equal.
+ * </p>
+ * <p>
+ * Adapted from <a
+ * href="http://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/">
+ * Bruce Dawson</a>. Returns {@code false} if either of the arguments is NaN.
+ * </p>
+ *
+ * @param x first value
+ * @param y second value
+ * @param maxUlps {@code (maxUlps - 1)} is the number of floating point
+ * values between {@code x} and {@code y}.
+ * @return {@code true} if there are fewer than {@code maxUlps} floating
+ * point values between {@code x} and {@code y}.
+ */
+ public static boolean equals(final double x, final double y, final int maxUlps) {
+
+ final long xInt = Double.doubleToRawLongBits(x);
+ final long yInt = Double.doubleToRawLongBits(y);
+
+ final boolean isEqual;
+ if (((xInt ^ yInt) & SGN_MASK) == 0l) {
+ // number have same sign, there is no risk of overflow
+ isEqual = Math.abs(xInt - yInt) <= maxUlps;
+ } else {
+ // number have opposite signs, take care of overflow
+ final long deltaPlus;
+ final long deltaMinus;
+ if (xInt < yInt) {
+ deltaPlus = yInt - POSITIVE_ZERO_DOUBLE_BITS;
+ deltaMinus = xInt - NEGATIVE_ZERO_DOUBLE_BITS;
+ } else {
+ deltaPlus = xInt - POSITIVE_ZERO_DOUBLE_BITS;
+ deltaMinus = yInt - NEGATIVE_ZERO_DOUBLE_BITS;
+ }
+
+ if (deltaPlus > maxUlps) {
+ isEqual = false;
+ } else {
+ isEqual = deltaMinus <= (maxUlps - deltaPlus);
+ }
+
+ }
+
+ return isEqual && !Double.isNaN(x) && !Double.isNaN(y);
+
+ }
+
+ /**
+ * Returns true if both arguments are NaN or if they are equal as defined
+ * by {@link #equals(double,double,int) equals(x, y, maxUlps)}.
+ *
+ * @param x first value
+ * @param y second value
+ * @param maxUlps {@code (maxUlps - 1)} is the number of floating point
+ * values between {@code x} and {@code y}.
+ * @return {@code true} if both arguments are NaN or if there are less than
+ * {@code maxUlps} floating point values between {@code x} and {@code y}.
+ */
+ public static boolean equalsIncludingNaN(double x, double y, int maxUlps) {
+ return (x != x || y != y) ? !(x != x ^ y != y) : equals(x, y, maxUlps);
+ }
+
+ /**
+ * Rounds the given value to the specified number of decimal places.
+ * The value is rounded using the {@link BigDecimal#ROUND_HALF_UP} method.
+ *
+ * @param x Value to round.
+ * @param scale Number of digits to the right of the decimal point.
+ * @return the rounded value.
+ */
+ public static double round(double x, int scale) {
+ return round(x, scale, BigDecimal.ROUND_HALF_UP);
+ }
+
+ /**
+ * Rounds the given value to the specified number of decimal places.
+ * The value is rounded using the given method which is any method defined
+ * in {@link BigDecimal}.
+ * If {@code x} is infinite or {@code NaN}, then the value of {@code x} is
+ * returned unchanged, regardless of the other parameters.
+ *
+ * @param x Value to round.
+ * @param scale Number of digits to the right of the decimal point.
+ * @param roundingMethod Rounding method as defined in {@link BigDecimal}.
+ * @return the rounded value.
+ * @throws ArithmeticException if {@code roundingMethod == ROUND_UNNECESSARY}
+ * and the specified scaling operation would require rounding.
+ * @throws IllegalArgumentException if {@code roundingMethod} does not
+ * represent a valid rounding mode.
+ */
+ public static double round(double x, int scale, int roundingMethod) {
+ try {
+ final double rounded = (new BigDecimal(Double.toString(x))
+ .setScale(scale, roundingMethod))
+ .doubleValue();
+ // MATH-1089: negative values rounded to zero should result in negative zero
+ return rounded == POSITIVE_ZERO ? POSITIVE_ZERO * x : rounded;
+ } catch (NumberFormatException ex) {
+ if (Double.isInfinite(x)) {
+ return x;
+ } else {
+ return Double.NaN;
+ }
+ }
+ }
+
+ /**
+ * Rounds the given value to the specified number of decimal places.
+ * The value is rounded using the {@link BigDecimal#ROUND_HALF_UP} method.
+ *
+ * @param x Value to round.
+ * @param scale Number of digits to the right of the decimal point.
+ * @return the rounded value.
+ */
+ public static float round(float x, int scale) {
+ return round(x, scale, BigDecimal.ROUND_HALF_UP);
+ }
+
+ /**
+ * Rounds the given value to the specified number of decimal places.
+ * The value is rounded using the given method which is any method defined
+ * in {@link BigDecimal}.
+ *
+ * @param x Value to round.
+ * @param scale Number of digits to the right of the decimal point.
+ * @param roundingMethod Rounding method as defined in {@link BigDecimal}.
+ * @return the rounded value.
+ * @throws ArithmeticException if an exact operation is required but result is not exact
+ * @throws IllegalArgumentException if {@code roundingMethod} is not a valid rounding method.
+ */
+ public static float round(float x, int scale, int roundingMethod) {
+ final float sign = Math.copySign(1f, x);
+ final float factor = (float) Math.pow(10.0f, scale) * sign;
+ return (float) roundUnscaled(x * factor, sign, roundingMethod) / factor;
+ }
+
+ /**
+ * Rounds the given non-negative value to the "nearest" integer. Nearest is
+ * determined by the rounding method specified. Rounding methods are defined
+ * in {@link BigDecimal}.
+ *
+ * @param unscaled Value to round.
+ * @param sign Sign of the original, scaled value.
+ * @param roundingMethod Rounding method, as defined in {@link BigDecimal}.
+ * @return the rounded value.
+ * @throws ArithmeticException if an exact operation is required but result is not exact
+ * @throws IllegalArgumentException if {@code roundingMethod} is not a valid rounding method.
+ */
+ private static double roundUnscaled(double unscaled,
+ double sign,
+ int roundingMethod) {
+ switch (roundingMethod) {
+ case BigDecimal.ROUND_CEILING :
+ if (sign == -1) {
+ unscaled = Math.floor(Math.nextAfter(unscaled, Double.NEGATIVE_INFINITY));
+ } else {
+ unscaled = Math.ceil(Math.nextAfter(unscaled, Double.POSITIVE_INFINITY));
+ }
+ break;
+ case BigDecimal.ROUND_DOWN :
+ unscaled = Math.floor(Math.nextAfter(unscaled, Double.NEGATIVE_INFINITY));
+ break;
+ case BigDecimal.ROUND_FLOOR :
+ if (sign == -1) {
+ unscaled = Math.ceil(Math.nextAfter(unscaled, Double.POSITIVE_INFINITY));
+ } else {
+ unscaled = Math.floor(Math.nextAfter(unscaled, Double.NEGATIVE_INFINITY));
+ }
+ break;
+ case BigDecimal.ROUND_HALF_DOWN : {
+ unscaled = Math.nextAfter(unscaled, Double.NEGATIVE_INFINITY);
+ double fraction = unscaled - Math.floor(unscaled);
+ if (fraction > 0.5) {
+ unscaled = Math.ceil(unscaled);
+ } else {
+ unscaled = Math.floor(unscaled);
+ }
+ break;
+ }
+ case BigDecimal.ROUND_HALF_EVEN : {
+ double fraction = unscaled - Math.floor(unscaled);
+ if (fraction > 0.5) {
+ unscaled = Math.ceil(unscaled);
+ } else if (fraction < 0.5) {
+ unscaled = Math.floor(unscaled);
+ } else {
+ // The following equality test is intentional and needed for rounding purposes
+ if (Math.floor(unscaled) / 2.0 == Math.floor(Math.floor(unscaled) / 2.0)) { // even
+ unscaled = Math.floor(unscaled);
+ } else { // odd
+ unscaled = Math.ceil(unscaled);
+ }
+ }
+ break;
+ }
+ case BigDecimal.ROUND_HALF_UP : {
+ unscaled = Math.nextAfter(unscaled, Double.POSITIVE_INFINITY);
+ double fraction = unscaled - Math.floor(unscaled);
+ if (fraction >= 0.5) {
+ unscaled = Math.ceil(unscaled);
+ } else {
+ unscaled = Math.floor(unscaled);
+ }
+ break;
+ }
+ case BigDecimal.ROUND_UNNECESSARY :
+ if (unscaled != Math.floor(unscaled)) {
+ throw new ArithmeticException();
+ }
+ break;
+ case BigDecimal.ROUND_UP :
+ // do not round if the discarded fraction is equal to zero
+ if (unscaled != Math.floor(unscaled)) {
+ unscaled = Math.ceil(Math.nextAfter(unscaled, Double.POSITIVE_INFINITY));
+ }
+ break;
+ default :
+ throw new IllegalArgumentException("Unhandled rounding method: " + roundingMethod);
+ }
+ return unscaled;
+ }
+
+
+ /**
+ * Computes a number {@code delta} close to {@code originalDelta} with
+ * the property that <pre><code>
+ * x + delta - x
+ * </code></pre>
+ * is exactly machine-representable.
+ * This is useful when computing numerical derivatives, in order to reduce
+ * roundoff errors.
+ *
+ * @param x Value.
+ * @param originalDelta Offset value.
+ * @return a number {@code delta} so that {@code x + delta} and {@code x}
+ * differ by a representable floating number.
+ */
+ public static double representableDelta(double x,
+ double originalDelta) {
+ return x + originalDelta - x;
+ }
+}