Phi
floating_point.hpp
1 // This file is heavily inspired by Jonathan Müllers <jonathanmueller.dev@gmail.com> type_safe library https://github.com/foonathan/type_safe
2 // licensed under the MIT license https://github.com/foonathan/type_safe/blob/master/LICENSE
3 // Original file at https://github.com/foonathan/type_safe/blob/master/include/type_safe/floating_point.hpp
4 /* MIT License
5 
6 Copyright (c) 2016-2020 Jonathan Müller
7 
8 Permission is hereby granted, free of charge, to any person obtaining a copy
9 of this software and associated documentation files (the "Software"), to deal
10 in the Software without restriction, including without limitation the rights
11 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 copies of the Software, and to permit persons to whom the Software is
13 furnished to do so, subject to the following conditions:
14 
15 The above copyright notice and this permission notice shall be included in all
16 copies or substantial portions of the Software.
17 
18 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 SOFTWARE.
25 */
26 
27 #ifndef INCG_PHI_CORE_FLOATING_POINT_HPP
28 #define INCG_PHI_CORE_FLOATING_POINT_HPP
29 
30 #include "phi/phi_config.hpp"
31 
32 #if PHI_HAS_EXTENSION_PRAGMA_ONCE()
33 # pragma once
34 #endif
35 
36 #include "phi/algorithm/swap.hpp"
37 #include "phi/compiler_support/constexpr.hpp"
38 #include "phi/compiler_support/inline.hpp"
39 #include "phi/compiler_support/nodiscard.hpp"
40 #include "phi/compiler_support/noexcept.hpp"
41 #include "phi/compiler_support/standard_library.hpp"
42 #include "phi/compiler_support/warning.hpp"
43 #include "phi/core/boolean.hpp"
44 #include "phi/type_traits/conditional.hpp"
45 #include "phi/type_traits/enable_if.hpp"
46 #include "phi/type_traits/integral_constant.hpp"
47 #include "phi/type_traits/is_unsafe_floating_point.hpp"
48 #include <cmath>
49 #include <iosfwd>
50 #include <limits>
51 
52 DETAIL_PHI_BEGIN_NAMESPACE()
53 
54 template <typename FloatT>
56 
58 namespace detail
59 {
60  // Floating point conversion
61  template <typename FromT, typename ToT>
62  struct is_safe_floating_point_conversion
63  : public integral_constant<bool, is_unsafe_floating_point<FromT>::value &&
64  is_unsafe_floating_point<ToT>::value &&
65  sizeof(FromT) <= sizeof(ToT)>
66  {};
67 
68  template <typename FromT, typename ToT>
69  using enable_safe_floating_point_conversion =
70  enable_if_t<is_safe_floating_point_conversion<FromT, ToT>::value>;
71 
72  template <typename FromT, typename ToT>
73  using fallback_safe_floating_point_conversion =
74  enable_if_t<!is_safe_floating_point_conversion<FromT, ToT>::value>;
75 
76  // Floating point comparison
77  template <typename LhsT, typename RhsT>
78  struct is_safe_floating_point_comparison
79  : public integral_constant<bool,
80  is_safe_floating_point_conversion<LhsT, RhsT>::value ||
81  is_safe_floating_point_conversion<RhsT, LhsT>::value>
82  {};
83 
84  template <typename LhsT, typename RhsT>
85  using enable_safe_floating_point_comparison =
86  enable_if_t<is_safe_floating_point_comparison<LhsT, RhsT>::value>;
87 
88  template <typename LhsT, typename RhsT>
89  using fallback_safe_floating_point_comparison =
90  enable_if_t<!is_safe_floating_point_comparison<LhsT, RhsT>::value>;
91 
92  // Floating point operation
93  template <typename LhsT, typename RhsT>
94  struct is_safe_floating_point_operation
95  : public integral_constant<bool, is_unsafe_floating_point<LhsT>::value &&
96  is_unsafe_floating_point<RhsT>::value>
97  {};
98 
99  template <typename LhsT, typename RhsT>
100  using floating_point_result_t =
101  floating_point<enable_if_t<is_safe_floating_point_operation<LhsT, RhsT>::value,
102  conditional_t<sizeof(LhsT) < sizeof(RhsT), RhsT, LhsT>>>;
103 } // namespace detail
105 
106 template <typename FloatT>
107 class floating_point
108 {
109  static_assert(is_unsafe_floating_point<FloatT>::value,
110  "[phi::floating_point] must be a floating point type");
111 
112 public:
113  using this_type = floating_point<FloatT>;
114  using value_type = FloatT;
115  using limits_type = std::numeric_limits<FloatT>;
116 
117  floating_point() = delete;
118 
119  template <typename TypeT,
120  typename = detail::enable_safe_floating_point_conversion<TypeT, FloatT>>
121  PHI_ALWAYS_INLINE PHI_CONSTEXPR floating_point(const TypeT& val) PHI_NOEXCEPT
122  : m_Value(static_cast<FloatT>(val))
123  {}
124 
125  template <typename TypeT,
126  typename = detail::enable_safe_floating_point_conversion<TypeT, FloatT>>
127  PHI_ALWAYS_INLINE PHI_CONSTEXPR floating_point(const floating_point<TypeT>& val) PHI_NOEXCEPT
128  : m_Value(static_cast<FloatT>(static_cast<TypeT>(val)))
129  {}
130 
131  template <typename TypeT,
132  typename = detail::fallback_safe_floating_point_conversion<TypeT, FloatT>>
133  floating_point(TypeT) = delete;
134 
135  //=== assignment ===//
136 
137  template <typename TypeT,
138  typename = detail::enable_safe_floating_point_conversion<TypeT, FloatT>>
139  PHI_ALWAYS_INLINE floating_point& operator=(const TypeT& val) PHI_NOEXCEPT
140  {
141  m_Value = val;
142  return *this;
143  }
144 
145  PHI_CLANG_SUPPRESS_WARNING_WITH_PUSH("-Wdouble-promotion")
146 
147  template <typename TypeT,
148  typename = detail::enable_safe_floating_point_conversion<TypeT, FloatT>>
149  PHI_ALWAYS_INLINE floating_point& operator=(const floating_point<TypeT>& val) PHI_NOEXCEPT
150  {
151  m_Value = static_cast<TypeT>(val);
152  return *this;
153  }
154 
155  PHI_CLANG_SUPPRESS_WARNING_POP()
156 
157  template <typename TypeT,
158  typename = detail::fallback_safe_floating_point_conversion<TypeT, FloatT>>
159  floating_point& operator=(TypeT) = delete;
160 
161  //=== conversion back ===//
162 
163  PHI_ALWAYS_INLINE explicit PHI_CONSTEXPR operator FloatT() const PHI_NOEXCEPT
164  {
165  return m_Value;
166  }
167 
168  PHI_NODISCARD PHI_ALWAYS_INLINE PHI_CONSTEXPR FloatT unsafe() const PHI_NOEXCEPT
169  {
170  return m_Value;
171  }
172 
173  PHI_EXTENDED_CONSTEXPR void swap(floating_point<FloatT>& other) PHI_NOEXCEPT
174  {
175  phi::swap(m_Value, other.m_Value);
176  }
177 
178  //=== unary operators ===//
179 
180  PHI_ALWAYS_INLINE PHI_CONSTEXPR floating_point operator+() const PHI_NOEXCEPT
181  {
182  return *this;
183  }
184 
185  PHI_ALWAYS_INLINE PHI_CONSTEXPR floating_point operator-() const PHI_NOEXCEPT
186  {
187  return -m_Value;
188  }
189 
190  //=== compound assignment ====//
191 
192  template <typename TypeT,
193  typename = detail::enable_safe_floating_point_conversion<TypeT, FloatT>>
194  PHI_ALWAYS_INLINE floating_point& operator+=(const floating_point<TypeT>& other) PHI_NOEXCEPT
195  {
196  m_Value += static_cast<TypeT>(other);
197  return *this;
198  }
199 
200  template <typename TypeT,
201  typename = detail::enable_safe_floating_point_conversion<TypeT, FloatT>>
202  PHI_ALWAYS_INLINE floating_point& operator+=(const TypeT& other) PHI_NOEXCEPT
203  {
204  return *this += floating_point<TypeT>(other);
205  }
206 
207  template <typename TypeT,
208  typename = detail::fallback_safe_floating_point_conversion<TypeT, FloatT>>
209  floating_point& operator+=(floating_point<TypeT>) = delete;
210 
211  template <typename TypeT,
212  typename = detail::fallback_safe_floating_point_conversion<TypeT, FloatT>>
213  floating_point& operator+=(TypeT) = delete;
214 
215  template <typename TypeT,
216  typename = detail::enable_safe_floating_point_conversion<TypeT, FloatT>>
217  PHI_ALWAYS_INLINE floating_point& operator-=(const floating_point<TypeT>& other) PHI_NOEXCEPT
218  {
219  m_Value -= static_cast<TypeT>(other);
220  return *this;
221  }
222 
223  template <typename TypeT,
224  typename = detail::enable_safe_floating_point_conversion<TypeT, FloatT>>
225  PHI_ALWAYS_INLINE floating_point& operator-=(const TypeT& other) PHI_NOEXCEPT
226  {
227  return *this -= floating_point<TypeT>(other);
228  }
229 
230  template <typename TypeT,
231  typename = detail::fallback_safe_floating_point_conversion<TypeT, FloatT>>
232  floating_point& operator-=(floating_point<TypeT>) = delete;
233 
234  template <typename TypeT,
235  typename = detail::fallback_safe_floating_point_conversion<TypeT, FloatT>>
236  floating_point& operator-=(TypeT) = delete;
237 
238  template <typename TypeT,
239  typename = detail::enable_safe_floating_point_conversion<TypeT, FloatT>>
240  PHI_ALWAYS_INLINE floating_point& operator*=(const floating_point<TypeT>& other) PHI_NOEXCEPT
241  {
242  m_Value *= static_cast<TypeT>(other);
243  return *this;
244  }
245 
246  template <typename TypeT,
247  typename = detail::enable_safe_floating_point_conversion<TypeT, FloatT>>
248  PHI_ALWAYS_INLINE floating_point& operator*=(const TypeT& other) PHI_NOEXCEPT
249  {
250  return *this *= floating_point<TypeT>(other);
251  }
252 
253  template <typename TypeT,
254  typename = detail::fallback_safe_floating_point_conversion<TypeT, FloatT>>
255  floating_point& operator*=(floating_point<TypeT>) = delete;
256 
257  template <typename TypeT,
258  typename = detail::fallback_safe_floating_point_conversion<TypeT, FloatT>>
259  floating_point& operator*=(TypeT) = delete;
260 
261  template <typename TypeT,
262  typename = detail::enable_safe_floating_point_conversion<TypeT, FloatT>>
263  PHI_ALWAYS_INLINE floating_point& operator/=(const floating_point<TypeT>& other) PHI_NOEXCEPT
264  {
265  m_Value /= static_cast<TypeT>(other);
266  return *this;
267  }
268 
269  template <typename TypeT,
270  typename = detail::enable_safe_floating_point_conversion<TypeT, FloatT>>
271  PHI_ALWAYS_INLINE floating_point& operator/=(const TypeT& other) PHI_NOEXCEPT
272  {
273  return *this /= floating_point<TypeT>(other);
274  }
275 
276  template <typename TypeT,
277  typename = detail::fallback_safe_floating_point_conversion<TypeT, FloatT>>
278  floating_point& operator/=(floating_point<TypeT>) = delete;
279 
280  template <typename TypeT,
281  typename = detail::fallback_safe_floating_point_conversion<TypeT, FloatT>>
282  floating_point& operator/=(TypeT) = delete;
283 
284  template <typename TypeT,
285  typename = detail::enable_safe_floating_point_conversion<TypeT, FloatT>>
286  PHI_ALWAYS_INLINE floating_point& operator%=(const floating_point<TypeT>& other) PHI_NOEXCEPT
287  {
288  m_Value = std::fmod(m_Value, static_cast<TypeT>(other));
289  return *this;
290  }
291 
292  template <typename TypeT,
293  typename = detail::enable_safe_floating_point_conversion<TypeT, FloatT>>
294  PHI_ALWAYS_INLINE floating_point& operator%=(const TypeT& other) PHI_NOEXCEPT
295  {
296  return *this %= floating_point<TypeT>(other);
297  }
298 
299  template <typename TypeT,
300  typename = detail::fallback_safe_floating_point_conversion<TypeT, FloatT>>
301  floating_point& operator%=(floating_point<TypeT>) = delete;
302 
303  template <typename TypeT,
304  typename = detail::fallback_safe_floating_point_conversion<TypeT, FloatT>>
305  floating_point& operator%=(TypeT) = delete;
306 
307 private:
308  FloatT m_Value;
309 };
310 
311 //=== comparison ===//
312 
313 template <typename LhsT, typename RhsT,
314  typename = detail::enable_safe_floating_point_comparison<LhsT, RhsT>>
315 PHI_ALWAYS_INLINE PHI_CONSTEXPR boolean operator<(const floating_point<LhsT>& lhs,
316  const floating_point<RhsT>& rhs) PHI_NOEXCEPT
317 {
318  return static_cast<LhsT>(lhs) < static_cast<RhsT>(rhs);
319 }
320 
321 template <typename LhsT, typename RhsT,
322  typename = detail::enable_safe_floating_point_conversion<LhsT, RhsT>>
323 PHI_ALWAYS_INLINE PHI_CONSTEXPR boolean operator<(const LhsT& lhs,
324  const floating_point<RhsT>& rhs) PHI_NOEXCEPT
325 {
326  return floating_point<LhsT>(lhs) < rhs;
327 }
328 
329 template <typename LhsT, typename RhsT,
330  typename = detail::enable_safe_floating_point_comparison<LhsT, RhsT>>
331 PHI_ALWAYS_INLINE PHI_CONSTEXPR boolean operator<(const floating_point<LhsT>& lhs,
332  const RhsT& rhs) PHI_NOEXCEPT
333 {
334  return lhs < floating_point<RhsT>(rhs);
335 }
336 
337 template <typename LhsT, typename RhsT,
338  typename = detail::fallback_safe_floating_point_comparison<LhsT, RhsT>>
339 PHI_CONSTEXPR boolean operator<(floating_point<LhsT>, floating_point<RhsT>) = delete;
340 
341 template <typename LhsT, typename RhsT,
342  typename = detail::fallback_safe_floating_point_comparison<LhsT, RhsT>>
343 PHI_CONSTEXPR boolean operator<(LhsT, floating_point<RhsT>) = delete;
344 
345 template <typename LhsT, typename RhsT,
346  typename = detail::fallback_safe_floating_point_comparison<LhsT, RhsT>>
347 PHI_CONSTEXPR boolean operator<(floating_point<LhsT>, RhsT) = delete;
348 
349 template <typename LhsT, typename RhsT,
350  typename = detail::enable_safe_floating_point_comparison<LhsT, RhsT>>
351 PHI_ALWAYS_INLINE PHI_CONSTEXPR boolean operator<=(const floating_point<LhsT>& lhs,
352  const floating_point<RhsT>& rhs) PHI_NOEXCEPT
353 {
354  return static_cast<LhsT>(lhs) <= static_cast<RhsT>(rhs);
355 }
356 
357 template <typename LhsT, typename RhsT,
358  typename = detail::enable_safe_floating_point_conversion<LhsT, RhsT>>
359 PHI_ALWAYS_INLINE PHI_CONSTEXPR boolean operator<=(const LhsT& lhs,
360  const floating_point<RhsT>& rhs) PHI_NOEXCEPT
361 {
362  return floating_point<LhsT>(lhs) <= rhs;
363 }
364 
365 template <typename LhsT, typename RhsT,
366  typename = detail::enable_safe_floating_point_comparison<LhsT, RhsT>>
367 PHI_ALWAYS_INLINE PHI_CONSTEXPR boolean operator<=(const floating_point<LhsT>& lhs,
368  const RhsT& rhs) PHI_NOEXCEPT
369 {
370  return lhs <= floating_point<RhsT>(rhs);
371 }
372 
373 template <typename LhsT, typename RhsT,
374  typename = detail::fallback_safe_floating_point_comparison<LhsT, RhsT>>
375 PHI_CONSTEXPR boolean operator<=(floating_point<LhsT>, floating_point<RhsT>) = delete;
376 
377 template <typename LhsT, typename RhsT,
378  typename = detail::fallback_safe_floating_point_comparison<LhsT, RhsT>>
379 PHI_CONSTEXPR boolean operator<=(LhsT, floating_point<RhsT>) = delete;
380 
381 template <typename LhsT, typename RhsT,
382  typename = detail::fallback_safe_floating_point_comparison<LhsT, RhsT>>
383 PHI_CONSTEXPR boolean operator<=(floating_point<LhsT>, RhsT) = delete;
384 
385 PHI_CLANG_SUPPRESS_WARNING_PUSH()
386 PHI_CLANG_SUPPRESS_WARNING("-Wdouble-promotion")
387 
388 template <typename LhsT, typename RhsT,
389  typename = detail::enable_safe_floating_point_comparison<LhsT, RhsT>>
390 PHI_ALWAYS_INLINE PHI_CONSTEXPR boolean operator>(const floating_point<LhsT>& lhs,
391  const floating_point<RhsT>& rhs) PHI_NOEXCEPT
392 {
393  return static_cast<LhsT>(lhs) > static_cast<RhsT>(rhs);
394 }
395 
396 PHI_CLANG_SUPPRESS_WARNING_POP()
397 
398 template <typename LhsT, typename RhsT,
399  typename = detail::enable_safe_floating_point_conversion<LhsT, RhsT>>
400 PHI_ALWAYS_INLINE PHI_CONSTEXPR boolean operator>(const LhsT& lhs,
401  const floating_point<RhsT>& rhs) PHI_NOEXCEPT
402 {
403  return floating_point<LhsT>(lhs) > rhs;
404 }
405 
406 template <typename LhsT, typename RhsT,
407  typename = detail::enable_safe_floating_point_comparison<LhsT, RhsT>>
408 PHI_ALWAYS_INLINE PHI_CONSTEXPR boolean operator>(const floating_point<LhsT>& lhs,
409  const RhsT& rhs) PHI_NOEXCEPT
410 {
411  return lhs > floating_point<RhsT>(rhs);
412 }
413 
414 template <typename LhsT, typename RhsT,
415  typename = detail::fallback_safe_floating_point_comparison<LhsT, RhsT>>
416 PHI_CONSTEXPR boolean operator>(floating_point<LhsT>, floating_point<RhsT>) = delete;
417 
418 template <typename LhsT, typename RhsT,
419  typename = detail::fallback_safe_floating_point_comparison<LhsT, RhsT>>
420 PHI_CONSTEXPR boolean operator>(LhsT, floating_point<RhsT>) = delete;
421 
422 template <typename LhsT, typename RhsT,
423  typename = detail::fallback_safe_floating_point_comparison<LhsT, RhsT>>
424 PHI_CONSTEXPR boolean operator>(floating_point<LhsT>, RhsT) = delete;
425 
426 PHI_GCC_SUPPRESS_WARNING_WITH_PUSH("-Wdouble-promotion")
427 
428 template <typename LhsT, typename RhsT,
429  typename = detail::enable_safe_floating_point_comparison<LhsT, RhsT>>
430 PHI_ALWAYS_INLINE PHI_CONSTEXPR boolean operator>=(const floating_point<LhsT>& lhs,
431  const floating_point<RhsT>& rhs) PHI_NOEXCEPT
432 {
433  return static_cast<LhsT>(lhs) >= static_cast<RhsT>(rhs);
434 }
435 
436 PHI_GCC_SUPPRESS_WARNING_POP()
437 
438 template <typename LhsT, typename RhsT,
439  typename = detail::enable_safe_floating_point_conversion<LhsT, RhsT>>
440 PHI_ALWAYS_INLINE PHI_CONSTEXPR boolean operator>=(const LhsT& lhs,
441  const floating_point<RhsT>& rhs) PHI_NOEXCEPT
442 {
443  return floating_point<LhsT>(lhs) >= rhs;
444 }
445 
446 template <typename LhsT, typename RhsT,
447  typename = detail::enable_safe_floating_point_comparison<LhsT, RhsT>>
448 PHI_ALWAYS_INLINE PHI_CONSTEXPR boolean operator>=(const floating_point<LhsT>& lhs,
449  const RhsT& rhs) PHI_NOEXCEPT
450 {
451  return lhs >= floating_point<RhsT>(rhs);
452 }
453 
454 template <typename LhsT, typename RhsT,
455  typename = detail::fallback_safe_floating_point_comparison<LhsT, RhsT>>
456 PHI_CONSTEXPR boolean operator>=(floating_point<LhsT>, floating_point<RhsT>) = delete;
457 
458 template <typename LhsT, typename RhsT,
459  typename = detail::fallback_safe_floating_point_comparison<LhsT, RhsT>>
460 PHI_CONSTEXPR boolean operator>=(LhsT, floating_point<RhsT>) = delete;
461 
462 template <typename LhsT, typename RhsT,
463  typename = detail::fallback_safe_floating_point_comparison<LhsT, RhsT>>
464 PHI_CONSTEXPR boolean operator>=(floating_point<LhsT>, RhsT) = delete;
465 
466 //=== binary operations ===//
467 
468 template <typename LhsT, typename RhsT>
469 PHI_ALWAYS_INLINE PHI_CONSTEXPR auto operator+(const floating_point<LhsT>& lhs,
470  const floating_point<RhsT>& rhs)
471  PHI_NOEXCEPT->detail::floating_point_result_t<LhsT, RhsT>
472 {
473  return static_cast<LhsT>(lhs) + static_cast<RhsT>(rhs);
474 }
475 
476 template <typename LhsT, typename RhsT>
477 PHI_ALWAYS_INLINE PHI_CONSTEXPR auto operator+(const LhsT& lhs, const floating_point<RhsT>& rhs)
478  PHI_NOEXCEPT->detail::floating_point_result_t<LhsT, RhsT>
479 {
480  return floating_point<LhsT>(lhs) + rhs;
481 }
482 
483 template <typename LhsT, typename RhsT>
484 PHI_ALWAYS_INLINE PHI_CONSTEXPR auto operator+(const floating_point<LhsT>& lhs, const RhsT& rhs)
485  PHI_NOEXCEPT->detail::floating_point_result_t<LhsT, RhsT>
486 {
487  return lhs + floating_point<RhsT>(rhs);
488 }
489 
490 template <typename LhsT, typename RhsT>
491 PHI_ALWAYS_INLINE PHI_CONSTEXPR auto operator-(const floating_point<LhsT>& lhs,
492  const floating_point<RhsT>& rhs)
493  PHI_NOEXCEPT->detail::floating_point_result_t<LhsT, RhsT>
494 {
495  return static_cast<LhsT>(lhs) - static_cast<RhsT>(rhs);
496 }
497 
498 template <typename LhsT, typename RhsT>
499 PHI_ALWAYS_INLINE PHI_CONSTEXPR auto operator-(const LhsT& lhs, const floating_point<RhsT>& rhs)
500  PHI_NOEXCEPT->detail::floating_point_result_t<LhsT, RhsT>
501 {
502  return floating_point<LhsT>(lhs) - rhs;
503 }
504 
505 template <typename LhsT, typename RhsT>
506 PHI_ALWAYS_INLINE PHI_CONSTEXPR auto operator-(const floating_point<LhsT>& lhs, const RhsT& rhs)
507  PHI_NOEXCEPT->detail::floating_point_result_t<LhsT, RhsT>
508 {
509  return lhs - floating_point<RhsT>(rhs);
510 }
511 
512 template <typename LhsT, typename RhsT>
513 PHI_ALWAYS_INLINE PHI_CONSTEXPR auto operator*(const floating_point<LhsT>& lhs,
514  const floating_point<RhsT>& rhs)
515  PHI_NOEXCEPT->detail::floating_point_result_t<LhsT, RhsT>
516 {
517  return static_cast<LhsT>(lhs) * static_cast<RhsT>(rhs);
518 }
519 
520 template <typename LhsT, typename RhsT>
521 PHI_ALWAYS_INLINE PHI_CONSTEXPR auto operator*(const LhsT& lhs, const floating_point<RhsT>& rhs)
522  PHI_NOEXCEPT->detail::floating_point_result_t<LhsT, RhsT>
523 {
524  return floating_point<LhsT>(lhs) * rhs;
525 }
526 
527 template <typename LhsT, typename RhsT>
528 PHI_ALWAYS_INLINE PHI_CONSTEXPR auto operator*(const floating_point<LhsT>& lhs, const RhsT& rhs)
529  PHI_NOEXCEPT->detail::floating_point_result_t<LhsT, RhsT>
530 {
531  return lhs * floating_point<RhsT>(rhs);
532 }
533 
534 template <typename LhsT, typename RhsT>
535 PHI_ALWAYS_INLINE PHI_CONSTEXPR auto operator/(const floating_point<LhsT>& lhs,
536  const floating_point<RhsT>& rhs)
537  PHI_NOEXCEPT->detail::floating_point_result_t<LhsT, RhsT>
538 {
539  return static_cast<LhsT>(lhs) / static_cast<RhsT>(rhs);
540 }
541 
542 template <typename LhsT, typename RhsT>
543 PHI_ALWAYS_INLINE PHI_CONSTEXPR auto operator/(const LhsT& lhs, const floating_point<RhsT>& rhs)
544  PHI_NOEXCEPT->detail::floating_point_result_t<LhsT, RhsT>
545 {
546  return floating_point<LhsT>(lhs) / rhs;
547 }
548 
549 template <typename LhsT, typename RhsT>
550 PHI_ALWAYS_INLINE PHI_CONSTEXPR auto operator/(const floating_point<LhsT>& lhs, const RhsT& rhs)
551  PHI_NOEXCEPT->detail::floating_point_result_t<LhsT, RhsT>
552 {
553  return lhs / floating_point<RhsT>(rhs);
554 }
555 
556 template <typename LhsT, typename RhsT>
557 PHI_ALWAYS_INLINE PHI_CONSTEXPR auto operator%(const floating_point<LhsT>& lhs,
558  const floating_point<RhsT>& rhs)
559  PHI_NOEXCEPT->detail::floating_point_result_t<LhsT, RhsT>
560 {
561  return std::fmod(static_cast<LhsT>(lhs), static_cast<RhsT>(rhs));
562 }
563 
564 template <typename LhsT, typename RhsT>
565 PHI_ALWAYS_INLINE PHI_CONSTEXPR auto operator%(const LhsT& lhs, const floating_point<RhsT>& rhs)
566  PHI_NOEXCEPT->detail::floating_point_result_t<LhsT, RhsT>
567 {
568  return floating_point<LhsT>(lhs) % rhs;
569 }
570 
571 template <typename LhsT, typename RhsT>
572 PHI_ALWAYS_INLINE PHI_CONSTEXPR auto operator%(const floating_point<LhsT>& lhs, const RhsT& rhs)
573  PHI_NOEXCEPT->detail::floating_point_result_t<LhsT, RhsT>
574 {
575  return lhs % floating_point<RhsT>(rhs);
576 }
577 
578 //=== input/output ===/
579 
580 template <typename CharT, class CharTraitsT, typename FloatT>
581 std::basic_istream<CharT, CharTraitsT>& operator>>(std::basic_istream<CharT, CharTraitsT>& stream,
582  floating_point<FloatT>& float_value)
583 {
584  FloatT val{FloatT(0.0)};
585  stream >> val;
586  float_value = val;
587  return stream;
588 }
589 
590 template <typename CharT, class CharTraitsT, typename FloatT>
591 std::basic_ostream<CharT, CharTraitsT>& operator<<(std::basic_ostream<CharT, CharTraitsT>& stream,
592  const floating_point<FloatT>& float_value)
593 {
594  return stream << static_cast<FloatT>(float_value);
595 }
596 
597 template <typename FloatT>
598 PHI_EXTENDED_CONSTEXPR_OR_INLINE void swap(floating_point<FloatT>& lhs,
599  floating_point<FloatT>& rhs) PHI_NOEXCEPT
600 {
601  lhs.swap(rhs);
602 }
603 
604 DETAIL_PHI_END_NAMESPACE()
605 
606 DETAIL_PHI_BEGIN_STD_NAMESPACE()
607 
608 template <typename FloatT>
609 struct hash<phi::floating_point<FloatT>>
610 {
611  phi::size_t operator()(const phi::floating_point<FloatT>& value) const PHI_NOEXCEPT
612  {
613  return std::hash<FloatT>()(static_cast<FloatT>(value));
614  }
615 };
616 
617 template <typename FloatT>
618 struct numeric_limits<phi::floating_point<FloatT>> : std::numeric_limits<FloatT>
619 {};
620 
621 DETAIL_PHI_END_STD_NAMESPACE()
622 
623 #endif // INCG_PHI_CORE_FLOATING_POINT_HPP
Definition: integral_constant.hpp:19
Definition: swap.hpp:23
Definition: floating_point.hpp:55
Definition: hash.hpp:15
Definition: common_type.test.cpp:195