fixed/
macros_const.rs

1// Copyright © 2018–2025 Trevor Spiteri
2
3// This library is free software: you can redistribute it and/or
4// modify it under the terms of either
5//
6//   * the Apache License, Version 2.0 or
7//   * the MIT License
8//
9// at your option.
10//
11// You should have recieved copies of the Apache License and the MIT
12// License along with the library. If not, see
13// <https://www.apache.org/licenses/LICENSE-2.0> and
14// <https://opensource.org/licenses/MIT>.
15
16macro_rules! fixed_const {
17    (
18        Self = $Self:ident,
19        Signedness = $Signedness:ident,
20        LeEqU = $LeEqU:ident,
21        [nm4 ..= n] = [$nm4:literal, $nm3:literal, $nm2:literal, $nm1:literal, $n:literal],
22        [LeEqUC0 ..= LeEqUC3] = [$LeEqUC0:ident, $LeEqUC1:ident, $LeEqUC2:ident, $LeEqUC3:ident],
23    ) => {
24        impl<Frac: Unsigned> $Self<Frac> {
25            const fn from_const<SrcFrac: Unsigned>(src: FixedU128<SrcFrac>) -> $Self<Frac> {
26                let right = SrcFrac::U32 - Frac::U32;
27                let bits128 = if right == 128 {
28                    0
29                } else {
30                    src.to_bits() >> right
31                };
32                $Self::from_bits(bits128 as _)
33            }
34        }
35
36        comment! {
37            "This block contains constants in the range 0&nbsp;<&nbsp;<i>x</i>&nbsp;<&nbsp;0.5.
38
39# Examples
40
41```rust
42use fixed::consts;
43use fixed::types::extra::U", $n, ";
44use fixed::", stringify!($Self), ";
45type Fix = ", stringify!($Self), "<U", $n, ">;
46assert_eq!(Fix::LOG10_2, Fix::from_num(consts::LOG10_2));
47```
48";
49            impl<Frac: $LeEqU> $Self<Frac> {
50                /// 1/τ = 0.159154…
51                pub const FRAC_1_TAU: $Self<Frac> = Self::from_const(consts::FRAC_1_TAU);
52
53                /// 2/τ = 0.318309…
54                pub const FRAC_2_TAU: $Self<Frac> = Self::from_const(consts::FRAC_2_TAU);
55
56                /// π/8 = 0.392699…
57                pub const FRAC_PI_8: $Self<Frac> = Self::from_const(consts::FRAC_PI_8);
58
59                /// 1/π = 0.318309…
60                pub const FRAC_1_PI: $Self<Frac> = Self::from_const(consts::FRAC_1_PI);
61
62                /// 1/√2π = 0.398942…
63                pub const FRAC_1_SQRT_2PI: $Self<Frac> = Self::from_const(consts::FRAC_1_SQRT_2PI);
64
65                /// log<sub>10</sub> 2 = 0.301029…
66                pub const LOG10_2: $Self<Frac> = Self::from_const(consts::LOG10_2);
67
68                /// log<sub>10</sub> e = 0.434294…
69                pub const LOG10_E: $Self<Frac> = Self::from_const(consts::LOG10_E);
70            }
71        }
72
73        comment! {
74            "This block contains constants in the range 0.5&nbsp;≤&nbsp;<i>x</i>&nbsp;<&nbsp;1",
75            if_signed_else_empty_str! {
76                $Signedness;
77                ", and &minus;1.
78
79These constants are not representable in signed fixed-point numbers with less
80than 1 integer bit"
81            },
82            ".
83
84# Examples
85
86```rust
87use fixed::consts;
88use fixed::types::extra::U",
89            if_signed_unsigned!($Signedness, $nm1, $n),
90            ";
91use fixed::", stringify!($Self), ";
92type Fix = ", stringify!($Self), "<U",
93            if_signed_unsigned!($Signedness, $nm1, $n),
94            ">;
95assert_eq!(Fix::LN_2, Fix::from_num(consts::LN_2));
96assert!(0.5 <= Fix::LN_2 && Fix::LN_2 < 1);
97```
98",
99            if_signed_else_empty_str! {
100                $Signedness;
101                "
102The following example fails to compile, since the maximum
103representable value with ", $n, " fractional bits and 0 integer
104bits is <&nbsp;0.5.
105
106```rust,compile_fail
107use fixed::consts;
108use fixed::types::extra::U", $n, ";
109use fixed::", stringify!($Self), ";
110type Fix = ", stringify!($Self), "<U", $n, ">;
111let _ = Fix::LN_2;
112```
113"
114            };
115            impl<Frac: Unsigned> $Self<Frac>
116            where
117                Frac: IsLessOrEqual<$LeEqUC0, Output = True>,
118            {
119                if_signed! {
120                    $Signedness;
121                    comment! {
122                        "Negative one.
123
124# Examples
125
126```rust
127use fixed::types::extra::U", $nm1, ";
128use fixed::", stringify!($Self), ";
129type Fix = ", stringify!($Self), "<U", $nm1, ">;
130assert_eq!(Fix::NEG_ONE, Fix::from_num(-1));
131```
132
133The following would fail as
134<code>[", stringify!($Self), "]&lt;[U", $nm1, "]></code>
135cannot represent 1, so there is no
136<code>[", stringify!($Self), "]::&lt;[U", $nm1, "]>::[ONE]</code>.
137
138[ONE]: ", stringify!($Self), "::ONE
139
140```rust,compile_fail
141use fixed::types::extra::U", $nm1, ";
142use fixed::", stringify!($Self), ";
143const _ERROR: ", stringify!($Self), "<U", $nm1, "> = ", stringify!($Self), "::ONE.unwrapped_neg();
144```
145";
146                        pub const NEG_ONE: $Self<Frac> = Self::from_bits(-1 << Frac::U32);
147                    }
148                }
149
150                /// τ/8 = 0.785398…
151                pub const FRAC_TAU_8: $Self<Frac> = Self::from_const(consts::FRAC_TAU_8);
152
153                /// τ/12 = 0.523598…
154                pub const FRAC_TAU_12: $Self<Frac> = Self::from_const(consts::FRAC_TAU_12);
155
156                /// 4/τ = 0.636619…
157                pub const FRAC_4_TAU: $Self<Frac> = Self::from_const(consts::FRAC_4_TAU);
158
159                /// π/4 = 0.785398…
160                pub const FRAC_PI_4: $Self<Frac> = Self::from_const(consts::FRAC_PI_4);
161
162                /// π/6 = 0.523598…
163                pub const FRAC_PI_6: $Self<Frac> = Self::from_const(consts::FRAC_PI_6);
164
165                /// 2/π = 0.636619…
166                pub const FRAC_2_PI: $Self<Frac> = Self::from_const(consts::FRAC_2_PI);
167
168                /// 1/√π = 0.564189…
169                pub const FRAC_1_SQRT_PI: $Self<Frac> = Self::from_const(consts::FRAC_1_SQRT_PI);
170
171                /// 1/√2 = 0.707106…
172                pub const FRAC_1_SQRT_2: $Self<Frac> = Self::from_const(consts::FRAC_1_SQRT_2);
173
174                /// 1/√3 = 0.577350…
175                pub const FRAC_1_SQRT_3: $Self<Frac> = Self::from_const(consts::FRAC_1_SQRT_3);
176
177                /// ln 2 = 0.693147…
178                pub const LN_2: $Self<Frac> = Self::from_const(consts::LN_2);
179
180                /// The golden ratio conjugate, Φ = 1/φ = 0.618033…
181                pub const FRAC_1_PHI: $Self<Frac> = Self::from_const(consts::FRAC_1_PHI);
182
183                /// The Euler-Mascheroni constant, γ = 0.577215…
184                pub const GAMMA: $Self<Frac> = Self::from_const(consts::GAMMA);
185
186                /// Catalan’s constant = 0.915965…
187                pub const CATALAN: $Self<Frac> = Self::from_const(consts::CATALAN);
188            }
189        }
190
191        comment! {
192            "This block contains constants in the range 1&nbsp;≤&nbsp;<i>x</i>&nbsp;<&nbsp;2.
193
194These constants are not representable in ",
195            if_signed_unsigned!($Signedness, "signed", "unsigned"),
196            " fixed-point numbers with less than ",
197            if_signed_unsigned!($Signedness, "2 integer bits", "1 integer bit"),
198            ".
199
200# Examples
201
202```rust
203use fixed::consts;
204use fixed::types::extra::U",
205            if_signed_unsigned!($Signedness, $nm2, $nm1),
206            ";
207use fixed::", stringify!($Self), ";
208type Fix = ", stringify!($Self), "<U",
209            if_signed_unsigned!($Signedness, $nm2, $nm1),
210            ">;
211assert_eq!(Fix::LOG2_E, Fix::from_num(consts::LOG2_E));
212assert!(1 <= Fix::LOG2_E && Fix::LOG2_E < 2);
213```
214
215The following example fails to compile, since the maximum
216representable value with ",
217            if_signed_unsigned!($Signedness, $nm1, $n),
218            " fractional bits and ",
219            if_signed_unsigned!($Signedness, "1 integer bit", "0 integer bits"),
220            " is <&nbsp;1.
221
222```rust,compile_fail
223use fixed::consts;
224use fixed::types::extra::U",
225            if_signed_unsigned!($Signedness, $nm1, $n),
226            ";
227use fixed::", stringify!($Self), ";
228type Fix = ", stringify!($Self), "<U",
229            if_signed_unsigned!($Signedness, $nm1, $n),
230            ">;
231let _ = Fix::LOG2_E;
232```
233";
234            impl<Frac: Unsigned> $Self<Frac>
235            where
236                Frac: IsLessOrEqual<$LeEqUC1, Output = True>,
237            {
238                comment! {
239                    "One.
240
241# Examples
242
243```rust
244use fixed::types::extra::U4;
245use fixed::", stringify!($Self), ";
246type Fix = ", stringify!($Self), "<U4>;
247assert_eq!(Fix::ONE, Fix::from_num(1));
248```
249";
250                    pub const ONE: $Self<Frac> = Self::from_bits(1 << Frac::U32);
251                }
252
253                /// τ/4 = 1.57079…
254                pub const FRAC_TAU_4: $Self<Frac> = Self::from_const(consts::FRAC_TAU_4);
255
256                /// τ/6 = 1.04719…
257                pub const FRAC_TAU_6: $Self<Frac> = Self::from_const(consts::FRAC_TAU_6);
258
259                /// π/2 = 1.57079…
260                pub const FRAC_PI_2: $Self<Frac> = Self::from_const(consts::FRAC_PI_2);
261
262                /// π/3 = 1.04719…
263                pub const FRAC_PI_3: $Self<Frac> = Self::from_const(consts::FRAC_PI_3);
264
265                /// √π = 1.77245…
266                pub const SQRT_PI: $Self<Frac> = Self::from_const(consts::SQRT_PI);
267
268                /// 2/√π = 1.12837…
269                pub const FRAC_2_SQRT_PI: $Self<Frac> = Self::from_const(consts::FRAC_2_SQRT_PI);
270
271                /// √2 = 1.41421…
272                pub const SQRT_2: $Self<Frac> = Self::from_const(consts::SQRT_2);
273
274                /// √3 = 1.73205…
275                pub const SQRT_3: $Self<Frac> = Self::from_const(consts::SQRT_3);
276
277                /// √e = 1.64872…
278                pub const SQRT_E: $Self<Frac> = Self::from_const(consts::SQRT_E);
279
280                /// log<sub>2</sub> e = 1.44269…
281                pub const LOG2_E: $Self<Frac> = Self::from_const(consts::LOG2_E);
282
283                /// The golden ratio, φ = 1.61803…
284                pub const PHI: $Self<Frac> = Self::from_const(consts::PHI);
285
286                /// √φ = 1.27201…
287                pub const SQRT_PHI: $Self<Frac> = Self::from_const(consts::SQRT_PHI);
288            }
289        }
290
291        comment! {
292            "This block contains constants in the range 2&nbsp;≤&nbsp;<i>x</i>&nbsp;<&nbsp;4.
293
294These constants are not representable in ",
295            if_signed_unsigned!($Signedness, "signed", "unsigned"),
296            " fixed-point numbers with less than ",
297            if_signed_unsigned!($Signedness, 3, 2),
298            " integer bits.
299
300# Examples
301
302```rust
303use fixed::consts;
304use fixed::types::extra::U",
305            if_signed_unsigned!($Signedness, $nm3, $nm2),
306            ";
307use fixed::", stringify!($Self), ";
308type Fix = ", stringify!($Self), "<U",
309            if_signed_unsigned!($Signedness, $nm3, $nm2),
310            ">;
311assert_eq!(Fix::E, Fix::from_num(consts::E));
312assert!(2 <= Fix::E && Fix::E < 4);
313```
314
315The following example fails to compile, since the maximum
316representable value with ",
317            if_signed_unsigned!($Signedness, $nm2, $nm1),
318            " fractional bits and ",
319            if_signed_unsigned!($Signedness, "2 integer bits", "1 integer bit"),
320            " is <&nbsp;2.
321
322```rust,compile_fail
323use fixed::consts;
324use fixed::types::extra::U",
325            if_signed_unsigned!($Signedness, $nm2, $nm1),
326            ";
327use fixed::", stringify!($Self), ";
328type Fix = ", stringify!($Self), "<U",
329            if_signed_unsigned!($Signedness, $nm2, $nm1),
330            ">;
331let _ = Fix::E;
332```
333";
334            impl<Frac: Unsigned> $Self<Frac>
335            where
336                Frac: IsLessOrEqual<$LeEqUC2, Output = True>,
337            {
338                /// τ/2 = 3.14159…
339                pub const FRAC_TAU_2: $Self<Frac> = Self::from_const(consts::FRAC_TAU_2);
340
341                /// τ/3 = 2.09439…
342                pub const FRAC_TAU_3: $Self<Frac> = Self::from_const(consts::FRAC_TAU_3);
343
344                /// Archimedes’ constant, π = 3.14159…
345                pub const PI: $Self<Frac> = Self::from_const(consts::PI);
346
347                /// √2π = 2.50662…
348                pub const SQRT_2PI: $Self<Frac> = Self::from_const(consts::SQRT_2PI);
349
350                /// Euler’s number, e = 2.71828…
351                pub const E: $Self<Frac> = Self::from_const(consts::E);
352
353                /// log<sub>2</sub> 10 = 3.32192…
354                pub const LOG2_10: $Self<Frac> = Self::from_const(consts::LOG2_10);
355
356                /// ln 10 = 2.30258…
357                pub const LN_10: $Self<Frac> = Self::from_const(consts::LN_10);
358            }
359        }
360
361        comment! {
362            "This block contains constants in the range 4&nbsp;≤&nbsp;<i>x</i>&nbsp;<&nbsp;8.
363
364These constants are not representable in ",
365            if_signed_unsigned!($Signedness, "signed", "unsigned"),
366            " fixed-point numbers with less than ",
367            if_signed_unsigned!($Signedness, 4, 3),
368            " integer bits.
369
370# Examples
371
372```rust
373use fixed::consts;
374use fixed::types::extra::U",
375            if_signed_unsigned!($Signedness, $nm4, $nm3),
376            ";
377use fixed::", stringify!($Self), ";
378type Fix = ", stringify!($Self), "<U",
379            if_signed_unsigned!($Signedness, $nm4, $nm3),
380            ">;
381assert_eq!(Fix::TAU, Fix::from_num(consts::TAU));
382assert!(4 <= Fix::TAU && Fix::TAU < 8);
383```
384
385The following example fails to compile, since the maximum
386representable value with ",
387            if_signed_unsigned!($Signedness, $nm3, $nm2),
388            " fractional bits and ",
389            if_signed_unsigned!($Signedness, 3, 2),
390            " integer bits is <&nbsp;4.
391
392```rust,compile_fail
393use fixed::consts;
394use fixed::types::extra::U",
395            if_signed_unsigned!($Signedness, $nm3, $nm2),
396            ";
397use fixed::", stringify!($Self), ";
398type Fix = ", stringify!($Self), "<U",
399            if_signed_unsigned!($Signedness, $nm3, $nm2),
400            ">;
401let _ = Fix::TAU;
402```
403";
404            impl<Frac: Unsigned> $Self<Frac>
405            where
406                Frac: IsLessOrEqual<$LeEqUC3, Output = True>,
407            {
408                /// A turn, τ = 6.28318…
409                pub const TAU: $Self<Frac> = Self::from_const(consts::TAU);
410            }
411        }
412    };
413}