Знак числа с плавающей запятой - PullRequest
10 голосов
/ 21 ноября 2010

Есть ли простой способ определить знак числа с плавающей запятой?

Я экспериментировал и придумал это:

#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 для отрицательного числа, но я думаю, что это требует от меня предположения, что:

  • Байты машины имеют размер 8 бит
  • число с плавающей запятой равно 4 байтабольшой?
  • Самый старший бит машины - это самый левый бит (порядковый номер?)

Пожалуйста, исправьте меня, если какое-либо из этих предположений неверно или я что-то пропустил.

Ответы [ 8 ]

10 голосов
/ 21 ноября 2010

Попробуйте

float s = copysign(1, f);

от <math.h>

Другая полезная вещь может быть #include <ieee754.h>, если она доступна в вашей системе / компиляторе.

10 голосов
/ 21 ноября 2010

Предполагая, что это действительное число с плавающей запятой (а не, например, NaN):

float f;
bool is_negative = f < 0;

Это оставлено в качестве упражнения для читателя, чтобы выяснить, как проверить, является ли число с плавающей запятойположительны.

9 голосов
/ 21 ноября 2010

Используйте signbit () из math.h.

1 голос
/ 21 ноября 2010

Google формат с плавающей запятой для вашей системы. Многие используют IEEE 754, и в данных есть специальный бит знака для проверки. 1 отрицательный 0 положительный. Другие форматы имеют что-то похожее, и их так же легко изучить.

Заметьте, пытаясь заставить компилятор точно дать вам желаемое число с помощью жестко заданного присваивания, такого как f = -0.0F; может не работать не имеет ничего общего с форматом с плавающей запятой, но имеет отношение к синтаксическому анализатору и библиотеке C / C ++, используемой компилятором. Генерация минус ноль может быть или не быть такой тривиальной в общем.

1 голос
/ 21 ноября 2010

1) sizeof (int) не имеет к этому никакого отношения.

2) при условии, что CHAR_BIT == 8, да.

3) нам для этого нужен MSB, но порядковый номер влияет толькопорядок байтов, а не порядок битов, поэтому бит, который мы должны проверить, равен c[0]&0x80 для большой последовательности или c[3]&0x80 для маленькой, поэтому было бы лучше объявить объединение с uint32_t и проверкой с 0x80000000.

Этот трюк имеет смысл только для не специальных операндов памяти.Выполнение этого для значения float, которое находится в регистре XMM или x87, будет медленнее, чем прямой подход.Кроме того, он не обрабатывает специальные значения, такие как NaN или INF.

0 голосов
/ 19 июня 2015

Подходя к этому поздно, но я подумал о другом подходе.

Если вы знаете, что ваша система использует формат с плавающей точкой 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);
}

Это работало на моих тестовых системах;Кто-нибудь видел какие-либо предостережения или упускали из виду «Гочас»?

0 голосов
/ 04 июня 2012

Я получил это от http://www.cs.uaf.edu/2008/fall/cs441/lecture/10_07_float.html попробуйте это:

/* 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 голосов
/ 21 ноября 2010

Почему бы не if (f < 0.0)?

...