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

commit a514149aadea1542c9c00004a0367f8ee2247c95
Author: Harald Kirsch <pifpaf...@gmx.de>
AuthorDate: Wed Oct 4 17:12:48 2023 +0100

    NUMBERS-205: Introduces isZero to Addition and isOne to Multiplication
    
    All classes already implementing Addition and Multiplication got their
    specialized versions instead of just calling equals() on zero() or
    one() respectively to avoid potentially expensive operations, like
    BigFraction creating fresh copies of numerator and/or denominator if
    either is negative.
---
 .../org/apache/commons/numbers/core/Addition.java  | 16 +++++
 .../java/org/apache/commons/numbers/core/DD.java   | 13 ++++
 .../commons/numbers/core/Multiplication.java       | 16 +++++
 .../apache/commons/numbers/core/AdditionTest.java  | 71 ++++++++++++++++++++++
 .../org/apache/commons/numbers/core/DDTest.java    | 25 ++++++++
 .../commons/numbers/core/MultiplicationTest.java   | 71 ++++++++++++++++++++++
 .../org/apache/commons/numbers/field/FP64.java     | 12 ++++
 .../org/apache/commons/numbers/field/FP64Test.java | 22 +++++++
 .../commons/numbers/fraction/BigFraction.java      | 21 ++++---
 .../apache/commons/numbers/fraction/Fraction.java  | 21 ++++---
 .../commons/numbers/fraction/BigFractionTest.java  | 16 +++++
 .../commons/numbers/fraction/FractionTest.java     | 24 ++++++++
 12 files changed, 310 insertions(+), 18 deletions(-)

diff --git 
a/commons-numbers-core/src/main/java/org/apache/commons/numbers/core/Addition.java
 
b/commons-numbers-core/src/main/java/org/apache/commons/numbers/core/Addition.java
index 1e319799..b93bdb44 100644
--- 
a/commons-numbers-core/src/main/java/org/apache/commons/numbers/core/Addition.java
+++ 
b/commons-numbers-core/src/main/java/org/apache/commons/numbers/core/Addition.java
@@ -44,4 +44,20 @@ public interface Addition<T> {
      * @return {@code -this}.
      */
     T negate();
+
+    /**
+     * Check if this is a neutral element of addition, i.e. {@code 
this.add(a)} returns
+     * {@code a} or an element representing the same value as {@code a}.
+     *
+     * <p>The default implementation calls {@link #equals(Object) 
equals(zero())}.
+     * Implementations may want to employ more a efficient method. This may 
even
+     * be required if an implementation has multiple representations of {@code 
zero} and its
+     * {@code equals} method differentiates between them.
+     *
+     * @return {@code true} if {@code this} is a neutral element of addition.
+     * @see #zero()
+     */
+    default boolean isZero() {
+        return this.equals(zero());
+    }
 }
diff --git 
a/commons-numbers-core/src/main/java/org/apache/commons/numbers/core/DD.java 
b/commons-numbers-core/src/main/java/org/apache/commons/numbers/core/DD.java
index 446916cd..7928197e 100644
--- a/commons-numbers-core/src/main/java/org/apache/commons/numbers/core/DD.java
+++ b/commons-numbers-core/src/main/java/org/apache/commons/numbers/core/DD.java
@@ -2297,6 +2297,13 @@ public final class DD
         return ZERO;
     }
 
+    /** {@inheritDoc} */
+    @Override
+    public boolean isZero() {
+        // we keep |x| > |xx| and Java provides 0.0 == -0.0
+        return x == 0.0;
+    }
+
     /**
      * {@inheritDoc}
      *
@@ -2309,6 +2316,12 @@ public final class DD
         return ONE;
     }
 
+    /** {@inheritDoc} */
+    @Override
+    public boolean isOne() {
+        return x == 1.0 && xx == 0.0;
+    }
+
     /**
      * {@inheritDoc}
      *
diff --git 
a/commons-numbers-core/src/main/java/org/apache/commons/numbers/core/Multiplication.java
 
b/commons-numbers-core/src/main/java/org/apache/commons/numbers/core/Multiplication.java
index e94ed860..ed1d8b36 100644
--- 
a/commons-numbers-core/src/main/java/org/apache/commons/numbers/core/Multiplication.java
+++ 
b/commons-numbers-core/src/main/java/org/apache/commons/numbers/core/Multiplication.java
@@ -44,4 +44,20 @@ public interface Multiplication<T> {
      * @return <code>this<sup>-1</sup></code>.
      */
     T reciprocal();
