C# 什么时候通过十进制从浮点转换为双精度有益
我们现有的应用程序从文件中读取一些浮点数。这些数字是由其他应用程序(我们称之为应用程序B)写入的。这个文件的格式很久以前就被修复了(我们无法更改它)。在该文件中,所有浮点数都以二进制表示形式保存为浮点数(文件中为4字节) 在我们的程序中,当我们读取数据时,我们将浮点转换为双倍,并在所有计算中使用双倍,因为计算非常广泛,我们关心舍入误差的传播 我们注意到,当我们通过十进制转换浮点数时(见下面的代码),我们得到的结果比直接转换时更精确。注意:应用程序B在内部也使用double,并且只将它们作为float写入文件。假设应用程序B将数字0.012作为float写入文件。如果我们在读取后将其转换为十进制,然后再转换为双精度,我们得到的正好是0.012,如果我们直接转换,我们得到0.0120000001043081 无需读取文件即可复制此文件-仅需分配:C# 什么时候通过十进制从浮点转换为双精度有益,c#,rounding,C#,Rounding,我们现有的应用程序从文件中读取一些浮点数。这些数字是由其他应用程序(我们称之为应用程序B)写入的。这个文件的格式很久以前就被修复了(我们无法更改它)。在该文件中,所有浮点数都以二进制表示形式保存为浮点数(文件中为4字节) 在我们的程序中,当我们读取数据时,我们将浮点转换为双倍,并在所有计算中使用双倍,因为计算非常广泛,我们关心舍入误差的传播 我们注意到,当我们通过十进制转换浮点数时(见下面的代码),我们得到的结果比直接转换时更精确。注意:应用程序B在内部也使用double,并且只将它们作为flo
float readFromFile = 0.012f;
Console.WriteLine("Read from file: " + readFromFile);
//prints 0.012
double forUse = readFromFile;
Console.WriteLine("Converted to double directly: " + forUse);
//prints 0.0120000001043081
double forUse1 = (double)Convert.ToDecimal(readFromFile);
Console.WriteLine("Converted to double via decimal: " + forUse1);
//prints 0.012
通过十进制从浮点转换为双精度总是有益的吗?如果不是,在什么条件下是有益的
编辑:应用程序B可以通过两种方式获得保存的值:
float
和double
都不能精确表示3/250。您得到的是字符串格式化程序Double.ToString()
作为“0.012”
呈现的值。但这是因为格式化程序没有显示确切的值
通过十进制
会导致四舍五入。只使用Math.Round
和所需的舍入参数可能会更快(更不用说更容易理解)。如果您关心的是有效位数,请参阅:
值得一提的是,
0.012f
(这意味着最接近0.012的32位IEEE-754值)正好是
0x3C449BA6
或
这可以精确地表示为系统.Decimal
。但是Convert.ToDecimal(0.012f)
不会给出准确的值--per
此方法返回的十进制
值最多包含七位有效数字。如果值参数包含七个以上的有效数字,则使用舍入到最接近值对其进行舍入
这里有一个不同的答案——我不确定它是否比Ben的好(几乎可以肯定不是),但它应该产生正确的结果:
float readFromFile = 0.012f;
decimal forUse = Convert.ToDecimal(readFromFile.ToString("0.000"));
只要.ToString(“0.000”)
生成了“正确”的数字(应该很容易抽查),那么您就可以使用它,而不必担心舍入错误。如果需要更高的精度,只需添加更多的0
当然,如果您确实需要将
0.012f
转换到最大精度,那么这不会有什么帮助,但如果是这样,那么您首先就不想将其从浮点转换为十进制。看起来很奇怪,通过十进制转换(使用转换.ToDecimal(float)
)在某些情况下可能是有益的
如果知道原始数字是由用户以十进制表示提供的,并且用户键入的有效数字不超过7位,则将提高精度。
为了证明这一点,我编写了一个小程序(见下文)。解释如下:
正如您从OP中回忆到的,这是一系列步骤:
(双精度)Convert.ToDecimal(float)
转换为十进制Convert.ToDecimal(float)
()将结果舍入到7位有效的十进制数字。在维基百科的about Single中,我们可以看到精度是24位-相当于log10(pow(2,24))≈ 7.225位小数。
因此,当我们转换为小数时,我们会丢失0.225位小数
因此,在一般情况下,当没有关于双精度的附加信息时,在大多数情况下转换为十进制会使我们失去一些精度。
但是(!)如果有额外的知识,最初(在作为浮点写入文件之前)双精度是不超过7位的小数,在小数舍入中引入的舍入误差(上面的步骤3(b)将补偿在二进制舍入中引入的舍入误差(在上述步骤2中)
在证明一般情况下语句的程序中,我随机生成double,然后将其转换为float,然后直接将其转换回double(a),通过十进制(b),然后测量原始double与double(a)和double(b)之间的距离。如果double(a)比double(b)更接近原始double(b),我增加pro-direct转换计数器,在相反的情况下,我增加pro-viaDecimal计数器。我在一个1百万个周期的循环中进行,然后我打印pro-direct与pro-viaDecimal计数器的比率。比率大约为3.7,即大约在5个循环中的4个循环中
float readFromFile = 0.012f;
decimal forUse = Convert.ToDecimal(readFromFile.ToString("0.000"));
private static void CompareWhichIsBetter(int numTypedDigits)
{
Console.WriteLine("Number of typed digits: " + numTypedDigits);
Random rnd = new Random(DateTime.Now.Millisecond);
int countDecimalIsBetter = 0;
int countDirectIsBetter = 0;
int countEqual = 0;
for (int i = 0; i < 1000000; i++)
{
double origDouble = rnd.NextDouble();
//Use the line below for the user-typed-in-numbers case.
//double origDouble = Math.Round(rnd.NextDouble(), numTypedDigits);
float x = (float)origDouble;
double viaFloatAndDecimal = (double)Convert.ToDecimal(x);
double viaFloat = x;
double diff1 = Math.Abs(origDouble - viaFloatAndDecimal);
double diff2 = Math.Abs(origDouble - viaFloat);
if (diff1 < diff2)
countDecimalIsBetter++;
else if (diff1 > diff2)
countDirectIsBetter++;
else
countEqual++;
}
Console.WriteLine("Decimal better: " + countDecimalIsBetter);
Console.WriteLine("Direct better: " + countDirectIsBetter);
Console.WriteLine("Equal: " + countEqual);
Console.WriteLine("Betterness of direct conversion: " + (double)countDirectIsBetter / countDecimalIsBetter);
Console.WriteLine("Betterness of conv. via decimal: " + (double)countDecimalIsBetter / countDirectIsBetter );
Console.WriteLine();
}