2009-08-26 15 views
6

Dado un número de coma flotante normalizado f cuál es el siguiente normalizado número de coma flotante después/antes de f.¿Cuál es el siguiente número de punto flotante normalizado después de (antes) un número de punto flotante normalizado f?

Con cambio de bit, mantisa y exponente de extracción que tienen:

next_normalized(double&){ 
     if mantissa is not all ones 
      maximally denormalize while maintaining equality 
      add 1 to mantissa 
      normalize 
     else 
      check overflow 
      set mantissa to 1 
      add (mantissa size in bits) to exponent. 
     endif 
} 

Pero en lugar de hacer eso se puede hacer esto con las operaciones de punto flotante?

Como

std::numeric_limits<double>::epsilon() 

no es más que una diferencia de error en un "barrio" de 1. - por ejemplo:

normalized(d+=std::numeric_limits<double>::epsilon()) = d for d large 

parece más una tasa de errores de una diferencia de error, por lo que mi intuición ingenua es

(1.+std::numeric_limits<double>::epsilon())*f //should be the next. 

Y

(1.-std::numeric_limits<double>::epsilon())*f //should be the previous. 

En particular tengo 3 preguntas que nadie ha hecho nada de lo siguiente (por IEEE754):

1 realizado el análisis de errores) sobre este tema?

2) demostró (o puede probar) que para cualquier normalizada doble d

(1.+std::numeric_limits<double>::epsilon())*d != d ? 

3) demostró que para cualquier normalizada número doble D no doble f existe tal que

d < f < (1.+std::numeric_limits<double>::epsilon())*d ? 

Respuesta

7

No estoy seguro de lo que quiere decir con "normalizado número doble", pero obteniendo el siguiente representa El número doble se hace con el nextafter() function en la mayoría de las bibliotecas matemáticas estándar de C.

+0

gracias por eso (no hacer hacer mucho punto flotante) – pgast

+1

Supongo que a diferencia de _denormals_ – kibibu

+0

nextafter devolverá el siguiente número, incluso si eso resulta ser un número desnormalizado. El caso desnormalizado no es tan raro, sucede si llama a nextafter (0.0, 1.0), ya que el siguiente número representable después de 0 es un número desnormalizado (4e-324, cuando DBL_MIN es 2e-308). Por lo tanto, solo debe usar esta solución si el primer número no puede ser cero, o los números desnormalizados no son un problema. –

3

La declaración en 3) es falsa. Si d es ligeramente menor que 2, entonces hay exactamente 1 número de coma flotante entre d y (1 + eps) * d. Aquí es un programa para mostrar que:

#include <limits> 
#include <iostream> 

int main(int, char**) 
{ 
    using namespace std; 
    double d = 1.875; 
    cout.precision(18); 
    cout << "d = " << d << "\n"; 
    double d2 = (1.+numeric_limits<double>::epsilon())*d; 
    cout << "d2 = " << d2 << "\n"; 
    double f = d + (d2-d)/2; 
    cout << "f = " << f << "\n"; 
} 

La razón es que (1 + EPS) * 1.875 es igual a 1,875 + 1,875 * EPS, que se redondea a 1,875 + 2 * EPS. Sin embargo, la diferencia entre los números de coma flotante consecutivos entre 1 y 2 es eps, por lo que hay un número de punto flotante entre 1.875 y 1.875 + 2 * eps, es decir, 1.875 + eps.

La afirmación en 2) es verdadera, creo. Y Robert Kern probablemente respondió tu verdadera pregunta.

+0

buen contador de ejemplo - no sé por qué no lo vi. – pgast

+0

y podría agregar que ha demostrado que como máximo 1 de esos d existe – pgast

+0

Lo que es verdadero con su predecesor (predecesor (2)), también es verdadero con cualquier potencia de dos, (1 + eps) * (pred (pred (2^i)))! = pred (2^i) ya que todos tienen el mismo patrón de bit de mantisa –

5

Como señaló Robert Kern, desea la función C nextafter(), o las funciones nextUp() y nextDown() IEEE754, aunque esas dos aún no se han implementado ampliamente.

Si se quiere evitar nextafter por alguna razón, puede hacerlo:

double next = x + scalbn(1.0, ilogb(x) - 52); 

Esto añade 2^(exponente de x - 52) para x, que es exactamente una unidad en el último lugar (ULP)

Si usted no tiene las funciones habituales disponibles cmath:

double x = 1.0; 
uint64_t rep; 
assert(sizeof x == sizeof rep); 
memcpy(&rep, &x, sizeof x); 
rep += 1; 
memcpy(&x, &rep, sizeof x); 

Esto se suma uno a la mantisa de x mediante una operación en el bit a bit-representación del valor de coma flotante; si el siguiente valor está en el próximo binade, esto llevará al exponente, devolviendo el valor correcto. Si quieres que funcione con valores negativos, deberás modificarlo.

1

Como se indica a continuación, después de investigar un poco para flotar en formato intel IEEE754 de tamaño n bits que son < + infinito tratar el exponente concatenado y significand como un entero sin signo de n-1 agregar uno obtiene el siguiente más alto y (restando uno el siguiente más bajo)

Y viceversa si es negativo. En particular, se puede interpretar que el entero n-1 bit representa la magnitud absoluta independiente del signo. Y así cuando uno negativo debe restar uno para obtener el siguiente número de punto flotante más cercano a cero después del número de punto flotante negativo f.

0

1,0 - épsilon no es el predecesor de 1,0, por lo que la contraparte negativa no funciona en absoluto ...
El predecesor de 1,0 es 1,0-épsilon/2.0

Cuestiones relacionadas