මුදල් නියෝජනය කිරීම සඳහා ද්විත්ව හෝ පාවෙන භාවිතා නොකරන්නේ ඇයි?


958

කිසි විටෙකත් මුදල් doubleහෝ floatවර්ග සමඟ මුදල් නියෝජනය නොකරන ලෙස මට නිතරම පවසා ඇති අතර , මේ වතාවේ මම ඔබට ප්‍රශ්නය අසමි: ඇයි?

ඉතා හොඳ හේතුවක් ඇති බව මට විශ්වාසයි, එය කුමක්දැයි මම නොදනිමි.


4
මෙම SO ප්‍රශ්නය බලන්න: වටකුරු දෝෂ?
ජෙෆ් ඔගාටා

81
පැහැදිලිව කිවහොත්, ඒවා නිරවද්‍යතාව අවශ්‍ය කිසිවක් සඳහා භාවිතා නොකළ යුතුය - මුදල් පමණක් නොවේ.
ජෙෆ්

155
නිරවද්‍යතාව අවශ්‍ය කිසිවක් සඳහා ඒවා භාවිතා නොකළ යුතුය . නමුත් ඩබල්ගේ සැලකිය යුතු බිටු 53 (dec 16 දශම ඉලක්කම්) සාමාන්‍යයෙන් නිරවද්‍යතාව අවශ්‍ය දේ සඳහා ප්‍රමාණවත් වේ .
dan04

23
@jeff ඔබේ අදහස් ද්විමය පාවෙන ලක්ෂ්‍යය සඳහා හොඳ කුමක්ද සහ එය හොඳ නැති දේ සම්පූර්ණයෙන්ම වැරදි ලෙස නිරූපණය කරයි. පහත දැක්වෙන zneak මගින් පිළිතුර කියවන්න, කරුණාකර ඔබේ නොමඟ යවන අදහස මකන්න.
පැස්කල් කියුක්

Answers:


1017

පාවෙන හා යුගල වශයෙන් අප මුදල් සඳහා භාවිතා කරන මූලික 10 ගුණකය නිවැරදිව නිරූපණය කළ නොහැකි බැවිනි. මෙම ගැටළුව ජාවා සඳහා පමණක් නොවේ, එය පදනම් 2 පාවෙන ලක්ෂ්‍ය වර්ග භාවිතා කරන ඕනෑම ක්‍රමලේඛන භාෂාවක් සඳහා වේ.

10 වන පාදයේ දී, ඔබට 10.25 1025 * 10 -2 ලෙස ලිවිය හැකිය (පූර්ණ සංඛ්‍යාවක් 10 ක බලයක් මෙන්). IEEE-754 පාවෙන ලක්ෂ්‍ය සංඛ්‍යා වෙනස් වේ, නමුත් ඒවා ගැන සිතීමට ඉතා සරල ක්‍රමයක් වන්නේ ඒ වෙනුවට දෙකක බලයකින් ගුණ කිරීමයි. නිදසුනක් ලෙස, ඔබ 164 * 2 -4 (පූර්ණ සංඛ්‍යා දෙකක බලයක් මෙන්) දෙස බැලිය හැකිය , එය 10.25 ට සමාන වේ. මතකයේ සංඛ්‍යා නිරූපණය වන්නේ එලෙස නොවේ, නමුත් ගණිත ඇඟවුම් සමාන වේ.

10 වන පාදයේ වුවද, මෙම අංකනයට බොහෝ සරල කොටස් නිවැරදිව නිරූපණය කළ නොහැක. උදාහරණයක් ලෙස, ඔබට 1/3 නියෝජනය කළ නොහැක: දශම නිරූපණය පුනරාවර්තනය වේ (0.3333 ...), එබැවින් 1/3 ලබා ගැනීම සඳහා ඔබට 10 ක බලයකින් ගුණ කළ හැකි සීමිත පූර්ණ සංඛ්‍යාවක් නොමැත. ඔබට 33 හි දිගු අනුක්‍රමයක් සහ 333333333 * 10 -10 වැනි කුඩා on ාතයක් මත පදිංචි විය හැකිය , නමුත් එය නිවැරදි නොවේ: ඔබ එය 3 න් ගුණ කළහොත් ඔබට 1 ක් නොලැබේ.

කෙසේ වෙතත්, මුදල් ගණනය කිරීමේ අරමුණ සඳහා, අවම වශයෙන් එක්සත් ජනපද ඩොලරයේ විශාලත්වය අනුව මුදල් වටිනාකමක් ඇති රටවල් සඳහා, සාමාන්‍යයෙන් ඔබට අවශ්‍ය වන්නේ 10 -2 ගුණක ගබඩා කිරීමට හැකි වීම පමණි , එබැවින් එය ඇත්ත වශයෙන්ම වැදගත් නොවේ 1/3 නිරූපණය කළ නොහැකි බව.

පාවෙන සහ යුගල පිළිබඳ ගැටළුව වන්නේ මුදල් වැනි සංඛ්‍යා වලින් බහුතරයකට පූර්ණ සංඛ්‍යා 2 ක බලයක් ලෙස නිශ්චිත නිරූපණයක් නොමැති වීමයි. ඇත්ත වශයෙන්ම, 0 සහ 1 අතර 0.01 හි එකම ගුණකය (ඒවා ගනුදෙනු කිරීමේදී වැදගත් වේ IEEE-754 ද්විමය පාවෙන ලක්ෂ්‍ය අංකයක් ලෙස නිරූපණය කළ හැකි 0, 0.25, 0.5, 0.75 සහ 1 ලෙස නිරූපණය කළ හැකි මුදල් සමඟ). අනෙක් සියල්ලම සුළු ප්‍රමාණයකින් අක්‍රීයයි. 0.333333 උදාහරණයට ප්‍රතිසමයක් ලෙස, ඔබ 0.1 සඳහා පාවෙන ලක්ෂ්‍ය අගය ගෙන 10 කින් ගුණ කළහොත් ඔබට 1 ක් නොලැබේ.

ලෙස මුදල් නියෝජනය doubleහෝ floatබොහෝ විට ඉතා කුඩා දෝෂ ඔබ්බෙන් වන මෘදුකාංග වට ලෙස පළමු හොඳ බලාපොරොත්තු වනු ඇත, නමුත් ඔබ අනිශ්චිත අංක පිළිබඳ වැඩි එකතු, subtractions, ගුණ හා බෙදීම් ඉටු ලෙස, දෝෂ, උග්ර කරනු ඇති අතර එවිට ඔබට නොපෙනෙන ලෙස බව වටිනාකම් සමග අවසන් කරන්නම් නිවැරදි නොවේ. මෙමඟින් මුදල් සමඟ ගනුදෙනු කිරීම සඳහා පාවෙන හා දෙගුණයක් ප්‍රමාණවත් නොවන අතර, මූලික 10 බලයේ ගුණකයන් සඳහා පරිපූර්ණ නිරවද්‍යතාවයක් අවශ්‍ය වේ.

ඕනෑම භාෂාවකින් ක්‍රියාත්මක වන විසඳුමක් නම් ඒ වෙනුවට පූර්ණ සංඛ්‍යා භාවිතා කර ශත ගණන් කිරීමයි. උදාහරණයක් ලෙස, 1025 ඩොලර් 10.25 ක් වනු ඇත. භාෂා කිහිපයකම මුදල් සමඟ ගනුදෙනු කිරීම සඳහා සාදන ලද වර්ග තිබේ. අනෙක් අය අතර, ජාවාට BigDecimalපන්තිය ඇති අතර , සී # decimalවර්ගය ඇත.


3
RanFran ඔබට වටකුරු දෝෂ ඇති වන අතර සමහර අවස්ථාවල විශාල මුදල් ප්‍රමාණයක් භාවිතා වන විට පොලී අනුපාත ගණනය කිරීම් අහෝසි කළ හැකිය
linuxuser27

5
... බොහෝ පාදක භාග 10, එනම්. උදාහරණයක් ලෙස, 0.1 ට නිශ්චිත ද්විමය පාවෙන ලක්ෂ්‍ය නිරූපණයක් නොමැත. එබැවින්, 1.0 / 10 * 101.0 ට සමාන නොවිය හැකිය.
ක්‍රිස් ජෙස්ටර්-යං

