2010-11-20 17 views
10

¿Existe alguna manera fácil de determinar el signo de un número de coma flotante?Signo de un número de punto flotante

Experimenté y se le ocurrió esto:

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

donde (c [3] & 0x10000000) da un valor> 0 para un número negativo, pero creo que esto me obliga a hacer las suposiciones que:

  • bytes de la máquina son 8 bits gran número
  • un punto flotante de 4 bytes de grande?
  • bit más significativo de la máquina es el bit más a la izquierda (orden de bits?)

Por favor, corríjanme si alguno de esos supuestos están equivocados o si me he perdido ninguna.

+3

Hasta que sepamos en qué sistema se encuentra, ¿cómo podemos corregir su suposición acerca de si su máquina es grande o poco endian? – jball

+0

mis suposiciones fueron generalizadas, lo siento si eso no estaba claro. – Rarge

+0

¿Qué pasa con <0? Sé que incluso el punto flotante 0 puede tener un signo, pero el operador hhafez

Respuesta

12

asumiendo que es un número de coma flotante válido (y no, por ejemplo, NaN):

float f; 
bool is_negative = f < 0; 

Se deja como ejercicio para el lector de encontrar la manera de probar si un número de punto flotante es positivo .

+15

Esto no funciona en el caso donde f = -0.0f; – Rarge

+1

@Rarge: ¿Qué estás haciendo en lo que importa? [Pregunte el objetivo, no el paso.] (Http://www.catb.org/esr/faqs/smart-questions.html) – GManNickG

+0

@Rarge: ¿Por qué le importa si un número es cero positivo o negativo? En cualquier caso, el número cero es un valor único que tiene dos representaciones en algunos formatos de punto flotante. Este código sí prueba el signo de un número; sin embargo, no prueba una representación particular del número. –

7

Use signbit() de math.h.

+1

AFAIK, eso es solo C99. – GManNickG

+2

'signbit()' no es parte de la biblioteca estándar de C++ actual. Es parte de la biblioteca estándar propuesta de C++ 0x (¿la mayoría de todos ?: la biblioteca estándar C99 es parte de C++ 0x). –

0

¿Por qué no if (f < 0.0)?

+7

Debido a que los números de punto flotante tienen dos ceros -0.0f y + 0.0f – Rarge

+0

@Rarge: echo eco del comentario de @GMan a la respuesta de @James McNellis. –

+0

Esto no proporciona una respuesta a la pregunta. Para criticar o solicitar aclaraciones de un autor, deje un comentario debajo de su publicación. - [De la crítica] (/ review/low-quality-posts/11005316) – Will

10

Trate

float s = copysign(1, f); 

de <math.h>

Otra cosa útil puede ser #including <ieee754.h>, si está disponible en su sistema/compilador.

+1

'copysign()' no es parte de la biblioteca estándar de C++ actual. Es parte de la biblioteca estándar propuesta de C++ 0x (¿la mayoría de todos ?: la biblioteca estándar C99 es parte de C++ 0x). –

+0

@Juegos: al menos gcc-4.3.4 lo admite (http://ideone.com/EAW3y) – Vlad

+0

@Juegos: ... y en el modo C++, también (http://ideone.com/WxGLJ) – Vlad

1

1) sizeof (int) no tiene nada que ver con eso.

2) asumiendo CHAR_BIT == 8, sí.

3) necesitamos MSB para eso, pero endianness afecta solamente orden de bytes, no orden de bits, por lo que el poco tenemos que comprobar es c[0]&0x80 para el gran orden de bits, o c[3]&0x80 por poco, por lo que sería mejor declarar la unión con un uint32_t y comprobando con 0x80000000.

Este truco tiene sentido solo para operandos de memoria no especiales. Si lo hace con un valor de float que está en XMM o en el registro x87 será más lento que el enfoque directo. Además, no trata los valores especiales como NaN o INF.

1

google el formato de coma flotante para su sistema. Muchos usan IEEE 754 y hay un bit de signo específico en los datos para examinar. 1 es negativo 0 es positivo. Otros formatos tienen algo similar y son fáciles de examinar.

Tenga en cuenta que el compilador debe darle exactamente el número que desea con una asignación codificada como f = -0.0F; puede que no funcione. no tiene nada que ver con el formato de coma flotante, pero tiene que ver con el analizador y la biblioteca C/C++ utilizada por el compilador. Generar un cero negativo puede o no ser tan trivial en general.

+0

http://www.psc.edu/general/software/packages/ieee/ieee.php –

0

Tengo esto desde http://www.cs.uaf.edu/2008/fall/cs441/lecture/10_07_float.html intente esto:

/* 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; 
} 
0

Viniendo a esta tarde, pero pensé en otro enfoque.

Si sabe que su sistema utiliza el formato de coma flotante IEEE754, pero no la magnitud de los tipos de punto flotante son en relación con los tipos enteros, usted podría hacer algo como esto:

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! 
} 

En esencia, se tratan los bytes en su flotante como un tipo entero sin signo, luego a la derecha, todos los bits menos uno (el bit de signo) a la derecha desaparecen. '>>' funciona independientemente de endianidad por lo que esto pasa por alto ese problema.

Si es posible determinar pre-ejecución que no firmada tipo entero es la misma longitud que el Tipo de punto flotante, se puede abreviar esto:

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

Esto funcionó en mis sistemas de prueba; ¿Alguien ve alguna advertencia o pasa por alto 'gotchas'?

Cuestiones relacionadas