Double.Epsilon pela igualdade, maior que, menor que, menor que ou igual a, maior ou igual a

StackOverflow https://stackoverflow.com/questions/2411392

  •  18-09-2019
  •  | 
  •  

Pergunta

http://msdn.microsoft.com/en- us / library / system.double.epsilon.aspx

Se você criar um algoritmo personalizado que determina se dois de ponto flutuante números podem ser considerados iguais, você deve usar um valor que é maior do que a constante Epsilon para estabelecer a margem absoluta aceitável de diferença para os dois valores sejam considerados iguais. (Tipicamente, isto margem de diferença é muitas vezes maior do que Epsilon.)

Então é isso não é realmente uma epsilon que poderia ser usado para comparações? Eu realmente não entendo o texto MSDN.

ele pode ser usado como a epsilon nos exemplos aqui? - Qual é a maneira mais eficaz para a bóia e comparação duplo ?

E, finalmente, isso parece realmente importante para que eu gostaria de ter certeza que tenho uma implementação sólida para a igualdade, maior que, menor que, menor que ou igual a, e maior ou igual a.

Foi útil?

Solução

Eu não sei o que eles estavam fumando quando escreveu isso. Double.Epsilon é o valor menor ponto representável não denormal flutuante que não é 0. Tudo o que sei é que, se há um erro de truncamento, ele sempre será maior do que esse valor. Muito maior.

O tipo System.Double pode representar valores precisos para até 15 dígitos. Assim, uma simples estimativa de primeira ordem se um valor x dupla é igual a alguma constante é usar um epsilon de constante * 1E-15

public static bool AboutEqual(double x, double y) {
    double epsilon = Math.Max(Math.Abs(x), Math.Abs(y)) * 1E-15;
    return Math.Abs(x - y) <= epsilon;
}

Você tem que tomar cuidado, porém, erros de truncamento pode acumular. Se ambos x e y são computados os valores, então você tem que aumentar o epsilon.

Outras dicas

Eu gostaria de ter certeza que tenho uma implementação sólida para a igualdade, maior que, menor que, menor que ou igual a, e maior ou igual a.

Você está usando binário aritmética de ponto flutuante.

Binário aritmética de ponto flutuante foi projetado para representar quantidades físicas, como comprimento, massa, carga, tempo, e assim por diante.

Presumivelmente, então você está usando binário aritmética de ponto como foi planejado para ser usado flutuante:. Para fazer aritmética em quantidades físicas

As medições de grandezas físicas sempre ter uma precisão particular, dependendo da precisão do dispositivo usado para medi-los.

Uma vez que você é o único fornecer os valores para as quantidades que você está manipulando, você é o único que sabe o que os "barras de erro" estão em que quantidade. Por exemplo, se você está fornecendo a quantidade "a altura do edifício é 123.56 metros", então você sabe que este é precisa ao centímetro, mas não para o micrômetro.

Portanto, ao comparar duas quantidades para a igualdade, a semântica desejada é dizer "são estas duas quantidades iguais dentro das barras de erro especificados por cada medição?"

Então, agora temos uma resposta para sua pergunta. O que você deve fazer é manter o controle de qual é o erro em cada quantidade; por exemplo, a altura do edifício é "dentro de 0,01 de 123.56 metros" porque você sabe que é assim que precisa a medição é. Se você, em seguida, obter uma outra medida que é 123.5587 e quer saber se as duas medidas são "iguais" dentro das tolerâncias de erro, em seguida, fazer a subtração e ver se ele cai na tolerância de erro. Neste caso, ele faz. Se as medições eram de fato precisa à micrometre, então eles não são iguais.

Em suma: você é a única pessoa aqui que sabe o que tolerâncias de erro sensíveis são, porque você é a única pessoa que sabe onde os números que estão manipulando veio em primeiro lugar. Use o que a tolerância de erro faz sentido para as suas medições dadas a precisão do equipamento utilizado para produzi-lo.

Se você tem dois valores duplas que estão perto de 1.0, mas eles diferem em apenas seus bits menos significativos, então a diferença entre eles será várias ordens de magnitude maior do que Double.Epsilon. Na verdade, a diferença é 324 ordens decimais de magnitude. Isto é por causa do efeito da porção expoente. Double.Epsilon tem uma enorme expoente negativo sobre ele, enquanto 1.0 tem um expoente zero (após os preconceitos são removidos, é claro).

Se você quiser comparar dois valores semelhantes para a igualdade, então você terá que escolher um valor epsilon personalizado que é apropriado para o tamanho ordens de grandeza dos valores a serem comparados.

