Драйвер Microsoft ACE изменяет точность с плавающей запятой в остальной части моей программы

У меня возникла проблема, когда кажется, что результаты некоторых вычислений меняются после использованияMicrosoft ACE драйвер открыть электронную таблицу Excel.

Код ниже воспроизводит проблему.

Первые два звонкаDoCalculation дают одинаковые результаты. Тогда я вызываю функциюOpenSpreadSheet который открывает и закрывает электронную таблицу Excel 2003 с помощью драйвера ACE. Вы не ожидаетеOpenSpreadSheet иметь какое-либо влияние на последний звонокDoCalculation но получается, что результат действительно меняется. Это вывод, который генерирует программа:

1,59142713593566
1,59142713593566
1,59142713593495

Обратите внимание на различия в последних 3 десятичных разрядах. Это не кажется большой разницей, но в нашем производственном коде вычисления сложны, и результирующие различия довольно велики.

Не имеет значения, если я использую драйвер JET вместо драйвера ACE. Если я изменю типы с двойного на десятичный, ошибка исчезнет. Но это не вариант в нашем производственном коде.

Я использую 64-разрядную версию Windows 7, и сборки скомпилированы для .NET 4.5 x86. Использование 64-битного драйвера ACE не вариант, так как мы используем 32-битный Office.

Кто-нибудь знает, почему это происходит и как я могу это исправить?

Следующий код воспроизводит мою проблему:

static void Main(string[] args)
{
    DoCalculation();
    DoCalculation();
    OpenSpreadSheet();
    DoCalculation();
}

static void DoCalculation()
{
    // Multiply two randomly chosen number 10.000 times.
    var d1 = 1.0003123132;
    var d3 = 0.999734234;

    double res = 1;
    for (int i = 0; i < 10000; i++)
    {
        res *= d1 * d3;
    }
    Console.WriteLine(res);
}

public static void OpenSpreadSheet()
{
    var cn = new OleDbConnection(@"Provider=Microsoft.ACE.OLEDB.12.0;data source=c:\temp\workbook1.xls;Extended Properties=Excel 8.0");
    var cmd = new OleDbCommand("SELECT [Column1] FROM [Sheet1$]", cn);
    cn.Open();

    using (cn)
    {
        using (OleDbDataReader reader = cmd.ExecuteReader())
        {
            // Do nothing
        }
    }
}

Ответы на вопрос(1)

Ваш ответ на вопрос