Sterownik Microsoft ACE zmienia precyzję zmiennoprzecinkową w pozostałej części mojego programu

Mam problem, gdzie wydaje się, że wyniki niektórych obliczeń zmieniają się po użyciuSterownik Microsoft ACE aby otworzyć arkusz kalkulacyjny Excel.

Poniższy kod odtwarza problem.

Pierwsze dwa połączeniaDoCalculation dają takie same wyniki. Następnie dzwonię do funkcjiOpenSpreadSheet który otwiera i zamyka arkusz kalkulacyjny Excel 2003 za pomocą sterownika ACE. Nie spodziewałbyś sięOpenSpreadSheet mieć jakikolwiek wpływ na ostatnie połączenieDoCalculation ale okazuje się, że wynik rzeczywiście się zmienia. Jest to wyjście generowane przez program:

1,59142713593566
1,59142713593566
1,59142713593495

Zwróć uwagę na różnice w 3 ostatnich miejscach po przecinku. Nie wydaje się to dużą różnicą, ale w naszym kodzie produkcyjnym obliczenia są złożone, a wynikające stąd różnice są dość duże.

Nie ma znaczenia, czy używam sterownika JET zamiast sterownika ACE. Jeśli zmienię typy z podwójnego na dziesiętny, błąd zniknie. Ale to nie jest opcja w naszym kodzie produkcyjnym.

Używam 64-bitowego systemu Windows 7, a zestawy są kompilowane dla .NET 4.5 x86. Używanie 64-bitowego sterownika ACE nie jest opcją, ponieważ używamy 32-bitowego pakietu Office.

Czy ktoś wie, dlaczego tak się dzieje i jak mogę to naprawić?

Poniższy kod powiela mój problem:

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
        }
    }
}

questionAnswers(1)

yourAnswerToTheQuestion