2012-02-22 27 views
11

Makine epsilonu, birine eklenen en küçük sayı olarak kanonik olarak tanımlanır, birinden farklı bir sonuç verir.C# makinesinde epsilon'u nerede bulabilirim?

Double.Epsilon var ama ad çok yanıltıcıdır: en küçük (denormalized) Double değeri gösterilebilir ve bu nedenle her tür sayısal programlama için kullanışsızdır.

Double türü için true epsilon'u almak istiyorum, böylece programımda toleransları kodlamak zorunda kalmamak için. Bunu nasıl yaparım ?

+0

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

+0

@AakashM: Bunu okudum. Epsilon'un anlamı IEEE754'ün bakış açısından oldukça açık ve Microsoft'un bu amatörce bir şey yapması çok yazık oldu. Kayan nokta uygulaması güvenilir mi? –

+0

@AlexandreC .: 'Double.MinValue', .NET Framework'teki diğer' MinValue 'alanlarına karşılık gelen' Int32.MinValue', 'DateTime.MinValue' vb. Gibi büyük olasılıkla tanımlanmıştır. C.'de DBL_MIN ile aynıdır. Ancak, Double.Epsilon'un tanımının kafa karıştırıcı olduğunu kabul ediyorum. –

cevap

8

O (benim makinede) var:

1.11022302462516E-16 

Kolayca bunu hesaplayabilirsiniz:

 double machEps = 1.0d; 

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

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

Düzenlendi:

Ben 2 kez epsilonu calcualted, şimdi doğru olmalıdır.

+0

Çok iyi fikir. Teşekkürler. –

+0

@Meonester machEps'i her seferinde 4'e bölmek mi istiyorsunuz? (Bir kez vücutta ve bir kere koşulda? Durum bölüünü terkedersem (yani ((double) (1,0 + (machEps))! = 1.0);) Ben 1.11022302462516E-16 için – AlanT

+0

@AlanT Right machEps için bir değer olsun, hangi Math.NET kodu önerdiği ile eşleşir. –

7

Math.NET kitaplığı, DoubleMachineEpsilon özelliğine sahip bir Precision sınıfını tanımlar.

Bunu nasıl yaptığını kontrol edebilirsiniz. o olduğunu göre

:

/// <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); 

Yani bu kaynağına göre 1,11022302462516E-16 olduğunu.

+0

Sistemin içsel gösterimi hakkında çok daha fazla bilgiye ihtiyaç duymak oldukça karmaşık, biraz karmaşıktır.Çifte uğraşmaya hazır olduğum (bu sadece * IEEE754 şeyler değil, aynı zamanda enderlik sorunları, vb). –

+0

@Alexandre: IEEE-754'ün kendisinin içsel ikili temsilini zorunlu kıldığından eminim. "Double" ın içeriğinin iyi bir açıklaması var [burada] (http://csharpindepth.com/Articles/General/FloatingPoint.aspx). Orada da Jon'un [DoubleConverter.cs] (http://pobox.com/~skeet/csharp/DoubleConverter.cs) sınıfına bir link var; Buna bakmak bazı ipuçları sunabilir. – LukeH

+0

@LukeH: Artık Microsoft'un en temel terminoloji hakkını bile alamamış olduğunu fark ettim, onların kayan nokta uygulamasının her amaç için doğru olduğunu varsaymıyorum. –

0

Hemen sabit kod değeri:

const double e1 = 2.2204460492503131e-16; 

veya ikisinin gücünü kullanın:

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

veya tanımını (az ya da çok) kullanın:

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

Ve bakınız Wikipedia: machine epsilon.

-2

Ref. Meonester'deki rutini: Aslında machEps'in çıkıştaki değeri, do ... iken, döngüde olduğu gibi 1 + machEps == 1. Makineyi epsilon elde etmek için, aşağıdakileri ekleyerek bir önceki değere geri dönmeliyiz döngüden sonra: machEps * = 2.0D; Bu, Microsoft'un Double.Epsilon belgelerinde yer alan öneriyle uyumlu olarak 2.2204460492503131e-16'yı döndürecektir.

İlgili konular