Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Начинающим";
Текущий архив: 2015.04.26;
Скачать: [xml.tar.bz2];

Вниз

Операции с Currency   Найти похожие ветки 

 
Дмитрий СС   (2014-02-07 19:34) [0]

Добрый день.
Пусть есть переменная Foo: Currency.

Подскажите, пожалуйста, как наиболее правильно получить:
1. Целую часть (в integer или в currency).
2. Дробную часть (в currency).
3. Округлить (в currency).

Конечно, есть множество функций Trunc, Round, и т. п., но есть сомнения, что они не очень предназначены для Currency.

И вопрос в тему.
Пусть X: Float, N: Integer; (Float - это какой-нибудь тип с плавающей точкой, например, Extended).

Всегда ли вернется TRUE?

X := N; // либо какие-либо операции над X, приводящие к значению N в математическом смысле.
Writeln(N = Trunc(X));


 
Rouse_ ©   (2014-02-07 19:53) [1]

Все что связано с матсопроцессором, не очень предназначено для точных вычислений из-за погрешности округления, для этого применяются софтверные алгоритмы.
Хотя у тебя тут всего 4 после запятой - какая точность нужна?


 
Rouse_ ©   (2014-02-07 19:55) [2]

ЗЫ: это я про тот случай когда проще умножить на 10000 и работать как с целым, чем заморачиваться с запятой...


 
Дмитрий СС   (2014-02-07 20:31) [3]


> Хотя у тебя тут всего 4 после запятой - какая точность нужна?

Дело даже не в точности. У меня считаются деньги и плюс/минус копейка роли не сыграет.
Это скорее вопрос порядка в голове. Насколько я понял из окна CPU, для Currency число конвертируется в Extended, округляется и возвращается обратно. Может это и нормально, конечно, учитывая, что при делении происходит то же самое.

Остается другой вопрос:

По сути то же самое происходит и при вызове Trunc:

Unit1.pas.32: C := Trunc(C);
005A829C DF6DF0           fild qword ptr [ebp-$10]
005A829F D8350C835A00     fdiv dword ptr [$005a830c]
005A82A5 E8E6EAE5FF       call @TRUNC
005A82AA 8945D8           mov [ebp-$28],eax
005A82AD 8955DC           mov [ebp-$24],edx
005A82B0 DF6DD8           fild qword ptr [ebp-$28]
005A82B3 D80D0C835A00     fmul dword ptr [$005a830c]
005A82B9 DF7DF0           fistp qword ptr [ebp-$10]
005A82BC 9B               wait

Предположим мы имеем C = 5. Может ли так получится, что при конвертировании в Extended мы получим не 5, а чуть меньше (например, 4,99...998...). Соответственно вызов Trunc вернет 4 и т. д., что приведет к вопросам в дальнейшем.
У меня не очень много опыта работы с числами с плавающей точкой, поэтому прошу поправить меня, если что-то не так.


 
Rouse_ ©   (2014-02-07 21:43) [4]


> Предположим мы имеем C = 5. Может ли так получится, что
> при конвертировании в Extended мы получим не 5, а чуть меньше

Если из целого - не может.


 
Inovet ©   (2014-02-08 09:59) [5]

> [3] Дмитрий СС   (07.02.14 20:31)
> У меня считаются деньги и плюс/минус копейка роли не сыграет.

Нифига себе. Люди выворачиваются, чтобы всё до копейки сходилось, а у тебя «не сыграет». Тогда плавающию точку бери и не парься, но вряд ли заказчик тебя похвалит, когда у него разные в разных случаях разные результаты будут получатся на одних и тех же данных. А уж если на ккалькуляторе начнёт проверять...


 
Юрий Зотов ©   (2014-02-08 12:41) [6]

В одном проекте этот вопрос был решен так: все расчеты велись в Extended, а представление результатов - с математическим округлением до 2-х знаков после запятой. Расхождений с калькулятором не наблюдалось.


 
Inovet ©   (2014-02-08 12:44) [7]

> [6] Юрий Зотов ©   (08.02.14 12:41)

Представление и хранение, так и надо, тогда нормально, только округлять до 2 знаков не забывать в нужных местах, обычно перед сохранением. И округлялку надо не ту, что в Делфи, ну это известный факт.


 
Юрий Зотов ©   (2014-02-08 13:07) [8]


> Inovet ©   (08.02.14 12:44) [7]

Там сохранялось в БД, а поле было прописано как (10,2) - поэтому округление при сохранении шло автоматом.


 
Дмитрий СС   (2014-02-08 14:08) [9]


> Нифига себе. Люди выворачиваются, чтобы всё до копейки сходилось,
>  а у тебя «не сыграет».

Отставить панику, я тоже выворачиваюсь, но в данном случае речь идет о расчете комиссии по процентам. И в какую сторону я округлю ее роли не сыграет. Все остальные суммы, зависящие от комиссии находятся с помощью сложения и вычитания ПОСЛЕ округления, поэтому суммы все сойдутся.


> Юрий Зотов ©   (08.02.14 12:41) [6]
> В одном проекте этот вопрос был решен так:

Здесь придется постоянно следить, где округленные данные, а где нет и не смешивать их. Хотя учитывая, что процессор и так переводит Currency-числа в Extended при расчетах - получаются что так как вы делают все:)


 
Inovet ©   (2014-02-08 14:10) [10]

> [9] Дмитрий СС   (08.02.14 14:08)

Да не важно, должно везде всё сходиться.


 
Незнакомец   (2014-02-10 11:09) [11]

