Pergunta

No C ++, tenho uma classe Bigint que pode conter um número inteiro de tamanho arbitrário.

Eu gostaria de converter carros alegóricos ou números duplos em bigint. Eu tenho um método de trabalho, mas é um pouco de hack. Usei especificação de número IEEE 754 para obter o sinal binário, o Mantissa e o expoente do número de entrada.

Aqui está o código (o sinal é ignorado aqui, isso não é 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;

Funciona, mas é bastante feio, e eu não sei como é portátil. Existe uma maneira melhor de fazer isso? Existe uma maneira menos feia e portátil de extrair a mantissa binária e o expoente de um flutuador ou o dobro?


Obrigado pelas respostas. Para posteridade, aqui está uma solução usando o Frexp. É menos eficiente por causa do loop, mas funciona para flutuar e dobrar igualmente, não usa reinterpret_cast ou depende de qualquer conhecimento das representações do número de pontos flutuantes.

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;
}   
Foi útil?

Solução

Você normalmente não pode extrair os valores usando Frexp (), Frexpf (), Frexpl ()?

Outras dicas

Eu gosto da sua solução! Isso me colocou no caminho certo.

Eu recomendaria uma coisa - por que não conseguir um monte de pedaços de uma só vez e quase sempre elimina qualquer loop? Eu implementei uma função de flutuação para Bigint como esta:

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 propósito, não conheço uma maneira fácil de colocar constantes de potência de dois pontos flutuantes, então defini float_pow_2 da seguinte maneira):

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 o float sempre contiver um valor integral, basta lançá -lo para int: float_to_int = (longa não assinada).

BTW, 77E12 transborda de um flutuador. Um duplo o segurará, mas você precisará deste elenco: (não assinada longa) entrada).

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top