6
@ linuxuser27 මම හිතන්නේ ෆ්‍රාන් විහිලු කරන්න උත්සාහ කළා. කෙසේ වෙතත්, zneak ගේ පිළිතුර මම දුටු හොඳම දේ, බ්ලොච්ගේ සම්භාව්‍ය අනුවාදයට වඩා හොඳයි.
අයිසැක් රබිනොවිච්

5
ඇත්ත වශයෙන්ම ඔබ නිරවද්‍යතාවය දන්නේ නම්, ඔබට සෑම විටම ප්‍රති result ලය වටහා ගත හැකි අතර එමඟින් සමස්ත ගැටළුව මඟහරවා ගත හැකිය. මෙය බිග් ඩෙසිමල් භාවිතා කිරීමට වඩා වේගවත් හා සරල ය. තවත් විකල්පයක් වන්නේ ස්ථාවර නිරවද්‍ය int හෝ දිගු භාවිතා කිරීමයි.
පීටර් ලෝරි

2
තාර්කික සංඛ්‍යා තාත්වික සංඛ්‍යා වල උප කුලකයක් බව ඔබ දන්නවාද ? IEEE-754, තාත්වික සංඛ්යා වේ තාත්වික සංඛ්යා. ඔවුන් හුදෙක් සිදු තාර්කික විය.
ටිම් සෙගුයින්

317

බ්ලොච් වෙතින්, ජේ., Java ලදායී ජාවා, 2 වන සංස්කරණය, අයිතමය 48:

මෙම floatසහ doubleඑය ලෙස 0.1 (හෝ දහයක් වෙනත් ඕනෑම සෘණ බලය) නියෝජනය කිරීමට අපහසු නිසාය විශේෂයෙන් මූල්ය ගණනය කිරීම් සඳහා රෝගාතුර-වෙළෙඳපොළට ගැළපෙන වර්ග floatහෝ doubleහරියටම.

උදාහරණයක් ලෙස, ඔබ සතුව ඩොලර් 1.03 ක් ඇතැයි සිතමු. ඔබට කොපමණ මුදල් ඉතිරිව තිබේද?

System.out.println(1.03 - .42);

මුද්‍රණය කරයි 0.6100000000000001.

මෙම ගැටලුව විසඳීම සඳහා නිවැරදි මාර්ගය භාවිතා කිරීමට BigDecimal, intහෝ long මූල්ය ගණනය කිරීම් සඳහා.

BigDecimalසමහර අවවාද තිබුණත් (කරුණාකර දැනට පිළිගත් පිළිතුර බලන්න).


6
මුදල් ගණනය කිරීම් සඳහා int හෝ long භාවිතා කිරීමේ නිර්දේශය නිසා මම ටිකක් ව්‍යාකූල වී සිටිමි. 1.03 පූර්ණ හෝ දිගු ලෙස ඔබ නියෝජනය කරන්නේ කෙසේද? මම "දිගු a = 1.04;" සහ "දිගු a = 104/100;" කිසිදු .ලක් නැත.
පීටර්

50
Et පීටර්, ඔබ long a = 104ඩොලර් වෙනුවට ශත වලින් භාවිතා කර ගණන් කරන්න.
zneak

nezneak පොලී සංයුක්ත කිරීම හෝ ඒ හා සමාන ප්‍රතිශතයක් යෙදිය යුතු විට කුමක් කළ යුතුද?
trusktr

3
ustrusktr, මම ඔබේ වේදිකාවේ දශම වර්ගය සමඟ යන්නෙමි. ජාවා වල, ඒ BigDecimal.
zneak

13
amaaartinus ... ඒ වගේම එවැනි දේ සඳහා දෙගුණයක් භාවිතා කිරීම දෝෂ සහිත යැයි ඔබ සිතන්නේ නැද්ද? පාවෙන වටකුරු ගැටළුව සැබෑ පද්ධතිවලට තදින් පහර දෙන බව මම දැක ඇත්තෙමි . බැංකුකරණයේදී පවා. කරුණාකර එය නිර්දේශ නොකරන්න, නැතහොත් ඔබ එසේ කරන්නේ නම්, එය වෙනම පිළිතුරක් ලෙස සපයන්න (එබැවින් අපට එය අවතක්සේරු කළ හැකිය: P)
eis

76

මෙය නිරවද්‍යතාව පිළිබඳ කාරණයක් හෝ නිරවද්‍යතාව පිළිබඳ කාරණයක් නොවේ. 2 වන පදනම වෙනුවට ගණනය කිරීම් සඳහා 10 වන පදනම භාවිතා කරන මිනිසුන්ගේ අපේක්ෂාවන් සපුරාලීම කාරණයකි. නිදසුනක් වශයෙන්, මූල්‍ය ගණනය කිරීම් සඳහා යුගල භාවිතා කිරීම ගණිතමය අර්ථයෙන් “වැරදි” පිළිතුරු සපයන්නේ නැත, නමුත් එයට පිළිතුරු සැපයිය හැකිය මූල්‍යමය අර්ථයෙන් අපේක්ෂා කරන දේ නොවේ.

නිමැවුමට පෙර අවසාන මොහොතේදී ඔබ ඔබේ ප්‍රති results ල වට කර ගත්තද, අපේක්ෂාවන්ට නොගැලපෙන යුගල භාවිතා කරමින් ඔබට ඉඳහිට ප්‍රති result ලයක් ලබා ගත හැකිය.

කැල්කියුලේටරයක් ​​භාවිතා කිරීම හෝ ප්‍රති results ල අතින් ගණනය කිරීම හරියටම 1.40 * 165 = 231. කෙසේ වෙතත්, අභ්‍යන්තරව යුගල භාවිතා කිරීම, මගේ සම්පාදක / මෙහෙයුම් පද්ධති පරිසරය මත, එය 230.99999 ට ආසන්න ද්විමය අංකයක් ලෙස ගබඩා කර ඇත ... එබැවින් ඔබ එම අංකය කපා දැමුවහොත්, ඔබට 231 වෙනුවට 230 ලැබෙනු ඇත. 231 හි අපේක්ෂිත ප්‍රති result ලය ලබා දී ඇත. එය සත්‍යයකි, නමුත් වටය සෑම විටම කප්පාදු කිරීම සම්බන්ධ වේ. ඔබ භාවිතා කරන වටකුරු තාක්‍ෂණය කුමක් වුවත්, මේ වගේ මායිම් කොන්දේසි තවමත් පවතී. අනියම් පරීක්ෂණ හෝ නිරීක්ෂණ මගින් ඒවා බොහෝ විට සොයාගත නොහැකි තරම් දුර්ලභ ය. අපේක්ෂිත පරිදි හැසිරෙන්නේ නැති ප්‍රති come ල විදහා දක්වන උදාහරණ සෙවීම සඳහා ඔබට යම් කේතයක් ලිවීමට සිදු විය හැකිය.

ඔබට ළඟම ඇති සතයට යමක් වට කිරීමට අවශ්‍ය යැයි උපකල්පනය කරන්න. එබැවින් ඔබ ඔබේ අවසාන ප්‍රති result ලය ගන්න, 100 කින් ගුණ කරන්න, 0.5 එකතු කරන්න, කප්පාදු කරන්න, ඉන්පසු ප්‍රති result ලය 100 න් බෙදන්න. ඔබ ගබඩා කළ අභ්‍යන්තර අංකය 3.465 වෙනුවට 3.46499999 නම්, ඔබ එම අංකය ළඟම ඇති සතයට වට කරන විට 3.46 වෙනුවට 3.47 ලබා ගනී. නමුත් ඔබේ මූලික 10 ගණනය කිරීම් මඟින් පිළිතුර හරියටම 3.465 විය යුතු අතර, එය පැහැදිලිවම 3.47 දක්වා නොව 3.46 දක්වා විය යුතුය. මූල්‍යමය ගණනය කිරීම් සඳහා ඔබ දෙගුණයක් භාවිතා කරන විට සැබෑ ජීවිතයේ විටින් විට මෙවැනි දේ සිදු වේ. එය දුර්ලභ ය, එබැවින් එය බොහෝ විට ගැටලුවක් ලෙස නොදැනේ, නමුත් එය සිදු වේ.

