Newsgroup: it.comp.lang.c
Titolo: Perplessità su porting del codice

Salve, come ormai tutti sapete sto effettuando un porting di codice da
fortran a C.
Ho comletato la conversione ed ora sto confrontando le prestazioni.
Il fatto è che non sono come giustificare una cosa.
Parte "fondamentale" sui risultati del programma è data da un generatore di
casuali che ho (anche questo) passato da fortran a C.
Ho verificato che i numeri generati siano gli stessi in ambedue i linguaggi.
Il numero generato è un long che viene utilizzato sia come long sia
convertito in reale con le seguenti operazioni:
In C:
    tmp_seed=randFortran(tmp_seed);
    s=(tmp_seed/
2147483647
/(*nrcl))+1;
IN Fortran:
call randp(seed)
s=(seed/
(2147483647
/nrcl))+1
e poi:
In C:
seed=randFortran(seed);
alpha=(((float)(seed))/
2147483647
);
dove alpha viene usato così:   cutoff = minsat + ((long)( alpha *
(maxsat-minsat) ));
In Fortran:
call randp(seed)
alpha= float(seed)/
2147483647
dove alpha viene usato così: cutoff=minsat+ifix(alpha*(maxsat-minsat))
Come è possibile che generando gli stessi long ed ottenendo gli stessi reali
(a partire dai long casuali) i risultati siano diversi?
Potrebbe dipendere da una maggiore precisione nel trattamento dei reali o
delle conversioni e cast che ho fatto?
Grazie

 Ho verificato che i numeri generati siano gli stessi in ambedue i linguaggi.
se non mi dici di che tipo sono tutte le variabili che stai usando
(int, float, double, etc.) non posso valutare  l'effetto dei cast
e la correttezza logica delle operazioni.
Perche' usi i float invece dei double?
A meno che tu non debba memorizzarne dei milioni io
eviterei sempre i float che hanno una precisione
molto scadente.
In fortran le variabili floating point di che tipo
sono ? (real, real*4, real*8, double precision, ?)
e in particolare quanti byte occupano ?
ciao,
g.

 molto scadente.
Ok, ma in realtà a me serve sono per quella variabile alpha per avere in
valore tra 0 ed 1.
In ogni caso ho verificato che in fortran con la stampa write (*,*) il real
arriva a 9 cifre dopo il punto.
La cosa strana è che risultano diversi anche minsat e maxsat, ma vengono
fatti con le stesse operazioni sugli stessi array che hanno lo stesso
contenuto (verificato).
In C:
  for(i=1; i<=n; i++){
    if ( plus0[i] > maxsat) maxsat =  plus0[i];
    if (minus0[i] > maxsat) maxsat = minus0[i];
    if ( plus0[i] < minsat) minsat =  plus0[i];
    if (minus0[i] < minsat) minsat = minus0[i];
  }
In fortran:
10 do 10 i=1,n
        if (plus0(i).gt.maxsat) maxsat=plus0(i)
        if (minus0(i).gt.maxsat) maxsat=minus0(i)
        if (plus0(i).lt.minsat) minsat=plus0(i)
        if (minus0(i).lt.minsat) minsat=minus0(i)
10 continue
Garantisco che minus0 e plus0 (array di long in C e di integer in fortran)
sono identici !!!
Grazie

 sono identici !!!
