InvGamma1pm1.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.numbers.gamma;

  18. /**
  19.  * Function \( \frac{1}{\Gamma(1 + x)} - 1 \).
  20.  *
  21.  * Class is immutable.
  22.  */
  23. final class InvGamma1pm1 {
  24.     /*
  25.      * Constants copied from DGAM1 in the NSWC library.
  26.      */
  27.     /** The constant {@code A0} defined in {@code DGAM1}. */
  28.     private static final double INV_GAMMA1P_M1_A0 = .611609510448141581788E-08;
  29.     /** The constant {@code A1} defined in {@code DGAM1}. */
  30.     private static final double INV_GAMMA1P_M1_A1 = .624730830116465516210E-08;
  31.     /** The constant {@code B1} defined in {@code DGAM1}. */
  32.     private static final double INV_GAMMA1P_M1_B1 = .203610414066806987300E+00;
  33.     /** The constant {@code B2} defined in {@code DGAM1}. */
  34.     private static final double INV_GAMMA1P_M1_B2 = .266205348428949217746E-01;
  35.     /** The constant {@code B3} defined in {@code DGAM1}. */
  36.     private static final double INV_GAMMA1P_M1_B3 = .493944979382446875238E-03;
  37.     /** The constant {@code B4} defined in {@code DGAM1}. */
  38.     private static final double INV_GAMMA1P_M1_B4 = -.851419432440314906588E-05;
  39.     /** The constant {@code B5} defined in {@code DGAM1}. */
  40.     private static final double INV_GAMMA1P_M1_B5 = -.643045481779353022248E-05;
  41.     /** The constant {@code B6} defined in {@code DGAM1}. */
  42.     private static final double INV_GAMMA1P_M1_B6 = .992641840672773722196E-06;
  43.     /** The constant {@code B7} defined in {@code DGAM1}. */
  44.     private static final double INV_GAMMA1P_M1_B7 = -.607761895722825260739E-07;
  45.     /** The constant {@code B8} defined in {@code DGAM1}. */
  46.     private static final double INV_GAMMA1P_M1_B8 = .195755836614639731882E-09;
  47.     /** The constant {@code P0} defined in {@code DGAM1}. */
  48.     private static final double INV_GAMMA1P_M1_P0 = .6116095104481415817861E-08;
  49.     /** The constant {@code P1} defined in {@code DGAM1}. */
  50.     private static final double INV_GAMMA1P_M1_P1 = .6871674113067198736152E-08;
  51.     /** The constant {@code P2} defined in {@code DGAM1}. */
  52.     private static final double INV_GAMMA1P_M1_P2 = .6820161668496170657918E-09;
  53.     /** The constant {@code P3} defined in {@code DGAM1}. */
  54.     private static final double INV_GAMMA1P_M1_P3 = .4686843322948848031080E-10;
  55.     /** The constant {@code P4} defined in {@code DGAM1}. */
  56.     private static final double INV_GAMMA1P_M1_P4 = .1572833027710446286995E-11;
  57.     /** The constant {@code P5} defined in {@code DGAM1}. */
  58.     private static final double INV_GAMMA1P_M1_P5 = -.1249441572276366213222E-12;
  59.     /** The constant {@code P6} defined in {@code DGAM1}. */
  60.     private static final double INV_GAMMA1P_M1_P6 = .4343529937408594255178E-14;
  61.     /** The constant {@code Q1} defined in {@code DGAM1}. */
  62.     private static final double INV_GAMMA1P_M1_Q1 = .3056961078365221025009E+00;
  63.     /** The constant {@code Q2} defined in {@code DGAM1}. */
  64.     private static final double INV_GAMMA1P_M1_Q2 = .5464213086042296536016E-01;
  65.     /** The constant {@code Q3} defined in {@code DGAM1}. */
  66.     private static final double INV_GAMMA1P_M1_Q3 = .4956830093825887312020E-02;
  67.     /** The constant {@code Q4} defined in {@code DGAM1}. */
  68.     private static final double INV_GAMMA1P_M1_Q4 = .2692369466186361192876E-03;
  69.     /** The constant {@code C} defined in {@code DGAM1}. */
  70.     private static final double INV_GAMMA1P_M1_C = -.422784335098467139393487909917598E+00;
  71.     /** The constant {@code C0} defined in {@code DGAM1}. */
  72.     private static final double INV_GAMMA1P_M1_C0 = .577215664901532860606512090082402E+00;
  73.     /** The constant {@code C1} defined in {@code DGAM1}. */
  74.     private static final double INV_GAMMA1P_M1_C1 = -.655878071520253881077019515145390E+00;
  75.     /** The constant {@code C2} defined in {@code DGAM1}. */
  76.     private static final double INV_GAMMA1P_M1_C2 = -.420026350340952355290039348754298E-01;
  77.     /** The constant {@code C3} defined in {@code DGAM1}. */
  78.     private static final double INV_GAMMA1P_M1_C3 = .166538611382291489501700795102105E+00;
  79.     /** The constant {@code C4} defined in {@code DGAM1}. */
  80.     private static final double INV_GAMMA1P_M1_C4 = -.421977345555443367482083012891874E-01;
  81.     /** The constant {@code C5} defined in {@code DGAM1}. */
  82.     private static final double INV_GAMMA1P_M1_C5 = -.962197152787697356211492167234820E-02;
  83.     /** The constant {@code C6} defined in {@code DGAM1}. */
  84.     private static final double INV_GAMMA1P_M1_C6 = .721894324666309954239501034044657E-02;
  85.     /** The constant {@code C7} defined in {@code DGAM1}. */
  86.     private static final double INV_GAMMA1P_M1_C7 = -.116516759185906511211397108401839E-02;
  87.     /** The constant {@code C8} defined in {@code DGAM1}. */
  88.     private static final double INV_GAMMA1P_M1_C8 = -.215241674114950972815729963053648E-03;
  89.     /** The constant {@code C9} defined in {@code DGAM1}. */
  90.     private static final double INV_GAMMA1P_M1_C9 = .128050282388116186153198626328164E-03;
  91.     /** The constant {@code C10} defined in {@code DGAM1}. */
  92.     private static final double INV_GAMMA1P_M1_C10 = -.201348547807882386556893914210218E-04;
  93.     /** The constant {@code C11} defined in {@code DGAM1}. */
  94.     private static final double INV_GAMMA1P_M1_C11 = -.125049348214267065734535947383309E-05;
  95.     /** The constant {@code C12} defined in {@code DGAM1}. */
  96.     private static final double INV_GAMMA1P_M1_C12 = .113302723198169588237412962033074E-05;
  97.     /** The constant {@code C13} defined in {@code DGAM1}. */
  98.     private static final double INV_GAMMA1P_M1_C13 = -.205633841697760710345015413002057E-06;

  99.     /** Private constructor. */
  100.     private InvGamma1pm1() {
  101.         // intentionally empty.
  102.     }

  103.     /**
  104.      * Computes the function \( \frac{1}{\Gamma(1 + x)} - 1 \) for {@code -0.5 <= x <= 1.5}.
  105.      *
  106.      * This implementation is based on the double precision implementation in
  107.      * the <em>NSWC Library of Mathematics Subroutines</em>, {@code DGAM1}.
  108.      *
  109.      * @param x Argument.
  110.      * @return \( \frac{1}{\Gamma(1 + x)} - 1 \)
  111.      * @throws IllegalArgumentException if {@code x < -0.5} or {@code x > 1.5}
  112.      */
  113.     public static double value(final double x) {
  114.         if (x < -0.5 || x > 1.5) {
  115.             throw new GammaException(GammaException.OUT_OF_RANGE, x, -0.5, 1.5);
  116.         }

  117.         final double t = x <= 0.5 ? x : (x - 0.5) - 0.5;
  118.         if (t < 0) {
  119.             final double a = INV_GAMMA1P_M1_A0 + t * INV_GAMMA1P_M1_A1;
  120.             double b = INV_GAMMA1P_M1_B8;
  121.             b = INV_GAMMA1P_M1_B7 + t * b;
  122.             b = INV_GAMMA1P_M1_B6 + t * b;
  123.             b = INV_GAMMA1P_M1_B5 + t * b;
  124.             b = INV_GAMMA1P_M1_B4 + t * b;
  125.             b = INV_GAMMA1P_M1_B3 + t * b;
  126.             b = INV_GAMMA1P_M1_B2 + t * b;
  127.             b = INV_GAMMA1P_M1_B1 + t * b;
  128.             b = 1.0 + t * b;

  129.             double c = INV_GAMMA1P_M1_C13 + t * (a / b);
  130.             c = INV_GAMMA1P_M1_C12 + t * c;
  131.             c = INV_GAMMA1P_M1_C11 + t * c;
  132.             c = INV_GAMMA1P_M1_C10 + t * c;
  133.             c = INV_GAMMA1P_M1_C9 + t * c;
  134.             c = INV_GAMMA1P_M1_C8 + t * c;
  135.             c = INV_GAMMA1P_M1_C7 + t * c;
  136.             c = INV_GAMMA1P_M1_C6 + t * c;
  137.             c = INV_GAMMA1P_M1_C5 + t * c;
  138.             c = INV_GAMMA1P_M1_C4 + t * c;
  139.             c = INV_GAMMA1P_M1_C3 + t * c;
  140.             c = INV_GAMMA1P_M1_C2 + t * c;
  141.             c = INV_GAMMA1P_M1_C1 + t * c;
  142.             c = INV_GAMMA1P_M1_C + t * c;
  143.             if (x > 0.5) {
  144.                 return t * c / x;
  145.             }
  146.             return x * ((c + 0.5) + 0.5);
  147.         }
  148.         double p = INV_GAMMA1P_M1_P6;
  149.         p = INV_GAMMA1P_M1_P5 + t * p;
  150.         p = INV_GAMMA1P_M1_P4 + t * p;
  151.         p = INV_GAMMA1P_M1_P3 + t * p;
  152.         p = INV_GAMMA1P_M1_P2 + t * p;
  153.         p = INV_GAMMA1P_M1_P1 + t * p;
  154.         p = INV_GAMMA1P_M1_P0 + t * p;

  155.         double q = INV_GAMMA1P_M1_Q4;
  156.         q = INV_GAMMA1P_M1_Q3 + t * q;
  157.         q = INV_GAMMA1P_M1_Q2 + t * q;
  158.         q = INV_GAMMA1P_M1_Q1 + t * q;
  159.         q = 1.0 + t * q;

  160.         double c = INV_GAMMA1P_M1_C13 + (p / q) * t;
  161.         c = INV_GAMMA1P_M1_C12 + t * c;
  162.         c = INV_GAMMA1P_M1_C11 + t * c;
  163.         c = INV_GAMMA1P_M1_C10 + t * c;
  164.         c = INV_GAMMA1P_M1_C9 + t * c;
  165.         c = INV_GAMMA1P_M1_C8 + t * c;
  166.         c = INV_GAMMA1P_M1_C7 + t * c;
  167.         c = INV_GAMMA1P_M1_C6 + t * c;
  168.         c = INV_GAMMA1P_M1_C5 + t * c;
  169.         c = INV_GAMMA1P_M1_C4 + t * c;
  170.         c = INV_GAMMA1P_M1_C3 + t * c;
  171.         c = INV_GAMMA1P_M1_C2 + t * c;
  172.         c = INV_GAMMA1P_M1_C1 + t * c;
  173.         c = INV_GAMMA1P_M1_C0 + t * c;

  174.         if (x > 0.5) {
  175.             return (t / x) * ((c - 0.5) - 0.5);
  176.         }
  177.         return x * c;
  178.     }
  179. }