1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements. See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17 package org.apache.commons.numbers.core;
18
19 /**
20 * <a href="https://en.wikipedia.org/wiki/Norm_(mathematics)">Norm</a> functions.
21 *
22 * <p>The implementations provide increased numerical accuracy.
23 * Algorithms primary source is the 2005 paper
24 * <a href="https://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.2.1547">
25 * Accurate Sum and Dot Product</a> by Takeshi Ogita, Siegfried M. Rump,
26 * and Shin'ichi Oishi published in <em>SIAM J. Sci. Comput</em>.
27 */
28 public enum Norm {
29 /**
30 * <a href="https://en.wikipedia.org/wiki/Norm_(mathematics)#Taxicab_norm_or_Manhattan_norm">
31 * Manhattan norm</a> (sum of the absolute values of the arguments).
32 */
33 L1(Norm::manhattan, Norm::manhattan, Norm::manhattan),
34 /** Alias for {@link #L1}. */
35 MANHATTAN(L1),
36 /** <a href="https://en.wikipedia.org/wiki/Norm_(mathematics)#Euclidean_norm">Euclidean norm</a>. */
37 L2(Norm::euclidean, Norm::euclidean, Norm::euclidean),
38 /** Alias for {@link #L2}. */
39 EUCLIDEAN(L2),
40 /**
41 * <a href="https://en.wikipedia.org/wiki/Norm_(mathematics)#Maximum_norm_(special_case_of:_infinity_norm,_uniform_norm,_or_supremum_norm)">
42 * Maximum norm</a> (maximum of the absolute values of the arguments).
43 */
44 LINF(Norm::maximum, Norm::maximum, Norm::maximum),
45 /** Alias for {@link #LINF}. */
46 MAXIMUM(LINF);
47
48 /**
49 * Threshold for scaling small numbers. This value is chosen such that doubles
50 * set to this value can be squared without underflow. Values less than this must
51 * be scaled up.
52 */
53 private static final double SMALL_THRESH = 0x1.0p-511;
54 /**
55 * Threshold for scaling large numbers. This value is chosen such that 2^31 doubles
56 * set to this value can be squared and added without overflow. Values greater than
57 * this must be scaled down.
58 */
59 private static final double LARGE_THRESH = 0x1.0p+496;
60 /**
61 * Threshold for scaling up a single value by {@link #SCALE_UP} without risking
62 * overflow when the value is squared.
63 */
64 private static final double SAFE_SCALE_UP_THRESH = 0x1.0p-100;
65 /** Value used to scale down large numbers. */
66 private static final double SCALE_DOWN = 0x1.0p-600;
67 /** Value used to scale up small numbers. */
68 private static final double SCALE_UP = 0x1.0p+600;
69
70 /** Threshold for the difference between the exponents of two Euclidean 2D input values
71 * where the larger value dominates the calculation.
72 */
73 private static final int EXP_DIFF_THRESHOLD_2D = 54;
74
75 /** Function of 2 arguments. */
76 private final Two two;
77 /** Function of 3 arguments. */
78 private final Three three;
79 /** Function of array argument. */
80 private final Array array;
81
82 /** Function of 2 arguments. */
83 @FunctionalInterface
84 private interface Two {
85 /**
86 * @param x Argument.
87 * @param y Argument.
88 * @return the norm.
89 */
90 double of(double x, double y);
91 }
92 /** Function of 3 arguments. */
93 @FunctionalInterface
94 private interface Three {
95 /**
96 * @param x Argument.
97 * @param y Argument.
98 * @param z Argument.
99 * @return the norm.
100 */
101 double of(double x, double y, double z);
102 }
103 /** Function of array argument. */
104 @FunctionalInterface
105 private interface Array {
106 /**
107 * @param v Array of arguments.
108 * @return the norm.
109 */
110 double of(double[] v);
111 }
112
113 /**
114 * @param two Function of 2 arguments.
115 * @param three Function of 3 arguments.
116 * @param array Function of array argument.
117 */
118 Norm(Two two,
119 Three three,
120 Array array) {
121 this.two = two;
122 this.three = three;
123 this.array = array;
124 }
125
126 /**
127 * @param alias Alternative name.
128 */
129 Norm(Norm alias) {
130 this.two = alias.two;
131 this.three = alias.three;
132 this.array = alias.array;
133 }
134
135 /**
136 * Computes the norm.
137 *
138 * <p>Special cases:
139 * <ul>
140 * <li>If either value is {@link Double#NaN}, then the result is {@link Double#NaN}.</li>
141 * <li>If either value is infinite and the other value is not {@link Double#NaN}, then
142 * the result is {@link Double#POSITIVE_INFINITY}.</li>
143 * </ul>
144 *
145 * @param x Argument.
146 * @param y Argument.
147 * @return the norm.
148 */
149 public final double of(double x,
150 double y) {
151 return two.of(x, y);
152 }
153
154 /**
155 * Computes the norm.
156 *
157 * <p>Special cases:
158 * <ul>
159 * <li>If any value is {@link Double#NaN}, then the result is {@link Double#NaN}.</li>
160 * <li>If any value is infinite and no value is not {@link Double#NaN}, then the
161 * result is {@link Double#POSITIVE_INFINITY}.</li>
162 * </ul>
163 *
164 * @param x Argument.
165 * @param y Argument.
166 * @param z Argument.
167 * @return the norm.
168 */
169 public final double of(double x,
170 double y,
171 double z) {
172 return three.of(x, y, z);
173 }
174
175 /**
176 * Computes the norm.
177 *
178 * <p>Special cases:
179 * <ul>
180 * <li>If any value is {@link Double#NaN}, then the result is {@link Double#NaN}.</li>
181 * <li>If any value is infinite and no value is not {@link Double#NaN}, then the
182 * result is {@link Double#POSITIVE_INFINITY}.</li>
183 * </ul>
184 *
185 * @param v Argument.
186 * @return the norm.
187 * @throws IllegalArgumentException if the array is empty.
188 */
189 public final double of(double[] v) {
190 ensureNonEmpty(v);
191 return array.of(v);
192 }
193
194 /** Computes the Manhattan norm.
195 *
196 * @param x first input value
197 * @param y second input value
198 * @return \(|x| + |y|\).
199 *
200 * @see #L1
201 * @see #MANHATTAN
202 * @see #of(double,double)
203 */
204 private static double manhattan(final double x,
205 final double y) {
206 return Math.abs(x) + Math.abs(y);
207 }
208
209 /** Computes the Manhattan norm.
210 *
211 * @param x first input value
212 * @param y second input value
213 * @param z third input value
214 * @return \(|x| + |y| + |z|\)
215 *
216 * @see #L1
217 * @see #MANHATTAN
218 * @see #of(double,double,double)
219 */
220 private static double manhattan(final double x,
221 final double y,
222 final double z) {
223 return Sum.of(Math.abs(x))
224 .add(Math.abs(y))
225 .add(Math.abs(z))
226 .getAsDouble();
227 }
228
229 /** Computes the Manhattan norm.
230 *
231 * @param v input values
232 * @return \(|v_0| + ... + |v_i|\)
233 *
234 * @see #L1
235 * @see #MANHATTAN
236 * @see #of(double[])
237 */
238 private static double manhattan(final double[] v) {
239 final Sum sum = Sum.create();
240
241 for (final double d : v) {
242 sum.add(Math.abs(d));
243 }
244
245 return sum.getAsDouble();
246 }
247
248 /** Computes the Euclidean norm.
249 * This implementation handles possible overflow or underflow.
250 *
251 * <p><strong>Comparison with Math.hypot()</strong>
252 * While not guaranteed to return the same result, this method provides
253 * similar error bounds as {@link Math#hypot(double, double)} (and may run faster on
254 * some JVM).
255 *
256 * @param x first input
257 * @param y second input
258 * @return \(\sqrt{x^2 + y^2}\).
259 *
260 * @see #L2
261 * @see #EUCLIDEAN
262 * @see #of(double,double)
263 */
264 private static double euclidean(final double x,
265 final double y) {
266 final double xabs = Math.abs(x);
267 final double yabs = Math.abs(y);
268
269 final double max;
270 final double min;
271 // the compare method considers NaN greater than other values, meaning that our
272 // check for if the max is finite later on will detect NaNs correctly
273 if (Double.compare(xabs, yabs) > 0) {
274 max = xabs;
275 min = yabs;
276 } else {
277 max = yabs;
278 min = xabs;
279 }
280
281 // if the max is not finite, then one of the inputs must not have
282 // been finite
283 if (!Double.isFinite(max)) {
284 // let the standard multiply operation determine whether to return NaN or infinite
285 return xabs * yabs;
286 } else if (Math.getExponent(max) - Math.getExponent(min) > EXP_DIFF_THRESHOLD_2D) {
287 // value is completely dominated by max; just return max
288 return max;
289 }
290
291 // compute the scale and rescale values
292 final double scale;
293 final double rescale;
294 if (max > LARGE_THRESH) {
295 scale = SCALE_DOWN;
296 rescale = SCALE_UP;
297 } else if (max < SAFE_SCALE_UP_THRESH) {
298 scale = SCALE_UP;
299 rescale = SCALE_DOWN;
300 } else {
301 scale = 1d;
302 rescale = 1d;
303 }
304
305 // initialise sum and compensation using scaled x
306 final double sx = xabs * scale;
307 double sum = sx * sx;
308 double comp = DD.twoSquareLow(sx, sum);
309
310 // add scaled y
311 final double sy = yabs * scale;
312 final double py = sy * sy;
313 comp += DD.twoSquareLow(sy, py);
314 final double sumPy = sum + py;
315 comp += DD.twoSumLow(sum, py, sumPy);
316 sum = sumPy;
317
318 return Math.sqrt(sum + comp) * rescale;
319 }
320
321 /** Computes the Euclidean norm.
322 * This implementation handles possible overflow or underflow.
323 *
324 * @param x first input
325 * @param y second input
326 * @param z third input
327 * @return \(\sqrt{x^2 + y^2 + z^2}\)
328 *
329 * @see #L2
330 * @see #EUCLIDEAN
331 * @see #of(double,double,double)
332 */
333 private static double euclidean(final double x,
334 final double y,
335 final double z) {
336 final double xabs = Math.abs(x);
337 final double yabs = Math.abs(y);
338 final double zabs = Math.abs(z);
339
340 final double max = Math.max(Math.max(xabs, yabs), zabs);
341
342 // if the max is not finite, then one of the inputs must not have
343 // been finite
344 if (!Double.isFinite(max)) {
345 // let the standard multiply operation determine whether to
346 // return NaN or infinite
347 return xabs * yabs * zabs;
348 }
349
350 // compute the scale and rescale values
351 final double scale;
352 final double rescale;
353 if (max > LARGE_THRESH) {
354 scale = SCALE_DOWN;
355 rescale = SCALE_UP;
356 } else if (max < SAFE_SCALE_UP_THRESH) {
357 scale = SCALE_UP;
358 rescale = SCALE_DOWN;
359 } else {
360 scale = 1d;
361 rescale = 1d;
362 }
363
364
365 // initialise sum and compensation using scaled x
366 final double sx = xabs * scale;
367 double sum = sx * sx;
368 double comp = DD.twoSquareLow(sx, sum);
369
370 // add scaled y
371 final double sy = yabs * scale;
372 final double py = sy * sy;
373 comp += DD.twoSquareLow(sy, py);
374 final double sumPy = sum + py;
375 comp += DD.twoSumLow(sum, py, sumPy);
376 sum = sumPy;
377
378 // add scaled z
379 final double sz = zabs * scale;
380 final double pz = sz * sz;
381 comp += DD.twoSquareLow(sz, pz);
382 final double sumPz = sum + pz;
383 comp += DD.twoSumLow(sum, pz, sumPz);
384 sum = sumPz;
385
386 return Math.sqrt(sum + comp) * rescale;
387 }
388
389 /** Computes the Euclidean norm.
390 * This implementation handles possible overflow or underflow.
391 *
392 * @param v input values
393 * @return \(\sqrt{v_0^2 + ... + v_{n-1}^2}\).
394 *
395 * @see #L2
396 * @see #EUCLIDEAN
397 * @see #of(double[])
398 */
399 private static double euclidean(final double[] v) {
400 // sum of big, normal and small numbers
401 double s1 = 0;
402 double s2 = 0;
403 double s3 = 0;
404
405 // sum compensation values
406 double c1 = 0;
407 double c2 = 0;
408 double c3 = 0;
409
410 for (int i = 0; i < v.length; ++i) {
411 final double x = Math.abs(v[i]);
412 if (!Double.isFinite(x)) {
413 // not finite; determine whether to return NaN or positive infinity
414 return euclideanNormSpecial(v, i);
415 } else if (x > LARGE_THRESH) {
416 // scale down
417 final double sx = x * SCALE_DOWN;
418
419 // compute the product and product compensation
420 final double p = sx * sx;
421 final double cp = DD.twoSquareLow(sx, p);
422
423 // compute the running sum and sum compensation
424 final double s = s1 + p;
425 final double cs = DD.twoSumLow(s1, p, s);
426
427 // update running totals
428 c1 += cp + cs;
429 s1 = s;
430 } else if (x < SMALL_THRESH) {
431 // scale up
432 final double sx = x * SCALE_UP;
433
434 // compute the product and product compensation
435 final double p = sx * sx;
436 final double cp = DD.twoSquareLow(sx, p);
437
438 // compute the running sum and sum compensation
439 final double s = s3 + p;
440 final double cs = DD.twoSumLow(s3, p, s);
441
442 // update running totals
443 c3 += cp + cs;
444 s3 = s;
445 } else {
446 // no scaling
447 // compute the product and product compensation
448 final double p = x * x;
449 final double cp = DD.twoSquareLow(x, p);
450
451 // compute the running sum and sum compensation
452 final double s = s2 + p;
453 final double cs = DD.twoSumLow(s2, p, s);
454
455 // update running totals
456 c2 += cp + cs;
457 s2 = s;
458 }
459 }
460
461 // The highest sum is the significant component. Add the next significant.
462 // Note that the "x * SCALE_DOWN * SCALE_DOWN" expressions must be executed
463 // in the order given. If the two scale factors are multiplied together first,
464 // they will underflow to zero.
465 if (s1 != 0) {
466 // add s1, s2, c1, c2
467 final double s2Adj = s2 * SCALE_DOWN * SCALE_DOWN;
468 final double sum = s1 + s2Adj;
469 final double comp = DD.twoSumLow(s1, s2Adj, sum) +
470 c1 + (c2 * SCALE_DOWN * SCALE_DOWN);
471 return Math.sqrt(sum + comp) * SCALE_UP;
472 } else if (s2 != 0) {
473 // add s2, s3, c2, c3
474 final double s3Adj = s3 * SCALE_DOWN * SCALE_DOWN;
475 final double sum = s2 + s3Adj;
476 final double comp = DD.twoSumLow(s2, s3Adj, sum) +
477 c2 + (c3 * SCALE_DOWN * SCALE_DOWN);
478 return Math.sqrt(sum + comp);
479 }
480 // add s3, c3
481 return Math.sqrt(s3 + c3) * SCALE_DOWN;
482 }
483
484 /** Special cases of non-finite input.
485 *
486 * @param v input vector
487 * @param start index to start examining the input vector from
488 * @return Euclidean norm special value
489 */
490 private static double euclideanNormSpecial(final double[] v,
491 final int start) {
492 for (int i = start; i < v.length; ++i) {
493 if (Double.isNaN(v[i])) {
494 return Double.NaN;
495 }
496 }
497 return Double.POSITIVE_INFINITY;
498 }
499
500 /** Computes the maximum norm.
501 *
502 * @param x first input
503 * @param y second input
504 * @return \(\max{(|x|, |y|)}\).
505 *
506 * @see #LINF
507 * @see #MAXIMUM
508 * @see #of(double,double)
509 */
510 private static double maximum(final double x,
511 final double y) {
512 return Math.max(Math.abs(x), Math.abs(y));
513 }
514
515 /** Computes the maximum norm.
516 *
517 * @param x first input
518 * @param y second input
519 * @param z third input
520 * @return \(\max{(|x|, |y|, |z|)}\).
521 *
522 * @see #LINF
523 * @see #MAXIMUM
524 * @see #of(double,double,double)
525 */
526 private static double maximum(final double x,
527 final double y,
528 final double z) {
529 return Math.max(Math.abs(x),
530 Math.max(Math.abs(y),
531 Math.abs(z)));
532 }
533
534 /** Computes the maximum norm.
535 *
536 * @param v input values
537 * @return \(\max{(|v_0|, \ldots, |v_{n-1}|)}\)
538 *
539 * @see #LINF
540 * @see #MAXIMUM
541 * @see #of(double[])
542 */
543 private static double maximum(final double[] v) {
544 double max = 0d;
545 for (final double d : v) {
546 max = Math.max(max, Math.abs(d));
547 }
548 return max;
549 }
550
551 /**
552 * @param a Array.
553 * @throws IllegalArgumentException for zero-size array.
554 */
555 private static void ensureNonEmpty(double[] a) {
556 if (a.length == 0) {
557 throw new IllegalArgumentException("Empty array");
558 }
559 }
560 }