You are viewing a plain text version of this content. The canonical link for it is here.
Posted to issues@commons.apache.org by GitBox <gi...@apache.org> on 2021/06/02 17:39:04 UTC

[GitHub] [commons-numbers] darkma773r commented on a change in pull request #92: NUMBERS-156: replacing SafeNorm with Norms and Summation

darkma773r commented on a change in pull request #92:
URL: https://github.com/apache/commons-numbers/pull/92#discussion_r644184359



##########
File path: commons-numbers-arrays/src/main/java/org/apache/commons/numbers/arrays/Norms.java
##########
@@ -0,0 +1,427 @@
+/*
+ * 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.arrays;
+
+/** Class providing methods to compute various norm values.
+ *
+ * <p>This class uses a variety of techniques to increase numerical accuracy
+ * and reduce errors. Primary sources for the included algorithms are the
+ * 2005 paper <a href="https://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.2.1547">
+ * Accurate Sum and Dot Product</a> by Takeshi Ogita, Siegfried M. Rump,
+ * and Shin'ichi Oishi published in <em>SIAM J. Sci. Comput</em> and the
+ * <a href="http://www.netlib.org/minpack">minpack</a> "enorm" subroutine.
+ * @see <a href="https://en.wikipedia.org/wiki/Norm_(mathematics)">Norm</a>
+ */
+public final class Norms {
+
+    /** Threshold for scaling small numbers. */
+    private static final double SMALL_THRESH = 0x1.0p-500;
+
+    /** Threshold for scaling large numbers. */
+    private static final double LARGE_THRESH = 0x1.0p+500;
+
+    /** Threshold for scaling up without risking overflow. */
+    private static final double SAFE_SCALE_UP_THRESH = 0x1.0p-200;
+
+    /** Value used to scale down large numbers. */
+    private static final double SCALE_DOWN = 0x1.0p-600;
+
+    /** Value used to scale up small numbers. */
+    private static final double SCALE_UP = 0x1.0p+600;
+
+    /** Utility class; no instantiation. */
+    private Norms() {}
+
+    /** Compute the Manhattan norm (also known as the Taxicab norm or L1 norm) of the arguments.
+     * The result is equal to \(|x| + |y|\), i.e., the sum of the absolute values of the arguments.
+     *
+     * <p>Special cases:
+     * <ul>
+     *  <li>If either value is NaN, then the result is NaN.</li>
+     *  <li>If either value is infinite and the other value is not NaN, then the result is positive infinity.</li>
+     * </ul>
+     * @param x first input value
+     * @param y second input value
+     * @return Manhattan norm
+     * @see <a href="https://en.wikipedia.org/wiki/Norm_(mathematics)#Taxicab_norm_or_Manhattan_norm">Manhattan norm</a>
+     */
+    public static double manhattan(final double x, final double y) {
+        return Math.abs(x) + Math.abs(y);
+    }
+
+    /** Compute the Manhattan norm (also known as the Taxicab norm or L1 norm) of the arguments.
+     * The result is equal to \(|x| + |y| + |z|\), i.e., the sum of the absolute values of the arguments.
+     *
+     * <p>Special cases:
+     * <ul>
+     *  <li>If any value is NaN, then the result is NaN.</li>
+     *  <li>If any value is infinite and no value is NaN, then the result is positive infinity.</li>
+     * </ul>
+     * @param x first input value
+     * @param y second input value
+     * @param z third input value
+     * @return Manhattan norm
+     * @see <a href="https://en.wikipedia.org/wiki/Norm_(mathematics)#Taxicab_norm_or_Manhattan_norm">Manhattan norm</a>
+     */
+    public static double manhattan(final double x, final double y, final double z) {
+        return Summation.value(
+                Math.abs(x),
+                Math.abs(y),
+                Math.abs(z));
+    }
+
+    /** Compute the Manhattan norm (also known as the Taxicab norm or L1 norm) of the given values.
+     * The result is equal to \(|v_0| + ... + |v_i|\), i.e., the sum of the absolute values of the input elements.
+     *
+     * <p>Special cases:
+     * <ul>
+     *  <li>If any value is NaN, then the result is NaN.</li>
+     *  <li>If any value is infinite and no value is NaN, then the result is positive infinity.</li>
+     *  <li>If the array is empty, then the result is 0.</li>
+     * </ul>
+     * @param v input values
+     * @return Manhattan norm
+     * @see <a href="https://en.wikipedia.org/wiki/Norm_(mathematics)#Taxicab_norm_or_Manhattan_norm">Manhattan norm</a>
+     */
+    public static double manhattan(final double[] v) {
+        double sum = 0d;
+        double comp = 0d;
+
+        for (int i = 0; i < v.length; ++i) {
+            final double x = Math.abs(v[i]);
+            final double sx = sum + x;
+            comp += ExtendedPrecision.twoSumLow(sum, x, sx);
+            sum = sx;
+        }
+
+        return Summation.summationResult(sum, comp);
+    }
+
+    /** Compute the Euclidean norm (also known as the L2 norm) of the arguments. The result is equal to
+     * \(\sqrt{x^2 + y^2}\). This method correctly handles the possibility of overflow or underflow
+     * during the computation.
+     *
+     * <p>Special cases:
+     * <ul>
+     *  <li>If either value is NaN, then the result is NaN.</li>
+     *  <li>If either value is infinite and the other value is not NaN, then the result is positive infinity.</li>
+     * </ul>
+     *
+     * <p><strong>Comparison with Math.hypot()</strong>
+     * <p>While not guaranteed to return the same result, this method does provide similar error bounds to
+     * the JDK's Math.hypot() method and may run faster on some JVMs.
+     * @param x first input
+     * @param y second input
+     * @return Euclidean norm
+     * @see <a href="https://en.wikipedia.org/wiki/Norm_(mathematics)#Euclidean_norm">Euclidean norm</a>
+     */
+    public static double euclidean(final double x, final double y) {
+        final double xabs = Math.abs(x);
+        final double yabs = Math.abs(y);
+
+        final double max = Math.max(xabs, yabs);
+
+        // if the max is not finite, then one of the inputs must not have
+        // been finite
+        if (!Double.isFinite(max)) {
+            if (Double.isNaN(x) || Double.isNaN(y)) {
+                return Double.NaN;
+            }
+            return Double.POSITIVE_INFINITY;
+        }
+
+        // compute the scale and rescale values
+        final double scale;
+        final double rescale;
+        if (max > LARGE_THRESH) {
+            scale = SCALE_DOWN;
+            rescale = SCALE_UP;
+        } else if (max < SAFE_SCALE_UP_THRESH) {

Review comment:
       Why the change for the array case? Also, should/could that apply to the other cases as well?




-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org