libfxd 0.2.dev
A fixed-point library for C++.
Loading...
Searching...
No Matches
round-div.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_ROUND_DIV_HPP
9#define LIBFXD_ROUND_DIV_HPP
10
11#include <csignal>
12
13#include "fixed.hpp"
14
15#include "concepts.hpp"
16
17#include "detail/bias.hpp"
18#include "detail/raw-div.hpp"
19#include "detail/shift.hpp"
20
21
22namespace fxd {
23
25 namespace zero {
26
28 template<fixed_point Fxd>
29 constexpr
30 Fxd
31 div(Fxd a,
32 Fxd b)
33 noexcept
34 {
35 const auto raw_a = a.raw_value;
36 const auto raw_b = b.raw_value;
37 const auto r = detail::raw::div<Fxd::frac_bits>(raw_a, raw_b);
38 if (!r)
39 std::raise(SIGFPE);
40
41 auto [c, expo, rem] = *r;
42
43 // offset used for shifting left
44 const int offset = expo + Fxd::frac_bits;
45
46 // Right-shifting a negative number would round it down, not to zero.
47 if (c < 0 && offset < 0)
48 c += detail::make_bias_for(-offset, c);
49
50 const auto d = detail::shl(c, offset);
51
52 return Fxd::from_raw(d);
53 }
54
55 } // namespace zero
56
57
59 namespace up {
60
62 template<fixed_point Fxd>
63 constexpr
64 Fxd
65 div(Fxd a,
66 Fxd b)
67 noexcept
68 {
69 const auto raw_a = a.raw_value;
70 const auto raw_b = b.raw_value;
71 const auto r = detail::raw::div<Fxd::frac_bits>(raw_a, raw_b);
72 if (!r)
73 std::raise(SIGFPE);
74
75 auto [c, expo, rem] = *r;
76
77 // Note: div() rounds to zero; so we might lose the info about which
78 // side of zero the result was.
79 const bool neg = (a.raw_value < 0) != (b.raw_value < 0);
80
81 // offset used for shifting left
82 const int offset = expo + Fxd::frac_bits;
83
84 // When a/b is positive, it may have been rounded down.
85 if (!neg && rem)
86 ++c;
87
88 // Right-shifting will always round down.
89 if (offset < 0)
90 c += detail::make_bias_for(-offset, c);
91
92 const auto d = detail::shl(c, offset);
93
94 return Fxd::from_raw(d);
95 }
96
97 } // namespace up
98
99
101 namespace down {
102
104 template<fixed_point Fxd>
105 constexpr
106 Fxd
107 div(Fxd a,
108 Fxd b)
109 noexcept
110 {
111 const auto raw_a = a.raw_value;
112 const auto raw_b = b.raw_value;
113 const auto r = detail::raw::div<Fxd::frac_bits>(raw_a, raw_b);
114 if (!r)
115 std::raise(SIGFPE);
116
117 auto [c, expo, rem] = *r;
118
119 const bool neg = (a.raw_value < 0) != (b.raw_value < 0);
120
121 // offset used for shifting left
122 const int offset = expo + Fxd::frac_bits;
123
124 // When a/b is negative, it may have been rounded up.
125 if (neg && rem)
126 --c;
127
128 // Right-shifting always rounds down, so we don't need to bias it.
129
130 const auto d = detail::shl(c, offset);
131
132 return Fxd::from_raw(d);
133 }
134
135 } // namespace down
136
137
138} // namespace fxd
139
140
141#endif
This is the namespace where the entire library is defined.
Definition: casting.hpp:19