ද්විත්ව වෙනුවට ඔබේ අභ්‍යන්තර ගණනය කිරීම් සඳහා ඔබ 10 වන පදනම භාවිතා කරන්නේ නම්, පිළිතුරු සැමවිටම මිනිසුන් අපේක්ෂා කරන දෙයම වේ, ඔබේ කේතයේ වෙනත් දෝෂ නොමැති බව උපකල්පනය කරයි.


3
ආශ්‍රිත, සිත්ගන්නාසුළු: මගේ ක්‍රෝම් js කොන්සෝලය තුළ: Math.round (.4999999999999999): 0 Math.round (.49999999999999999): 1
Curtis Yallop

16
මෙම පිළිතුර නොමඟ යවන සුළුය. 1.40 * 165 = 231. හරියටම 231 හැර වෙනත් ඕනෑම සංඛ්යාවක් වේ ගණිතමය අර්ථාන්විතය (සහ අනෙකුත් සියලු සංවේදනා) වැරදි.
කරු

2
Ar කරු මම හිතන්නේ රැන්ඩි පවසන්නේ පාවෙන නරක බවයි ... මගේ ක්‍රෝම් ජේඑස් කොන්සෝලය 230.99999999999997 පෙන්වයි. ඒ වන පිළිතුර දී සඳහන් කළ කරුණ වන වැරදි,.
trusktr

6
Ar කරු: ඉම්හෝ පිළිතුර ගණිතමය වශයෙන් වැරදිය. ප්‍රශ්න 2 ක් ඇති අතර එය අසනු ලබන ප්‍රශ්නය නොවේ. ඔබේ සම්පාදකයා පිළිතුරු දෙන ප්‍රශ්නය 1.39999999 * 164.99999999 වන අතර ගණිතමය වශයෙන් නිවැරදි 230.99999 ට සමාන වේ .... නිසැකවම එය මුලින් ඇසූ ප්‍රශ්නය නොවේ ....
මාර්කස්

2
UrtCurtisYallop ද්විත්ව අගය 0.49999999999999999 ට වසා ඇති නිසා 0.5 ක් ආපසු එන්නේ ඇයි Math.round(0.49999999999999994)?
phuclv

53

මෙම සමහර ප්‍රතිචාර නිසා මම කලබල වී සිටිමි. මූල්‍ය ගණනය කිරීම් වලදී ද්විත්ව හා පාවෙන ස්ථාන ඇති බව මම සිතමි. නියත වශයෙන්ම, භාගික නොවන මුදල් ප්‍රමාණයක් එකතු කිරීමේදී හා අඩු කිරීමේදී පූර්ණ සංඛ්‍යා පන්ති හෝ බිග් ඩෙසිමල් පන්ති භාවිතා කරන විට නිරවද්‍යතාව නැති නොවේ. නමුත් වඩාත් සංකීර්ණ මෙහෙයුම් සිදු කරන විට, ඔබ සංඛ්‍යා ගබඩා කරන්නේ කෙසේ වෙතත්, බොහෝ විට දශම ස්ථාන කිහිපයක් හෝ වැඩි ගණනක් ලබා දෙන ප්‍රති results ල සමඟ ඔබ අවසන් වේ. ගැටලුව වන්නේ ඔබ ප්‍රති .ලය ඉදිරිපත් කරන්නේ කෙසේද යන්නයි.

ඔබේ ප්‍රති result ලය වටකුරු හා වටකුරු අතර මායිමෙහි තිබේ නම් සහ අවසාන සතයක් ඇත්තෙන්ම වැදගත් නම්, ඔබ බොහෝ විට නරඹන්නාට පැවසිය යුත්තේ පිළිතුර ආසන්න වශයෙන් මැද - වැඩි දශම ස්ථාන පෙන්වීමෙනි.

ද්විත්ව හා තවත් බොහෝ දේ පාවෙන ගැටළුව වන්නේ ඒවා විශාල සංඛ්‍යා හා කුඩා සංඛ්‍යා ඒකාබද්ධ කිරීමට භාවිතා කරන විටය. ජාවා හි,

System.out.println(1000000.0f + 1.2f - 1000000.0f);

ප්‍රති results ල

1.1875

16
මෙය!!!! මෙම අදාළ සත්‍යය සොයා ගැනීම සඳහා මම සියලු පිළිතුරු සොයමින් සිටියෙමි !!! සාමාන්‍ය ගණනය කිරීම් වලදී ඔබ සතයෙන් යම් ප්‍රමාණයකට අයත් දැයි කිසිවෙකු ගණන් ගන්නේ නැත, නමුත් මෙහි ඉහළ සංඛ්‍යාවක් ඇති ගනුදෙනුවකට ඩොලර් කිහිපයක් පහසුවෙන් අහිමි වේ!
ෆැල්කෝ

22
දැන් යමෙකු ඩොලර් මිලියනයකට 0.01% ක දෛනික ආදායමක් ලබා ගනී යැයි සිතන්න - ඔහුට සෑම දිනකම කිසිවක් නොලැබෙනු ඇත - වසරකට පසු ඔහුට ඩොලර් 1000 ක් උපයා නැත, මෙම අභිප්‍රාය
ෆැල්කෝ

6
ගැටළුව නිරවද්‍යතාවය නොවේ, නමුත් එම පාවීම එය සාවද්‍ය බවට ඔබට නොකියයි. පූර්ණ සංඛ්‍යාවකට සාවද්‍ය නොවී පාවෙන 6 ක් දක්වා රඳවා තබා ගත හැක්කේ ඉලක්කම් 10 ක් පමණි (ඔබ ඒ අනුව එය කපන විට). පූර්ණ සංඛ්‍යාවක් පිටාර ගැලීමක් ලබා ගන්නා අතර ජාවා වැනි භාෂාවක් ඔබට අනතුරු අඟවයි හෝ එයට ඉඩ නොදේ. ඔබ දෙගුණයක් භාවිතා කරන විට, ඔබට ඉලක්කම් 16 ක් දක්වා යා හැකිය, එය බොහෝ භාවිත අවස්ථා සඳහා ප්‍රමාණවත් වේ.
sigi

39

පාවෙන සහ යුගල වශයෙන් දළ වශයෙන් වේ. ඔබ බිග් ඩෙසිමල් එකක් සාදා ඉදිකිරීම්කරු වෙත පාවීමක් ලබා දෙන්නේ නම්, පාවෙන ඇත්ත වශයෙන්ම සමාන වන්නේ කුමක්දැයි ඔබට පෙනේ:

groovy:000> new BigDecimal(1.0F)
===> 1
groovy:000> new BigDecimal(1.01F)
===> 1.0099999904632568359375

මෙය ඔබට $ 1.01 නියෝජනය කිරීමට අවශ්‍ය වන්නේ නැත.

