Diskuze: Finance
Člen
Zobrazeno 13 zpráv z 13.
//= Settings::TRACKING_CODE_B ?> //= Settings::TRACKING_CODE ?>
MSSQL + C# má typ Decimal, který se na tyhle věci hodí, protože u něj
nedochází ke ztrátě přesnosti.
Jak jsou na tom ostatní jazyky netuším, ale určitě to bude možné nahradit
alespoň nějakou knihovnou, pokud nemají nějakou obdobu.
I u typu Decimal dochází ke ztrátě přesnosti - a už z principu neexistuje typ, kde by nedocházelo. Jenom je těžší si ho všimnout díky fixní řádové čárce a vyššímu počtu desetinných míst. Z toho důvodu se finanční výpočty vždy počítají v celých čísel.
Ale nedochází
(samozřejmě pokud nezadáš číslo mimo rozsah nebo s více než 28
číslicemi).
Decimal je právě uložený jako celé číslo s desítkovým exponentem a je
určený pro práci s financemi.
The Decimal value type represents decimal numbers ranging from positive 79,228,162,514,264,337,593,543,950,335 to negative 79,228,162,514,264,337,593,543,950,335. The Decimal value type is appropriate for financial calculations that require large numbers of significant integral and fractional digits and no round-off errors. The Decimal type does not eliminate the need for rounding. Rather, it minimizes errors due to rounding. For example, the following code produces a result of 0.9999999999999999999999999999 instead of 1.
Trik je v tom, že se používá 128 bitů místo 64 a mantisa má více bitů na úkor exponentu, aby se posunula hranice zaokrouhlovací chyby. Takže chyby jsou vzácnější, ale stále s nimi musíš počítat.
Až budeš psát nějaký finanční systém, tak si dej pozor na prvočíselný počet dní v měsíci a nesoudělnost. Když jsem dělal za ekonomickém sw, hledali jsme takovou chybu dlouho.
Navíc je v téhle části zákon nejasný, a když ti účetní kontroluje výsledky, dojdete ke odlišným výsledkům - a oba budou správně. Ve výsledku decimal vůbec nic neřeší.
S tou nepřesností jsem to myslel jinak než ty - ne u výpočtů, ale už
při ukládání (a případně základních operací).
Ve finančnictví se používá desítková soustava a Decimal používá jako
základ pro exponent taky 10, takže při ukládání hodnot, které jsou v
desítkové soustavě bez period nebo neukončených desetinných rozvojů
nedochází ke ztrátě přesnosti, narozdíl od běžného floatu (který má
základ 2).
Např. v následujícím kódu:
float a = 0.3f;
float b = 0.2f;
float c = 0.5f;
if ((a + b) == c)
Console.WriteLine("true");
else
Console.WriteLine("false");
Console.WriteLine(a + b);
Console.WriteLine(c);
, který vypíše:
false
0,5
0,5
tedy že 0,5 != 0,5.
Pokud samozřejmě do Decimalu uložíš číslo, které uložit nedokáže, tak tam tu přesnost ztratí.
Do konzole můžeš vypsat přímo bool a napíše ti to True/ False
Právě, že to je omyl, protože decimal funguje zcela stejně jako float.
Zaměstnanec pracuje denně 8 hodin, 20 dní v měsíci a máš 10
zaměstnanců.
8 * 20 * 10 = 1600
Takže řekněme že čísla do 2000 jsou zcela běžná.
Teď už je snadné parafrázovat tvůj příklad protipříkladem.
decimal a = 3m / 1121m;
decimal b = 2m / 1121m;
decimal c = 5m / 1121m;
Console.WriteLine(a + b == c);
Jak říkám, psal jsem ekonomický sw a decimal ve srovnání s double nic neřeší.
Ještě mě napadl případ, který se nám opravdu stával.
Počítáš mzdu podle zákona, který uvádí vzorec pro výpočet s poznámkou, že poté se částka zaokrouhlí na koruny směrem dolů. V tomhle případě jsme dostávali dva výsledky v lehce odlišných situacích. Nakonec jsme zjistili, že v jednom případě vyšla částka 1000,000....001 zatímco ve druhém 999.999....999
Zaokrouhlení dolů pak dá rozdíl jednu korunu, která se ve výsledku jeví jako chyba.
Řešení? Používat decimal pro jednotlivé operace a mezivýsledky zaoukrouhlovat z 28 míst na 25. Jenže zákon, který se o zaoukrohlování zmiňuje, říká, že tohle bys dělat neměl (v zákoníku je to trochu nejednoznačné, ale spíše ne).
Jiné řešení? Banky vždy počítaly pouze v celých číslech na 4-8 míst s fixní řádovou čárkou, a protože se dělí v celých číslech, zbytky po dělení se ignorují.
Ne, to v desítkové soustavě nezapíšeš na omezeném prostoru přesně.
Zobrazeno 13 zpráv z 13.