0^2
./31198>
oui c'est normal.
cette fonction 'IDivMulInv' calcule le resultat d'une division entiere entre deux nombres 32bits signes: une variable divisee par une constante, sans utiliser d'instruction idiv.
le principe c'est de la faire en fixed-point, tu multiplie ta variable 'x' par (1<<32)/constante et tu recupere les 32-bits hauts du resultat.
sauf qu'il faut offsetter le complement a deux pour avoir la bonne troncation (?frenglish ftw), et pour eviter de perdre de la precision et avoir des erreurs d'arrondis en fait c'est pas (1<<32)/constante, mais (1<<(32+n))/constante, de sorte a ce que la constante prenne le max de bits utiles dans les 32 bits du multiplicateur constant.
donc pour une division par une constante 'k' tu peux calculer un multiplicateur 'km' et un shifteur 'ks', et t'as un truc de la forme:
xdivk = mulhi(x, km) >> ks
en rajoutant les corrections de signe:
offset = (km < 0 && kDiv > 0) ? +x : (km > 0 && kDiv < 0) ? -x : 0;
a = mulhi(x, km);
b = (a + offset ) >> ks;
xdivk = b + sign(b)
en virant les branches du calcul de 'offset' (qui est aussi constant vu qu'il depend que des constantes calculees depuis le diviseur constant) ca donne le code du copy/paste d'au dessus ^^
la version sans bugs:
static HH_FORCEINLINE hh_i32 _MulHiS32(hh_i32 x, hh_i32 y)
{
const hh_u64 mulloS64 = hh_i64(x) * hh_i64(y);
return mulloS64 >> 32;
}
//----------------------------------------------------------------------------
static HH_FORCEINLINE hh_i32 _IDivMulInv(hh_i32 x, hh_i32 kMul, hh_i32 kSra, hh_i32 kAddMask, hh_i32 kSubMask)
{
const hh_i32 offset = (x & kAddMask) - (x & kSubMask);
const hh_i32 mulHi = _MulHiS32(x, kMul) + offset;
const hh_i32 mulHiS = mulHi >> kSra;
const hh_i32 sign = hh_u32(mulHiS) >> 31; // rounding offset for negative values
const hh_i32 d = mulHiS + sign;
return d;
}
//----------------------------------------------------------------------------
static HH_FORCEINLINE hh_i32 _IDivMulInv(hh_i32 x, hh_i32 kDiv, hh_i32 kMul, hh_i32 kSra)
{
#if 1
const hh_i32 kDivSign = (kDiv >> 31);
const hh_i32 kMulSign = (kMul >> 31);
const hh_i32 kAddMask = kMulSign & ~kDivSign;
const hh_i32 kSubMask = kDivSign & ~kMulSign;
return _IDivMulInv(x, kMul, kSra, kAddMask, kSubMask);
#else
return (kDiv != 0) ? x / kDiv : 0;
#endif
}
C'est au passage ce qui est utilise par tous les compilateurs un minimum potables (ceci inclut msvc

) lorsque tu divise (ou modulo) par une constante.
la division ou modulo non signes sont plus simples vu que t'as pas toute la partie correction de signe. (mais c'est pas les memes km et ks)