001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.commons.numbers.core; 018 019/** 020 * <a href="https://en.wikipedia.org/wiki/Norm_(mathematics)">Norm</a> functions. 021 * 022 * <p>The implementations provide increased numerical accuracy. 023 * Algorithms primary source is the 2005 paper 024 * <a href="https://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.2.1547"> 025 * Accurate Sum and Dot Product</a> by Takeshi Ogita, Siegfried M. Rump, 026 * and Shin'ichi Oishi published in <em>SIAM J. Sci. Comput</em>. 027 */ 028public enum Norm { 029 /** 030 * <a href="https://en.wikipedia.org/wiki/Norm_(mathematics)#Taxicab_norm_or_Manhattan_norm"> 031 * Manhattan norm</a> (sum of the absolute values of the arguments). 032 */ 033 L1(Norm::manhattan, Norm::manhattan, Norm::manhattan), 034 /** Alias for {@link #L1}. */ 035 MANHATTAN(L1), 036 /** <a href="https://en.wikipedia.org/wiki/Norm_(mathematics)#Euclidean_norm">Euclidean norm</a>. */ 037 L2(Norm::euclidean, Norm::euclidean, Norm::euclidean), 038 /** Alias for {@link #L2}. */ 039 EUCLIDEAN(L2), 040 /** 041 * <a href="https://en.wikipedia.org/wiki/Norm_(mathematics)#Maximum_norm_(special_case_of:_infinity_norm,_uniform_norm,_or_supremum_norm)"> 042 * Maximum norm</a> (maximum of the absolute values of the arguments). 043 */ 044 LINF(Norm::maximum, Norm::maximum, Norm::maximum), 045 /** Alias for {@link #LINF}. */ 046 MAXIMUM(LINF); 047 048 /** 049 * Threshold for scaling small numbers. This value is chosen such that doubles 050 * set to this value can be squared without underflow. Values less than this must 051 * be scaled up. 052 */ 053 private static final double SMALL_THRESH = 0x1.0p-511; 054 /** 055 * Threshold for scaling large numbers. This value is chosen such that 2^31 doubles 056 * set to this value can be squared and added without overflow. Values greater than 057 * this must be scaled down. 058 */ 059 private static final double LARGE_THRESH = 0x1.0p+496; 060 /** 061 * Threshold for scaling up a single value by {@link #SCALE_UP} without risking 062 * overflow when the value is squared. 063 */ 064 private static final double SAFE_SCALE_UP_THRESH = 0x1.0p-100; 065 /** Value used to scale down large numbers. */ 066 private static final double SCALE_DOWN = 0x1.0p-600; 067 /** Value used to scale up small numbers. */ 068 private static final double SCALE_UP = 0x1.0p+600; 069 070 /** Threshold for the difference between the exponents of two Euclidean 2D input values 071 * where the larger value dominates the calculation. 072 */ 073 private static final int EXP_DIFF_THRESHOLD_2D = 54; 074 075 /** Function of 2 arguments. */ 076 private final Two two; 077 /** Function of 3 arguments. */ 078 private final Three three; 079 /** Function of array argument. */ 080 private final Array array; 081 082 /** Function of 2 arguments. */ 083 @FunctionalInterface 084 private interface Two { 085 /** 086 * @param x Argument. 087 * @param y Argument. 088 * @return the norm. 089 */ 090 double of(double x, double y); 091 } 092 /** Function of 3 arguments. */ 093 @FunctionalInterface 094 private interface Three { 095 /** 096 * @param x Argument. 097 * @param y Argument. 098 * @param z Argument. 099 * @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}