libfxd 0.2.dev
A fixed-point library for C++.
Loading...
Searching...
No Matches
operators.hpp
Go to the documentation of this file.
1/*
2 * libfxd - a fixed-point library for C++
3 *
4 * Copyright 2023 Daniel K. O.
5 * SPDX-License-Identifier: Apache-2.0
6 */
7
8#ifndef LIBFXD_OPERATORS_HPP
9#define LIBFXD_OPERATORS_HPP
10
11#include <compare>
12#include <concepts>
13#include <ostream>
14#include <istream>
15
16#include "concepts.hpp"
17#include "limits.hpp"
18#include "round-div.hpp"
19#include "round-mul.hpp"
20#include "traits.hpp"
21
22
23
24/*
25 * This file contains the unsafe, but fast, operators.
26 *
27 * They map directly to integer operators, with the same safety provisions as the
28 * underlying integer type:
29 * - signed integers create UB on overflow; so do signed fixed points.
30 * - unsigned integers don't create UB; neither do unsigned fixed points.
31 *
32 * Different compilers offer options that control signed integer overflow, like '-ftrapv'
33 * and '-fwrapv', thus making them defined behavior; these options directly apply to fixed
34 * point overflows.
35 */
36
37
38namespace fxd {
39
40
41 // ---------- //
42 // Assignment //
43 // ---------- //
44
46 template<fixed_point Fxd,
47 std::convertible_to<Fxd> T>
48 constexpr
49 Fxd&
51 T b)
52 noexcept
53 {
54 a.raw_value += Fxd{b}.raw_value;
55 return a;
56 }
57
58
60 template<fixed_point Fxd,
61 std::convertible_to<Fxd> T>
62 constexpr
63 Fxd&
65 T b)
66 noexcept
67 {
68 a.raw_value -= Fxd{b}.raw_value;
69 return a;
70 }
71
72
74 template<fixed_point Fxd,
75 std::convertible_to<Fxd> T>
76 requires (!std::integral<T>)
77 constexpr
78 Fxd&
79 operator *=(Fxd& a,
80 T b)
81 noexcept
82 {
83 return a = zero::mul<Fxd>(a, b);
84 }
85
86
88 template<fixed_point Fxd,
89 std::integral I>
90 constexpr
91 Fxd&
93 I b)
94 noexcept
95 {
96 a.raw_value *= b;
97 return a;
98 }
99
100
102 template<fixed_point Fxd,
103 std::convertible_to<Fxd> T>
104 requires (!std::integral<T>)
105 constexpr
106 Fxd&
107 operator /=(Fxd& a,
108 T b)
109 noexcept
110 {
111 return a = zero::div<Fxd>(a, b);
112 }
113
114
116 template<fixed_point Fxd,
117 std::integral I>
118 constexpr
119 Fxd&
121 I b)
122 noexcept
123 {
124 a.raw_value /= b;
125 return a;
126 }
127
128
129 // ------------------- //
130 // Increment/Decrement //
131 // ------------------- //
132
133
135 template<fixed_point Fxd>
136 constexpr
137 Fxd&
139 noexcept
140 {
141 a += 1;
142 return a;
143 }
144
145
147 template<fixed_point Fxd>
148 constexpr
149 Fxd&
151 noexcept
152 {
153 a -= 1;
154 return a;
155 }
156
157
159 template<fixed_point Fxd>
160 constexpr
161 Fxd
162 operator ++(Fxd& a, int)
163 noexcept
164 {
165 Fxd old = a;
166 ++a;
167 return old;
168 }
169
170
172 template<fixed_point Fxd>
173 constexpr
174 Fxd
175 operator --(Fxd& a, int)
176 noexcept
177 {
178 Fxd old = a;
179 --a;
180 return old;
181 }
182
183
184
185 // ---------- //
186 // Arithmetic //
187 // ---------- //
188
189
191 template<fixed_point Fxd>
192 constexpr
193 Fxd
195 noexcept
196 {
197 return a;
198 }
199
200
202 template<fixed_point Fxd>
203 constexpr
204 Fxd
206 noexcept
207 {
208 return Fxd::from_raw(-a.raw_value);
209 }
210
211
213 template<typename A,
214 typename B>
215 requires (fixed_point<A> || fixed_point<B>)
216 constexpr
217 std::common_type_t<A, B>
218 operator +(A a,
219 B b)
220 noexcept
221 {
222 using Fxd = std::common_type_t<A, B>;
223 return Fxd::from_raw(Fxd{a}.raw_value
224 +
225 Fxd{b}.raw_value);
226 }
227
228
230 template<typename A,
231 typename B>
232 requires (fixed_point<A> || fixed_point<B>)
233 constexpr
234 std::common_type_t<A, B>
235 operator -(A a,
236 B b)
237 noexcept
238 {
239 using Fxd = std::common_type_t<A, B>;
240 return Fxd::from_raw(Fxd{a}.raw_value
241 -
242 Fxd{b}.raw_value);
243 }
244
245
247 template<fixed_point A,
248 fixed_point B>
249 constexpr
250 std::common_type_t<A, B>
252 B b)
253 noexcept
254 {
255 using Fxd = std::common_type_t<A, B>;
256 return zero::mul<Fxd>(a, b);
257 }
258
259
261 template<fixed_point Fxd,
262 std::integral I>
263 constexpr
264 Fxd
266 I b)
267 noexcept
268 {
269 return Fxd::from_raw(a.raw_value * b);
270 }
271
272
274 template<std::integral I,
275 fixed_point Fxd>
276 constexpr
277 Fxd
279 Fxd b) noexcept
280 {
281 return Fxd::from_raw(a * b.raw_value);
282 }
283
284
286 template<fixed_point Fxd,
287 std::floating_point Flt>
288 constexpr
289 Fxd
291 Flt b)
292 noexcept
293 {
294 // TODO: optimize fixed * float
295 return zero::mul<Fxd>(a, b);
296 }
297
298
300 template<std::floating_point Flt,
301 fixed_point Fxd>
302 constexpr
303 Fxd
305 Fxd b)
306 noexcept
307 {
308 // TODO: optimize float * fixed
309 return zero::mul<Fxd>(a, b);
310 }
311
312
313
315 template<fixed_point A,
316 fixed_point B>
317 constexpr
318 std::common_type_t<A, B>
320 B b)
321 noexcept
322 {
323 using Fxd = std::common_type_t<A, B>;
324 return zero::div<Fxd>(a, b);
325 }
326
327
329 template<fixed_point Fxd,
330 std::integral I>
331 constexpr
332 Fxd
334 I b)
335 noexcept
336 {
337 return Fxd::from_raw(a.raw_value / b);
338 }
339
340
342 template<std::integral I,
343 fixed_point Fxd>
344 constexpr
345 Fxd
347 Fxd b)
348 noexcept
349 {
350 return Fxd{a} / b;
351 }
352
353
355 template<fixed_point Fxd,
356 std::floating_point Flt>
357 constexpr
358 Fxd
360 Flt b)
361 noexcept
362 {
363 return zero::div<Fxd>(a, b);
364 }
365
366
368 template<std::floating_point Flt,
369 fixed_point Fxd>
370 constexpr
371 Fxd
373 Fxd b)
374 noexcept
375 {
376 return zero::div<Fxd>(a, b);
377 }
378
379
380 // --- //
381 // I/O //
382 // --- //
383
384
386 template<typename CharT,
387 typename Traits,
388 fixed_point Fxd>
389 std::basic_ostream<CharT, Traits>&
390 operator <<(std::basic_ostream<CharT, Traits>& out,
391 Fxd f)
392 {
393 return out << to_float(f);
394 }
395
396
398 template<typename CharT,
399 typename Traits,
400 fixed_point Fxd>
401 std::basic_istream<CharT, Traits>&
402 operator >>(std::basic_istream<CharT, Traits>& in,
403 Fxd& f)
404 {
405 typename std::numeric_limits<Fxd>::float_type ff;
406 in >> ff;
407 f = ff;
408 return in;
409 }
410
411
412
413}
414
415
416#endif
This is the namespace where the entire library is defined.
Definition: casting.hpp:19
constexpr Fxd operator+(Fxd a) noexcept
Unary +.
Definition: operators.hpp:194
constexpr Fxd & operator-=(Fxd &a, T b) noexcept
In-place subtraction.
Definition: operators.hpp:64
std::basic_istream< CharT, Traits > & operator>>(std::basic_istream< CharT, Traits > &in, Fxd &f)
Input (by converting from a floatiung-point value).
Definition: operators.hpp:402
constexpr Fxd & operator*=(Fxd &a, T b) noexcept
In-place multiplication.
Definition: operators.hpp:79
constexpr std::common_type_t< A, B > operator*(A a, B b) noexcept
Multiply: fxd::fixed * fxd::fixed
Definition: operators.hpp:251
constexpr Fxd operator-(Fxd a) noexcept
Negation.
Definition: operators.hpp:205
std::basic_ostream< CharT, Traits > & operator<<(std::basic_ostream< CharT, Traits > &out, Fxd f)
Output (by converting to a floating-point value).
Definition: operators.hpp:390
constexpr Fxd & operator++(Fxd &a) noexcept
Pre-increment.
Definition: operators.hpp:138
constexpr Fxd & operator--(Fxd &a) noexcept
Pre-decrement.
Definition: operators.hpp:150
constexpr Flt to_float(Fxd f) noexcept
Convert a fixed-point to a floating-point type, rounds to zero.
Definition: conversions.hpp:98
constexpr Fxd & operator+=(Fxd &a, T b) noexcept
In-place addition.
Definition: operators.hpp:50
constexpr Fxd & operator/=(Fxd &a, T b) noexcept
In-place division.
Definition: operators.hpp:107
constexpr std::common_type_t< A, B > operator/(A a, B b) noexcept
Divide: fxd::fixed / fxd::fixed
Definition: operators.hpp:319