tl; dr: Что не так с моей Cur
(денежной) структурой?
tl; dr 2: Прочтите, пожалуйста, остальную часть вопроса, прежде чем приводить пример с float
или double
. : -)
Я знаю, что этот вопрос уже много раз поднимался по всему Интернету, но я еще не видел убедительного ответа , поэтому решил спросить еще раз.
Я не понимаю, почему использование недесятичного типа данных плохо для работы с деньгами. (Это относится к типам данных, которые хранят двоичные цифры вместо десятичных.)
Верно, неразумно сравнивать два double
s с a == b
. Но вы можете легко сказать a - b <= EPSILON
или что-то в этом роде.
Что не так в этом подходе?
Например, я только что создал struct
в C #, который, как мне кажется, обрабатывает деньги правильно, без использования каких-либо десятичных форматов данных:
struct Cur
{
private const double EPS = 0.00005;
private double val;
Cur(double val) { this.val = Math.Round(val, 4); }
static Cur operator +(Cur a, Cur b) { return new Cur(a.val + b.val); }
static Cur operator -(Cur a, Cur b) { return new Cur(a.val - b.val); }
static Cur operator *(Cur a, double factor) { return new Cur(a.val * factor); }
static Cur operator *(double factor, Cur a) { return new Cur(a.val * factor); }
static Cur operator /(Cur a, double factor) { return new Cur(a.val / factor); }
static explicit operator double(Cur c) { return Math.Round(c.val, 4); }
static implicit operator Cur(double d) { return new Cur(d); }
static bool operator <(Cur a, Cur b) { return (a.val - b.val) < -EPS; }
static bool operator >(Cur a, Cur b) { return (a.val - b.val) > +EPS; }
static bool operator <=(Cur a, Cur b) { return (a.val - b.val) <= +EPS; }
static bool operator >=(Cur a, Cur b) { return (a.val - b.val) >= -EPS; }
static bool operator !=(Cur a, Cur b) { return Math.Abs(a.val - b.val) < EPS; }
static bool operator ==(Cur a, Cur b) { return Math.Abs(a.val - b.val) > EPS; }
bool Equals(Cur other) { return this == other; }
override int GetHashCode() { return ((double)this).GetHashCode(); }
override bool Equals(object o) { return o is Cur && this.Equals((Cur)o); }
override string ToString() { return this.val.ToString("C4"); }
}
(Извините за изменение имени Currency
на Cur
, из-за плохих имен переменных, за пропуск public
, а также из-за плохого макета; я попытался уместить все это на экране, чтобы вы могли читать без прокрутки.):)
Вы можете использовать это как:
Currency a = 2.50;
Console.WriteLine(a * 2);
Конечно , C # имеет тип данных decimal
, но это ' s здесь не в тему - вопрос в том, почему это опасно, а не в том, почему мы не должны использовать десятичное
.
Так что не мог бы кто-нибудь предоставить мне контрпример из реального мира опасного оператора, который не смог бы выполнить это в C #? Я ничего не могу придумать.
Спасибо!
Примечание: я не спорю, является ли десятичным числом
хорошим выбором. Я спрашиваю, почему двоичная система считается неуместной.