Проблема с запуском сборки x86-target в Win7 - PullRequest
3 голосов
/ 08 сентября 2011

У меня есть проект C #, настроенный для целевой платформы x86. Приложение отлично работает в WinXP, но в Win7 возникает проблема. Я использую VS2008.

Пожалуйста, посмотрите тестовый код ниже (проблема: он печатает 0 в WinXP и 1 в Win7).
Примечание: код также отлично работает в Win7, если он работает в режиме отладки или добавляет строку трассировки.

Пожалуйста, сообщите, спасибо!

using System;
using System.Windows.Forms;

namespace Hello
{
    public partial class MainForm : Form
    {
        public MainForm()
        {
            //The problem: it shows "0" in WinXP, and shows "1" in Win7
            MessageBox.Show(Test.GetValue().ToString());

            Environment.Exit(0);
        }
    }

    public class Test
    {
        static int a = 0;

        static public float GetValue()
        {
            float b = 0.8149883f;

            float x = (696f / b + a);

            //Note: it returns 0 if uncomments the line below, otherwise it returns 1 
            //MessageBox.Show("hello");

            return (x - (int)x);
        }
    }
}

Ответы [ 3 ]

1 голос
/ 08 сентября 2011

В дополнение к тому, что делает @CodeInChaos, вычисления с плавающей запятой различаются для разных аппаратных архитектур.Это просто природа единиц с плавающей точкой.Даже два блока FP, которые придерживаются стандарта IEEE754, могут давать разные результаты друг другу.Очевидно, что различия будут исчезающе малыми.Поэтому даже без каких-либо различий в JIT вы можете увидеть разные результаты на разных машинах.

В вашем случае вам просто нужно сравнивать значения с плавающей запятой другим способом.Вместо проверки на точное равенство, проверьте на равенство с небольшим допуском, т.е. abs(a-b)<epsilon, где epsilon - небольшое число.

1 голос
/ 08 сентября 2011

JIT-компилятор может оптимизировать число с плавающей запятой, даже если это немного меняет результат. Вы просто не можете ожидать, что результаты будут одинаковыми на всех платформах.

Иногда он интерпретирует ваш 853.9999... как 854.0, иногда он сохраняет его как 853.9999.... Это связано с тем, что на некоторых платформах промежуточные результаты рассчитываются с большей точностью. И в этот момент оно ухудшается до float меняется. В вашем примере это выглядит так, будто окно сообщения вынуждает компилятор хранить значение вне FPU, после чего оно преобразуется в 32-разрядное значение с плавающей запятой.

Смежный вопрос: Согласна ли математика с плавающей точкой в ​​C #? Это может быть?

Если производительность не слишком важна, вы можете просто использовать Decimal и получать детерминированные результаты.

0 голосов
/ 08 сентября 2011

Обратите внимание, что если вы используете double, результаты будут работать, как и ожидалось.

Если вы возьмете результат деления и посмотрите на представление в IEEE-754 как для float, так и для double, вы увидитепочему:

853.99998993850586566702859415282

Как число с плавающей запятой: 854.00000

Двойное число: 853.99998993850590

(От http://babbage.cs.qc.edu/courses/cs341/IEEE-754.html)

Почему вы видитеразные результаты между отладкой и выпуском, я не уверен - я не вижу этого в VS2010.

...