Java - 有没有办法生成随机但确定的信号?
Java - is there a way to generate random, but deterministic signal?
我正在 Java 中编写一个信号发生器应用程序,其中一个功能是生成一个信号,该信号是具有高斯分布的噪声。我当前对此 class 的 returning 值的实现如下:
import java.util.Random;
public class FormulaGaussianDistributionNoise extends Formula {
private Double stdEv;
private Random r;
public FormulaGaussianDistributionNoise(Double stdEv) {
this.stdEv = stdEv;
this.r = new Random();
}
@Override
public Double value(Double x) {
return stdEv*r.nextGaussian();
}
}
当我生成 ie. 100Hz 采样的 10 秒信号我得到了漂亮的高斯噪声信号,看起来像这样:
Great gaussian signal
但是问题是我希望我的信号一旦生成就变成确定性的。正如你们中的许多人所注意到的,如果使用相同的参数调用两次,我准备的 class 将 return 两个不同的值。我想实现我的 FormulaGaussianDistributionNoise
对象的方法 value(Double x)
使用相同的参数 return 调用的对象总是相同的值。
到目前为止我尝试的是在 value(Double x)
的每次调用中使用 Random
class 的方法 setSeed(long x)
。我的 class 看起来像这样:
public class FormulaGaussianDistributionNoise extends Formula {
private Double stdEv;
private Random r;
private long seed;
public FormulaGaussianDistributionNoise(Double stdEv) {
this.stdEv = stdEv;
this.seed = System.currentTimeMillis();
this.r = new Random(seed);
}
@Override
public Double value(Double x) {
//Generate new seed based on the double value
long newSeed = Double.doubleToRawLongBits(x);
r.setSeed(this.seed ^ newSeed);
return stdEv*r.nextGaussian();
}
}
this.seed
class 的属性用于使此 class 的对象彼此不同。在 value(x)
调用中,我将 Random
对象的新种子设置为 this,seed
和 x
的位异或。因此,如果使用相同的 x
调用,它总是为 r
对象设置相同的种子,因此 nextGaussian()
总是 return 相同的值。问题是实际上这些值经常重复并且信号看起来不再像高斯:
Great NO-gaussian signal
我对此进行了更深入的研究,Random
class 的 setSeed(long seed)
的实现如下所示:
/**
* Sets the seed of this random number generator using a single
* {@code long} seed. The general contract of {@code setSeed} is
* that it alters the state of this random number generator object
* so as to be in exactly the same state as if it had just been
* created with the argument {@code seed} as a seed. The method
* {@code setSeed} is implemented by class {@code Random} by
* atomically updating the seed to
* <pre>{@code (seed ^ 0x5DEECE66DL) & ((1L << 48) - 1)}</pre>
* and clearing the {@code haveNextNextGaussian} flag used by {@link
* #nextGaussian}.
*
* <p>The implementation of {@code setSeed} by class {@code Random}
* happens to use only 48 bits of the given seed. In general, however,
* an overriding method may use all 64 bits of the {@code long}
* argument as a seed value.
*
* @param seed the initial seed
*/
synchronized public void setSeed(long seed) {
this.seed.set(initialScramble(seed));
haveNextNextGaussian = false;
}
private static long initialScramble(long seed) {
return (seed ^ multiplier) & mask;
}
private static final long multiplier = 0x5DEECE66DL;
private static final long mask = (1L << 48) - 1;
如您所见,方法 setSeed(long seed)
将种子设置为一些 initialScramble(seed)
,它实际上仅使用我的 64 位种子的 48 位。当我像那样炒我的种子时,我实际上经常得到相同的种子:
this.seed x newSeed this.seed^newSeed [y] initialScramble(y)
1590082351125 0.0 0 1590082351125 1614482495096
1590082351125 0.25 4598175219545276416 4598176809627627541 1614482495096
1590082351125 0.5 4602678819172646912 4602680409254998037 1614482495096
1590082351125 0.75 4604930618986332160 4604932209068683285 1614482495096
1590082351125 1.0 4607182418800017408 4607184008882368533 1614482495096
1590082351125 1.25 4608308318706860032 4608309908789211157 1614482495096
1590082351125 1.5 4609434218613702656 4609435808696053781 1614482495096
1590082351125 1.75 4610560118520545280 4610561708602896405 1614482495096
1590082351125 2.0 4611686018427387904 4611687608509739029 1614482495096
1590082351125 2.25 4612248968380809216 4612250558463160341 1614482495096
1590082351125 2.5 4612811918334230528 4612813508416581653 1614482495096
1590082351125 2.75 4613374868287651840 4613376458370002965 1614482495096
1590082351125 3.0 4613937818241073152 4613939408323424277 1614482495096
1590082351125 3.25 4614500768194494464 4614502358276845589 1614482495096
1590082351125 3.5 4615063718147915776 4615065308230266901 1614482495096
1590082351125 3.75 4615626668101337088 4615628258183688213 1614482495096
1590082351125 4.0 4616189618054758400 4616191208137109525 1614482495096
1590082351125 4.25 4616471093031469056 4616472683113820181 1614482495096
1590082351125 4.5 4616752568008179712 4616754158090530837 1614482495096
1590082351125 4.75 4617034042984890368 4617035633067241493 1614482495096
1590082351125 5.0 4617315517961601024 4617317108043952149 1614482495096
1590082351125 5.25 4617596992938311680 4617598583020662805 1614482495096
1590082351125 5.5 4617878467915022336 4617880057997373461 1614482495096
1590082351125 5.75 4618159942891732992 4618161532974084117 1614482495096
1590082351125 6.0 4618441417868443648 4618443007950794773 1614482495096
1590082351125 6.25 4618722892845154304 4618724482927505429 1614482495096
1590082351125 6.5 4619004367821864960 4619005957904216085 1614482495096
1590082351125 6.75 4619285842798575616 4619287432880926741 1614482495096
1590082351125 7.0 4619567317775286272 4619568907857637397 1614482495096
1590082351125 7.25 4619848792751996928 4619850382834348053 1614482495096
1590082351125 7.5 4620130267728707584 4620131857811058709 1614482495096
1590082351125 7.75 4620411742705418240 4620413332787769365 1614482495096
1590082351125 8.0 4620693217682128896 4620694807764480021 1614482495096
1590082351125 8.5 4620974692658839552 4620976282741190677 1614482495096
1590082351125 9.0 4621256167635550208 4621257757717901333 1614482495096
1590082351125 9.5 4621537642612260864 4621539232694611989 1614482495096
但是覆盖 Random
class 以摆脱 initialScramble
也没有帮助。我发现 Random.next()
方法也只使用 48 位种子,所以这可能是问题所在。
/**
* Generates the next pseudorandom number. Subclasses should
* override this, as this is used by all other methods.
*
* <p>The general contract of {@code next} is that it returns an
* {@code int} value and if the argument {@code bits} is between
* {@code 1} and {@code 32} (inclusive), then that many low-order
* bits of the returned value will be (approximately) independently
* chosen bit values, each of which is (approximately) equally
* likely to be {@code 0} or {@code 1}. The method {@code next} is
* implemented by class {@code Random} by atomically updating the seed to
* <pre>{@code (seed * 0x5DEECE66DL + 0xBL) & ((1L << 48) - 1)}</pre>
* and returning
* <pre>{@code (int)(seed >>> (48 - bits))}.</pre>
*
* This is a linear congruential pseudorandom number generator, as
* defined by D. H. Lehmer and described by Donald E. Knuth in
* <i>The Art of Computer Programming,</i> Volume 3:
* <i>Seminumerical Algorithms</i>, section 3.2.1.
*
* @param bits random bits
* @return the next pseudorandom value from this random number
* generator's sequence
* @since 1.1
*/
protected int next(int bits) {
long oldseed, nextseed;
AtomicLong seed = this.seed;
do {
oldseed = seed.get();
nextseed = (oldseed * multiplier + addend) & mask;
} while (!seed.compareAndSet(oldseed, nextseed));
return (int)(nextseed >>> (48 - bits));
}
private static final long multiplier = 0x5DEECE66DL;
private static final long addend = 0xBL;
private static final long mask = (1L << 48) - 1;
我的问题是:是否有使用 64 位种子生成下一个值的随机数生成器 classes?我找不到任何。也许您有不同的解决方案来使我的 value(Double x)
具有确定性?
我使用 java.security
包中的 SecureRandom
class 达到了预期的效果。
这个 post 的答案帮助了我:
工作实施:
import java.security.SecureRandom;
public class FormulaGaussianDistributionNoise extends Formula {
private Double stdEv;
private long basicSeed;
public FormulaGaussianDistributionNoise(Double stdEv) {
this.stdEv = stdEv;
this.basicSeed = System.currentTimeMillis();
}
@Override
public Double value(Double x) {
SecureRandom r = new SecureRandom();
long newSeed = Double.doubleToRawLongBits(x);
r.setSeed(this.basicSeed ^ newSeed);
return stdEv*r.nextGaussian();
}
}
我正在 Java 中编写一个信号发生器应用程序,其中一个功能是生成一个信号,该信号是具有高斯分布的噪声。我当前对此 class 的 returning 值的实现如下:
import java.util.Random;
public class FormulaGaussianDistributionNoise extends Formula {
private Double stdEv;
private Random r;
public FormulaGaussianDistributionNoise(Double stdEv) {
this.stdEv = stdEv;
this.r = new Random();
}
@Override
public Double value(Double x) {
return stdEv*r.nextGaussian();
}
}
当我生成 ie. 100Hz 采样的 10 秒信号我得到了漂亮的高斯噪声信号,看起来像这样: Great gaussian signal
但是问题是我希望我的信号一旦生成就变成确定性的。正如你们中的许多人所注意到的,如果使用相同的参数调用两次,我准备的 class 将 return 两个不同的值。我想实现我的 FormulaGaussianDistributionNoise
对象的方法 value(Double x)
使用相同的参数 return 调用的对象总是相同的值。
到目前为止我尝试的是在 value(Double x)
的每次调用中使用 Random
class 的方法 setSeed(long x)
。我的 class 看起来像这样:
public class FormulaGaussianDistributionNoise extends Formula {
private Double stdEv;
private Random r;
private long seed;
public FormulaGaussianDistributionNoise(Double stdEv) {
this.stdEv = stdEv;
this.seed = System.currentTimeMillis();
this.r = new Random(seed);
}
@Override
public Double value(Double x) {
//Generate new seed based on the double value
long newSeed = Double.doubleToRawLongBits(x);
r.setSeed(this.seed ^ newSeed);
return stdEv*r.nextGaussian();
}
}
this.seed
class 的属性用于使此 class 的对象彼此不同。在 value(x)
调用中,我将 Random
对象的新种子设置为 this,seed
和 x
的位异或。因此,如果使用相同的 x
调用,它总是为 r
对象设置相同的种子,因此 nextGaussian()
总是 return 相同的值。问题是实际上这些值经常重复并且信号看起来不再像高斯:
Great NO-gaussian signal
我对此进行了更深入的研究,Random
class 的 setSeed(long seed)
的实现如下所示:
/**
* Sets the seed of this random number generator using a single
* {@code long} seed. The general contract of {@code setSeed} is
* that it alters the state of this random number generator object
* so as to be in exactly the same state as if it had just been
* created with the argument {@code seed} as a seed. The method
* {@code setSeed} is implemented by class {@code Random} by
* atomically updating the seed to
* <pre>{@code (seed ^ 0x5DEECE66DL) & ((1L << 48) - 1)}</pre>
* and clearing the {@code haveNextNextGaussian} flag used by {@link
* #nextGaussian}.
*
* <p>The implementation of {@code setSeed} by class {@code Random}
* happens to use only 48 bits of the given seed. In general, however,
* an overriding method may use all 64 bits of the {@code long}
* argument as a seed value.
*
* @param seed the initial seed
*/
synchronized public void setSeed(long seed) {
this.seed.set(initialScramble(seed));
haveNextNextGaussian = false;
}
private static long initialScramble(long seed) {
return (seed ^ multiplier) & mask;
}
private static final long multiplier = 0x5DEECE66DL;
private static final long mask = (1L << 48) - 1;
如您所见,方法 setSeed(long seed)
将种子设置为一些 initialScramble(seed)
,它实际上仅使用我的 64 位种子的 48 位。当我像那样炒我的种子时,我实际上经常得到相同的种子:
this.seed x newSeed this.seed^newSeed [y] initialScramble(y)
1590082351125 0.0 0 1590082351125 1614482495096
1590082351125 0.25 4598175219545276416 4598176809627627541 1614482495096
1590082351125 0.5 4602678819172646912 4602680409254998037 1614482495096
1590082351125 0.75 4604930618986332160 4604932209068683285 1614482495096
1590082351125 1.0 4607182418800017408 4607184008882368533 1614482495096
1590082351125 1.25 4608308318706860032 4608309908789211157 1614482495096
1590082351125 1.5 4609434218613702656 4609435808696053781 1614482495096
1590082351125 1.75 4610560118520545280 4610561708602896405 1614482495096
1590082351125 2.0 4611686018427387904 4611687608509739029 1614482495096
1590082351125 2.25 4612248968380809216 4612250558463160341 1614482495096
1590082351125 2.5 4612811918334230528 4612813508416581653 1614482495096
1590082351125 2.75 4613374868287651840 4613376458370002965 1614482495096
1590082351125 3.0 4613937818241073152 4613939408323424277 1614482495096
1590082351125 3.25 4614500768194494464 4614502358276845589 1614482495096
1590082351125 3.5 4615063718147915776 4615065308230266901 1614482495096
1590082351125 3.75 4615626668101337088 4615628258183688213 1614482495096
1590082351125 4.0 4616189618054758400 4616191208137109525 1614482495096
1590082351125 4.25 4616471093031469056 4616472683113820181 1614482495096
1590082351125 4.5 4616752568008179712 4616754158090530837 1614482495096
1590082351125 4.75 4617034042984890368 4617035633067241493 1614482495096
1590082351125 5.0 4617315517961601024 4617317108043952149 1614482495096
1590082351125 5.25 4617596992938311680 4617598583020662805 1614482495096
1590082351125 5.5 4617878467915022336 4617880057997373461 1614482495096
1590082351125 5.75 4618159942891732992 4618161532974084117 1614482495096
1590082351125 6.0 4618441417868443648 4618443007950794773 1614482495096
1590082351125 6.25 4618722892845154304 4618724482927505429 1614482495096
1590082351125 6.5 4619004367821864960 4619005957904216085 1614482495096
1590082351125 6.75 4619285842798575616 4619287432880926741 1614482495096
1590082351125 7.0 4619567317775286272 4619568907857637397 1614482495096
1590082351125 7.25 4619848792751996928 4619850382834348053 1614482495096
1590082351125 7.5 4620130267728707584 4620131857811058709 1614482495096
1590082351125 7.75 4620411742705418240 4620413332787769365 1614482495096
1590082351125 8.0 4620693217682128896 4620694807764480021 1614482495096
1590082351125 8.5 4620974692658839552 4620976282741190677 1614482495096
1590082351125 9.0 4621256167635550208 4621257757717901333 1614482495096
1590082351125 9.5 4621537642612260864 4621539232694611989 1614482495096
但是覆盖 Random
class 以摆脱 initialScramble
也没有帮助。我发现 Random.next()
方法也只使用 48 位种子,所以这可能是问题所在。
/**
* Generates the next pseudorandom number. Subclasses should
* override this, as this is used by all other methods.
*
* <p>The general contract of {@code next} is that it returns an
* {@code int} value and if the argument {@code bits} is between
* {@code 1} and {@code 32} (inclusive), then that many low-order
* bits of the returned value will be (approximately) independently
* chosen bit values, each of which is (approximately) equally
* likely to be {@code 0} or {@code 1}. The method {@code next} is
* implemented by class {@code Random} by atomically updating the seed to
* <pre>{@code (seed * 0x5DEECE66DL + 0xBL) & ((1L << 48) - 1)}</pre>
* and returning
* <pre>{@code (int)(seed >>> (48 - bits))}.</pre>
*
* This is a linear congruential pseudorandom number generator, as
* defined by D. H. Lehmer and described by Donald E. Knuth in
* <i>The Art of Computer Programming,</i> Volume 3:
* <i>Seminumerical Algorithms</i>, section 3.2.1.
*
* @param bits random bits
* @return the next pseudorandom value from this random number
* generator's sequence
* @since 1.1
*/
protected int next(int bits) {
long oldseed, nextseed;
AtomicLong seed = this.seed;
do {
oldseed = seed.get();
nextseed = (oldseed * multiplier + addend) & mask;
} while (!seed.compareAndSet(oldseed, nextseed));
return (int)(nextseed >>> (48 - bits));
}
private static final long multiplier = 0x5DEECE66DL;
private static final long addend = 0xBL;
private static final long mask = (1L << 48) - 1;
我的问题是:是否有使用 64 位种子生成下一个值的随机数生成器 classes?我找不到任何。也许您有不同的解决方案来使我的 value(Double x)
具有确定性?
我使用 java.security
包中的 SecureRandom
class 达到了预期的效果。
这个 post 的答案帮助了我:
工作实施:
import java.security.SecureRandom;
public class FormulaGaussianDistributionNoise extends Formula {
private Double stdEv;
private long basicSeed;
public FormulaGaussianDistributionNoise(Double stdEv) {
this.stdEv = stdEv;
this.basicSeed = System.currentTimeMillis();
}
@Override
public Double value(Double x) {
SecureRandom r = new SecureRandom();
long newSeed = Double.doubleToRawLongBits(x);
r.setSeed(this.basicSeed ^ newSeed);
return stdEv*r.nextGaussian();
}
}