Pergunta

Existe uma maneira fácil de determinar o sinal de um número de ponto flutuante?

Eu experimentei e criei isso:

#include <iostream>

int main(int argc, char** argv)
{
 union
 {
  float f;
  char c[4];
 };

 f = -0.0f;
 std::cout << (c[3] & 0x10000000) << "\n";

 std::cin.ignore();
 std::cin.get();
 return 0;
}

Onde (c [3] e 0x10000000) fornece um valor> 0 para um número negativo, mas acho que isso exige que eu faça as suposições que:

  • Os bytes da máquina são 8 bits grandes
  • Um número de ponto de flutuação é 4 bytes grandes?
  • A parte mais significativa da máquina é a parte mais à esquerda (Endianness?)

Por favor, corrija -me se alguma dessas suposições estiver errada ou se eu tiver perdido alguma.

Foi útil?

Solução

Supondo que seja um número de ponto flutuante válido (e não, por exemplo, NAN):

float f;
bool is_negative = f < 0;

É deixado como um exercício ao leitor para descobrir como testar se um número de ponto flutuante é positivo.

Outras dicas

Tentar

float s = copysign(1, f);

a partir de <math.h>

Outra coisa útil pode ser #including <ieee754.h>, se estiver disponível no seu sistema/compilador.

Use SignBit () de Math.H.

1) Sizeof (int) não tem nada a ver com isso.

2) Assumindo char_bit == 8, sim.

3) Precisamos do MSB para isso, mas Endianness afeta apenas a ordem de byte, não a ordem de bit, então a parte que precisamos verificar é c[0]&0x80 para Big Endianness, ou c[3]&0x80 por pouco, então seria melhor declarar união com um uint32_t e verificando com 0x80000000.

Esse truque tem sentido apenas para operandos de memória não especiais. Fazendo isso para um float O valor que está no registro XMM ou X87 será mais lento que a abordagem direta. Além disso, ele não trata os valores especiais como NAN ou INF.

Google o formato de ponto flutuante para o seu sistema. Muitos usam o IEEE 754 e há um bit de sinal específico nos dados para examinar. 1 é negativo 0 é positivo. Outros formatos têm algo semelhante e fácil de examinar.

Nota Tentando fazer com que o compilador forneça exatamente o número que você deseja com uma atribuição de codificação dura como f = -0,0f; pode não funcionar. Não tem nada a ver com o formato de ponto flutuante, mas tem a ver com o analisador e a biblioteca C/C ++ usada pelo compilador. Gerar um zero menos pode ou não ser tão trivial em geral.

Eu tenho isso de http://www.cs.uaf.edu/2008/fall/cs441/lecture/10_07_float.htmlExperimente isso:

/* IEEE floating-point number's bits:  sign  exponent   mantissa */
struct float_bits {
    unsigned int fraction:23; /**< Value is binary 1.fraction ("mantissa") */
    unsigned int exp:8; /**< Value is 2^(exp-127) */
    unsigned int sign:1; /**< 0 for positive, 1 for negative */
};

/* A union is a struct where all the fields *overlap* each other */
union float_dissector {
    float f;
    struct float_bits b;
};

int main() {
    union float_dissector s;
    s.f = 16;
    printf("float %f  sign %u  exp %d  fraction %u",s.f, s.b.sign,((int)s.b.exp - 127),s.b.fraction);
    return 0;
}

Chegando a isso tarde, mas pensei em outra abordagem.

Se você sabe que seu sistema usa o formato IEEE754 de ponto flutuante, mas não o tamanho dos tipos de ponto flutuante são relativos aos tipos inteiros, você pode fazer algo assim:

bool isFloatIEEE754Negative(float f)
{
    float d = f;
    if (sizeof(float)==sizeof(unsigned short int)) {
        return (*(unsigned short int *)(&d) >> (sizeof(unsigned short int)*CHAR_BIT - 1) == 1);
    }
    else if (sizeof(float)==sizeof(unsigned int)) {
        return (*(unsigned int *)(&d) >> (sizeof(unsigned int)*CHAR_BIT - 1) == 1);
    }
    else if (sizeof(float)==sizeof(unsigned long)) {
        return (*(unsigned long *)(&d) >> (sizeof(unsigned long)*CHAR_BIT - 1) == 1);
    }
    else if (sizeof(float)==sizeof(unsigned char)) {
        return (*(unsigned char *)(&d) >> (sizeof(unsigned char)*CHAR_BIT - 1) == 1);
    }
    else if (sizeof(float)==sizeof(unsigned long long)) {
        return (*(unsigned long long *)(&d) >> (sizeof(unsigned long long)*CHAR_BIT - 1) == 1);
    }
    return false; // Should never get here if you've covered all the potential types!
}

Essencialmente, você trata os bytes em seu flutuador como um tipo inteiro não assinado e, em seguida, o deslocamento direito, exceto um dos bits (o bit de sinal) fora da existência. '>> funciona independentemente da Endianness, para que isso ignore essa questão.

Se for possível determinar a pré-execução qual tipo inteiro não assinado tem o mesmo comprimento do tipo de ponto flutuante, você pode abreviar isso:

#define FLOAT_EQUIV_AS_UINT unsigned int // or whatever it is

bool isFloatIEEE754Negative(float f)
{
    float d = f;
    return (*(FLOAT_EQUIV_AS_UINT *)(&d) >> (sizeof(FLOAT_EQUIV_AS_UINT)*CHAR_BIT - 1) == 1);
}

Isso funcionou nos meus sistemas de teste; Alguém vê advertências ou 'pegadas' esquecidas?

Por que não if (f < 0.0)?

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