This is an automated email from the ASF dual-hosted git repository.
aherbert pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/commons-numbers.git
The following commit(s) were added to refs/heads/master by this push:
new 28b3eaf7 NUMBERS-203: Add a field class for the DD number
28b3eaf7 is described below
commit 28b3eaf79181ae9feddf140eb76c618ea4da6f24
Author: aherbert <[email protected]>
AuthorDate: Thu Sep 7 16:47:18 2023 +0100
NUMBERS-203: Add a field class for the DD number
---
.../org/apache/commons/numbers/field/DDField.java | 47 ++++++++++++++++++
.../apache/commons/numbers/field/FieldsList.java | 57 ++++++++++++++++++++++
src/changes/changes.xml | 3 ++
.../resources/spotbugs/spotbugs-exclude-filter.xml | 1 +
4 files changed, 108 insertions(+)
diff --git
a/commons-numbers-field/src/main/java/org/apache/commons/numbers/field/DDField.java
b/commons-numbers-field/src/main/java/org/apache/commons/numbers/field/DDField.java
new file mode 100644
index 00000000..c36521c3
--- /dev/null
+++
b/commons-numbers-field/src/main/java/org/apache/commons/numbers/field/DDField.java
@@ -0,0 +1,47 @@
+/*
+ * 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.field;
+
+import org.apache.commons.numbers.core.DD;
+
+/**
+ * {@link DD} field.
+ */
+public final class DDField extends AbstractField<DD> {
+ /** Singleton. */
+ private static final DDField INSTANCE = new DDField();
+
+ /** Singleton. */
+ private DDField() {}
+
+ /** @return the field instance. */
+ public static DDField get() {
+ return INSTANCE;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public DD one() {
+ return DD.ONE;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public DD zero() {
+ return DD.ZERO;
+ }
+}
diff --git
a/commons-numbers-field/src/test/java/org/apache/commons/numbers/field/FieldsList.java
b/commons-numbers-field/src/test/java/org/apache/commons/numbers/field/FieldsList.java
index 4ac9b721..aac269db 100644
---
a/commons-numbers-field/src/test/java/org/apache/commons/numbers/field/FieldsList.java
+++
b/commons-numbers-field/src/test/java/org/apache/commons/numbers/field/FieldsList.java
@@ -22,9 +22,12 @@ import java.util.stream.Stream;
import java.util.ArrayList;
import org.apache.commons.numbers.fraction.Fraction;
+import org.apache.commons.numbers.core.DD;
import org.apache.commons.numbers.core.Precision;
import org.apache.commons.numbers.fraction.BigFraction;
+import org.junit.jupiter.api.Assertions;
+
/**
* List of fields.
*/
@@ -50,6 +53,12 @@ final class FieldsList {
FP64.of(-234.5678901),
// double operations are subject to rounding so allow a
tolerance
(x, y) -> Precision.equals(x.doubleValue(), y.doubleValue(),
1));
+ add(DDField.get(),
+ createDD(23.45678901, 4.5671892973),
+ createDD(-543.2109876, 5.237848286),
+ createDD(-234.5678901, -4.561268179),
+ // double-double operations are subject to rounding so allow a
tolerance.
+ FieldsList::areEqual);
} catch (Exception e) {
e.printStackTrace(System.err);
@@ -87,6 +96,54 @@ final class FieldsList {
LIST.add(new FieldTestData<>(field, a, b, c, equals));
}
+ /**
+ * Creates the double-double number from two random values.
+ * The second value is scaled so that it does not overlap the first.
+ *
+ * @param a Value.
+ * @param b Value.
+ * @return the number
+ */
+ private static DD createDD(double a, double b) {
+ final int ea = Math.getExponent(a);
+ final int eb = Math.getExponent(b);
+ // Scale to have a non-overlapping 53-bit mantissa
+ double bb = Math.scalb(b, ea - eb - 53);
+ // If b has a larger mantissa than a (ignoring the exponent) then an
overlap may occur
+ if (a != a + bb) {
+ bb *= 0.5;
+ }
+ Assertions.assertEquals(a, a + bb);
+ return DD.ofSum(a, bb);
+ }
+
+ /**
+ * Test if the two numbers are equal.
+ *
+ * @param x Value.
+ * @param y Value.
+ * @return true if equal
+ */
+ private static boolean areEqual(DD x, DD y) {
+ // A simple binary equality is fine for most cases.
+ if (x.equals(y)) {
+ return true;
+ }
+ // If the high part is the same we can test a ULP tolerance on the low
part.
+ if (x.hi() == y.hi()) {
+ return Precision.equals(x.lo(), y.lo(), 1);
+ }
+ // Note that the high part could be different by 1 ulp and then the
low part
+ // can be significantly different (opposite signed values) to create
numbers that
+ // are almost the same: x+xx ~ y-yy.
+ // Here we obtain the difference and use a relative error of 2^-105:
+ // | x - y |
+ // ------------ < relative error
+ // max(|x|, |y|)
+ return Math.abs(x.subtract(y).doubleValue()) /
+ Math.max(Math.abs(x.doubleValue()), Math.abs(y.doubleValue())) <
Math.pow(2, -105);
+ }
+
/**
* Subclasses that are "parametric" tests can forward the call to
* the "@Parameters"-annotated method to this method.
diff --git a/src/changes/changes.xml b/src/changes/changes.xml
index 6823ef34..98585e56 100644
--- a/src/changes/changes.xml
+++ b/src/changes/changes.xml
@@ -56,6 +56,9 @@ If the output is not quite correct, check for invisible
trailing spaces!
<release version="1.2" date="TBD" description="
New features, updates and bug fixes.
">
+ <action dev="aherbert" type="add" issue="NUMBERS-203">
+ "DDField": Add a field for the DD number.
+ </action>
<action dev="aherbert" type="fix" issue="NUMBERS-204">
"Sum": Correct sub-normal round-off computation in sum of products.
</action>
diff --git a/src/main/resources/spotbugs/spotbugs-exclude-filter.xml
b/src/main/resources/spotbugs/spotbugs-exclude-filter.xml
index 09caccb4..70028b17 100644
--- a/src/main/resources/spotbugs/spotbugs-exclude-filter.xml
+++ b/src/main/resources/spotbugs/spotbugs-exclude-filter.xml
@@ -64,6 +64,7 @@
<Match>
<Or>
<!-- False positive exposure of immutable field. -->
+ <Class name="org.apache.commons.numbers.field.DDField"/>
<Class name="org.apache.commons.numbers.field.FP64Field"/>
<Class name="org.apache.commons.numbers.field.FractionField"/>
<Class name="org.apache.commons.numbers.field.BigFractionField"/>