+
+    /**
+     * Check if this is a neutral element of multiplication, i.e. {@code 
this.multiply(a)} returns
+     * {@code a} or an element representing the same value as {@code a}.
+     *
+     * <p>The default implementation calls {@link #equals(Object) 
equals(one())}.
+     * Implementations may want to employ more a efficient method. This may 
even
+     * be required if an implementation has multiple representations of {@code 
one} and its
+     * {@code equals} method differentiates between them.
+     *
+     * @return {@code true} if {@code this} is a neutral element of 
multiplication.
+     * @see #one()
+     */
+    default boolean isOne() {
+        return this.equals(one());
+    };
 }
diff --git 
a/commons-numbers-core/src/test/java/org/apache/commons/numbers/core/AdditionTest.java
 
b/commons-numbers-core/src/test/java/org/apache/commons/numbers/core/AdditionTest.java
new file mode 100644
index 00000000..7aff2a61
--- /dev/null
+++ 
b/commons-numbers-core/src/test/java/org/apache/commons/numbers/core/AdditionTest.java
@@ -0,0 +1,71 @@
+/*
+ * 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 org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+/**
+ * Tests for default methods of {@link Addition}.
+ */
+class AdditionTest {
+    private static class AdditionTester implements Addition<AdditionTester> {
+        private final int value;
+
+        AdditionTester(int value) {
+            this.value = value;
+        }
+
+        @Override
+        public AdditionTester add(AdditionTester a) {
+            throw new UnsupportedOperationException("not needed for testing");
+        }
+
+        @Override
+        public AdditionTester zero() {
+            return new AdditionTester(0);
+        }
+
+        @Override
+        public AdditionTester negate() {
+            throw new UnsupportedOperationException("not needed for testing");
+        }
+
+        @Override
+        public boolean equals(Object o) {
+            if (this == o) {
+                return true;
+            }
+            if (o == null || getClass() != o.getClass()) {
+                return false;
+            }
+            AdditionTester that = (AdditionTester) o;
+            return value == that.value;
+        }
+
+        @Override
+        public int hashCode() {
+            return value;
+        }
+    }
+
+    @Test
+    void testIsZero() {
+        Assertions.assertTrue(new AdditionTester(0).isZero());
+        Assertions.assertFalse(new AdditionTester(1).isZero());
+    }
+}
diff --git 
a/commons-numbers-core/src/test/java/org/apache/commons/numbers/core/DDTest.java
 
b/commons-numbers-core/src/test/java/org/apache/commons/numbers/core/DDTest.java
index 5e9980e3..ff4b3e3d 100644
--- 
a/commons-numbers-core/src/test/java/org/apache/commons/numbers/core/DDTest.java
+++ 
b/commons-numbers-core/src/test/java/org/apache/commons/numbers/core/DDTest.java
@@ -78,6 +78,31 @@ class DDTest {
         Assertions.assertSame(DD.ZERO, DD.of(1.23).zero());
     }
 
