Sur la base des observations par @CodeInChaos et @Alexandre C, j'ai été en mesure de jeter ensemble un peu de code pour reproduire le problème sur mon PC (Win7 x64, .NET 4.0). Il apparaît que ce problème est dû à des nombres dénormalisés de contrôle qui peut être défini à l'aide de _controlfp_s. La valeur de la double.Epsilon est le même dans les deux cas, mais la façon dont il est évalué les changements lorsque les nombres dénormalisés de contrôle est activé à partir de l'ENREGISTRER pour le RINCER.
Voici un exemple de code:
using System;
using System.Runtime.InteropServices;
namespace fpuconsole
{
class Program
{
[DllImport("msvcrt.dll", EntryPoint = "_controlfp_s",
CallingConvention = CallingConvention.Cdecl)]
public static extern int ControlFPS(IntPtr currentControl,
uint newControl, uint mask);
public const int MCW_DN= 0x03000000;
public const int _DN_SAVE = 0x00000000;
public const int _DN_FLUSH = 0x01000000;
static void PrintLog10()
{
//Display original values
Console.WriteLine("_controlfp_s Denormal Control untouched");
Console.WriteLine("\tCurrent _controlfp_s control word: 0x{0:X8}",
GetCurrentControlWord());
Console.WriteLine("\tdouble.Epsilon = {0}", double.Epsilon);
Console.WriteLine("\tMath.Log10(double.Epsilon) = {0}",
Math.Log10(double.Epsilon));
Console.WriteLine("");
//Set Denormal to Save, calculate Math.Log10(double.Epsilon)
var controlWord = new UIntPtr();
var err = ControlFPS(controlWord, _DN_SAVE, MCW_DN);
if (err != 0)
{
Console.WriteLine("Error setting _controlfp_s: {0}", err);
return;
}
Console.WriteLine("_controlfp_s Denormal Control set to SAVE");
Console.WriteLine("\tCurrent _controlfp_s control word: 0x{0:X8}",
GetCurrentControlWord());
Console.WriteLine("\tdouble.Epsilon = {0}", double.Epsilon);
Console.WriteLine("\tMath.Log10(double.Epsilon) = {0}",
Math.Log10(double.Epsilon));
Console.WriteLine("");
//Set Denormal to Flush, calculate Math.Log10(double.Epsilon)
err = ControlFPS(controlWord, _DN_FLUSH, MCW_DN);
if (err != 0)
{
Console.WriteLine("Error setting _controlfp_s: {0}", err);
return;
}
Console.WriteLine("_controlfp_s Denormal Control set to FLUSH");
Console.WriteLine("\tCurrent _controlfp_s control word: 0x{0:X8}",
GetCurrentControlWord());
Console.WriteLine("\tdouble.Epsilon = {0}", double.Epsilon);
Console.WriteLine("\tMath.Log10(double.Epsilon) = {0}",
Math.Log10(double.Epsilon));
Console.WriteLine("");
}
static int GetCurrentControlWord()
{
unsafe
{
var controlWord = 0;
var controlWordPtr = &controlWord;
ControlFPS((IntPtr)controlWordPtr, 0, 0);
return controlWord;
}
}
static void Main(string[] args)
{
PrintLog10();
}
}
}
Un couple de choses à noter. Tout d'abord, j'ai eu de spécifier CallingConvention = CallingConvention.Cdecl
sur le ControlFPS
déclaration pour éviter un déséquilibre de la pile d'exception pendant le débogage. Deuxièmement, j'ai dû recourir à la contamination de code pour récupérer la valeur du mot de contrôle en GetCurrentControlWord()
. Si quelqu'un connaît une meilleure façon d'écrire la méthode, s'il vous plaît laissez-moi savoir.
Voici le résultat:
_controlfp_s Denormal Control untouched
Current _controlfp_s control word: 0x0009001F
double.Epsilon = 4.94065645841247E-324
Math.Log10(double.Epsilon) = -323.306215343116
_controlfp_s Denormal Control set to SAVE
Current _controlfp_s control word: 0x0009001F
double.Epsilon = 4.94065645841247E-324
Math.Log10(double.Epsilon) = -323.306215343116
_controlfp_s Denormal Control set to FLUSH
Current _controlfp_s control word: 0x0109001F
double.Epsilon = 4.94065645841247E-324
Math.Log10(double.Epsilon) = -Infinity
Pour déterminer ce qui se passe avec machine et la machine B, vous pouvez prendre l'exemple d'application ci-dessus et de les exécuter sur chaque machine. Je pense que vous allez trouver que:
- Machine et la Machine B sont à l'aide de différents paramètres pour _controlfp_s dès le début. L'exemple d'application montrent différentes de contrôle de la valeur d'un mot dans le premier bloc de sorties sur Une Machine que sur une Machine B. Après l'application des forces de nombres dénormalisés de contrôle pour ENREGISTRER, puis la sortie doit correspondre. Si c'est le cas, alors peut-être vous pouvez simplement la force de nombres dénormalisés de contrôle pour ENREGISTRER sur la Machine B lorsque l'application démarre.
- Machine et la Machine B utilisez les mêmes paramètres pour _controlfp_s, et la sortie de l'exemple d'application est exactement le même sur les deux machines. Si c'est le cas, alors il doit y avoir un peu de code dans votre application (éventuellement DirectX, WPF?) c'est en feuilletant le _controlfp_s réglages sur la Machine B, mais pas sur la Machine A.
Si vous obtenez une chance d'essayer l'exemple d'application sur chaque machine, veuillez mettre à jour les commentaires avec les résultats. Je suis intéressé de voir ce qui se passe.