2012-02-22 18 views
11

La máquina épsilon se define canónicamente como el número más pequeño que, sumado a uno, da un resultado diferente de uno.¿Dónde encuentro la máquina épsilon en C#?

Hay un Double.Epsilon pero el nombre es muy engañoso: es el valor más pequeño (desnormalizado) Double representable, y por lo tanto inútil para cualquier tipo de programación numérica.

Me gustaría obtener el verdadero épsilon para el tipo Double, para no tener que codificar las tolerancias en mi programa. Cómo hago esto ?

+0

Relevante: http://www.johndcook.com/blog/2010/06/08/c-math-gotchas/ – AakashM

+0

@AakashM: Lo leí. El significado de épsilon es bastante claro a la vista de IEEE754, y es una pena que Microsoft haya hecho algo así de amateur. ¿Es confiable su implementación en coma flotante? –

+0

@AlexandreC .: 'Double.MinValue' se define muy probablemente como corresponde a los otros campos 'MinValue' en .NET Framework como' Int32.MinValue', 'DateTime.MinValue' etc. Esto obviamente no es el igual que 'DBL_MIN' en C. Sin embargo, estoy de acuerdo en que la definición de' Double.Epsilon' es confusa. –

Respuesta

8

Es (en mi máquina):

1.11022302462516E-16 

se puede calcular fácilmente:

 double machEps = 1.0d; 

     do { 
      machEps /= 2.0d; 
     } 
     while ((double)(1.0 + machEps) != 1.0); 

     Console.WriteLine("Calculated machine epsilon: " + machEps); 

Editado:

I calcualted 2 veces épsilon, que ahora debe ser correcta.

+0

Muy buena idea. Gracias. –

+0

@Meonester ¿Quiere dividir machEps por 4 cada vez (una vez en el cuerpo y una vez en la condición? Si dejo fuera la división de condición (es decir, mientras ((doble) (1.0 + (machEps))! = 1.0);) Obtengo un valor para machEps de 1.11022302462516E-16. – AlanT

+0

@AlanT Right, que coincide con lo que sugiere el código 'Math.NET'. –

7

La biblioteca Math.NET define una clase Precision, que tiene una propiedad DoubleMachineEpsilon.

Puede comprobar cómo lo hacen.

acuerdo con que es:

/// <summary> 
    /// The base number for binary values 
    /// </summary> 
    private const int BinaryBaseNumber = 2; 

    /// <summary> 
    /// The number of binary digits used to represent the binary number for a double precision floating 
    /// point value. i.e. there are this many digits used to represent the 
    /// actual number, where in a number as: 0.134556 * 10^5 the digits are 0.134556 and the exponent is 5. 
    /// </summary> 
    private const int DoublePrecision = 53; 

    private static readonly double doubleMachinePrecision = Math.Pow(BinaryBaseNumber, -DoublePrecision); 

Por lo tanto, es 1,11022302462516E-16 según esta fuente.

+0

Es un truco bastante complejo, necesitando saber mucho más sobre la representación interna de 'System.Double' que estoy listo para abordar (no es * solo * material IEEE754, sino también problemas de endianness, etc.). –

+0

@Alexandre: estoy bastante seguro de que la representación binaria interna es obligatoria por el propio IEEE-754. Hay una buena descripción de las partes internas de 'double' [aquí] (http://csharpindepth.com/Articles/General/FloatingPoint.aspx). También hay un enlace a la clase de Jon [DoubleConverter.cs] (http://pobox.com/~skeet/csharp/DoubleConverter.cs) allí también; mirar eso podría ofrecer algunas pistas. – LukeH

+0

@LukeH: Ahora que noto que Microsoft no puede obtener ni siquiera la terminología más básica, no puedo suponer que su implementación en coma flotante sea correcta para todos los propósitos. –

0

Sólo código el valor:

const double e1 = 2.2204460492503131e-16; 

o utilizar la potencia de dos:

static readonly double e2 = Math.Pow(2, -52); 

o utilizar su definición (más o menos):

static readonly double e3 = BitConverter.Int64BitsToDouble(BitConverter.DoubleToInt64Bits(1.0) + 1L) - 1.0; 

Y ver Wikipedia: machine epsilon.

-2

Ref. la rutina en Meonester: En realidad, el valor de machEps en la salida del ciclo do ... while es tal que 1 + machEps == 1. Para obtener el épsilon de la máquina debemos volver al valor anterior, agregando lo siguiente después del ciclo: machEps * = 2.0D; Esto devolverá 2.2204460492503131e-16 de acuerdo con la recomendación en la documentación de Microsoft para Double.Epsilon.

Cuestiones relacionadas