Domanda

Voglio trovare il numero di cifre della mantissa e l'arrotondamento dell'unità su un determinato computer. Ho una comprensione di cosa sono, non ho idea di come trovarli, anche se capisco che possono variare da computer a computer.

Ho bisogno di questo numero per eseguire alcuni aspetti dell'analisi numerica, come l'analisi degli errori.

Quello che sto pensando attualmente è che potrei scrivere un piccolo programma c ++ per aumentare lentamente un numero fino a quando si verifica un overflow, ma non sono sicuro del tipo di numero da usare.

Sono sulla buona strada? Come si fa esattamente a calcolare questo?

È stato utile?

Soluzione

Penserei che qualunque lingua tu stia usando specifica il modo in cui sono stati memorizzati i float. So che Java lo fa utilizzando uno standard IEEE specifico (754, credo).

Se non è specificato, penso che potresti semplicemente fare il tuo controllo aggiungendo 0,5 a 1 per vedere se il numero effettivo cambia. In tal caso, aggiungi 0,25 a 1, 0,125 a 1 e così via fino a quando il numero non cambia, qualcosa del tipo:

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

Se avessi solo 3 bit di mantissa, 1 + 1/16 sarebbe uguale a 1.

Allora hai esaurito i tuoi pezzi di mantissa.

Potrebbe essere necessario che il numero di base sia 2 anziché 1, poiché IEEE754 utilizza un "1+" implicito all'inizio.

EDIT:

Sembra che il metodo sopra descritto possa avere alcuni problemi in quanto fornisce 63 bit per un sistema che ha chiaramente float a 4 byte.

Sia che si tratti di risultati intermedi (ne dubito poiché lo stesso codice con cast espliciti [while (((float)(a + b) != (float)(a))] ha problemi simili) o (più probabilmente, credo) la possibilità che il valore unitario a possa essere rappresentato con bit più vicini al frazionario b regolando l'esponente, non lo so ancora.

Per ora, è meglio fare affidamento sulle informazioni sulla lingua che ho menzionato sopra, come l'uso di IEEE754 (se tali informazioni sono disponibili).

Lascerò il codice problematico come una trappola per i giocatori diffidenti. Forse qualcuno con più conoscenza in virgola mobile quindi posso lasciare una nota che spiega perché agisce in modo strano (nessuna congettura, per favore :-).

MODIFICA 2:

Questo pezzo di codice lo risolve assicurando che gli intermedi siano memorizzati in float. Scopre che Jonathan Leffler aveva ragione: erano risultati intermedi.

#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;

}

Questo codice genera (24,24) per mostrare che il valore calcolato corrisponde a quello nel file di intestazione.

Sebbene scritto in C, dovrebbe essere applicabile a qualsiasi lingua (in particolare quella in cui le informazioni non sono disponibili in un'intestazione o in virtù di ciò che è specificato nella documentazione linguistica). Ho provato solo in C perché Eclipse impiega così tanto tempo ad avviarsi sul mio Ubuntu :-).

Altri suggerimenti

Per C, e per estensione C ++, le informazioni sono nelle intestazioni <float.h> o <cfloat>.

Per C99, le informazioni sono contenute nella sezione 5.2.4.2.2 della norma:

  • 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

E allo stesso modo per le variazioni DBL e LDBL sulla maggior parte di queste (no DBL_RADIX o LDBL_RADIX). Lo standard suggerisce valori appropriati per IEEE 754 (la versione precedente dello standard IEEE 754 che era attuale nel 1999; c'era una nuova versione pubblicata, credo, nel 2008).

Potresti voler controllare <limits> nella tua libreria 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;
}

Penso che tu voglia std::numeric_limits<T>::digits che dovrebbe essere uno in più rispetto al numero di bit di mantissa. La mia macchina stampa:

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
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top