Der Microsoft ACE-Treiber ändert die Gleitkommapräzision im Rest meines Programms

Ich habe ein Problem, bei dem es den Anschein hat, dass sich die Ergebnisse einiger Berechnungen ändern, nachdem ich das verwendet habeMicrosoft ACE-Treiber um eine Excel-Tabelle zu öffnen.

Der folgende Code gibt das Problem wieder.

Die ersten beiden Anrufe nachDoCalculation die gleichen Ergebnisse erzielen. Dann rufe ich die Funktion aufOpenSpreadSheet Hiermit wird eine Excel 2003-Tabelle mithilfe des ACE-Treibers geöffnet und geschlossen. Das würdest du nicht erwartenOpenSpreadSheet Auswirkungen auf den letzten Anruf zu habenDoCalculation Es stellt sich jedoch heraus, dass sich das Ergebnis tatsächlich ändert. Dies ist die Ausgabe, die das Programm generiert:

1,59142713593566
1,59142713593566
1,59142713593495

Beachten Sie die Unterschiede in den letzten 3 Dezimalstellen. Dies scheint kein großer Unterschied zu sein, aber in unserem Produktionscode sind die Berechnungen komplex und die resultierenden Unterschiede sind ziemlich groß.

Es macht keinen Unterschied, ob ich den JET-Treiber anstelle des ACE-Treibers verwende. Wenn ich die Typen von doppelt auf dezimal ändere, verschwindet der Fehler. Dies ist jedoch in unserem Produktionscode keine Option.

Ich laufe auf einem Windows 7 64-Bit und die Assemblys sind für .NET 4.5 x86 kompiliert. Die Verwendung des 64-Bit-ACE-Treibers ist keine Option, da 32-Bit-Office ausgeführt wird.

Weiß jemand, warum dies geschieht und wie ich es beheben kann?

Der folgende Code reproduziert mein 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
        }
    }
}

Antworten auf die Frage(1)

Ihre Antwort auf die Frage