> Подскажите, пожалуйста, как наиболее правильно получить:
>
> 1. Целую часть (в integer или в currency).
> 2. Дробную часть (в currency).
> 3. Округлить (в currency).


procedure CurrencyTrunc(var Result: Currency; const C: Currency); overload;
var
 X: int64 absolute C;
 R: int64 absolute Result;
begin
 R := X - (X mod 10000);
end;

procedure CurrencyTrunc(var Result: integer; const C: Currency);  overload;
var
 X: int64 absolute C;
begin
 Result := (X div 10000);
end;

procedure CurrencyFrac(var Result: Currency; const C: Currency); overload;
var
 X: int64 absolute C;
 R: int64 absolute Result;
begin
 R := X mod 10000;
end;

procedure CurrencyRound(var Result: Currency; const C: Currency);  overload;
const
 OFFSETS: array[boolean] of int64 = (5000, -5000);
var
 X: int64 absolute C;
 Y: int64;
 R: int64 absolute Result;
begin
 Y := X + OFFSETS[X < 0];
 R := Y - (Y mod 10000);
end;


Результат в var, а не результат функции потому, что во втором случае происходят преобразования через Extended, что приводит к потере точности и производительности


 
Незнакомец   (2014-02-10 11:12) [12]

> И вопрос в тему.
> Пусть X: Float, N: Integer; (Float - это какой-нибудь тип
> с плавающей точкой, например, Extended).
>
> Всегда ли вернется TRUE?
>
> X := N; // либо какие-либо операции над X, приводящие к
> значению N в математическом смысле.
> Writeln(N = Trunc(X));


Нет
У single маленькая точность
Можешь прогнать тестовый цикл по всему диапазону чисел Integer и выявить, где данное условие не сработает


 
Дмитрий СС   (2014-02-10 20:41) [13]


> Незнакомец   (10.02.14 11:09) [11]
>

Благодарю. Это наработки или специально для темы написали?


 
Незнакомец   (2014-02-10 22:02) [14]

> Дмитрий СС   (10.02.14 20:41) [13]

Я думаю доступнее сразу кодом показывать
Нет, это не наработки


 
Дмитрий СС   (2014-02-11 01:10) [15]

Интересно, а как будет выглядеть умножение и деление без потери точности и выхода за диапазон Int64.


 
Незнакомец   (2014-02-11 09:57) [16]

> Дмитрий СС   (11.02.14 01:10) [15]

Хз :)
Но видимо сложно :)


 
Незнакомец   (2014-02-11 10:00) [17]

По сути Currency это число с фиксированной точкой
Поэтому вся логика для них соответствует рутине с фиксированной точкой

Ситуация усложняется размером переменных :)
Если для фикс точки от Integer умножение реализуется через Int64, то в случае Currency наверное через Int128 :)


 
Inovet ©   (2014-02-11 10:46) [18]

Они в целых 64 бита, значит так:
a*b/10000


 
Inovet ©   (2014-02-11 10:50) [19]

> [18] Inovet ©   (11.02.14 10:46)

Да и что выдумывать, вот оно всё в исходниках в
syscurr.h


 
Inovet ©   (2014-02-11 10:51) [20]

> [19] Inovet ©   (11.02.14 10:50)
> в исходниках

т.е. в
include\windows\rtl\


 
Мистер Хэ   (2014-02-11 10:52) [21]

> Inovet ©

> без потери точности и выхода за диапазон Int64.


 
Inovet ©   (2014-02-11 10:57) [22]

> [21] Мистер Хэ   (11.02.14 10:52)

Ну дык тут ничего не поможет, кроме увеличения точности, очевидно же. А для фиксированной точки &#151; ака целое &#151; всё как и для целого с некоторыми приведениями в нужных местах.


 
Inovet ©   (2014-02-11 10:59) [23]

Ну т.е. что должно быть с этими пресловутыми копейками в операции
1,99*0,01
?


 
Dimka Maslov ©   (2014-02-11 15:52) [24]

Лучше сращу всё считать в копейках. Во-первых будет влезать в диапазон int64. Во вторых в копейках считать выгоднее: к примеру если возвести 1 рубль в квадрат - рубль и получим, а если 100 копеек - получим 10000 копеек, а это 100 рублей!!!


 
Inovet ©   (2014-02-11 16:24) [25]

> [24] Dimka Maslov ©   (11.02.14 15:52)

Шутишь? Квадратный рубль совсем оставим в покое, но и с простым рублём тоже не получится.


 
Inovet ©   (2014-02-11 16:26) [26]

> [25] Inovet ©   (11.02.14 16:24)

Или что? Вместо рублей копейки? Ну тогда да.


 
Дмитрий СС   (2014-02-12 02:27) [27]


> Dimka Maslov ©   (11.02.14 15:52) [24]

Мы отказались (отказываемся) от этого из-за того что трудно воспринимать - слишком много нулей.



Страницы: 1 вся ветка

Форум: "Начинающим";
Текущий архив: 2015.04.26;
Скачать: [xml.tar.bz2];

Наверх





Память: 0.52 MB
Время: 0.002 c
15-1409920082
Darvin
2014-09-05 16:28
2015.04.26
Delphi XE5 Приложение для Андроид


15-1410318818
Inovet
2014-09-10 07:13
2015.04.26
Альтенативный переключатель раскладки клавиатуры в Вин7


15-1410414198
Пит
2014-09-11 09:43
2015.04.26
Сортировка в проводнике windows


2-1392017218
Роман
2014-02-10 11:26
2015.04.26
компонент StatusBar


15-1409925976
alexdn
2014-09-05 18:06
2015.04.26
Яндекс перешел на другой протокол?





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский