Чи існує єдине представлення даних, яке працює для всіх валют (навіть тих, що відрізняються від доларів, євро та фунтів)?


12

Я можу знайти багато запитань про бібліотеки, які можна використовувати для представлення сум у певній валюті. І про вікове питання, чому ви не повинні зберігати валюту як номер IEEE 754 з плаваючою точкою. Але я, здається, нічого більше не можу знайти. Звичайно, про валюту в реальному світі можна дізнатися набагато більше. Мене особливо цікавить те, що вам потрібно знати, щоб представити його у фізичному використанні (наприклад, з доларом ви ніколи не маєте точності менше 0,01 долара, що дозволяє представити як цілу кількість центів).

Але важко зробити припущення щодо того, наскільки універсальною є ваша програма, коли єдиними відомими вам валютами є популярні західні (наприклад, долар, євро та фунт). Які ще є відповідні знання в суто програмній перспективі? Мене не хвилює тема конверсії.

Зокрема, що нам потрібно знати, щоб мати змогу зберігати значення в якійсь валюті та роздруковувати їх?


2
Не всі програмісти працюють у галузях, що маніпулюють сумою валюти.
whatsisname

4
О, звичайно. Але це можна сказати майже про все. Я думаю, ми можемо припустити, що тим, хто вважає це питання корисним, будуть ті, хто працює з валютою.
Кет

5
Я багато працював у розробці для банків та інших фірм, що надають фінансові послуги в Нью-Йорку. І я можу гарантувати вам, що у вашому запитанні немає відповіді "закритої форми". Ви також можете запитати: "скільки математики я повинен знати?" Наприклад, ще в 1990 р. Ціни на акції перейшли від восьмої та 256-ї до десяткової, що вимагало багато перепрограмувань. Хто міг здогадатися, що це станеться? Вам просто потрібно зрозуміти бізнес, який підтримують ваші програми, і як найкраще представляти дані (у цьому випадку валюту) для підтримки цих потреб бізнесу.
Джон Форкош

4
Мій 0,02: Ціна - одне. Валюта - інша.
Мачадо

3
Я подумав: О, має бути якийсь спільний знаменник для всіх валют. Але, можливо, ні. Пенні стерлінгів наразі становить 1–100 фунта, але склав 1–240 фунта. Отже, ви не тільки маєте поділ 1/240, але у вас є дата переходу, і, можливо, обмінний курс на старий пенс, який ще не перейшов. en.wikipedia.org/wiki/Penny_sterling Навіть не пускайте мене на оболонки! en.wikipedia.org/wiki/Shell_money чи той факт, що гроші потребують віри, щоб стати реальністю: en.wikipedia.org/wiki/Money Велике питання, навіть якщо воно не відповідає StackExchange!
GlenPeterson

Відповіді:


24

наприклад, з доларом ви ніколи не маєте точності менше 0,01 долара

О, справді? введіть тут опис зображення

вікове питання, чому не слід зберігати валюту як номер IEEE 754 з плаваючою точкою.

введіть тут опис зображення

Будь ласка, не соромтесь зберігати дюйми в номерах IEEE 754 з плаваючою комою . Вони зберігають точно так, як ви очікували.

Будь ласка, не соромтеся зберігати будь-яку суму грошей у номерах плаваючої крапки IEEE 754, які ви можете зберігати за допомогою кліщів, які ділять лінійку на частки дюйма.

Чому? Тому що, коли ви використовуєте IEEE 754 , саме так ви зберігаєте його.

Справа в дюймах - це те, що вони розділені навпіл. Справа в більшості видів валюти полягає в тому, що вони діляться на десяті частини (деякі види не є, але залишаємося зосередженими).

Ця різниця не була б такою заплутаною, за винятком того, що для більшості мов програмування введення та виведення чисел з плаваючою комою IEEE 754 виражається у десяткових колах! Що дуже дивно, оскільки вони не зберігаються у децималах.

Через це ви ніколи не можете побачити, як біти дивують речі, коли ви попросите комп'ютер зберігати 0.1. Дивовижність ви бачите лише тоді, коли займаєтесь математикою проти неї, і у неї є дивні помилки.

Від ефективної Java Джоша Блоха :

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

Виробляє 0.6100000000000001

Що найбільше говорить про це, це не 1сидячий шлях справа. Це дивні номери, які потрібно було використати, щоб отримати його. Замість того, щоб використовувати найпопулярніший приклад, 0.1ми повинні використовувати приклад, який показує проблему і уникає округлення, яке б приховало її.

Наприклад, чому це працює?

