Newsgroup: it.comp.os.linux.development
Titolo: divisioni con Int

Ciao,
Ho un problema con.... le divisioni !
Se io voglio dividere due numeri interi ed assegnare il valore
risultante ad una variabile devo per forza passare per variabili
float ?
Se lo faccio con numeri interi mi si annullano i valori...
Questa funzione :
/*	int Random(int NMax);
Ritorna un numero intero casuale compreso tra 0 e NMax-1 */
int Random(int NMax)
{
	return   (rand() * NMax)/RAND_MAX;
}
Mi risulta sempre 0 a meno che non dichiari NMax e RAND_MAX
come float, anche se poi il loro valore e' sempre intero.
Tra l'altro questo codice compilato con gcc in OS2 funziona, 
evidentemente il Linux devo considerare qualche cosa che mi
sfugge...
Francesco
IACT Member.
http://frengo.dragonfire.net/

 sfugge...
tipo che rand vuole srand() prima? o che cosi' rischi l'overflow?



Prima di richiamare rand ho chiamato srand, e comunque il
problema si propone con le divisioni in generale, indipendentemente
dalla presenza di chiamate a rand nel calcolo.
Per l'overflow ci ho pensato, ma non mi segnala nulla al riguardo.
Il risultato comunque e' un int, i risultati intermedi delle 
operazioni
possono superare l'int ma nelle varie prove ho anche assegnato
il valore a variabili long int e non e' cambiato nulla.


 il valore a variabili long int e non e' cambiato nulla.
e chi te lo garantisce? anzi, scommetto che sulla tua macchina 
sizeof(int)==sizeof(long)

 come float, anche se poi il loro valore e' sempre intero.
e' un problema di overflow.
$ cat a.c
#include <stdlib.h>
main(){
int n, i, NMax=0;
        srand(1);
        for(i=0; i<10; i++){
                n = rand();
                NMax++;
                printf("%d * %d = %d\n", n, NMax, n*NMax);
        }
}
$ gcc a.c
$ a.out
1804289383 * 1 = 1804289383
846930886 * 2 = 1693861772
1681692777 * 3 = 750111035     
1714636915 * 4 = -1731386932   
1957747793 * 5 = 1198804373    
424238335 * 6 = -1749537286
719885386 * 7 = 744230406
1649760492 * 8 = 313182048
596516649 * 9 = 1073682545
1189641421 * 10 = -988487678
come vedi dal terzo in poi sono andati tutti in overflow.
D'altronde RAND_MAX sotto linux vale...
#define        RAND_MAX        
2147483647
ovvero il massimo valore che un intero con segno puo' assumere.
Quindi qualsiasi intero e' comunque inferiore a RAND_MAX e, se diviso
per RAND_MAX, da' come risultato zero. 
Usa i double, Luke :)
-- 
addio, e grazie per tutto il pesce

 Francesco
bye
-- 
David Mugnai
To err is human...to really foul up requires the root password.

 il valore a variabili long int e non e' cambiato nulla.
$ cat a.c
int main(void){
        printf("%d, %d\n", sizeof(int), sizeof(long));
        return 0;
}
$ gcc a.c
$ a.out
4, 4
int e long, sotto linux e con architetture x86, hanno la stessa
dimensione: 4 byte. Questo e' perfettamente in linea con quanto dice
lo standard ansi C: gli unici vincoli sono che
* sizeof(char) = 1
* sizeof(short) >= 2, sizeof(int) >= 2
* sizeof(long) >= 4
* sizeof(short) <= sizeof(int) <= sizeof(long)


 Usa i double, Luke :)
Quindi dovrei usare i double per il calcolo e poi passare un
return mia_variabile_double 


 ora se rand()*NMax < RAND_MAX hai 0 (avresti 0.xxxx in float troncato in int)
Si', certo, infatti lo scopo del calcolo e' avere un valore compreso
tra 0 e NMax.
Per valori "bassi" di rand() il risultato e' 0....


 Per valori "bassi" di rand() il risultato e' 0....
Sotto Linux RAND_MAX e' a 32 bit, sotto Win a 16bit (forse anche sotto OS/2)
se dividi un numero *intero con segno* a 32 bit per un numero intero con segno
che vale *il massimo rappresentabile* a 32 bit ottieni 0.
ciao
-- 
David Mugnai
There are two ways to write error-free programs. Only the third one works.

