@@ -3496,19 +3496,29 @@ namespace CppCore
34963496 // / Modulo for any sized unsigned integers.
34973497 // / Based on Knuth's Algorithm in Hacker's Delight. (r=u%v)
34983498 // / </summary>
3499- template <typename UINT1 , typename UINT2 , typename MEM >
3500- INLINE static void umod (UINT2 & r, const UINT1 & u, const UINT2 & v, MEM & mem)
3499+ template <typename UINT1 , typename UINT2 , typename UINT3 , typename MEM >
3500+ INLINE static void umod (UINT3 & r, const UINT1 & u, const UINT2 & v, MEM & mem)
35013501 {
3502- static_assert (sizeof (UINT1 ) != 0 && sizeof (UINT2 ) != 0 && sizeof (MEM ) != 0 );
3503- if constexpr (sizeof (UINT1 ) < sizeof (size_t ))
3502+ static_assert (sizeof (UINT1 ) != 0 && sizeof (UINT2 ) != 0 && sizeof (UINT3 ) != 0 && sizeof (MEM ) != 0 );
3503+ if constexpr (sizeof (UINT3 ) < sizeof (size_t ))
3504+ {
3505+ size_t tr;
3506+ CppCore::umod (tr, u, v, mem);
3507+ CppCore::clone (r, *(UINT3 *)&tr);
3508+ }
3509+ else if constexpr (sizeof (UINT1 ) < sizeof (size_t ))
35043510 {
35053511 CppCore::umod (r, (size_t )u, v, mem);
35063512 }
35073513 else if constexpr (sizeof (UINT2 ) < sizeof (size_t ))
35083514 {
3509- size_t tr;
3510- CppCore::umod (tr, u, (size_t )v, mem);
3511- CppCore::clone (r, *(UINT2 *)&tr);
3515+ CppCore::umod (r, u, (size_t )v, mem);
3516+ }
3517+ else if constexpr (sizeof (UINT3 ) % sizeof (size_t ) != 0 )
3518+ {
3519+ Padded<UINT3 > tr;
3520+ CppCore::umod (tr, u, v, mem);
3521+ CppCore::clone (r, tr.v );
35123522 }
35133523 else if constexpr (sizeof (UINT1 ) % sizeof (size_t ) != 0 )
35143524 {
@@ -3518,31 +3528,35 @@ namespace CppCore
35183528 else if constexpr (sizeof (UINT2 ) % sizeof (size_t ) != 0 )
35193529 {
35203530 Padded<UINT2 > tv (v);
3521- Padded<UINT2 > tr;
3522- CppCore::umod (tr, u, tv, mem);
3523- CppCore::clone (r, tr.v );
3531+ CppCore::umod (r, u, tv, mem);
35243532 }
35253533 #if defined(CPPCORE_CPU_X64)
3526- else if constexpr (sizeof (UINT1 ) % 8 == 0 && sizeof (UINT2 ) == 8 )
3534+ else if constexpr (sizeof (UINT1 ) % 8 == 0 && sizeof (UINT2 ) == 8 && sizeof ( UINT3 ) % 8 == 0 )
35273535 {
3536+ if constexpr (sizeof (UINT3 ) > 8 )
3537+ CppCore::clear (r);
35283538 constexpr uint32_t N64 = sizeof (UINT1 ) / 8 ;
35293539 *(uint64_t *)&r = CppCore::umod128_64x ((uint64_t *)&u, v, N64 );
35303540 }
35313541 #endif
3532- else if constexpr (sizeof (UINT1 ) % 4 == 0 && sizeof (UINT2 ) == 4 )
3542+ else if constexpr (sizeof (UINT1 ) % 4 == 0 && sizeof (UINT2 ) == 4 && sizeof ( UINT3 ) % 4 == 0 )
35333543 {
3544+ if constexpr (sizeof (UINT3 ) > 4 )
3545+ CppCore::clear (r);
35343546 constexpr uint32_t N32 = sizeof (UINT1 ) / 4 ;
35353547 *(uint32_t *)&r = CppCore::umod64_32x ((uint32_t *)&u, v, N32 );
35363548 }
35373549 #if defined(CPPCORE_CPU_X64)
3538- else if constexpr (sizeof (UINT1 ) % 8 == 0 && sizeof (UINT2 ) % 8 == 0 )
3550+ else if constexpr (sizeof (UINT1 ) % 8 == 0 && sizeof (UINT2 ) % 8 == 0 && sizeof ( UINT3 ) % 8 == 0 )
35393551 {
35403552 // using 64-bit chunks
3541- assert (&r != &v);
3553+ assert ((void *)&r != (void *)&v);
3554+ assert ((void *)&r != (void *)&u);
3555+ static_assert (sizeof (UINT3 ) >= MIN (sizeof (UINT1 ), sizeof (UINT2 )));
35423556 static_assert (sizeof (MEM ) >= sizeof (UINT1 ) + 8U );
3543- static_assert (sizeof (UINT1 ) >= sizeof (UINT2 ));
35443557 static_assert (alignof (MEM ) >= alignof (UINT1 ));
35453558 static_assert (alignof (MEM ) >= alignof (UINT2 ));
3559+ static_assert (alignof (MEM ) >= alignof (UINT3 ));
35463560 constexpr uint32_t M = sizeof (UINT1 ) / 8 ;
35473561 constexpr uint32_t N = sizeof (UINT2 ) / 8 ;
35483562 uint64_t * rp = (uint64_t *)&r;
@@ -3552,23 +3566,31 @@ namespace CppCore
35523566 uint64_t * vno;
35533567 uint64_t * vne;
35543568 uint32_t n = N;
3569+ uint32_t m = M;
3570+ CppCore::clear (r);
35553571 while (n != 0U && vp[n-1 ] == 0U )
35563572 n--;
35573573 if (n == 0U )
35583574 return ;
3575+ while (m != 0U && up[m-1 ] == 0U )
3576+ m--;
3577+ if (n > m) {
3578+ if constexpr (sizeof (UINT3 ) <= sizeof (UINT1 ))
3579+ CppCore::clone (r, *(UINT3 *)&u);
3580+ else CppCore::clone (*(UINT1 *)&r, u);
3581+ return ;
3582+ }
35593583 if (n == 1U ) {
3560- CppCore::clear (r);
3561- *rp = CppCore::umod128_64x (up, *vp, M);
3584+ *rp = CppCore::umod128_64x (up, *vp, m);
35623585 return ;
35633586 }
35643587 const auto S ((uint8_t )CppCore::lzcnt (vp[n-1 ]));
35653588 if (S) {
3566- CppCore::clear (r);
35673589 CppCore::shl64x (vp, rp, n, S);
35683590 vno = rp;
35693591 vne = &rp[n];
3570- unp[M ] = up[M -1 ] >> (64U -S);
3571- CppCore::shl64x (up, unp, M , S);
3592+ unp[m ] = up[m -1 ] >> (64U -S);
3593+ CppCore::shl64x (up, unp, m , S);
35723594 }
35733595 else {
35743596 vno = vp;
@@ -3578,7 +3600,7 @@ namespace CppCore
35783600 }
35793601 const auto VNN1 = vno[n-1 ];
35803602 const auto VNN2 = vno[n-2 ];
3581- for (uint32_t j = M -n; j != UINT32_MAX ; j--)
3603+ for (uint32_t j = m -n; j != UINT32_MAX ; j--)
35823604 {
35833605 auto * unpjo = &unp[j];
35843606 auto * unpj = unpjo;
@@ -3632,17 +3654,23 @@ namespace CppCore
36323654 *unpj = kl;
36333655 }
36343656 if (S) { CppCore::shr64x (unp, rp, n, S); }
3635- else { CppCore::clone (r, *(UINT2 *)&mem); }
3657+ else {
3658+ if constexpr (sizeof (UINT3 ) <= sizeof (UINT1 ))
3659+ CppCore::clone (r, *(UINT3 *)&mem);
3660+ else CppCore::clone (*(UINT1 *)&r, *(UINT1 *)&mem);
3661+ }
36363662 }
3637- else
36383663 #endif
3664+ else if constexpr (sizeof (UINT1 ) % 4 == 0 && sizeof (UINT2 ) % 4 == 0 && sizeof (UINT3 ) % 4 == 0 )
36393665 {
36403666 // using 32-bit chunks
3641- assert (&r != &v);
3667+ assert ((void *)&r != (void *)&v);
3668+ assert ((void *)&r != (void *)&u);
3669+ static_assert (sizeof (UINT3 ) >= MIN (sizeof (UINT1 ), sizeof (UINT2 )));
36423670 static_assert (sizeof (MEM ) >= sizeof (UINT1 ) + 4U );
3643- static_assert (sizeof (UINT1 ) >= sizeof (UINT2 ));
36443671 static_assert (alignof (MEM ) >= alignof (UINT1 ));
36453672 static_assert (alignof (MEM ) >= alignof (UINT2 ));
3673+ static_assert (alignof (MEM ) >= alignof (UINT3 ));
36463674 constexpr uint32_t M = sizeof (UINT1 ) / 4 ;
36473675 constexpr uint32_t N = sizeof (UINT2 ) / 4 ;
36483676 uint32_t * rp = (uint32_t *)&r;
@@ -3652,23 +3680,31 @@ namespace CppCore
36523680 uint32_t * vno;
36533681 uint32_t * vne;
36543682 uint32_t n = N;
3683+ uint32_t m = M;
3684+ CppCore::clear (r);
36553685 while (n != 0U && vp[n-1 ] == 0U )
36563686 n--;
36573687 if (n == 0U )
36583688 return ;
3689+ while (m != 0U && up[m-1 ] == 0U )
3690+ m--;
3691+ if (n > m) {
3692+ if constexpr (sizeof (UINT3 ) <= sizeof (UINT1 ))
3693+ CppCore::clone (r, *(UINT3 *)&u);
3694+ else CppCore::clone (*(UINT1 *)&r, u);
3695+ return ;
3696+ }
36593697 if (n == 1U ) {
3660- CppCore::clear (r);
3661- *rp = CppCore::umod64_32x (up, *vp, M);
3698+ *rp = CppCore::umod64_32x (up, *vp, m);
36623699 return ;
36633700 }
36643701 const auto S ((uint8_t )CppCore::lzcnt (vp[n-1 ]));
36653702 if (S) {
3666- CppCore::clear (r);
36673703 CppCore::shl32x (vp, rp, n, S);
36683704 vno = rp;
36693705 vne = &rp[n];
3670- unp[M ] = up[M -1 ] >> (32U -S);
3671- CppCore::shl32x (up, unp, M , S);
3706+ unp[m ] = up[m -1 ] >> (32U -S);
3707+ CppCore::shl32x (up, unp, m , S);
36723708 }
36733709 else {
36743710 vno = vp;
@@ -3678,7 +3714,7 @@ namespace CppCore
36783714 }
36793715 const auto VNN1 = vno[n-1 ];
36803716 const auto VNN2 = vno[n-2 ];
3681- for (uint32_t j = M -n; j != UINT32_MAX ; j--)
3717+ for (uint32_t j = m -n; j != UINT32_MAX ; j--)
36823718 {
36833719 auto * unpjo = &unp[j];
36843720 auto * unpj = unpjo;
@@ -3732,17 +3768,22 @@ namespace CppCore
37323768 *unpj = kl;
37333769 }
37343770 if (S) { CppCore::shr32x (unp, rp, n, S); }
3735- else { CppCore::clone (r, *(UINT2 *)&mem); }
3771+ else {
3772+ if constexpr (sizeof (UINT3 ) <= sizeof (UINT1 ))
3773+ CppCore::clone (r, *(UINT3 *)&mem);
3774+ else CppCore::clone (*(UINT1 *)&r, *(UINT1 *)&mem);
3775+ }
37363776 }
3777+ else assert (false );
37373778 }
37383779
37393780 // / <summary>
37403781 // / Like other variant but using temporary stack memory
37413782 // / </summary>
3742- template <typename UINT1 , typename UINT2 >
3743- INLINE static void umod (UINT2 & r, const UINT1 & u, const UINT2 & v)
3783+ template <typename UINT1 , typename UINT2 , typename UINT3 >
3784+ INLINE static void umod (UINT3 & r, const UINT1 & u, const UINT2 & v)
37443785 {
3745- struct alignas (MAX (alignof (size_t ), MAX (alignof (UINT1 ), alignof (UINT2 )))) MEM {
3786+ struct alignas (MAX (alignof (size_t ), MAX (alignof (UINT1 ), MAX ( alignof (UINT2 ), alignof ( UINT3 ) )))) MEM {
37463787 Padded<UINT1 > x;
37473788 size_t p;
37483789 };
@@ -3774,6 +3815,14 @@ namespace CppCore
37743815 r = u % v;
37753816 }
37763817
3818+ // / <summary>
3819+ // / 64%32=64
3820+ // / </summary>
3821+ template <> INLINE void umod (uint64_t & r, const uint64_t & u, const uint32_t & v)
3822+ {
3823+ r = u % v;
3824+ }
3825+
37773826 // / <summary>
37783827 // / TODO: Special Version for High Bit on Divisor set.
37793828 // / </summary>
@@ -3930,8 +3979,8 @@ namespace CppCore
39303979 // / <summary>
39313980 // / a*b mod m. For any sized integers that are multiples of 32-bit.
39323981 // / </summary>
3933- template <typename UINT1 , typename UINT2 , typename UINT3 , typename MEM >
3934- INLINE static void umulmod (const UINT1 & a, const UINT2 & b, const UINT3 & m, UINT3 & r, MEM & mem)
3982+ template <typename UINT1 , typename UINT2 , typename UINT3 , typename UINT4 , typename MEM >
3983+ INLINE static void umulmod (const UINT1 & a, const UINT2 & b, const UINT3 & m, UINT4 & r, MEM & mem)
39353984 {
39363985 static_assert (sizeof (MEM ) >= sizeof (Padded<UINT1 >) + sizeof (Padded<UINT2 >) + sizeof (size_t ));
39373986 struct UINTX2 { UINT1 a; UINT2 b; };
@@ -3942,10 +3991,10 @@ namespace CppCore
39423991 // / <summary>
39433992 // / a*b mod m. For any sized integers that are multiples of 32-bit.
39443993 // / </summary>
3945- template <typename UINT1 , typename UINT2 , typename UINT3 >
3946- INLINE static void umulmod (const UINT1 & a, const UINT2 & b, const UINT3 & m, UINT3 & r)
3994+ template <typename UINT1 , typename UINT2 , typename UINT3 , typename UINT4 >
3995+ INLINE static void umulmod (const UINT1 & a, const UINT2 & b, const UINT3 & m, UINT4 & r)
39473996 {
3948- struct alignas (MAX (alignof (size_t ), MAX (alignof (UINT1 ), MAX (alignof (UINT2 ), alignof (UINT3 ))))) MEM {
3997+ struct alignas (MAX (alignof (size_t ), MAX (alignof (UINT1 ), MAX (alignof (UINT2 ), MAX ( alignof (UINT3 ), alignof ( UINT4 ) ))))) MEM {
39493998 Padded<UINT1 > a;
39503999 Padded<UINT2 > b;
39514000 size_t p;
@@ -4020,8 +4069,8 @@ namespace CppCore
40204069 // / <summary>
40214070 // / a*a mod m. For any sized integers that are multiples of 32-bit.
40224071 // / </summary>
4023- template <typename UINT1 , typename UINT2 , typename MEM >
4024- INLINE static void usquaremod (const UINT1 & a, const UINT2 & m, UINT2 & r, MEM & mem)
4072+ template <typename UINT1 , typename UINT2 , typename UINT3 , typename MEM >
4073+ INLINE static void usquaremod (const UINT1 & a, const UINT2 & m, UINT3 & r, MEM & mem)
40254074 {
40264075 static_assert (sizeof (MEM ) >= sizeof (Padded<UINT1 >) + sizeof (Padded<UINT1 >) + sizeof (size_t ));
40274076 struct UINTX2 { UINT1 a1; UINT1 a2; };
@@ -4032,10 +4081,10 @@ namespace CppCore
40324081 // / <summary>
40334082 // / a*a mod m. For any sized integers that are multiples of 32-bit.
40344083 // / </summary>
4035- template <typename UINT1 , typename UINT2 >
4036- INLINE static void usquaremod (const UINT1 & a, const UINT2 & m, UINT2 & r)
4084+ template <typename UINT1 , typename UINT2 , typename UINT3 >
4085+ INLINE static void usquaremod (const UINT1 & a, const UINT2 & m, UINT3 & r)
40374086 {
4038- struct alignas (MAX (alignof (size_t ), MAX (alignof (UINT1 ), alignof (UINT2 )))) MEM {
4087+ struct alignas (MAX (alignof (size_t ), MAX (alignof (UINT1 ), MAX ( alignof (UINT2 ), alignof ( UINT3 ) )))) MEM {
40394088 Padded<UINT1 > a1;
40404089 Padded<UINT1 > a2;
40414090 size_t p;
0 commit comments