1#![doc = include_str!("../README.md")]
2#![no_std]
3#![cfg_attr(docsrs, feature(doc_cfg))]
4
5use core::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Rem, RemAssign, Sub, SubAssign};
6
7use thermite::vector::ops::{MulAddAssignExt, MulAddExt, Square};
8
9pub mod math;
10mod vector;
11
12pub use crate::vector::RealFloatVector;
13
14pub mod prelude {
25 pub use crate::math::specialized::{ComplexVector, SpecializedComplexMath};
26 pub use crate::math::{ComplexMath, ComplexMathWithPolicy};
27 pub use crate::RealFloatVector;
28 pub use crate::{Complex, RealValue};
29
30 #[cfg(feature = "special")]
31 pub use crate::math::special::{ComplexSpecialMath, ComplexSpecialMathWithPolicy, SpecializedComplexSpecialMath};
32}
33
34pub trait RealValue:
42 Copy
43 + Add<Output = Self>
44 + Sub<Output = Self>
45 + Mul<Output = Self>
46 + Div<Output = Self>
47 + Neg<Output = Self>
48 + MulAddExt<Self, Self, Output = Self>
49{
50 const VAL_ZERO: Self;
52 const VAL_ONE: Self;
54
55 fn val_trunc(self) -> Self;
57}
58
59impl RealValue for f32 {
60 const VAL_ZERO: Self = 0.0;
61 const VAL_ONE: Self = 1.0;
62
63 #[inline(always)]
64 fn val_trunc(self) -> Self {
65 thermite::register::FloatElement::trunc(self)
66 }
67}
68
69impl RealValue for f64 {
70 const VAL_ZERO: Self = 0.0;
71 const VAL_ONE: Self = 1.0;
72
73 #[inline(always)]
74 fn val_trunc(self) -> Self {
75 thermite::register::FloatElement::trunc(self)
76 }
77}
78
79impl<R: thermite::register::FloatRegister> RealValue for thermite::prelude::Vector<R> {
80 const VAL_ZERO: Self = <Self as thermite::prelude::NumericVector>::ZERO;
81 const VAL_ONE: Self = <Self as thermite::prelude::NumericVector>::ONE;
82
83 #[inline(always)]
84 fn val_trunc(self) -> Self {
85 thermite::prelude::FloatVector::trunc(self)
86 }
87}
88
89#[cfg(feature = "dual")]
98impl<V: thermite_dual::DualValue, const N: usize> RealValue for thermite_dual::Dual<V, N> {
99 const VAL_ZERO: Self = Self::ZERO;
100 const VAL_ONE: Self = Self::ONE;
101
102 #[inline(always)]
103 fn val_trunc(self) -> Self {
104 thermite_dual::DualValue::val_trunc(self)
105 }
106}
107
108#[cfg(feature = "compensated")]
118impl<V: thermite_compensated::ScalarValue> RealValue for thermite_compensated::Compensated<V> {
119 const VAL_ZERO: Self = thermite_compensated::Compensated {
120 value: V::SCALAR_ZERO,
121 error: V::SCALAR_ZERO,
122 };
123
124 const VAL_ONE: Self = thermite_compensated::Compensated {
125 value: V::SCALAR_ONE,
126 error: V::SCALAR_ZERO,
127 };
128
129 #[inline(always)]
132 fn val_trunc(self) -> Self {
133 thermite_compensated::Compensated::new(self.value().scalar_trunc())
134 }
135}
136
137#[derive(Debug, Default, Clone, Copy, PartialEq, PartialOrd)]
143#[repr(C)]
144pub struct Complex<V> {
145 pub re: V,
147 pub im: V,
149}
150
151impl<V: RealValue> thermite::const_default::ConstDefault for Complex<V> {
152 const DEFAULT: Self = Self::ZERO;
153}
154
155impl<V: RealValue> Complex<V> {
156 pub const ZERO: Self = Self::new(V::VAL_ZERO, V::VAL_ZERO);
158 pub const ONE: Self = Self::new(V::VAL_ONE, V::VAL_ZERO);
160 pub const I: Self = Self::new(V::VAL_ZERO, V::VAL_ONE);
162
163 #[inline(always)]
165 pub const fn new(re: V, im: V) -> Self {
166 Self { re, im }
167 }
168
169 #[inline(always)]
171 pub const fn real(re: V) -> Self {
172 Self::new(re, V::VAL_ZERO)
173 }
174
175 #[inline(always)]
177 pub const fn imag(im: V) -> Self {
178 Self::new(V::VAL_ZERO, im)
179 }
180
181 #[inline(always)]
183 pub fn conj(self) -> Self {
184 Self::new(self.re, -self.im)
185 }
186
187 #[inline(always)]
192 pub fn norm_sqr(self) -> V {
193 self.re.mul_adde(self.re, self.im * self.im)
194 }
195
196 #[inline(always)]
201 pub fn inv(self) -> Self {
202 self.conj() / self.norm_sqr()
203 }
204}
205
206impl<V: RealValue> Neg for Complex<V> {
209 type Output = Self;
210
211 #[inline(always)]
212 fn neg(self) -> Self {
213 Self::new(-self.re, -self.im)
214 }
215}
216
217impl<V: RealValue> Add for Complex<V> {
218 type Output = Self;
219
220 #[inline(always)]
221 fn add(self, rhs: Self) -> Self {
222 Self::new(self.re + rhs.re, self.im + rhs.im)
223 }
224}
225
226impl<V: RealValue> Sub for Complex<V> {
227 type Output = Self;
228
229 #[inline(always)]
230 fn sub(self, rhs: Self) -> Self {
231 Self::new(self.re - rhs.re, self.im - rhs.im)
232 }
233}
234
235impl<V: RealValue> Mul for Complex<V> {
236 type Output = Self;
237
238 #[inline(always)]
240 fn mul(self, rhs: Self) -> Self {
241 Self::new(
242 self.re.mul_sube(rhs.re, self.im * rhs.im),
243 self.re.mul_adde(rhs.im, self.im * rhs.re),
244 )
245 }
246}
247
248impl<V: RealValue> Div for Complex<V> {
249 type Output = Self;
250
251 #[allow(clippy::suspicious_arithmetic_impl)]
254 #[inline(always)]
255 fn div(self, rhs: Self) -> Self {
256 let denom = rhs.re.mul_adde(rhs.re, rhs.im * rhs.im);
257 let inv = V::VAL_ONE / denom;
258
259 Self::new(
260 self.re.mul_adde(rhs.re, self.im * rhs.im) * inv,
261 self.im.mul_sube(rhs.re, self.re * rhs.im) * inv,
262 )
263 }
264}
265
266#[allow(clippy::suspicious_arithmetic_impl)]
269impl<V: RealValue> Rem for Complex<V> {
270 type Output = Self;
271
272 #[inline(always)]
273 fn rem(self, rhs: Self) -> Self {
274 let q = self / rhs;
275 let k = Complex::new(q.re.val_trunc(), q.im.val_trunc());
276
277 k.nmul_adde(rhs, self) }
279}
280
281impl<V: RealValue> Add<V> for Complex<V> {
284 type Output = Self;
285
286 #[inline(always)]
287 fn add(self, rhs: V) -> Self {
288 Self::new(self.re + rhs, self.im)
289 }
290}
291
292impl<V: RealValue> Sub<V> for Complex<V> {
293 type Output = Self;
294
295 #[inline(always)]
296 fn sub(self, rhs: V) -> Self {
297 Self::new(self.re - rhs, self.im)
298 }
299}
300
301impl<V: RealValue> Mul<V> for Complex<V> {
302 type Output = Self;
303
304 #[inline(always)]
305 fn mul(self, rhs: V) -> Self {
306 Self::new(self.re * rhs, self.im * rhs)
307 }
308}
309
310impl<V: RealValue> Div<V> for Complex<V> {
311 type Output = Self;
312
313 #[allow(clippy::suspicious_arithmetic_impl)]
315 #[inline(always)]
316 fn div(self, rhs: V) -> Self {
317 let inv = V::VAL_ONE / rhs;
319
320 Self::new(self.re * inv, self.im * inv)
321 }
322}
323
324#[allow(clippy::suspicious_arithmetic_impl)]
325impl<V: RealValue> Rem<V> for Complex<V> {
326 type Output = Self;
327
328 #[inline(always)]
329 fn rem(self, rhs: V) -> Self {
330 let q = self / rhs;
331 let k = Complex::new(q.re.val_trunc(), q.im.val_trunc());
332
333 k.nmul_adde(Complex::real(rhs), self)
334 }
335}
336
337macro_rules! complex_real_fma {
343 ($($name:ident),* $(,)?) => {
344 $(
345 #[inline(always)]
346 fn $name(self, a: V, b: Self) -> Self {
347 Self::new(self.re.$name(a, b.re), self.im.$name(a, b.im))
348 }
349 )*
350 };
351}
352
353#[rustfmt::skip]
354impl<V: RealValue> MulAddExt<V, Self> for Complex<V> {
355 type Output = Self;
356
357 const HAS_TRUE_FMA: bool = <V as MulAddExt<V, V>>::HAS_TRUE_FMA;
358
359 complex_real_fma!(mul_add, mul_sub, nmul_add, nmul_sub, mul_adde, mul_sube, nmul_adde, nmul_sube);
360}
361
362macro_rules! impl_assign {
365 ($($assign_trait:ident::$assign_method:ident => $op_trait:ident::$op_method:ident),* $(,)?) => {$(
366 impl<V: RealValue, T> $assign_trait<T> for Complex<V>
367 where
368 Self: $op_trait<T, Output = Self>,
369 {
370 #[inline(always)]
371 fn $assign_method(&mut self, rhs: T) {
372 *self = $op_trait::$op_method(*self, rhs);
373 }
374 }
375 )*};
376}
377
378#[rustfmt::skip]
379impl_assign! {
380 AddAssign::add_assign => Add::add,
381 SubAssign::sub_assign => Sub::sub,
382 MulAssign::mul_assign => Mul::mul,
383 DivAssign::div_assign => Div::div,
384 RemAssign::rem_assign => Rem::rem,
385}
386
387macro_rules! complex_mul_add {
401 ($($name:ident => $neg_self:expr, $neg_addend:expr, $fma:ident, $nfma:ident);* $(;)?) => {
402 $(
403 #[inline(always)]
404 fn $name(self, a: Self, b: Self) -> Self {
405 let p = if $neg_self { -self } else { self };
406 let c = if $neg_addend { -b } else { b };
407
408 Self::new(
410 p.im.$nfma(a.im, p.re.$fma(a.re, c.re)),
411 p.re.$fma(a.im, p.im.$fma(a.re, c.im)),
412 )
413 }
414 )*
415 };
416}
417
418#[rustfmt::skip]
419impl<V: RealValue> MulAddExt<Self, Self> for Complex<V> {
420 type Output = Self;
421
422 const HAS_TRUE_FMA: bool = false;
425
426 complex_mul_add! {
427 mul_add => false, false, mul_add, nmul_add;
428 mul_sub => false, true, mul_add, nmul_add;
429 nmul_add => true, false, mul_add, nmul_add;
430 nmul_sub => true, true, mul_add, nmul_add;
431 mul_adde => false, false, mul_adde, nmul_adde;
432 mul_sube => false, true, mul_adde, nmul_adde;
433 nmul_adde => true, false, mul_adde, nmul_adde;
434 nmul_sube => true, true, mul_adde, nmul_adde;
435 }
436}
437
438#[rustfmt::skip]
439impl<V: RealValue, A, B> MulAddAssignExt<A, B> for Complex<V>
440where
441 Self: MulAddExt<A, B, Output = Self>,
442{
443 #[inline(always)] fn mul_add_assign(&mut self, a: A, b: B) { *self = self.mul_add(a, b); }
444 #[inline(always)] fn mul_sub_assign(&mut self, a: A, b: B) { *self = self.mul_sub(a, b); }
445 #[inline(always)] fn nmul_add_assign(&mut self, a: A, b: B) { *self = self.nmul_add(a, b); }
446 #[inline(always)] fn nmul_sub_assign(&mut self, a: A, b: B) { *self = self.nmul_sub(a, b); }
447 #[inline(always)] fn mul_adde_assign(&mut self, a: A, b: B) { *self = self.mul_adde(a, b); }
448 #[inline(always)] fn mul_sube_assign(&mut self, a: A, b: B) { *self = self.mul_sube(a, b); }
449 #[inline(always)] fn nmul_adde_assign(&mut self, a: A, b: B) { *self = self.nmul_adde(a, b); }
450 #[inline(always)] fn nmul_sube_assign(&mut self, a: A, b: B) { *self = self.nmul_sube(a, b); }
451}
452
453impl<V: RealValue> Square for Complex<V> {
454 type Output = Self;
455
456 #[inline(always)]
459 fn square(self) -> Self {
460 Self::new(
461 self.re.mul_sube(self.re, self.im * self.im),
462 (self.re + self.re) * self.im,
463 )
464 }
465}
466
467impl<V: RealValue> core::iter::Sum for Complex<V> {
470 #[inline]
471 fn sum<I: Iterator<Item = Self>>(iter: I) -> Self {
472 iter.fold(Self::ZERO, |a, b| a + b)
473 }
474}
475
476impl<V: RealValue> core::iter::Product for Complex<V> {
477 #[inline]
478 fn product<I: Iterator<Item = Self>>(iter: I) -> Self {
479 iter.fold(Self::ONE, |a, b| a * b)
480 }
481}
482
483macro_rules! impl_float_consts {
486 ($($name:ident),* $(,)?) => {
487 impl<V: RealValue + thermite::math::FloatConsts> thermite::math::FloatConsts for Complex<V> {
488 $(const $name: Self = Self::real(<V as thermite::math::FloatConsts>::$name);)*
489 }
490 };
491}
492
493impl_float_consts!(
494 NEG_ZERO,
495 E,
496 EULER_GAMMA,
497 PI_SQUARED,
498 PI_CUBED,
499 PI_FOURTH,
500 FRAC_1_PI,
501 FRAC_1_SQRT_2,
502 FRAC_1_SQRT_3,
503 FRAC_2_PI,
504 FRAC_1_SQRT_PI,
505 FRAC_2_SQRT_PI,
506 FRAC_SQRT_PI_2,
507 FRAC_1_SQRT_TAU,
508 FRAC_PI_2,
509 FRAC_PI_3,
510 FRAC_PI_4,
511 FRAC_PI_6,
512 FRAC_PI_8,
513 FRAC_PI_180,
514 FRAC_180_PI,
515 LN_2,
516 LN_10,
517 LN_PI,
518 FRAC_LN_PI_2,
519 LOG2_10,
520 LOG2_E,
521 LOG10_2,
522 LOG10_E,
523 PI,
524 SQRT_2,
525 SQRT_3,
526 SQRT_E,
527 EPSILON,
528 SQRT_EPSILON,
529 FOURTH_ROOT_EPSILON,
530 TAU,
531 SQRT_FRAC_PI_2,
532 SQRT_TAU,
533 PHI,
534 FRAC_1_3,
535 FRAC_2_3,
536 FRAC_1_4,
537 FRAC_1_6,
538 FRAC_NEG_1_E
539);