2012-02-22 14 views
11

Maszyna epsilon jest kanonicznie definiowana jako najmniejsza liczba dodana do jednego, daje wynik inny niż jeden.Gdzie mogę znaleźć epsilon maszyny w C#?

Istnieje Double.Epsilon, ale nazwa jest bardzo myląca: jest to najmniejsza (zdenormalizowana) wartość Double reprezentowana, a zatem bezużyteczna przy wszelkiego rodzaju programowaniu numerycznym.

Chciałbym uzyskać prawdziwą epsilon dla typu Double, tak że nie trzeba hardcode tolerancji w moim programie. Jak mam to zrobic ?

+0

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

+0

@AakashM: Przeczytałem to. Znaczenie epsilon jest dość jasne w świetle IEEE754 i szkoda, że ​​Microsoft zrobił coś tak amatorskiego. Czy ich implementacja zmiennoprzecinkowa jest zaufana? –

+0

@AlexandreC .: 'Double.MinValue' jest najprawdopodobniej zdefiniowany jako odpowiadający innym polom' MinValue' w .NET Framework takim jak 'Int32.MinValue',' DateTime.MinValue' itd. To oczywiście nie jest taki sam jak 'DBL_MIN' w C. Zgadzam się jednak, że definicja' Double.Epsilon' jest myląca. –

Odpowiedz

8

To (na moim komputerze):

1.11022302462516E-16 

Można łatwo obliczyć:

 double machEps = 1.0d; 

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

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

edycja:

I calcualted 2 razy epsilon, teraz powinno być prawidłowe.

+0

Bardzo dobry pomysł. Dzięki. –

+0

@Meonester Czy chcesz podzielić machEps przez 4 za każdym razem (raz w ciele i raz w stanie? Jeśli opuszczę podział warunków (tj. Podczas ((podwójne) (1.0 + (machEps))! = 1.0);) Dostaję wartość dla machEps 1.11022302462516E-16. – AlanT

+0

@AlanT Right, która pasuje do tego, co sugeruje kod 'Math.NET'. –

7

Biblioteka definiuje klasę Precision, która ma właściwość DoubleMachineEpsilon.

Można sprawdzić, jak to robią.

Według że:

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

Tak jest 1,11022302462516E-16 według tego źródła.

+0

To dość skomplikowane błahostki, które muszą wiedzieć znacznie więcej na temat wewnętrznej reprezentacji 'Systemu.Podwójnie "jestem gotów się zająć (to nie jest * tylko * IEEE754, ale także problemy z endianizmem, itp.). –

+0

@Alexandre: Jestem prawie pewny, że wewnętrzna reprezentacja binarna jest wymagana przez samą IEEE-754. Istnieje dobry opis wewnętrznych elementów 'double' [tutaj] (http://csharpindepth.com/Articles/General/FloatingPoint.aspx). Jest tam również link do klasy Jona [DoubleConverter.cs] (http://pobox.com/~skeet/csharp/DoubleConverter.cs); patrząc na to, może dać jakieś wskazówki. – LukeH

+0

@LukeH: Teraz, gdy zauważam, że Microsoft nie może uzyskać nawet najbardziej podstawowej terminologii, nie mogę założyć, że ich implementacja zmiennoprzecinkowa jest poprawna dla wszystkich celów. –

0

Podobnie trudno kod wartość:

const double e1 = 2.2204460492503131e-16; 

lub wykorzystać moc dwóch:

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

lub używać definicji (bardziej lub mniej):

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

I patrz Wikipedia: machine epsilon.

-2

Nr ref. rutyna w Meonester: Właściwie wartość machEps przy wyjściu z pętli do ... while jest taka, że ​​1 + machEps == 1. Aby uzyskać epsilon maszyny, musimy wrócić do poprzedniej wartości, dodając następujące po pętli: machEps * = 2.0D; To zwróci 2.2204460492503131e-16 w porozumieniu z zaleceniem w dokumentacji Microsoft dla Double.Epsilon.

Powiązane problemy