对double进行转换是否始终返回相同的值?

时间:2012-03-16 19:00:56

标签: c# floating-point double rounding

double投射到float总是会产生相同的结果,还是会出现一些“舍入差异”?

例如,

中的x
float x = (float)0.123456789d;

始终是相同的值?

当将float转换为double,然后将其转换回float时,该怎么办? (float)(double)someFloat

最感兴趣的是C#中的结果,但如果您对其他语言的工作原理有所了解,请随时分享。

6 个答案:

答案 0 :(得分:12)

除非语言偏离IEEE规范,否则结果不应取决于语言。

所有浮点数都可以精确地表示为双精度数,因此从浮点数到双精度数到浮点数的往返行程应该产生与您开始时相同的值。

类似地,将任何double值转换为float应始终产生相同的结果,但是,当然,有许多不同的double值会截断为相同的float值。

答案 1 :(得分:6)

如果您向下转发 doublefloat,您将失去精确度和数据。将float上传到double扩展转换;如果然后往返,则不会丢失任何数据...也就是说,除非您在将其向下转换回浮点之前对该值执行某些操作

浮点数会牺牲范围的精度和准确度。单精度浮点数可提供32位精度;双精度给你64位。但是它们可以表示超出基础精度指示范围的值。

C#floatdouble是IEEE 754浮点值。

尾数的有效精度比其表观大小(浮点魔法)高1位。

为您提供一些CLR浮点资源:

本文可能是关于浮点运算的危险和陷阱的规范性论文。如果您不是ACM的成员,请单击标题上的链接以查找该文章的公开下载:

  • David Goldberg。 1991年。What every computer scientist should know about floating-point arithmetic。 ACM Comput。监测网。 23,1(1991年3月),5-48。 DOI = 10.1145 / 103162.103163 http://doi.acm.org/10.1145/103162.103163
      

    <强>抽象
      浮点算术被许多人视为深奥的主题。   这是相当令人惊讶的,因为浮点在计算机系统中无处不在:   几乎每种语言都有浮点数据类型;从PC到PC的电脑   超级计算机有浮点加速器;大多数编译器都会被调用   不时编译浮点算法;几乎每一次操作   系统必须响应浮点异常,例如溢出。这篇报告   介绍了一个直接影响浮点方面的教程   计算机系统的设计者。它以浮点背景开始   表示和舍入错误,继续讨论IEEE浮动   点标准,并以计算机系统构建者如何能够的示例作为结束   更好地支持浮点。

答案 2 :(得分:1)

考虑到它们具有不同的精度,即使我从较低精度到较宽精度(我认为这实际上是你的怀疑),结果也不能总是相同。

浮点运算,尤其是转换,始终是截断/舍入和任何其他类型的近似的主题。

答案 3 :(得分:1)

在某些情况下,对数字数量的最接近的float表示可能与通过将最近的double表示四舍五入到float而获得的值不同。两个这样的数量是12,344,321.4999999991和12,345,678.50000000093。这些数量上下的整数可以精确表示为float,但每个最接近double的部分精确为0.5。因为将这样的double值(在2 ^ 23和2 ^ 24之间,精确到0.5的一小部分)转换为float将舍入到最接近的偶数整数;在每种情况下,编译器都会从最接近原始数字的值开始四舍五入。

请注意,在实践中,编译器似乎将数字解析为double,然后转换为float,因此即使12344321.4999999991f应该舍入到12344321f,它也会舍入到12344322f。同样,12345678.50000000093f应舍入为12345679f但舍入为12345678f,因此即使转换为double然后float失去精度,也无法通过将数字直接指定为float来避免此类转换损失

顺便提一下,值12344321.4999999992f和12345678.50000000094f正确舍入。

答案 4 :(得分:0)

double应该能够准确地保存float的每个可能值。将float转换为double不应更改该值,并且只要在此期间未对double执行任何计算,则返回到float应该返回原始值。

答案 5 :(得分:0)

C#中的浮点数使用IEEE 754格式存储(http://en.wikipedia.org/wiki/IEEE_754)。这种格式有两部分:数字和指数。双打保持52位数,浮动保持23位数。基数是2,而不是10。因此,对于上面的示例(0.123456789),数字将是111010110111100110100010101(123456789的二进制表示)。这是27位数,它很适合双倍,但不是浮点数,所以是的,在往返转换中精度会丢失。

另一方面,如果你的数字是0.123456,那么数字将是11110001001000000(17位数),它可以很好地适合浮点数或小数点,所以在往返演员中你将失去精确度。