System.out.println(.01 - .02);

Виробляє -0.01

Тому що нам пощастило.

Я ненавиджу проблеми, які важко діагностувати, бо мені іноді «пощастило».

IEEE 754 просто не може точно зберігати 0,1. Але якщо ви попросите його зберігати 0,1, а потім попросите його надрукувати, він покаже 0,1, і ви подумаєте, що все добре. Це не добре, але ви цього не бачите, оскільки це округлення, щоб повернутися до 0,1.

Деякі люди плутають хек з інших, називаючи ці розбіжності помилками округлення. Ні, це не помилки округлення. Округлення робить те, що належить, і перетворює те, що не є десятком, у десяткові, щоб воно могло друкуватись на екрані.

Але це приховує невідповідність між тим, як відображається число, і тим, як воно зберігається. Помилка не сталася, коли відбулося округлення. Це сталося, коли ви вирішили ввести номер у систему, яка не може його точно зберігати, і припустили, що він зберігається саме тоді, коли його не було.

Ніхто не сподівається, що π точно зберігатиметься в калькуляторі, і їм вдається добре працювати з ним. Тому проблема навіть не в точності. Йдеться про очікувану точність. Комп'ютери відображають одну десяту частину так 0.1само, як і наші калькулятори, тому ми очікуємо, що вони зберігатимуть одну десяту як ідеально, як це роблять наші калькулятори. Вони ні. Що дивно, адже комп’ютери дорожчі.

Дозвольте мені показати вам невідповідність:

введіть тут опис зображення

Зауважте, що 1/2 та 0,5 ліній ідеально. Але 0,1 просто не вирівнюється. Звичайно, ви зможете наблизитись, якщо продовжуєте ділити на 2, але ніколи не вдаритесь точно. І нам потрібно все більше і більше бітів щоразу, коли ми ділимо їх на 2. Отже, для представлення 0,1 у будь-якій системі, яка ділиться на 2, потрібно нескінченна кількість бітів. Мій жорсткий диск просто не такий великий.

Тож IEEE 754 перестає пробувати, коли у нього закінчується біт. Що приємно, бо мені потрібно місце на жорсткому диску для ... сімейних фотографій. Насправді ні. Сімейні фотографії. : P

У будь-якому випадку те, що ви вводите і те, що ви бачите, є десятковими знаками ( праворуч), але те, що ви зберігаєте, - це двозначні зображення (зліва). Іноді ці ідеально однакові. Іноді їх немає. Іноді дивиться, як вони однакові, коли їх просто немає. Ось округлення.

Зокрема, що нам потрібно знати, щоб мати змогу зберігати значення у певній валюті та роздруковувати їх?

Будь ласка, якщо ви обробляєте мої гроші на десятковій основі, не використовуйте поплавці чи подвійні.

Якщо ви впевнені, що такі речі, як десяті копійки, не будуть задіяні, тоді просто зберігайте копійки. Якщо ви цього не зробите, то зрозумійте, якою буде найменша одиниця цієї валюти, і використовуйте її. Якщо ви не можете, використовуйте щось на кшталт BigDecimal .

Моя чиста вартість, ймовірно, завжди вписується в 64-бітове ціле число, але такі речі, як BigInteger, добре працюють для проектів, більших за це. Вони просто повільніше, ніж рідні типи.

З'ясувати, як його зберігати - це лише половина проблеми. Пам'ятайте, що ви також повинні мати можливість відображати це. Хороший дизайн розділить ці дві речі. Справжня проблема використання плавців тут - це те, що дві речі збиті разом.

введіть тут опис зображення


6
Я не шукав ще одного пояснення, чому IEEE 754 не працює за гроші. Я говорив в ОП, що це було добре пояснено в інших місцях. Так само є причина, що я використовував термін "фізичне використання". А саме тому, що, хоча ціни на газ, біржові цінності тощо можуть мати довільну точність, фізичні гроші (і величезна кількість операцій з користувачами) не проходять повз сотні позицій (а різні програми програмного забезпечення хочуть представляти лише те, за що можна заплатити фізичні гроші). Інформація, якій я дивувався, була, чи існують валюти, які переходять у більше десяткових знаків.
Кет

3
"Дивацтво" плаваючої точки не обмежується лише наполовину проти 1/10. Аспект "плаваючої точки" в імені також викликає часом несподівані результати.
whatsisname

