1*b1e83836Smrg /* Implementation of the BESSEL_JN and BESSEL_YN transformational
2*b1e83836Smrg function using a recurrence algorithm.
3*b1e83836Smrg Copyright (C) 2010-2022 Free Software Foundation, Inc.
4*b1e83836Smrg Contributed by Tobias Burnus <burnus@net-b.de>
5*b1e83836Smrg
6*b1e83836Smrg This file is part of the GNU Fortran runtime library (libgfortran).
7*b1e83836Smrg
8*b1e83836Smrg Libgfortran is free software; you can redistribute it and/or
9*b1e83836Smrg modify it under the terms of the GNU General Public
10*b1e83836Smrg License as published by the Free Software Foundation; either
11*b1e83836Smrg version 3 of the License, or (at your option) any later version.
12*b1e83836Smrg
13*b1e83836Smrg Libgfortran is distributed in the hope that it will be useful,
14*b1e83836Smrg but WITHOUT ANY WARRANTY; without even the implied warranty of
15*b1e83836Smrg MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16*b1e83836Smrg GNU General Public License for more details.
17*b1e83836Smrg
18*b1e83836Smrg Under Section 7 of GPL version 3, you are granted additional
19*b1e83836Smrg permissions described in the GCC Runtime Library Exception, version
20*b1e83836Smrg 3.1, as published by the Free Software Foundation.
21*b1e83836Smrg
22*b1e83836Smrg You should have received a copy of the GNU General Public License and
23*b1e83836Smrg a copy of the GCC Runtime Library Exception along with this program;
24*b1e83836Smrg see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
25*b1e83836Smrg <http://www.gnu.org/licenses/>. */
26*b1e83836Smrg
27*b1e83836Smrg #include "libgfortran.h"
28*b1e83836Smrg
29*b1e83836Smrg
30*b1e83836Smrg
31*b1e83836Smrg #if defined(POWER_IEEE128)
32*b1e83836Smrg #define MATHFUNC(funcname) __ ## funcname ## ieee128
33*b1e83836Smrg #else
34*b1e83836Smrg #define MATHFUNC(funcname) funcname ## q
35*b1e83836Smrg #endif
36*b1e83836Smrg
37*b1e83836Smrg #if defined (HAVE_GFC_REAL_17)
38*b1e83836Smrg
39*b1e83836Smrg
40*b1e83836Smrg
41*b1e83836Smrg #if 1 /* FIXME: figure this out later. */
42*b1e83836Smrg extern void bessel_jn_r17 (gfc_array_r17 * const restrict ret, int n1,
43*b1e83836Smrg int n2, GFC_REAL_17 x);
44*b1e83836Smrg export_proto(bessel_jn_r17);
45*b1e83836Smrg
46*b1e83836Smrg void
bessel_jn_r17(gfc_array_r17 * const restrict ret,int n1,int n2,GFC_REAL_17 x)47*b1e83836Smrg bessel_jn_r17 (gfc_array_r17 * const restrict ret, int n1, int n2, GFC_REAL_17 x)
48*b1e83836Smrg {
49*b1e83836Smrg int i;
50*b1e83836Smrg index_type stride;
51*b1e83836Smrg
52*b1e83836Smrg GFC_REAL_17 last1, last2, x2rev;
53*b1e83836Smrg
54*b1e83836Smrg stride = GFC_DESCRIPTOR_STRIDE(ret,0);
55*b1e83836Smrg
56*b1e83836Smrg if (ret->base_addr == NULL)
57*b1e83836Smrg {
58*b1e83836Smrg size_t size = n2 < n1 ? 0 : n2-n1+1;
59*b1e83836Smrg GFC_DIMENSION_SET(ret->dim[0], 0, size-1, 1);
60*b1e83836Smrg ret->base_addr = xmallocarray (size, sizeof (GFC_REAL_17));
61*b1e83836Smrg ret->offset = 0;
62*b1e83836Smrg }
63*b1e83836Smrg
64*b1e83836Smrg if (unlikely (n2 < n1))
65*b1e83836Smrg return;
66*b1e83836Smrg
67*b1e83836Smrg if (unlikely (compile_options.bounds_check)
68*b1e83836Smrg && GFC_DESCRIPTOR_EXTENT(ret,0) != (n2-n1+1))
69*b1e83836Smrg runtime_error("Incorrect extent in return value of BESSEL_JN "
70*b1e83836Smrg "(%ld vs. %ld)", (long int) n2-n1,
71*b1e83836Smrg (long int) GFC_DESCRIPTOR_EXTENT(ret,0));
72*b1e83836Smrg
73*b1e83836Smrg stride = GFC_DESCRIPTOR_STRIDE(ret,0);
74*b1e83836Smrg
75*b1e83836Smrg if (unlikely (x == 0))
76*b1e83836Smrg {
77*b1e83836Smrg ret->base_addr[0] = 1;
78*b1e83836Smrg for (i = 1; i <= n2-n1; i++)
79*b1e83836Smrg ret->base_addr[i*stride] = 0;
80*b1e83836Smrg return;
81*b1e83836Smrg }
82*b1e83836Smrg
83*b1e83836Smrg last1 = MATHFUNC(jn) (n2, x);
84*b1e83836Smrg ret->base_addr[(n2-n1)*stride] = last1;
85*b1e83836Smrg
86*b1e83836Smrg if (n1 == n2)
87*b1e83836Smrg return;
88*b1e83836Smrg
89*b1e83836Smrg last2 = MATHFUNC(jn) (n2 - 1, x);
90*b1e83836Smrg ret->base_addr[(n2-n1-1)*stride] = last2;
91*b1e83836Smrg
92*b1e83836Smrg if (n1 + 1 == n2)
93*b1e83836Smrg return;
94*b1e83836Smrg
95*b1e83836Smrg x2rev = GFC_REAL_17_LITERAL(2.)/x;
96*b1e83836Smrg
97*b1e83836Smrg for (i = n2-n1-2; i >= 0; i--)
98*b1e83836Smrg {
99*b1e83836Smrg ret->base_addr[i*stride] = x2rev * (i+1+n1) * last2 - last1;
100*b1e83836Smrg last1 = last2;
101*b1e83836Smrg last2 = ret->base_addr[i*stride];
102*b1e83836Smrg }
103*b1e83836Smrg }
104*b1e83836Smrg
105*b1e83836Smrg #endif
106*b1e83836Smrg
107*b1e83836Smrg #if 1 /* FIXME: figure this out later. */
108*b1e83836Smrg extern void bessel_yn_r17 (gfc_array_r17 * const restrict ret,
109*b1e83836Smrg int n1, int n2, GFC_REAL_17 x);
110*b1e83836Smrg export_proto(bessel_yn_r17);
111*b1e83836Smrg
112*b1e83836Smrg void
bessel_yn_r17(gfc_array_r17 * const restrict ret,int n1,int n2,GFC_REAL_17 x)113*b1e83836Smrg bessel_yn_r17 (gfc_array_r17 * const restrict ret, int n1, int n2,
114*b1e83836Smrg GFC_REAL_17 x)
115*b1e83836Smrg {
116*b1e83836Smrg int i;
117*b1e83836Smrg index_type stride;
118*b1e83836Smrg
119*b1e83836Smrg GFC_REAL_17 last1, last2, x2rev;
120*b1e83836Smrg
121*b1e83836Smrg stride = GFC_DESCRIPTOR_STRIDE(ret,0);
122*b1e83836Smrg
123*b1e83836Smrg if (ret->base_addr == NULL)
124*b1e83836Smrg {
125*b1e83836Smrg size_t size = n2 < n1 ? 0 : n2-n1+1;
126*b1e83836Smrg GFC_DIMENSION_SET(ret->dim[0], 0, size-1, 1);
127*b1e83836Smrg ret->base_addr = xmallocarray (size, sizeof (GFC_REAL_17));
128*b1e83836Smrg ret->offset = 0;
129*b1e83836Smrg }
130*b1e83836Smrg
131*b1e83836Smrg if (unlikely (n2 < n1))
132*b1e83836Smrg return;
133*b1e83836Smrg
134*b1e83836Smrg if (unlikely (compile_options.bounds_check)
135*b1e83836Smrg && GFC_DESCRIPTOR_EXTENT(ret,0) != (n2-n1+1))
136*b1e83836Smrg runtime_error("Incorrect extent in return value of BESSEL_JN "
137*b1e83836Smrg "(%ld vs. %ld)", (long int) n2-n1,
138*b1e83836Smrg (long int) GFC_DESCRIPTOR_EXTENT(ret,0));
139*b1e83836Smrg
140*b1e83836Smrg stride = GFC_DESCRIPTOR_STRIDE(ret,0);
141*b1e83836Smrg
142*b1e83836Smrg if (unlikely (x == 0))
143*b1e83836Smrg {
144*b1e83836Smrg for (i = 0; i <= n2-n1; i++)
145*b1e83836Smrg #if defined(GFC_REAL_17_INFINITY)
146*b1e83836Smrg ret->base_addr[i*stride] = -GFC_REAL_17_INFINITY;
147*b1e83836Smrg #else
148*b1e83836Smrg ret->base_addr[i*stride] = -GFC_REAL_17_HUGE;
149*b1e83836Smrg #endif
150*b1e83836Smrg return;
151*b1e83836Smrg }
152*b1e83836Smrg
153*b1e83836Smrg last1 = MATHFUNC(yn) (n1, x);
154*b1e83836Smrg ret->base_addr[0] = last1;
155*b1e83836Smrg
156*b1e83836Smrg if (n1 == n2)
157*b1e83836Smrg return;
158*b1e83836Smrg
159*b1e83836Smrg last2 = MATHFUNC(yn) (n1 + 1, x);
160*b1e83836Smrg ret->base_addr[1*stride] = last2;
161*b1e83836Smrg
162*b1e83836Smrg if (n1 + 1 == n2)
163*b1e83836Smrg return;
164*b1e83836Smrg
165*b1e83836Smrg x2rev = GFC_REAL_17_LITERAL(2.)/x;
166*b1e83836Smrg
167*b1e83836Smrg for (i = 2; i <= n2 - n1; i++)
168*b1e83836Smrg {
169*b1e83836Smrg #if defined(GFC_REAL_17_INFINITY)
170*b1e83836Smrg if (unlikely (last2 == -GFC_REAL_17_INFINITY))
171*b1e83836Smrg {
172*b1e83836Smrg ret->base_addr[i*stride] = -GFC_REAL_17_INFINITY;
173*b1e83836Smrg }
174*b1e83836Smrg else
175*b1e83836Smrg #endif
176*b1e83836Smrg {
177*b1e83836Smrg ret->base_addr[i*stride] = x2rev * (i-1+n1) * last2 - last1;
178*b1e83836Smrg last1 = last2;
179*b1e83836Smrg last2 = ret->base_addr[i*stride];
180*b1e83836Smrg }
181*b1e83836Smrg }
182*b1e83836Smrg }
183*b1e83836Smrg #endif
184*b1e83836Smrg
185*b1e83836Smrg #endif
186*b1e83836Smrg
187