Domanda

In C ++, ho una classe bigint che può contenere un numero intero di dimensione arbitraria.

Mi piacerebbe convertire galleggiante di grandi dimensioni o di numeri doppi a BIGINT. Ho un metodo di lavoro, ma è un po 'di hack. Ho usato IEEE 754 specifica il numero per ottenere il segnale binario, mantissa ed esponente del numero di ingresso.

Ecco il codice (segno viene ignorato qui, questo non è importante):

 float input = 77e12;
 bigint result;

 // extract sign, exponent and mantissa, 
 // according to IEEE 754 single precision number format
 unsigned int *raw = reinterpret_cast<unsigned int *>(&input); 
 unsigned int sign = *raw >> 31;
 unsigned int exponent = (*raw >> 23) & 0xFF;
 unsigned int mantissa = *raw & 0x7FFFFF;

 // the 24th bit is always 1.
 result = mantissa + 0x800000;

 // use the binary exponent to shift the result left or right
 int shift = (23 - exponent + 127);
 if (shift > 0) result >>= shift; else result <<= -shift;

 cout << input << " " << result << endl;

Funziona, ma è piuttosto brutto, e io non so come portatile è. C'è un modo migliore per fare questo? C'è un modo portatile meno brutta di estrarre la mantissa e l'esponente binario da un galleggiante o raddoppiare?


Grazie per le risposte. Ai posteri, ecco una soluzione che utilizza frexp. E 'meno efficiente a causa del ciclo, ma funziona per float e double simili, non usa reinterpret_cast o dipendere alcuna conoscenza di floating point rappresentazioni numeriche.

float input = 77e12;
bigint result;

int exponent;
double fraction = frexp (input, &exponent);
result = 0;
exponent--;
for (; exponent > 0; --exponent)
{
    fraction *= 2;
    if (fraction >= 1)
    {
        result += 1;
        fraction -= 1;
    }
    result <<= 1;
}   
È stato utile?

Soluzione

Non puoi normalmente estrarre i valori utilizzando frexp (), frexpf (), frexpl () ?

Altri suggerimenti

Mi piace la tua soluzione! E mi ha fatto sulla strada giusta.

Mi raccomando una cosa però - perché non avere un mucchio di bit in una sola volta ed eliminare quasi sempre qualsiasi loop? Ho implementato una funzione float-to-bigint in questo modo:

template<typename F>
explicit inline bigint(F f, typename std::enable_if<(std::is_floating_point<F>::value)>::type* enable = nullptr) {
    int exp;
    F fraction = frexp(fabs(f),&exp);
    F chunk = floor(fraction *= float_pow_2<F,ulong_bit_count>::value);
    *this = ulong(chunk); // will never overflow; frexp() is guaranteed < 1
    exp -= ulong_bit_count;
    while (sizeof(F) > sizeof(ulong) && (fraction -= chunk)) // this is very unlikely
    {
        chunk = floor(fraction *= float_pow_2<F,ulong_bit_count>::value);
        *this <<= ulong_bit_count;
        (*this).data[0] = ulong(chunk);
        exp -= ulong_bit_count;
    }
    *this <<= exp;
    sign = f < 0;
}

(A proposito, non so di un modo semplice per mettere in virgola mobile potenze di due costanti, così ho definito float_pow_2 come segue):

template<typename F, unsigned Exp, bool Overflow = (Exp >= sizeof(unsigned))>
struct float_pow_2 {
    static constexpr F value = 1u << Exp;
};
template<typename F, unsigned Exp>
struct float_pow_2<F,Exp,true> {
    static constexpr F half = float_pow_2<F,Exp/2>::value;
    static constexpr F value = half * half * (Exp & 1 ? 2 : 1);
};

Se il galleggiante contiene sempre un valore integrale, basta cast a int. Float_to_int = input (più firmato)

A proposito, 77e12 trabocca un galleggiante. Un doppio si terrà, ma poi avrete bisogno di questo cast:. (Lunga unsigned long) ingresso

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top