gpt4 book ai didi

未经检查的 uint 的 C# 溢出行为

转载 作者:行者123 更新时间:2023-12-03 15:51:31 25 4
gpt4 key购买 nike

我一直在 https://dotnetfiddle.net/ 测试此代码:

using System;

public class Program
{
const float scale = 64 * 1024;

public static void Main()
{
Console.WriteLine(unchecked((uint)(ulong)(1.2 * scale * scale + 1.5 * scale)));
Console.WriteLine(unchecked((uint)(ulong)(scale* scale + 7)));
}
}
如果我用 .NET 4.7.2 编译我得到

859091763

7


但是如果我使用 Roslyn 或 .NET Core,我会得到

859091763

0


为什么会发生这种情况?

最佳答案

我的结论是错误的。有关更多详细信息,请参阅更新。

看起来像您使用的第一个编译器中的错误。 在这种情况下,零是正确的结果 . C# 规范规定的操作顺序如下:

  • scale来自 scale , 屈服 a
  • 执行 a + 7 , 屈服 b
  • Actor bulong , 屈服 c
  • Actor cuint , 屈服 d

  • 前两个操作为您留下浮点值
    b = 4.2949673E+09f .在标准浮点运算下,这是
    4294967296 ( you can check it here )。那
    适合 ulong很好,所以 c = 4294967296 ,但它正好比
    uint.MaxValue ,所以它往返于 0 ,因此 d = 0 .现在,令人惊讶的是,因为浮点运算是
    时髦, 4.2949673E+09f4.2949673E+09f + 7完全一样
    IEEE 754 中的数字。所以 scale * scale会给你同样的值(value)
    floatscale * scale + 7 , a = b ,所以第二个操作基本上是空操作。

    Roslyn 编译器在编译时执行(一些)const 操作,并将整个表达式优化为 0 .再次, 这是正确的结果 ,并且允许编译器执行任何优化,这些优化将导致与没有它们的代码完全相同的行为。

    我的猜测是您使用的 .NET 4.7.2 编译器也试图优化它,但有一个错误导致它在错误的地方评估强制转换。当然,如果你先投 scaleuint然后执行操作,得到 7 , 因为 scale * scale往返 0然后你添加 7 .但是 这与您在运行时逐步评估表达式时得到的结果不一致 .同样,根本原因只是在查看产生的行为时的猜测,但鉴于我上面所说的一切,我确信这是第一个编译器方面的规范违规。

    更新:

    我做了一个傻瓜。有 this bit of the C# specification写上面的答案时我不知道存在的:

    Floating-point operations may be performed with higher precision than the result type of the operation. For example, some hardware architectures support an "extended" or "long double" floating-point type with greater range and precision than the double type, and implicitly perform all floating-point operations using this higher precision type. Only at excessive cost in performance can such hardware architectures be made to perform floating-point operations with less precision, and rather than require an implementation to forfeit both performance and precision, C# allows a higher precision type to be used for all floating-point operations. Other than delivering more precise results, this rarely has any measurable effects. However, in expressions of the form x * y / z, where the multiplication produces a result that is outside the double range, but the subsequent division brings the temporary result back into the double range, the fact that the expression is evaluated in a higher range format may cause a finite result to be produced instead of an infinity.



    C# 保证操作提供至少在 IEEE 754 级别上的精度级别,但不一定完全如此。这不是错误,而是规范功能。 Roslyn 编译器有权完全按照 IEEE 754 的规定计算表达式,而另一个编译器有权推导出 2^32 + 77当放入 uint .

    我很抱歉我误导性的第一个答案,但至少我们今天都学到了一些东西。

    关于未经检查的 uint 的 C# 溢出行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59815362/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com