Ho letto un po' delle risposte che hai ottenuto, ma continuo
a non capire perche' moltiplichi per NMax e poi cerchi il
quozioente per MAX_RAND.
io ho sempre generato un numero intero casuale con l' operazione
modulo (rand() % NMax) che da' un intero da 0 a (NMax - 1).
Nel tuo codice tutti i casi in cui il prodotto (che e' intero)
di rand() + NMax e' minore di RAND_MAX il risultato e' 0 dato
che int / int non viene promosso ad altro tipo ma rimane int e
questo dovrebbe essere ordinario se RAND_MAX e' il piu' grande
intero rappresentabile sul tuo sistema. infatti se il prodotto
per essere rappresentato dovesse essere promosso a tipo superiore
es long, e questo non e' possibile perche' sizeof(long) == sizeof(int)
Secondo me c' e' un bug logico nel tuo source.
Consiglio rand() % NMax
Comunque che io sappia:
int / int da int
float / int viene promosso a float
int / float   "     "         "
Ciao.
Roberto.
Frengo wrote:
+> 
+> Ciao,
+> 
+> Ho un problema con.... le divisioni !
+> 
+> Se io voglio dividere due numeri interi ed assegnare il valore
+> risultante ad una variabile devo per forza passare per variabili
+> float ?
+> 
+> Se lo faccio con numeri interi mi si annullano i valori...
+> 
+> Questa funzione :
+> 
+> /*      int Random(int NMax);
+> Ritorna un numero intero casuale compreso tra 0 e NMax-1 */
+> int Random(int NMax)
+> {
+>         return   (rand() * NMax)/RAND_MAX;
+> }
+> 
+> Mi risulta sempre 0 a meno che non dichiari NMax e RAND_MAX
+> come float, anche se poi il loro valore e' sempre intero.
+> 
+> Tra l'altro questo codice compilato con gcc in OS2 funziona,
+> evidentemente il Linux devo considerare qualche cosa che mi
+> sfugge...
+> 
+> Francesco
+> 
+> IACT Member.
+> 
http://frengo.dragonfire.net/

 quozioente per MAX_RAND.
penso abbia letto il man di rand:
If  you  want  to generate a random integer between 1 and 10,
you should always do it by using high-order bits, as in
        j=1+(int) (10.0*rand()/(RAND_MAX+1.0));
ma lo abbia reinterpretato

 che vale *il massimo rappresentabile* a 32 bit ottieni 0.
Beh, il risultato della prima operazione ( rand()*NMax)  puo'
 benissimo superare il max degli int, pero' magari l'overflow 
non mi e' consentito...
Scusate se mi dilungo, ho gia' aggirato il problema specifico, 
pero' se non capisco il meccanismo ogni operazione diventera'
un incubo o dovro' dichiarare sempre variabili enormi per evitare
gli overflow :)))


 int / float   "     "         "
Io pensavo che dipendesse tutto dalla variabile a cui assegno
il risultato, ma evidentemente mi sbagliavo...


 penso abbia letto il man di rand:
No, mi sono letto la definizione di rand() nel manuale ansi c
di Kernighan e Ritchie ed ho cercato di adattare la funzione alle
mie necessita'.
Le str****** sono tutte farina del mio sacco... 


 Non dubito che funzioni, ma non capisco il meccanismo...
E' chiaro che il risultato dell' operazione resto non puo' essere
maggione del dividendo quindi hai ottenuto quello che vuoi.
Se il generatore di numeri casuali del tuo sistema e' di buona qualita'
puoi ottenere un intero random che mutui le stesse qualita' di
distribuzione con l' operazione resto. se il dividendo dell' operazione
resto e' un numero primo, tutto il numero generato da rand()
determinera'
il valore del resto, se invece e' una potenza di 2 es 256 solo gli
ultimi 8 bit del risultato di rand() saranno selezionati e questo
POTREBBE far perdere qualita' di bonta' del numero random, come e'
spiegato sul Sedgewich.
Ti posto il codice del mio generatore di password che ho postato 
qualche giorno fa':
<CODICE>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
char * genpass(char * setcaratteri, size_t n, char * stringa)
{
  size_t i=0;
 
  while(i<n)
    stringa[i++]=setcaratteri[rand()%36];
 
  stringa[n]=0;
  return stringa;
}
int main()
{
  char str[512];
  char setcaratteri[] = "abcdefghijklmnopqrstuvwxyz0123456789";
  srand(time(NULL));
  printf("%s\n",genpass(setcaratteri,20,str));
  return 0;
}
</CODICE>
Ciao
Roberto.

 Scusate se mi dilungo, ho gia' aggirato il problema specifico, 
di nulla
-- 
David Mugnai
Real programmers don't document. If it was hard to write, it should be hard to understand

 degli int.
ovviamente si. L'operatore / applicato tra due interi restituisce un intero.
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

 qualche giorno fa':
Avevo gia' guardato il tuo codice, prima di postare mi sono letto un
po' di mex arretrati...
Solo che quando ho visto il % mi sono bloccato un po' :)


 gli overflow
per evitare gli overflow, anche nei valori in v.mobile, e' meglio fare 
le divisioni prima delle moltiplicazioni

intermedi neanche se il risultato finale e' un numero int
Se non ricordo male invece negli Intel compatibili è possibile, visto
che il processore userebbe due registri; ma forse serve l'assembly per
sfruttare questa possibilità.
-- 
Saluti,
    Mardy
http://castellina.org/interlingua

 gli overflow :)))
bisogna solo entrare nella logica contorta del C :))


 il risultato, ma evidentemente mi sbagliavo...
infatti: la variabile a cui assegni il risultato non influenza
minimamente il tipo dell'espressione.
ad esempio:
int a, b;
float c;
a = 3;
c = 2.0;
b = a / c;
in questo caso hai un intero diviso un float. Il risultato di quella
divisione e' un float (vedi le regole di promozione di tipo elencate
sopra). Poi quel float viene assegnato ad una variabile intera (b) e
quindi viene troncato e diventa un intero. In ogni caso il risultato
della divisione era un float.
PS: ti consiglio di leggere un buon libro sul C come il 
mitico Kernighan & Ritchie "Linguaggio C" (seconda edizione)
jackson libri.


 jackson libri.
A dire la verita' sto leggendo proprio quel libro, anche se confesso 
che non mi sta entusiasmando
molto, salta alcuni passaggi che non sono per niente scontati.