Se os valores duplas que você está comparando são perto de 1,0. Em seguida, o valor do bit menos siginificant estaria perto ,0000000000000001. Se os valores duplas que você está comparando são nos quatrilhões, em seguida, o valor do bit menos significativo poderia ser tanto quanto mil. Nenhum valor único para epsilon poderia ser usado para comparações de igualdade em ambas as circunstâncias.

Eu apenas fiz isso -. Utilizando Kent Bogarts ideia

private bool IsApproximatelyEqual(double x, double y, double acceptableVariance)
{
     double variance = x > y ? x - y : y - x;
     return variance < acceptableVariance;

     //or
     //return Math.Abs(x - y) < acceptableVariance;
}

Pode ser usado para comparações, supondo que você quer para garantir os dois valores são ou exatamente iguais, ou ter a menor diferença representável para o tipo de casal. De um modo geral, você iria querer usar um número maior do que double.Epsilon para verificar se duas duplas são aproximadamente iguais.

Por que o .NET framework não define algo como

bool IsApproximatelyEqual(double value, double permittedVariance);

está além de mim.

Eu acho que os bits pertinentes no link MSDN que você postou são os seguintes:

No entanto, a propriedade Epsilon não é um medida geral de precisão do Tipo Duplo; que se aplica apenas aos Duplo instâncias que têm um valor de zero.

Nota: O valor da Epsilon propriedade não é equivalente à máquina epsilon, o que representa a gáspea ligado do erro relativo devido arredondamento em aritmética de ponto flutuante.

Este valor não é definido como menor X número positivo, de tal modo que x + 1,0 não é igual a 1,0, de modo Double.Epsilon não pode ser usado para "quase igualdade". Não existe nenhum constante no quadro cujo valor é menor X número positivo, de tal modo que x + 1,0 não é igual a 1.0.

Eu tenho que dizer, que me surpreende. Eu também tinha assumido que Double.Epsilon era o equivalente a DBL_EPSILON em c / c ++ - claramente não!

De que eu posso ler dessa ligação parece estar dizendo 'você precisa descobrir um valor decente se para comparações', que é bastante surpreendente para dizer o mínimo.
Talvez alguém mais qualificado pode esclarecer:)

Eu uso o seguinte

public static class MathUtil {
    /// <summary>
    /// smallest such that 1.0+EpsilonF != 1.0
    /// </summary>
    public const float EpsilonF = 1.192092896e-07F;

    /// <summary>
    /// smallest such that 1.0+EpsilonD != 1.0
    /// </summary>
    public const double EpsilonD = 2.2204460492503131e-016;

    [MethodImpl( MethodImplOptions.AggressiveInlining )]
    public static bool IsZero( this double value ) {
        return value < EpsilonD && value > -EpsilonD;
    }

    [MethodImpl( MethodImplOptions.AggressiveInlining )]
    public static int Sign( this double value ) {
        if ( value < -EpsilonD ) {
            return -1;
        }
        if ( value > EpsilonD )
            return 1;
        return 0;
    }

e se você quiser verificar a igualdade de dois duplos 'a' e 'b', você pode usar

(a-b).IsZero();

e se você deseja obter o resultado de comparação, o uso

(a-b).Sign();

O problema com comparando duplas é que quando você faz uma comparação entre dois resultados de matemática diferentes que são iguais, mas que, devido a erros de arredondamento, não estão avaliando para o mesmo valor, eles terão alguma diferença ... o que é maior do que epsilon, exceto em casos extremos. E usando um valor epsilon confiável também é difícil. Algumas pessoas consideram duas duplas iguais se a diferença entre eles é inferior a alguns valor percentual, uma vez usando um epsilon diferença mínima estática pode significar suas diferenças são muito pequenas ou grandes, quando a dupla em si é alto ou baixo.

Aqui está um código que incluiu duas vezes dentro do Silverlight Control Toolkit:

    public static bool AreClose(double value1, double value2)
    {
        //in case they are Infinities (then epsilon check does not work)
        if(value1 == value2) return true;
        // This computes (|value1-value2| / (|value1| + |value2| + 10.0)) < DBL_EPSILON
        double eps = (Math.Abs(value1) + Math.Abs(value2) + 10.0) * DBL_EPSILON;
        double delta = value1 - value2;
        return(-eps < delta) && (eps > delta);
    }

Em um lugar que eles usam 1e-6 para epsilon; em outra eles usam 1.192093E-07. Você vai querer escolher o seu próprio epsilon.

Não há escolha você tem que calcular-lo sozinho ou definir próprio constante.

double calculateMachineEpsilon() {
    double result = 1.0;
    double one = 1.0/256;

    while(one + result/2.0 != 1.0) {
        result/=2.0;
    }
    return result;
}
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top