69

C# 中的这些行

decimal a = 2m;
decimal b = 2.0m;
decimal c = 2.00000000m;
decimal d = 2.000000000000000000000000000m;

Console.WriteLine(a);
Console.WriteLine(b);
Console.WriteLine(c);
Console.WriteLine(d);

生成此输出:

2
2.0
2.00000000
2.000000000000000000000000000

所以我可以看到从文字创建一个十进制变量可以让我控制精度。

  • 我可以在不使用文字的情况下调整十进制变量的精度吗?
  • 如何从 a 创建 b?如何从 c 创建 b?
4

7 回答 7

57

像这样保留尾随零是在 .NET 1.1 中引入的,以更严格地符合 ECMA CLI 规范。

MSDN 上有一些关于此的信息,例如这里

您可以按如下方式调整精度:

  • Math.Round(或天花板、地板等)以降低精度(b 从 c)

  • 乘以 1.000...(使用您想要的小数位数)以提高精度 - 例如乘以 1.0M 以从 a 中获得 b。

于 2009-07-15T20:37:02.957 回答
19

您只是看到完全相同数据的不同表示。a 的精度decimal将被缩放到它需要的大小(在合理范围内)。

来自System.Decimal

十进制数是一个浮点值,它由一个符号、一个数值中的每个数字的范围从 0 到 9 以及一个比例因子组成,该比例因子表示分隔整数和小数部分的浮点小数点的位置的数值。

Decimal 值的二进制表示由 1 位符号、96 位整数和用于划分 96 位整数并指定它的哪一部分是小数部分的比例因子组成。比例因子是隐含的数字 10,指数范围从 0 到 28。因此,十进制值的二进制表示形式为 ((-2 96到 2 96 ) / 10 (0 到 28) ) ,其中-2 96 -1 等于MinValue,2 96 -1 等于MaxValue。

缩放因子还保留 Decimal 数字中的任何尾随零。尾随零不会影响算术或比较运算中的 Decimal 数的值。但是,如果应用了适当的格式字符串,则 ToString 方法可以显示尾随零。

于 2009-07-15T17:26:55.850 回答
8

Math.Round (decimal d, int decimals)怎么样?

于 2009-07-15T17:50:05.257 回答
7

我发现我可以通过乘以或除以一个花哨的 1 来“篡改”比例。

decimal a = 2m;
decimal c = 2.00000000m;
decimal PreciseOne = 1.000000000000000000000000000000m;
  //add maximum trailing zeros to a
decimal x = a * PreciseOne;
  //remove all trailing zeros from c
decimal y = c / PreciseOne;

我可以制造一个足够精确的 1 来通过已知大小改变比例因子。

decimal scaleFactorBase = 1.0m;
decimal scaleFactor = 1m;
int scaleFactorSize = 3;

for (int i = 0; i < scaleFactorSize; i++)
{
  scaleFactor *= scaleFactorBase;
}

decimal z = a * scaleFactor;
于 2009-07-15T18:38:05.457 回答
6

很容易将decimalSQL Server 与decimal.NET 混淆。它们完全不同。

SQL Serverdecimal是一个定点数,其精度和小数位数在定义列或变量时是固定的。

.NET是一个类似于anddecimal的浮点数(区别在于准确地保留十进制数字,而准确地保留二进制数字)。试图控制 .NET 的精度是没有意义的,因为无论是否存在填充零,所有计算都会产生相同的结果。floatdoubledecimalfloatdoubledecimal

于 2009-08-25T21:09:48.807 回答
2

这将从小数中删除所有尾随零,然后您就可以使用ToString().

public static class DecimalExtensions
{
    public static Decimal Normalize(this Decimal value)
    {
        return value / 1.000000000000000000000000000000000m;
    }
}

或者,如果您想要一个确切数量的尾随零,比如 5,首先 Normalize(),然后乘以 1.00000m。

于 2013-01-09T18:18:53.407 回答
1

问题是 - 你真的需要存储在小数中的精度,而不是仅仅将小数显示为所需的精度。大多数应用程序在内部都知道它们想要达到的精度并显示到该精度级别。例如,即使用户在帐户包中输入了 100 的发票,它仍然使用 val.ToString("n2") 之类的东西打印为 100.00。

如何从 a 创建 b?如何从 c 创建 b?

c 到 b 是可能的。

Console.WriteLine(Math.Round(2.00000000m, 1)) 

产生 2.0

a 到 b 很棘手,因为引入精度的概念对数学来说有点陌生。

我想一个可怕的黑客可能是一个往返。

decimal b = Decimal.Parse(a.ToString("#.0"));
Console.WriteLine(b);

产生 2.0

于 2009-07-15T18:03:36.947 回答