View Javadoc
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  
18  // License for the Boost continued fraction adaptation:
19  
20  //  (C) Copyright John Maddock 2006.
21  //  Use, modification and distribution are subject to the
22  //  Boost Software License, Version 1.0. (See accompanying file
23  //  LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
24  
25  package org.apache.commons.numbers.examples.jmh.gamma;
26  
27  import java.util.Arrays;
28  import java.util.concurrent.TimeUnit;
29  import java.util.function.DoubleBinaryOperator;
30  import java.util.function.Supplier;
31  import org.apache.commons.numbers.fraction.GeneralizedContinuedFraction;
32  import org.apache.commons.numbers.fraction.GeneralizedContinuedFraction.Coefficient;
33  import org.openjdk.jmh.annotations.Benchmark;
34  import org.openjdk.jmh.annotations.BenchmarkMode;
35  import org.openjdk.jmh.annotations.Fork;
36  import org.openjdk.jmh.annotations.Measurement;
37  import org.openjdk.jmh.annotations.Mode;
38  import org.openjdk.jmh.annotations.OutputTimeUnit;
39  import org.openjdk.jmh.annotations.Param;
40  import org.openjdk.jmh.annotations.Scope;
41  import org.openjdk.jmh.annotations.Setup;
42  import org.openjdk.jmh.annotations.State;
43  import org.openjdk.jmh.annotations.Warmup;
44  import org.openjdk.jmh.infra.Blackhole;
45  
46  /**
47   * Executes a benchmark to estimate the speed of continued fraction implementations
48   * that compute the regularized incomplete upper gamma function Q.
49   */
50  @BenchmarkMode(Mode.AverageTime)
51  @OutputTimeUnit(TimeUnit.NANOSECONDS)
52  @Warmup(iterations = 5, time = 1, timeUnit = TimeUnit.SECONDS)
53  @Measurement(iterations = 5, time = 1, timeUnit = TimeUnit.SECONDS)
54  @State(Scope.Benchmark)
55  @Fork(value = 1, jvmArgs = {"-server", "-Xms512M", "-Xmx512M"})
56  public class GammaContinuedFractionPerformance {
57  
58      /** Commons Numbers 1.0 implementation. */
59      static final String IMP_NUMBERS_1_0 = "Numbers 1.0";
60      /** Commons Numbers ContinuedFraction extended to skip the initial term. */
61      static final String IMP_NUMBERS_EXT_A = "Numbers Extended A";
62      /** Commons Numbers ContinuedFraction extended to skip the initial term.
63       * The series starts at n=1. */
64      static final String IMP_NUMBERS_EXT_A1 = "Numbers Extended A1";
65      /** Next iterator implementation. */
66      static final String IMP_ITERATOR = "Iterator";
67      /** Commons Numbers 1.1 implementation. */
68      static final String IMP_NUMBERS_1_1 = "Numbers 1.1";
69      /** Commons Numbers 1.1 implementation using direct increment of the term. */
70      static final String IMP_NUMBERS_1_1_INC = "Numbers 1.1 Inc";
71  
72      /**
73       * The value for any number close to zero.
74       *
75       * <p>"The parameter small should be some non-zero number less than typical values of
76       * eps * |b_n|, e.g., 1e-50".
77       */
78      private static final double SMALL = 1e-50;
79      /**
80       * The minimum epsilon value for relative error.
81       * Equals to Math.ulp(1.0) or 2^-52.
82       */
83      private static final double EPSILON = 0x1.0p-52;
84      /** Maximum iterations. */
85      private static final int MAX_ITERATIONS = 100000;
86  
87      /**
88       * Data for the regularized gamma Q function: gamma_q(a, z).
89       *
90       * <p>This data was extracted from the test data for the Boost incomplete
91       * gamma functions for cases where the function evaluates with a continued fraction.
92       *
93       * <p>The first column indicates the number of iterations for the IMP_NUMBERS_EXT_A1
94       * implementation.
95       */
96      private static final double[][] A_Z = {
97          /* 15 */ {32.5, 65.0},
98          /* 15 */ {33.0, 66.0},
99          /* 16 */ {36.5, 73.0},
100         /* 15 */ {37.0, 74.0},
101         /*  7 */ {1.6504575484077577E-12, 100.0},
102         /*  7 */ {2.0654589150126412E-12, 100.0},
103         /*  7 */ {6.93323176648164E-12, 100.0},
104         /*  7 */ {1.335143107183967E-11, 100.0},
105         /*  7 */ {1.6399770430552962E-11, 100.0},
106         /*  7 */ {5.730160790307082E-11, 100.0},
107         /*  7 */ {1.113731329382972E-10, 100.0},
108         /*  7 */ {1.4214707189097453E-10, 100.0},
109         /*  7 */ {3.800633141537446E-10, 100.0},
110         /*  7 */ {6.09162720266454E-10, 100.0},
111         /*  7 */ {1.0221641311147778E-9, 100.0},
112         /*  7 */ {2.8819229225263143E-9, 100.0},
113         /*  7 */ {4.7627768395841485E-9, 100.0},
114         /*  7 */ {8.854135202795987E-9, 100.0},
115         /*  7 */ {2.305032964500242E-8, 100.0},
116         /*  7 */ {5.9392490925347374E-8, 100.0},
117         /*  7 */ {1.1667650312574551E-7, 100.0},
118         /*  7 */ {2.3799674409019644E-7, 100.0},
119         /*  7 */ {4.684659415943315E-7, 100.0},
120         /*  7 */ {9.382700909554842E-7, 100.0},
121         /*  7 */ {1.1039858236472355E-6, 100.0},
122         /*  7 */ {3.2917764656303916E-6, 100.0},
123         /*  7 */ {7.517214726249222E-6, 100.0},
124         /*  7 */ {1.5114666894078255E-5, 100.0},
125         /*  7 */ {2.986399704241194E-5, 100.0},
126         /*  7 */ {3.387029209989123E-5, 100.0},
127         /*  7 */ {9.06601344468072E-5, 100.0},
128         /*  7 */ {2.194953412981704E-4, 100.0},
129         /*  7 */ {4.395215946715325E-4, 100.0},
130         /*  7 */ {6.333151832222939E-4, 100.0},
131         /*  7 */ {0.0011151233920827508, 100.0},
132         /*  7 */ {0.001962467795237899, 100.0},
133         /*  7 */ {0.005553754977881908, 100.0},
134         /*  7 */ {0.00869112927466631, 100.0},
135         /*  7 */ {0.029933366924524307, 100.0},
136         /*  7 */ {0.05124260485172272, 100.0},
137         /* 62 */ {0.9759566783905029, 1.9519133567810059},
138         /*  7 */ {0.9759566783905029, 100.0},
139         /* 26 */ {3.667367935180664, 4.034104824066162},
140         /* 17 */ {3.667367935180664, 7.334735870361328},
141         /*  5 */ {3.667367935180664, 366.7367858886719},
142         /* 24 */ {3.927384853363037, 4.320123195648193},
143         /* 15 */ {3.927384853363037, 7.854769706726074},
144         /*  5 */ {3.927384853363037, 392.7384948730469},
145         /* 24 */ {4.053312301635742, 4.458643436431885},
146         /* 15 */ {4.053312301635742, 8.106624603271484},
147         /*  5 */ {4.053312301635742, 405.33123779296875},
148         /* 22 */ {4.125904560089111, 4.538495063781738},
149         /* 16 */ {4.125904560089111, 8.251809120178223},
150         /*  5 */ {4.125904560089111, 412.5904541015625},
151         /* 19 */ {5.094053268432617, 5.603458404541016},
152         /* 13 */ {5.094053268432617, 10.188106536865234},
153         /*  5 */ {5.094053268432617, 509.40533447265625},
154         /* 21 */ {5.596034526824951, 6.155638217926025},
155         /* 13 */ {5.596034526824951, 11.192069053649902},
156         /*  5 */ {5.596034526824951, 559.6034545898438},
157         /* 15 */ {10.16461181640625, 11.181073188781738},
158         /* 12 */ {10.16461181640625, 20.3292236328125},
159         /* 15 */ {10.205269813537598, 11.225796699523926},
160         /* 12 */ {10.205269813537598, 20.410539627075195},
161         /* 15 */ {11.431244850158691, 12.574369430541992},
162         /* 12 */ {11.431244850158691, 22.862489700317383},
163         /* 15 */ {11.69021987915039, 12.859241485595703},
164         /* 12 */ {11.69021987915039, 23.38043975830078},
165         /* 15 */ {12.955684661865234, 14.251253128051758},
166         /* 13 */ {12.955684661865234, 25.91136932373047},
167         /* 15 */ {13.026715278625488, 14.329386711120605},
168         /* 13 */ {13.026715278625488, 26.053430557250977},
169         /* 15 */ {13.135188102722168, 14.44870662689209},
170         /* 13 */ {13.135188102722168, 26.270376205444336},
171         /* 15 */ {13.979962348937988, 15.377958297729492},
172         /* 13 */ {13.979962348937988, 27.959924697875977},
173         /* 16 */ {14.617691040039062, 16.07946014404297},
174         /* 13 */ {14.617691040039062, 29.235382080078125},
175         /* 16 */ {15.336841583251953, 16.870525360107422},
176         /* 14 */ {15.336841583251953, 30.673683166503906},
177         /* 17 */ {16.18250274658203, 17.800752639770508},
178         /* 14 */ {16.18250274658203, 32.36500549316406},
179         /* 18 */ {17.5330753326416, 19.2863826751709},
180         /* 14 */ {17.5330753326416, 35.0661506652832},
181         /* 18 */ {17.799583435058594, 19.57954216003418},
182         /* 14 */ {17.799583435058594, 35.59916687011719},
183         /* 19 */ {19.09382438659668, 21.003206253051758},
184         /* 15 */ {19.09382438659668, 38.18764877319336},
185         /* 19 */ {19.24400520324707, 21.168405532836914},
186         /* 14 */ {19.24400520324707, 38.48801040649414},
187         /* 15 */ {21.415802001953125, 42.83160400390625},
188         /* 15 */ {21.586471557617188, 43.172943115234375},
189         /* 15 */ {22.492887496948242, 44.985774993896484},
190         /* 15 */ {28.053834915161133, 56.107669830322266},
191         /* 15 */ {28.210573196411133, 56.421146392822266},
192         /* 15 */ {30.054428100585938, 60.108856201171875},
193         /* 16 */ {30.540353775024414, 61.08070755004883},
194         /* 15 */ {31.162620544433594, 62.32524108886719},
195         /* 15 */ {31.996768951416016, 63.99353790283203},
196         /* 15 */ {32.05139923095703, 64.10279846191406},
197         /* 15 */ {36.448753356933594, 72.89750671386719},
198         /* 16 */ {38.465065002441406, 76.93013000488281},
199         /* 15 */ {39.526588439941406, 79.05317687988281},
200         /* 15 */ {40.17448425292969, 80.34896850585938},
201         /* 15 */ {41.16875076293945, 82.3375015258789},
202         /* 15 */ {42.465248107910156, 84.93049621582031},
203         /* 15 */ {42.49772262573242, 84.99544525146484},
204         /* 15 */ {44.15506362915039, 88.31012725830078},
205         /* 15 */ {44.8358268737793, 89.6716537475586},
206         /* 15 */ {46.06991958618164, 92.13983917236328},
207         /* 15 */ {47.738487243652344, 95.47697448730469},
208         /* 14 */ {48.79487609863281, 97.58975219726562},
209         /* 14 */ {49.01310729980469, 98.02621459960938},
210         /* 15 */ {49.2315559387207, 98.4631118774414},
211         /* 15 */ {49.3136100769043, 98.6272201538086},
212         /* 15 */ {50.61444091796875, 101.2288818359375},
213         /* 14 */ {54.91470718383789, 109.82941436767578},
214         /* 15 */ {54.948448181152344, 109.89689636230469},
215         /* 14 */ {63.41974639892578, 126.83949279785156},
216         /* 14 */ {64.15645599365234, 128.3129119873047},
217         /* 15 */ {64.80814361572266, 129.6162872314453},
218         /* 15 */ {65.72004699707031, 131.44009399414062},
219         /* 14 */ {65.74620056152344, 131.49240112304688},
220         /* 14 */ {66.52874755859375, 133.0574951171875},
221         /* 14 */ {68.03414916992188, 136.06829833984375},
222         /* 14 */ {68.29527282714844, 136.59054565429688},
223         /* 14 */ {69.63545227050781, 139.27090454101562},
224         /* 14 */ {70.7515869140625, 141.503173828125},
225         /* 14 */ {71.08180236816406, 142.16360473632812},
226         /* 14 */ {72.72097778320312, 145.44195556640625},
227         /* 14 */ {74.19440460205078, 148.38880920410156},
228         /* 14 */ {74.44168090820312, 148.88336181640625},
229         /* 14 */ {75.59132385253906, 151.18264770507812},
230         /* 14 */ {75.8951416015625, 151.790283203125},
231         /* 14 */ {76.49312591552734, 152.9862518310547},
232         /* 14 */ {76.6689224243164, 153.3378448486328},
233         /* 14 */ {79.32462310791016, 158.6492462158203},
234         /* 14 */ {79.5005111694336, 159.0010223388672},
235         /* 13 */ {79.62239074707031, 159.24478149414062},
236         /* 14 */ {79.829345703125, 159.65869140625},
237         /* 13 */ {79.8938980102539, 159.7877960205078},
238         /* 14 */ {79.91152954101562, 159.82305908203125},
239         /* 13 */ {80.1279067993164, 160.2558135986328},
240         /* 14 */ {80.84933471679688, 161.69866943359375},
241         /* 13 */ {81.56500244140625, 163.1300048828125},
242         /* 13 */ {82.27938079833984, 164.5587615966797},
243         /* 13 */ {82.43405151367188, 164.86810302734375},
244         /* 13 */ {83.5833511352539, 167.1667022705078},
245         /* 14 */ {84.98836517333984, 169.9767303466797},
246         /* 13 */ {87.30667114257812, 174.61334228515625},
247         /* 13 */ {87.90385437011719, 175.80770874023438},
248         /* 13 */ {90.62629699707031, 181.25259399414062},
249         /* 13 */ {91.38089752197266, 182.7617950439453},
250         /* 13 */ {91.61568450927734, 183.2313690185547},
251         /* 13 */ {92.12703704833984, 184.2540740966797},
252         /* 14 */ {93.43232727050781, 186.86465454101562},
253         /* 13 */ {95.0470962524414, 190.0941925048828},
254         /* 13 */ {95.73811340332031, 191.47622680664062},
255         /* 13 */ {95.77192687988281, 191.54385375976562},
256         /* 13 */ {95.96949768066406, 191.93899536132812},
257         /* 13 */ {96.50640869140625, 193.0128173828125},
258         /* 13 */ {96.78564453125, 193.5712890625},
259         /* 13 */ {96.90234375, 193.8046875},
260         /* 13 */ {97.07398223876953, 194.14796447753906},
261         /* 13 */ {98.12041473388672, 196.24082946777344},
262         /* 13 */ {99.29168701171875, 198.5833740234375},
263         /* 13 */ {99.4098129272461, 198.8196258544922},
264         /* 13 */ {99.64790344238281, 199.29580688476562},
265         /*  7 */ {1.7306554127571872E-6, 100.0},
266         /*  7 */ {2.1657506295014173E-6, 100.0},
267         /*  7 */ {7.2700195232755505E-6, 100.0},
268         /*  7 */ {1.4000004739500582E-5, 100.0},
269         /*  7 */ {1.71964547917014E-5, 100.0},
270         /*  7 */ {6.008507625665516E-5, 100.0},
271         /*  7 */ {1.1678319424390793E-4, 100.0},
272         /*  7 */ {1.490520080551505E-4, 100.0},
273         /*  7 */ {3.98525211494416E-4, 100.0},
274         /*  7 */ {6.387534085661173E-4, 100.0},
275         /*  7 */ {0.0010718167759478092, 100.0},
276         /*  7 */ {0.0030219152104109526, 100.0},
277         /*  7 */ {0.004994133487343788, 100.0},
278         /*  7 */ {0.009284233674407005, 100.0},
279         /*  7 */ {0.02417002245783806, 100.0},
280         /*  7 */ {0.06227754056453705, 100.0},
281         /*  7 */ {0.12234418094158173, 100.0},
282         /*  7 */ {0.24955767393112183, 100.0},
283         /*  7 */ {0.4912221431732178, 100.0},
284         /* 53 */ {0.9838474988937378, 1.9676949977874756},
285         /*  7 */ {0.9838474988937378, 100.0},
286         /* 48 */ {1.1576130390167236, 2.3152260780334473},
287         /*  6 */ {1.1576130390167236, 115.76130676269531},
288         /* 27 */ {3.4516777992248535, 3.7968456745147705},
289         /* 18 */ {3.4516777992248535, 6.903355598449707},
290         /*  5 */ {3.4516777992248535, 345.16778564453125},
291         /* 15 */ {7.882370948791504, 8.670608520507812},
292         /* 12 */ {7.882370948791504, 15.764741897583008},
293         /* 16 */ {15.848876953125, 17.433765411376953},
294         /* 14 */ {15.848876953125, 31.69775390625},
295         /* 15 */ {31.31467056274414, 62.62934112548828},
296         /* 15 */ {35.51557540893555, 71.0311508178711},
297         /* 13 */ {95.06404113769531, 190.12808227539062},
298         /* 11 */ {230.1575469970703, 460.3150939941406},
299         /* 10 */ {460.8717956542969, 921.7435913085938},
300         /*  5 */ {0.75, 708.0},
301         /*  5 */ {0.75, 708.5},
302         /*  5 */ {0.75, 707.5},
303         /* 24 */ {32.5, 34.5},
304         /* 25 */ {33.0, 35.0},
305         /* 26 */ {36.5, 38.5},
306         /* 26 */ {37.0, 39.0},
307         /* 20 */ {21.415802001953125, 23.415802001953125},
308         /* 20 */ {21.586471557617188, 23.586471557617188},
309         /* 20 */ {22.492887496948242, 24.492887496948242},
310         /* 23 */ {28.053834915161133, 30.053834915161133},
311         /* 23 */ {28.210573196411133, 30.210573196411133},
312         /* 24 */ {30.054428100585938, 32.05442810058594},
313         /* 24 */ {30.540353775024414, 32.54035186767578},
314         /* 24 */ {31.162620544433594, 33.162620544433594},
315         /* 24 */ {31.996768951416016, 33.996768951416016},
316         /* 24 */ {32.05139923095703, 34.05139923095703},
317         /* 26 */ {36.448753356933594, 38.448753356933594},
318         /* 26 */ {38.465065002441406, 40.465065002441406},
319         /* 27 */ {39.526588439941406, 41.526588439941406},
320         /* 27 */ {40.17448425292969, 42.17448425292969},
321         /* 27 */ {41.16875076293945, 43.16875076293945},
322         /* 27 */ {42.465248107910156, 44.465248107910156},
323         /* 27 */ {42.49772262573242, 44.49772262573242},
324         /* 28 */ {44.15506362915039, 46.15506362915039},
325         /* 28 */ {44.8358268737793, 46.8358268737793},
326         /* 28 */ {46.06991958618164, 48.06991958618164},
327         /* 30 */ {47.738487243652344, 49.738487243652344},
328         /* 30 */ {48.79487609863281, 50.79487609863281},
329         /* 29 */ {49.01310729980469, 51.01310729980469},
330         /* 30 */ {49.2315559387207, 51.2315559387207},
331         /* 29 */ {49.3136100769043, 51.3136100769043},
332         /* 30 */ {50.61444091796875, 52.61444091796875},
333         /* 31 */ {54.91470718383789, 56.91470718383789},
334         /* 32 */ {54.948448181152344, 56.948448181152344},
335         /* 33 */ {63.41974639892578, 65.41974639892578},
336         /* 33 */ {64.15645599365234, 66.15645599365234},
337         /* 33 */ {64.80814361572266, 66.80814361572266},
338         /* 33 */ {65.72004699707031, 67.72004699707031},
339         /* 33 */ {65.74620056152344, 67.74620056152344},
340         /* 33 */ {66.52874755859375, 68.52874755859375},
341         /* 33 */ {68.03414916992188, 70.03414916992188},
342         /* 34 */ {68.29527282714844, 70.29527282714844},
343         /* 35 */ {69.63545227050781, 71.63545227050781},
344         /* 34 */ {70.7515869140625, 72.7515869140625},
345         /* 34 */ {71.08180236816406, 73.08180236816406},
346         /* 35 */ {72.72097778320312, 74.72097778320312},
347         /* 35 */ {74.19440460205078, 76.19440460205078},
348         /* 35 */ {74.44168090820312, 76.44168090820312},
349         /* 35 */ {75.59132385253906, 77.59132385253906},
350         /* 35 */ {75.8951416015625, 77.8951416015625},
351         /* 36 */ {76.49312591552734, 78.49312591552734},
352         /* 36 */ {76.6689224243164, 78.6689224243164},
353         /* 35 */ {79.32462310791016, 81.32462310791016},
354         /* 35 */ {79.5005111694336, 81.5005111694336},
355         /* 35 */ {79.62239074707031, 81.62239074707031},
356         /* 35 */ {79.829345703125, 81.829345703125},
357         /* 35 */ {79.8938980102539, 81.8938980102539},
358         /* 35 */ {79.91152954101562, 81.91152954101562},
359         /* 37 */ {80.1279067993164, 82.1279067993164},
360         /* 36 */ {80.84933471679688, 82.84933471679688},
361         /* 36 */ {81.56500244140625, 83.56500244140625},
362         /* 36 */ {82.27938079833984, 84.27938079833984},
363         /* 37 */ {82.43405151367188, 84.43405151367188},
364         /* 37 */ {83.5833511352539, 85.5833511352539},
365         /* 36 */ {84.98836517333984, 86.98836517333984},
366         /* 36 */ {87.30667114257812, 89.30667114257812},
367         /* 37 */ {87.90385437011719, 89.90385437011719},
368         /* 37 */ {90.62629699707031, 92.62629699707031},
369         /* 39 */ {91.38089752197266, 93.38089752197266},
370         /* 38 */ {91.61568450927734, 93.61568450927734},
371         /* 38 */ {92.12703704833984, 94.12703704833984},
372         /* 39 */ {93.43232727050781, 95.43232727050781},
373         /* 38 */ {95.0470962524414, 97.0470962524414},
374         /* 39 */ {95.73811340332031, 97.73811340332031},
375         /* 39 */ {95.77192687988281, 97.77192687988281},
376         /* 39 */ {95.96949768066406, 97.96949768066406},
377         /* 39 */ {96.50640869140625, 98.50640869140625},
378         /* 38 */ {96.78564453125, 98.78564453125},
379         /* 39 */ {96.90234375, 98.90234375},
380         /* 39 */ {97.07398223876953, 99.07398223876953},
381         /* 39 */ {98.12041473388672, 100.12041473388672},
382         /* 40 */ {99.29168701171875, 101.29168701171875},
383         /* 40 */ {99.4098129272461, 101.4098129272461},
384         /* 39 */ {99.64790344238281, 101.64790344238281},
385         /*  5 */ {7.882370948791504, 788.2371215820312},
386         /* 24 */ {31.31467056274414, 33.31467056274414},
387         /* 25 */ {35.51557540893555, 37.51557540893555},
388         /* 39 */ {95.06404113769531, 97.06404113769531},
389         /*  4 */ {230.1575469970703, 23015.75390625},
390         /*  4 */ {460.8717956542969, 46087.1796875},
391         /*  4 */ {664.0791015625, 66407.90625},
392         /*  4 */ {1169.2916259765625, 116929.1640625},
393         /*  4 */ {2057.796630859375, 205779.65625},
394         /*  4 */ {5823.5341796875, 582353.4375},
395         /*  4 */ {9113.3095703125, 911330.9375},
396         /*  4 */ {31387.41015625, 3138741.0},
397         /*  3 */ {53731.765625, 5373176.5},
398         /*  3 */ {117454.09375, 1.1745409E7},
399         /*  3 */ {246209.65625, 2.4620966E7},
400         /*  3 */ {513669.1875, 5.136692E7},
401         /*  3 */ {788352.3125, 7.8835232E7},
402         /*  3 */ {1736170.0, 1.73616992E8},
403         /*  7 */ {170.0, 1000.0},
404         /*  6 */ {185.0, 1500.0},
405     };
406 
407     /**
408      * Contains the function to evaluate the continued fraction.
409      */
410     @State(Scope.Benchmark)
411     public static class BaseData {
412         /** Error message when the fraction diverged to non-finite. */
413         private static final String MSG_DIVERGED = "Continued fraction diverged to %s for value %s";
414         /** Error message when the maximum iterations was exceeded. */
415         private static final String MSG_MAX_ITERATIONS = "Maximum iterations exceeded: ";
416 
417         /** The implementation of the function. */
418         @Param({IMP_NUMBERS_1_0, IMP_NUMBERS_EXT_A, IMP_NUMBERS_EXT_A1,
419                 IMP_ITERATOR, IMP_NUMBERS_1_1, IMP_NUMBERS_1_1_INC})
420         private String implementation;
421 
422         /** The function. */
423         private DoubleBinaryOperator function;
424 
425         /**
426          * Gets the function.
427          *
428          * @return the function
429          */
430         public DoubleBinaryOperator getFunction() {
431             return function;
432         }
433 
434         /**
435          * Create the numbers and the function.
436          */
437         @Setup
438         public void setup() {
439             function = createFunction(implementation);
440         }
441 
442         /**
443          * Creates the function to evaluate the continued fraction for
444          * regularized gamma Q.
445          *
446          * @param implementation Function implementation
447          * @return the function
448          */
449         static DoubleBinaryOperator createFunction(String implementation) {
450             if (IMP_NUMBERS_1_0.equals(implementation)) {
451                 // Method from Commons Numbers 1.0 : RegularizedGamma.Q
452                 return (a, z) -> {
453                     final ContinuedFraction cf = new ContinuedFraction() {
454                         /** {@inheritDoc} */
455                         @Override
456                         protected double getA(int n, double x) {
457                             return n * (a - n);
458                         }
459 
460                         /** {@inheritDoc} */
461                         @Override
462                         protected double getB(int n, double x) {
463                             return ((2 * n) + 1) - a + x;
464                         }
465                     };
466 
467                     return 1 / cf.evaluate(z, EPSILON, MAX_ITERATIONS);
468                 };
469             } else if (IMP_NUMBERS_EXT_A.equals(implementation)) {
470                 // Modified implementation that uses term a0.
471                 // The series must be advanced 1 term (hence the 'n++' code).
472                 return (a, z) -> {
473                     final ContinuedFractionA cf = new ContinuedFractionA() {
474                         @Override
475                         protected double getA(int n, double x) {
476                             n++;
477                             return n * (a - n);
478                         }
479 
480                         @Override
481                         protected double getB(int n, double x) {
482                             n++;
483                             return ((2 * n) + 1) - a + x;
484                         }
485                     };
486 
487                     return 1 / (z - a + 1 + cf.evaluate(z, EPSILON, MAX_ITERATIONS));
488                 };
489             } else if (IMP_NUMBERS_EXT_A1.equals(implementation)) {
490                 // Modified implementation that starts from (a1,b1) and uses term a1.
491                 return (a, z) -> {
492                     final ContinuedFractionA1 cf = new ContinuedFractionA1() {
493                         @Override
494                         protected double getA(int n, double x) {
495                             return n * (a - n);
496                         }
497 
498                         @Override
499                         protected double getB(int n, double x) {
500                             return ((2 * n) + 1) - a + x;
501                         }
502                     };
503 
504                     return 1 / (z - a + 1 + cf.evaluate(z, EPSILON, MAX_ITERATIONS));
505                 };
506             } else if (IMP_ITERATOR.equals(implementation)) {
507                 // Implementation that sets terms a and b directly
508                 return (a, z) -> {
509                     final ContinuedFractionIterator cf = new ContinuedFractionIterator() {
510                         /** Factor. */
511                         private double x = z - a + 1;
512                         /** Iteration. */
513                         private int k;
514 
515                         @Override
516                         void next() {
517                             ++k;
518                             x += 2;
519                             setCoefficients(k * (a - k), x);
520                         }
521                     };
522 
523                     return 1 / (z - a + 1 + cf.evaluate(EPSILON, MAX_ITERATIONS));
524                 };
525             } else if (IMP_NUMBERS_1_1.equals(implementation)) {
526                 // Numbers 1.1 implementation using a generator of coefficients
527                 // from (a1,b1) and supplies b0 as an argument
528                 return (a, z) -> {
529                     final double zma1 = z - a + 1;
530 
531                     final Supplier<Coefficient> gen = new Supplier<>() {
532                         /** Iteration. */
533                         private int k;
534 
535                         @Override
536                         public Coefficient get() {
537                             ++k;
538                             return Coefficient.of(k * (a - k), zma1 + 2.0 * k);
539                         }
540                     };
541 
542                     return 1 / GeneralizedContinuedFraction.value(zma1, gen, EPSILON, MAX_ITERATIONS);
543                 };
544             } else if (IMP_NUMBERS_1_1_INC.equals(implementation)) {
545                 // Numbers 1.1 implementation using a generator of coefficients
546                 // from (a1,b1) and supplies b0 as an argument
547                 return (a, z) -> {
548 
549                     final Supplier<Coefficient> gen = new Supplier<>() {
550                         /** Iteration. */
551                         private int k;
552                         /** b term. */
553                         private double b = z - a + 1;
554 
555                         @Override
556                         public Coefficient get() {
557                             ++k;
558                             b += 2;
559                             return Coefficient.of(k * (a - k), b);
560                         }
561                     };
562 
563                     return 1 / GeneralizedContinuedFraction.value(z - a + 1, gen, EPSILON, MAX_ITERATIONS);
564                 };
565             } else {
566                 throw new IllegalStateException("unknown: " + implementation);
567             }
568         }
569 
570         // Note: The following implementations have the same error checks as the
571         // evaluation method in Numbers 1.1
572 
573         /**
574          * Provides a generic means to evaluate
575          * <a href="https://mathworld.wolfram.com/ContinuedFraction.html">continued fractions</a>.
576          *
577          * <p>This is a copy of the implementation from Commons Numbers 1.0. Redundant methods
578          * have been removed. Error checks have been updated to match
579          * {@link GeneralizedContinuedFraction}.
580          *
581          * <p>The continued fraction uses the following form for the numerator ({@code a}) and
582          * denominator ({@code b}) coefficients:
583          * <pre>
584          *              a1
585          * b0 + ------------------
586          *      b1 +      a2
587          *           -------------
588          *           b2 +    a3
589          *                --------
590          *                b3 + ...
591          * </pre>
592          *
593          * <p>Subclasses must provide the {@link #getA(int,double) a} and {@link #getB(int,double) b}
594          * coefficients to evaluate the continued fraction.
595          */
596         abstract static class ContinuedFraction {
597             /**
598              * Defines the <a href="https://mathworld.wolfram.com/ContinuedFraction.html">
599              * {@code n}-th "a" coefficient</a> of the continued fraction.
600              *
601              * @param n Index of the coefficient to retrieve.
602              * @param x Evaluation point.
603              * @return the coefficient <code>a<sub>n</sub></code>.
604              */
605             protected abstract double getA(int n, double x);
606 
607             /**
608              * Defines the <a href="https://mathworld.wolfram.com/ContinuedFraction.html">
609              * {@code n}-th "b" coefficient</a> of the continued fraction.
610              *
611              * @param n Index of the coefficient to retrieve.
612              * @param x Evaluation point.
613              * @return the coefficient <code>b<sub>n</sub></code>.
614              */
615             protected abstract double getB(int n, double x);
616 
617             /**
618              * Evaluates the continued fraction.
619              * <p>
620              * The implementation of this method is based on the modified Lentz algorithm as described
621              * on page 508 in:
622              * </p>
623              *
624              * <ul>
625              *   <li>
626              *   I. J. Thompson,  A. R. Barnett (1986).
627              *   "Coulomb and Bessel Functions of Complex Arguments and Order."
628              *   Journal of Computational Physics 64, 490-509.
629              *   <a target="_blank" href="https://www.fresco.org.uk/papers/Thompson-JCP64p490.pdf">
630              *   https://www.fresco.org.uk/papers/Thompson-JCP64p490.pdf</a>
631              *   </li>
632              * </ul>
633              *
634              * @param x Point at which to evaluate the continued fraction.
635              * @param epsilon Maximum relative error allowed.
636              * @param maxIterations Maximum number of iterations.
637              * @return the value of the continued fraction evaluated at {@code x}.
638              * @throws ArithmeticException if the algorithm fails to converge.
639              * @throws ArithmeticException if the maximal number of iterations is reached
640              * before the expected convergence is achieved.
641              */
642             public double evaluate(double x, double epsilon, int maxIterations) {
643                 // Relative error epsilon must not be zero.
644                 // Do not use Math.max as NaN would be returned for a NaN epsilon.
645                 final double eps =  epsilon > EPSILON ? epsilon : EPSILON;
646 
647                 double hPrev = updateIfCloseToZero(getB(0, x));
648 
649                 int n = 1;
650                 double dPrev = 0.0;
651                 double cPrev = hPrev;
652                 double hN;
653 
654                 while (n <= maxIterations) {
655                     final double a = getA(n, x);
656                     final double b = getB(n, x);
657 
658                     double dN = updateIfCloseToZero(b + a * dPrev);
659                     final double cN = updateIfCloseToZero(b + a / cPrev);
660 
661                     dN = 1 / dN;
662                     final double deltaN = cN * dN;
663                     hN = hPrev * deltaN;
664 
665                     if (!Double.isFinite(hN)) {
666                         throw new ArithmeticException(String.format(
667                                 MSG_DIVERGED, hN, x));
668                     }
669 
670                     // Additional check added in Numbers 1.1
671                     if (deltaN == 0) {
672                         throw new ArithmeticException();
673                     }
674 
675                     if (Math.abs(deltaN - 1) < eps) {
676                         return hN;
677                     }
678 
679                     dPrev = dN;
680                     cPrev = cN;
681                     hPrev = hN;
682                     ++n;
683                 }
684 
685                 throw new ArithmeticException(MSG_MAX_ITERATIONS + maxIterations);
686             }
687         }
688 
689         /**
690          * Extend the ContinuedFraction class to add a method that uses
691          * the leading term a0.
692          * Evaluates:
693          * <pre>
694          *            a0
695          *      ---------------
696          *      b0 +     a1
697          *           ----------
698          *           b1 +   a2
699          *                -----
700          *                b2 + ...
701          * </pre>
702          */
703         abstract static class ContinuedFractionA extends ContinuedFraction {
704             @Override
705             public double evaluate(double x, double epsilon, int maxIterations) {
706                 // Relative error epsilon must not be zero.
707                 // Do not use Math.max as NaN would be returned for a NaN epsilon.
708                 final double eps =  epsilon > EPSILON ? epsilon : EPSILON;
709 
710                 final double a0 = getA(0, x);
711 
712                 double hPrev = updateIfCloseToZero(getB(0, x));
713 
714                 int n = 1;
715                 double dPrev = 0.0;
716                 double cPrev = hPrev;
717                 double hN;
718 
719                 while (n <= maxIterations) {
720                     final double a = getA(n, x);
721                     final double b = getB(n, x);
722 
723                     double dN = updateIfCloseToZero(b + a * dPrev);
724                     final double cN = updateIfCloseToZero(b + a / cPrev);
725 
726                     dN = 1 / dN;
727                     final double deltaN = cN * dN;
728                     hN = hPrev * deltaN;
729 
730                     if (!Double.isFinite(hN)) {
731                         throw new ArithmeticException(String.format(
732                             MSG_DIVERGED, hN, x));
733                     }
734 
735                     if (deltaN == 0) {
736                         throw new ArithmeticException();
737                     }
738 
739                     if (Math.abs(deltaN - 1) < eps) {
740                         // Divide the numerator a0 by the converged continued fraction
741                         return a0 / hN;
742                     }
743 
744                     dPrev = dN;
745                     cPrev = cN;
746                     hPrev = hN;
747                     ++n;
748                 }
749 
750                 throw new ArithmeticException(MSG_MAX_ITERATIONS + maxIterations);
751             }
752         }
753 
754         /**
755          * Extend the ContinuedFraction class to add a method that does not use
756          * the leading term b0. The first terms requested use n=1.
757          * Evaluates:
758          * <pre>
759          *            a1
760          *      ---------------
761          *      b1 +     a2
762          *           ----------
763          *           b2 +   a3
764          *                -----
765          *                b3 + ...
766          * </pre>
767          */
768         abstract static class ContinuedFractionA1 extends ContinuedFraction {
769             @Override
770             public double evaluate(double x, double epsilon, int maxIterations) {
771                 // Relative error epsilon must not be zero.
772                 // Do not use Math.max as NaN would be returned for a NaN epsilon.
773                 final double eps =  epsilon > EPSILON ? epsilon : EPSILON;
774 
775                 final double a0 = getA(1, x);
776 
777                 double hPrev = updateIfCloseToZero(getB(1, x));
778 
779                 int n = 2;
780                 double dPrev = 0.0;
781                 double cPrev = hPrev;
782                 double hN;
783 
784                 while (n <= maxIterations) {
785                     final double a = getA(n, x);
786                     final double b = getB(n, x);
787 
788                     double dN = updateIfCloseToZero(b + a * dPrev);
789                     final double cN = updateIfCloseToZero(b + a / cPrev);
790 
791                     dN = 1 / dN;
792                     final double deltaN = cN * dN;
793                     hN = hPrev * deltaN;
794 
795                     if (!Double.isFinite(hN)) {
796                         throw new ArithmeticException(String.format(
797                             MSG_DIVERGED, hN, x));
798                     }
799 
800                     if (deltaN == 0) {
801                         throw new ArithmeticException();
802                     }
803 
804                     if (Math.abs(deltaN - 1) < eps) {
805                         // Divide the numerator a0 by the converged continued fraction
806                         return a0 / hN;
807                     }
808 
809                     dPrev = dN;
810                     cPrev = cN;
811                     hPrev = hN;
812                     ++n;
813                 }
814 
815                 throw new ArithmeticException(MSG_MAX_ITERATIONS + maxIterations);
816             }
817         }
818 
819         /**
820          * A continued fraction class.
821          * Evaluates:
822          * <pre>
823          *            a1
824          *      ---------------
825          *      b1 +     a2
826          *           ----------
827          *           b2 +   a3
828          *                -----
829          *                b3 + ...
830          * </pre>
831          */
832         abstract static class ContinuedFractionIterator {
833             /** Current a coefficient. */
834             private double a = 1;
835             /** Current b coefficient. */
836             private double b = 1;
837 
838             /**
839              * @param ca the next a coefficient
840              * @param cb the next b coefficient
841              */
842             protected void setCoefficients(double ca, double cb) {
843                 this.a = ca;
844                 this.b = cb;
845             }
846 
847             /**
848              * Set the next coefficients using {@link #setCoefficients(double, double)}.
849              */
850             abstract void next();
851 
852             /**
853              * Evaluate the fraction.
854              *
855              * @param epsilon the epsilon
856              * @param maxIterations the max iterations
857              * @return the value
858              */
859             public double evaluate(double epsilon, int maxIterations) {
860                 // Relative error epsilon must not be zero.
861                 // Do not use Math.max as NaN would be returned for a NaN epsilon.
862                 final double eps = epsilon > EPSILON ? epsilon : EPSILON;
863 
864                 next();
865                 final double a0 = a;
866 
867                 double hPrev = updateIfCloseToZero(b);
868 
869                 int n = 2;
870                 double dPrev = 0.0;
871                 double cPrev = hPrev;
872                 double hN;
873 
874                 while (n <= maxIterations) {
875                     next();
876 
877                     double dN = updateIfCloseToZero(b + a * dPrev);
878                     final double cN = updateIfCloseToZero(b + a / cPrev);
879 
880                     dN = 1 / dN;
881                     final double deltaN = cN * dN;
882                     hN = hPrev * deltaN;
883 
884                     if (!Double.isFinite(hN)) {
885                         throw new ArithmeticException("Continued fraction diverged to: " + hN);
886                     }
887 
888                     if (deltaN == 0) {
889                         throw new ArithmeticException();
890                     }
891 
892                     // Note:
893                     // Changing this from '< eps' to '<= eps' has a small but
894                     // noticeable effect on the performance.
895                     if (Math.abs(deltaN - 1) <= eps) {
896                         // Divide the numerator a0 by the converged continued fraction
897                         return a0 / hN;
898                     }
899 
900                     dPrev = dN;
901                     cPrev = cN;
902                     hPrev = hN;
903                     ++n;
904                 }
905 
906                 throw new ArithmeticException(MSG_MAX_ITERATIONS + maxIterations);
907             }
908         }
909 
910         /**
911          * Returns the value, or if close to zero returns a small epsilon.
912          *
913          * <p>This method is used in Thompson & Barnett to monitor both the numerator and denominator
914          * ratios for approaches to zero.
915          *
916          * @param value the value
917          * @return the value (or small epsilon)
918          */
919         private static double updateIfCloseToZero(double value) {
920             return Math.abs(value) < SMALL ? Math.copySign(SMALL, value) : value;
921         }
922     }
923 
924     /**
925      * Gets the pairs of (a,z) data used for benchmarking.
926      *
927      * @return the data
928      */
929     static double[][] getData() {
930         return Arrays.stream(A_Z).map(d -> d.clone()).toArray(double[][]::new);
931     }
932 
933     /**
934      * Apply the function to all the numbers.
935      *
936      * @param fun Function.
937      * @param bh Data sink.
938      */
939     private static void apply(DoubleBinaryOperator fun, Blackhole bh) {
940         for (int i = 0; i < A_Z.length; i++) {
941             final double[] az = A_Z[i];
942             bh.consume(fun.applyAsDouble(az[0], az[1]));
943         }
944     }
945 
946     // Benchmark methods.
947     // Benchmarks use function references to perform different operations on the numbers.
948 
949     /**
950      * Benchmark the error function.
951      *
952      * @param data Test data.
953      * @param bh Data sink.
954      */
955     @Benchmark
956     public void evaluate(BaseData data, Blackhole bh) {
957         apply(data.getFunction(), bh);
958     }
959 }