2010-11-20 4 views
10

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

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

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

где (в [3] & 0x10000000) дает значение> 0 для отрицательного числа, но я думаю, что это требует от меня, чтобы сделать предположение, что:

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

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

+3

До тех пор, пока мы не узнаем, в какой системе вы находитесь, как мы можем исправить ваше предположение о том, является ли ваша машина большой или маленькой? – jball

+0

мои предположения были обобщены, извините, если это было непонятно. – Rarge

+0

Что случилось с <0? Я знаю, что даже с плавающей запятой 0 может иметь знак, но простой <оператор прост и будет охватывать почти все ваши случаи – hhafez

ответ

12

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

float f; 
bool is_negative = f < 0; 

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

+15

Это не работает в случае, когда f = -0.0f; – Rarge

+1

@ Rarge: Что вы делаете, в чем дело? [Задайте цель, а не шаг.] (Http://www.catb.org/esr/faqs/smart-questions.html) – GManNickG

+0

@Rarge: Почему вас волнует, является ли число положительным или отрицательным? В любом случае, число ноль - это одно значение, которое имеет два представления в некоторых форматах с плавающей запятой. Этот код проверяет знак числа; однако он не проверяет конкретное представление числа. –

7

Использовать signbit() от math.h.

+1

AFAIK, это C99 только. – GManNickG

+2

'signbit()' не является частью текущей стандартной библиотеки C++. Он является частью предлагаемой стандартной библиотеки C++ 0x (большинство - все?) Стандартной библиотеки C99 является частью C++ 0x). –

0

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

+7

Поскольку числа с плавающей запятой имеют два нуля -0.0f и + 0.0f – Rarge

+0

@Rarge: I echo @ комментарий GMan к ответу @James McNellis. –

+0

Это не дает ответа на вопрос. Чтобы критиковать или просить разъяснения у автора, оставьте комментарий ниже их сообщения. - [Из обзора] (/ review/low-quality-posts/11005316) – Will

10

Попробуйте

float s = copysign(1, f); 

из <math.h>

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

+1

'copysign()' не является частью текущей стандартной библиотеки C++. Он является частью предлагаемой стандартной библиотеки C++ 0x (большинство - все?) Стандартной библиотеки C99 является частью C++ 0x). –

+0

@James: по крайней мере gcc-4.3.4 поддерживает его (http://ideone.com/EAW3y) – Vlad

+0

@James: ... и в режиме C++ тоже (http://ideone.com/WxGLJ) – Vlad

1

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

2) Принимая CHAR_BIT == 8, да.

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

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

1

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

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

+0

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

0

Я получил это от 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

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

Если вы знаете, ваша система использует формат с плавающей запятой 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»?

Смежные вопросы