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 */ 017 package org.apache.commons.nabla; 018 019 import org.apache.commons.nabla.core.DifferentialPair; 020 021 /** <code>StrictMath</code>-like utility class computing differentials. 022 * <p>This class provides mathematical functions similar to the functions 023 * provided by the standard <code>java.lang.StrictMath</code> class but 024 * using {@link org.apache.commons.nabla.core.DifferentialPair DifferentialPair} 025 * instances instead of doubles.</p> 026 */ 027 public class NablaStrictMath { 028 029 /** Hidden constructor. 030 * <p>Since this class is a utility class, it cannot be instantiated.</p> 031 */ 032 private NablaStrictMath() { 033 } 034 035 /////////////////////////// 036 // exponential functions // 037 /////////////////////////// 038 039 /** Exponential function. 040 * @param a function input value 041 * @return e<sup>a</sup> 042 */ 043 public static DifferentialPair exp(final DifferentialPair a) { 044 final double e = StrictMath.exp(a.getValue()); 045 return new DifferentialPair(e, a.getFirstDerivative() * e); 046 } 047 048 /** Exponential minus 1 function. 049 * @param a function input value 050 * @return e<sup>a</sup>-1 051 */ 052 public static DifferentialPair expm1(final DifferentialPair a) { 053 final double e = StrictMath.expm1(a.getValue()); 054 return new DifferentialPair(e, a.getFirstDerivative() * (e + 1)); 055 } 056 057 /** Natural logarithm function. 058 * @param a function input value 059 * @return log(a) 060 */ 061 public static DifferentialPair log(final DifferentialPair a) { 062 final double a0 = a.getValue(); 063 return new DifferentialPair(StrictMath.log(a0), a.getFirstDerivative() / a0); 064 } 065 066 /** Shifted natural logarithm function. 067 * @param a function input value 068 * @return log(1+a) 069 */ 070 public static DifferentialPair log1p(final DifferentialPair a) { 071 final double a0 = a.getValue(); 072 return new DifferentialPair(StrictMath.log1p(a0), a.getFirstDerivative() / (1 + a0)); 073 } 074 075 /** Base 10 logarithm function. 076 * @param a function input value 077 * @return log<sub>10</sub>(a) 078 */ 079 public static DifferentialPair log10(final DifferentialPair a) { 080 final double a0 = a.getValue(); 081 return new DifferentialPair(StrictMath.log10(a0), a.getFirstDerivative() / (a0 * StrictMath.log(10))); 082 } 083 084 085 //////////////////////// 086 // circular functions // 087 //////////////////////// 088 089 /** Cosine function. 090 * @param a function input value 091 * @return cos(a) 092 */ 093 public static DifferentialPair cos(final DifferentialPair a) { 094 final double a0 = a.getValue(); 095 return new DifferentialPair(StrictMath.cos(a0), -a.getFirstDerivative() * StrictMath.sin(a0)); 096 } 097 098 /** Sine function. 099 * @param a function input value 100 * @return sin(a) 101 */ 102 public static DifferentialPair sin(final DifferentialPair a) { 103 final double a0 = a.getValue(); 104 return new DifferentialPair(StrictMath.sin(a0), a.getFirstDerivative() * StrictMath.cos(a0)); 105 } 106 107 /** Tangent function. 108 * @param a function input value 109 * @return tan(a) 110 */ 111 public static DifferentialPair tan(final DifferentialPair a) { 112 final double t = StrictMath.tan(a.getValue()); 113 return new DifferentialPair(t, a.getFirstDerivative() * (1 + t * t)); 114 } 115 116 /** Inverse cosine function. 117 * @param a function input value 118 * @return acos(a) 119 */ 120 public static DifferentialPair acos(final DifferentialPair a) { 121 final double a0 = a.getValue(); 122 return new DifferentialPair(StrictMath.acos(a0), -a.getFirstDerivative() / StrictMath.sqrt(1 - a0 * a0)); 123 } 124 125 /** Inverse sine function. 126 * @param a function input value 127 * @return asin(a) 128 */ 129 public static DifferentialPair asin(final DifferentialPair a) { 130 final double a0 = a.getValue(); 131 return new DifferentialPair(StrictMath.asin(a0), a.getFirstDerivative() / StrictMath.sqrt(1 - a0 * a0)); 132 } 133 134 /** Inverse tangent function. 135 * @param a function input value 136 * @return atan(a) 137 */ 138 public static DifferentialPair atan(final DifferentialPair a) { 139 final double a0 = a.getValue(); 140 return new DifferentialPair(StrictMath.atan(a0), a.getFirstDerivative() / (1 + a0 * a0)); 141 } 142 143 144 ///////////////////////////////// 145 // cartesian/polar conversions // 146 //////////////////////////////// 147 148 /** Cartesian to polar conversion function. 149 * @param y cartesian ordinate of the point 150 * @param x cartesian abscissa of the point 151 * @return angular part of the polar coordinates of the point 152 */ 153 public static DifferentialPair atan2(final DifferentialPair y, final double x) { 154 final double y0 = y.getValue(); 155 return new DifferentialPair(StrictMath.atan2(y0, x), 156 x * y.getFirstDerivative() / (x * x + y0 * y0)); 157 } 158 159 /** Cartesian to polar conversion function. 160 * @param y cartesian ordinate of the point 161 * @param x cartesian abscissa of the point 162 * @return angular part of the polar coordinates of the point 163 */ 164 public static DifferentialPair atan2(final double y, final DifferentialPair x) { 165 final double x0 = x.getValue(); 166 return new DifferentialPair(StrictMath.atan2(y, x0), 167 -y * x.getFirstDerivative() / (x0 * x0 + y * y)); 168 } 169 170 /** Cartesian to polar conversion function. 171 * @param y cartesian ordinate of the point 172 * @param x cartesian abscissa of the point 173 * @return angular part of the polar coordinates of the point 174 */ 175 public static DifferentialPair atan2(final DifferentialPair y, final DifferentialPair x) { 176 final double y0 = y.getValue(); 177 final double x0 = x.getValue(); 178 return new DifferentialPair(StrictMath.atan2(y0, x0), 179 (x0 * y.getFirstDerivative() - y0 * x.getFirstDerivative()) / (x0 * x0 + y0 * y0)); 180 } 181 182 /** Cartesian to polar conversion function. 183 * @param x cartesian abscissa of the point 184 * @param y cartesian ordinate of the point 185 * @return radius part of the polar coordinates of the point 186 */ 187 public static DifferentialPair hypot(final DifferentialPair x, final double y) { 188 final double x0 = x.getValue(); 189 final double h = StrictMath.hypot(x0, y); 190 return new DifferentialPair(h, x0 * x.getFirstDerivative() / h); 191 } 192 193 /** Cartesian to polar conversion function. 194 * @param x cartesian abscissa of the point 195 * @param y cartesian ordinate of the point 196 * @return radius part of the polar coordinates of the point 197 */ 198 public static DifferentialPair hypot(final double x, final DifferentialPair y) { 199 final double y0 = y.getValue(); 200 final double h = StrictMath.hypot(x, y0); 201 return new DifferentialPair(h, y0 * y.getFirstDerivative() / h); 202 } 203 204 /** Cartesian to polar conversion function. 205 * @param x cartesian abscissa of the point 206 * @param y cartesian ordinate of the point 207 * @return radius part of the polar coordinates of the point 208 */ 209 public static DifferentialPair hypot(final DifferentialPair x, final DifferentialPair y) { 210 final double x0 = x.getValue(); 211 final double y0 = y.getValue(); 212 final double h = StrictMath.hypot(x0, y0); 213 return new DifferentialPair(h, (x0 * x.getFirstDerivative() + y0 * y.getFirstDerivative()) / h); 214 } 215 216 217 ////////////////////////// 218 // hyperbolic functions // 219 ////////////////////////// 220 221 /** Hyperbolic cosine function. 222 * @param a function input value 223 * @return cosh(a) 224 */ 225 public static DifferentialPair cosh(final DifferentialPair a) { 226 final double a0 = a.getValue(); 227 return new DifferentialPair(StrictMath.cosh(a0), a.getFirstDerivative() * StrictMath.sinh(a0)); 228 } 229 230 /** Hyperbolic sine function. 231 * @param a function input value 232 * @return sinh(a) 233 */ 234 public static DifferentialPair sinh(final DifferentialPair a) { 235 final double a0 = a.getValue(); 236 return new DifferentialPair(StrictMath.sinh(a0), a.getFirstDerivative() * StrictMath.cosh(a0)); 237 } 238 239 /** Hyperbolic tangent function. 240 * @param a function input value 241 * @return tanh(a) 242 */ 243 public static DifferentialPair tanh(final DifferentialPair a) { 244 final double t = StrictMath.tanh(a.getValue()); 245 return new DifferentialPair(t, a.getFirstDerivative() * (1 - t * t)); 246 } 247 248 /** Inverse hyperbolic cosine function. 249 * @param a function input value 250 * @return acosh(a) 251 */ 252 public static DifferentialPair acosh(final DifferentialPair a) { 253 // the acosh function is not provided by java.lang.StrictMath as of Java6 254 final double a0 = a.getValue(); 255 final double root = StrictMath.sqrt(a0 - 1) * StrictMath.sqrt(a0 + 1); 256 return new DifferentialPair(StrictMath.log(a0 + root), a.getFirstDerivative() / root); 257 } 258 259 /** Inverse hyperbolic sine function. 260 * @param a function input value 261 * @return asinh(a) 262 */ 263 public static DifferentialPair asinh(final DifferentialPair a) { 264 // the asinh function is not provided by java.lang.StrictMath as of Java6 265 final double a0 = a.getValue(); 266 final double root = StrictMath.sqrt(a0 * a0 + 1); 267 return new DifferentialPair(StrictMath.log(a0 + root), a.getFirstDerivative() / root); 268 } 269 270 /** Inverse hyperbolic tangent function. 271 * @param a function input value 272 * @return atanh(a) 273 */ 274 public static DifferentialPair atanh(final DifferentialPair a) { 275 // the atanh function is not provided by java.lang.StrictMath as of Java6 276 final double a0 = a.getValue(); 277 final double ath = (StrictMath.log1p(a0) - StrictMath.log1p(-a0)) / 2; 278 return new DifferentialPair(ath, a.getFirstDerivative() / (1 - a0 * a0)); 279 } 280 281 ///////////////////// 282 // power functions // 283 ///////////////////// 284 285 /** Square root function. 286 * @param a function input value 287 * @return &sqrt;a 288 */ 289 public static DifferentialPair sqrt(final DifferentialPair a) { 290 final double root = StrictMath.sqrt(a.getValue()); 291 return new DifferentialPair(root, a.getFirstDerivative() / (2 * root)); 292 } 293 294 /** Cubic root function. 295 * @param a function input value 296 * @return cbrt(a) 297 */ 298 public static DifferentialPair cbrt(final DifferentialPair a) { 299 final double root = StrictMath.cbrt(a.getValue()); 300 return new DifferentialPair(root, a.getFirstDerivative() / (3 * root * root)); 301 } 302 303 /** Power function. 304 * @param a base value 305 * @param b exponent value 306 * @return a<sup>b</sup> 307 */ 308 public static DifferentialPair pow(final DifferentialPair a, final double b) { 309 final double a0 = a.getValue(); 310 final double p = StrictMath.pow(a0, b); 311 return new DifferentialPair(p, a.getFirstDerivative() * b * p / a0); 312 } 313 314 /** Power function. 315 * @param a base value 316 * @param b exponent value 317 * @return a<sup>b</sup> 318 */ 319 public static DifferentialPair pow(final double a, final DifferentialPair b) { 320 final double p = StrictMath.pow(a, b.getValue()); 321 return new DifferentialPair(p, b.getFirstDerivative() * StrictMath.log(a) * p); 322 } 323 324 /** Power function. 325 * @param a base value 326 * @param b exponent value 327 * @return a<sup>b</sup> 328 */ 329 public static DifferentialPair pow(final DifferentialPair a, final DifferentialPair b) { 330 final double a0 = a.getValue(); 331 final double b0 = b.getValue(); 332 final double p = StrictMath.pow(a0, b0); 333 return new DifferentialPair(p, (a.getFirstDerivative() * b0 / a0 + b.getFirstDerivative() * StrictMath.log(a0)) * p); 334 } 335 336 337 //////////////////////////// 338 // sign related functions // 339 //////////////////////////// 340 341 /** Absolute value function. 342 * @param a function input value 343 * @return |a| 344 */ 345 public static DifferentialPair abs(final DifferentialPair a) { 346 return (a.getValue() >= 0) ? a : DifferentialPair.negate(a); 347 } 348 349 /** Sign function. 350 * @param a function input value 351 * @return -1, 0 or +1 according to the sign of a 352 */ 353 public static DifferentialPair signum(final DifferentialPair a) { 354 return DifferentialPair.newConstant(StrictMath.signum(a.getValue())); 355 } 356 357 /** Sign copy function. 358 * @param magnitude function input value 359 * @param sign sign reference 360 * @return either magnitude or -magnitude to match sign 361 */ 362 public static DifferentialPair copySign(final DifferentialPair magnitude, 363 final double sign) { 364 final long mBits = Double.doubleToLongBits(magnitude.getValue()); 365 final long sBits = Double.doubleToLongBits(sign); 366 return (((mBits ^ sBits) & 0x8000000000000000L) == 0) ? 367 magnitude : DifferentialPair.negate(magnitude); 368 } 369 370 /** Sign copy function. 371 * @param magnitude function input value 372 * @param sign sign reference 373 * @return either magnitude or -magnitude to match sign 374 */ 375 public static DifferentialPair copySign(final double magnitude, 376 final DifferentialPair sign) { 377 final long mBits = Double.doubleToLongBits(magnitude); 378 final long sBits = Double.doubleToLongBits(sign.getValue()); 379 return (((mBits ^ sBits) & 0x8000000000000000L) == 0) ? 380 DifferentialPair.newConstant(magnitude) : 381 DifferentialPair.newConstant(-magnitude); 382 } 383 384 /** Sign copy function. 385 * @param magnitude function input value 386 * @param sign sign reference 387 * @return either magnitude or -magnitude to match sign 388 */ 389 public static DifferentialPair copySign(final DifferentialPair magnitude, 390 final DifferentialPair sign) { 391 final long mBits = Double.doubleToLongBits(magnitude.getValue()); 392 final long sBits = Double.doubleToLongBits(sign.getValue()); 393 return (((mBits ^ sBits) & 0x8000000000000000L) == 0) ? 394 magnitude : DifferentialPair.negate(magnitude); 395 } 396 397 398 //////////////////////////// 399 // neighborhood functions // 400 //////////////////////////// 401 402 /** Floor function. 403 * @param a function input value 404 * @return largest integer value smaller than a or equal to a 405 */ 406 public static DifferentialPair floor(final DifferentialPair a) { 407 return DifferentialPair.newConstant(StrictMath.floor(a.getValue())); 408 } 409 410 /** Rounding function. 411 * @param a function input value 412 * @return closest integer value to a 413 */ 414 public static DifferentialPair rint(final DifferentialPair a) { 415 return DifferentialPair.newConstant(StrictMath.rint(a.getValue())); 416 } 417 418 /** Ceil function. 419 * @param a function input value 420 * @return smallest integer value greater than a or equal to a 421 */ 422 public static DifferentialPair ceil(final DifferentialPair a) { 423 return DifferentialPair.newConstant(StrictMath.ceil(a.getValue())); 424 } 425 426 /** Neighbor function. 427 * @param a function input value 428 * @return smallest representable double value ly greater than a 429 */ 430 public static DifferentialPair nextUp(final DifferentialPair a) { 431 return new DifferentialPair(StrictMath.nextUp(a.getValue()), a.getFirstDerivative()); 432 } 433 434 /** Neighbor function. 435 * @param start function input value 436 * @param direction direction of neighboring (relative to a) 437 * @return closest double value different than a in given direction 438 */ 439 public static DifferentialPair nextAfter(final DifferentialPair start, 440 final double direction) { 441 return new DifferentialPair(StrictMath.nextAfter(start.getValue(), direction), 442 start.getFirstDerivative()); 443 } 444 445 /** Neighbor function. 446 * @param start function input value 447 * @param direction direction of neighboring (relative to a) 448 * @return closest double value different than a in given direction 449 */ 450 public static DifferentialPair nextAfter(final double start, 451 final DifferentialPair direction) { 452 return DifferentialPair.newConstant(StrictMath.nextAfter(start, direction.getValue())); 453 } 454 455 /** Neighbor function. 456 * @param start function input value 457 * @param direction direction of neighboring (relative to a) 458 * @return closest double value different than a in given direction 459 */ 460 public static DifferentialPair nextAfter(final DifferentialPair start, 461 final DifferentialPair direction) { 462 return new DifferentialPair(StrictMath.nextAfter(start.getValue(), direction.getValue()), start.getFirstDerivative()); 463 } 464 465 466 //////////////////////// 467 // encoding functions // 468 //////////////////////// 469 470 /** Unit in Last Position function. 471 * @param a function input value 472 * @return value of the least significant bit of a 473 */ 474 public static DifferentialPair ulp(final DifferentialPair a) { 475 return DifferentialPair.newConstant(StrictMath.ulp(a.getValue())); 476 } 477 478 /** Binary rescaling function. 479 * @param a function input value 480 * @param scale exponent part of the 2<sup>scale</sup> multiplication factor 481 * @return a × 2<sup>scale</sup> 482 */ 483 public static DifferentialPair scalb(final DifferentialPair a, 484 final int scale) { 485 return new DifferentialPair(StrictMath.scalb(a.getValue(), scale), 486 StrictMath.scalb(a.getFirstDerivative(), scale)); 487 } 488 489 /** Remainder function. 490 * @param f1 dividend 491 * @param f2 divisor 492 * @return remainder of f1/f2, following IEEE754 conventions 493 */ 494 public static DifferentialPair IEEEremainder(final DifferentialPair f1, 495 final double f2) { 496 final double r = StrictMath.IEEEremainder(f1.getValue(), f2); 497 return new DifferentialPair(r, f1.getFirstDerivative()); 498 } 499 500 /** Remainder function. 501 * @param f1 dividend 502 * @param f2 divisor 503 * @return remainder of f1/f2, following IEEE754 conventions 504 */ 505 public static DifferentialPair IEEEremainder(final double f1, 506 final DifferentialPair f2) { 507 final double f20 = f2.getValue(); 508 final double r = StrictMath.IEEEremainder(f1, f20); 509 final int n = (int) ((r - f1) / f20); 510 return new DifferentialPair(r, n * f2.getFirstDerivative()); 511 } 512 513 /** Remainder function. 514 * @param f1 dividend 515 * @param f2 divisor 516 * @return remainder of f1/f2, following IEEE754 conventions 517 */ 518 public static DifferentialPair IEEEremainder(final DifferentialPair f1, 519 final DifferentialPair f2) { 520 final double f10 = f1.getValue(); 521 final double f20 = f2.getValue(); 522 final double r = StrictMath.IEEEremainder(f10, f20); 523 final int n = (int) ((r - f10) / f20); 524 return new DifferentialPair(r, f1.getFirstDerivative() + n * f2.getFirstDerivative()); 525 } 526 527 528 ////////////////////////// 529 // conversion functions // 530 ////////////////////////// 531 532 /** Angular conversion function. 533 * @param a angle in radians 534 * @return angle converted to degrees 535 */ 536 public static DifferentialPair toDegrees(final DifferentialPair a) { 537 return new DifferentialPair(StrictMath.toDegrees(a.getValue()), StrictMath.toDegrees(a.getFirstDerivative())); 538 } 539 540 /** Angular conversion function. 541 * @param a angle in degrees 542 * @return angle converted to radians 543 */ 544 public static DifferentialPair toRadians(final DifferentialPair a) { 545 return new DifferentialPair(StrictMath.toRadians(a.getValue()), StrictMath.toRadians(a.getFirstDerivative())); 546 } 547 548 549 ////////////////////////// 550 // comparison functions // 551 ////////////////////////// 552 553 /** Max function. 554 * @param a first function input value 555 * @param b second function input value 556 * @return maximal value from the (a, b) pair 557 */ 558 public static DifferentialPair max(final DifferentialPair a, 559 final double b) { 560 return (a.getValue() >= b) ? a : DifferentialPair.newConstant(b); 561 } 562 563 /** Max function. 564 * @param a first function input value 565 * @param b second function input value 566 * @return maximal value from the (a, b) pair 567 */ 568 public static DifferentialPair max(final double a, 569 final DifferentialPair b) { 570 return (b.getValue() >= a) ? b : DifferentialPair.newConstant(a); 571 } 572 573 /** Max function. 574 * @param a first function input value 575 * @param b second function input value 576 * @return maximal value from the (a, b) pair 577 */ 578 public static DifferentialPair max(final DifferentialPair a, 579 final DifferentialPair b) { 580 return (a.getValue() >= b.getValue()) ? a : b; 581 } 582 583 /** Min function. 584 * @param a first function input value 585 * @param b second function input value 586 * @return minimal value from the (a, b) pair 587 */ 588 public static DifferentialPair min(final DifferentialPair a, 589 final double b) { 590 return (a.getValue() <= b) ? a : DifferentialPair.newConstant(b); 591 } 592 593 /** Min function. 594 * @param a first function input value 595 * @param b second function input value 596 * @return minimal value from the (a, b) pair 597 */ 598 public static DifferentialPair min(final double a, 599 final DifferentialPair b) { 600 return (b.getValue() <= a) ? b : DifferentialPair.newConstant(a); 601 } 602 603 /** Min function. 604 * @param a first function input value 605 * @param b second function input value 606 * @return minimal value from the (a, b) pair 607 */ 608 public static DifferentialPair min(final DifferentialPair a, 609 final DifferentialPair b) { 610 return (a.getValue() <= b.getValue()) ? a : b; 611 } 612 613 }