+    @Test
+    void testIsOne() {
+        Assertions.assertTrue(DD.ONE.isOne());
+        Assertions.assertTrue(DD.of(0.5, 0).add(DD.of(0.5, 0)).isOne());
+        DD value = DD.ofSum(1e300, 1e-300);
+        Assertions.assertTrue(value.divide(value).isOne());
+
+        Assertions.assertFalse(DD.ZERO.isOne());
+        Assertions.assertFalse(DD.of(0.5).isOne());
+        Assertions.assertFalse(DD.of(0.5, 1e-20).isOne());
+        Assertions.assertFalse(DD.ofSum(1.0, 1e-20).isOne());
+    }
+
+    @Test
+    void testIsZero() {
+        Assertions.assertTrue(DD.ZERO.isZero());
+        Assertions.assertTrue(DD.of(-0.0).isZero());
+        Assertions.assertTrue(DD.of(0.5, 0).subtract(DD.of(0.5, 0)).isZero());
+        DD value = DD.ofSum(1e300, 1e-300);
+        Assertions.assertTrue(value.multiply(DD.of(0.0)).isZero());
+
+        Assertions.assertFalse(DD.ONE.isZero());
+        Assertions.assertFalse(DD.of(3.1415926).isZero());
+    }
+
     @ParameterizedTest
     @ValueSource(doubles = {0, 1, Math.PI, Double.MIN_VALUE, Double.MAX_VALUE, 
Double.POSITIVE_INFINITY, Double.NaN})
     void testOfDouble(double x) {
diff --git 
a/commons-numbers-core/src/test/java/org/apache/commons/numbers/core/MultiplicationTest.java
 
b/commons-numbers-core/src/test/java/org/apache/commons/numbers/core/MultiplicationTest.java
new file mode 100644
index 00000000..d4b08d63
--- /dev/null
+++ 
b/commons-numbers-core/src/test/java/org/apache/commons/numbers/core/MultiplicationTest.java
@@ -0,0 +1,71 @@
+/*
+ * 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 org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+/**
+ * Tests for default methods of {@link Multiplication}.
+ */
+class MultiplicationTest {
+    private static class MultiplicationTester implements 
Multiplication<MultiplicationTester> {
+        private final int value;
+
+        MultiplicationTester(int value) {
+            this.value = value;
+        }
+
+        @Override
+        public MultiplicationTester multiply(MultiplicationTester a) {
+            throw new UnsupportedOperationException("not needed for testing");
+        }
+
+        @Override
+        public MultiplicationTester one() {
+            return new MultiplicationTester(1);
+        }
+
+        @Override
+        public MultiplicationTester reciprocal() {
+            throw new UnsupportedOperationException("not needed for testing");
+        }
+
+        @Override
+        public boolean equals(Object o) {
+            if (this == o) {
+                return true;
+            }
+            if (o == null || getClass() != o.getClass()) {
+                return false;
+            }
+            MultiplicationTester that = (MultiplicationTester) o;
+            return value == that.value;
+        }
+
+        @Override
+        public int hashCode() {
+            return value;
+        }
+    }
+
+    @Test
+    void testIsZero() {
+        Assertions.assertTrue(new MultiplicationTester(1).isOne());
+        Assertions.assertFalse(new MultiplicationTester(0).isOne());
+    }
+}
diff --git 
a/commons-numbers-field/src/main/java/org/apache/commons/numbers/field/FP64.java
 
b/commons-numbers-field/src/main/java/org/apache/commons/numbers/field/FP64.java
index 4768e2ad..fe1c6e63 100644
--- 
a/commons-numbers-field/src/main/java/org/apache/commons/numbers/field/FP64.java
+++ 
b/commons-numbers-field/src/main/java/org/apache/commons/numbers/field/FP64.java
@@ -165,9 +165,21 @@ public final class FP64 extends Number
         return ZERO;
     }
 
+    /** {@inheritDoc} */
+    @Override
+    public boolean isZero() {
+        return value == 0.0;
+    }
+
     /** {@inheritDoc} */
     @Override
     public FP64 one() {
         return ONE;
     }
+
+    /** {@inheritDoc} */
+    @Override
+    public boolean isOne() {
+        return value == 1.0;
+    }
 }
diff --git 
a/commons-numbers-field/src/test/java/org/apache/commons/numbers/field/FP64Test.java
 
