PDA

View Full Version : floating point, virgola mobile in (c)


robs05
21-02-2007, 10:55
sto cercando di rappresentare il codice binario di un float.
con operatori bitwise ma qundo lo compilo mi dice

invalid operands to binary &
invalid operands to binary >>

chi mi può dare una mano?
con gl'interi nn me lo fa

grazie mille


#include <stdio.h>
#include <stdlib.h>
#define n_len 32
void rappr_float(float n);


int main()
{
float a=36.25f;
printf("%.2f\n",a);

rappr_float(a);
system ("pause");
return 0;
}


void rappr_float(float n)
{
int i=n_len,bit[n_len];
do{
bit[i]=n&1;
i--;
n=n>>1;
}while(n!=0 && i>=0);

if(i>0)
do{
bit[i]=0;
i--;
}while(i>=0);

for(i=0;i<n_len;i++)
pritnf("%d",bit[i]);

}

yorkeiser
21-02-2007, 11:13
Non è possibile utilizzare gli operatori bitwise con i float. Ti dò anche una spiegazione tecnica: i float vengono processati nella fpu, mentre gli operatori bitwise sono normali operazioni della cpu (and,shl,shr eccetera), per cui agiscono solo sui registri della cpu e non su quelli della fpu

robs05
21-02-2007, 11:19
ok grazie ecome potrei fare

yorkeiser
21-02-2007, 11:28
O usi un altro tipo semplice per la tua rappresentazione, che supporti gli operatori bitwise (ad esempio gli int) o usi una struttura e ti riscrivi delle funzioni che "simulino" i bitwise

Michael Jennings
21-02-2007, 11:35
Potresti usare la union. In questo modo fai condividere la stessa porzione di memoria a due variabili di tipo diverso. Nel tuo caso una float e un'altra int (o long se int è meno di 4 byte). Inserisci il valore come float e lavora con il tipo intero per applicare gli operatori bitwise.:cool:

andbin
21-02-2007, 12:07
Si potrebbe fare così:
#include <stdio.h>

void print_bin_float (float f)
{
unsigned int m, n = *((unsigned int*) &f);

for (m = 1<<31; m != 0; m >>= 1)
printf (n & m ? "1" : "0");

printf ("\n");
}

int main (void)
{
float a = 1.23f;

print_bin_float (a);

return 0;
}Questa soluzione però non mi piace al 100%. Presuppone che int e float abbiano la stessa dimensione (e sui sistemi a 32 bit è così).

trallallero
21-02-2007, 12:58
Si potrebbe fare così:
#include <stdio.h>

void print_bin_float (float f)
{
unsigned int m, n = *((unsigned int*) &f);

for (m = 1<<31; m != 0; m >>= 1)
printf (n & m ? "1" : "0");

printf ("\n");
}

int main (void)
{
float a = 1.23f;

print_bin_float (a);

return 0;
}Questa soluzione però non mi piace al 100%. Presuppone che int e float abbiano la stessa dimensione (e sui sistemi a 32 bit è così).

l'idea é buona ma se mi posso permettere di perfezionarla :D
in caso di sistemi in cui int e float son diversi puoi usare un unsigned char *
e scorrere byte per byte il float:


void print_bin_float (float f)
{
unsigned char *pC;
int k, i;

for (pC = (unsigned char *)&f, i = 0; i < sizeof(float); pC++, i++)
for (k = 7; k >= 0; k--)
printf ("%d", *pC & (1 << k)? 1 : 0);

printf ("\n");
}

andbin
21-02-2007, 13:26
in caso di sistemi in cui int e float son diversi puoi usare un unsigned char *
e scorrere byte per byte il floatCerto ... anche io all'inizio avevo pensato a una cosa del genere:
void print_bin_float (float f)
{
char *p = (char*) &f;
int i, m;

for (i = sizeof(float)-1; i >= 0; i--)
for (m = 128; m != 0; m >>= 1)
printf (p[i] & m ? "1" : "0");

printf ("\n");
}Ma c'è una questione importante: se la macchina è little-endian o big-endian!!!

Il mio codice è per una macchina little-endian, il tuo codice l'hai scritto per una macchina big-endian.

trallallero
21-02-2007, 13:49
Certo ... anche io all'inizio avevo pensato a una cosa del genere:
void print_bin_float (float f)
{
char *p = (char*) &f;
int i, m;

for (i = sizeof(float)-1; i >= 0; i--)
for (m = 128; m != 0; m >>= 1)
printf (p[i] & m ? "1" : "0");

printf ("\n");
}Ma c'è una questione importante: se la macchina è little-endian o big-endian!!!

Il mio codice è per una macchina little-endian, il tuo codice l'hai scritto per una macchina big-endian.
immagino ci sia la define giusta a livello di SO. Si puó sempre swappare no ?
Mi ricordo il porting da Tandem a Unix un continuo swap

++CERO++
21-02-2007, 13:53
la butto lì, ma non conviene passare per l'esadecimale ? :stordita:

andbin
21-02-2007, 14:04
immagino ci sia la define giusta a livello di SO.Uhm ... non so se c'è una macro predefinita "standard" per questo ... non credo. Stavo guardando adesso le macro predefinite di un gcc 3.2.3 ma non trovo nulla di utile.

Si puó sempre swappare no ?
Mi ricordo il porting da Tandem a Unix un continuo swapBastarebbe mettere (facendo riferimento al mio codice):

#ifdef BIG_ENDIAN
for (i = 0; i < sizeof(float); i++)
#else
for (i = sizeof(float)-1; i >= 0; i--)
#endif

E sarei a posto. Naturalmente definendo la macro BIG_ENDIAN, se su una macchina big-endian.

trallallero
21-02-2007, 14:16
Uhm ... non so se c'è una macro predefinita "standard" per questo ... non credo. Stavo guardando adesso le macro predefinite di un gcc 3.2.3 ma non trovo nulla di utile.

qui su linux le ho (endian.h):
#define __LITTLE_ENDIAN 1234
#define __BIG_ENDIAN 4321
e questo :eek:
#define __PDP_ENDIAN 3412

andbin
21-02-2007, 14:34
qui su linux le ho (endian.h):Già .... è vero! :doh: (sapevo di questo file :p ).
Comunque non è "standard", con gcc su Linux è ok ma non so se c'è una cosa simile con altri compilatori.

trallallero
21-02-2007, 14:41
Già .... è vero! :doh: (sapevo di questo file :p ).
Comunque non è "standard", con gcc su Linux è ok ma non so se c'è una cosa simile con altri compilatori.

vedo adesso che su Sun trovi tanti:
#ifdef _BIG_ENDIAN
...
#ifdef _LITTLE_ENDIAN
quindi probabilmente é standard :boh:

ma endian.h non c'é.

Ma in effetti endian.h é della GNU:
/* Copyright (C) 1992, 1996, 1997, 2000 Free Software Foundation, Inc.
This file is part of the GNU C Library.