Jen*_*ens 7 .net vb.net roslyn
在一些数字代码中,我注意到编译为x86或使用AnyCPU +"Prefer 32-bit"时的调试和发布版本给出了不同的结果.我已经将我的代码分解为几乎无法重现问题的最低限度.事实证明,在其中一个计算步骤中只有1位发生了变化.
代码:
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim tau = 0.000001
Dim a = 0.5
Dim value2 = (2 * Math.PI * 0.000000001 * tau) ^ a * Math.Sin(a * (Math.PI / 2))
RichTextBox1.Text = BitConverter.DoubleToInt64Bits(value2).ToString
End Sub
Run Code Online (Sandbox Code Playgroud)
在Int64中,Debug构建给出4498558851738655340,Release构建给出4498558851738655341(注意最后一位数).
我尝试在调试版本中手动启用优化(同样也是DEBUG常量和pdb生成),但结果保持不变.仅将完整构建类型更改为Release会更改结果.
更进一步,我试图比较Telerik的JustDecompile给出的IL:
调试版本:
.method private instance void Button1_Click (
object sender,
class [mscorlib]System.EventArgs e
) cil managed
{
.locals init (
[0] float64 V_0,
[1] float64 V_1,
[2] float64 V_2,
[3] int64 V_3
)
IL_0000: nop
IL_0001: ldc.r8 1E-06
IL_000a: stloc.0
IL_000b: ldc.r8 0.5
IL_0014: stloc.1
IL_0015: ldc.r8 6.2831853071795863E-09
IL_001e: ldloc.0
IL_001f: mul
IL_0020: ldloc.1
IL_0021: call float64 [mscorlib]System.Math::Pow(float64, float64)
IL_0026: ldloc.1
IL_0027: ldc.r8 1.5707963267948966
IL_0030: mul
IL_0031: call float64 [mscorlib]System.Math::Sin(float64)
IL_0036: mul
IL_0037: stloc.2
IL_0038: ldarg.0
IL_0039: callvirt instance class [System.Windows.Forms]System.Windows.Forms.RichTextBox CETestGenerator.Form1::get_RichTextBox1()
IL_003e: ldloc.2
IL_003f: call int64 [mscorlib]System.BitConverter::DoubleToInt64Bits(float64)
IL_0044: stloc.3
IL_0045: ldloca.s V_3
IL_0047: call instance string [mscorlib]System.Int64::ToString()
IL_004c: callvirt instance void [System.Windows.Forms]System.Windows.Forms.RichTextBox::set_Text(string)
IL_0051: nop
IL_0052: ret
}
Run Code Online (Sandbox Code Playgroud)
发布版本:
.method private instance void Button1_Click (
object sender,
class [mscorlib]System.EventArgs e
) cil managed
{
.locals init (
[0] float64 V_0,
[1] float64 V_1,
[2] float64 V_2,
[3] int64 V_3
)
IL_0000: ldc.r8 1E-06
IL_0009: stloc.0
IL_000a: ldc.r8 0.5
IL_0013: stloc.1
IL_0014: ldc.r8 6.2831853071795863E-09
IL_001d: ldloc.0
IL_001e: mul
IL_001f: ldloc.1
IL_0020: call float64 [mscorlib]System.Math::Pow(float64, float64)
IL_0025: ldloc.1
IL_0026: ldc.r8 1.5707963267948966
IL_002f: mul
IL_0030: call float64 [mscorlib]System.Math::Sin(float64)
IL_0035: mul
IL_0036: stloc.2
IL_0037: ldarg.0
IL_0038: callvirt instance class [System.Windows.Forms]System.Windows.Forms.RichTextBox CETestGenerator.Form1::get_RichTextBox1()
IL_003d: ldloc.2
IL_003e: call int64 [mscorlib]System.BitConverter::DoubleToInt64Bits(float64)
IL_0043: stloc.3
IL_0044: ldloca.s V_3
IL_0046: call instance string [mscorlib]System.Int64::ToString()
IL_004b: callvirt instance void [System.Windows.Forms]System.Windows.Forms.RichTextBox::set_Text(string)
IL_0050: ret
}
Run Code Online (Sandbox Code Playgroud)
如你所见,它几乎是一样的.唯一的区别是两个额外的nop命令(不应该做什么?).
现在我的问题是,我做错了什么,编译器或框架做了什么奇怪的事情,或者这只是它的方式?我知道不是每个数字都可以用双精度表示.这就是我比较Int64表示的原因.但我的理解是,结果不应该在构建之间发生变化.
鉴于只是启用优化不会改变它,Debug和Release之间的进一步区别是什么?
我正在为.NET Framework 4.5编译,正如我上面所说,错误只发生在x86版本中(或AnyCPU + Prefer 32位选项).
编辑: 根据Tomers的评论,这个问题对待一个类似的想法,同时更专注于调试/发布构建差异.我仍然觉得有点奇怪,不同的架构虽然运行相同的代码时应该给出不同的结果.这是设计的吗?我怎么能相信我计算的价值呢?
在 上,我已经在使用和使用Windows 11上测试了您的代码(经过一些调整)。Visual Studio 2019.Net Framework 4.7.2Visual Studio 2022.Net 6
使用Debug或Release版本显示的结果始终相同。我看不出有什么区别。
Visual Studio 2019始终返回以 40 结尾的值作为调试版本,并Visual Studio 2022在为 cible 编译时返回以 41 结尾的值x64。
Visual Studio 2022我的 PC 上安装的是 64 位应用程序。
我使用过以下程序
Imports System
Module Program
Sub Main(args As String())
Dim tau As Double = 0.000001
Dim a As Double = 0.5
Dim n1 = 2 * Math.PI * 0.000000001 * tau
Dim n2 = Math.Sin(a * (Math.PI / 2))
Dim n3 = n1 ^ a
Dim n4 = n3 * n2
Dim x2 = Math.Sin(Math.PI * a / 2)
Dim x3 = a * Math.PI / 2
Dim x4 = Math.Sin(x3)
Dim x5 = Math.Sin(0.78539816339744828)
Dim value2 As Double = (2 * Math.PI * 0.000000001 * tau) ^ a * Math.Sin(a * (Math.PI / 2))
Dim s As String = BitConverter.DoubleToInt64Bits(value2).ToString
Console.WriteLine(">> 64 bits signed integer : " & s)
Console.WriteLine(">> n1 : " & n1)
Console.WriteLine(">> n2 : " & n2)
Console.WriteLine(">> n3 : " & n3)
Console.WriteLine(">> n4 : " & n4)
Console.WriteLine(">> 64 bits n4: " & BitConverter.DoubleToInt64Bits(n4).ToString)
Console.WriteLine(">> x2 : " & x2)
Console.WriteLine(">> x3 : " & x3)
Console.WriteLine(">> x4 : " & x4)
Console.WriteLine(">> x5 : " & x5)
End Sub
End Module
Run Code Online (Sandbox Code Playgroud)
x86构建显示以下结果
>> 64 bits signed integer : 4498558851738655340
>> n1 : 6,283185307179586E-15
>> n2 : 0,7071067811865475
>> n3 : 7,926654595212022E-08
>> n4 : 5,604991216397928E-08
>> 64 bits n4: 4498558851738655340
>> x2 : 0,7071067811865475
>> x3 : 0,7853981633974483
>> x4 : 0,7071067811865475
>> x5 : 0,7071067811865475
Run Code Online (Sandbox Code Playgroud)
x64构建显示以下结果
>> 64 bits signed integer : 4498558851738655341
>> n1 : 6,283185307179586E-15
>> n2 : 0,7071067811865476
>> n3 : 7,926654595212022E-08
>> n4 : 5,6049912163979286E-08
>> 64 bits n4: 4498558851738655341
>> x2 : 0,7071067811865476
>> x3 : 0,7853981633974483
>> x4 : 0,7071067811865476
>> x5 : 0,7071067811865476
Run Code Online (Sandbox Code Playgroud)
x86和版本之间的差异x64是由于Math.Sin()功能造成的(参见变量 x4 和 x5)!
| 归档时间: |
|
| 查看次数: |
137 次 |
| 最近记录: |