thermite_special/tables/bernoulli.rs
1// @generated by gen_consts.py at the workspace root. DO NOT EDIT BY HAND.
2//! Bernoulli numbers `$B_{2n}$`, as one static table per float format.
3//!
4//! **The tables start at `$B_2$`**, so entry `i` is `$B_{2i+2}$`. They are even-index
5//! only: every odd-index Bernoulli number past `$B_1$` is zero, so storing them would
6//! double the table for nothing.
7//!
8//! ```
9//! use thermite_special::tables::bernoulli::BernoulliNumbers;
10//!
11//! assert_eq!(f64::B2N[0], 1.0 / 6.0); // B_2
12//! assert_eq!(f64::B2N[2], 1.0 / 42.0); // B_6
13//! ```
14//!
15//! # `$B_0$` and `$B_1$` are deliberately absent
16//!
17//! `$B_1$` is the single value the two competing conventions disagree on: `$-1/2$` if
18//! you take the generating function to be `$x/(e^x - 1)$`, `$+1/2$` if you take it to be
19//! `$x/(1 - e^{-x})$` (Knuth has argued in print for the latter). Every _other_ Bernoulli
20//! number is identical under both, so omitting `$B_1$` makes this table convention-free
21//! rather than convention-bearing.
22//!
23//! `$B_0 = 1$` is not contested, but it goes with it, because the two co-occur. A formula
24//! that indexes the sequence from zero (Faulhaber's sum of powers, the binomial
25//! recurrence, the Bernoulli polynomials) reaches `$B_1$` at `$k = 1$` and therefore
26//! already special-cases the head of the sequence. A formula that skips `$B_1$`
27//! (Euler-Maclaurin, the `$\ln\Gamma$` / `$\psi$` asymptotic series, the `$\zeta(2n)$`
28//! identity) starts at `$B_2$` and never wanted `$B_0$` either. Nothing sits in the gap,
29//! so the table holds exactly the values that need a table.
30//!
31//! Callers who want the head should let their heart guide them on `$B_1 = \pm\tfrac{1}{2}$`
32//! and write `$B_0 = 1$` beside it.
33//!
34//! # The table ends where the format does
35//!
36//! `$|B_{2n}|$` grows factorially,
37//!
38//! ```math
39//! |B_{2n}| = \frac{2\,(2n)!}{(2\pi)^{2n}}\,\zeta(2n)
40//! \sim 4\sqrt{\pi n}\left(\frac{n}{\pi e}\right)^{2n}
41//! ```
42//!
43//! with consecutive terms growing by roughly `$n^2/\pi^2$`, so each format has a _last_
44//! representable Bernoulli number and nothing beyond it to return.
45//!
46//! The tables stop exactly there, which means **`B2N.len()` is the overflow boundary**:
47//! `B2N.get(i)` is `None` precisely where the value would be infinite. There is no
48//! overflow policy, no error type and no limit constant, because the slice length
49//! already carries that information.
50//!
51//! There is no underflow at the other end. `$|B_{2n}|$` bottoms out at
52//! `$B_6 = 1/42$` and grows monotonically after it, so no entry is denormal.
53//!
54//! | format | entries | first | last finite | first to overflow |
55//! |---|---|---|---|---|
56//! | `f32` | 32 | `$B_2$` | `$B_{64}$` | `$B_{66}$` |
57//! | `f64` | 129 | `$B_2$` | `$B_{258}$` | `$B_{260}$` |
58//!
59//! `thermite-compensated` implements the same trait for `Compensated<f32>` and
60//! `Compensated<f64>` under its `special` feature. Those tables are the SAME lengths: a
61//! double-double carries twice the mantissa but the same exponent range, so widening the
62//! type buys precision, not reach.
63
64use thermite::element::FloatElement;
65
66/// Static Bernoulli number tables for a float format.
67///
68/// Implemented for `f32` and `f64` here, and for `Compensated<f32>` /
69/// `Compensated<f64>` by `thermite-compensated` under its `special` feature.
70pub trait BernoulliNumbers: FloatElement {
71 /// `$B_2, B_4, B_6, \ldots$`, every even-index Bernoulli number finite in `Self`,
72 /// starting at `$B_2$`, so that entry `i` is `$B_{2i+2}$`.
73 ///
74 /// See the [module docs](self) for why the table ends where it does, and why
75 /// `$B_0$` and `$B_1$` are not in it.
76 const B2N: &'static [Self];
77}
78
79/// `$B_{2n}$`, or `None` when it is not tabulated: either `$n = 0$`, or `$B_{2n}$`
80/// overflows `E`.
81///
82/// The argument is `n` as in `$B_{2n}$`, following the mathematics rather than the
83/// slice index, so `bernoulli_b2n::<f64>(1)` is `$B_2$`, the first entry. Reach for
84/// [`BernoulliNumbers::B2N`] directly when iterating, where entry `i` is `$B_{2i+2}$`.
85#[inline]
86#[must_use]
87pub fn bernoulli_b2n<E: BernoulliNumbers>(n: usize) -> Option<E> {
88 E::B2N.get(n.checked_sub(1)?).copied()
89}
90
91impl BernoulliNumbers for f32 {
92 #[rustfmt::skip]
93 const B2N: &'static [f32] = &[
94 0.16666667, // B_2
95 -0.033333335, // B_4
96 0.023809524, // B_6
97 -0.033333335, // B_8
98 0.07575758, // B_10
99 -0.25311357, // B_12
100 1.1666666, // B_14
101 -7.092157, // B_16
102 54.971176, // B_18
103 -529.12427, // B_20
104 6192.123, // B_22
105 -86580.25, // B_24
106 1425517.1, // B_26
107 -27298232.0, // B_28
108 6.0158086e+08, // B_30
109 -1.5116316e+10, // B_32
110 4.2961463e+11, // B_34
111 -1.3711655e+13, // B_36
112 4.883323e+14, // B_38
113 -1.929658e+16, // B_40
114 8.4169306e+17, // B_42
115 -4.0338073e+19, // B_44
116 2.1150749e+21, // B_46
117 -1.20866265e+23, // B_48
118 7.500867e+24, // B_50
119 -5.038778e+26, // B_52
120 3.6528777e+28, // B_54
121 -2.849877e+30, // B_56
122 2.3865428e+32, // B_58
123 -2.139995e+34, // B_60
124 2.0500976e+36, // B_62
125 -2.0938006e+38, // B_64
126 ];
127}
128
129impl BernoulliNumbers for f64 {
130 #[rustfmt::skip]
131 const B2N: &'static [f64] = &[
132 0.16666666666666666, // B_2
133 -0.03333333333333333, // B_4
134 0.023809523809523808, // B_6
135 -0.03333333333333333, // B_8
136 0.07575757575757576, // B_10
137 -0.2531135531135531, // B_12
138 1.1666666666666667, // B_14
139 -7.092156862745098, // B_16
140 54.971177944862156, // B_18
141 -529.1242424242424, // B_20
142 6192.123188405797, // B_22
143 -86580.25311355312, // B_24
144 1425517.1666666667, // B_26
145 -27298231.067816094, // B_28
146 601580873.9006424, // B_30
147 -15116315767.092157, // B_32
148 429614643061.1667, // B_34
149 -13711655205088.332, // B_36
150 488332318973593.2, // B_38
151 -1.9296579341940068e+16, // B_40
152 8.416930475736826e+17, // B_42
153 -4.0338071854059454e+19, // B_44
154 2.1150748638081993e+21, // B_46
155 -1.2086626522296526e+23, // B_48
156 7.500866746076964e+24, // B_50
157 -5.038778101481069e+26, // B_52
158 3.6528776484818122e+28, // B_54
159 -2.849876930245088e+30, // B_56
160 2.3865427499683627e+32, // B_58
161 -2.1399949257225335e+34, // B_60
162 2.0500975723478097e+36, // B_62
163 -2.093800591134638e+38, // B_64
164 2.2752696488463515e+40, // B_66
165 -2.6257710286239577e+42, // B_68
166 3.212508210271803e+44, // B_70
167 -4.159827816679471e+46, // B_72
168 5.692069548203528e+48, // B_74
169 -8.218362941978458e+50, // B_76
170 1.2502904327166994e+53, // B_78
171 -2.001558323324837e+55, // B_80
172 3.3674982915364376e+57, // B_82
173 -5.947097050313545e+59, // B_84
174 1.1011910323627977e+62, // B_86
175 -2.1355259545253502e+64, // B_88
176 4.3328896986641194e+66, // B_90
177 -9.188552824166933e+68, // B_92
178 2.0346896776329074e+71, // B_94
179 -4.700383395803573e+73, // B_96
180 1.131804344548425e+76, // B_98
181 -2.8382249570693707e+78, // B_100
182 7.406424897967885e+80, // B_102
183 -2.0096454802756605e+83, // B_104
184 5.665717005080594e+85, // B_106
185 -1.6584511154136216e+88, // B_108
186 5.036885995049238e+90, // B_110
187 -1.5861468237658186e+93, // B_112
188 5.1756743617545625e+95, // B_114
189 -1.7488921840217116e+98, // B_116
190 6.116051999495218e+100, // B_118
191 -2.2122776912707833e+103, // B_120
192 8.272277679877097e+105, // B_122
193 -3.195892511141571e+108, // B_124
194 1.2750082223387793e+111, // B_126
195 -5.250092308677413e+113, // B_128
196 2.2301817894241627e+116, // B_130
197 -9.76845219309552e+118, // B_132
198 4.409836197845295e+121, // B_134
199 -2.050857088646409e+124, // B_136
200 9.821443327979128e+126, // B_138
201 -4.841260079820888e+129, // B_140
202 2.4553088801480982e+132, // B_142
203 -1.2806926804084748e+135, // B_144
204 6.867616710466858e+137, // B_146
205 -3.7846468581969106e+140, // B_148
206 2.142610125066529e+143, // B_150
207 -1.2456727137183695e+146, // B_152
208 7.434578755100016e+148, // B_154
209 -4.5535795304641704e+151, // B_156
210 2.861211281685887e+154, // B_158
211 -1.843772355203387e+157, // B_160
212 1.2181154536221047e+160, // B_162
213 -8.248218718531412e+162, // B_164
214 5.722587793783294e+165, // B_166
215 -4.0668530525059105e+168, // B_168
216 2.9596092064642052e+171, // B_170
217 -2.2049522565189457e+174, // B_172
218 1.68125970728896e+177, // B_174
219 -1.3116736213556958e+180, // B_176
220 1.0467894009478039e+183, // B_178
221 -8.543289357883371e+185, // B_180
222 7.128782132248655e+188, // B_182
223 -6.08029314555359e+191, // B_184
224 5.299677642484992e+194, // B_186
225 -4.719425916874586e+197, // B_188
226 4.292841379140298e+200, // B_190
227 -3.9876744968232205e+203, // B_192
228 3.781978041935888e+206, // B_194
229 -3.661423368368119e+209, // B_196
230 3.617609027237286e+212, // B_198
231 -3.647077264519136e+215, // B_200
232 3.750875543645441e+218, // B_202
233 -3.934586729643903e+221, // B_204
234 4.208821114819008e+224, // B_206
235 -4.590229622061792e+227, // B_208
236 5.103172577262957e+230, // B_210
237 -5.782276230365695e+233, // B_212
238 6.676248216783588e+236, // B_214
239 -7.853530764445042e+239, // B_216
240 9.410689406705872e+242, // B_218
241 -1.1484933873465185e+246, // B_220
242 1.4272958742848785e+249, // B_222
243 -1.805955958690931e+252, // B_224
244 2.3261535307660807e+255, // B_226
245 -3.0495751715499594e+258, // B_228
246 4.068580607643398e+261, // B_230
247 -5.523103132197436e+264, // B_232
248 7.6277279396434395e+267, // B_234
249 -1.0715571119697886e+271, // B_236
250 1.5310200895969188e+274, // B_238
251 -2.2244891682179836e+277, // B_240
252 3.286267919069014e+280, // B_242
253 -4.935592895596035e+283, // B_244
254 7.534957120083251e+286, // B_246
255 -1.1691485154584178e+290, // B_248
256 1.843526146783894e+293, // B_250
257 -2.953682617296808e+296, // B_252
258 4.807932127750157e+299, // B_254
259 -7.950212504588525e+302, // B_256
260 1.3352784187354634e+306, // B_258
261 ];
262}