Ответ 1
Предполагая, что это допустимое число с плавающей запятой (а не, например, NaN):
float f;
bool is_negative = f < 0;
В качестве упражнения читателю нужно выяснить, как проверить, является ли число с плавающей точкой положительным.
Есть ли простой способ определить знак числа с плавающей запятой?
Я экспериментировал и придумал это:
#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;
}
где (c [3] и 0x10000000) дает значение > 0 для отрицательного числа, но я думаю, что это требует от меня сделать предположения, что:
Пожалуйста, исправьте меня, если какое-либо из этих допущений ошибочно или я пропустил какой-либо.
Предполагая, что это допустимое число с плавающей запятой (а не, например, NaN):
float f;
bool is_negative = f < 0;
В качестве упражнения читателю нужно выяснить, как проверить, является ли число с плавающей точкой положительным.
Try
float s = copysign(1, f);
из <math.h>
Еще одна полезная вещь может быть #including <ieee754.h>
, если она доступна в вашей системе/компиляторе.
Используйте signbit() из math.h.
1) sizeof (int) не имеет к этому никакого отношения.
2), предполагая CHAR_BIT == 8, да.
3) для этого нам нужен MSB, но endianness влияет только на порядок байтов, а не на порядок бит, поэтому бит, который нам нужно проверить, - c[0]&0x80
для большой endianness, или c[3]&0x80
для мало, так что было бы лучше объявить объединение с uint32_t
и проверить с помощью 0x80000000.
Этот трюк имеет смысл только для неспецифических операндов памяти. Выполнение этого значения float
, которое находится в регистре XMM или x87, будет медленнее, чем прямой подход. Кроме того, он не обрабатывает специальные значения, такие как NaN или INF.
google формат с плавающей запятой для вашей системы. Многие используют IEEE 754, и в данных, которые необходимо изучить, есть определенный бит знака. 1 отрицательно 0 положительно. Другие форматы имеют нечто похожее и легко проверяются.
Обратите внимание, пытаясь заставить компилятор точно указать нужный вам номер с жестким кодированным присваиванием, например f = -0.0F; может не работать. не имеет ничего общего с форматом с плавающей запятой, но имеет отношение к парсеру и библиотеке C/С++, используемой компилятором. Генерация минус нуля может быть или не быть вообще тривиальной.
Почему бы не if (f < 0.0)
?
Я получил это от http://www.cs.uaf.edu/2008/fall/cs441/lecture/10_07_float.html попробуйте следующее:
/* IEEE floating-point number 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;
}
Придя к этому поздно, но я подумал о другом подходе.
Если вы знаете, что ваша система использует формат с плавающей запятой IEEE754, но не насколько большие типы с плавающей запятой относятся к целым типам, вы можете сделать что-то вроде этого:
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!
}
По существу, вы обрабатываете байты в своем float как целочисленный тип без знака, а затем сдвигаете вправо все, кроме одного из битов (знаковый бит), из существующих. " → " работает независимо от его соответствия, поэтому это обходит эту проблему.
Если возможно определить предварительное выполнение, которое беззнаковый целочисленный тип имеет ту же длину, что и тип с плавающей запятой, вы можете сократить это:
#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);
}
Это работало на моих тестовых системах; кто-нибудь видит какие-либо оговорки или пропускает "gotchas"?