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 #define MATHFUNC(funcname) funcname ## l
32181254a7Smrg
33181254a7Smrg #if defined (HAVE_GFC_REAL_10)
34181254a7Smrg
35181254a7Smrg
36181254a7Smrg
37181254a7Smrg #if defined (HAVE_JNL)
38181254a7Smrg extern void bessel_jn_r10 (gfc_array_r10 * const restrict ret, int n1,
39181254a7Smrg int n2, GFC_REAL_10 x);
40181254a7Smrg export_proto(bessel_jn_r10);
41181254a7Smrg
42181254a7Smrg void
bessel_jn_r10(gfc_array_r10 * const restrict ret,int n1,int n2,GFC_REAL_10 x)43181254a7Smrg bessel_jn_r10 (gfc_array_r10 * const restrict ret, int n1, int n2, GFC_REAL_10 x)
44181254a7Smrg {
45181254a7Smrg int i;
46181254a7Smrg index_type stride;
47181254a7Smrg
48181254a7Smrg GFC_REAL_10 last1, last2, x2rev;
49181254a7Smrg
50181254a7Smrg stride = GFC_DESCRIPTOR_STRIDE(ret,0);
51181254a7Smrg
52181254a7Smrg if (ret->base_addr == NULL)
53181254a7Smrg {
54181254a7Smrg size_t size = n2 < n1 ? 0 : n2-n1+1;
55181254a7Smrg GFC_DIMENSION_SET(ret->dim[0], 0, size-1, 1);
56181254a7Smrg ret->base_addr = xmallocarray (size, sizeof (GFC_REAL_10));
57181254a7Smrg ret->offset = 0;
58181254a7Smrg }
59181254a7Smrg
60181254a7Smrg if (unlikely (n2 < n1))
61181254a7Smrg return;
62181254a7Smrg
63181254a7Smrg if (unlikely (compile_options.bounds_check)
64181254a7Smrg && GFC_DESCRIPTOR_EXTENT(ret,0) != (n2-n1+1))
65181254a7Smrg runtime_error("Incorrect extent in return value of BESSEL_JN "
66181254a7Smrg "(%ld vs. %ld)", (long int) n2-n1,
67181254a7Smrg (long int) GFC_DESCRIPTOR_EXTENT(ret,0));
68181254a7Smrg
69181254a7Smrg stride = GFC_DESCRIPTOR_STRIDE(ret,0);
70181254a7Smrg
71181254a7Smrg if (unlikely (x == 0))
72181254a7Smrg {
73181254a7Smrg ret->base_addr[0] = 1;
74181254a7Smrg for (i = 1; i <= n2-n1; i++)
75181254a7Smrg ret->base_addr[i*stride] = 0;
76181254a7Smrg return;
77181254a7Smrg }
78181254a7Smrg
79181254a7Smrg last1 = MATHFUNC(jn) (n2, x);
80181254a7Smrg ret->base_addr[(n2-n1)*stride] = last1;
81181254a7Smrg
82181254a7Smrg if (n1 == n2)
83181254a7Smrg return;
84181254a7Smrg
85181254a7Smrg last2 = MATHFUNC(jn) (n2 - 1, x);
86181254a7Smrg ret->base_addr[(n2-n1-1)*stride] = last2;
87181254a7Smrg
88181254a7Smrg if (n1 + 1 == n2)
89181254a7Smrg return;
90181254a7Smrg
91181254a7Smrg x2rev = GFC_REAL_10_LITERAL(2.)/x;
92181254a7Smrg
93181254a7Smrg for (i = n2-n1-2; i >= 0; i--)
94181254a7Smrg {
95181254a7Smrg ret->base_addr[i*stride] = x2rev * (i+1+n1) * last2 - last1;
96181254a7Smrg last1 = last2;
97181254a7Smrg last2 = ret->base_addr[i*stride];
98181254a7Smrg }
99181254a7Smrg }
100181254a7Smrg
101181254a7Smrg #endif
102181254a7Smrg
103181254a7Smrg #if defined (HAVE_YNL)
104181254a7Smrg extern void bessel_yn_r10 (gfc_array_r10 * const restrict ret,
105181254a7Smrg int n1, int n2, GFC_REAL_10 x);
106181254a7Smrg export_proto(bessel_yn_r10);
107181254a7Smrg
108181254a7Smrg void
bessel_yn_r10(gfc_array_r10 * const restrict ret,int n1,int n2,GFC_REAL_10 x)109181254a7Smrg bessel_yn_r10 (gfc_array_r10 * const restrict ret, int n1, int n2,
110181254a7Smrg GFC_REAL_10 x)
111181254a7Smrg {
112181254a7Smrg int i;
113181254a7Smrg index_type stride;
114181254a7Smrg
115181254a7Smrg GFC_REAL_10 last1, last2, x2rev;
116181254a7Smrg
117181254a7Smrg stride = GFC_DESCRIPTOR_STRIDE(ret,0);
118181254a7Smrg
119181254a7Smrg if (ret->base_addr == NULL)
120181254a7Smrg {
121181254a7Smrg size_t size = n2 < n1 ? 0 : n2-n1+1;
122181254a7Smrg GFC_DIMENSION_SET(ret->dim[0], 0, size-1, 1);
123181254a7Smrg ret->base_addr = xmallocarray (size, sizeof (GFC_REAL_10));
124181254a7Smrg ret->offset = 0;
125181254a7Smrg }
126181254a7Smrg
127181254a7Smrg if (unlikely (n2 < n1))
128181254a7Smrg return;
129181254a7Smrg
130181254a7Smrg if (unlikely (compile_options.bounds_check)
131181254a7Smrg && GFC_DESCRIPTOR_EXTENT(ret,0) != (n2-n1+1))
132181254a7Smrg runtime_error("Incorrect extent in return value of BESSEL_JN "
133181254a7Smrg "(%ld vs. %ld)", (long int) n2-n1,
134181254a7Smrg (long int) GFC_DESCRIPTOR_EXTENT(ret,0));
135181254a7Smrg
136181254a7Smrg stride = GFC_DESCRIPTOR_STRIDE(ret,0);
137181254a7Smrg
138181254a7Smrg if (unlikely (x == 0))
139181254a7Smrg {
140181254a7Smrg for (i = 0; i <= n2-n1; i++)
141181254a7Smrg #if defined(GFC_REAL_10_INFINITY)
142181254a7Smrg ret->base_addr[i*stride] = -GFC_REAL_10_INFINITY;
143181254a7Smrg #else
144181254a7Smrg ret->base_addr[i*stride] = -GFC_REAL_10_HUGE;
145181254a7Smrg #endif
146181254a7Smrg return;
147181254a7Smrg }
148181254a7Smrg
149181254a7Smrg last1 = MATHFUNC(yn) (n1, x);
150181254a7Smrg ret->base_addr[0] = last1;
151181254a7Smrg
152181254a7Smrg if (n1 == n2)
153181254a7Smrg return;
154181254a7Smrg
155181254a7Smrg last2 = MATHFUNC(yn) (n1 + 1, x);
156181254a7Smrg ret->base_addr[1*stride] = last2;
157181254a7Smrg
158181254a7Smrg if (n1 + 1 == n2)
159181254a7Smrg return;
160181254a7Smrg
161181254a7Smrg x2rev = GFC_REAL_10_LITERAL(2.)/x;
162181254a7Smrg
163181254a7Smrg for (i = 2; i <= n2 - n1; i++)
164181254a7Smrg {
165181254a7Smrg #if defined(GFC_REAL_10_INFINITY)
166181254a7Smrg if (unlikely (last2 == -GFC_REAL_10_INFINITY))
167181254a7Smrg {
168181254a7Smrg ret->base_addr[i*stride] = -GFC_REAL_10_INFINITY;
169181254a7Smrg }
170181254a7Smrg else
171181254a7Smrg #endif
172181254a7Smrg {
173181254a7Smrg ret->base_addr[i*stride] = x2rev * (i-1+n1) * last2 - last1;
174181254a7Smrg last1 = last2;
175181254a7Smrg last2 = ret->base_addr[i*stride];
176181254a7Smrg }
177181254a7Smrg }
178181254a7Smrg }
179181254a7Smrg #endif
180181254a7Smrg
181181254a7Smrg #endif
182181254a7Smrg
183