1
1
/*
2
- Copyright (C) 2016 Fredrik Johansson
2
+ Copyright (C) 2016, 2025 Fredrik Johansson
3
3
4
4
This file is part of FLINT.
5
5
9
9
(at your option) any later version. See <https://www.gnu.org/licenses/>.
10
10
*/
11
11
12
+ #include "mag.h"
12
13
#include "acb_poly.h"
13
14
15
+ void
16
+ _acb_sinc_jet_zero (acb_ptr res , const acb_t z , slong len , slong prec )
17
+ {
18
+ mag_ptr D ;
19
+ slong n ;
20
+ int is_real , is_imag ;
21
+ mag_t zm , err , fac ;
22
+ arb_t wide ;
23
+
24
+ is_real = acb_is_real (z );
25
+ is_imag = arb_is_zero (acb_realref (z ));
26
+
27
+ mag_init (zm );
28
+ mag_init (err );
29
+ mag_init (fac );
30
+ arb_init (wide );
31
+
32
+ acb_get_mag (zm , z );
33
+
34
+ D = _mag_vec_init (len + 1 );
35
+
36
+ /* Compute sequence of derivative bounds
37
+
38
+ sinc^{(n)}(z) = int_0^1 t^n cos(t z + n pi / 2) dt
39
+
40
+ |sinc^{(n)}(z)| <= cosh(im(z)) min(1/|z|, 1/(n+1))
41
+ |sinc^{(n)}(z)| <= cosh(im(z)) min(1/|z|, 1/(n+1), |z|/(n+2)) (odd n)
42
+ */
43
+ {
44
+ mag_t C , b1 , b2 , b3 ;
45
+
46
+ mag_init (C );
47
+ mag_init (b1 );
48
+ mag_init (b2 );
49
+ mag_init (b3 );
50
+
51
+ /* C = cosh(im(z)) */
52
+ arb_get_mag (C , acb_imagref (z ));
53
+ mag_cosh (C , C );
54
+
55
+ /* b1 = 1/|z| */
56
+ acb_get_mag_lower (b1 , z );
57
+ mag_inv (b1 , b1 );
58
+
59
+ for (n = 0 ; n <= len ; n ++ )
60
+ {
61
+ /* b2 = 1/(n+1) */
62
+ mag_one (b2 );
63
+ mag_div_ui (b2 , b2 , n + 1 );
64
+ mag_min (b2 , b1 , b2 );
65
+
66
+ /* b3 = |z|/(n+2) */
67
+ if (n % 2 == 1 )
68
+ {
69
+ mag_div_ui (b3 , zm , n + 2 );
70
+ mag_min (b2 , b2 , b3 );
71
+ }
72
+
73
+ mag_mul (D + n , C , b2 );
74
+ }
75
+
76
+ mag_clear (C );
77
+ mag_clear (b1 );
78
+ mag_clear (b2 );
79
+ mag_clear (b3 );
80
+ }
81
+
82
+ mag_one (fac );
83
+
84
+ for (n = 0 ; n < len ; n ++ )
85
+ {
86
+ /* sinc^{(n)}(0) / n! */
87
+ if (n == 0 )
88
+ acb_one (res + n );
89
+ else if (n % 2 == 1 )
90
+ acb_zero (res + n );
91
+ else
92
+ acb_div_si (res + n , res + n - 2 , - n * (n + 1 ), prec );
93
+
94
+ if (n > 1 )
95
+ mag_div_ui (fac , fac , n );
96
+
97
+ /* |sinc^{(n)}(0 + eps) - sinc^{(n)}(0)| / n! <= |eps| * |sinc^{(n+1)}(z)| / n!, z = (+/- eps) */
98
+ mag_mul (err , zm , D + n + 1 );
99
+ mag_mul (err , err , fac );
100
+ acb_add_error_mag (res + n , err );
101
+
102
+ /* sinc^{(n)}(+/- eps) is a possibly better enclosure */
103
+ arb_zero (wide );
104
+ mag_mul (err , D + n , fac );
105
+ arb_add_error_mag (wide , err );
106
+ arb_intersection (acb_realref (res + n ), acb_realref (res + n ), wide , prec );
107
+ arb_intersection (acb_imagref (res + n ), acb_imagref (res + n ), wide , prec );
108
+
109
+ if (is_real || (is_imag && (n % 2 == 0 )))
110
+ arb_zero (acb_imagref (res + n ));
111
+
112
+ if (is_imag && (n % 2 == 1 ))
113
+ arb_zero (acb_realref (res + n ));
114
+ }
115
+
116
+ _mag_vec_clear (D , len + 1 );
117
+
118
+ mag_clear (zm );
119
+ mag_clear (err );
120
+ mag_clear (fac );
121
+ arb_clear (wide );
122
+ }
123
+
14
124
void
15
125
_acb_poly_sinc_series (acb_ptr g , acb_srcptr h , slong hlen , slong n , slong prec )
16
126
{
@@ -35,6 +145,13 @@ _acb_poly_sinc_series(acb_ptr g, acb_srcptr h, slong hlen, slong n, slong prec)
35
145
_acb_poly_sin_series (t , u , hlen , n + 1 , prec );
36
146
_acb_poly_div_series (g , t + 1 , n , u + 1 , hlen - 1 , n , prec );
37
147
}
148
+ else if (acb_contains_zero (h ))
149
+ {
150
+ _acb_sinc_jet_zero (t , h , n , prec );
151
+ /* compose with nonconstant part */
152
+ acb_zero (u );
153
+ _acb_poly_compose_series (g , t , n , u , hlen , n , prec );
154
+ }
38
155
else
39
156
{
40
157
_acb_poly_sin_series (t , u , hlen , n , prec );
0 commit comments