tl; др: Что не так с моей Cur
(валютой) структурой?
tl; др 2: Прочитать остальную частьвопрос, прежде чем привести пример с float
или double
. : -)
Я знаю, что этот вопрос неоднократно возникал раньше, чем во всем Интернете, но Я еще не видел убедительного ответа , поэтому я решил спросить еще раз.
Я не понимаю, почему использование недесятичного типа данных плохо для обработки денег.(Это относится к типам данных, которые хранят двоичные цифры вместо десятичных.)
Правда, сравнивать два double
с 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
, но это не относится к этому вопросу - вопрос в том, почему вышеописанное опасно, а не в том, почему мы не должны использовать decimal
.
.не возражаете, предоставив мне реальный контрпример опасного утверждения, которое может не сработать в C #?Я не могу думать ни о чем.
Спасибо!
Примечание: я не обсуждаю, является ли decimal
хорошимвыбор.Я спрашиваю, почему двоичная система считается неуместной.