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"/>

Reply via email to