Embedded Template Library 1.0
Loading...
Searching...
No Matches
rounded_integral_division.h
Go to the documentation of this file.
1
2
3/******************************************************************************
4The MIT License(MIT)
5
6Embedded Template Library.
7https://github.com/ETLCPP/etl
8https://www.etlcpp.com
9
10Copyright(c) 2025 John Wellbelove
11
12Permission is hereby granted, free of charge, to any person obtaining numerator
13copy of this software and associated documentation files(the "Software"), to
14deal in the Software without restriction, including without limitation the
15rights to use, copy, modify, merge, publish, distribute, sublicense, and / or
16sell copies of the Software, and to permit persons to whom the Software is
17furnished to do so, subject to the following conditions :
18
19The above copyright notice and this permission notice shall be included in all
20copies or substantial portions of the Software.
21
22THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
23IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
25AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
27OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
28SOFTWARE.
29******************************************************************************/
30
31#ifndef ETL_ROUNDED_INTEGRAL_DIVISION_INCLUDED
32#define ETL_ROUNDED_INTEGRAL_DIVISION_INCLUDED
33
34#include "platform.h"
35#include "absolute.h"
36#include "type_traits.h"
37#include "utility.h"
38
39#if ETL_USING_CPP11
40
41namespace etl
42{
43 namespace private_rounded_integral_division
44 {
45 //*****************************************************************************
46 // Checks if two values have the same sign.
47 // For signed integral types.
48 //*****************************************************************************
49 template <typename T>
50 ETL_CONSTEXPR typename etl::enable_if< etl::is_integral<T>::value && etl::is_signed<T>::value, bool>::type are_same_sign(T a, T b) ETL_NOEXCEPT
51 {
52 return ((a ^ b) >= 0);
53 }
54
55 //*****************************************************************************
56 // Checks if two values have the same sign.
57 // For unsigned integral types.
58 //*****************************************************************************
59 template <typename T>
60 ETL_CONSTEXPR typename etl::enable_if< etl::is_integral<T>::value && etl::is_unsigned<T>::value, bool>::type are_same_sign(T /*a*/, T /*b*/)
61 ETL_NOEXCEPT
62 {
63 return true;
64 }
65 } // namespace private_rounded_integral_division
66
67 //***************************************************************************
74 //***************************************************************************
75 template <typename T>
76 ETL_CONSTEXPR14 typename etl::enable_if< etl::is_integral<T>::value && etl::is_signed<T>::value, T>::type divide_round_to_ceiling(T numerator,
77 T denominator)
78 ETL_NOEXCEPT
79 {
80 const T remainder = numerator % denominator;
81 const T quotient = numerator / denominator;
82
83 // If remainder is zero, already exact
84 if (remainder == 0)
85 {
86 return quotient;
87 }
88
89 // If signs are the same, increment quotient
90 return private_rounded_integral_division::are_same_sign(numerator, denominator) ? quotient + 1 : quotient;
91 }
92
93 //***************************************************************************
101 //***************************************************************************
102 template <typename T1, typename T2>
103 ETL_CONSTEXPR14
104 typename etl::enable_if< etl::is_integral<T1>::value && etl::is_integral<T2>::value && etl::is_signed<T1>::value && etl::is_signed<T2>::value,
105 typename etl::common_type<T1, T2>::type>::type
106 divide_round_to_ceiling(T1 numerator, T2 denominator) ETL_NOEXCEPT
107 {
108 typedef typename etl::common_type<T1, T2>::type type;
109
110 return divide_round_to_ceiling(static_cast<type>(numerator), static_cast<type>(denominator));
111 }
112
113 //***************************************************************************
120 //***************************************************************************
121 template <typename T>
122 ETL_CONSTEXPR14 typename etl::enable_if< etl::is_integral<T>::value && etl::is_unsigned<T>::value, T>::type divide_round_to_ceiling(T numerator,
123 T denominator)
124 ETL_NOEXCEPT
125 {
126 const T remainder = numerator % denominator;
127 const T quotient = numerator / denominator;
128
129 // If remainder is zero, already exact, otherwise, increment quotient
130 return remainder == 0U ? quotient : quotient + 1U;
131 }
132
133 //***************************************************************************
141 //***************************************************************************
142 template <typename T1, typename T2>
143 ETL_CONSTEXPR14
144 typename etl::enable_if< etl::is_integral<T1>::value && etl::is_integral<T2>::value && etl::is_unsigned<T1>::value && etl::is_unsigned<T2>::value,
145 typename etl::common_type<T1, T2>::type>::type
146 divide_round_to_ceiling(T1 numerator, T2 denominator) ETL_NOEXCEPT
147 {
148 typedef typename etl::common_type<T1, T2>::type type;
149
150 return divide_round_to_ceiling(static_cast<type>(numerator), static_cast<type>(denominator));
151 }
152
153 //***************************************************************************
160 //***************************************************************************
161 template <typename T>
162 ETL_CONSTEXPR14 typename etl::enable_if< etl::is_integral<T>::value && etl::is_signed<T>::value, T>::type divide_round_to_floor(T numerator,
163 T denominator)
164 ETL_NOEXCEPT
165 {
166 const T remainder = numerator % denominator;
167 const T quotient = numerator / denominator;
168
169 // If remainder is zero, already exact
170 if (remainder == 0)
171 {
172 return quotient;
173 }
174
175 // If signs are different, decrement quotient
176 return private_rounded_integral_division::are_same_sign(numerator, denominator) ? quotient : quotient - 1;
177 }
178
179 //***************************************************************************
187 //***************************************************************************
188 template <typename T1, typename T2>
189 ETL_CONSTEXPR14
190 typename etl::enable_if< etl::is_integral<T1>::value && etl::is_integral<T2>::value && etl::is_signed<T1>::value && etl::is_signed<T2>::value,
191 typename etl::common_type<T1, T2>::type>::type
192 divide_round_to_floor(T1 numerator, T2 denominator) ETL_NOEXCEPT
193 {
194 typedef typename etl::common_type<T1, T2>::type type;
195
196 return divide_round_to_floor(static_cast<type>(numerator), static_cast<type>(denominator));
197 }
198
199 //***************************************************************************
206 //***************************************************************************
207 template <typename T>
208 ETL_CONSTEXPR14 typename etl::enable_if< etl::is_integral<T>::value && etl::is_unsigned<T>::value, T>::type divide_round_to_floor(T numerator,
209 T denominator)
210 ETL_NOEXCEPT
211 {
212 return numerator / denominator;
213 }
214
215 //***************************************************************************
224 template <typename T1, typename T2>
225 ETL_CONSTEXPR14
226 typename etl::enable_if< etl::is_integral<T1>::value && etl::is_integral<T2>::value && etl::is_unsigned<T1>::value && etl::is_unsigned<T2>::value,
227 typename etl::common_type<T1, T2>::type>::type
228 divide_round_to_floor(T1 numerator, T2 denominator) ETL_NOEXCEPT
229 {
230 typedef typename etl::common_type<T1, T2>::type type;
231
232 const type common_numerator = numerator;
233 const type common_denominator = denominator;
234
235 return common_numerator / common_denominator;
236 }
237
238 //***************************************************************************
245 //***************************************************************************
246 template <typename T>
247 ETL_CONSTEXPR14 typename etl::enable_if< etl::is_integral<T>::value && etl::is_signed<T>::value, T>::type divide_round_to_infinity(T numerator,
248 T denominator)
249 ETL_NOEXCEPT
250 {
251 const T remainder = numerator % denominator;
252 const T quotient = numerator / denominator;
253
254 if (private_rounded_integral_division::are_same_sign(numerator, denominator))
255 {
256 // Same sign, round towards +infinity
257 return (remainder != 0) ? quotient + 1 : quotient;
258 }
259 else
260 {
261 // Different signs, round towards -infinity
262 return (remainder != 0) ? quotient - 1 : quotient;
263 }
264 }
265
266 //***************************************************************************
274 //***************************************************************************
275 template <typename T1, typename T2>
276 ETL_CONSTEXPR14
277 typename etl::enable_if< etl::is_integral<T1>::value && etl::is_integral<T2>::value && etl::is_signed<T1>::value && etl::is_signed<T2>::value,
278 typename etl::common_type<T1, T2>::type>::type
279 divide_round_to_infinity(T1 numerator, T2 denominator) ETL_NOEXCEPT
280 {
281 typedef typename etl::common_type<T1, T2>::type type;
282
283 return divide_round_to_infinity(static_cast<type>(numerator), static_cast<type>(denominator));
284 }
285
286 //***************************************************************************
293 //***************************************************************************
294 template <typename T>
295 ETL_CONSTEXPR14 typename etl::enable_if< etl::is_integral<T>::value && etl::is_unsigned<T>::value, T>::type
296 divide_round_to_infinity(T numerator, T denominator) ETL_NOEXCEPT
297 {
298 const T remainder = numerator % denominator;
299 const T quotient = numerator / denominator;
300
301 return remainder ? quotient + 1U : quotient;
302 }
303
304 //***************************************************************************
312 //***************************************************************************
313 template <typename T1, typename T2>
314 ETL_CONSTEXPR14
315 typename etl::enable_if< etl::is_integral<T1>::value && etl::is_integral<T2>::value && etl::is_unsigned<T1>::value && etl::is_unsigned<T2>::value,
316 typename etl::common_type<T1, T2>::type>::type
317 divide_round_to_infinity(T1 numerator, T2 denominator) ETL_NOEXCEPT
318 {
319 typedef typename etl::common_type<T1, T2>::type type;
320
321 return divide_round_to_infinity(static_cast<type>(numerator), static_cast<type>(denominator));
322 }
323
324 //***************************************************************************
331 //***************************************************************************
332 template <typename T>
333 ETL_CONSTEXPR14 typename etl::enable_if< etl::is_integral<T>::value && etl::is_unsigned<T>::value, T>::type divide_round_to_zero(T numerator,
334 T denominator)
335 ETL_NOEXCEPT
336 {
337 return numerator / denominator;
338 }
339
340 //***************************************************************************
348 //***************************************************************************
349 template <typename T1, typename T2>
350 ETL_CONSTEXPR14 typename etl::enable_if<etl::is_integral<T1>::value && etl::is_integral<T2>::value, typename etl::common_type<T1, T2>::type>::type
351 divide_round_to_zero(T1 numerator, T2 denominator) ETL_NOEXCEPT
352 {
353 typedef typename etl::common_type<T1, T2>::type type;
354
355 // Cast to common type to avoid overflow.
356 const type common_numerator = numerator;
357 const type common_denominator = denominator;
358
359 return common_numerator / common_denominator;
360 }
361
362 //***************************************************************************
369 //***************************************************************************
370 template <typename T>
371 ETL_CONSTEXPR14 typename etl::enable_if< etl::is_integral<T>::value && etl::is_signed<T>::value, T>::type divide_round_half_up(T numerator,
372 T denominator)
373 ETL_NOEXCEPT
374 {
375 // Normal division
376 const T remainder = numerator % denominator;
377 const T quotient = numerator / denominator;
378
379 // Work with magnitudes in unsigned form (avoids abs() overflow)
380 typedef typename etl::make_unsigned<T>::type utype;
381 utype abs_remainder = remainder < 0 ? utype(0) - utype(remainder) : utype(remainder);
382 utype abs_denominator = denominator < 0 ? utype(0) - utype(denominator) : utype(denominator);
383
384 // Threshold for rounding up (half the denominatorominator, rounded up)
385 utype half_denominator = (abs_denominator + 1) / 2;
386
387 if (abs_remainder >= half_denominator)
388 {
389 // Round away from zero
390 if (private_rounded_integral_division::are_same_sign(numerator, denominator))
391 {
392 return quotient + 1; // same sign ? increment
393 }
394 else
395 {
396 return quotient - 1; // different sign ? decrement
397 }
398 }
399
400 return quotient;
401 }
402
403 //***************************************************************************
411 //***************************************************************************
412 template <typename T1, typename T2>
413 ETL_CONSTEXPR14
414 typename etl::enable_if< etl::is_integral<T1>::value && etl::is_integral<T2>::value && etl::is_signed<T1>::value && etl::is_signed<T2>::value,
415 typename etl::common_type<T1, T2>::type>::type
416 divide_round_half_up(T1 numerator, T2 denominator) ETL_NOEXCEPT
417 {
418 typedef typename etl::common_type<T1, T2>::type type;
419
420 return divide_round_half_up(static_cast<type>(numerator), static_cast<type>(denominator));
421 }
422
423 //***************************************************************************
430 //***************************************************************************
431 template <typename T>
432 ETL_CONSTEXPR14 typename etl::enable_if< etl::is_integral<T>::value && etl::is_unsigned<T>::value, T>::type divide_round_half_up(T numerator,
433 T denominator)
434 ETL_NOEXCEPT
435 {
436 const T remainder = numerator % denominator;
437 const T quotient = numerator / denominator;
438
439 // If remainder is at least half the divisor, round up
440 return (remainder >= (denominator / 2U) + (denominator % 2U)) ? quotient + 1U : quotient;
441 }
442
443 //***************************************************************************
451 //***************************************************************************
452 template <typename T1, typename T2>
453 ETL_CONSTEXPR14
454 typename etl::enable_if< etl::is_integral<T1>::value && etl::is_integral<T2>::value && etl::is_unsigned<T1>::value && etl::is_unsigned<T2>::value,
455 typename etl::common_type<T1, T2>::type>::type
456 divide_round_half_up(T1 numerator, T2 denominator) ETL_NOEXCEPT
457 {
458 typedef typename etl::common_type<T1, T2>::type type;
459
460 return divide_round_half_up(static_cast<type>(numerator), static_cast<type>(denominator));
461 }
462
463 //***************************************************************************
470 //***************************************************************************
471 template <typename T>
472 ETL_CONSTEXPR14 typename etl::enable_if< etl::is_integral<T>::value && etl::is_signed<T>::value, T>::type divide_round_half_down(T numerator,
473 T denominator)
474 ETL_NOEXCEPT
475 {
476 const T quotient = numerator / denominator;
477 const T remainder = numerator % denominator;
478
479 typedef typename etl::make_unsigned<T>::type utype;
480 const utype abs_denominator = etl::absolute_unsigned(denominator);
481 const utype abs_remainder = etl::absolute_unsigned(remainder);
482
483 // Direction: +1 if result should be more positive, -1 if more negative
484 const T direction = private_rounded_integral_division::are_same_sign(numerator, denominator) ? 1 : -1;
485
486 // Only round away from zero if remainder is strictly greater than half the
487 // divisor
488 return abs_remainder > (abs_denominator / 2U) ? quotient + direction : quotient;
489 }
490
491 //***************************************************************************
499 //***************************************************************************
500 template <typename T1, typename T2>
501 ETL_CONSTEXPR14
502 typename etl::enable_if< etl::is_integral<T1>::value && etl::is_integral<T2>::value && etl::is_signed<T1>::value && etl::is_signed<T2>::value,
503 typename etl::common_type<T1, T2>::type>::type
504 divide_round_half_down(T1 numerator, T2 denominator) ETL_NOEXCEPT
505 {
506 typedef typename etl::common_type<T1, T2>::type type;
507
508 return divide_round_half_down(static_cast<type>(numerator), static_cast<type>(denominator));
509 }
510
511 //***************************************************************************
518 //***************************************************************************
519 template <typename T>
520 ETL_CONSTEXPR14 typename etl::enable_if< etl::is_integral<T>::value && etl::is_unsigned<T>::value, T>::type divide_round_half_down(T numerator,
521 T denominator)
522 ETL_NOEXCEPT
523 {
524 const T remainder = numerator % denominator;
525 const T quotient = numerator / denominator;
526
527 // If remainder is at least half the divisor, round down
528 return (remainder > (denominator / 2U)) ? quotient + 1U : quotient;
529 }
530
531 //***************************************************************************
539 //***************************************************************************
540 template <typename T1, typename T2>
541 ETL_CONSTEXPR14
542 typename etl::enable_if< etl::is_integral<T1>::value && etl::is_integral<T2>::value && etl::is_unsigned<T1>::value && etl::is_unsigned<T2>::value,
543 typename etl::common_type<T1, T2>::type>::type
544 divide_round_half_down(T1 numerator, T2 denominator) ETL_NOEXCEPT
545 {
546 typedef typename etl::common_type<T1, T2>::type type;
547
548 return divide_round_half_down(static_cast<type>(numerator), static_cast<type>(denominator));
549 }
550
551 //***************************************************************************
558 //***************************************************************************
559 template <typename T>
560 ETL_CONSTEXPR14 typename etl::enable_if< etl::is_integral<T>::value && etl::is_signed<T>::value, T>::type divide_round_half_even(T numerator,
561 T denominator)
562 ETL_NOEXCEPT
563 {
564 const T quotient = numerator / denominator;
565 const T remainder = numerator % denominator;
566 const T direction = ((numerator >= 0) == (denominator >= 0)) ? 1 : -1;
567
568 // Work with magnitudes in unsigned form (avoids abs() overflow for
569 // T::min()).
570 typedef typename etl::make_unsigned<T>::type utype;
571 const utype abs_denominator = (denominator < 0) ? (utype(0) - utype(denominator)) : utype(denominator);
572 const utype abs_remainder = (remainder < 0) ? (utype(0) - utype(remainder)) : utype(remainder);
573 const utype half_denominator = abs_denominator / 2U;
574
575 // Compare without `* 2` to avoid unsigned overflow.
576 if ((abs_denominator & 1U) == 0U)
577 {
578 // Even denominator: can be exactly half.
579 if (abs_remainder < half_denominator)
580 {
581 return quotient;
582 }
583 else if (abs_remainder > half_denominator)
584 {
585 return quotient + direction;
586 }
587 else
588 {
589 // Exactly halfway, round to even
590 return (quotient & 1) == 0 ? quotient : quotient + direction;
591 }
592 }
593 else
594 {
595 // Odd denominator: no exact half case.
596 return (abs_remainder <= half_denominator) ? quotient : (quotient + direction);
597 }
598 }
599
600 //***************************************************************************
608 //***************************************************************************
609 template <typename T1, typename T2>
610 ETL_CONSTEXPR14
611 typename etl::enable_if< etl::is_integral<T1>::value && etl::is_integral<T2>::value && etl::is_signed<T1>::value && etl::is_signed<T2>::value,
612 typename etl::common_type<T1, T2>::type>::type
613 divide_round_half_even(T1 numerator, T2 denominator) ETL_NOEXCEPT
614 {
615 typedef typename etl::common_type<T1, T2>::type type;
616
617 return divide_round_half_even(static_cast<type>(numerator), static_cast<type>(denominator));
618 }
619
620 //***************************************************************************
627 //***************************************************************************
628 template <typename T>
629 ETL_CONSTEXPR14 typename etl::enable_if< etl::is_integral<T>::value && etl::is_unsigned<T>::value, T>::type divide_round_half_even(T numerator,
630 T denominator)
631 ETL_NOEXCEPT
632 {
633 const T quotient = numerator / denominator;
634 const T remainder = numerator % denominator;
635
636 if ((remainder * 2U) < denominator)
637 {
638 // Less than halfway, round down
639 return quotient;
640 }
641 else if ((remainder * 2U) > denominator)
642 {
643 // More than halfway, round up
644 return quotient + 1U;
645 }
646 else
647 {
648 // Exactly halfway, round to even
649 return (quotient & 1U) == 0U ? quotient : quotient + 1;
650 }
651 }
652
653 //***************************************************************************
661 //***************************************************************************
662 template <typename T1, typename T2>
663 ETL_CONSTEXPR14
664 typename etl::enable_if< etl::is_integral<T1>::value && etl::is_integral<T2>::value && etl::is_unsigned<T1>::value && etl::is_unsigned<T2>::value,
665 typename etl::common_type<T1, T2>::type>::type
666 divide_round_half_even(T1 numerator, T2 denominator) ETL_NOEXCEPT
667 {
668 typedef typename etl::common_type<T1, T2>::type type;
669
670 return divide_round_half_even(static_cast<type>(numerator), static_cast<type>(denominator));
671 }
672
673 //***************************************************************************
680 //***************************************************************************
681 template <typename T>
682 ETL_CONSTEXPR14 typename etl::enable_if< etl::is_integral<T>::value && etl::is_signed<T>::value, T>::type divide_round_half_odd(T numerator,
683 T denominator)
684 ETL_NOEXCEPT
685 {
686 const T quotient = numerator / denominator;
687 const T remainder = numerator % denominator;
688
689 typedef typename etl::make_unsigned<T>::type utype;
690 const utype abs_denominator = etl::absolute_unsigned(denominator);
691 const utype abs_remainder = etl::absolute_unsigned(remainder);
692 const utype half = abs_denominator / 2U;
693 const T direction = private_rounded_integral_division::are_same_sign(numerator, denominator) ? 1 : -1;
694
695 // Odd divisor => no exact-half case; 'half' is floor(abs_denominator/2).
696 if ((abs_denominator & 1U) != 0U)
697 {
698 return (abs_remainder > half) ? quotient + direction : quotient;
699 }
700
701 if (abs_remainder < half)
702 {
703 return quotient;
704 }
705 else if (abs_remainder > half)
706 {
707 return quotient + direction;
708 }
709 else
710 {
711 // Exactly halfway, round to odd
712 return (quotient & 1) != 0 ? quotient : quotient + direction;
713 }
714 }
715
716 //***************************************************************************
724 //***************************************************************************
725 template <typename T1, typename T2>
726 ETL_CONSTEXPR14
727 typename etl::enable_if< etl::is_integral<T1>::value && etl::is_integral<T2>::value && etl::is_signed<T1>::value && etl::is_signed<T2>::value,
728 typename etl::common_type<T1, T2>::type>::type
729 divide_round_half_odd(T1 numerator, T2 denominator) ETL_NOEXCEPT
730 {
731 typedef typename etl::common_type<T1, T2>::type type;
732
733 return divide_round_half_odd(static_cast<type>(numerator), static_cast<type>(denominator));
734 }
735
736 //***************************************************************************
743 //***************************************************************************
744 template <typename T>
745 ETL_CONSTEXPR14 typename etl::enable_if< etl::is_integral<T>::value && etl::is_unsigned<T>::value, T>::type divide_round_half_odd(T numerator,
746 T denominator)
747 ETL_NOEXCEPT
748 {
749 const T quotient = numerator / denominator;
750 const T remainder = numerator % denominator;
751
752 if ((remainder * 2U) < denominator)
753 {
754 return quotient;
755 }
756 else if ((remainder * 2U) > denominator)
757 {
758 return quotient + 1U;
759 }
760 else
761 {
762 // Exactly halfway, round to odd
763 return (quotient & 1U) != 0U ? quotient : quotient + 1U;
764 }
765 }
766
767 //***************************************************************************
775 //***************************************************************************
776 template <typename T1, typename T2>
777 ETL_CONSTEXPR14
778 typename etl::enable_if< etl::is_integral<T1>::value && etl::is_integral<T2>::value && etl::is_unsigned<T1>::value && etl::is_unsigned<T2>::value,
779 typename etl::common_type<T1, T2>::type>::type
780 divide_round_half_odd(T1 numerator, T2 denominator) ETL_NOEXCEPT
781 {
782 typedef typename etl::common_type<T1, T2>::type type;
783
784 return divide_round_half_odd(static_cast<type>(numerator), static_cast<type>(denominator));
785 }
786} // namespace etl
787
788#endif
789#endif
Definition absolute.h:40