Главная страница
Top.Mail.Ru    Яндекс.Метрика
Текущий архив: 2015.04.26;
Скачать: CL | DM;

Вниз

Операции с 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;
Скачать: CL | DM;

Наверх




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


15-1410365521
Rouse_
2014-09-10 20:12
2015.04.26
С Днем Рождения, Маэстро :)


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


2-1391787281
Дмитрий СС
2014-02-07 19:34
2015.04.26
Операции с Currency


2-1392032469
Drowsy
2014-02-10 15:41
2015.04.26
При закрытии программы появляется ошибка