Copy instance variable of type java.util.Random to create object in same state
我正在实现一个模拟退火(SA)算法,在这里我需要复制状态(例如,要记住迄今为止最好的解决方案)。
我实现了一个复制方法,因为它不鼓励使用Java的EDCOX1 0。
SA是一种启发式算法,因此要采取的下一步是随机确定的。这是通过使用一个
虽然算法没有要求它,但我希望副本具有完全相同的状态。但是,如果我在对象创建之后直接创建一个"拷贝"并用相同的种子初始化它,情况就只有这样了。
但是,如果在复制过程之前随机执行一些操作,那么the
那么,我怎样才能得到一个
例子
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 | public class State { private final Random r; private final long seed; private Object currentOperand; public State() { this(System.nanoTime(), null); } private State(long seed, Object currentOperand) { this.seed = seed; this.r = new Random(seed); this.currentOperand = currentOperand; } public State copy() { return new State(seed, currentOperand); } public void doSth() { /* operation with random operand */ currentOperand = r.nextInt(100); } public void redo() { // redo then set to null currentOperand = null; } /* for completeness' sake... since it's simulated annealing */ public int computeEnergy() { return 0; } } |
我知道这是一个老问题,有一个公认的答案,但我在寻找答案的时候遇到了这个问题,最后我采取了不同的方法。
看到Mike上面提到的
1 2 3 4 5 6 7 8 9 10 11 12 13 | /** * Uses serialization to create a copy of the given Random, needed for * repeatability in some tests. */ public static Random cloneRandom(Random src) throws Exception { ByteArrayOutputStream bo = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(bo); oos.writeObject(src); oos.close(); ObjectInputStream ois = new ObjectInputStream( new ByteArrayInputStream(bo.toByteArray())); return (Random)(ois.readObject()); } |
。
它的性能可能不如Mike的
(我有一个现有的单元测试,从一个已知种子的
我想出了自己的解决办法。它主要覆盖
它提供调用此方法的实例的精确副本(制作随机实例的副本是否有意义是另一个主题…^^)。它应该表现得像它的超级班级,至少这是我的意图。
请随意添加您的想法!
因为其他的问题是如何获得种子:我们可以很容易地在我的解决方案中添加一个
1 2 3 4 5 6 7 | /* Bounded parameter type since a class that implements this interface * should only be able to create copies of the same type (or a subtype). */ public interface Copyable<T extends Copyable<T>> { public T copy(); } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 | public class CopyableRandom extends Random implements Copyable<CopyableRandom> { private final AtomicLong seed = new AtomicLong(0L); private final static long multiplier = 0x5DEECE66DL; private final static long addend = 0xBL; private final static long mask = (1L << 48) - 1; public CopyableRandom() { this(++seedUniquifier + System.nanoTime()); } private static volatile long seedUniquifier = 8682522807148012L; public CopyableRandom(long seed) { this.seed.set((seed ^ multiplier) & mask); } /* copy of superclasses code, as you can seed the seed changes */ @Override 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)); } /* necessary to prevent changes to seed that are made in constructor */ @Override public CopyableRandom copy() { return new CopyableRandom((seed.get() ^ multiplier) & mask); } public static void main(String[] args) { CopyableRandom cr = new CopyableRandom(); /* changes intern state of cr */ for (int i = 0; i < 10; i++) System.out.println(cr.nextInt(50)); Random copy = cr.copy() System.out.println(" TEST: INTEGER "); for (int i = 0; i < 10; i++) System.out.println("CR\t=" + cr.nextInt(50) +" COPY\t=" + copy.nextInt(50) +" "); Random anotherCopy = (copy instanceof CopyableRandom) ? ((CopyableRandom) copy).copy() : new Random(); System.out.println(" TEST: DOUBLE "); for (int i = 0; i < 10; i++) System.out.println("CR\t=" + cr.nextDouble() +" A_COPY\t=" + anotherCopy.nextDouble() +" "); } } |
。
主要方法的输出如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 | 19 23 26 37 41 34 17 28 29 6 TEST: INTEGER CR = 3 COPY = 3 CR = 18 COPY = 18 CR = 25 COPY = 25 CR = 9 COPY = 9 CR = 24 COPY = 24 CR = 5 COPY = 5 CR = 15 COPY = 15 CR = 5 COPY = 5 CR = 30 COPY = 30 CR = 26 COPY = 26 TEST: DOUBLE CR = 0.7161924830704971 A_COPY = 0.7161924830704971 CR = 0.06333509362539957 A_COPY = 0.06333509362539957 CR = 0.6340753697524675 A_COPY = 0.6340753697524675 CR = 0.13546677259518425 A_COPY = 0.13546677259518425 CR = 0.37133033932410586 A_COPY = 0.37133033932410586 CR = 0.796277965335522 A_COPY = 0.796277965335522 CR = 0.8610310118615391 A_COPY = 0.8610310118615391 CR = 0.793617231340077 A_COPY = 0.793617231340077 CR = 0.3454111197621874 A_COPY = 0.3454111197621874 CR = 0.25314618087856255 A_COPY = 0.25314618087856255 |
我还做了一个测试,我比较了可复制随机和随机。结果是一样的。
1 2 3 4 |
。
我认为你应该在你的
A pseudo random number generator can be started from an arbitrary starting state using a seed state. It will always produce the same sequence thereafter when initialized with that state
号
让我先给你解释一下样品:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
结果是:
1 2 3 4 5 6 7 8 9 10 | First random -1170105035 First random 234785527 First random -1360544799 First random 205897768 First random 1325939940 Second random -1170105035 Second random 234785527 Second random -1360544799 Second random 205897768 Second random 1325939940 |
号
由于两个随机实例都以相同的种子开始,所以我总是得到相同的数字序列。
因此,在复制对象时,您应该将新的
完成此操作后,在副本上调用
为了更好地理解伪随机数生成器(prng),也称为确定性随机位生成器(drbg),您可以查看这篇维基百科文章。