1181254a7Smrg /* Implementation of the BESSEL_JN and BESSEL_YN transformational
2181254a7Smrg function using a recurrence algorithm.
3*b1e83836Smrg Copyright (C) 2010-2022 Free Software Foundation, Inc.
4181254a7Smrg Contributed by Tobias Burnus <burnus@net-b.de>
5181254a7Smrg
6181254a7Smrg This file is part of the GNU Fortran runtime library (libgfortran).
7181254a7Smrg
8181254a7Smrg Libgfortran is free software; you can redistribute it and/or
9181254a7Smrg modify it under the terms of the GNU General Public
10181254a7Smrg License as published by the Free Software Foundation; either
11181254a7Smrg version 3 of the License, or (at your option) any later version.
12181254a7Smrg
13181254a7Smrg Libgfortran is distributed in the hope that it will be useful,
14181254a7Smrg but WITHOUT ANY WARRANTY; without even the implied warranty of
15181254a7Smrg MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16181254a7Smrg GNU General Public License for more details.
17181254a7Smrg
18181254a7Smrg Under Section 7 of GPL version 3, you are granted additional
19181254a7Smrg permissions described in the GCC Runtime Library Exception, version
20181254a7Smrg 3.1, as published by the Free Software Foundation.
21181254a7Smrg
22181254a7Smrg You should have received a copy of the GNU General Public License and
23181254a7Smrg a copy of the GCC Runtime Library Exception along with this program;
24181254a7Smrg see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
25181254a7Smrg <http://www.gnu.org/licenses/>. */
26181254a7Smrg
27181254a7Smrg #include "libgfortran.h"
28181254a7Smrg
29181254a7Smrg
30181254a7Smrg
31181254a7Smrg #if defined(GFC_REAL_16_IS_FLOAT128)
32181254a7Smrg #define MATHFUNC(funcname) funcname ## q
33181254a7Smrg #else
34181254a7Smrg #define MATHFUNC(funcname) funcname ## l
35181254a7Smrg #endif
36181254a7Smrg
37181254a7Smrg #if defined (HAVE_GFC_REAL_16)
38181254a7Smrg
39181254a7Smrg
40181254a7Smrg
41181254a7Smrg #if (defined(GFC_REAL_16_IS_FLOAT128) || defined(HAVE_JNL))
42181254a7Smrg extern void bessel_jn_r16 (gfc_array_r16 * const restrict ret, int n1,
43181254a7Smrg int n2, GFC_REAL_16 x);
44181254a7Smrg export_proto(bessel_jn_r16);
45181254a7Smrg
46181254a7Smrg void
bessel_jn_r16(gfc_array_r16 * const restrict ret,int n1,int n2,GFC_REAL_16 x)47181254a7Smrg bessel_jn_r16 (gfc_array_r16 * const restrict ret, int n1, int n2, GFC_REAL_16 x)
48181254a7Smrg {
49181254a7Smrg int i;
50181254a7Smrg index_type stride;
51181254a7Smrg
52181254a7Smrg GFC_REAL_16 last1, last2, x2rev;
53181254a7Smrg
54181254a7Smrg stride = GFC_DESCRIPTOR_STRIDE(ret,0);
55181254a7Smrg
56181254a7Smrg if (ret->base_addr == NULL)
57181254a7Smrg {
58181254a7Smrg size_t size = n2 < n1 ? 0 : n2-n1+1;
59181254a7Smrg GFC_DIMENSION_SET(ret->dim[0], 0, size-1, 1);
60181254a7Smrg ret->base_addr = xmallocarray (size, sizeof (GFC_REAL_16));
61181254a7Smrg ret->offset = 0;
62181254a7Smrg }
63181254a7Smrg
64181254a7Smrg if (unlikely (n2 < n1))
65181254a7Smrg return;
66181254a7Smrg
67181254a7Smrg if (unlikely (compile_options.bounds_check)
68181254a7Smrg && GFC_DESCRIPTOR_EXTENT(ret,0) != (n2-n1+1))
69181254a7Smrg runtime_error("Incorrect extent in return value of BESSEL_JN "
70181254a7Smrg "(%ld vs. %ld)", (long int) n2-n1,
71181254a7Smrg (long int) GFC_DESCRIPTOR_EXTENT(ret,0));
72181254a7Smrg
73181254a7Smrg stride = GFC_DESCRIPTOR_STRIDE(ret,0);
74181254a7Smrg
75181254a7Smrg if (unlikely (x == 0))
76181254a7Smrg {
77181254a7Smrg ret->base_addr[0] = 1;
78181254a7Smrg for (i = 1; i <= n2-n1; i++)
79181254a7Smrg ret->base_addr[i*stride] = 0;
80181254a7Smrg return;
81181254a7Smrg }
82181254a7Smrg
83181254a7Smrg last1 = MATHFUNC(jn) (n2, x);
84181254a7Smrg ret->base_addr[(n2-n1)*stride] = last1;
85181254a7Smrg
86181254a7Smrg if (n1 == n2)
87181254a7Smrg return;
88181254a7Smrg
89181254a7Smrg last2 = MATHFUNC(jn) (n2 - 1, x);
90181254a7Smrg ret->base_addr[(n2-n1-1)*stride] = last2;
91181254a7Smrg
92181254a7Smrg if (n1 + 1 == n2)
93181254a7Smrg return;
94181254a7Smrg
95181254a7Smrg x2rev = GFC_REAL_16_LITERAL(2.)/x;
96181254a7Smrg
97181254a7Smrg for (i = n2-n1-2; i >= 0; i--)
98181254a7Smrg {
99181254a7Smrg ret->base_addr[i*stride] = x2rev * (i+1+n1) * last2 - last1;
100181254a7Smrg last1 = last2;
101181254a7Smrg last2 = ret->base_addr[i*stride];
102181254a7Smrg }
103181254a7Smrg }
104181254a7Smrg
105181254a7Smrg #endif
106181254a7Smrg
107181254a7Smrg #if (defined(GFC_REAL_16_IS_FLOAT128) || defined(HAVE_YNL))
108181254a7Smrg extern void bessel_yn_r16 (gfc_array_r16 * const restrict ret,
109181254a7Smrg int n1, int n2, GFC_REAL_16 x);
110181254a7Smrg export_proto(bessel_yn_r16);
111181254a7Smrg
112181254a7Smrg void
bessel_yn_r16(gfc_array_r16 * const restrict ret,int n1,int n2,GFC_REAL_16 x)113181254a7Smrg bessel_yn_r16 (gfc_array_r16 * const restrict ret, int n1, int n2,
114181254a7Smrg GFC_REAL_16 x)
115181254a7Smrg {
116181254a7Smrg int i;
117181254a7Smrg index_type stride;
118181254a7Smrg
119181254a7Smrg GFC_REAL_16 last1, last2, x2rev;
120181254a7Smrg
121181254a7Smrg stride = GFC_DESCRIPTOR_STRIDE(ret,0);
122181254a7Smrg
123181254a7Smrg if (ret->base_addr == NULL)
124181254a7Smrg {
125181254a7Smrg size_t size = n2 < n1 ? 0 : n2-n1+1;
126181254a7Smrg GFC_DIMENSION_SET(ret->dim[0], 0, size-1, 1);
127181254a7Smrg ret->base_addr = xmallocarray (size, sizeof (GFC_REAL_16));
128181254a7Smrg ret->offset = 0;
129181254a7Smrg }
130181254a7Smrg
131181254a7Smrg if (unlikely (n2 < n1))
132181254a7Smrg return;
133181254a7Smrg
134181254a7Smrg if (unlikely (compile_options.bounds_check)
135181254a7Smrg && GFC_DESCRIPTOR_EXTENT(ret,0) != (n2-n1+1))
136181254a7Smrg runtime_error("Incorrect extent in return value of BESSEL_JN "
137181254a7Smrg "(%ld vs. %ld)", (long int) n2-n1,
138181254a7Smrg (long int) GFC_DESCRIPTOR_EXTENT(ret,0));
139181254a7Smrg
140181254a7Smrg stride = GFC_DESCRIPTOR_STRIDE(ret,0);
141181254a7Smrg
142181254a7Smrg if (unlikely (x == 0))
143181254a7Smrg {
144181254a7Smrg for (i = 0; i <= n2-n1; i++)
145181254a7Smrg #if defined(GFC_REAL_16_INFINITY)
146181254a7Smrg ret->base_addr[i*stride] = -GFC_REAL_16_INFINITY;
147181254a7Smrg #else
148181254a7Smrg ret->base_addr[i*stride] = -GFC_REAL_16_HUGE;
149181254a7Smrg #endif
150181254a7Smrg return;
151181254a7Smrg }
152181254a7Smrg
153181254a7Smrg last1 = MATHFUNC(yn) (n1, x);
154181254a7Smrg ret->base_addr[0] = last1;
155181254a7Smrg
156181254a7Smrg if (n1 == n2)
157181254a7Smrg return;
158181254a7Smrg
159181254a7Smrg last2 = MATHFUNC(yn) (n1 + 1, x);
160181254a7Smrg ret->base_addr[1*stride] = last2;
161181254a7Smrg
162181254a7Smrg if (n1 + 1 == n2)
163181254a7Smrg return;
164181254a7Smrg
165181254a7Smrg x2rev = GFC_REAL_16_LITERAL(2.)/x;
166181254a7Smrg
167181254a7Smrg for (i = 2; i <= n2 - n1; i++)
168181254a7Smrg {
169181254a7Smrg #if defined(GFC_REAL_16_INFINITY)
170181254a7Smrg if (unlikely (last2 == -GFC_REAL_16_INFINITY))
171181254a7Smrg {
172181254a7Smrg ret->base_addr[i*stride] = -GFC_REAL_16_INFINITY;
173181254a7Smrg }
174181254a7Smrg else
175181254a7Smrg #endif
176181254a7Smrg {
177181254a7Smrg ret->base_addr[i*stride] = x2rev * (i-1+n1) * last2 - last1;
178181254a7Smrg last1 = last2;
179181254a7Smrg last2 = ret->base_addr[i*stride];
180181254a7Smrg }
181181254a7Smrg }
182181254a7Smrg }
183181254a7Smrg #endif
184181254a7Smrg
185181254a7Smrg #endif
186181254a7Smrg
187