6
До декадинізації валюта Великобританії була фунтами, шилінгами і пенсами (£ sd), £ 1 == 20s, 1s = 12d, таким чином, £ 1 = 240d, так 1d = 0,0046666666666 .. тому навіть не може бути представлена ​​як десяткова. До вступу в євро італійська ліра перевищила 2346,4 (у 2001 р.) До долара США, тому такі речі, як зарплати та ціни на житло, іноді досягали верхньої межі поодиноких поплавків, а економічні показники потрапляли у верхній рівень удвічі.
Стів Барнс

2
Я просто стверджую / зазначу, що Валюта - це одне, а Ціна - інша річ. Ви можете мати більш ніж 0,01 долара точності в цінах, але ви не можете ефективно платити з цією точністю.
Мачадо

1
Також сімейні фотографії . Pft. :)
Мачадо

10

Я можу знайти багато запитань про бібліотеки, які можна використовувати для представлення сум у певній валюті.

Як я поясню, "бібліотеки" не потрібні, якщо стандартна бібліотека вашої мови не має певних типів даних.

Звичайно, про валюту в реальному світі можна дізнатися набагато більше. Мене особливо цікавить те, що вам потрібно знати, щоб представити це у фізичному використанні (наприклад, з доларом, ви ніколи не маєте точності менше 0,01 долара, що дозволяє представити як цілу кількість центів).

Простіше, вам потрібна десяткова фіксація , а не десяткова плаваюча точка. Наприклад, клас BigDecimal Java може бути використаний для зберігання суми валюти. Інші сучасні мови мають вбудовані подібні типи, зокрема C # та Python . Реалізації відрізняються, але вони зазвичай зберігають число як ціле число, десяткове місце розташування - як окремий член даних. Це дає точну точність, навіть при виконанні арифметики, яка дала б непарні залишки (наприклад, 0,0000001) з номерами IEEE з плаваючою комою.

Зокрема, що нам потрібно знати, щоб мати змогу зберігати значення у певній валюті та роздруковувати їх?

Є кілька важливих моментів.

  1. Використовуйте фактичний десятковий тип, а не плаваючу крапку.

  2. Зрозумійте, що сума валюти має дві складові: значення (5,63) та код або тип валюти (USD, CAD, GBP, EUR та ін.). Іноді ви можете ігнорувати код валюти, в інших випадках це дуже важливо. Що робити, якщо ви працюєте у системі фінансової чи роздрібної торгівлі / електронної комерції, яка дозволяє отримати кілька валют? Що станеться, якщо ви намагаєтесь взяти гроші у клієнта в CAD, але він хоче платити за допомогою MXN? Вам потрібен тип "гроші" з кодом валюти та сумою валюти, щоб мати можливість змішувати ці значення (також обмінний курс, але я не хочу надто далеко за дотичною). У той же час моє програмне забезпечення для особистого фінансування ніколи не потребує цього хвилюватися, оскільки все в доларах США (воно може змішувати валюти, але мені це ніколи не потрібно).

  3. Хоча на валюті може бути найменша фізична одиниця на практиці (CAD і USD мають центи, JPY - це просто ... Єна), можна зменшити. Відповідь CandiedOrange вказує ціни на пальне в десятих частках відсотка. Мої податки на нерухомість оцінюються як млини за долар, або десяті частки відсотка (1/1000 долара США). Не обмежуйте себе 0,01 дол. Хоча ви можете відображати ці значення більшу частину часу, ваші типи повинні допускати менші (десяткові типи, на які посилається вище, роблять).

  4. Проміжні розрахунки, безумовно, повинні забезпечувати більш точність, ніж один цент. Я працював над системами роздрібної торгівлі та електронної комерції, де внутрішні значення були округлені до 0,00000001 доларів внутрішньо. Нескінченна точність, як правило, не підтримується десятковими типами (або SQL), тому має бути деякий ліміт. Наприклад, розділення 1/3 за допомогою Java BigDecimal призведе до винятку без вказаних RoundingMode або MathContext, оскільки значення не може бути представлено точно.

    У будь-якому випадку це критично важливо в певних випадках. Припустимо, у вас у кошику є користувач із шістьма предметами, і він їде перевірити. Ваша система повинна обчислювати податок і робить це за кожну позицію, оскільки товари можуть оподатковуватися по-різному. Якщо ви округляєте податки за кожним елементом, ви можете отримати помилки округлення копійок на рівні транзакції / кошика. Одним із підходів для виправлення цього може бути зберігання податків до більшої кількості десяткових знаків за позицію, отримання загальної суми за всю транзакцію, повернення та кругообіг кожного елемента, щоб загальний податок був правильним (можливо, один предмет заокруглюється, інший - вниз).

