Pregunta

Quiero encontrar el número de dígitos de mantisa y el redondeo de la unidad en una computadora en particular. Entiendo lo que son, solo que no tengo idea de cómo encontrarlos, aunque entiendo que pueden variar de una computadora a otra.

Necesito este número para realizar ciertos aspectos del análisis numérico, como analizar errores.

Lo que estoy pensando actualmente es que podría escribir un pequeño programa en C ++ para incrementar lentamente un número hasta que se produzca un desbordamiento, pero no estoy seguro de qué tipo de número utilizar.

¿Estoy en el camino correcto? ¿Cómo se hace exactamente para calcular esto?

¿Fue útil?

Solución

Creo que cualquier idioma que esté utilizando especificará cómo se almacenan los flotantes. Sé que Java hace esto mediante el uso de un estándar IEEE específico (754, creo).

Si no se especifica, creo que podría hacer su propia comprobación agregando 0.5 a 1 para ver si el número real cambia. Si lo hace, agregue 0.25 a 1, 0.125 a 1, y así sucesivamente hasta que el número no cambie, algo como:

float a = 1;
float b = 0.5;
int bits = 0;
while (a + b != a) {
    bits = bits + 1;
    b = b / 2;
}

Si solo tuviera 3 bits de mantisa, entonces 1 + 1/16 sería igual a 1.

Entonces has agotado tus partes de mantisa.

Es posible que necesite que el número base sea 2 en lugar de 1, ya que IEEE754 usa un '1+' implícito al comienzo.

EDITAR:

Parece que el método descrito anteriormente puede tener algunos problemas, ya que proporciona 63 bits para un sistema que claramente tiene flotantes de 4 bytes.

Si eso tiene que ver con resultados intermedios (lo dudo ya que el mismo código con conversiones explícitas [while (((float)(a + b) != (float)(a))] tiene problemas similares) o (lo más probable, creo) la posibilidad de que el valor unitario a pueda representarse con bits más cercanos al fraccionario b ajustando el exponente, aún no lo sé.

Por ahora, es mejor confiar en la información del idioma que mencioné anteriormente, como el uso de IEEE754 (si esa información está disponible).

Dejaré el código problemático como una trampa para jugadores cautelosos. Tal vez alguien con más conocimiento de coma flotante pueda dejar una nota explicando por qué actúa de manera extraña (sin conjeturas, por favor :-).

EDITAR 2:

Este código lo corrige al garantizar que los intermedios se almacenen en flotantes. Resulta que Jonathan Leffler tenía razón: fueron resultados intermedios.

#include <stdio.h>
#include <float.h>

int main(void) {
    float a = 1;
    float b = 0.5;
    float c = a + b;
    int bits = 1;
    while (c != a) {
        bits = bits + 1;
        b = b / 2;
        c = a + b;
    }
    printf("%d\n",FLT_MANT_DIG);
    printf("%d\n",bits);
    return 0;

}

Este código genera (24,24) para mostrar que el valor calculado coincide con el del archivo de encabezado.

Si bien está escrito en C, debería ser aplicable a cualquier idioma (específicamente uno donde la información no está disponible en un encabezado o en virtud de que se especifica en la documentación del idioma). Solo probé en C porque Eclipse tarda mucho en comenzar en mi cuadro de Ubuntu :-).

Otros consejos

Para C, y por extensión C ++, la información está en los encabezados <float.h> o <cfloat>.

Para C99, la información se encuentra en la sección 5.2.4.2.2 del estándar:

  • FLT_RADIX
  • FLT_MANT_DIG
  • FLT_DIG
  • FLT_EPSILON
  • FLT_MIN_EXP
  • FLT_MIN
  • FLT_MIN_10_EXP
  • FLT_MAX_EXP
  • FLT_MAX
  • FLT_MAX_10_EXP

Y de manera similar para las variaciones DBL y LDBL en la mayoría de estos (no DBL_RADIX o LDBL_RADIX). El estándar sugiere valores apropiados para IEEE 754 (la versión anterior del estándar IEEE 754 que estaba vigente en 1999; había una nueva versión publicada, creo, en 2008).

Es posible que desee consultar <limits> en su biblioteca de C ++:

#include <iostream>
#include <limits>
#include <typeinfo>

template <typename T>
void printDetailsFor() {
    std::cout
        << "Printing details for " << typeid(T).name() << ":\n"
        << "\tradix:        " << std::numeric_limits<T>::radix        << "\n"
        << "\tradix digits: " << std::numeric_limits<T>::digits       << "\n"
        << "\tepsilon:      " << std::numeric_limits<T>::epsilon()    << "\n"
        << std::endl;
}

int main() {
    printDetailsFor<int>();
    printDetailsFor<float>();
    printDetailsFor<double>();
    printDetailsFor<long double>();
    return 0;
}

Creo que quieres std::numeric_limits<T>::digits que debería ser uno más que el número de bits de mantisa. Mi máquina imprime:

Printing details for i:
    radix:        2
    radix digits: 31
    epsilon:      0

Printing details for f:
    radix:        2
    radix digits: 24
    epsilon:      1.19209e-07

Printing details for d:
    radix:        2
    radix digits: 53
    epsilon:      2.22045e-16

Printing details for e:
    radix:        2
    radix digits: 64
    epsilon:      1.0842e-19
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top