Zrovna dnes se projevil jeden z problémů celých čísel.
Na počítání s penězi poutžíváme long int (32 bitů rozsah hodnot +/- 2 miliardy). Ovšem jeden zákazník si stěžoval, že nemůže prodat jeden single řádek s hodnotou větší než 20000 euro. Problém je s mezivýpočty. Množství počítáme na tisíciny, takže pokud potřebuju prodat například 3 kusy, každý za 10000, vynásobím 3000x1000000/1000 a jsem na 3 miliardách, což se zakóduje jako asi -1 miliarda, ta se potom vydělí 1000 a výsledek je -1 milión centu = -10000 euro. A mělo to být 30000 euro.
Stačí upravit program, aby mezivýpočty prováděl v long long a problém samozrejme zmizí a výsledek je teď správný. Je to mimochodem přesně ten samý mechanismus, který používá BigInt. V případě potřeby automaticky zvětší rozsah, aby ho potom zase zmenšil v okamžiku, kdy má ukládaný výsledek nižší hodnotu.
Jinak, v případech, kdy se počítalo s tím, že by mezivýsledek mohl přetéct, jsme většinou používali tuto konstrukci
#define SAFE_MULDIV(A,B,C) /* A*B/C */ ((A)/(C)*(B)+(A)%(C)*(B)/(C))
Teď si ale nejsem jistý, jestli funguje i pro záporná čísla.
ano, SAFE_MULDIV funguje i pro zaporna cisla
#define SAFE_MULDIV(A,B,C) /* A*B/C */ ((A)/(C)*(B)+(A)%(C)*(B)/(C))
#include <stdio.h>
int main()
{
printf(" 3_000 x 10_000_00 / 1_000 = %d\n", SAFE_MULDIV( 3000, 1000000, 1000));
printf("-3_000 x 10_000_00 / 1_000 = %d\n", SAFE_MULDIV(-3000, 1000000, 1000));
printf(" 3_000 x 10_000_00 /-1_000 = %d\n", SAFE_MULDIV( 3000, 1000000,-1000));
printf(" 3_000 x-10_000_00 / 1_000 = %d\n", SAFE_MULDIV( 3000,-1000000, 1000));
}
$ ./x
3_000 x 10_000_00 / 1_000 = 3000000
-3_000 x 10_000_00 / 1_000 = -3000000
3_000 x 10_000_00 /-1_000 = -3000000
3_000 x-10_000_00 / 1_000 = -3000000