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 copy
13of this software and associated documentation files(the "Software"), to deal
14in the Software without restriction, including without limitation the rights
15to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
16copies 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 "type_traits.h"
36#include "absolute.h"
37#include "utility.h"
38
39namespace etl
40{
41 namespace private_rounded_integral_division
42 {
43 //*****************************************************************************
44 // Checks if two values have the same sign.
45 // For signed integral types.
46 //*****************************************************************************
47 template <typename T>
48 ETL_CONSTEXPR
49 typename etl::enable_if<etl::is_integral<T>::value && etl::is_signed<T>::value, bool>::type
50 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
61 typename etl::enable_if<etl::is_integral<T>::value && etl::is_unsigned<T>::value, bool>::type
62 are_same_sign(T /*a*/, T /*b*/) ETL_NOEXCEPT
63 {
64 return true;
65 }
66 }
67
68 //***************************************************************************
75 //***************************************************************************
76 template <typename T>
77 ETL_CONSTEXPR14
78 typename etl::enable_if<etl::is_integral<T>::value && etl::is_signed<T>::value, T>::type
79 divide_round_to_ceiling(T numerator, T denominator) ETL_NOEXCEPT
80 {
81 const T remainder = numerator % denominator;
82 const T quotient = numerator / denominator;
83
84 // If remainder is zero, already exact
85 if (remainder == 0)
86 {
87 return quotient;
88 }
89
90 // If signs are the same, increment quotient
91 return private_rounded_integral_division::are_same_sign(numerator, denominator) ? quotient + 1 : quotient;
92 }
93
94 //***************************************************************************
102 //***************************************************************************
103 template <typename T1, typename T2>
104 ETL_CONSTEXPR14
106 etl::is_integral<T2>::value &&
107 etl::is_signed<T1>::value &&
108 etl::is_signed<T2>::value,
109 typename etl::common_type<T1, T2>::type>::type
110 divide_round_to_ceiling(T1 numerator, T2 denominator) ETL_NOEXCEPT
111 {
112 typedef typename etl::common_type<T1, T2>::type type;
113
114 return divide_round_to_ceiling(static_cast<type>(numerator), static_cast<type>(denominator));
115 }
116
117 //***************************************************************************
124 //***************************************************************************
125 template <typename T>
126 ETL_CONSTEXPR14
129 T>::type
130 divide_round_to_ceiling(T numerator, T denominator) ETL_NOEXCEPT
131 {
132 const T remainder = numerator % denominator;
133 const T quotient = numerator / denominator;
134
135 // If remainder is zero, already exact, otherwise, increment quotient
136 return remainder == 0U ? quotient : quotient + 1U;
137 }
138
139 //***************************************************************************
147 //***************************************************************************
148 template <typename T1, typename T2>
149 ETL_CONSTEXPR14
151 etl::is_integral<T2>::value &&
154 typename etl::common_type<T1, T2>::type>::type
155 divide_round_to_ceiling(T1 numerator, T2 denominator) ETL_NOEXCEPT
156 {
157 typedef typename etl::common_type<T1, T2>::type type;
158
159 return divide_round_to_ceiling(static_cast<type>(numerator), static_cast<type>(denominator));
160 }
161
162 //***************************************************************************
169 //***************************************************************************
170 template <typename T>
171 ETL_CONSTEXPR14
173 etl::is_signed<T>::value,
174 T>::type
175 divide_round_to_floor(T numerator, T denominator) ETL_NOEXCEPT
176 {
177 const T remainder = numerator % denominator;
178 const T quotient = numerator / denominator;
179
180 // If remainder is zero, already exact
181 if (remainder == 0)
182 {
183 return quotient;
184 }
185
186 // If signs are different, decrement quotient
187 return private_rounded_integral_division::are_same_sign(numerator, denominator) ? quotient : quotient - 1;
188 }
189
190 //***************************************************************************
198 //***************************************************************************
199 template <typename T1, typename T2>
200 ETL_CONSTEXPR14
202 etl::is_integral<T2>::value &&
203 etl::is_signed<T1>::value &&
204 etl::is_signed<T2>::value,
205 typename etl::common_type<T1, T2>::type>::type
206 divide_round_to_floor(T1 numerator, T2 denominator) ETL_NOEXCEPT
207 {
208 typedef typename etl::common_type<T1, T2>::type type;
209
210 return divide_round_to_floor(static_cast<type>(numerator), static_cast<type>(denominator));
211 }
212
213 //***************************************************************************
220 //***************************************************************************
221 template <typename T>
222 ETL_CONSTEXPR14
225 T>::type
226 divide_round_to_floor(T numerator, T denominator) ETL_NOEXCEPT
227 {
228 return numerator / denominator;
229 }
230
231 //***************************************************************************
240 template <typename T1, typename T2>
241 ETL_CONSTEXPR14
243 etl::is_integral<T2>::value &&
246 typename etl::common_type<T1, T2>::type>::type
247 divide_round_to_floor(T1 numerator, T2 denominator) ETL_NOEXCEPT
248 {
249 typedef typename etl::common_type<T1, T2>::type type;
250
251 const type common_numerator = numerator;
252 const type common_denominator = denominator;
253
254 return common_numerator / common_denominator;
255 }
256
257 //***************************************************************************
264 //***************************************************************************
265 template <typename T>
266 ETL_CONSTEXPR14
268 etl::is_signed<T>::value,
269 T>::type
270 divide_round_to_infinity(T numerator, T denominator) ETL_NOEXCEPT
271 {
272 const T remainder = numerator % denominator;
273 const T quotient = numerator / denominator;
274
275 if (private_rounded_integral_division::are_same_sign(numerator, denominator))
276 {
277 // Same sign, round towards +infinity
278 return (remainder != 0) ? quotient + 1 : quotient;
279 }
280 else
281 {
282 // Different signs, round towards -infinity
283 return (remainder != 0) ? quotient - 1 : quotient;
284 }
285 }
286
287 //***************************************************************************
295 //***************************************************************************
296 template <typename T1, typename T2>
297 ETL_CONSTEXPR14
299 etl::is_integral<T2>::value &&
300 etl::is_signed<T1>::value &&
301 etl::is_signed<T2>::value,
302 typename etl::common_type<T1, T2>::type>::type
303 divide_round_to_infinity(T1 numerator, T2 denominator) ETL_NOEXCEPT
304 {
305 typedef typename etl::common_type<T1, T2>::type type;
306
307 return divide_round_to_infinity(static_cast<type>(numerator), static_cast<type>(denominator));
308 }
309
310 //***************************************************************************
317 //***************************************************************************
318 template <typename T>
319 ETL_CONSTEXPR14
322 T>::type
323 divide_round_to_infinity(T numerator, T denominator) ETL_NOEXCEPT
324 {
325 const T remainder = numerator % denominator;
326 const T quotient = numerator / denominator;
327
328 return remainder ? quotient + 1U : quotient;
329 }
330
331 //***************************************************************************
339 //***************************************************************************
340 template <typename T1, typename T2>
341 ETL_CONSTEXPR14
343 etl::is_integral<T2>::value &&
346 typename etl::common_type<T1, T2>::type>::type
347 divide_round_to_infinity(T1 numerator, T2 denominator) ETL_NOEXCEPT
348 {
349 typedef typename etl::common_type<T1, T2>::type type;
350
351 return divide_round_to_infinity(static_cast<type>(numerator), static_cast<type>(denominator));
352 }
353
354 //***************************************************************************
361 //***************************************************************************
362 template <typename T>
363 ETL_CONSTEXPR14
366 T>::type
367 divide_round_to_zero(T numerator, T denominator) ETL_NOEXCEPT
368 {
369 return numerator / denominator;
370 }
371
372 //***************************************************************************
380 //***************************************************************************
381 template <typename T1, typename T2>
382 ETL_CONSTEXPR14
384 etl::is_integral<T2>::value,
385 typename etl::common_type<T1, T2>::type>::type
386 divide_round_to_zero(T1 numerator, T2 denominator) ETL_NOEXCEPT
387 {
388 typedef typename etl::common_type<T1, T2>::type type;
389
390 // Cast to common type to avoid overflow.
391 const type common_numerator = numerator;
392 const type common_denominator = denominator;
393
394 return common_numerator / common_denominator;
395 }
396
397 //***************************************************************************
404 //***************************************************************************
405 template <typename T>
406 ETL_CONSTEXPR14
408 etl::is_signed<T>::value,
409 T>::type
410 divide_round_half_up(T numerator, T denominator) ETL_NOEXCEPT
411 {
412 // Normal division
413 const T remainder = numerator % denominator;
414 const T quotient = numerator / denominator;
415
416 // Work with magnitudes in unsigned form (avoids abs() overflow)
417 typedef typename std::make_unsigned<T>::type utype;
418 utype abs_remainder = remainder < 0 ? utype(0) - utype(remainder) : utype(remainder);
419 utype abs_denominator = denominator < 0 ? utype(0) - utype(denominator) : utype(denominator);
420
421 // Threshold for rounding up (half the denominatorominator, rounded up)
422 utype half_denominator = (abs_denominator + 1) / 2;
423
424 if (abs_remainder >= half_denominator)
425 {
426 // Round away from zero
427 if (private_rounded_integral_division::are_same_sign(numerator, denominator))
428 {
429 return quotient + 1; // same sign ? increment
430 }
431 else
432 {
433 return quotient - 1; // different sign ? decrement
434 }
435 }
436
437 return quotient;
438 }
439
440 //***************************************************************************
448 //***************************************************************************
449 template <typename T1, typename T2>
450 ETL_CONSTEXPR14
452 etl::is_integral<T2>::value &&
453 etl::is_signed<T1>::value &&
454 etl::is_signed<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
475 T>::type
476 divide_round_half_up(T numerator, T denominator) ETL_NOEXCEPT
477 {
478 const T remainder = numerator % denominator;
479 const T quotient = numerator / denominator;
480
481 // If remainder is at least half the divisor, round up
482 return (remainder >= (denominator / 2U) + (denominator % 2U)) ? quotient + 1U : quotient;
483 }
484
485 //***************************************************************************
493 //***************************************************************************
494 template <typename T1, typename T2>
495 ETL_CONSTEXPR14
497 etl::is_integral<T2>::value &&
499 etl::is_unsigned<T2>::value, typename etl::common_type<T1, T2>::type>::type
500 divide_round_half_up(T1 numerator, T2 denominator) ETL_NOEXCEPT
501 {
502 typedef typename etl::common_type<T1, T2>::type type;
503
504 return divide_round_half_up(static_cast<type>(numerator), static_cast<type>(denominator));
505 }
506
507 //***************************************************************************
514 //***************************************************************************
515 template <typename T>
516 ETL_CONSTEXPR14
518 etl::is_signed<T>::value,
519 T>::type
520 divide_round_half_down(T numerator, T denominator) ETL_NOEXCEPT
521 {
522 const T quotient = numerator / denominator;
523 const T remainder = numerator % denominator;
524 const T abs_denominator = etl::absolute(denominator);
525 const T abs_remainderainder = etl::absolute(remainder);
526
527 // Direction: +1 if result should be more positive, -1 if more negative
528 const T direction = ((numerator >= 0) == (denominator >= 0)) ? 1 : -1;
529
530 // Only round away from zero if remainder is strictly greater than half the divisor
531 return abs_remainderainder > (abs_denominator / 2) ? quotient + direction : quotient;
532 }
533
534 //***************************************************************************
542 //***************************************************************************
543 template <typename T1, typename T2>
544 ETL_CONSTEXPR14
546 etl::is_integral<T2>::value &&
547 etl::is_signed<T1>::value &&
548 etl::is_signed<T2>::value,
549 typename etl::common_type<T1, T2>::type>::type
550 divide_round_half_down(T1 numerator, T2 denominator) ETL_NOEXCEPT
551 {
552 typedef typename etl::common_type<T1, T2>::type type;
553
554 return divide_round_half_down(static_cast<type>(numerator), static_cast<type>(denominator));
555 }
556
557 //***************************************************************************
564 //***************************************************************************
565 template <typename T>
566 ETL_CONSTEXPR14
569 T>::type
570 divide_round_half_down(T numerator, T denominator) ETL_NOEXCEPT
571 {
572 const T remainder = numerator % denominator;
573 const T quotient = numerator / denominator;
574
575 // If remainder is at least half the divisor, round down
576 return (remainder > (denominator / 2U)) ? quotient + 1U : quotient;
577 }
578
579 //***************************************************************************
587 //***************************************************************************
588 template <typename T1, typename T2>
589 ETL_CONSTEXPR14
591 etl::is_integral<T2>::value &&
593 etl::is_unsigned<T2>::value, typename etl::common_type<T1, T2>::type>::type
594 divide_round_half_down(T1 numerator, T2 denominator) ETL_NOEXCEPT
595 {
596 typedef typename etl::common_type<T1, T2>::type type;
597
598 return divide_round_half_down(static_cast<type>(numerator), static_cast<type>(denominator));
599 }
600
601 //***************************************************************************
608 //***************************************************************************
609 template <typename T>
610 ETL_CONSTEXPR14
612 etl::is_signed<T>::value,
613 T>::type
614 divide_round_half_even(T numerator, T denominator) ETL_NOEXCEPT
615 {
616 const T quotient = numerator / denominator;
617 const T remainder = numerator % denominator;
618 const T abs_denominator = etl::absolute(denominator);
619 const T abs_remainderainder = etl::absolute(remainder);
620 const T direction = ((numerator >= 0) == (denominator >= 0)) ? 1 : -1;
621
622 if ((abs_remainderainder * 2) < abs_denominator)
623 {
624 return quotient;
625 }
626 else if ((abs_remainderainder * 2) > abs_denominator)
627 {
628 return quotient + direction;
629 }
630 else
631 {
632 // Exactly halfway, round to even
633 return (quotient & 1) == 0 ? quotient : quotient + direction;
634 }
635 }
636
637 //***************************************************************************
645 //***************************************************************************
646 template <typename T1, typename T2>
647 ETL_CONSTEXPR14
649 etl::is_integral<T2>::value &&
650 etl::is_signed<T1>::value &&
651 etl::is_signed<T2>::value,
652 typename etl::common_type<T1, T2>::type>::type
653 divide_round_half_even(T1 numerator, T2 denominator) ETL_NOEXCEPT
654 {
655 typedef typename etl::common_type<T1, T2>::type type;
656
657 return divide_round_half_even(static_cast<type>(numerator), static_cast<type>(denominator));
658 }
659
660 //***************************************************************************
667 //***************************************************************************
668 template <typename T>
669 ETL_CONSTEXPR14
672 T>::type
673 divide_round_half_even(T numerator, T denominator) ETL_NOEXCEPT
674 {
675 const T quotient = numerator / denominator;
676 const T remainder = numerator % denominator;
677
678 if ((remainder * 2U) < denominator)
679 {
680 // Less than halfway, round down
681 return quotient;
682 }
683 else if ((remainder * 2U) > denominator)
684 {
685 // More than halfway, round up
686 return quotient + 1U;
687 }
688 else
689 {
690 // Exactly halfway, round to even
691 return (quotient & 1U) == 0U ? quotient : quotient + 1;
692 }
693 }
694
695 //***************************************************************************
703 //***************************************************************************
704 template <typename T1, typename T2>
705 ETL_CONSTEXPR14
707 etl::is_integral<T2>::value &&
710 typename etl::common_type<T1, T2>::type>::type
711 divide_round_half_even(T1 numerator, T2 denominator) ETL_NOEXCEPT
712 {
713 typedef typename etl::common_type<T1, T2>::type type;
714
715 return divide_round_half_even(static_cast<type>(numerator), static_cast<type>(denominator));
716 }
717
718 //***************************************************************************
725 //***************************************************************************
726 template <typename T>
727 ETL_CONSTEXPR14
729 etl::is_signed<T>::value,
730 T>::type
731 divide_round_half_odd(T numerator, T denominator) ETL_NOEXCEPT
732 {
733 const T quotient = numerator / denominator;
734 const T remainder = numerator % denominator;
735 const T abs_denominator = etl::absolute(denominator);
736 const T abs_remainderainder = etl::absolute(remainder);
737 const T direction = ((numerator >= 0) == (denominator >= 0)) ? 1 : -1;
738
739 if ((abs_remainderainder * 2) < abs_denominator)
740 {
741 return quotient;
742 }
743 else if ((abs_remainderainder * 2) > abs_denominator)
744 {
745 return quotient + direction;
746 }
747 else
748 {
749 // Exactly halfway, round to odd
750 return (quotient & 1) != 0 ? quotient : quotient + direction;
751 }
752 }
753
754 //***************************************************************************
762 //***************************************************************************
763 template <typename T1, typename T2>
764 ETL_CONSTEXPR14
766 etl::is_integral<T2>::value &&
767 etl::is_signed<T1>::value &&
768 etl::is_signed<T2>::value,
769 typename etl::common_type<T1, T2>::type>::type
770 divide_round_half_odd(T1 numerator, T2 denominator) ETL_NOEXCEPT
771 {
772 typedef typename etl::common_type<T1, T2>::type type;
773
774 return divide_round_half_odd(static_cast<type>(numerator), static_cast<type>(denominator));
775 }
776
777 //***************************************************************************
784 //***************************************************************************
785 template <typename T>
786 ETL_CONSTEXPR14
789 T>::type
790 divide_round_half_odd(T numerator, T denominator) ETL_NOEXCEPT
791 {
792 const T quotient = numerator / denominator;
793 const T remainder = numerator % denominator;
794 const T direction = ((numerator >= 0U) == (denominator >= 0U)) ? 1 : -1;
795
796 if ((remainder * 2U) < denominator)
797 {
798 return quotient;
799 }
800 else if ((remainder * 2U) > denominator)
801 {
802 return quotient + direction;
803 }
804 else
805 {
806 // Exactly halfway, round to odd
807 return (quotient & 1U) != 0U ? quotient : quotient + direction;
808 }
809 }
810
811 //***************************************************************************
819 //***************************************************************************
820 template <typename T1, typename T2>
821 ETL_CONSTEXPR14
823 etl::is_integral<T2>::value &&
826 typename etl::common_type<T1, T2>::type>::type
827 divide_round_half_odd(T1 numerator, T2 denominator) ETL_NOEXCEPT
828 {
829 typedef typename etl::common_type<T1, T2>::type type;
830
831 return divide_round_half_odd(static_cast<type>(numerator), static_cast<type>(denominator));
832 }
833}
834
835#endif
enable_if
Definition type_traits_generator.h:1254
is_unsigned
Definition type_traits_generator.h:1084
bitset_ext
Definition absolute.h:39
ETL_CONSTEXPR14 etl::enable_if< etl::is_integral< T >::value &&etl::is_signed< T >::value, T >::type divide_round_half_odd(T numerator, T denominator) ETL_NOEXCEPT
Integral division with rounding to half odd. For signed integral types. For identical argument types.
Definition rounded_integral_division.h:731
ETL_CONSTEXPR14 etl::enable_if< etl::is_integral< T >::value &&etl::is_signed< T >::value, T >::type divide_round_to_infinity(T numerator, T denominator) ETL_NOEXCEPT
Integral division with rounding towards infinity. For signed integral types. For identical argument t...
Definition rounded_integral_division.h:270
ETL_CONSTEXPR14 etl::enable_if< etl::is_integral< T >::value &&etl::is_unsigned< T >::value, T >::type divide_round_to_zero(T numerator, T denominator) ETL_NOEXCEPT
Integral division with rounding towards zero. For integral types. For identical argument types.
Definition rounded_integral_division.h:367
ETL_CONSTEXPR14 etl::enable_if< etl::is_integral< T >::value &&etl::is_signed< T >::value, T >::type divide_round_half_down(T numerator, T denominator) ETL_NOEXCEPT
Integral division with rounding to half down. For signed integral types. For identical argument types...
Definition rounded_integral_division.h:520
ETL_CONSTEXPR14 etl::enable_if< etl::is_integral< T >::value &&etl::is_signed< T >::value, T >::type divide_round_half_up(T numerator, T denominator) ETL_NOEXCEPT
Integral division with rounding to half up. For signed integral types. For identical argument types.
Definition rounded_integral_division.h:410
ETL_CONSTEXPR14 etl::enable_if< etl::is_integral< T >::value &&etl::is_signed< T >::value, T >::type divide_round_half_even(T numerator, T denominator) ETL_NOEXCEPT
Integral division with rounding to half even. For signed integral types. For identical argument types...
Definition rounded_integral_division.h:614
ETL_CONSTEXPR14 etl::enable_if< etl::is_integral< T >::value &&etl::is_signed< T >::value, T >::type divide_round_to_floor(T numerator, T denominator) ETL_NOEXCEPT
Integral division with rounding to floor. For signed integral types. For identical argument types.
Definition rounded_integral_division.h:175
ETL_CONSTEXPR14 etl::enable_if< etl::is_integral< T >::value &&etl::is_signed< T >::value, T >::type divide_round_to_ceiling(T numerator, T denominator) ETL_NOEXCEPT
Integral division with rounding to ceiling. For signed integral types. For identical argument types.
Definition rounded_integral_division.h:79