Newsgroup: it.comp.lang.c
Titolo: operatori binari

salve,
non riesco a utilizzare gli operatori come & e << con le variabili
float, come mai?
se provo a fare
float f = 2,5;
int i;
i = f << 10;
non funziona...
ho provato a usarli oggi perchè mi serve una funzione per arrotondare
un numero float in int, so che esiste la funzione rint ma nonostante
includa math.h nel mio sorgente mi dice che non è dichiarata ecc.

i = f << 10;
i = ((int)f) << 10;
-- 
The Follet

 includa math.h nel mio sorgente mi dice che non è dichiarata ecc.
   "Arrotondare" o "convertire"?
   Nel primo caso, la funzione rint() fa parte dello standard da poco 
(C99), essendo stata mutuata dal mondo BSD, quindi potrebbe non far 
parte della tua libreria (consulta la manualistica del tuo compilatore 
in proposito). D'altra parte, lo standard C89 prevedeva le funzioni 
floor() e ceil() che, a mio avviso, sono in grado di risolvere la 
maggior parte dei problemi di arrotondamento.
   Nel secondo, posto il piu` semplice criterio di arrotondamento, la 
seguente porzione di codice risolve quasi certamente il tuo cruccio:
<code>
	int
	myround(double in)
	{
		int aux=in;	/* surprise!  you can assign a
				   double value to an integer
				   variable:  what will be
				   the behaviour? */
		if((in-aux)>0.5)	return aux+1;
		else			return aux;
	}
</code>
--
Alla prossima,
Marco

 numeri interi.
Ne approfitto per fare una domanda, non direttamente legata al C: è
possibile, con qualche stratagemma, eseguire operazioni matematiche a
precisione indefinita?
Mi spiego meglio: io so che un numero in virgola mobile non potrà mai
essere rappresentato esattamente dalla macchina. Ad esempio un float
quale 1.9 in binario è un numero periodico, quindi la rappresentazione
della macchina introduce un errore, dovuto al fatto che i bit della
rappresentazione sono limitati; eseguendo operazioni matematiche tra
numeri di questo tipo  gli errori si accumulano. Come è possibile
eseguire operazioni che diano risultati esatti, avendo fissato a priori
la precisione da utilizzare? Devo necessariamente tener conto
dell'aritmetica degli errori oppure c'è qualche metodo più furbo?
Grazie,
Cecco

dell'aritmetica degli errori oppure c'č qualche metodo piů furbo?
Non e' possibile avere risultati esatti.
E' solo possibile avere risultati molto vicini a quelli
esatti.
Il discorso e' molto piu' semplice di quanto possa sembrare:
eseguire operazioni con precisione infinita non e' possibile
e quindi bisogna, comunque, fissare un grado di precisione.
Si puo' cercare di aumentare questa precisione con
l'aritmetica multipla (ovvero estendendo quello che e' il
formato dei numeri reali implementato con il proprio
compilatore) e per farlo esistono librerie in proposito.
L'unica furbizia che si puo' adottare, quando si ha a che
fare con l'aritmetica con precisione fissa e' quella di
eseguire le operazioni in modo tale che la perdita di
precisione non sia troppo alta.
Per esempio, contrariamente a quanto avviene nella
matematica, dividere o sottrarre numeri molto vicini tra
loro conduce a una grossa perdita di precisione, per cui
un'espressione del tipo:
999/998 * 1000
Non equivale a compiere:
999*1000 / 998
-- 
The Follet

   "Arrotondare" o "convertire"?
beh arrotondare o cmq troncare la parte decimale.
grazie per la risposta :-)

 precisione indefinita?
un "trucco" e' eseguire le operazioni in forma simbolica (cioe' con 
frazioni, radici, logaritmi etc) un po' come si fa al liceo, e poi dare 
il risultato con quanti decimali esatti si vuole, oppure lasciarlo in 
forma astratta, ad es. 3/2 + sqrt(2) + sin (63°) - ln 2
logicamente questo elimina il rischio di errori intermedi, ma complica 
enormemente la gestione delle operazioni

 dell'aritmetica degli errori oppure c'è qualche metodo più furbo?
   Puoi utilizzare stringhe di cifre, come fa l'applicativo bc(1) di 
Unix. In questo caso, al costo della riscrittura di *tutte* le 
operazioni, dalla semplice somma alla funzione di bessel, puoi lavorare 
con la precisione che preferisci e senza errori di arrotondamento.
--
Alla prossima,
Marco
 

 starndard IEEE 754.
   Esattamente, e come allora certamente sai, non tutti i bit hanno lo 
stesso significato: c'e` quello per il segno della mantissa, ce n'e` un 
po' per la mantissa stessa, e cosi` via, sicche` traslarli o sottoporli 
ad operazioni logiche comporta risultati diversi da quelli che si 
ottengono con gli interi.
--
Alla prossima,
Marco

starndard IEEE 754.
Si, appunto, quindi prima mette le cifre significative e poi la
mantissa.
Facendo uno shift stravolgi completamente il modo di lettura del
numero in virgola mobile (accorgiando/allungando la mantissa/le cifre
significative) Non tronchi proprio niente, stravolgi solo il numero in
virgola mobile. Se sai come funziona lo standard IEEE 754 (oltre a
saperne il nome) allora capirai anche perche'.
Mox.

