Mam problem, gdy wydaje się, że wyniki niektórych obliczeń zmieniają się po użyciu Microsoft ACE driver w celu otwarcia arkusza kalkulacyjnego Excel.Sterownik Microsoft ACE zmienia precyzję zmiennoprzecinkową w pozostałej części mojego programu.
Kod poniżej przedstawia problem.
Pierwsze dwie rozmowy z numerem DoCalculation
dają takie same wyniki. Następnie wywołuje funkcję OpenSpreadSheet
, która otwiera i zamyka arkusz kalkulacyjny programu Excel 2003 przy użyciu sterownika ACE. Nie spodziewałbyś się, że OpenSpreadSheet
będzie miał jakikolwiek wpływ na ostatnie połączenie z DoCalculation
, ale okazuje się, że wynik faktycznie się zmienia. To jest dane wyjściowe generowane przez program:
1,59142713593566
1,59142713593566
1,59142713593495
Uwaga różnice między ostatnimi 3 miejscami po przecinku. Nie wydaje się to dużą różnicą, ale w naszym kodzie produkcyjnym obliczenia są złożone, a wynikające 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 nie jest to 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ć?
Następujący kod powtarza 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
}
}
}
Dziękuję za dokładną odpowiedź. Rozumiem, że jeden wynik nie jest poprawniejszy od drugiego, ale jest problem, że sterownik ACE ma te skutki uboczne, które powodują zmiany w obliczeniach wykonanych w ramach tego samego procesu. Próbowałem twoich metod i obaj pracują. Metoda wyjątków działa jednak tylko w przypadku wersji debugowania. Dziękuję za Twój czas. –
Hmm, nie, reset ten jest również wykonywany w wersji Release. Znajduje się wewnątrz CLR, kodu, na który nie ma wpływu sposób, w jaki zbudowałeś swój program. Czy pamiętasz ostatni akapit, otrzymasz różne wyniki w wersji Release, które zależą od tego, czy masz dołączony debugger. –
Och, mój błąd. Chciałem powiedzieć, że metoda exception działa tylko w przypadku RELEASE builds - nie debugowania kompilacji. –