<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type="text/xsl" href="http://blog.aspnet.sk/utility/FeedStylesheets/rss.xsl" media="screen"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:wfw="http://wellformedweb.org/CommentAPI/"><channel><title>Skippov blog : .NET, float</title><link>http://blog.aspnet.sk/skippo/archive/tags/.NET/float/default.aspx</link><description>Štítky: .NET, float</description><dc:language>sk-SK</dc:language><generator>CommunityServer 2007 SP1 (Build: 20510.895)</generator><item><title>Prakticke problemy pri konvertovani mien pomocou datoveho typu Double</title><link>http://blog.aspnet.sk/skippo/archive/2008/12/11/prakticke-problemy-pri-konvertovani-mien-pomocou-datoveho-typu-double.aspx</link><pubDate>Thu, 11 Dec 2008 08:59:00 GMT</pubDate><guid isPermaLink="false">cbdfeddd-8b45-43cb-b10b-361e40cba84b:55429</guid><dc:creator>skippo</dc:creator><slash:comments>3</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://blog.aspnet.sk/skippo/rsscomments.aspx?PostID=55429</wfw:commentRss><comments>http://blog.aspnet.sk/skippo/archive/2008/12/11/prakticke-problemy-pri-konvertovani-mien-pomocou-datoveho-typu-double.aspx#comments</comments><description>&lt;p&gt;Zacnime vtipom:&lt;/p&gt;&lt;p&gt;&lt;i&gt;&amp;quot;Rada nad zlato.

Chcete zvacsit svoj kapital?



