Skip to content

Commit 06c148c

Browse files
committed
Optimize signed multiplication and division.
1 parent e98b29a commit 06c148c

8 files changed

Lines changed: 144 additions & 55 deletions

File tree

include/slimcpplib/long_fixdiv.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
////////////////////////////////////////////////////////////////////////////////////////////////////
22
//
33
// Simple Long Integer Math for C++
4-
// version 1.0
4+
// version 1.3
55
//
66
////////////////////////////////////////////////////////////////////////////////////////////////////
77
//
@@ -82,7 +82,7 @@ class long_fixed_divider
8282
template<typename type_t>
8383
constexpr long_fixed_divider<type_t> make_fixed_divider(const type_t value) noexcept;
8484
template<typename type_t>
85-
constexpr type_t operator/(const type_t& dividend, const long_fixed_divider<type_t>& divider) noexcept;
85+
constexpr type_t operator/(type_t dividend, const long_fixed_divider<type_t>& divider) noexcept;
8686

8787

8888

@@ -204,7 +204,7 @@ constexpr long_fixed_divider<type_t> make_fixed_divider(const type_t value) noex
204204

205205
////////////////////////////////////////////////////////////////////////////////////////////////////
206206
template<typename type_t>
207-
constexpr type_t operator/(const type_t& dividend, const long_fixed_divider<type_t>& divider) noexcept
207+
constexpr type_t operator/(type_t dividend, const long_fixed_divider<type_t>& divider) noexcept
208208
{
209209
return divider.divide(dividend);
210210
}

include/slimcpplib/long_int.h

Lines changed: 24 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
////////////////////////////////////////////////////////////////////////////////////////////////////
22
//
33
// Simple Long Integer Math for C++
4-
// version 1.0
4+
// version 1.3
55
//
66
////////////////////////////////////////////////////////////////////////////////////////////////////
77
//
@@ -118,17 +118,6 @@ inline constexpr bool is_signed_v<long_int_t<native_t, size>> = true;
118118

119119

120120

121-
////////////////////////////////////////////////////////////////////////////////////////////////////
122-
// make_unsigned_t
123-
////////////////////////////////////////////////////////////////////////////////////////////////////
124-
125-
template<typename native_t, uint_t size>
126-
struct make_unsigned<long_int_t<native_t, size>> {
127-
using type = long_uint_t<native_t, size>;
128-
};
129-
130-
131-
132121
////////////////////////////////////////////////////////////////////////////////////////////////////
133122
// standalone methods
134123
////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -217,20 +206,13 @@ constexpr bool long_int_t<native_t, size>::sign() const noexcept
217206
template<typename native_t, uint_t size>
218207
constexpr long_int_t<native_t, size>& long_int_t<native_t, size>::negate() noexcept
219208
{
220-
bool borrow = true;
221-
222-
for (uint_t n = 0; n < std::size(digits); ++n) {
223-
224-
borrow = subb<native_t>(digits[n], 0, borrow);
225-
digits[n] = ~digits[n];
226-
}
209+
slim::negate(digits);
227210

228211
return *this;
229212
}
230213

231214

232215

