你似乎完全了解使用浮点类型的好处。我倾向于在所有情况下都为小数进行设计,并依赖于分析器让我知道对小数的操作是否会导致瓶颈或速度减慢。在这些情况下,我将“向下强制转换”为双精度或浮点数,但只在内部执行,并通过限制正在执行的数学运算中的有效数字数量来小心地尝试管理精度损失。
一般来说,如果你的值是瞬态的(没有被重用),使用浮点类型是安全的。浮点类型的真正问题在于以下三种情况。
您正在聚合浮点值(在这种情况下,精度误差会复合)
基于浮点值构建值(例如在递归算法中)
您正在使用非常多的有效数字进行数学运算(例如,123456789.1 * .000000000000000987654321)
EDIT
根据c#小数的参考文档:
关键字decimal表示a
128位数据类型。相比
浮点类型,十进制类型
有更大的精度和更小的
范围,这使得它适用于
财务和货币计算。
为了澄清我上面的说法:
我倾向于设计所有的小数
案件,并依靠一个分析器让
我知道对小数的运算
造成瓶颈或慢速。
我只在偏爱小数的行业工作过。如果您正在处理物理或图形引擎,那么为浮点类型(浮点类型或双浮点类型)进行设计可能更有益。
Decimal不是无限精确的(在基本数据类型中不可能表示非整型的无限精确),但它比double精确得多:
十进制= 28-29位有效数字
Double = 15-16位有效数字
Float = 7位有效数字
编辑2
作为对Konrad Rudolph评论的回应,第一条(上面)绝对是正确的。不精确的聚集确实会产生复合效应。请看下面的示例代码:
private const float THREE_FIFTHS = 3f / 5f;
private const int ONE_MILLION = 1000000;
public static void Main(string[] args)
{
Console.WriteLine("Three Fifths: {0}", THREE_FIFTHS.ToString("F10"));
float asSingle = 0f;
double asDouble = 0d;
decimal asDecimal = 0M;
for (int i = 0; i < ONE_MILLION; i++)
{
asSingle += THREE_FIFTHS;
asDouble += THREE_FIFTHS;
asDecimal += (decimal) THREE_FIFTHS;
}
Console.WriteLine("Six Hundred Thousand: {0:F10}", THREE_FIFTHS * ONE_MILLION);
Console.WriteLine("Single: {0}", asSingle.ToString("F10"));
Console.WriteLine("Double: {0}", asDouble.ToString("F10"));
Console.WriteLine("Decimal: {0}", asDecimal.ToString("F10"));
Console.ReadLine();
}
输出如下:
Three Fifths: 0.6000000000
Six Hundred Thousand: 600000.0000000000
Single: 599093.4000000000
Double: 599999.9999886850
Decimal: 600000.0000000000
正如您所看到的,即使我们从相同的源常量进行加法,double的结果也没有那么精确(尽管可能会正确舍入),而且浮点数也远没有那么精确,以至于它被简化为只有两位有效数字。