Vlákno názorů k článku BigInt: nový celočíselný typ v JavaScriptu od Josef Pavlik - Zrovna dnes se projevil jeden z problémů celých...

  • Článek je starý, nové názory již nelze přidávat.
  • 20. 6. 2019 16:46

    Josef Pavlik

    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.

  • 20. 6. 2019 16:59

    Josef Pavlik

    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