En informática y análisis numérico , unidad en último lugar o unidad de menor precisión ( ulp ) es el espaciado entre dos números de coma flotante consecutivos , es decir, el valor que representa el dígito menos significativo (dígito más a la derecha) si es 1. Se utiliza como medida de precisión en cálculos numéricos. [1]
Una definición es: En base con precisión , si , entonces . [2]
Otra definición, sugerida por John Harrison, es ligeramente diferente: es la distancia entre los dos números de coma flotante más cercanos y (es decir, aquellos con y ), suponiendo que el rango del exponente no tiene un límite superior. [3] [4] Estas definiciones difieren sólo en las potencias con signo de la base. [2]
La especificación IEEE 754 , seguida por todo el hardware moderno de punto flotante, requiere que el resultado de una operación aritmética elemental (suma, resta, multiplicación, división y raíz cuadrada desde 1985, y FMA desde 2008) se redondee correctamente , lo que implica que al redondear al más cercano, el resultado redondeado está dentro de 0,5 ulp del resultado matemáticamente exacto, utilizando la definición de John Harrison; por el contrario, esta propiedad implica que la distancia entre el resultado redondeado y el resultado matemáticamente exacto se minimiza (pero para los casos intermedios, se satisface con dos números de punto flotante consecutivos). Bibliotecas numéricas acreditadas calculan las funciones trascendentales básicas entre 0,5 y aproximadamente 1 ulp. Sólo unas pocas bibliotecas los calculan dentro de 0,5 ulp, siendo este problema complejo debido al dilema del creador de tablas . [5]
Sea un número de punto flotante positivo y supongamos que el modo de redondeo activo es redondear al más cercano, vinculado a par , denotado . Si entonces . En caso contrario, o , dependiendo del valor del dígito menos significativo y del exponente de . Esto se demuestra en el siguiente código Haskell escrito en un mensaje interactivo: [ cita necesaria ]
> hasta ( \ x -> x == x + 1 ) ( + 1 ) 0 :: Flotar 1.6777216e7> eso - 11.6777215e7> eso + 11.6777216e7
Aquí comenzamos con 0 en precisión simple y agregamos 1 repetidamente hasta que la operación no cambia el valor. Dado que el significado de un número de precisión simple contiene 24 bits, el primer número entero que no es exactamente representable es 2 24 +1, y este valor se redondea a 2 24 redondeando al más cercano, empatando con par. Por tanto, el resultado es igual a 2 24 .
El siguiente ejemplo en Java aproxima π como un valor de punto flotante al encontrar los dos valores dobles entre corchetes : .
// π con 20 dígitos decimales BigDecimal π = new BigDecimal ( "3.14159265358979323846" ); // truncar a doble punto flotante double p0 = π . dobleValor (); // -> 3.141592653589793 (hexadecimal: 0x1.921fb54442d18p1) // p0 es menor que π, así que encuentre el siguiente número representable como doble doble p1 = Math . siguienteArriba ( p0 ); // -> 3.1415926535897936 (hexadecimal: 0x1.921fb54442d19p1)
Entonces se determina como .
// ulp(π) es la diferencia entre p1 y p0 BigDecimal ulp = new BigDecimal ( p1 ). restar ( nuevo BigDecimal ( p0 )); // -> 4.44089209850062616169452667236328125E-16 // (esto es precisamente 2**(-51)) // mismo resultado cuando se utiliza la función de biblioteca estándar double ulpMath = Math . ulp ( p0 ); // -> 4.440892098500626E-16 (hexadecimal: 0x1.0p-51)
Otro ejemplo, en Python , también escrito en un mensaje interactivo, es:
>>> x = 1.0 >>> p = 0 >>> mientras x != x + 1 : ... x = x * 2 ... p = p + 1 ... >>> x 9007199254740992.0 >>> página 53 >>> x + 2 + 1 9007199254740996.0
En este caso, comenzamos con x = 1
y lo duplicamos repetidamente hasta x = x + 1
. De manera similar al ejemplo 1, el resultado es 2 53 porque el formato de punto flotante de doble precisión utiliza un significado de 53 bits.
Las bibliotecas de Boost C++ proporcionan las funciones boost::math::float_next
, boost::math::float_prior
y para obtener valores de punto flotante cercanos (y distantes), boost::math::nextafter
[ 6] y para calcular la distancia de punto flotante entre dos dobles. [7]boost::math::float_advance
boost::math::float_distance(a, b)
La biblioteca de lenguaje C proporciona funciones para calcular el siguiente número de punto flotante en una dirección determinada: nextafterf
y nexttowardf
para float
, nextafter
y nexttoward
para double
, nextafterl
y nexttowardl
para long double
, declarado en <math.h>
. También proporciona las macros ,,, FLT_EPSILON
que representan la diferencia positiva entre 1,0 y el siguiente número representable mayor en el tipo correspondiente (es decir, el ulp de uno). [8]DBL_EPSILON
LDBL_EPSILON
La biblioteca estándar de Java proporciona las funciones Math.ulp(double)
y Math.ulp(float)
. Fueron introducidos con Java 1.5.
La biblioteca estándar de Swift proporciona acceso al siguiente número de punto flotante en una dirección determinada a través de las propiedades de instancia nextDown
y nextUp
. También proporciona la propiedad de instancia ulp
y la propiedad de tipo ulpOfOne
(que corresponde a macros de C como FLT_EPSILON
[9] ) para los tipos de punto flotante de Swift. [10]