libjmmcg  release_579_6_g8cffd
A C++ library containing an eclectic mix of useful, advanced components.
fma.hpp
Go to the documentation of this file.
1 #ifndef LIBJMMCG_CORE_FMA_HPP
2 #define LIBJMMCG_CORE_FMA_HPP
3 /******************************************************************************
4 ** Copyright © 2015 by J.M.McGuiness, coder@hussar.me.uk
5 **
6 ** This library is free software; you can redistribute it and/or
7 ** modify it under the terms of the GNU Lesser General Public
8 ** License as published by the Free Software Foundation; either
9 ** version 2.1 of the License, or (at your option) any later version.
10 **
11 ** This library is distributed in the hope that it will be useful,
12 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
13 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 ** Lesser General Public License for more details.
15 **
16 ** You should have received a copy of the GNU Lesser General Public
17 ** License along with this library; if not, write to the Free Software
18 ** Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
20 
21 #include "config.h"
22 
23 #include <cmath>
24 #include <iostream>
25 
26 namespace jmmcg { namespace LIBJMMCG_VER_NAMESPACE {
27 
28 /// The set of contained classes implements a DSEL that allows one to more naturally make use of the fma() operation using the natural mathematical operators of which std::fma() implements: * and + (or -).
29 namespace fma {
30 
31 namespace private_ {
32 struct dbl_mul;
33 struct dbl_add;
34 struct dbl_sub;
35 struct dbl_mul_add;
36 }
37 
38 /// To use this functionality convert one of the doubles used in the multiply operation to this class. It will then automatically implement the m*x+c into a fused multiply-add operation.
39 /**
40  Commutativity & associativity of the equation is supported, as is nesting and m*x-c.
41 
42  \see std::fma()
43 */
44 struct dbl {
45  const double lhs_;
46 
47  /// Explicitly allow implicit conversions.
48  constexpr dbl(double const l) noexcept(true) FORCE_INLINE;
49  /// Allow nesting of std::fma() operations.
50  dbl(private_::dbl_mul_add const &l) noexcept(true) FORCE_INLINE;
51 
52  constexpr bool operator==(const double r) const noexcept(true) FORCE_INLINE;
53  constexpr bool operator==(const dbl r) const noexcept(true) FORCE_INLINE;
54  constexpr private_::dbl_mul operator*(const double r) const noexcept(true) FORCE_INLINE;
55  constexpr private_::dbl_mul operator*(const dbl r) const noexcept(true) FORCE_INLINE;
56  constexpr private_::dbl_add operator+(const double r) const noexcept(true) FORCE_INLINE;
57  constexpr private_::dbl_sub operator-(const double r) const noexcept(true) FORCE_INLINE;
58 };
59 
60 /**
61  Allow associativity regarding the additions.
62 */
63 constexpr private_::dbl_mul_add
64 operator+(const dbl a, private_::dbl_mul const &d) noexcept(true) FORCE_INLINE;
65 
66 /**
67  Allow associativity regarding the additions.
68 */
69 constexpr private_::dbl_mul_add
70 operator-(const dbl a, private_::dbl_mul const &d) noexcept(true) FORCE_INLINE;
71 
72 /**
73  Allow associativity regarding the multiplies.
74 */
75 constexpr private_::dbl_mul
76 operator*(const double l, dbl const r) noexcept(true) FORCE_INLINE;
77 
78 std::ostream &
79 operator<<(std::ostream &os, dbl const d) noexcept(false) FORCE_INLINE;
80 
81 namespace private_ {
82 
83 struct dbl_mul {
84  const double lhs_;
85  const double rhs_;
86 
87  constexpr dbl_mul(double const &l, double const &r) noexcept(true) FORCE_INLINE;
88 
89  /// Allow sequences of multiplies then the add.
90  constexpr dbl_mul operator*(const double r) const noexcept(true) FORCE_INLINE;
91  constexpr dbl_mul operator*(const dbl r) const noexcept(true) FORCE_INLINE;
92 
93  constexpr dbl_mul_add operator+(const double a) const noexcept(true) FORCE_INLINE;
94  constexpr dbl_mul_add operator+(const dbl a) const noexcept(true) FORCE_INLINE;
95 
96  /// Also admit fused-multiply-subtract.
97  constexpr dbl_mul_add operator-(const double a) const noexcept(true) FORCE_INLINE;
98  constexpr dbl_mul_add operator-(const dbl a) const noexcept(true) FORCE_INLINE;
99 };
100 
101 struct dbl_mul_add {
102  const dbl_mul mul_;
103  const double add_;
104 
105  constexpr dbl_mul_add(dbl_mul const &m, double const a) noexcept(true) FORCE_INLINE;
106  constexpr dbl_mul_add(dbl_add const &a, double const m) noexcept(true) FORCE_INLINE;
107  constexpr dbl_mul_add(dbl_sub const &a, double const m) noexcept(true) FORCE_INLINE;
108 
109  /// Allow implicit conversion back to double to ease use within formulae.
110  operator double () const noexcept(true) FORCE_INLINE;
111 };
112 
113 struct dbl_add {
114  const double lhs_;
115  const double rhs_;
116 
117  constexpr dbl_add(double const l, double const r) noexcept(true) FORCE_INLINE;
118 
119  /// Allow sequences of multiplies then the add.
120 };
121 
122 struct dbl_sub {
123  const double lhs_;
124  const double rhs_;
125 
126  explicit constexpr dbl_sub(double const l, double const r) noexcept(true) FORCE_INLINE;
127 
128  /// Allow sequences of multiplies then the add.
129 };
130 
131 /**
132  Allow associativity regarding the additions.
133 */
134 constexpr dbl_mul_add
135 operator+(const double a, dbl_mul const &m) noexcept(true) FORCE_INLINE;
136 /**
137  Allow associativity regarding the subtractions.
138 */
139 constexpr dbl_mul_add
140 operator-(const double a, dbl_mul const &m) noexcept(true) FORCE_INLINE;
141 
142 double &
143 operator+=(double &a, dbl_mul const &m) noexcept(true) FORCE_INLINE;
144 
145 double &
146 operator-=(double &a, dbl_mul const &m) noexcept(true) FORCE_INLINE;
147 
148 }
149 
150 } } }
151 
152 #include "fma_impl.hpp"
153 
154 #endif