这是一个错误吗?浮动操作被视为整数

Mar*_*287 9 c# asp.net

此操作返回0:

string value = “0.01”;
float convertedValue = float.Parse(value);
return (int)(convertedValue * 100.0f);
Run Code Online (Sandbox Code Playgroud)

但是这个操作返回1:

string value = “0.01”;
float convertedValue = float.Parse(value) * 100.0f;
return (int)(convertedValue);
Run Code Online (Sandbox Code Playgroud)

因为convertedValue是一个浮点数,它在括号内*100f它不应该被视为浮点运算吗?

Ken*_*rey 19

两者之间的区别在于编译器优化浮点运算的方式.让我解释.

string value = "0.01";
float convertedValue = float.Parse(value);
return (int)(convertedValue * 100.0f);
Run Code Online (Sandbox Code Playgroud)

在此示例中,该值被解析为80位浮点数,以便在计算机的内部浮点地牢中使用.然后将其转换为32位浮点数以存储在convertedValue变量中.这导致该值四舍五入到似乎小于0.01的数字.然后将其转换回80位浮点数并乘以100,将舍入误差增加100倍.然后它被转换为32位int.这会导致浮动被截断,并且因为它实际上略小于1,所以int转换返回0.

string value = "0.01";
float convertedValue = float.Parse(value) * 100.0f;
return (int)(convertedValue);
Run Code Online (Sandbox Code Playgroud)

在此示例中,该值再次被解析为80位浮点数.然后在它转换为32位浮点数之前再乘以100.这意味着舍入误差非常小,以至于当它被转换为32位浮点数进行存储时convertedValue,它将精确地舍入为1.然后当它转换为int时,得到1.

主要思想是计算机使用高精度浮点数进行计算,然后在将值存储在变量中时对其进行舍入.使用浮点数的分配越多,舍入错误累积的越多.

  • 这是一个典型的答案; 我只想回应CodeInChaos的观点,即允许C#和JIT编译器在他们的奇思妙想*完全进行优化*,并且它基本上归结为寄存器调度的细节.CodeInChaos还正确地指出,转换为float会禁用优化. (4认同)

Cod*_*aos 14

请阅读浮点介绍.这是典型的浮点问题.二进制浮点不能完全表示0.01.

0.01 * 100 约为1.

如果它恰好被四舍五入到0.999...你得到0,如果它四舍五入1.000...你得到1.你得到的那个是未定义的.

每次遇到类似的表达式(甚至不同的上下文中的相同表达式)时,jit编译器都不需要以相同的方式进行舍入.特别是它可以随时使用更高的精度,但如果它认为这是一个好主意,可以降级到32位浮点数.


一个有趣的观点是显式转换float(即使您已经有类型的表达式float).这会强制JITer将精度降低到该点的32位浮点数.但确切的舍入仍未定义.

由于舍入未定义,因此可以在.net版本,调试/发布版本,调试器的存在(以及可能的月相:P)之间变化.

浮点数(静态,数组元素和类的字段)的存储位置具有固定大小.支持的存储大小为float32和float64.其他地方(在评估堆栈上,作为参数,作为返回类型和作为局部变量)浮点数使用内部浮点类型表示.

当内部表示具有比其标称类型更大的范围和/或精度的浮点值被放入存储位置时,它将自动强制转换为存储位置的类型.这可能涉及精度损失或创建超出范围的值(NaN,+无穷大或无穷大).但是,如果在未经修改的情况下从存储位置重新加载该值,则该值可能会保留在内部表示中以供将来使用. 编译器有责任确保保留值在后续加载时仍然有效,同时考虑到别名和其他执行线程的影响(参见内存模型(第12.6节)).但是,在执行显式转换(conv.r4或conv.r8)之后,不允许进行额外精度的自由,此时内部表示必须在关联类型中准确表示.


您的具体问题可以通过使用来解决Decimal,但类似的问题3*(1/3f)将无法解决,因为Decimal不能完全代表三分之一.

  • @NoonSilk:这个答案绝不是错的.低估一个非常好的答案因为**那些在忙碌的一天中抽出时间来帮助你的人没有为懒得在搜索引擎中键入关键字的人提供链接**是一种不好的方式来感谢某人尝试增加价值. (9认同)
  • 你应该强调这不是一个错误的事实. (4认同)
  • @ user1270287因为它可以.如果需要,jit-compiler可以自由地使用更高的精度,但不是必需的.有时确实如此,有时却没有. (2认同)
  • @Noon行为*被允许是非确定性的,这是未定义的整点,兔子可以从帽子中拔出,并且他们的耳朵长度用于确定内部计算的精确度.不提供链接的投票只是蹩脚的. (2认同)