为什么使用非十进制数据类型为差钱? [英] Why is using a NON-decimal data type bad for money?
问题描述
TL;博士:有什么毛病我的姜黄素
(货币)的结构。
tl;dr: What's wrong with my Cur
(currency) structure?
TL;博士2: 阅读问题的其余部分请,给予与浮动
或双
的: - )
tl;dr 2: Read the rest of the question please, before giving an example with float
or double
. :-)
我知道,这个问题想出了无数次的前四周互联网,但的我还没有看到令人信服的答案的,所以我想我会再问。
I'm aware that this question has come up numerous times before all around the internet, but I have not yet seen a convincing answer, so I thought I'd ask again.
我不明白,为什么使用非十进制数据类型是坏弄钱。 (这指的是存储而不是十进制数字的二进制数字数据类型。)
I fail to understand why using a non-decimal data type is bad for handling money. (That refers to data types that store binary digits instead of decimal digits.)
诚然,这不是明智的做法来比较两个双击
s的 A == b
。但是你可以很容易地说 A - B< = EPSILON
或类似的东西。
True, it's not wise to compare two double
s with a == b
. But you can easily say a - b <= EPSILON
or something like that.
的什么是错了这种方法?的
举例来说,我只是做了一个结构
在C#中,我相信正确处理金钱,而无需使用任何基于十进制数据格式:
For instance, I just made a struct
in C# that I believe handles money correctly, without using any decimal-based data formats:
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"); }
}
(对不起,更改名称货币
到姜黄素
,为穷人变量名称,省略公共
,并为不良布局;我试图把它所有在屏幕上,让你可以无需滚动阅读):)
(Sorry for changing the name Currency
to Cur
, for the poor variable names, for omitting the public
, and for the bad layout; I tried to fit it all onto the screen so that you could read it without scrolling.) :)
您可以用它喜欢的:
Currency a = 2.50;
Console.WriteLine(a * 2);
当然,C#有小数
数据类型,但是这是题外话这里 - 问题是关于为什么上面是危险的,不是我们不应该使用小数
Of course, C# has the decimal
data type, but that's beside the point here -- the question is about why the above is dangerous, not why we shouldn't use decimal
.
所以,会有人心中为我提供的真实世界的反的一个危险的声明,将在C#中失败这一点?我想不出任何。
So would someone mind providing me with a real-world counterexample of a dangerous statement that would fail for this in C#? I can't think of any.
谢谢!
注:我的的不的讨论小数
是否是一个不错的选择。我问,为什么一个二进制为基础的系统,被认为是不恰当的。
Note: I am not debating whether decimal
is a good choice. I'm asking why a binary-based system is said to be inappropriate.
推荐答案
花车不是为积累和递减稳定资金。这是你的实际的例子:
Floats aren't stable for accumulating and decrementing funds. Here's your actual example:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace BadFloat
{
class Program
{
static void Main(string[] args)
{
Currency yourMoneyAccumulator = 0.0d;
int count = 200000;
double increment = 20000.01d; //1 cent
for (int i = 0; i < count; i++)
yourMoneyAccumulator += increment;
Console.WriteLine(yourMoneyAccumulator + " accumulated vs. " + increment * count + " expected");
}
}
struct Currency
{
private const double EPSILON = 0.00005;
public Currency(double value) { this.value = value; }
private double value;
public static Currency operator +(Currency a, Currency b) { return new Currency(a.value + b.value); }
public static Currency operator -(Currency a, Currency b) { return new Currency(a.value - b.value); }
public static Currency operator *(Currency a, double factor) { return new Currency(a.value * factor); }
public static Currency operator *(double factor, Currency a) { return new Currency(a.value * factor); }
public static Currency operator /(Currency a, double factor) { return new Currency(a.value / factor); }
public static Currency operator /(double factor, Currency a) { return new Currency(a.value / factor); }
public static explicit operator double(Currency c) { return System.Math.Round(c.value, 4); }
public static implicit operator Currency(double d) { return new Currency(d); }
public static bool operator <(Currency a, Currency b) { return (a.value - b.value) < -EPSILON; }
public static bool operator >(Currency a, Currency b) { return (a.value - b.value) > +EPSILON; }
public static bool operator <=(Currency a, Currency b) { return (a.value - b.value) <= +EPSILON; }
public static bool operator >=(Currency a, Currency b) { return (a.value - b.value) >= -EPSILON; }
public static bool operator !=(Currency a, Currency b) { return Math.Abs(a.value - b.value) <= EPSILON; }
public static bool operator ==(Currency a, Currency b) { return Math.Abs(a.value - b.value) > EPSILON; }
public bool Equals(Currency other) { return this == other; }
public override int GetHashCode() { return ((double)this).GetHashCode(); }
public override bool Equals(object other) { return other is Currency && this.Equals((Currency)other); }
public override string ToString() { return this.value.ToString("C4"); }
}
}
在我的机器上这给$ 4,000,002,000.0203积累与4000002000预计在C#。这是一个糟糕的协议,如果这丢失了许多交易在一家银行 - 它并不一定要路数,只是众多。这是否帮助?
On my box this gives $4,000,002,000.0203 accumulated vs. 4000002000 expected in C#. It's a bad deal if this gets lost over many transactions in a bank - it doesn't have to be large ones, just many. Does that help?
这篇关于为什么使用非十进制数据类型为差钱?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!