b/commons-numbers-field/src/test/java/org/apache/commons/numbers/field/FP64Test.java
index 6388c107..5b77d9a6 100644
--- 
a/commons-numbers-field/src/test/java/org/apache/commons/numbers/field/FP64Test.java
+++ 
b/commons-numbers-field/src/test/java/org/apache/commons/numbers/field/FP64Test.java
@@ -101,6 +101,28 @@ class FP64Test {
         Assertions.assertEquals(a, a.zero().add(a));
     }
 
+    @Test
+    void testIsOne() {
+        Assertions.assertTrue(FP64.of(1.0).isOne());
+        Assertions.assertTrue(FP64.of(0.5).add(FP64.of(0.5)).isOne());
+        FP64 value = FP64.of(1e300);
+        Assertions.assertTrue(value.divide(value).isOne());
+        // avoid weirdness
+        Assertions.assertFalse(FP64.of(3).isOne());
+        Assertions.assertFalse(FP64.of(0.0).isOne());
+    }
+
+    @Test
+    void testIsZero() {
+        Assertions.assertTrue(FP64.of(0.0).isZero());
+        Assertions.assertTrue(FP64.of(0.5).subtract(FP64.of(0.5)).isZero());
+        FP64 value = FP64.of(1e300);
+        Assertions.assertTrue(value.multiply(value.zero()).isZero());
+        // avoid weirdness
+        Assertions.assertFalse(FP64.of(3).isZero());
+        Assertions.assertFalse(FP64.of(1.0).isZero());
+    }
+
     @Test
     void testSubtract() {
         final double a = 123.4;
diff --git 
a/commons-numbers-fraction/src/main/java/org/apache/commons/numbers/fraction/BigFraction.java
 
b/commons-numbers-fraction/src/main/java/org/apache/commons/numbers/fraction/BigFraction.java
index de664e6d..e1720340 100644
--- 
a/commons-numbers-fraction/src/main/java/org/apache/commons/numbers/fraction/BigFraction.java
+++ 
b/commons-numbers-fraction/src/main/java/org/apache/commons/numbers/fraction/BigFraction.java
@@ -503,11 +503,23 @@ public final class BigFraction
         return ZERO;
     }
 
+    /** {@inheritDoc} */
+    @Override
+    public boolean isZero() {
+        return numerator.signum() == 0;
+    }
+
     @Override
     public BigFraction one() {
         return ONE;
     }
 
+    /** {@inheritDoc} */
+    @Override
+    public boolean isOne() {
+        return numerator.equals(denominator);
+    }
+
     /**
      * Access the numerator as a {@code BigInteger}.
      *
@@ -1280,13 +1292,4 @@ public final class BigFraction
 
         return result;
     }
-
-    /**
-     * Returns true if this fraction is zero.
-     *
-     * @return true if zero
-     */
-    private boolean isZero() {
-        return numerator.signum() == 0;
-    }
 }
diff --git 
a/commons-numbers-fraction/src/main/java/org/apache/commons/numbers/fraction/Fraction.java
 
b/commons-numbers-fraction/src/main/java/org/apache/commons/numbers/fraction/Fraction.java
index 3f3500e8..a7eed5ce 100644
--- 
a/commons-numbers-fraction/src/main/java/org/apache/commons/numbers/fraction/Fraction.java
+++ 
b/commons-numbers-fraction/src/main/java/org/apache/commons/numbers/fraction/Fraction.java
@@ -423,11 +423,23 @@ public final class Fraction
         return ZERO;
     }
 
+    /** {@inheritDoc} */
+    @Override
+    public boolean isZero() {
+        return numerator == 0;
+    }
+
     @Override
     public Fraction one() {
         return ONE;
     }
 
