Некоторые существующие ответы указывают, что это твердо. Это действительно верно, потому что Вам нужен полный компилятор для обнаружения случаев, в которых предописание было бы соответствующим. Вы наклоняете C++ синтаксического анализа, не зная то, что означают символы; грамматика просто слишком неоднозначна для этого. Необходимо знать, называет ли определенное имя класс (мог бы быть вперед - объявлен), или переменная (не может). Кроме того, необходимо быть осведомлены о пространстве имен.
Приведите адрес вашего числа с плавающей запятой к адресу типа int того же размера и передайте это int в существующую функцию.
Благодарю Паскаля Куока за его комментарий. Наконец я понял, как решить свою проблему. Да, просто назначьте адрес числа с плавающей запятой указателю на целое число, а затем разыменуйте его. Вот мой код решения:
#include <stdio.h>
// bit returned at location
int bit_return(int a, int loc)
{
int buf = a & 1<<loc;
if (buf == 0) return 0;
else return 1;
}
int main()
{
//11000010111011010100000000000000
// 1 sign bit | 8 exponent bit | 23 fraction bits
float a = -118.625;
int *b;
b = &a;
int i;
for (i = 31; i >= 0; i--)
{
printf("%d",bit_return(*b,i));
}
return 0;
}
static void printme(void *c, size_t n)
{
unsigned char *t = c;
if (c == NULL)
return;
while (n > 0) {
--n;
printf("%02x", t[n]);
}
printf("\n");
}
void fpp(float f, double d)
{
printme(&f, sizeof f);
printme(&d, sizeof d);
}
float
fpp ()
в области видимости, когда вы вызываете его, иначе вы вызовете неясный K&R C против ANSI C проблема. Обновление: двоичный вывод ...
while (n > 0) {
int q;
--n;
for(q = 0x80; q; q >>= 1)
printf("%x", !!(t[n] & q));
}
Хотя из комментариев кажется, что вывод битов внутреннего представления может быть тем, что нужно, вот код для выполнения того, о чем буквально спрашивал вопрос, без преобразования с потерями в int, которое некоторые предлагали:
Вывод числа с плавающей запятой в двоичном формате:
#include <stdio.h>
#include <stdlib.h>
void output_binary_fp_number(double arg)
{
double pow2;
if ( arg < 0 ) { putchar('-'); arg = -arg; }
if ( arg - arg != 0 ) {
printf("Inf");
}
else {
/* compare and subtract descending powers of two, printing a binary digit for each */
/* first figure out where to start */
for ( pow2 = 1; pow2 * 2 <= arg; pow2 *= 2 ) ;
while ( arg != 0 || pow2 >= 1 ) {
if ( pow2 == .5 ) putchar('.');
if ( arg < pow2 ) putchar('0');
else {
putchar('1');
arg -= pow2;
}
pow2 *= .5;
}
}
putchar('\n');
return;
}
void usage(char *progname) {
fprintf(stderr, "Usage: %s real-number\n", progname);
exit(EXIT_FAILURE);
}
int main(int argc, char **argv) {
double arg;
char *endp;
if ( argc != 2 ) usage(argv[0]);
arg = strtod(argv[1], &endp);
if ( endp == argv[1] || *endp ) usage(argv[0]);
output_binary_fp_number(arg);
return EXIT_SUCCESS;
}
Если вы хотите использовать функцию bit_return для числа с плавающей запятой, вы можете просто обмануть:
float f = 42.69;
for ....
bit_return((int) f, loc)
Приведение (int) заставит компилятор поверить, что вы работаете с целым числом, поэтому bit_return будет работать.
По сути, это то, что предлагал Паскаль.
РЕДАКТИРОВАТЬ:
Я стою исправлен Паскалем. Я думаю, что это будет соответствовать его последнему комментарию:
bit_return (*((float *) &f), loc)
надеюсь, что тогда я понял.
Другой альтернативой (с меньшим количеством скобок) было бы использование объединения для обмана типа данных.
В следующем коде предполагается, что числа с плавающей запятой и указатели имеют одинаковый размер, что верно для многих систем:
float myfloat = 254940.4394f;
printf("0x%p", *(void**)(&myfloat));
В языке C термин «бит» относится к элементу двоичного позиционного представления числа. Целые числа в C используют двоичное позиционное представление, поэтому они имеют «биты». Это биты, которые вы «видите» с помощью побитовых операторов (логических и сдвигов). Числа с плавающей запятой не используют это представление. Кроме того, представление чисел с плавающей запятой не определено спецификацией языка. Другими словами, числа с плавающей запятой в C не имеют «битов» , поэтому вы не сможете получить доступ любой из их «битов» любыми законными средствами языка, и именно поэтому вы не можете применять какие-либо побитовые операторы к объектам с плавающей запятой.
Сказав это, я ' Я подозреваю, что вас могут заинтересовать физические биты, представляющие объект с плавающей запятой. Вы можете заново интерпретировать память, занимаемую объектом с плавающей запятой (или любым другим объектом), как массив элементов unsigned char
и вывести биты каждого из объектов unsigned char
. Это даст вам карту всех физических битов, представляющих объект.
Однако это не будет в точности эквивалентно тому, что у вас есть в приведенном выше коде. Ваш код выше печатает биты представления значения целостного объекта (то есть это логические биты, которые я описал выше), в то время как подход переинтерпретации памяти даст вам биты объекта представление (т.е. физических битов). Но опять же, числа с плавающей запятой в C не Они имеют логические биты по определению.
Добавлено позже: Я считаю, что понимание разницы между концепциями физических и логических битов может быть нелегкой задачей для некоторых читателей. В качестве еще одного примера, который может помочь в понимании, я хотел бы отметить, что нет абсолютно ничего, что могло бы помешать полностью совместимой реализации C на троичном оборудовании, то есть оборудовании, которое вообще не имеет физических двоичных битов. . В такой реализации побитовые операции по-прежнему будут работать отлично, они все равно будут обращаться к двоичным битам, то есть к элементам [теперь только мнимого] двоичного позиционного представления каждого целого числа. Это будут логические биты, о которых я говорю выше.
Я считаю, что понимание разницы между понятиями физических и логических битов может быть нелегкой задачей для некоторых читателей. В качестве еще одного примера, который может способствовать пониманию, я хотел бы отметить, что нет абсолютно ничего, что могло бы помешать полностью совместимой реализации C на троичном оборудовании, то есть на оборудовании, которое вообще не имеет физических двоичных битов. . В такой реализации побитовые операции по-прежнему будут работать отлично, они все равно будут обращаться к двоичным битам, то есть к элементам [теперь только мнимого] двоичного позиционного представления каждого целого числа. Это будут логические биты, о которых я говорю выше. Я считаю, что понимание разницы между понятиями физических и логических битов может оказаться непростой задачей для некоторых читателей. В качестве еще одного примера, который может помочь в понимании, я хотел бы отметить, что нет абсолютно ничего, что могло бы помешать полностью совместимой реализации C на троичном оборудовании, то есть оборудовании, которое вообще не имеет физических двоичных битов. . В такой реализации побитовые операции по-прежнему будут работать отлично, они все равно будут обращаться к двоичным битам, то есть к элементам [теперь только мнимого] двоичного позиционного представления каждого целого числа. Это будут логические биты, о которых я говорю выше. В качестве еще одного примера, который может способствовать пониманию, я хотел бы отметить, что нет абсолютно ничего, что могло бы помешать полностью совместимой реализации C на троичном оборудовании, то есть на оборудовании, которое вообще не имеет физических двоичных битов. . В такой реализации побитовые операции по-прежнему будут работать отлично, они все равно будут обращаться к двоичным битам, то есть к элементам [теперь только мнимого] двоичного позиционного представления каждого целого числа. Это будут логические биты, о которых я говорю выше. В качестве еще одного примера, который может способствовать пониманию, я хотел бы отметить, что нет абсолютно ничего, что могло бы помешать полностью совместимой реализации C на троичном оборудовании, то есть на оборудовании, которое вообще не имеет физических двоичных битов. . В такой реализации побитовые операции по-прежнему будут работать отлично, они все равно будут обращаться к двоичным битам, то есть к элементам [теперь только мнимого] двоичного позиционного представления каждого целого числа. Это будут логические биты, о которых я говорю выше. В такой реализации побитовые операции по-прежнему будут работать отлично, они все равно будут обращаться к двоичным битам, то есть к элементам [теперь только мнимого] двоичного позиционного представления каждого целого числа. Это будут логические биты, о которых я говорю выше. В такой реализации побитовые операции по-прежнему будут работать отлично, они все равно будут обращаться к двоичным битам, то есть к элементам [теперь только мнимого] двоичного позиционного представления каждого целого числа. Это будут логические биты, о которых я говорю выше.У меня есть включенный код, который производит шестнадцатеричный вывод, который, я думаю, может помочь вам понять числа с плавающей запятой. Вот пример:
double: 00 00 A4 0F 0D 4B 72 42 (1257096936000.000000) (+ 0x1.24B0D0FA40000 x 2 ^ 40)
Из моего примера кода ниже вам должно стать очевидно, как выводить биты. Преобразуйте адрес двойной точности в unsigned char *
и выведите биты sizeof (double)
chars.
Так как я хочу вывести экспоненту и значащую (и знаковый бит) число с плавающей запятой, мой примерный код копается в битах стандартного представления IEEE-754 для 64-битных точка с плавающей точкой двойной точности в системе счисления 2. Поэтому я не использую sizeof (double)
, кроме как для проверки того, что компилятор и я согласны с тем, что double
означает 64-битное число с плавающей запятой.
Если вы хотите вывести биты для числа с плавающей запятой любого типа, используйте sizeof (double)
вместо 8
.
void hexdump_ieee754_double_x86(double dbl)
{
LONGLONG ll = 0;
char * pch = (char *)≪
int i;
int exponent = 0;
assert(8 == sizeof(dbl));
// Extract the 11-bit exponent, and apply the 'bias' of 0x3FF.
exponent = (((((char *)&(dbl))[7] & 0x7F) << 4) + ((((char *)&(dbl))[6] & 0xF0) >> 4) & 0x7FF) - 0x3FF;
// Copy the 52-bit significand to an integer we will later display
for (i = 0; i < 6; i ++)
*pch++ = ((char *)&(dbl))[i];
*pch++ = ((char *)&(dbl))[6] & 0xF;
printf("double: %02X %02X %02X %02X %02X %02X %02X %02X (%f)",
((unsigned char *)&(dbl))[0],
((unsigned char *)&(dbl))[1],
((unsigned char *)&(dbl))[2],
((unsigned char *)&(dbl))[3],
((unsigned char *)&(dbl))[4],
((unsigned char *)&(dbl))[5],
((unsigned char *)&(dbl))[6],
((unsigned char *)&(dbl))[7],
dbl);
printf( "\t(%c0x1.%05X%08X x 2^%d)\n",
(((char *)&(dbl))[6] & 0x80) ? '-' : '+',
(DWORD)((ll & 0xFFFFFFFF00000000LL) >> 32),
(DWORD)(ll & 0xFFFFFFFFLL),
exponent);
}
Nota Bene: The Значение отображается в виде шестнадцатеричной дроби («0x1.24B0D0FA40000»), а показатель степени отображается в виде десятичной дроби («40»). Для меня это был интуитивно понятный способ отображения битов с плавающей запятой.
Если вы хотите вывести биты для числа с плавающей запятой любого типа, используйте sizeof (double)
вместо 8
.
void hexdump_ieee754_double_x86(double dbl)
{
LONGLONG ll = 0;
char * pch = (char *)≪
int i;
int exponent = 0;
assert(8 == sizeof(dbl));
// Extract the 11-bit exponent, and apply the 'bias' of 0x3FF.
exponent = (((((char *)&(dbl))[7] & 0x7F) << 4) + ((((char *)&(dbl))[6] & 0xF0) >> 4) & 0x7FF) - 0x3FF;
// Copy the 52-bit significand to an integer we will later display
for (i = 0; i < 6; i ++)
*pch++ = ((char *)&(dbl))[i];
*pch++ = ((char *)&(dbl))[6] & 0xF;
printf("double: %02X %02X %02X %02X %02X %02X %02X %02X (%f)",
((unsigned char *)&(dbl))[0],
((unsigned char *)&(dbl))[1],
((unsigned char *)&(dbl))[2],
((unsigned char *)&(dbl))[3],
((unsigned char *)&(dbl))[4],
((unsigned char *)&(dbl))[5],
((unsigned char *)&(dbl))[6],
((unsigned char *)&(dbl))[7],
dbl);
printf( "\t(%c0x1.%05X%08X x 2^%d)\n",
(((char *)&(dbl))[6] & 0x80) ? '-' : '+',
(DWORD)((ll & 0xFFFFFFFF00000000LL) >> 32),
(DWORD)(ll & 0xFFFFFFFFLL),
exponent);
}
Nota Bene: Значение отображается в виде шестнадцатеричной дроби («0x1.24B0D0FA40000»), а показатель степени отображается в виде десятичной дроби («40»). Для меня это был интуитивно понятный способ отображения битов с плавающей запятой.
Если вы хотите вывести биты для числа с плавающей запятой любого типа, используйте sizeof (double)
вместо 8
.
void hexdump_ieee754_double_x86(double dbl)
{
LONGLONG ll = 0;
char * pch = (char *)≪
int i;
int exponent = 0;
assert(8 == sizeof(dbl));
// Extract the 11-bit exponent, and apply the 'bias' of 0x3FF.
exponent = (((((char *)&(dbl))[7] & 0x7F) << 4) + ((((char *)&(dbl))[6] & 0xF0) >> 4) & 0x7FF) - 0x3FF;
// Copy the 52-bit significand to an integer we will later display
for (i = 0; i < 6; i ++)
*pch++ = ((char *)&(dbl))[i];
*pch++ = ((char *)&(dbl))[6] & 0xF;
printf("double: %02X %02X %02X %02X %02X %02X %02X %02X (%f)",
((unsigned char *)&(dbl))[0],
((unsigned char *)&(dbl))[1],
((unsigned char *)&(dbl))[2],
((unsigned char *)&(dbl))[3],
((unsigned char *)&(dbl))[4],
((unsigned char *)&(dbl))[5],
((unsigned char *)&(dbl))[6],
((unsigned char *)&(dbl))[7],
dbl);
printf( "\t(%c0x1.%05X%08X x 2^%d)\n",
(((char *)&(dbl))[6] & 0x80) ? '-' : '+',
(DWORD)((ll & 0xFFFFFFFF00000000LL) >> 32),
(DWORD)(ll & 0xFFFFFFFFLL),
exponent);
}
Nota Bene: The Значение отображается как шестнадцатеричная дробь («0x1.24B0D0FA40000»), а показатель степени отображается как десятичный («40»). Для меня это был интуитивно понятный способ отображения битов с плавающей запятой.
Выведите целую часть, затем '.', затем дробную часть.
float f = ...
int int_part = floor(f)
int fraction_part = floor((f - int_part) * pow(2.0, 32))
Затем вы можете используйте свой bit_return для печати x и y. Бонусные баллы за то, что не печатаются начальные и / или конечные нули.