233-
234216
////////////////////////////////////////////////////////////////////////////////////////////////////
235217
template<typename native_t, uint_t size>
236218
template<uint_t other_size, std::enable_if_t<(other_size < size), int>>
@@ -398,10 +380,7 @@ constexpr long_int_t<native_t, size> long_int_t<native_t, size>::operator-() con
398380
template<typename native_t, uint_t size>
399381
constexpr long_int_t<native_t, size>& long_int_t<native_t, size>::operator*=(const long_int_t& that) noexcept
400382
{
401-
long_uint_t<native_t, size>::operator*=(that.sign() ? -that : that);
402-
403-
if (that.sign())
404-
negate();
383+
long_uint_t<native_t, size>::operator*=(that);
405384

406385
return *this;
407386
}
@@ -421,15 +400,15 @@ constexpr long_int_t<native_t, size> long_int_t<native_t, size>::operator*(const
421400
template<typename native_t, uint_t size>
422401
constexpr long_int_t<native_t, size>& long_int_t<native_t, size>::operator/=(const long_int_t& that) noexcept
423402
{
424-
const long_uint_t<native_t, size> value1 = this->sign() ? -*this : *this;
425-
const long_uint_t<native_t, size> value2 = that.sign() ? -that : that;
403+
const bool sing = sign();
426404

427-
long_uint_t<native_t, size> result = value1 / value2;
405+
if (sing)
406+
negate();
428407

429-
if (this->sign() ^ that.sign())
430-
result = -result;
408+
long_uint_t<native_t, size>::operator/=(that.sign() ? -that : that);
431409

432-
*this = result;
410+
if (sing != that.sign())
411+
negate();
433412

434413
return *this;
435414
}
@@ -449,15 +428,15 @@ constexpr long_int_t<native_t, size> long_int_t<native_t, size>::operator/(const
449428
template<typename native_t, uint_t size>
450429
constexpr long_int_t<native_t, size>& long_int_t<native_t, size>::operator%=(const long_int_t& that) noexcept
451430
{
452-
const long_uint_t<native_t, size> value1 = this->sign() ? -*this : *this;
453-
const long_uint_t<native_t, size> value2 = that.sign() ? -that : that;
431+
const bool sing = sign();
454432

455-
long_uint_t<native_t, size> result = value1 % value2;
433+
if (sing)
434+
negate();
456435

457-
if (this->sign() ^ that.sign())
458-
result = -result;
436+
long_uint_t<native_t, size>::operator%=(that.sign() ? -that : that);
459437

460-
*this = result;
438+
if (sing != that.sign())
439+
negate();
461440

462441
return *this;
463442
}
@@ -538,13 +517,18 @@ template<typename type_t, std::enable_if_t<is_signed_v<type_t>, int>>
538517
constexpr type_t muldiv(const type_t& value, const type_t& multiplier, const type_t& divider) noexcept
539518
{
540519
using unsigned_t = make_unsigned_t<type_t>;
541-
const unsigned_t uvalue = value >= 0 ? value : -value;
542-
const unsigned_t umultiplier = multiplier >= 0 ? multiplier : -multiplier;
543-
const unsigned_t udivider = divider >= 0 ? divider : -divider;
520+
521+
const bool value_sign = sign(value);
522+
const bool multiplier_sign = sign(multiplier);
523+
const bool divider_sign = sign(divider);
524+
525+
const unsigned_t uvalue = value_sign ? -value : value;
526+
const unsigned_t umultiplier = multiplier_sign ? -multiplier : multiplier;
527+
const unsigned_t udivider = divider_sign ? -divider : divider;
544528

545529
type_t result = muldiv<unsigned_t>(uvalue, umultiplier, udivider);
546530

547-
if ((value < 0) ^ (multiplier < 0) ^ (divider < 0))
531+
if (value_sign != multiplier_sign != divider_sign)
548532
result = -result;
549533

550534
return result;

include/slimcpplib/long_io.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
////////////////////////////////////////////////////////////////////////////////////////////////////
22
//
33
// Simple Long Integer Math for C++
4-
// version 1.0
4+
// version 1.3
55
//
66
////////////////////////////////////////////////////////////////////////////////////////////////////
77
//

include/slimcpplib/long_math.h

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
////////////////////////////////////////////////////////////////////////////////////////////////////
22
//
33
// Simple Long Integer Math for C++
4-
// version 1.0
4+
// version 1.3
55
//
66
////////////////////////////////////////////////////////////////////////////////////////////////////
77
//
@@ -102,6 +102,19 @@ using make_unsigned_t = typename make_unsigned<type_t>::type;
102102

103103

104104

105+
////////////////////////////////////////////////////////////////////////////////////////////////////
106+
// make_signed_t
107+
////////////////////////////////////////////////////////////////////////////////////////////////////
108+
109+
template<typename type_t>
110+
struct make_signed {
111+
using type = typename std::make_signed<type_t>::type;
112+
};
113+
template<typename type_t>
114+
using make_signed_t = typename make_signed<type_t>::type;
115+
116+
117+
105118
////////////////////////////////////////////////////////////////////////////////////////////////////
106119
// half_t
107120
////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -141,6 +154,11 @@ constexpr type_t half_hi(type_t value) noexcept;
141154
template<typename type_t, std::enable_if_t<is_unsigned_v<type_t>, int> = 0>
142155
constexpr type_t half_make_hi(type_t value) noexcept;
143156

157+
// return most significant bit
158+
159+
template<typename type_t, std::enable_if_t<is_unsigned_v<type_t> || is_signed_v<type_t>, int> = 0>
160+
constexpr bool sign(type_t value);
161+
144162
// propagate most significant bit to the right
145163

146164
template<typename type_t, uint_t byte_count = byte_count_v<type_t>, std::enable_if_t<is_unsigned_v<type_t>, int> = 0>
@@ -245,6 +263,15 @@ constexpr type_t half_make_hi(type_t value) noexcept
245263

246264

247265

266+
////////////////////////////////////////////////////////////////////////////////////////////////////
267+
template<typename type_t, std::enable_if_t<is_unsigned_v<type_t> || is_signed_v<type_t>, int>>
268+
constexpr bool sign(type_t value)
269+
{
270+
return make_signed_t<type_t>(value) < 0;
271+
}
272+
273+
274+
248275
////////////////////////////////////////////////////////////////////////////////////////////////////
249276
template<typename type_t, uint_t byte_count, std::enable_if_t<is_unsigned_v<type_t>, int>>
250277
constexpr type_t pmsbr(type_t value) noexcept

include/slimcpplib/long_math_gcc.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
////////////////////////////////////////////////////////////////////////////////////////////////////
22
//
33
// Simple Long Integer Math for C++
4-
// version 1.0
4+
// version 1.3
55
//
66
////////////////////////////////////////////////////////////////////////////////////////////////////
77
//

0 commit comments

Comments
 (0)