Округлення дійсних чисел

Речові числа, на відміну цілих чисел, зберігають лише приблизне значення, і там використовують у основному зберігання наукових даних. Для зберігання грошових величин зазвичай використовуються цілі типи даних. Однак integer зазвичай не вистачає для зберігання наших грошей (особливо гостро стоїть ця проблема в Туреччині, де зарплату отримують мільйонами турецьких лір). Тому для грошей доводиться використовувати речові числа (починаючи з InterBase 6.0 та в наступних версіях InterBase/Firebird/Yaffil є підтримка int64 або bigint у третьому діалекті).

InterBase має 2 типи даних для зберігання речових чисел: float та double precision. Ці типи еквівалентні дельфійським single та double, відповідно. Single має дуже низьку точність (довжина всього 4 байти), тоді як double precision – цілком достатню (8 байт).

Загалом правило просте: якщо вам потрібно зберігати речове число, то оголошуйте його як NUMERIC(15, 2) або DECIMAL(15, 2) (у діалекті 3 precision може бути до 18 знаків замість 15). У першому діалекті при виконанні обчислень обов'язково буде похибка (через число, що зберігається в речовинному типі), а в третьому діалекті похибок не буде (число зберігається як ціле), але можуть бути проблеми переповнення (див. докладно про реалізацію int64) .

Для перевірки точності дійсних чисел у IB необов'язково створювати таблиці та виконувати SQL-оператори. Ви можете поекспериментувати з числами double у Delphi або C++Builder. Одночасно можна використовувати будь-який наведений нижче код як UDF для округлення дійсних чисел як банківського, так і звичайного. Одним із найпопулярніших рішень на сьогоднішній день є UDF FormatFloat.

Далі наведено приклади втрати точності з різнимитипами речових чисел, та способи боротьби з цим. Інформація зібрана з конференцій: fido7.ru.delphi.db, fido7.su.dbms, fido7.su.dbms.interbase, [email protected]. Авторство деяких листів, на жаль, загублено.

KDV ([email protected])

Результат -43,9400000000001. Якщо замість double використовувати single (еквівалент FLOAT), то результат буде ще гіршим: -43,9400634765625.

Subject: Round(2.5) = 2.

Пон Вер 14 1998, Eugeny Ivanoff == Gleb V. Ufimtsev: ==============================

Я наведу листування з ехи з бухгалтерії, вибач.

===== початок ========= Якщо я купив 100 зошитів за 12.10 і в місяці продав 5 штук, то в оборотці з'являється зайва копійка

==== = 1. Вести облік із десятими частками копійки. 2. Розділити придбану партію на 2 комплекти: 10 штук - по 13 коп, 90 штук - по 12 коп. Тоді 10 х 0,13 + 90 х 0,12 = 12,10. ===== AB> 1. Вести облік із десятими частками копійки.

За тих обсягів облік ведеться з 6 знаками від гривні, інакше податкова не буде коректною (12 200 шт. по 0.083333 грн без ПДВ). не рятує - підсумкова цифра в рядку має бути в копійках

AB> 2. Розділити придбану партію на 2 комплекти: 10 штук - по 13 коп, 90 штук - по 12 коп. Тоді 10 х 0,13 + 90 х 0,12 = 12,10.

Поясни це фірмі, від якої ми привезли податкові накладні ====== SV>> Веди облік зошитів у тис. шт. Якщо мало – у десяти тисяч штук. Проблема з копійками піде – перевірено.

VK> Вірно. Коли я налаштовував облік швацького виробництва, мене намагалися нав'язати облік ниток за метрів.;-) VK> З того часу - тільки в умовних "котушках" по 200 м. (хоча іноді йдуть кілометрові бобіні.

Особливо приємно видати на руки накладну чи чек на 0.006тис.шт. Люди купують партії до 1000 000 шт., І продають поштучно! ==== Хлопці, перепрошую, що втручаюся, але, я вже писав Ігорю милом, а чи не легше користуватися (я, до речі, вже давно користуюся) якоюсь багофічою (це, на мою думку, з буржуйської банківської системи) системою округлення до _найближчого _парному - фор екзампл (з прикладу Ігоря):

І немає жодних проблем із копійками.

IC> Мається на увазі складський облік і оборотна відомість, і щоб вважалася автоматично.

Все вважається автоматично. Єдине – але. Hадо мати прямі руки для написання якоїсь функції – що забезпечує дане округлення :))) ============= Кінець ========

>>>> Це правило бухгалтерського округлення. >>>> Половинки до найближчого парного. >>>> Так як ця фіча у дельфей була заявлена ​​давно, то, гадаю, буде виявлена ​​в будь-якій версії.

EI> народ, бо це баг, я не фічу, або в американців бухгалтерія зовсім неруська, я ці граблі обійшов використовуючи перемінну EI> var x: real; i: integer; EI> x:=2.5; i:=round(x); EI> в результаті i = 3, я думаю, що це давно можна було і фак помістити, кожен місяць на них хто-небудь настає :)

Павло Зотов

Andrew Bagirov ([email protected])

Дякую, Євгене. Без тебе не дорахувався б я копійки. :)

З повагою, Сергій Бєлов.

Документ із www.borland.com/devsupport/

Since Delphi's Round() функція використовується "bankers rounding", where the value is rounded to nearest even number, how can I round floating point number using the more traditional means, where fractional values ​​less than .5 round down, .5 and greater round up?

Answer: The following function demonstratesрівні вниз номери з fractional values ​​of less than .5, and rounding up numbers with fractional values ​​of .5 and greater.

Example:

Paul Bonnette

I have been using x = CAST (((x+0.00001)*100) AS INTEGER) /100; до боротьби знижується вірогідність у двосторонній точці розв'язання.

Це forces a number into integer representing pennies the divides back down to decimal form, removing creaping millipennies. 10,000th of penny (або whatever you would like to use) is added so that if the decimal representation rounds up, no truncate down.

Ця технологія не може бути невпинно випробувана, але вона була працювала з far без проблем. Tell me if anyone finds better technique or tests this one thoroughly.