Pozerajte si vyplatu pod lupou.&amp;quot;&lt;/i&gt;&lt;/p&gt;&lt;p&gt;Skippova poznamka: &amp;quot;&lt;i&gt;najma po 1. januari 2009&lt;/i&gt;&amp;quot; :-)&lt;/p&gt;&lt;p&gt;Kazdy programator sa skor ci neskor dostane do kontaktu s aplikaciou, ktora naraba s peniazmi. Peniaze su citliva tema, najma ak sa dostane na ich reprezentaciu v pocitaci, ktory ma obmedzenu pamat (-:jedina nekonecna vec by mala byt ludska hlupost:-). Nedavno som opravoval par problemom suvisiacich s konverziou penazi do roznych mien a teraz sa mi naskytlo trosku casu to nejako zosumarizovat. Niektore veci su trivialne, ine trosku menej, nic-menej vsetko, co suvisi s peniazmi (klientov) je dolezite. Ked som problem videl prvy krat na obrazovke, hned som si spomenul na duracellkov &lt;a href="http://blog.aspnet.sk/duracellko/archive/2008/04/11/je-naozaj-typ-double-presnej-237-ako-float.aspx" target="_blank"&gt;post&lt;/a&gt; o problemoch datovych typov s pohyblivou desatinnou ciarkou a bol som na spravnej stope. Dufam, ze tento prispevok pomoze niekomu dalsiemu v luskani otazok suvisiacich s peniazmi.&lt;/p&gt;&lt;p&gt;&lt;b&gt;Situacia&lt;/b&gt;&lt;br /&gt;Ste programator znamej online 3D hry &lt;a href="http://secondlife.com/" target="_blank"&gt;2nd Life&lt;/a&gt;. Vasi klienti si mozu do systemu naliat peniaze a potom obchodovat a fungovat ako v realnom svete. Pre jednoduchost predpokladajme, ze tu mame fantasticky slovensky trh a specialne prenho sme vytvorili specialnu x-mas verziu, kde moze klient nahrat peniaze len v SKK mene (EUR este nestihlo prist).&lt;/p&gt;&lt;p&gt;&lt;img src="http://blog.aspnet.sk/blogs/skippo/images/2ndlife.jpg" title="2nd life" alt="2nd life" width="640" height="372" /&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;Vasi klienti mozu virtualne peniaze, ktore vlozili do systemu menit za rozne veci (oblecenie, zetony do kasina, nehnutelnosti a pod.). Idu vianoce a preto budu obchodovat ako divy :-)&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;b&gt;Problemy&lt;/b&gt;&lt;br /&gt;Hned na uvod by som rad zdoraznil, ze dane problemy sa nesnazia byt vseobecne pre vsetky typy aplikacie, skor chcu nabadat citatela, aby sa nad nimi zamyslel v kontexte tej &lt;i&gt;jeho&lt;/i&gt; aplikacie.&lt;/p&gt;&lt;p&gt;&lt;b&gt;1. Zobrazenie penazi&lt;/b&gt;&lt;br /&gt;Na prvy pohlad jasna vec, no nemusi to tak byt. Na kolko desatinnych miest zobrazime aktualny stav uctu klienta? Pri transakciach penazi tam a spat nam moze stav uctu nadobudnut velmi rozne hodnoty. Kedze pocitac nedokaze niektore cisla s nekonecnym desatinny rozvojom drzat v pamati, pracujeme vzdy s najlepsim priblizenim - aproximaciou. Kolko mieste je OK? V nasej hre by sme pokojne mohli rozhodnut, ze &lt;b&gt;2&lt;/b&gt;. Teda klient po urcitom case hrania a niekolkych trasakciach bude mat na svojom urcte 100,126 SKK. Zobrazime hodnotu na 2 desatinne miesta ale ako - 100,12 alebo 100,13 ?&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;b&gt;2. Zaokruhlovanie&lt;/b&gt;&lt;br /&gt;Zaokruhlovanie suvisi aj s bodom c.1 - zobrazenu sumu zaokruhlovat alebo orezavat? Vacsinou chceme byt ku klientom dobri a pri &lt;i&gt;istych &lt;/i&gt;transakciach zaokruhlujeme v prospech klienta. Tu chcem zdoraznit jeden &lt;i&gt;bezpecnostny problem&lt;/i&gt;, ak budeme na klienta prilis dobry, moze sa nam to vypomstit. Predstavme si, ze vojdeme do virtualneho kasina, kupime si za cely nas ucet zetony (nech jeden zeton == 1EUR). Ak zaokruhlujeme aj v tomto pripade v prospech klienta a nechame na strane klienta istu desatinnu cast, moze sa nam lahko stat, ze parta polsko-ruskych nadsencov nam zacne prelievat peniaze tam a spat a za jeden den nas okradne par sto az tisic korun. Obrana pred takymito utokmi vsak patri do ineho clanku.&lt;br /&gt;&lt;/p&gt;&lt;p&gt; Co ale s vypisom jeho stavu uctu. Nuz tu treba byt opatrny. Este raz, nech klient ma na svojom ucte realnych 100,126 SKK a nech padlo rozhodnutie zobrazovat stav na 2 desatinne miesta. Ako - orezat? -zaokruhlit? Nuz obe moznosti sa &lt;i&gt;v nasom&lt;/i&gt; pripade 2nd Life daju aplikovat, s roznymi dosledkami. &lt;/p&gt;&lt;p&gt;Ak &lt;i&gt;orezeme&lt;/i&gt;, klient moze mat pocit, ze mu zobrazujeme nespravne informacie (ludia nie su hlupi), nebodaj, ze sme ho okradli. To moze vazne poskodit nasu rokmi budovanu znacku a znicit cely biznis, ak je klient nespokojny a hlavne nam &lt;b&gt;neveri&lt;/b&gt;.&lt;/p&gt;&lt;p&gt;&lt;i&gt;Zaokruhlime&lt;/i&gt;? V poriadku, klient nemoze namietat, davame mu viac ako od nas ocakava (a ktomu odpovedajuci vtip: &amp;quot;&lt;i&gt;pride chlapik na konkurz na policajta a dostane otazku: kolko je dva plus dva. Muz odpoveda: dvanast. Policajti: vyborne, berieme vas, povedali ste nam viac, ako sme od vas ocakavali&lt;/i&gt;&amp;quot;). Toto rozhodnutie nam vsak moze poriadne skomplikovat zivot, ak na inom mieste v aplikacii ponukame funkcnost typu &amp;#39;&lt;i&gt;zamen vsetky peniaze za zetony&lt;/i&gt;&amp;#39; a uzivatel do textoveho policka napise sumu 100,13 v domienke, ze tolko penazi naozaj ma. Po odklepnuti tlacidka vsak dostane hlasku, ze na svojom ucte nema tolko penazi, a ze si moze zamenit o nieco menej zetonov. To znamena robit dotatocnu kontrolu a rozne cesticky, ktore v konecnom dosledu a pri velkosti hry 2nd Life mozu mat negativny dopad na udrzbu, zmenu a vyvoj aplikacie. Urcite vas hned napada n-dalsich problemov.&lt;/p&gt;&lt;p&gt;&lt;b&gt;3. Implementacia v .NET&lt;/b&gt;&lt;br /&gt;V .NETe a C# mame 3 datove typy pracujuce podla standardu pre aritmetiku s pohyblivou desatinnou ciarkou: double, float, decimal. Ktory typ pouzit. Decimal je urceny na pracu s penaznymi hodnotami a mal by sa na to pouzivat. Je vsak asi 40x pomalsi ako double. Interny popis double a floatu najdete v napr v duracellkovom clanku alebo na wikipedii.&amp;nbsp;&lt;/p&gt;&lt;p&gt;Niekedy situaciu nemame vo svojich rukach a dostaneme pod ruky kod, ktory pracuje s &lt;i&gt;double&lt;/i&gt;. Tiez zdoraznim jednu podstatnu vec, realna hodnota double a jeho textova reprezentacia .ToString() &lt;i&gt;nie su&lt;/i&gt; rovnake. Nie som expert v implementacii aritmetiky s pohyblivou desatinnou ciarkou v .NET, no docital som sa, ze nie je uplna podla standardov. Mozno by sa niekto mohol vyjadrit v komentaroch, aky je momentalny stav v .NET 3.5, teda CLR 2.0 a BCL.&lt;/p&gt;&lt;p&gt;Jeden lahko prehliadnutelny dosledok tohto faktu je, ak pouzivame ASP.NET ViewState. Ak potrebujeme preniest stav-&lt;i&gt;double cislo&lt;/i&gt; vo viewstate, jednoduche priradenie ViewState[&amp;quot;mojeCislo&amp;quot;] = cislo; sposobi (predpokladam) zavolanie overrided .ToString() metody na vstupnom objekte. A v dalsom volani stranky a ziskani hodnoty z viewstate cez double.Parse nam vrati inu hodnotu, ako sme povodne vlozili. Tym padom dostavame neocakavane vysledky v dalsich vypoctoch.&lt;/p&gt;&lt;p&gt;Riesenim je ulozit cislo vo formate &lt;i&gt;round-trip&lt;/i&gt; ViewState[&amp;quot;mojeCislo&amp;quot;] = cislo.ToString(&amp;quot;r&amp;quot;); Ako pise MSDN, takto ziskana reprezentacia cisla zaruci rovnake vysledny po opatovnom parsovani. &lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;b&gt;Zaver&lt;br /&gt;&lt;/b&gt;Pri praci s aproximaciou realnych cisel je dolezite vediet, ako dana platforma pracuje a implementuje system pre aritmetiku cisel s pohyblivou desatinnou ciarkou. O to viac, ak robime porovnavania a cisla reprezentuju peniaze. Chyby v kode sa opravia lahko, tazko sa opat nadobudne dovera zakaznikov. &lt;/p&gt;&lt;p&gt;Dufam, ze vas mozno trosku odlahceny styl s prikladom z praxe a zaujal. Chcem dodat, ze som sa nesnazil o ziadnu reklamu spominanej hry. Jednoducho mi to padlo ako dobry programatorsko-managersky priklad, pre mnohych z vas mozno nie celkom typickej aplikacie, na ktorych denne pracujete.&lt;/p&gt;&lt;p&gt;&lt;b&gt;Kviz&lt;br /&gt;&lt;/b&gt;Pre naruziveho citatela ponukame v skutku jednoduchu otazku:&amp;nbsp; aka hodnota bude ulozena v booleovskej premennej &lt;b&gt;b&lt;/b&gt; po vykonani nasledujuceho riadku (C#):&lt;br /&gt;&lt;i&gt;bool b = double.NaN == double.NaN&lt;/i&gt;&lt;/p&gt;&lt;p&gt;Tesim sa na Vase odpovede.&lt;br /&gt;&lt;/p&gt;
&lt;!-- AddThis Button BEGIN --&gt;&lt;div&gt;&lt;script type="text/javascript"&gt;var addthis_pub="spigi";&lt;/script&gt;&lt;a href="http://www.addthis.com/bookmark.php?v=20" onmouseover="return addthis_open(this, '', 'http://blog.aspnet.sk/skippo/archive/2008/12/11/prakticke-problemy-pri-konvertovani-mien-pomocou-datoveho-typu-double.aspx', 'Prakticke problemy pri konvertovani mien pomocou datoveho typu Double')" onmouseout="addthis_close()" onclick="return addthis_sendto()"&gt;&lt;img src="http://s7.addthis.com/static/btn/lg-share-en.gif" width="125" height="16" alt="Bookmark and Share" style="border:0"/&gt;&lt;/a&gt;&lt;script type="text/javascript" src="http://s7.addthis.com/js/200/addthis_widget.js"&gt;&lt;/script&gt;&lt;/div&gt;&lt;!-- AddThis Button END --&gt;&lt;img src="http://blog.aspnet.sk/aggbug.aspx?PostID=55429" width="1" height="1"&gt;</description><category domain="http://blog.aspnet.sk/skippo/archive/tags/ASP.NET/default.aspx">ASP.NET</category><category domain="http://blog.aspnet.sk/skippo/archive/tags/double/default.aspx">double</category><category domain="http://blog.aspnet.sk/skippo/archive/tags/float/default.aspx">float</category><category domain="http://blog.aspnet.sk/skippo/archive/tags/2nd+Life/default.aspx">2nd Life</category><category domain="http://blog.aspnet.sk/skippo/archive/tags/.NET/default.aspx">.NET</category></item></channel></rss>