类java.util.Random中的复制实例变量来创建相同的状态对象变量、实例、对象、状态

2023-09-11 02:32:52 作者:半生浮名

我采取一个模拟退火(SA)的算法,在这里我需要复制状态(例如:要记住,到目前为止最好的解决方案)。

我实现了一个复制方法,因为它鼓励使用Java的的clone()

SA是一种启发式算法,因此下一步采取随机确定。这是通过使用随机的对象,这是我要复制也做了。

虽然它不是通过算法该电源线,我想复制到具有完全相同的状态。 但是,这只是个案,如果我做一个复制直接对象创建之后,并使用相同的种子进行初始化。

但是,如果我在复制过程之前,对随机执行某些操作,内在状态的随机对象的变化(即种子)和复制的行为不同。

所以,我怎么能得到的一个实例的精确副本 java.util.Random中的

示例

 公共类国家
{
  私人最终随机ř;
  私人最终长的后裔。

  私有对象currentOperand;

  公州()
  {
    这个(System.nanoTime(),NULL);
  }

  私人州(long种子,对象currentOperand)
  {
    this.seed =种子;
    this.r =新的随机(种子);
    this.currentOperand = currentOperand;
  }

  公州复印件()
  {
    返回新的国家(种子,currentOperand);
  }

  公共无效doSth()
  {
    / *操作使用随机操作数* /
    currentOperand = r.nextInt(100);
  }

  公共无效重做()
  {
    //重做然后设置为null
    currentOperand = NULL;
  }

  / *为了完整性的缘故......因为它是模拟退火* /
  公众诠释computeEnergy(){返回0; }
}
 

解决方案

我想出了一个自己的解决方案。它主要覆盖下一个()随机(因为所有其他方法依赖于那一个),以及一些其他的东西,保持一致性。

它提供了这种方法的调用实例的精确副本(是否有意义做一个随机实例副本是另一个话题... ^^)。它应该完全表现得像其超一流的,至少这是我的本意。

随意添加您的想法!

由于其他问题是有关获取种子:人们可以在 getSeed()的方法很容易地添加到我的解决方案。或 getInitialSeed() getCurrentSeed()

  / *,因为实现此接口的类有界参数类型
 *只应该能够创建相同类型(或子类型)的副本。
 * /
公共接口拷贝的<吨延伸可复制< T>>
{
  公共牛逼副本();
}
 
学习Java需吃透这些基本概念

 公共类CopyableRandom扩展随机实现可复制< CopyableRandom>
{
  私人最终的AtomicLong种子=新的AtomicLong(0L);

  私人最终静态长乘数= 0x5DEECE66DL;
  私人最终静态长加数= 0xBL;
  私人最终静态长面膜=(1L<< 48) -  1;

  公共CopyableRandom(){此(++ seedUniquifier + System.nanoTime()); }
  私有静态挥发长seedUniquifier = 8682522807148012L;

  公共CopyableRandom(long种子){this.seed.set((种子^乘数)及面罩); }

  / *的超code复制,你可以播种种子的变化* /
  @覆盖
  保护INT下一个(INT位)
  {
    长oldseed,nextseed;
    AtomicLong的seed_ = this.seed;
    做
    {
      oldseed = seed_.get();
      nextseed =(oldseed *乘数+加数)及面具;
    }而(seed_.compareAndSet(oldseed,nextseed)!);
    返程(INT)(nextseed>>>(48  - 位));
  }

  必要prevent改变种子在构造函数中做/ * * /
  @覆盖
  公共CopyableRandom副本(){返回新CopyableRandom((seed.get()^乘数)及面罩); }

  公共静态无效的主要(字串[] args)
  {
    CopyableRandom CR =新CopyableRandom();

    / *改变CR *实习生状态/
    的for(int i = 0;我小于10;我++)
      的System.out.println(cr.nextInt(50));

    随机副本= cr.copy()

    的System.out.println(\ NTEST:INTEGER的\ n);
    的for(int i = 0;我小于10;我++)
      的System.out.println(CR \ T =+ cr.nextInt(50)+\ n复制\ T =+ copy.nextInt(50)+\ N);

    随机anotherCopy =(副本的instanceof CopyableRandom)? ((CopyableRandom)复印件).copy():新的随机();
    的System.out.println(\ NTEST:DOUBLE \ N);
    的for(int i = 0;我小于10;我++)
      的System.out.println(CR \ T =+ cr.nextDouble()+\ nA_COPY \ T =+ anotherCopy.nextDouble()+\ N);
  }
}
 

和这里的主要方法的输出:

  19
23
26
37
41
34
17
28
29
6

测试: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


测试:双

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
 

我也有一个测试,我比较CopyableRandom对随机。它得到了相同的结果。

  long种子= System.nanoTime();

随机CR =新CopyableRandom(种子);
随机CMP =新的随机(种子);
 

I'm implementing a simulated annealing (SA) algorithm, where I need to copy states (e. g. to remember best solution so far).

I implemented a copy method, since it's discouraged to use java's clone().

SA is a heuristic algorithm, so the next step to take is determined randomly. This is done by using a Random object, which I want to copy too.

Although it's not requiered by the algorithm, I want the copy to have exactly the same state. But this is only the case, if I make a 'copy' direct after object creation and initialize it with the same seed.

But if I perform some operations on the random before the copy process , the intrinsic state (i. e. the seed) of theRandom object changes and the copy behaves differently.

So how can I get an exact copy of an instance of java.util.Random?

EXAMPLE

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; }
}

解决方案

I came up with an own solution. It mainly overrides next() in Random (since all other methods rely on that one), and some other stuff to keep the consistency.

It delivers an exact copy of the instance this method was invoked on (whether it makes sense to make a copy of a random instance is another topic...^^). It should exactly behave like its super class, at least that was my intention.

Feel free to add your thoughts!

Since other questions were about getting the seed: One could easily add a getSeed() method to my solution. Or getInitialSeed(), getCurrentSeed().

/* 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();
}

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("\nTEST: INTEGER\n");
    for (int i = 0; i < 10; i++)
      System.out.println("CR\t= " + cr.nextInt(50) + "\nCOPY\t= " + copy.nextInt(50) + "\n");

    Random anotherCopy = (copy instanceof CopyableRandom) ? ((CopyableRandom) copy).copy() : new Random();
    System.out.println("\nTEST: DOUBLE\n");
    for (int i = 0; i < 10; i++)
      System.out.println("CR\t= " + cr.nextDouble() + "\nA_COPY\t= " + anotherCopy.nextDouble() + "\n");
  }
}

And here the output of the main method:

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

I also had a test where I compared CopyableRandom against Random. It yielded the same results.

long seed = System.nanoTime();

Random cr  = new CopyableRandom(seed);
Random cmp = new Random(seed);