+    /** {@inheritDoc} */
+    @Override
+    public boolean isOne() {
+        return numerator == denominator;
+    }
+
     /**
      * Access the numerator as an {@code int}.
      *
@@ -898,13 +910,4 @@ public final class Fraction
         final int denS = Integer.signum(denominator);
         return (31 * (31 + numerator * numS) + denominator * denS) * numS * 
denS;
     }
-
-    /**
-     * Returns true if this fraction is zero.
-     *
-     * @return true if zero
-     */
-    private boolean isZero() {
-        return numerator == 0;
-    }
 }
diff --git 
a/commons-numbers-fraction/src/test/java/org/apache/commons/numbers/fraction/BigFractionTest.java
 
b/commons-numbers-fraction/src/test/java/org/apache/commons/numbers/fraction/BigFractionTest.java
index cc3eb7f2..c1095d22 100644
--- 
a/commons-numbers-fraction/src/test/java/org/apache/commons/numbers/fraction/BigFractionTest.java
+++ 
b/commons-numbers-fraction/src/test/java/org/apache/commons/numbers/fraction/BigFractionTest.java
@@ -229,6 +229,22 @@ class BigFractionTest {
         assertFraction(769, 1250, BigFraction.from(0.6152, 1.0e-7, 100));
     }
 
+    @Test
+    void testIsOne() {
+        Assertions.assertTrue(BigFraction.of(1).isOne());
+        Assertions.assertTrue(BigFraction.of(1, 
2).multiply(BigFraction.of(2)).isOne());
+        BigFraction value = BigFraction.of(17, 33);
+        Assertions.assertTrue(value.multiply(value.reciprocal()).isOne());
+    }
+
+    @Test
+    void testIsZero() {
+        Assertions.assertTrue(BigFraction.of(0, 4712).isZero());
+        
Assertions.assertTrue(BigFraction.of(3).subtract(BigFraction.of(3)).isZero());
+        BigFraction value = BigFraction.of(11, 1111111111);
+        Assertions.assertTrue(value.multiply(value.zero()).isZero());
+    }
+
     @Test
     void testCompareTo() {
         final BigFraction a = BigFraction.of(1, 2);
diff --git 
a/commons-numbers-fraction/src/test/java/org/apache/commons/numbers/fraction/FractionTest.java
 
b/commons-numbers-fraction/src/test/java/org/apache/commons/numbers/fraction/FractionTest.java
index a0dd2ff3..def672ff 100644
--- 
a/commons-numbers-fraction/src/test/java/org/apache/commons/numbers/fraction/FractionTest.java
+++ 
b/commons-numbers-fraction/src/test/java/org/apache/commons/numbers/fraction/FractionTest.java
@@ -181,6 +181,30 @@ class FractionTest {
         assertFraction(769, 1250, Fraction.from(0.6152, 1.0e-7, 100));
     }
 
+    @Test
+    void testIsOne() {
+        Assertions.assertTrue(Fraction.of(1, 2).one().isOne());
+        Assertions.assertTrue(Fraction.of(1).isOne());
+        Assertions.assertTrue(Fraction.of(1, 
2).multiply(Fraction.of(2)).isOne());
+        Fraction value = Fraction.of(17, 33);
+        Assertions.assertTrue(value.multiply(value.reciprocal()).isOne());
+
+        Assertions.assertFalse(Fraction.of(3, 4).zero().isOne());
+        Assertions.assertFalse(Fraction.of(11, 12).isOne());
+    }
+
+    @Test
+    void testIsZero() {
+        Assertions.assertTrue(Fraction.of(1, 1).zero().isZero());
+        Assertions.assertTrue(Fraction.of(0, 4712).isZero());
+        
Assertions.assertTrue(Fraction.of(3).subtract(Fraction.of(3)).isZero());
+        Fraction value = Fraction.of(11, 1111111111);
+        Assertions.assertTrue(value.multiply(value.zero()).isZero());
+
+        Assertions.assertFalse(Fraction.of(11, 12).one().isZero());
+        Assertions.assertFalse(Fraction.of(-3, 14).isZero());
+    }
+
     @Test
     void testCompareTo() {
         final Fraction a = Fraction.of(1, 2);

Reply via email to