更新
经过一些调查和在Jon和Hans提供的有用答案的帮助下,我能够整理出如下内容。到目前为止,我认为它似乎工作得很好。当然,我不能保证它完全正确。
public static int GetSignificantDigitCount(this decimal value)
{
/* So, the decimal type is basically represented as a fraction of two
* integers: a numerator that can be anything, and a denominator that is
* some power of 10.
*
* For example, the following numbers are represented by
* the corresponding fractions:
*
* VALUE NUMERATOR DENOMINATOR
* 1 1 1
* 1.0 10 10
* 1.012 1012 1000
* 0.04 4 100
* 12.01 1201 100
*
* So basically, if the magnitude is greater than or equal to one,
* the number of digits is the number of digits in the numerator.
* If it's less than one, the number of digits is the number of digits
* in the denominator.
*/
int[] bits = decimal.GetBits(value);
if (value >= 1M || value <= -1M)
{
int highPart = bits[2];
int middlePart = bits[1];
int lowPart = bits[0];
decimal num = new decimal(lowPart, middlePart, highPart, false, 0);
int exponent = (int)Math.Ceiling(Math.Log10((double)num));
return exponent;
}
else
{
int scalePart = bits[3];
// Accoring to MSDN, the exponent is represented by
// bits 16-23 (the 2nd word):
// http://msdn.microsoft.com/en-us/library/system.decimal.getbits.aspx
int exponent = (scalePart & 0x00FF0000) >> 16;
return exponent + 1;
}
}
虽然我未对其进行全面测试,但以下是一些样本输入/输出:
Value Precision 0 1 位数字。 0.000 4 位数字。 1.23 3 位数字。 12.324 5 位数字。 1.2300 5 位数字。 -5 1 位数字。 -5.01 3 位数字。 -0.012 4 位数字。 -0.100 4 位数字。 0.0 2 位数字。 10443.31 7 位数字。 -130.340 6 位数字。 -80.8000 6 位数字。
使用这段代码,我想通过执行以下操作来实现我的目标:
public static decimal DivideUsingLesserPrecision(decimal x, decimal y)
{
int xDigitCount = x.GetSignificantDigitCount();
int yDigitCount = y.GetSignificantDigitCount();
int lesserPrecision = System.Math.Min(xDigitCount, yDigitCount);
return System.Math.Round(x / y, lesserPrecision);
}
我还没有完全解决这个问题。希望有人能分享一下自己的想法:谢谢!
原始问题
假设我编写了以下代码:
decimal a = 1.23M;
decimal b = 1.23000M;
Console.WriteLine(a);
Console.WriteLine(b);
上述代码的输出结果为:
1.23 1.23000
我发现如果我使用decimal.Parse("1.23")
替换a
,并使用decimal.Parse("1.23000")
替换b
(这意味着此问题适用于程序接收用户输入的情况)也能够起到同样的效果。
因此,显然decimal
类型的值可以“感知”它所谓的精度。但是,除了ToString
本身之外,我没有看到decimal
类型上提供任何访问这种信息的成员。
假设我想要将两个decimal
值相乘,并将结果修约到较不准确参数的精度。也就是说:
decimal a = 123.4M;
decimal b = 5.6789M;
decimal x = a / b;
Console.WriteLine(x);
以上输出:
21.729560302171195125816619416
我的问题是:我应该如何编写一个方法,返回21.73
而不是原始结果(因为123.4M
有四个有效数字)?
明确一下:我知道可以在两个参数上调用ToString
,计算每个字符串中的有效数字,然后使用这个数字来舍入计算结果。如果可能的话,我正在寻找一个不同的方式。
(我也意识到,在大多数涉及有效数字的情况下,您可能不需要使用decimal
类型。但我问这个问题是因为,正如我在开头提到的那样,decimal
类型 似乎包含与精度有关的信息,而double
则不包含,就我所知。)