/**
   * Computes x + y without losing precision using ln(x) and ln(y).
   *
   * @param lna Value.
   * @param lnc Value.
   * @return Result.
   */
  public static double LogSum(float lna, float lnc) {
    if (lna == Float.NEGATIVE_INFINITY) return lnc;
    if (lnc == Float.NEGATIVE_INFINITY) return lna;

    if (lna > lnc) return lna + Special.Log1p(Math.exp(lnc - lna));

    return lnc + Special.Log1p(Math.exp(lna - lnc));
  }
  /** Computes the Basic Spline of order <c>n</c>. */
  public static double BSpline(int n, double x) {
    // ftp://ftp.esat.kuleuven.ac.be/pub/SISTA/hamers/PhD_bhamers.pdf
    // http://sepwww.stanford.edu/public/docs/sep105/sergey2/paper_html/node5.html

    if (n == Integer.MAX_VALUE) throw new IllegalArgumentException("n");

    double a = 1.0 / Special.Factorial(n);
    double c;

    boolean positive = true;
    for (int k = 0; k <= n + 1; k++) {
      c = Binomial(n + 1, k) * Tools.TruncatedPower(x + (n + 1.0) / 2.0 - k, n);
      a += positive ? c : -c;
      positive = !positive;
    }

    return a;
  }