GCC Code Coverage Report


Directory: include/polyfloat/
File: include/polyfloat/module/core/fma.hpp
Date: 2026-11-09 15:28:50
Exec Total Coverage
Lines: 26 26 100.0%
Functions: 141 141 100.0%
Branches: 0 0 -%

Line Branch Exec Source
1 //======================================================================================================================
2 /*
3 POLYFLOAT - Extended precision floating points
4 Copyright : POLYFLOAT Contributors & Maintainers
5 SPDX-License-Identifier: BSL-1.0
6 */
7 //======================================================================================================================
8 #pragma once
9
10 #include <polyfloat/details/callable.hpp>
11 #include <polyfloat/types/concepts.hpp>
12 #include <polyfloat/types/traits.hpp>
13 #include <type_traits>
14 #include <polyfloat/module/core/three_fma.hpp>
15 #include <polyfloat/details/graillat.hpp>
16
17 namespace plf
18 {
19
20 template<typename Options> struct fma_t : eve::strict_tuple_callable<fma_t, Options, raw_option, pedantic_option>
21 {
22 template<typename... Ts> struct result : as_polyfloat_like<Ts...>
23 {
24 };
25
26 template<concepts::polyfloat_like Z0, concepts::polyfloat_like Z1, concepts::polyfloat_like Z2>
27 36912 POLYFLOAT_ABI typename result<Z0, Z1, Z2>::type constexpr operator()(Z0 z0, Z1 z1, Z2 z2) const noexcept
28 {
29 36912 return POLYFLOAT_CALL(z0, z1, z2);
30 }
31
32 34392 POLYFLOAT_CALLABLE_OBJECT(fma_t, fma_);
33 };
34 //======================================================================================================================
35 //! @addtogroup core
36 //! @{
37 //! @var fma
38 //! @brief return the fused multiply add of the parameters.
39 //!
40 //! @groupheader{Header file}
41 //!
42 //! @code
43 //! #include <polyfloat/core.hpp>
44 //! @endcode
45 //!
46 //! @groupheader{Callable Signatures}
47 //!
48 //! @code
49 //! namespace polyfloat
50 //! {
51 //! template<polyfloat::concepts::polyfloat_like Z1, polyfloat_like Z2, polyfloat_like Z3> constexpr auto fma(Z1 z1, Z2 z2, Z3 z3) noexcept;
52 //! }
53 //! @endcode
54 //!
55 //! **Parameters**
56 //!
57 //! * `z1`, `z2`, `z3`: Values to process.
58 //!
59 //! **Return value**
60 //!
61 //! Returns the fused multiply add of the arguments.
62 //!
63 //! @note contrarily to `eve::fma`, `plf::fma` garanties the correct fused multiply add rounding behaviour, even if it has to be emulated.
64 //!
65 //! @groupheader{Example}
66 //!
67 //! @godbolt_todo{doc/core/fma.cpp}
68 //======================================================================================================================
69
70 inline constexpr auto fma = eve::functor<fma_t>;
71 //======================================================================================================================
72 //! @}
73 //======================================================================================================================
74 }
75
76 namespace plf::_
77 {
78 template<typename Z1, typename Z2, typename Z3, eve::callable_options O>
79 34392 constexpr auto fma_(POLYFLOAT_DELAY(), O const&, Z1 const& x, Z2 const& y, Z3 const& z) noexcept
80 {
81 using r_t = as_polyfloat_t<Z1, Z2, Z3>;
82 46 if constexpr (dimension_v<r_t> == 1) return eve::fma[pedantic](x, y, z);
83 else if constexpr ((dimension_v<Z1> > 2) || (dimension_v<Z2> > 2) || (dimension_v<Z3> > 2))
84 {
85 21114 auto cvt = [](auto a) { return r_t(plf::convert(a, eve::as<eve::element_type_t<r_t>>())); };
86
87 27624 auto [xh, xl] = dekker_prod(cvt(x), cvt(y));
88 14076 return plf::_::cr_dw_fp_add(xl, xh, cvt(z));
89 }
90 else if constexpr ((dimension_v<Z1> == 2) && (dimension_v<Z2> == 2) && (dimension_v<Z3> == 2))
91 {
92 20262 auto [xhi, xlo] = x;
93 20262 auto [yhi, ylo] = y;
94 20262 auto [zhi, zlo] = z;
95 39704 auto [chi, c1] = eve::two_prod(xhi, yhi);
96 20262 auto t0 = xlo * ylo;
97 20262 auto t1 = eve::fma(xhi, ylo, t0);
98 20262 auto c2 = eve::fma(xlo, yhi, t1);
99 20262 auto c3 = c1 + c2;
100 39704 auto [dhi, dlo] = eve::two_add[eve::raw](chi, c3);
101
102 39704 auto [shi, slo] = eve::two_add(zhi, dhi);
103 39704 auto [thi, tlo] = eve::two_add(zlo, dlo);
104 20262 auto c = slo + thi;
105 39704 auto [vhi, vlo] = eve::two_add[eve::raw](shi, c);
106 20262 auto w = tlo + vlo;
107 39704 auto [hi, lo] = eve::two_add[eve::raw](vhi, w);
108 20262 return r_t(hi, lo);
109 }
110 else if constexpr ((dimension_v<Z1> == 1) && (dimension_v<Z2> == 1))
111 {
112 auto [zhi, zlo] = z;
113 auto [chi, c1] = eve::two_prod(x, y);
114 auto [shi, slo] = eve::two_add(zhi, chi);
115 auto [thi, tlo] = eve::two_add(zlo, c1);
116 auto c = slo + thi;
117 auto [vhi, vlo] = eve::two_add[eve::raw](shi, c);
118 auto w = tlo + vlo;
119 auto [hi, lo] = eve::two_add[eve::raw](vhi, w);
120 return r_t(hi, lo);
121 }
122 else
123 {
124 using r_t = as_polyfloat_t<Z1, Z2, Z3>;
125 12 auto cvt = [](auto a) { return plf::convert(a, eve::as<eve::element_type_t<r_t>>()); };
126 8 return fma(cvt(x), cvt(y), cvt(z));
127 }
128 }
129 }
130