[A 'resposta correta' encobre a seleção K. A seleção Kacaba sendo tão ad-hoc quanto a seleção, VISIBLE_SHIFTmas a seleção Ké menos óbvia, porque, ao contrário VISIBLE_SHIFT, não se baseia em nenhuma propriedade de exibição. Assim, escolha seu veneno - selecione Kou selecione VISIBLE_SHIFT. Esta resposta defende a seleção VISIBLE_SHIFTe, em seguida, demonstra a dificuldade em selecionar K]
Precisamente devido a erros de arredondamento, você não deve usar a comparação de valores 'exatos' para operações lógicas. No seu caso específico de uma posição em uma exibição visual, não importa se a posição é 0,0 ou 0,0000000003 - a diferença é invisível aos olhos. Portanto, sua lógica deve ser algo como:
#define VISIBLE_SHIFT 0.0001 // for example
if (fabs(theView.frame.origin.x) < VISIBLE_SHIFT) { /* ... */ }
No entanto, no final, 'invisível aos olhos' dependerá das propriedades da sua exibição. Se você pode limitar o display (você deve conseguir); escolha VISIBLE_SHIFTser uma fração desse limite superior.
Agora, a 'resposta certa' se baseia, Kentão vamos explorar a escolha K. A 'resposta correta' acima diz:
K é uma constante que você escolhe para que o erro acumulado de seus cálculos seja definitivamente limitado por K unidades em último lugar (e se você não tiver certeza de ter acertado o cálculo de erro, faça K algumas vezes maior do que seus cálculos diga que deveria ser)
Então nós precisamos K. Se conseguir Ké mais difícil, menos intuitivo do que selecionar o meu, VISIBLE_SHIFTentão você decidirá o que funciona para você. Para descobrir K, vamos escrever um programa de teste que analise vários Kvalores para que possamos ver como ele se comporta. Deveria ser óbvio como escolher K, se a 'resposta certa' for utilizável. Não?
Vamos usar como detalhes da 'resposta certa':
if (fabs(x-y) < K * DBL_EPSILON * fabs(x+y) || fabs(x-y) < DBL_MIN)
Vamos apenas tentar todos os valores de K:
#include <math.h>
#include <float.h>
#include <stdio.h>
void main (void)
{
double x = 1e-13;
double y = 0.0;
double K = 1e22;
int i = 0;
for (; i < 32; i++, K = K/10.0)
{
printf ("K:%40.16lf -> ", K);
if (fabs(x-y) < K * DBL_EPSILON * fabs(x+y) || fabs(x-y) < DBL_MIN)
printf ("YES\n");
else
printf ("NO\n");
}
}
ebg@ebg$ gcc -o test test.c
ebg@ebg$ ./test
K:10000000000000000000000.0000000000000000 -> YES
K: 1000000000000000000000.0000000000000000 -> YES
K: 100000000000000000000.0000000000000000 -> YES
K: 10000000000000000000.0000000000000000 -> YES
K: 1000000000000000000.0000000000000000 -> YES
K: 100000000000000000.0000000000000000 -> YES
K: 10000000000000000.0000000000000000 -> YES
K: 1000000000000000.0000000000000000 -> NO
K: 100000000000000.0000000000000000 -> NO
K: 10000000000000.0000000000000000 -> NO
K: 1000000000000.0000000000000000 -> NO
K: 100000000000.0000000000000000 -> NO
K: 10000000000.0000000000000000 -> NO
K: 1000000000.0000000000000000 -> NO
K: 100000000.0000000000000000 -> NO
K: 10000000.0000000000000000 -> NO
K: 1000000.0000000000000000 -> NO
K: 100000.0000000000000000 -> NO
K: 10000.0000000000000000 -> NO
K: 1000.0000000000000000 -> NO
K: 100.0000000000000000 -> NO
K: 10.0000000000000000 -> NO
K: 1.0000000000000000 -> NO
K: 0.1000000000000000 -> NO
K: 0.0100000000000000 -> NO
K: 0.0010000000000000 -> NO
K: 0.0001000000000000 -> NO
K: 0.0000100000000000 -> NO
K: 0.0000010000000000 -> NO
K: 0.0000001000000000 -> NO
K: 0.0000000100000000 -> NO
K: 0.0000000010000000 -> NO
Ah, então K deve ser 1e16 ou maior se eu quiser que 1e-13 seja 'zero'.
Então, eu diria que você tem duas opções:
- Faça um cálculo epsilon simples usando seu julgamento de engenharia pelo valor de 'epsilon', como sugeri. Se você estiver criando gráficos e 'zero' for uma 'mudança visível', examine seus recursos visuais (imagens, etc.) e julgue o que é epsilon.
- Não tente fazer cálculos de ponto flutuante até ler a referência da resposta que não é de carga (e obter seu doutorado no processo) e, em seguida, use seu julgamento não intuitivo para selecionar
K.
fabs(x+y)é problemático sexey(pode) ter sinal diferente. Ainda assim, uma boa resposta contra a maré de comparações entre cultos de carga.