ma minsat e maxsat li hai inizializzati opportunamente ?
(scusa se te lo chiedo, ma e' l'errore piu' tipico)
ciao
g.

 ha scritto nel messaggio
news:dblch9$ii7$5...@newsfeed.cineca.it...

Si certo.
 minsat=LONG_MAX;
 maxsat=0;
Ri guardo il resto? Cosa ne pensi?

 s=(seed/
(2147483647
/nrcl))+1
scusa, ma tmp_seed e' un long ?
e nrcl di che tipo e' ?
in ogni caso tra
tmp_seed/
2147483647
/(*nrcl)  (C)
e
seed/
(2147483647
/nrcl)  (FORTRAN)
c'e una bella differenza: sono due espressioni
algebriche diverse.
inoltre stai molto attento al fatto che, se tmp_seed e' un long
allora probabilmente
tmp_seed/
2147483647
vale 0.
in generale c'e una bella differenza tra
1000/300/0.5   e
1000/300./0.5
nel primo caso viene fatto 1000/300 sugli interi che fa 3 e poi diviso 
per 0.5 e quindi si ottiene 6.0000
nel secondo viene fatto
1000/300.0 nei double che faa 3.33333... e poi diviso per 0.5 e quindi
si ottiene
6.666666...
non so se questo puo' essere il tuo problema, ma in
ogni caso stai attento a mischiare variabili e costanti
intere e floating point. Il C ha delle regole di
cast implicito ben precise, presumo che le abbia anche il
fortran, ma non so se coincidono !
ciao
g.

 fortran, ma non so se coincidono !
Mhmhm.
E quindi come andrebbe tradotto:
seed/
(2147483647
/nrcl)
in C avendo seed ed nrcl come long e dovendo ottenere s come int?
Grazie

 
seed/
(2147483647
/nrcl)
o nel tuo caso dove nrcl e' un puntatore come
seed/
(2147483647
/*nrcl)
che rimane comunque una istruzione un po' strana
(per non dire probabilmente sbagliata concettualmente)
sia in fortran che in C...
visto che verosimilmente vorrebbe servire ad ottenere numeri casuali
interi tra 0 e nrcl-1 distribuiti in modo
uniforme, ma puo' ottere anche valori uguali a nrcl a causa
del troncamento inerente nella divisione intera.
Infatti se ad esempio nrcl = 1000 allora
2147483647
/*nrcl fa
2147483 e quindi se il seed e' compreso tra
2147483000
 e 
2147483647
 abbiamo che
seed/
(2147483647
/*nrcl) vale 1000 ovvero nrcl.
quindi tieni conto che con probabilita' piccola ma non
nulla, il tuo programma potrebbe produrre valori
errati che possono causare risultati errati o
un segmentation falut.
Sia in fortran che in C
il modo corretto  di ottenere un numero intero
casuale tra 1 e nrlc sarebbe qualcosa del tipo:
val = 1+(int)((seed/(RAND_MAX+1.0))*nrcl);
dove RAND_MAX e' il massimo numero casuale restituito dalla funzione.
e il cast (int) e' in realta' inutile.
ciao,
g.

 e il cast (int) e' in realta' inutile.
Ok, ma non sarebbe basterebbe allora una operazione di modulo (%)?
Nel codice in versione modificata (quindi ora sto parlando di un'altra
versione che ho dovuto fare) ho usato:
    s = (genrand_int31()%(*nrcl))+1;
dove genrand_int31() genera uno pseudo casuale in [0,MAX_LONG].
In ogni caso, tornando al codice del post iniziale il mio obiettivo č di
ottenere gli stessi valori della espressione scritta in fortran.

 ottenere gli stessi valori della espressione scritta in fortran.
allora
s=(tmp_seed/
(2147483647
/*nrcl))+1;
come ti ho gia' detto, ma poi non ti lamentare se
il programma si pianta o fornice dei risultati sbagliati.
ciao,
g.

 il programma si pianta o fornice dei risultati sbagliati.
Scusami, magari sono un po' (:-)) tonto.
Diciamo che ho un array di n+1 elementi:
[0][1][2][3]........[n]
Io utilizzo gli elementi da 1 a n non considerando l'elemento 0.
Ora, come faccio ad ottenere da quel codice, rimanendo il + possibile vicino
al codice fortran o cmq, cercando di ottenere gli stessi valori, un valore s
in [1,n] ??
Inoltre, ed infine, lo giuro:
Questo codice: s = (genrand_int31()%(*nrcl))+1; genera numeri in [1,n]?
Vero?
Grazie e scusa
P.S.: perchè dicevi che è meglio val = 1+(int)((seed/(RAND_MAX+1.0))*nrcl);

 Io utilizzo gli elementi da 1 a n non considerando l'elemento 0.
Perché ?


perche' ha fatto un porting paro-paro da un programma in
fortran dove gli indici cominciano da 1.
in questo modo non ha dovuto ragionare su e modificare ogni
accesso ad array/ciclo etc.
effettivamente se uno ha 3 cicli annidati
e poi un accesso del tipo
a[i+j,k+2*h-1,j]=b[j+1,a[k+2-1]]+b[j-1,i+k]]
allora capisco che non voglia ricalcolarsi
tutti gli indici.
ciao,
g.


Si, ne ho anche di peggio. Insomma per una locazione per un totale di 15
array, non valeva la pena rifare tutto.
Circa quegli ultimi miei quesiti?
Grazie

 tutti gli indici.
Be', io non lo capisco, perché, a parte che (meccanicamente 
sottraendo -1 a ciascun indice) diventerebbe semplicemente:
a[i+j-1,k+2*h-1-1,j-1]=b[j+1-1,a[k+2-1]-1]+b[j-1-1,i+k-1]]
quello di non toccare gli indici è un comportamento che può 
condurre facilmente ad errori.  Capisco che non si vogliano 
ricalcolare, ma si avesse del codice del tipo:
a[i+j,2]=b[3*2*f(x+y),3];
bisognerebbe comunque stare attentissimi.

 P.S.: perchè dicevi che è meglio val = 1+(int)((seed/(RAND_MAX+1.0))*nrcl);
i primi generatori casuali implementati nelle librerie disponibili
con i piu' comuni compilatori C avevano il difetto di generare numeri
casuali nei quali i bit "bassi" (meno significativi)
erano meno casuali dei bit alti.
Siccome il modulo, specialmente rispetto ad una potenza di 2, dipende
dai bit bassi questo produceva risultati meno casuali di quanto
uno desiderava.
Quindi veniva consigliato di usare il metodo con la divisione per 
RAND_MAX che invece usa implicitamente i bit "alti".
E' probabile che ora tutti i compilatori/librerie che ci sono in giro
siano stati aggiornati e corretti, ma si preferisce comunque evitare
il modulo.
ciao,
g.

"Andrea Laforgia" <x...@xx.xx> ha scritto nel messaggio
news:BAsDe.28813$b93....@tornado.fastwebnet.it...

Quello che dici è corretto, ma il fatto è che gli stessi indici hanno le
programma un significato legato al file di input e la presenza dello zero
creerebbe non poche difficoltà.
In pratica si tratterebbe di riproggettare tutto e non è quello che devo
fare ne' è conveniente.
Grazie di tutto

 ha scritto nel messaggio
news:dblkn5$kkc$3...@newsfeed.cineca.it...

Ok, io sto usando il Mersenne Twister.


Non riesco a vedere il problema. A cosa ti riferisci ?
La f() verrebbe tradotta dal fortran al C facendo in modo
che restituisca gli stessi valori.
Se lo spreco di qualche locazione di memoria non e' un problema,
direi che a modificare tutti gli indici si puo' magari
rischiare di dimenticarsene uno e quindi preferirei il modo
di Ciobin.
ciao,
g.

 che restituisca gli stessi valori.
ROTFL... tu cambieresti la traduzione della funzione e non 
decrementeresti semplicemente di 1 l'indice ?


penso che non ci siamo capiti.
io lascerei tutto inalterato, definizioni di f()
compresa
quindi dal fortran
DO 100, i=1,N
DO 100, j=1,M
   a(i+j,2)=b(3*2*f(x+y),3);
100 CONTINUE
passerei al C:
for (i=1; i<=N; i++)
for (j=1; j<=M; j++)
   a[i+j][2]=b[3*2*f(x+y)][3];
quello che non mi era chiaro e' a cosa
ti riferivi quando dicevi che in questo caso
bisognerebbe stare attentissimi.
ciao,
g.

 bisognerebbe stare attentissimi.
Non ci fare caso, sto dicendo cazzate, č stanchezza pomeridiana, 
scusa ;-)