Важливе, що слід зрозуміти з усього цього, - це те, що таке важливе, як заокруглення грошей, може бути дуже важливим для правильних людей (наприклад, деякі мої минулі клієнти, які повинні були сплачувати державні податки з продажу від імені своїх клієнтів). Однак це все вирішені проблеми. Майте на увазі вищезазначені моменти і робіть експерименти самостійно, і ви навчитесь робити це.


На другому, я вважаю, що обмінного курсу достатньо, щоб отримати хоча б свою кількість. Ви повинні врахувати, що ставки змінюються з часом, що має кілька різних способів обробки.
Ізката

2
+1. Також з часом змінюються валюти. У Бразилії ми неодноразово змінювались валюти протягом 80-х та 90-х, скорочуючи нулі та перейменувавши валюту в разі необхідності через інфляцію поза контролем. Це означає, що з часом може змінюватися кожен аспект валюти.
Мачадо

@Izkata звичайно, я працював над системами, які змінюють валюти. Я хотів торкнутися теми, як це актуально. Однак це питання не в центрі уваги, і я, мабуть, міг би набрати іншу відповідь, поки ця на тему обміну валюти.

"" Бібліотеки "не потрібні, якщо стандартна бібліотека вашої мови не має певних типів даних, як я поясню." Валюти можуть мати половинки, чверті, десяті, восьмі тощо, а це означає, що нам принаймні потрібне десятичне зображення. Але чи ми повністю впевнені, що немає грошових одиниць із 1/3 цілого шматка?
Даніель МакЛаурі

4

Одне місце, де багато розробників стикаються з єдиним представленням даних для будь-якої валюти, - це покупки через додатки для iOS. Ваш клієнт може бути підключений до магазину майже в будь-якій країні світу. І в цій ситуації вам буде надана ціна закупівлі, що складається з подвійного точного номера та коду валюти.

Потрібно знати, що цифри можуть бути великими. Є валюти, де еквівалент, наприклад, десяти доларів, перевищує 100 000 одиниць. І нам пощастило, що немає таких валют, як зімбабвійський долар на даний момент, де ви могли мати сто трильйонів банкнот!

Для відображення валют вам знадобиться деяка бібліотека - у вас немає шансів самостійно все виправити. Відображення залежить від двох речей: коду валюти та місцеположення користувача. Подумайте, як американські долари та канадські долари відображатимуться за допомогою локального пункту США та канадського локалу. У США у вас є $ проти CAN $, а в Канаді - US проти $. Сподіваюся, що це вбудована в ОС, або у вас хороша бібліотека.

Для розрахунків будь-який розрахунок закінчується кроком округлення. Вам доведеться дізнатися, як ви повинні виконати це округлення на законних підставах . Це не проблема програмування, це юридична проблема. Наприклад, якщо ви обчислюєте ПДВ у Великобританії, ви повинні нарахувати податок за кожну позицію чи за окремий рядок та округлити її до копій. Що ви обіжете, залежить від валюти. Але правила очевидно залежать від країни. Ви не можете очікувати, що розрахунок, який є юридично правильним у Великобританії, буде юридично правильним у Японії та навпаки.


0

Зокрема, що нам потрібно знати, щоб мати змогу зберігати значення в якійсь валюті та роздруковувати їх?

  • "для зберігання значень" : тип даних з фіксованою точкою та тип валюти. Я думаю, що це досить очевидно. Збереження до нефіксованої точки може включати деяке округлення та змінити значення. Обчислення валюти було б іншим питанням.
  • "роздрукувати їх" : користувацька мова. Якщо вам пощастить, ви отримуєте стандартну бібліотеку, щоб зробити все, наприклад, символ валюти, роздільник тисяч, десятковий роздільник, точність тощо.

Деякі приклади проблем, пов’язаних з локальним словом:

  • 100 доларів США у мові США повинні становити 100,00 долара, в іншому мові з крапкою як десятковим роздільником буде 100,00 доларів США.
  • Деякі країни використовують безліч тисяч замість тисяч для групування номерів, наприклад, замість 10 000,00 це буде лише 1,0000,00
  • З практичних причин люди не друкують усі цифри для невеликих валют, наприклад, замість 1 000 000 000,00 доларів, вони просто хочуть, щоб ви надрукували 1 мільярд доларів.

Інша потенційна проблема - навіть якщо ви правильно зберігаєте валюту у фіксованому точковому номері, її може знадобитися перетворити на номер з плаваючою комою, оскільки бібліотека, що використовується для друку, підтримує лише плаваючу крапку.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.