В некотором числовом коде я заметил, что сборка отладки и выпуска при компиляции для x86 или с AnyCPU + «Prefer 32-bit» давала разные результаты.Я разбил свой код до минимума, который воспроизводит проблему.Оказывается, что только один бит изменяется на одном из этапов вычисления.
Код:
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
В Int64 сборка Debug дает 4498558851738655340
, а сборка Release дает 4498558851738655341
(обратите внимание на последнюю цифру).
Я попытался включить оптимизацию вручную в отладочной сборке (а также константу DEBUG и генерацию pdb), но результат остался прежним.Только изменение полного типа сборки на Release приводит к изменению результата.
Идя дальше, я попытался сравнить IL, как указано в JustDecompile от Telerik:
Отладочная сборка:
.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
}
Выпуск сборки:
.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
}
Как видите, это почти то же самое.Единственное отличие - две дополнительные команды nop (которые ничего не должны делать?).
Теперь мой вопрос: я что-то не так делаю, компилятор или фреймворк делают что-то странное, или это так?Я знаю, что не каждое число может быть представлено ровно в два раза.Вот почему я сравниваю представления Int64.Однако я понимаю, что результаты не должны меняться между сборками.
Учитывая, что простое включение оптимизаций не меняет его, какова дальнейшая разница между Debug и Release, которая может вызвать это?
Я компилирую для .NET Framework 4.5, и, как я уже говорил выше, ошибка возникает только в сборках x86 (или AnyCPU + Prefer 32-bit option).
Редактировать: ВВ свете комментариев Томера, этот вопрос рассматривает аналогичную идею, в то же время уделяя больше внимания различиям в сборках Debug / Release.Я все еще нахожу немного странным, что разные архитектуры должны давать разные результаты, хотя при запуске одного и того же кода.Это по замыслу?Как я могу доверять значениям, которые я тогда вычисляю?