Interpolation.java

  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.statistics.descriptive;

  18. /**
  19.  * Support class for interpolation.
  20.  *
  21.  * @since 1.1
  22.  */
  23. final class Interpolation {
  24.     /** No instances. */
  25.     private Interpolation() {}

  26.     /**
  27.      * Compute the arithmetic mean of the two values taking care to avoid overflow.
  28.      *
  29.      * @param x Value.
  30.      * @param y Value.
  31.      * @return the mean
  32.      */
  33.     static double mean(double x, double y) {
  34.         final double v = x + y;
  35.         if (Double.isFinite(v)) {
  36.             return v * 0.5;
  37.         }
  38.         // Note: Using this by default can be incorrect on sub-normal numbers
  39.         return x * 0.5 + y * 0.5;
  40.     }

  41.     /**
  42.      * Compute the arithmetic mean of the two values.
  43.      *
  44.      * @param x Value.
  45.      * @param y Value.
  46.      * @return the mean
  47.      */
  48.     static double mean(int x, int y) {
  49.         // long arithmetic handles a 32-bit signed integer
  50.         return ((long) x + y) * 0.5;
  51.     }

  52.     /**
  53.      * Linear interpolation between sorted values {@code a <= b} using the
  54.      * interpolant {@code t} taking care to avoid overflow.
  55.      *
  56.      * <pre>
  57.      * value = a + t * (b - a)
  58.      * </pre>
  59.      *
  60.      * <p>Note
  61.      *
  62.      * <p>This function has the same properties of as the C++ function <a
  63.      * href="https://en.cppreference.com/w/cpp/numeric/lerp">std::lerp</a> for
  64.      * {@code t in (0, 1)} and {@code b >= a}. It is not a full implementation as it
  65.      * removes explicit checks for {@code t==0} and {@code t==1} and does not support
  66.      * extrapolation as the usage is intended for interpolation of sorted values.
  67.      * The function is monotonic and avoids overflow for finite {@code a} and {@code b}.
  68.      *
  69.      * <p>Interpolation between equal signed infinity arguments will return {@code a}.
  70.      * Alternative implementations may return {@code NaN} for this case. Thus this method
  71.      * interprets infinity values as equivalent and avoids interpolation.
  72.      *
  73.      * @param a Min value.
  74.      * @param b Max value.
  75.      * @param t Interpolant in (0, 1).
  76.      * @return the value
  77.      */
  78.     static double interpolate(double a, double b, double t) {
  79.         // Linear interpolation adapted from:
  80.         // P0811R2: Well-behaved interpolation for numbers and pointers
  81.         // https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p0811r2.html
  82.         // https://en.cppreference.com/w/cpp/numeric/lerp

  83.         // Notes:
  84.         // a+t*(b-a) does not in general reproduce b when t==1, and can overflow if a and b
  85.         // have the largest exponent and opposite signs.
  86.         // t*b+(1-t)*a is not monotonic in general (unless the product ab≤0).

  87.         // Exact, monotonic, bounded, determinate, and (for a=b=0) consistent:
  88.         // Removed check a >= 0 && b <= 0 as the arguments are assumed to be sorted.
  89.         if (a <= 0 && b >= 0) {
  90.             // Note: Does not return a for a=-0.0, b=0.0, t=0.0.
  91.             // This is ignored as interpolation is only used when t != 0.0.
  92.             return t * b + (1.0 - t) * a;
  93.         }

  94.         // Here a and b are on the same side of zero, and at least 1 is non-zero.
  95.         // Since we assume t in (0, 1) remove: if t==1 return b.

  96.         // P0811R2 assumes finite arguments so we add a case to detect same signed infinity
  97.         // and avoid (b - a) == NaN. This is simply handled with floating-point equivalence.
  98.         if (a == b) {
  99.             return a;
  100.         }

  101.         // Exact at t=0, monotonic except near t=1,
  102.         // bounded, determinate, and consistent:
  103.         // Note: switching to 'b - (1.0 - t) * (b - a)' when t > 0.5 would
  104.         // provide exact ends at t=0 and t=1.
  105.         return a + t * (b - a);
  106.     }
  107. }