C ++ possui std::nextafter()
, que retorna o próximo valor representável após um determinado valor de ponto flutuante f . No meu caso, eu gostaria de permitir n bits de slop nos bits inferiores da mantissa, portanto, 3 bits de slop exigiriam obter o 8º próximo valor após um determinado valor f . Eu poderia ligar nextafter()
oito vezes, mas existe uma maneira melhor de lidar com isso?
Para a maioria dos valores, é possível converter o valor FP em uint_64
, adicionar a tolerância ( 1<<3
para 3 bits de slop) e depois converter novamente double
, graças ao layout do IEEE 754. No entanto, isso depende do ponto flutuante do IEEE 754 ( uma boa suposição, mas também não sólida como uma rocha).
(Como pano de fundo, quero usar isso para içar pontos de interseção da superfície dos raios, que ocasionalmente estão localizados dentro da superfície devido à imprecisão do FP. Aqueles familiarizados com o ponto flutuante robusto entenderão por que epsilon
é uma solução terrível.)
fonte
std::numeric_limits<T>::is_iec559
para verificar se o IEEE 754 é usado e especializar a função de acordo.Respostas:
Uma abordagem ingênua poderia ser multiplicar por 8 a distância entre um valor e o próximo ponto flutuante representável, em vez de chamar 8 vezes
std::nextafter
Aqui existem alguns testes, mas depende de você determinar se isso é adequado para o seu caso de uso.
Editar
Como observado por Steve Hollash ,
x
pode ser tão grande quex + d == d
. Daniel Jour sugeriu aproveitarfrexp
(eldexp
), mas na tentativa a seguir, usarei uma abordagem diferente para determinar a direção.Note-se que ele assume que
std::numeric_limits<double>::has_infinity == true
, caso contrário,::lowest()
e::max()
deve ser utilizado.Esses são alguns resultados
fonte
x+d
não é o que você está procurando, no entanto. Se x é grande, então (x + d) == x. Mas eu gosto da idéia: calcule o valor igual ao bit de ordem mais baixa com um expoente correspondente, escalado pelo "slop" e depois adicionado ao valor original.nextafter
, como passar a "direção".frexp
antes eldexp
depois deve funcionar, não?frexp
particular, eu posso mover mundos. Obrigado!Tanto quanto eu sei, não há função padrão para isso. O Boost já cobriu você: Veja
boost::math::float_advance
. Se você estiver usando isso para comparar dois carros alegóricos, provavelmente desejaráboost::math::float_distance
.fonte