Lim
14-12-2015, 15:04
Salve a tutti, ho un problema con la generazione dei numeri casuali in Java.
Ho sviluppato una piattaforma di simulazione per il moto di migliaia di particelle in uno spazio 3D.
Ho la necessità di aggiornare le loro coordinate spaziali (x, y, z) ad ogni istante temporale della simulazione in modo del tutto casuale (data da un moto di tipo Browniano) secondo una distribuzione Gaussiana con media nulla e deviazione standard predefinita.
Ipotizzando una dislocazione iniziale delle particelle in un punto ben preciso dello spazio, ci si aspetterebbe che dopo un certo tempo, le particelle si siano sparpagliate nello spazio in modo uniforme, mantenendo il baricentro di tutti i punti grosso modo intorno al punto iniziale.
Ho eseguito diversi run su macchine diverse ed ho ottenuto risultati diversi. La maggior parte delle macchine utilizzate resituisce i risultati attesi, mentre alcune configurazioni specifiche restituiscono risultati polarizzati.
Infatti dai risultati emerge che la "nuvola" di punti si sposti lungo una direzione preferenziale (lungo l'asse x).
Mi chiedo se la generazione dei numeri casuali possa dipendere in qualche modo dall'architettura del processore utilizzato.
Le architetture utilizzate per i test sono le seguenti:
Tipo 1:
Intel(R) Core(TM) i7-3770 CPU @ 3.40GHz
RAM: 32GB
Tipo 2:
Intel(R) Core(TM) i5-2300 CPU @ 2.80GHz
RAM: da 8GB a 24GB
Tipo 3:
Intel(R) Xeon(R) CPU E5410 @ 2.33GHz
RAM: 24GB
Tipo 4:
Six-Core AMD Opteron(tm) Processor 8425 HE @ 2.1GHz
RAM: 64GB
Tipo 5:
AMD Opteron(tm) Processor 6128 @ 2GHz
RAM: 128GB
Tipo 6:
Intel(R) Xeon(R) CPU E5-2650 v3 @ 2.30GHz
RAM: 64GB
Le tipologie 1 e 2 forniscono i risultati attesi, tutte le altre danno risultati polarizzati.
Il sistema operativo utilizzato è Ubuntu 12.04 LTS e Ubuntu 14.04 LTS.
La versione della JVM è: OpenJDK 1.7 (64-Bit)
Riporto anche il codice dell'algoritmo per l'aggiornamento delle coordinate dei punti:
Il metodo move() è invocato ad ogni passo temporale della simulazione per ogni singolo punto da aggiornare mediante un approccio multithread (non mostrato qui):
public void move(MyObj p) {
float[] center=p.getCenter();
float sigma2=getDiffusionCoefficient(p);
float dx=getGauss(sigma2);
float dy=getGauss(sigma2);
float dz=getGauss(sigma2);
center[0]=center[0]+dx;
center[1]=center[1]+dy;
center[2]=center[2]+dz;
p.setCenter(center[0],center[1],center[2]);
}
// A better implementation of Gaussian Random Number
public float getGauss(float sigma){
float rai=(float) Math.sqrt(-2*sigma*sigma*Math.log(1-(random.next(val)/div)));
float teta=(float) (2*Math.PI*(random.next(val)/div));
return (float) (rai*Math.cos(teta));
}
Dove random è un'istanza di XORShiftRandom:
// XORShiftRandom
int val=31;
double div=Math.pow(2, val);
XORShiftRandom random=new XORShiftRandom();
// End XORShiftRandom
public class XORShiftRandom {
private long seed = System.nanoTime();
public XORShiftRandom() {
}
protected int next(int nbits) {
long x = this.seed;
x ^= (x << 21);
x ^= (x >>> 35);
x ^= (x << 4);
this.seed = x;
x &= ((1L << nbits) -1);
return (int)(x);
}
}
Avendo rilevato una polarizzazione lungo l'asse x, ho voluto provare ad invertire l'ordine di generazione delle nuove coordinate, da x,y,z a y,z,x. La polarizzazione si è spostata dalla componente lungo x a quella lungo y! Quindi a quanto pare è la prima coordinata generata a subire principalmente gli effetti della polarizzazione.
Non ho idea del perché...
Inoltre, sembrerebbe che al crescere del numero di punti, cresca anche l'effetto della polarizzazione (in effetti, al crescere del numero di punti cresce il numero di chiamate al metodo di generazione delle coordinate).
Qualcuno ha qualche idea al riguardo?
Ho sviluppato una piattaforma di simulazione per il moto di migliaia di particelle in uno spazio 3D.
Ho la necessità di aggiornare le loro coordinate spaziali (x, y, z) ad ogni istante temporale della simulazione in modo del tutto casuale (data da un moto di tipo Browniano) secondo una distribuzione Gaussiana con media nulla e deviazione standard predefinita.
Ipotizzando una dislocazione iniziale delle particelle in un punto ben preciso dello spazio, ci si aspetterebbe che dopo un certo tempo, le particelle si siano sparpagliate nello spazio in modo uniforme, mantenendo il baricentro di tutti i punti grosso modo intorno al punto iniziale.
Ho eseguito diversi run su macchine diverse ed ho ottenuto risultati diversi. La maggior parte delle macchine utilizzate resituisce i risultati attesi, mentre alcune configurazioni specifiche restituiscono risultati polarizzati.
Infatti dai risultati emerge che la "nuvola" di punti si sposti lungo una direzione preferenziale (lungo l'asse x).
Mi chiedo se la generazione dei numeri casuali possa dipendere in qualche modo dall'architettura del processore utilizzato.
Le architetture utilizzate per i test sono le seguenti:
Tipo 1:
Intel(R) Core(TM) i7-3770 CPU @ 3.40GHz
RAM: 32GB
Tipo 2:
Intel(R) Core(TM) i5-2300 CPU @ 2.80GHz
RAM: da 8GB a 24GB
Tipo 3:
Intel(R) Xeon(R) CPU E5410 @ 2.33GHz
RAM: 24GB
Tipo 4:
Six-Core AMD Opteron(tm) Processor 8425 HE @ 2.1GHz
RAM: 64GB
Tipo 5:
AMD Opteron(tm) Processor 6128 @ 2GHz
RAM: 128GB
Tipo 6:
Intel(R) Xeon(R) CPU E5-2650 v3 @ 2.30GHz
RAM: 64GB
Le tipologie 1 e 2 forniscono i risultati attesi, tutte le altre danno risultati polarizzati.
Il sistema operativo utilizzato è Ubuntu 12.04 LTS e Ubuntu 14.04 LTS.
La versione della JVM è: OpenJDK 1.7 (64-Bit)
Riporto anche il codice dell'algoritmo per l'aggiornamento delle coordinate dei punti:
Il metodo move() è invocato ad ogni passo temporale della simulazione per ogni singolo punto da aggiornare mediante un approccio multithread (non mostrato qui):
public void move(MyObj p) {
float[] center=p.getCenter();
float sigma2=getDiffusionCoefficient(p);
float dx=getGauss(sigma2);
float dy=getGauss(sigma2);
float dz=getGauss(sigma2);
center[0]=center[0]+dx;
center[1]=center[1]+dy;
center[2]=center[2]+dz;
p.setCenter(center[0],center[1],center[2]);
}
// A better implementation of Gaussian Random Number
public float getGauss(float sigma){
float rai=(float) Math.sqrt(-2*sigma*sigma*Math.log(1-(random.next(val)/div)));
float teta=(float) (2*Math.PI*(random.next(val)/div));
return (float) (rai*Math.cos(teta));
}
Dove random è un'istanza di XORShiftRandom:
// XORShiftRandom
int val=31;
double div=Math.pow(2, val);
XORShiftRandom random=new XORShiftRandom();
// End XORShiftRandom
public class XORShiftRandom {
private long seed = System.nanoTime();
public XORShiftRandom() {
}
protected int next(int nbits) {
long x = this.seed;
x ^= (x << 21);
x ^= (x >>> 35);
x ^= (x << 4);
this.seed = x;
x &= ((1L << nbits) -1);
return (int)(x);
}
}
Avendo rilevato una polarizzazione lungo l'asse x, ho voluto provare ad invertire l'ordine di generazione delle nuove coordinate, da x,y,z a y,z,x. La polarizzazione si è spostata dalla componente lungo x a quella lungo y! Quindi a quanto pare è la prima coordinata generata a subire principalmente gli effetti della polarizzazione.
Non ho idea del perché...
Inoltre, sembrerebbe che al crescere del numero di punti, cresca anche l'effetto della polarizzazione (in effetti, al crescere del numero di punti cresce il numero di chiamate al metodo di generazione delle coordinate).
Qualcuno ha qualche idea al riguardo?