Skip to content

Commit 5babc4c

Browse files
committed
Implement standard stream input/output
- Fix mistyping in '%' operator - Optimize performance - Change internal architecture - Implement <<,>> stream serialization/deserialization
1 parent 650bdc1 commit 5babc4c

7 files changed

Lines changed: 1056 additions & 396 deletions

File tree

include/slimcpplib/long_fixdiv.h

Lines changed: 191 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,191 @@
1+
////////////////////////////////////////////////////////////////////////////////////////////////////
2+
//
3+
// Simple Long Integer Math for C++
4+
// version 1.0
5+
//
6+
////////////////////////////////////////////////////////////////////////////////////////////////////
7+
//
8+
// Licensed under the MIT License <http://opensource.org/licenses/MIT>.
9+
// SPDX-License-Identifier: MIT
10+
//
11+
// Copyright (c) 2020-2021 Yury Kalmykov <y_kalmykov@mail.ru>.
12+
//
13+
// Permission is hereby granted, free of charge, to any person obtaining a copy
14+
// of this software and associated documentation files (the "Software"), to deal
15+
// in the Software without restriction, including without limitation the rights
16+
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
17+
// copies of the Software, and to permit persons to whom the Software is
18+
// furnished to do so, subject to the following conditions:
19+
//
20+
// The above copyright notice and this permission notice shall be included in all
21+
// copies or substantial portions of the Software.
22+
//
23+
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24+
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25+
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
26+
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27+
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
28+
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
29+
// SOFTWARE.
30+
//
31+
////////////////////////////////////////////////////////////////////////////////////////////////////
32+
33+
#pragma once
34+
35+
#include "long_int.h"
36+
#include "long_uint.h"
37+
38+
namespace slim
39+
{
40+
////////////////////////////////////////////////////////////////////////////////////////////////////
41+
// long_fixed_divider class
42+
////////////////////////////////////////////////////////////////////////////////////////////////////
43+
44+
template<typename type_t>
45+
class long_fixed_divider
46+
{
47+
public:
48+
////////////////////////////////////////////////////////////////////////////////////////////////
49+
// construction/destruction
50+
51+
constexpr long_fixed_divider() noexcept = default;
52+
constexpr long_fixed_divider(const long_fixed_divider& that) noexcept = default;
53+
constexpr long_fixed_divider(long_fixed_divider&& that) noexcept = default;
54+
constexpr long_fixed_divider(const type_t& divider) noexcept;
55+
constexpr long_fixed_divider(const type_t& multiplier, const type_t& addition, const type_t& shift) noexcept;
56+
57+
////////////////////////////////////////////////////////////////////////////////////////////////
58+
// public methods
59+
60+
constexpr void swap(long_fixed_divider& that) noexcept;
61+
constexpr long_fixed_divider& operator=(const long_fixed_divider& that) noexcept = default;
62+
constexpr long_fixed_divider& operator=(long_fixed_divider&& that) noexcept = default;
63+
64+
static constexpr long_fixed_divider create(const type_t& divider) noexcept;
65+
constexpr type_t divide(const type_t& dividend) const noexcept;
66+
67+
////////////////////////////////////////////////////////////////////////////////////////////////
68+
// data members
69+
70+
type_t multiplier;
71+
type_t addition;
72+
uint_t shift;
73+
};
74+
75+
76+
77+
////////////////////////////////////////////////////////////////////////////////////////////////////
78+
// standalone methods
79+
////////////////////////////////////////////////////////////////////////////////////////////////////
80+
81+
template <typename type_t>
82+
constexpr long_fixed_divider<type_t> make_fixed_divider(const type_t value) noexcept;
83+
template <typename type_t>
84+
constexpr type_t operator/(const type_t& dividend, const long_fixed_divider<type_t>& divider) noexcept;
85+
86+
87+
88+
////////////////////////////////////////////////////////////////////////////////////////////////////
89+
// long_fixed_divider class
90+
////////////////////////////////////////////////////////////////////////////////////////////////////
91+
92+
////////////////////////////////////////////////////////////////////////////////////////////////////
93+
// construction/destruction
94+
95+
template<typename type_t>
96+
constexpr long_fixed_divider<type_t>::long_fixed_divider(const type_t& divider) noexcept
97+
: long_fixed_divider(create(divider))
98+
{
99+
}
100+
101+
template<typename type_t>
102+
constexpr long_fixed_divider<type_t>::long_fixed_divider(const type_t& multiplier, const type_t& addition, const type_t& shift) noexcept
103+
: multiplier(std::move(multiplier))
104+
, addition(std::move(addition))
105+
, shift(std::move(shift))
106+
{
107+
}
108+
109+
110+
111+
////////////////////////////////////////////////////////////////////////////////////////////////////
112+
// public methods
113+
114+
template<typename type_t>
115+
constexpr long_fixed_divider<type_t> long_fixed_divider<type_t>::create(const type_t& divider) noexcept
116+
{
117+
type_t multiplier = 0;
118+
type_t addition = 0;
119+
uint_t shift = bit_count_v<type_t> - nlz(divider) - 1;
120+
121+
// check if divider is power of 2 or zero
122+
123+
if (divider == 0 || (divider & (divider - 1)) != 0) {
124+
125+
const type_t one = type_t(1) << shift;
126+
std::optional<type_t> reminder = type_t();
127+
multiplier = divr2(one, type_t(0), divider, reminder);
128+
129+
const type_t error = divider - *reminder;
130+
131+
if (error < one)
132+
++multiplier;
133+
else
134+
addition = multiplier;
135+
136+
} else {
137+
138+
if (divider == 1) {
139+
140+
multiplier = ~multiplier;
141+
addition = multiplier;
142+
shift = 0;
143+
144+
} else {
145+
146+
multiplier = type_t(1) << (bit_count_v<type_t> - 1);
147+
--shift;
148+
}
149+
}
150+
151+
return long_fixed_divider(multiplier, addition, shift);
152+
}
153+
154+
155+
156+
////////////////////////////////////////////////////////////////////////////////////////////////////
157+
template<typename type_t>
158+
constexpr type_t long_fixed_divider<type_t>::divide(const type_t& dividend) const noexcept
159+
{
160+
type_t mul_hi = addition;
161+
const type_t mul_lo = mulc(dividend, multiplier, mul_hi);
162+
163+
return mul_hi >> shift;
164+
}
165+
166+
167+
168+
////////////////////////////////////////////////////////////////////////////////////////////////////
169+
// standalone methods
170+
////////////////////////////////////////////////////////////////////////////////////////////////////
171+
172+
template<typename type_t>
173+
constexpr long_fixed_divider<type_t> make_fixed_divider(const type_t value) noexcept
174+
{
175+
return long_fixed_divider<type_t>(value);
176+
}
177+
178+
179+
180+
////////////////////////////////////////////////////////////////////////////////////////////////////
181+
template<typename type_t>
182+
constexpr type_t operator/(const type_t& dividend, const long_fixed_divider<type_t>& divider) noexcept
183+
{
184+
return divider.divide(dividend);
185+
}
186+
187+
} // namespace slim
188+
189+
////////////////////////////////////////////////////////////////////////////////////////////////////
190+
// End of long_fixdiv.h
191+
////////////////////////////////////////////////////////////////////////////////////////////////////

0 commit comments

Comments
 (0)