Ringrazio tutti per la risposta. In effetti quello a cui pensavo io è
proprio quello di utilizzare stringhe di cifre, come ha proposto Marco
Natoni. Se non ho capito male, un programma del genere dovrebbe
convertire ogni numero immesso nella corrispondente stringa, elaborare
ogni singola operazione e restituire la stringa del risultato finale.
L'elaborazione dovrà essere effettuata sui singoli caratteri delle
stringhe, un pò come si impara in prima elementare (mi pare :).
Comunque non sò, al di là di un interesse didattico, quanto possa
servire una cosa del genere: se operazioni di questo tipo venissero
usate per implementare funzioni (matematiche) complesse, probabilmente
il guadagno nella precisione sarebbe perso tutto in tempo di esecuzione.
Voi che ne dite?
Ciao,
Cecco
PS: scusate per l'OT

starndard IEEE 754.
Non "il C", ma molte implementazioni si'.
Lo standard IEEE 754 prevede che la disposizione dei bit in
un float/double/long double, segua una logica particolare e
operare degli slittamenti di bit produce un risultato che
non rispetta questa logica.
-- 
The Follet

Voi che ne dite?
Ribadisco: per non avere limiti evidenti a livello di
prestazioni, bisogna usare l'aritmetica in precisione
multipla.
-- 
The Follet

 lo stesso significato:
forse ho capito... tu pensi che io voglia che so fare uno shift di 2 a
sinistra per moltiplicare per 4 come si fa in binario ma io mica
voglio fare così!
prendo il primo bit e ho il segno, prendo i successivi 8 e ho
l'esponente e il resto è mantissa...
conosciuto l'esponente so quante cifre prendere della mantissa per
avere la parte intera e con questo ho fatto il mio arrotondamento.
so che sembra assurdo perchè ci sono già le funzioni per arrotondare
ma a questo punto mi sono ostinato e voglio fare così :-)

i = ((int)f) << 10;
ok, solo che cosě non ottengo l'effetto che voglio io (quello che ho
spiegato nell'altro post). beh pazienza...
avrei un'altra domanda, io uso lcc che mi sembra abbastanza comodo
soprattutto per fare il debug ma ogni tanto da qualche problemino
fastidioso... ad esempio se faccio l'esecuzione passo passo una volta
arrivato all'istruzione che mi hai suggerito lui termina il programma
(come se avessi fatto un return)...
volevo chiedervi se conoscete un ambiente simile, mi andrebbe bene
pure qualcosa simile al turbo pascal che era comodissimo
grazie!

 ma a questo punto mi sono ostinato e voglio fare così :-)
   Fammi sapere come va a finire. A me sembra un'operazione destinata a 
finire in un bagno di lacrime e sangue e mi sento in dovere di 
demoralizzarti prima, onde evitarti questo triste destino:
 
http://research.microsoft.com/~hollasch/cgindex/coding/ieeefloat.html
--
Alla prossima,
Marco

Uhmm, preferivo pensare che volessi shiftare a sinistra o a destra per
ottenere una divisione/moltiplicazione :P
http://anubis.dkuug.dk/JTC1/SC22/WG14/www/docs/n751.htm
Qui si parla dei Floating point secondo lo standard c99.
"The C89 Committee also endeavored to accommodate the IEEE 754
floating point standard by not adopting any constraints on floating
point which are contrary to that standard. In C9X, the floating
point standard is IEC 559."
Forse puoi farcela uando le costandi definite in limits.h (e forse in
float.h secondo il C99).
Nota pero' che e' un lavorone perche' lo standard non dice i valori
massimi per i numeri in virgola mobile, te le devi ricavare tu
leggendoti le costanti contenute appunto in quelle 2 librerie poiche'
ogni implementazione e' libera di definirle come meglio crede.
Se ci riesci ed e' un modo portabile ti devo fare i complimenti.
Mox :)

 precisione indefinita?
In aggiunta a tutte le soluzioni riguardanti il calcolo numerico che ti 
hanno fornito, te ne propongo un'altra che svia un po' dalla domanda 
generale.
Se ti interessa operare solo su numeri razionali la cosa migliore e' 
crearti una struttura del tipo:
struct Rational {
  int num, denom;
};
Rappresentante una frazione. Volendo e' possibile estendere questo 
approccio creandosi strutture apposta anche per rappresentare radicali, 
logaritmi, numeri "magici" (tipo pigreco ed "e"). In pratica potresti 
fare in modo che il computer svolga tutte le operazioni matematiche in 
modo simbolico e non decimale, proprio come fanno gli uomini.
Realizzare un sistema che riesca a rappresentare tutti gli ambiti della 
matematica e' estremamente complicato, ma e' senz'alto il modo per 
effettuare calcoli alla massima precisione possibile.
Inoltre, in applicazioni concrete, potrebbe essere sufficiente 
realizzare solo una piccola parte del sistema completo (ad esempio, 
solo frazioni e radicali) semplificando notevolmente il compito.
ciao Anto
-- 
Antonio Cuni, 19 anni, studente
Brainbench C++ Master: 4.6, higher than 98% of all previous test takers.
C Language: 3.32, higher than 79% of all previous test takers.
Guida C/C++ di Programmazione.it: 
http://cpp.programmazione.it