Chci geek triko! Chci geek triko!
Extra 10 % bodů navíc a tričko zdarma při zadání kódu "TRIKO10"

Diskuze: Nepřesné násobení vysokými čísly - špatně zvolené datové typy?

C a C++ C a C++ Nepřesné násobení vysokými čísly - špatně zvolené datové typy? American English version English version

Aktivity (1)
Avatar
Honza 211
Člen
Avatar
Honza 211:10. září 13:39

Zdravím,
mám následující problém: pokud v c vynásobím např. 23.69*1000000000, tak mi vyjde 23690000384. Nevíte někdo, kde by mohla být chyba? Tuším, že to bude něco s datovými typy - když násobím o nulu menším číslem nebo desetkrát menší číslo, tak to funguje jak má.
Díky za všechny nápady!

Zkusil jsem: Vyabstrahovat operaci z programu a zkusit to na samostatném kódu.

Chci docílit: Pokouším se o jednoduchý program na převod racionálních čísel na zlomky. Číslo vynásobím třeba právě miliardou a pak v cyklu dělím deseti, dokud nebude zbytek po dělení větší než 0. Zároveň s ním dělím číslo, kterým jsem ho vynásobil a to pak přijde do jmenovatele.

 
Odpovědět 10. září 13:39
Avatar
Luboš Satik Běhounek
Autoredaktor
Avatar
Odpovídá na Honza 211
Luboš Satik Běhounek:10. září 13:49

V čem máš čísla uložený? Ve floatu?
Desetinný čísla jsou uložený tak, že maj přesnost jen na několik platných číslic - podle toho, jak velkej typ použiješ.

Float to má cca 7 platných číslic, pokud do něj uložíš i celý číslo větší než tuším 16 777 216, tak ti to už může vrátit jiný číslo, než jsi tam uložil, aniž bys s ním dělal nějaký výpočty.

Nahoru Odpovědět 10. září 13:49
https://www.facebook.com/peasantsandcastles/
Avatar
Honza 211
Člen
Avatar
Honza 211:10. září 14:01

Přesně tak, je to float. Pomohl by mi double nebo long double? Víc desetinných míst nepotřebuju, jde mi o tu hranici pro celá čísla, kde už to začíná blbnout. Nebo bych to taky mohl nějak šikovně zaokrouhlit...

 
Nahoru Odpovědět 10. září 14:01
Avatar
Luboš Satik Běhounek
Autoredaktor
Avatar
Odpovídá na Honza 211
Luboš Satik Běhounek:10. září 14:04

na tohle by jeste mohl stacit double, kam az ty cisla muzou rust?

Nahoru Odpovědět 10. září 14:04
https://www.facebook.com/peasantsandcastles/
Avatar
Honza 211
Člen
Avatar
Honza 211:10. září 14:26

vstupni hodnoty staci do desitek tisic a pri presnosti 6 desetinnych mist by stacilo nasobit milionem a vysledky by se tudiz pohybovaly v desitkach miliard.

Kazdopadne diky za tip, zkusim to predefinovat.

 
Nahoru Odpovědět 10. září 14:26
Avatar
Honza 211
Člen
Avatar
Honza 211:10. září 16:50

Tak double uz nezlobi. Akorat je problem, kdyz si tu hodnotu chci ulozit do int, to se pak z 2350000000 stane -2147483648. Zkusil jsem pretypovat na long a nic. A v intu to mit potrebuju, protoze pouzivam funkci modulo.

 
Nahoru Odpovědět 10. září 16:50
Avatar
DarkCoder
Člen
Avatar
Odpovídá na Honza 211
DarkCoder:10. září 17:20

Operátor modulo % lze použít pro libovolný celočíselný typ.

Nahoru Odpovědět 10. září 17:20
"„Učíš-li se proto, aby sis zapamatoval, zapomeneš. Učíš-li se proto, abys porozuměl, zapamatuješ si."
Avatar
Luboš Satik Běhounek
Autoredaktor
Avatar
Odpovídá na Honza 211
Luboš Satik Běhounek:10. září 17:36

2350000000 je mimo rozsah signed 32bit intu -> budto unsigned nebo 64bit int.

Nahoru Odpovědět 10. září 17:36
https://www.facebook.com/peasantsandcastles/
Avatar
Martin Dráb
Redaktor
Avatar
Odpovídá na DarkCoder
Martin Dráb:10. září 17:36

Pořád se tam můžeš potýkat se zaokrouhlovacími chybami, což je dáno tím, jak jsou interně desetinná čísla uložena v paměti (viz IEEE 754). Vzhledem k jejich reprezentaci třeba není možné přesně uložit čísla jako dvě desetiny – protože nejdou rozložit na konečný součet (byť i záporných) mocnin dvojky.

Pokud potřebuješ přesnost na relativně málo desetinných míst, můžeš desetinná čísla reprezentovat čísly celými. Pokud třeba potřebuješ být přesný na pět des. míst, prostě místo jednotek pracuj se statisíci (v zásadě vše vynásobíš 100000, abyses s des čísly vůbec nesetkal). Pokud ti bude stačit 64bitový integer, tak máš vyhráno.

Navíc, počítání s celými čísly je výrazně rychlejší než z desetinnými (pokud nevyužiješ paralelizační možnosti procesoru či grafické karty).

Akceptované řešení
+20 Zkušeností
+1 bodů
Řešení problému
Nahoru Odpovědět  +2 10. září 17:36
2 + 2 = 5 for extremely large values of 2
Avatar
DarkCoder
Člen
Avatar
Odpovídá na Honza 211
DarkCoder:10. září 20:02

Int, long, unsigned, unsigned long jsou stále mimo rozsah. Proto při převodu z větší hodnoty která je mimo rozsah na menší dochází k nesmyslné hodnotě. Aby si mohl provést operaci modulo s velkou hodnotou, použij datový typ long long, nebo unsigned long long. Tyto typy jsou podporovány od verze C99. Pro výpis pomocí printf() long long použij specifikaci formátu %lli, pro unsigned long long použij specifikaci formátu %llu.

Např:

printf("%lli\n", ((long long)(a*b)) % x);
Nahoru Odpovědět 10. září 20:02
"„Učíš-li se proto, aby sis zapamatoval, zapomeneš. Učíš-li se proto, abys porozuměl, zapamatuješ si."
Avatar
Honza 211
Člen
Avatar
Honza 211:10. září 20:42

Díky za všechny odpovědi i věcné připomínky. Inu, nováček se sám vytrestal tím, že poznatky o syntaxi a datových typech céčka čerpal pouze z prvního českého zdroje, který mu strejda Google vyplivl - tak o půlce zde zmíněných typech jsem neměl ani páru.

Díky Lubošovi za okamžité a věcné odpovědi, díky DarkCoderovi za syntaxi, jako řešení ale nakonec označím Martina. Myslím, že jeho návrh výrazně zkrátil toto vlákno a šetří čas i nervy ostatních přispěvatelů, protože okamžitým převodem na celá čísla předejdu dalším problémům, které bych zde jinak konzultoval.

 
Nahoru Odpovědět 10. září 20:42
Děláme co je v našich silách, aby byly zdejší diskuze co nejkvalitnější. Proto do nich také mohou přispívat pouze registrovaní členové. Pro zapojení do diskuze se přihlas. Pokud ještě nemáš účet, zaregistruj se, je to zdarma.

Zobrazeno 11 zpráv z 11.