ගැටළුව වන්නේ අයිඊඊඊ පිරිවිතරයට සියලු භාගයන් හරියටම නිරූපණය කිරීමට ක්‍රමයක් නොමැති වීමයි, ඒවායින් සමහරක් පුනරාවර්තන අතුරු කොටස් ලෙස අවසන් වන අතර එමඟින් ඔබ ආසන්න වශයෙන් දෝෂ වලින් අවසන් වේ. ගණකාධිකාරිවරු හරියටම සතයක් පිටතට පැමිණීමට කැමති නිසාත්, ඔවුන්ගේ බිල්පත ගෙවා ගනුදෙනුකරුවන් කෝපයට පත් වන නිසාත්, ගෙවීම සැකසූ පසු ඔවුන් ගෙවිය යුතු මුදල .01 වන අතර ඔවුන්ට ගාස්තුවක් අය කිරීම හෝ ඔවුන්ගේ ගිණුම වැසීමට නොහැකි වීම, භාවිතා කිරීම වඩා හොඳය ජාවා හි දශම (C # වලින්) හෝ java.math.BigDecimal වැනි නිශ්චිත වර්ග.

ඔබ වටේ ගියහොත් දෝෂය පාලනය කළ නොහැකි බව නොවේ: පීටර් ලෝරිගේ මෙම ලිපිය බලන්න . මුලින් වටේ නොයෑම පහසුය. මුදල් හසුරුවන බොහෝ යෙදුම් විශාල ගණිතයක් ඉල්ලා නොසිටින අතර, මෙහෙයුම් වලින් දේවල් එකතු කිරීම හෝ විවිධ බාල්දි සඳහා මුදල් වෙන් කිරීම ඇතුළත් වේ. පාවෙන ලක්ෂ්‍යය හඳුන්වා දීම සහ වටකුරු කිරීම දේවල් සංකීර්ණ කරයි.


6
float, doubleසහ නිශ්චිත අගයන් BigDecimalනියෝජනය කරයි . වස්තුව පරිවර්තනය කිරීමේ කේතය නිරවද්‍ය මෙන්ම වෙනත් මෙහෙයුම් ද වේ. වර්ගයන්ම නිරවද්‍ය නොවේ.
chux - මොනිකා

1
@chux: මෙය නැවත කියවීමෙන්, මගේ වචන වැඩි දියුණු කළ හැකි යැයි ඔබට සිතේ. මම මෙය සංස්කරණය කර නැවත කියමි.
නේතන් හියුස්

33

මම අවතක්සේරු කිරීමේ අවදානමක් ඇත, නමුත් මුදල් ගණනය කිරීම් සඳහා පාවෙන ලක්ෂ්‍ය අංකවල නුසුදුසුකම ඉක්මවා යයි මම සිතමි. Zneak විසින් පැහැදිලි කරන ලද ද්විමය-දශම නිරූපණ නොගැලපීම මැඩපැවැත්වීම සඳහා ඔබ සෙන්ටිමීටර නිවැරදිව සිදු කරන බවටත්, වැඩ කිරීමට ප්‍රමාණවත් තරම් ඉලක්කම් ඇති බවත් ඔබ සහතික කරන තාක් කල්, කිසිදු ගැටළුවක් ඇති නොවනු ඇත.

එක්සෙල් හි මුදල් සමඟ ගණනය කරන පුද්ගලයින් සෑම විටම ද්විත්ව නිරවද්‍යතා පාවෙන භාවිතා කර ඇත (එක්සෙල් හි මුදල් වර්ගයක් නොමැත) සහ වටකුරු දෝෂ පිළිබඳව කිසිවෙකු පැමිණිලි කරන බවක් මා දැක නැත.

ඇත්ත වශයෙන්ම, ඔබ තර්කානුකූලව සිටිය යුතුය; උදා: සරල වෙබ් සාප්පුවක් කිසි විටෙකත් ද්විත්ව නිරවද්‍යතාවයකින් යුත් පාවෙන ගැටළු ඇති නොවනු ඇත, නමුත් ඔබ උදා: ගිණුම්කරණය හෝ විශාල (සීමා රහිත) සංඛ්‍යාවක් එකතු කිරීමට අවශ්‍ය වෙනත් දෙයක් කරන්නේ නම්, ඔබට අඩි දහයක් සහිත පාවෙන ලක්ෂ්‍ය අංක ස්පර්ශ කිරීමට අවශ්‍ය නොවනු ඇත. ධ්රැවය.


3
මෙය සැබවින්ම හොඳ පිළිතුරකි. බොහෝ අවස්ථාවන්හීදී ඒවා භාවිතා කිරීම ඉතා සුදුසුය.
වහීඩ් අමිරි

3
බොහෝ ආයෝජන බැංකු බොහෝ C ++ වැඩසටහන් මෙන් දෙගුණයක් භාවිතා කරන බව සැලකිල්ලට ගත යුතුය. සමහර ඒවා දිගු කාලයක් භාවිතා කරන නමුත් එමඟින් එය ලුහුබැඳීමේ පරිමාණයේ ගැටලුවක් ඇත.
පීටර් ලෝරි

20

පාවෙන ලක්ෂ්‍ය වර්ගයට ආසන්න වශයෙන් දශම දත්ත පමණක් නිරූපණය කළ හැකි බව සත්‍යයක් වන අතර, ඒවා ඉදිරිපත් කිරීමට පෙර අවශ්‍ය නිරවද්‍යතාවයට එක් වටයක් සංඛ්‍යා කළහොත් යමෙක් නිවැරදි ප්‍රති .ලය ලබා ගනී. සාමාන්යයෙන්.

සාමාන්‍යයෙන් ද්විත්ව වර්ගයේ නිරවද්‍යතාව සංඛ්‍යා 16 ට වඩා අඩු නිසා. ඔබට වඩා හොඳ නිරවද්‍යතාවයක් අවශ්‍ය නම් එය සුදුසු වර්ගයක් නොවේ. දළ විශ්ලේෂණයන් ද රැස් කර ගත හැකිය.

ඔබ ස්ථාවර ලක්ෂ්‍ය ගණිතයක් භාවිතා කළත් ඔබට තවමත් සංඛ්‍යා වට කළ යුතු බව පැවසිය යුතුය. ඔබ වරින් වර දශම සංඛ්‍යා ලබා ගන්නේ නම් බිග් ඉන්ටෙගර් සහ බිග් ඩෙසිමල් දෝෂ ලබා දෙයි. එබැවින් මෙහි දළ විශ්ලේෂණයක් ද ඇත.

උදාහරණයක් ලෙස මූල්‍ය ගණනය කිරීම් සඳහා histor තිහාසිකව භාවිතා කරන COBOL හි උපරිම නිරවද්‍යතාව සංඛ්‍යා 18 කි. එබැවින් බොහෝ විට ව්‍යංග වටරවුමක් ඇත.

නිගමනය නම්, දෙගුණයක් එහි ඉලක්කම් 16 ක නිරවද්‍යතාවයට බොහෝ දුරට නුසුදුසු වන අතර එය ප්‍රමාණවත් නොවිය හැකිය, එය ආසන්න වශයෙන් නිසා නොවේ.

පසුකාලීන වැඩසටහනේ පහත ප්‍රතිදානය සලකා බලන්න. එය පෙන්වන්නේ ද්විත්ව වටයකින් පසු බිග් ඩෙසිමල්ගේ ප්‍රති result ලය නිරවද්‍යතාව 16 දක්වා ලබා දෙන බවයි.

Precision 14
------------------------------------------------------
BigDecimalNoRound             : 56789.012345 / 1111111111 = Non-terminating decimal expansion; no exact representable decimal result.
DoubleNoRound                 : 56789.012345 / 1111111111 = 5.111011111561101E-5
BigDecimal                    : 56789.012345 / 1111111111 = 0.000051110111115611
Double                        : 56789.012345 / 1111111111 = 0.000051110111115611

Precision 15
------------------------------------------------------
BigDecimalNoRound             : 56789.012345 / 1111111111 = Non-terminating decimal expansion; no exact representable decimal result.
DoubleNoRound                 : 56789.012345 / 1111111111 = 5.111011111561101E-5
BigDecimal                    : 56789.012345 / 1111111111 = 0.0000511101111156110
Double                        : 56789.012345 / 1111111111 = 0.0000511101111156110

Precision 16
------------------------------------------------------
BigDecimalNoRound             : 56789.012345 / 1111111111 = Non-terminating decimal expansion; no exact representable decimal result.
DoubleNoRound                 : 56789.012345 / 1111111111 = 5.111011111561101E-5
BigDecimal                    : 56789.012345 / 1111111111 = 0.00005111011111561101
Double                        : 56789.012345 / 1111111111 = 0.00005111011111561101

Precision 17
------------------------------------------------------
BigDecimalNoRound             : 56789.012345 / 1111111111 = Non-terminating decimal expansion; no exact representable decimal result.
DoubleNoRound                 : 56789.012345 / 1111111111 = 5.111011111561101E-5
BigDecimal                    : 56789.012345 / 1111111111 = 0.000051110111115611011
Double                        : 56789.012345 / 1111111111 = 0.000051110111115611013

Precision 18
------------------------------------------------------
BigDecimalNoRound             : 56789.012345 / 1111111111 = Non-terminating decimal expansion; no exact representable decimal result.
DoubleNoRound                 : 56789.012345 / 1111111111 = 5.111011111561101E-5
BigDecimal                    : 56789.012345 / 1111111111 = 0.0000511101111156110111
Double                        : 56789.012345 / 1111111111 = 0.0000511101111156110125

Precision 19
------------------------------------------------------
BigDecimalNoRound             : 56789.012345 / 1111111111 = Non-terminating decimal expansion; no exact representable decimal result.
DoubleNoRound                 : 56789.012345 / 1111111111 = 5.111011111561101E-5
BigDecimal                    : 56789.012345 / 1111111111 = 0.00005111011111561101111
Double                        : 56789.012345 / 1111111111 = 0.00005111011111561101252

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.math.MathContext;

public class Exercise {
    public static void main(String[] args) throws IllegalArgumentException,
            SecurityException, IllegalAccessException,
            InvocationTargetException, NoSuchMethodException {
        String amount = "56789.012345";
        String quantity = "1111111111";
        int [] precisions = new int [] {14, 15, 16, 17, 18, 19};
        for (int i = 0; i < precisions.length; i++) {
            int precision = precisions[i];
            System.out.println(String.format("Precision %d", precision));
            System.out.println("------------------------------------------------------");
            execute("BigDecimalNoRound", amount, quantity, precision);
            execute("DoubleNoRound", amount, quantity, precision);
            execute("BigDecimal", amount, quantity, precision);
            execute("Double", amount, quantity, precision);
            System.out.println();
        }
    }

    private static void execute(String test, String amount, String quantity,
            int precision) throws IllegalArgumentException, SecurityException,
            IllegalAccessException, InvocationTargetException,
            NoSuchMethodException {
        Method impl = Exercise.class.getMethod("divideUsing" + test, String.class,
                String.class, int.class);
        String price;
        try {
            price = (String) impl.invoke(null, amount, quantity, precision);
        } catch (InvocationTargetException e) {
            price = e.getTargetException().getMessage();
        }
        System.out.println(String.format("%-30s: %s / %s = %s", test, amount,
                quantity, price));
    }

    public static String divideUsingDoubleNoRound(String amount,
            String quantity, int precision) {
        // acceptance
        double amount0 = Double.parseDouble(amount);
        double quantity0 = Double.parseDouble(quantity);

        //calculation
        double price0 = amount0 / quantity0;

        // presentation
        String price = Double.toString(price0);
        return price;
    }

    public static String divideUsingDouble(String amount, String quantity,
            int precision) {
        // acceptance
        double amount0 = Double.parseDouble(amount);
        double quantity0 = Double.parseDouble(quantity);

        //calculation
        double price0 = amount0 / quantity0;

        // presentation
        MathContext precision0 = new MathContext(precision);
        String price = new BigDecimal(price0, precision0)
                .toString();
        return price;
    }

    public static String divideUsingBigDecimal(String amount, String quantity,
            int precision) {
        // acceptance
        BigDecimal amount0 = new BigDecimal(amount);
        BigDecimal quantity0 = new BigDecimal(quantity);
        MathContext precision0 = new MathContext(precision);

        //calculation
        BigDecimal price0 = amount0.divide(quantity0, precision0);

        // presentation
        String price = price0.toString();
        return price;
    }

    public static String divideUsingBigDecimalNoRound(String amount, String quantity,
            int precision) {
        // acceptance
        BigDecimal amount0 = new BigDecimal(amount);
        BigDecimal quantity0 = new BigDecimal(quantity);

        //calculation
        BigDecimal price0 = amount0.divide(quantity0);

        // presentation
        String price = price0.toString();
        return price;
    }
}

15

පාවෙන ලක්ෂ්‍ය අංකයේ ප්‍රති result ලය නිශ්චිත නොවේ, එමඟින් නිශ්චිත ප්‍රති result ල අවශ්‍ය වන සහ ආසන්න වශයෙන් නොව ඕනෑම මූල්‍ය ගණනය කිරීමකට නුසුදුසු වේ. float සහ double සැලසුම් කර ඇත්තේ ඉංජිනේරු සහ විද්‍යාත්මක ගණනය කිරීම් සඳහා වන අතර බොහෝ විට නිශ්චිත ප්‍රති result ල නොලැබේ. පාවෙන ලක්ෂ්‍ය ගණනය කිරීමේ ප්‍රති result ලය JVM සිට JVM දක්වා වෙනස් විය හැකිය. මුදල් වටිනාකම නිරූපණය කිරීම සඳහා භාවිතා කරන බිග් ඩෙසිමල් සහ ද්විත්ව ප්‍රාථමික පිළිබඳ පහත උදාහරණය දෙස බලන්න, පාවෙන ලක්ෂ්‍ය ගණනය කිරීම හරියටම නොවිය හැකි බවත් මූල්‍ය ගණනය කිරීම් සඳහා යමෙකු බිග් ඩෙසිමල් භාවිතා කළ යුතු බවත් පැහැදිලිය.

    // floating point calculation
    final double amount1 = 2.0;
    final double amount2 = 1.1;
    System.out.println("difference between 2.0 and 1.1 using double is: " + (amount1 - amount2));

    // Use BigDecimal for financial calculation
    final BigDecimal amount3 = new BigDecimal("2.0");
    final BigDecimal amount4 = new BigDecimal("1.1");
    System.out.println("difference between 2.0 and 1.1 using BigDecimal is: " + (amount3.subtract(amount4)));

ප්‍රතිදානය:

difference between 2.0 and 1.1 using double is: 0.8999999999999999
difference between 2.0 and 1.1 using BigDecimal is: 0.9

3
සුළු එකතු කිරීම / අඩු කිරීම සහ නිඛිල මුට්ලිකයිටෝන් හැර වෙනත් දෙයක් අපි උත්සාහ කරමු, කේතය 7% ක ණයක් සඳහා මාසික අනුපාතය ගණනය කළහොත්, වර්ග දෙකටම නිශ්චිත අගයක් ලබා දීමට අපොහොසත් විය යුතු අතර ආසන්නතම 0.01 වෙත වටය අවශ්‍ය වේ. අවම මුදල් ඒකකයට වට කිරීම මුදල් ගණනය කිරීම්වල කොටසකි, දශම වර්ග භාවිතා කිරීම එකතු කිරීම / අඩු කිරීම සමඟ එම අවශ්‍යතාව මඟහරවා ගනී - නමුත් වෙනත් බොහෝ දේ නොවේ.
chux - මොනිකා නැවත ස්ථාපනය කරන්න

ux chux-ReinstateMonica: පොළිය මාසිකව සංයුක්ත කිරීමට අදහස් කරන්නේ නම්, දෛනික ශේෂය එකතු කරමින් සෑම මසකම පොළිය ගණනය කරන්න, එය 7 කින් වැඩි කරන්න (පොලී අනුපාතය), සහ බෙදන්න, ළඟම ඇති සතයට වටය, දින ගණන අනුව වසර. අවසාන පියවරේදී මසකට එක් වරක් හැර වෙනත් තැනක වටයක් නොමැත.
සුපර් කැට්

uppupercat මගේ අදහස් මගින් අවධාරණය කරනුයේ කුඩාම මූල්‍ය ඒකකයේ ද්විමය එෆ්.පී. හෝ දශම එෆ්.පී. බේස් 2 හෝ බේස් 10 එෆ්පී භාවිතා කිරීමෙන් ඔබේ තත්වය තුළ වාසියක් නොලැබේ.
chux - මොනිකා නැවත ස්ථාපනය කරන්න

ux chux-ReinstateMonica: ඉහත තත්වය තුළ, පොළිය හරියටම ශත භාගයකට සමාන විය යුතු යැයි ගණිතය ක්‍රියා කරන්නේ නම්, නිවැරදි මූල්‍ය වැඩසටහනක් නිශ්චිතව දක්වා ඇති ආකාරයට වට කළ යුතුය. පාවෙන ලක්ෂ්‍ය ගණනය කිරීම් මගින් උදා: $ 1.23499941 ක පොලී අගයක් ලබා දෙයි, නමුත් වටයට පෙර ගණිතමය වශයෙන් නිවැරදි වටිනාකම ඩොලර් 1.235 ක් විය යුතු අතර වටය “ආසන්නතම ඉරට්ටේ” ලෙස දක්වා තිබේ නම්, එවැනි පාවෙන ලක්ෂ්‍ය ගණනය කිරීම් භාවිතා කිරීමෙන් ප්‍රති result ලය නොලැබේ off 0.000059 කින් ඉවත් වන්න, නමුත් සමස්ත $ 0.01 කින්, ගිණුම්කරණ අරමුණු සඳහා Just Plain Wrong.
සුපර් කැට්

ද්විමය භාවිතා කරමින් @supercat doubleෆෙඩරල් පක්ෂයට දශාංශික ඇත වත් ලෙස සියයට ෆෙඩරල් පක්ෂයට කිසිදු කරදර 0.5 සියයට ගණනය සිදු වනු ඇත. පාවෙන ලක්ෂ්‍ය ගණනය කිරීම් මඟින් උදා: 123.499941 of ක පොලී අගයක් ලබා දෙන්නේ නම්, ද්විමය එෆ්පී හෝ දශම එෆ්පී හරහා නම්, ද්විත්ව වටකුරු ගැටළුව සමාන වේ - කිසිදු ආකාරයකින් වාසියක් නැත. ඔබේ පරිශ්‍රය ගණිතමය වශයෙන් නිවැරදි අගය උපකල්පනය කරන අතර දශම FP එක සමාන වේ - දශම FP පවා සහතික නොකරයි. 0.5 / 7.0 * 7.0 යනු ද්විමය හා ඩයික්මාල් එෆ්පී සඳහා ගැටළුවකි. අයිඒසී, සී හි ඊළඟ අනුවාදය දශම එෆ්පී ලබා දෙනු ඇතැයි මා අපේක්ෂා කරන පරිදි බොහෝමයක් වෙනස් වනු ඇත.
chux - මොනිකා නැවත ස්ථාපනය කරන්න

11

කලින් පවසා ඇති පරිදි, මෘදුකාංගය කුඩා දෝෂයන්ගෙන් මිදෙන විට මුලින් මුදල් දෙගුණයක් හෝ පාවීමක් ලෙස නිරූපණය කිරීම හොඳ වනු ඇත, නමුත් ඔබ නිරවද්‍ය සංඛ්‍යා මත තවත් එකතු කිරීම්, අඩු කිරීම්, ගුණ කිරීම් සහ බෙදීම් සිදු කරන විට, ඔබට වැඩි වැඩියෙන් නිරවද්‍යතාවය අහිමි වේ දෝෂ එකතු වන විට, මෙය මුදල් සමඟ ගනුදෙනු කිරීම සඳහා පාවෙන හා දෙගුණයක් ප්‍රමාණවත් නොවන අතර, මූලික 10 බලයේ ගුණකයන් සඳහා පරිපූර්ණ නිරවද්‍යතාවයක් අවශ්‍ය වේ.

අවසාන වශයෙන් ජාවාට මුදල් හා මුදල් සමඟ වැඩ කිරීමට සම්මත ක්‍රමයක් තිබේ!

JSR 354: මුදල් සහ මුදල් API

JSR 354 මුදල් සහ මුදල් සමඟ සවිස්තරාත්මක ගණනය කිරීම් නියෝජනය කිරීම, ප්‍රවාහනය කිරීම සහ සිදු කිරීම සඳහා API සපයයි. ඔබට මෙම සබැඳියෙන් එය බාගත හැකිය:

JSR 354: මුදල් සහ මුදල් API බාගත කිරීම

පිරිවිතර පහත සඳහන් දේවලින් සමන්විත වේ:

  1. උදා: මුදල් හා මුදල් හැසිරවීමේ API
  2. හුවමාරු කළ හැකි ක්‍රියාත්මක කිරීම් සඳහා සහාය වන API
  3. ක්‍රියාත්මක කිරීමේ පන්තිවල අවස්ථා නිර්මාණය කිරීම සඳහා කර්මාන්තශාලා
  4. මුදල් ප්‍රමාණයන් ගණනය කිරීම, පරිවර්තනය කිරීම සහ හැඩතල ගැන්වීම සඳහා ක්‍රියාකාරීත්වය
  5. ජාවා 9 හි ඇතුළත් කිරීමට සැලසුම් කර ඇති මුදල් සහ මුදල් සමඟ වැඩ කිරීම සඳහා ජාවා ඒපීඅයි.
  6. සියලුම පිරිවිතර පන්ති සහ අතුරුමුහුණත් javax.money හි පිහිටා ඇත. * පැකේජය.

JSR 354 හි නියැදි උදාහරණ: මුදල් සහ මුදල් API:

MonitAmount නිර්මාණය කර එය කොන්සෝලය වෙත මුද්‍රණය කිරීමේ උදාහරණයක් ලෙස පෙනේ:

MonetaryAmountFactory<?> amountFactory = Monetary.getDefaultAmountFactory();
MonetaryAmount monetaryAmount = amountFactory.setCurrency(Monetary.getCurrency("EUR")).setNumber(12345.67).create();
MonetaryAmountFormat format = MonetaryFormats.getAmountFormat(Locale.getDefault());
System.out.println(format.format(monetaryAmount));

යොමු ක්‍රියාත්මක කිරීමේ API භාවිතා කරන විට, අවශ්‍ය කේතය වඩාත් සරල ය:

MonetaryAmount monetaryAmount = Money.of(12345.67, "EUR");
MonetaryAmountFormat format = MonetaryFormats.getAmountFormat(Locale.getDefault());
System.out.println(format.format(monetaryAmount));

API ද මුදල් ගණනය කිරීම් සමඟ ගණනය කිරීම් සඳහා සහය දක්වයි:

MonetaryAmount monetaryAmount = Money.of(12345.67, "EUR");
MonetaryAmount otherMonetaryAmount = monetaryAmount.divide(2).add(Money.of(5, "EUR"));

මුදල් ඒකකය සහ මුදල් මුදල

// getting CurrencyUnits by locale
CurrencyUnit yen = MonetaryCurrencies.getCurrency(Locale.JAPAN);
CurrencyUnit canadianDollar = MonetaryCurrencies.getCurrency(Locale.CANADA);

පවරන ලද මුදල්, සංඛ්‍යාත්මක මුදල, එහි නිරවද්‍යතාවය සහ තවත් දේ වෙත ප්‍රවේශ වීමට ඉඩ සලසන විවිධ ක්‍රම මූල්‍ය අණු සතුව ඇත:

MonetaryAmount monetaryAmount = Money.of(123.45, euro);
CurrencyUnit currency = monetaryAmount.getCurrency();
NumberValue numberValue = monetaryAmount.getNumber();

int intValue = numberValue.intValue(); // 123
double doubleValue = numberValue.doubleValue(); // 123.45
long fractionDenominator = numberValue.getAmountFractionDenominator(); // 100
long fractionNumerator = numberValue.getAmountFractionNumerator(); // 45
int precision = numberValue.getPrecision(); // 5

// NumberValue extends java.lang.Number.
// So we assign numberValue to a variable of type Number
Number number = numberValue;

වටකුරු ක්‍රියාකරුවෙකු භාවිතයෙන් මුදල් ගණනය කළ හැකිය:

CurrencyUnit usd = MonetaryCurrencies.getCurrency("USD");
MonetaryAmount dollars = Money.of(12.34567, usd);
MonetaryOperator roundingOperator = MonetaryRoundings.getRounding(usd);
MonetaryAmount roundedDollars = dollars.with(roundingOperator); // USD 12.35

MonitiAmounts එකතු කිරීම සමඟ වැඩ කරන විට, පෙරීම, වර්ග කිරීම සහ කණ්ඩායම් කිරීම සඳහා හොඳ උපයෝගීතා ක්‍රම කිහිපයක් තිබේ.

List<MonetaryAmount> amounts = new ArrayList<>();
amounts.add(Money.of(2, "EUR"));
amounts.add(Money.of(42, "USD"));
amounts.add(Money.of(7, "USD"));
amounts.add(Money.of(13.37, "JPY"));
amounts.add(Money.of(18, "USD"));

අභිරුචි මූල්‍ය ගිණුම් මෙහෙයුම්

// A monetary operator that returns 10% of the input MonetaryAmount
// Implemented using Java 8 Lambdas
MonetaryOperator tenPercentOperator = (MonetaryAmount amount) -> {
    BigDecimal baseAmount = amount.getNumber().numberValue(BigDecimal.class);
    BigDecimal tenPercent = baseAmount.multiply(new BigDecimal("0.1"));
    return Money.of(tenPercent, amount.getCurrency());
};

MonetaryAmount dollars = Money.of(12.34567, "USD");

// apply tenPercentOperator to MonetaryAmount
MonetaryAmount tenPercentDollars = dollars.with(tenPercentOperator); // USD 1.234567

සම්පත්:

JSR 354 සමඟ ජාවා හි මුදල් සහ මුදල් හැසිරවීම

ජාවා 9 මුදල් හා මුදල් ඒපීඅයි (ජේඑස්ආර් 354) සොයා බැලීම

මෙයද බලන්න: JSR 354 - මුදල් සහ මුදල්


5

ඔබේ ගණනය කිරීම සඳහා විවිධ පියවරයන් ඇතුළත් නම්, අත්තනෝමතික නිරවද්‍ය ගණිතය ඔබව 100% ක් ආවරණය නොකරයි.

ප්‍රති results ලවල පරිපූර්ණ නිරූපණයක් භාවිතා කිරීමට ඇති එකම විශ්වාසදායක ක්‍රමය (බෙදීම් මෙහෙයුම් අවසාන පියවර දක්වා කාණ්ඩගත කරන අභිරුචි භාග දත්ත වර්ගයක් භාවිතා කරන්න) සහ අවසාන පියවරේදී දශම අංකනය බවට පරිවර්තනය කිරීම පමණි.

අත්තනෝමතික නිරවද්‍යතාව උදව් නොවනු ඇත, මන්ද සෑම විටම බොහෝ දශම ස්ථාන ඇති සංඛ්‍යා තිබිය හැකි නිසා හෝ සමහර ප්‍රති results ල වැනි 0.6666666... අත්තනෝමතික නියෝජනයක් අවසාන උදාහරණය ආවරණය නොකරයි. එබැවින් සෑම පියවරකදීම ඔබට කුඩා දෝෂ ඇතිවේ.

මෙම දෝෂ එකතු කිරීම, අවසානයේදී නොසලකා හැරීම පහසු නොවනු ඇත. මෙය දෝෂ ප්‍රචාරණය ලෙස හැඳින්වේ .


4

බොහෝ පිළිතුරු මගින් මුදල් හා මුදල් ගණනය කිරීම් සඳහා දෙගුණයක් භාවිතා නොකිරීමට හේතු පෙන්වා දී ඇත. මම ඔවුන් සමඟ සම්පූර්ණයෙන්ම එකඟ වෙමි.

ඒ සඳහා දෙවරක් භාවිතා කළ නොහැකි බව එයින් අදහස් නොවේ.

මම ඉතා අඩු gc අවශ්‍යතා සහිත ව්‍යාපෘති ගණනාවක වැඩ කර ඇති අතර, BigDecimal වස්තු තිබීම එම පොදු කාර්යයට විශාල දායකත්වයක් සපයයි.

මෙම නැණවත් යෝජනාව ගෙන එන ද්විත්ව නිරූපණය පිළිබඳ අවබෝධය නොමැතිකම සහ නිරවද්‍යතාව සහ නිරවද්‍යතාව හැසිරවීමේ අත්දැකීම් නොමැතිකම ය.

ඔබේ ව්‍යාපෘතියේ නිරවද්‍යතාව සහ නිරවද්‍යතා අවශ්‍යතා හසුරුවා ගැනීමට ඔබට හැකි නම් ඔබට එය ක්‍රියාත්මක කළ හැකිය, එය කළ යුත්තේ එක් ද්විත්ව අගයන් පරාසයක් සමඟ ගනුදෙනු කිරීමෙනි.

වැඩි අදහසක් ලබා ගැනීම සඳහා ඔබට guava හි FuzzyCompare ක්‍රමය වෙත යොමු විය හැකිය. පරාමිති ඉවසීම යතුරයි. සුරැකුම්පත් වෙළඳ යෙදුමක් සඳහා අපි මෙම ගැටළුව සමඟ කටයුතු කළ අතර විවිධ පරාසයන්හි විවිධ සංඛ්‍යාත්මක අගයන් සඳහා භාවිතා කළ යුතු ඉවසීම් මොනවාද යන්න පිළිබඳව අපි පරිපූර්ණ පර්යේෂණයක් කළෙමු.

එසේම, හැෂ් සිතියම ක්‍රියාත්මක කිරීම සමඟ සිතියම් යතුරක් ලෙස ද්විත්ව එතීම් භාවිතා කිරීමට ඔබ පෙළඹෙන අවස්ථාද තිබිය හැකිය. එය ඉතා අවදානම් සහගත බැවින් "0.5" සහ "0.6 - 0.1" අගයන් සඳහා Double.equals සහ හැෂ් කේතය විශාල අවුලක් ඇති කරයි.


2

මෙම ප්‍රශ්නයට පළ කරන ලද බොහෝ පිළිතුරු IEEE සහ පාවෙන ලක්ෂ්‍ය අංක ගණිතය වටා ඇති ප්‍රමිතීන් සාකච්ඡා කරයි.

පරිගණක නොවන විද්‍යා පසුබිමකින් (භෞතික විද්‍යාව හා ඉංජිනේරු විද්‍යාව) මම වෙනත් දෘෂ්ටිකෝණයකින් ගැටලු දෙස බැලීමට නැඹුරු වෙමි. මට නම්, මම ගණිතමය ගණනය කිරීමක දී දෙගුණයක් හෝ පාවීමක් භාවිතා නොකිරීමට හේතුව මට ඕනෑවට වඩා තොරතුරු නැති වීමයි.

විකල්ප මොනවාද? බොහෝ දේ ඇත (සහ තවත් බොහෝ දේ මම නොදනිමි!).

ජාවා හි බිග් ඩෙසිමල් ජාවා භාෂාවට ආවේණිකය. Apfloat යනු ජාවා සඳහා තවත් අත්තනෝමතික-නිරවද්‍ය පුස්තකාලයකි.

C # හි ඇති දශම දත්ත වර්ගය මයික්‍රොසොෆ්ට් හි .NET විකල්පයයි.

SciPy (Scientific Python) හට බොහෝ විට මූල්‍ය ගණනය කිරීම් ද කළ හැකිය (මම උත්සාහ කර නැත, නමුත් මම එසේ සැක කරමි).

GNU බහු නිරවද්‍ය පුස්තකාලය (GMP) සහ GNU MFPR පුස්තකාලය යනු C සහ C ++ සඳහා නිදහස් හා විවෘත මූලාශ්‍ර සම්පත් දෙකකි.

ජාවාස්ක්‍රිප්ට් (!) සඳහා සංඛ්‍යාත්මක නිරවද්‍යතා පුස්තකාල ද ඇති අතර මූල්‍ය ගණනය කිරීම් හැසිරවිය හැකි PHP ලෙස මම සිතමි.

බොහෝ පරිගණක භාෂා සඳහා හිමිකාරීත්වය (විශේෂයෙන්, ෆෝට්රාන් සඳහා) සහ විවෘත-මූලාශ්‍ර විසඳුම් ද ඇත.

මම පරිගණක විද්‍යා scient යෙක් නොවේ. කෙසේ වෙතත්, මම ජාවා හි බිග් ඩෙසිමල් හෝ සී # හි දශම දෙසට නැඹුරු වෙමි. මම ලැයිස්තුගත කර ඇති වෙනත් විසඳුම් මම උත්සාහ කර නැත, නමුත් ඒවා ද ඉතා හොඳ ය.

මට නම්, මම BigDecimal වලට කැමතියි එය සහාය දක්වන ක්‍රම නිසා. සී # දශම ඉතා හොඳයි, නමුත් මට කැමති තරම් එය සමඟ වැඩ කිරීමට මට අවස්ථාවක් ලැබී නැත. මගේ විවේක කාලය තුළ මා උනන්දුවක් දක්වන විද්‍යාත්මක ගණනය කිරීම් සිදු කරන අතර, බිග් ඩෙසිමල් ඉතා හොඳින් ක්‍රියා කරන බව පෙනේ, මන්ද මගේ පාවෙන ලක්ෂ්‍ය සංඛ්‍යා වල නිරවද්‍යතාවය සැකසිය හැකි බැවිනි. බිග් ඩෙසිමල් හි අවාසිය? සමහර විට එය බෙදීමේ ක්‍රමය භාවිතා කරන්නේ නම් එය මන්දගාමී විය හැකිය.

ඔබට සී, සී ++ සහ ෆෝට්රාන් හි නිදහස් හා හිමිකාර පුස්තකාල සොයා බැලිය හැකිය.


1
SciPy / Numpy, ස්ථාවර නිරවද්යතාව (එනම් Python හි decimal.Decimal) සම්බන්ධයෙන් (සහය නොදක්වයි docs.scipy.org/doc/numpy-dev/user/basics.types.html ). සමහර ශ්‍රිතයන් දශම සමඟ නිසියාකාරව ක්‍රියා නොකරනු ඇත (උදාහරණයක් ලෙස isnan). පැන්ඩාස් නැම්පි මත පදනම් වූ අතර එය ආරම්භ කළේ එක් ප්‍රධාන ප්‍රමාණාත්මක හෙජ් අරමුදලක් වන AQR හි ය. එබැවින් මූල්‍ය ගණනය කිරීම් සම්බන්ධයෙන් ඔබේ පිළිතුර ඇත (සිල්ලර ගිණුම්කරණය නොවේ).
comte

2

පෙර පිළිතුරු එකතු කිරීම සඳහා, ප්‍රශ්නයේ දී විසඳන ලද ගැටලුව සමඟ කටයුතු කිරීමේදී බිග් ඩෙසිමල් හැරුණු විට ජෝඩා -මුදල් ජාවා හි ක්‍රියාත්මක කිරීමේ විකල්පයක් ද ඇත. ජාවා මොඩියුලයේ නම org.joda.money.

එයට ජාවා එස්ඊ 8 හෝ ඊට පසුව අවශ්‍ය වන අතර කිසිදු පරායත්තතාවයක් නොමැත.

වඩාත් නිවැරදිව කිවහොත්, සම්පාදක-කාල පරායත්තතාවයක් ඇති නමුත් එය අවශ්‍ය නොවේ.

<dependency>
  <groupId>org.joda</groupId>
  <artifactId>joda-money</artifactId>
  <version>1.0.1</version>
</dependency>

ජෝඩා මුදල් භාවිතා කිරීමේ උදාහරණ:

  // create a monetary value
  Money money = Money.parse("USD 23.87");

  // add another amount with safe double conversion
  CurrencyUnit usd = CurrencyUnit.of("USD");
  money = money.plus(Money.of(usd, 12.43d));

  // subtracts an amount in dollars
  money = money.minusMajor(2);

  // multiplies by 3.5 with rounding
  money = money.multipliedBy(3.5d, RoundingMode.DOWN);

  // compare two amounts
  boolean bigAmount = money.isGreaterThan(dailyWage);

  // convert to GBP using a supplied rate
  BigDecimal conversionRate = ...;  // obtained from code outside Joda-Money
  Money moneyGBP = money.convertedTo(CurrencyUnit.GBP, conversionRate, RoundingMode.HALF_UP);

  // use a BigMoney for more complex calculations where scale matters
  BigMoney moneyCalc = money.toBigMoney();

ප්‍රලේඛනය: http://joda-money.sourceforge.net/apidocs/org/joda/money/Money.html

ක්‍රියාත්මක කිරීමේ උදාහරණ: https://www.programcreek.com/java-api-examples/?api=org.joda.money.Money


0

සමහර උදාහරණ ... මෙය ඕනෑම ක්‍රමලේඛන භාෂාවකින් ක්‍රියා කරයි (ඇත්ත වශයෙන්ම බලාපොරොත්තු වූ පරිදි ක්‍රියා නොකරයි) ... මම ඩෙල්ෆි, වීබීඑස්ක්‍රිප්ට්, විෂුවල් බේසික්, ජාවාස්ක්‍රිප්ට් සහ දැන් ජාවා / ඇන්ඩ්‍රොයිඩ් සමඟ උත්සාහ කර ඇත:

    double total = 0.0;

    // do 10 adds of 10 cents
    for (int i = 0; i < 10; i++) {
        total += 0.1;  // adds 10 cents
    }

    Log.d("round problems?", "current total: " + total);

    // looks like total equals to 1.0, don't?

    // now, do reverse
    for (int i = 0; i < 10; i++) {
        total -= 0.1;  // removes 10 cents
    }

    // looks like total equals to 0.0, don't?
    Log.d("round problems?", "current total: " + total);
    if (total == 0.0) {
        Log.d("round problems?", "is total equal to ZERO? YES, of course!!");
    } else {
        Log.d("round problems?", "is total equal to ZERO? NO... thats why you should not use Double for some math!!!");
    }

නිමැවුම්:

round problems?: current total: 0.9999999999999999 round problems?: current total: 2.7755575615628914E-17 round problems?: is total equal to ZERO? NO... thats why you should not use Double for some math!!!


3
ගැටළුව වන්නේ වටකුරු දෝෂයක් සිදුවීම නොවේ, නමුත් ඔබ එය සමඟ ගනුදෙනු නොකිරීමයි. ප්‍රති result ලය දශම ස්ථාන දෙකකට (ඔබට ශත අවශ්‍ය නම්) වට කර ඔබ ඉවරයි.
maaartinus

0

පාවීම යනු විවිධ මෝස්තර සහිත දශමයේ ද්විමය ආකාරයකි; ඒවා වෙනස් කරුණු දෙකකි. එකිනෙකට පරිවර්තනය කිරීමේදී වර්ග දෙකක් අතර සුළු දෝෂ තිබේ. එසේම, පාවීම නිර්මාණය කර ඇත්තේ විද්‍යාත්මක සඳහා අනන්ත විශාල අගයන් නිරූපණය කිරීම සඳහා ය. ඒ කියන්නේ එය නිර්මාණය කර ඇත්තේ එම ස්ථාවර බයිට් ගණන සමඟ අතිශය කුඩා හා අන්ත විශාල සංඛ්‍යාවට නිරවද්‍යතාව නැති කර ගැනීම සඳහා ය. දශමයට අසීමිත අගයන් සංඛ්‍යාවක් නිරූපණය කළ නොහැක, එය එම දශම සංඛ්‍යා ගණනට සීමා වේ. එබැවින් ෆ්ලෝට් සහ දශම විවිධ අරමුණු සඳහා වේ.

මුදල් වටිනාකම සඳහා දෝෂය කළමනාකරණය කිරීමට ක්‍රම කිහිපයක් තිබේ:

  1. දිගු නිඛිලයක් භාවිතා කර ඒ වෙනුවට ශත වලින් ගණන් කරන්න.

  2. ද්විත්ව නිරවද්‍යතාවය භාවිතා කරන්න, ඔබේ සැලකිය යුතු ඉලක්කම් 15 දක්වා තබා ගන්න එවිට දශම හරියටම අනුකරණය කළ හැකිය. අගයන් ඉදිරිපත් කිරීමට පෙර වටය; ගණනය කිරීම් සිදු කරන විට බොහෝ විට වටය.

  3. ජාවා බිග් ඩෙසිමල් වැනි දශම පුස්තකාලයක් භාවිතා කරන්න, එවිට ඔබට දශම අනුකරණය කිරීමට දෙවරක් භාවිතා කිරීමට අවශ්‍ය නොවේ.

බොහෝ වෙළඳ නාම අතින් ගෙන යා හැකි විද්‍යාත්මක කැල්කියුලේටරයන් පාවීම වෙනුවට දශමයෙන් ක්‍රියා කරන බව දැන ගැනීම සිත්ගන්නා කරුණකි. එබැවින් කිසිවෙකු පාවෙන පරිවර්තන දෝෂ පැමිණිලි නොකරයි.


-1

ඇමරිකානු මුදල් පහසුවෙන් ඩොලර් හා සත ප්‍රමාණයෙන් නිරූපණය කළ හැකිය. පූර්ණ සංඛ්‍යා 100% නිරවද්‍ය වන අතර, පාවෙන ලක්ෂ්‍ය ද්විමය සංඛ්‍යා හරියටම පාවෙන ලක්ෂ්‍ය දශමයට නොගැලපේ.


වැරදි. පූර්ණ සංඛ්‍යා 100% නිරවද්‍ය නොවේ. නිරවද්‍යතාවයට දශම හෝ භාගයක් අවශ්‍ය වේ.
alexherm
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.