Double.Epsilon pela igualdade, maior que, menor que, menor que ou igual a, maior ou igual a
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.
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;
}