0

Processingでアニメーションをやっています。ランダム ポイントを使用しており、ステレオ ビジョンのためにコードを 2 回実行する必要があります。私のコードにはランダム変数がたくさんあるので、2 回目の実行のためにどこかに保存するか、プログラムを実行するたびに「乱数」の同じ文字列を再生成する必要があります。(ここで述べたように: http://www.coderanch.com/t/372076/java/java/save-random-numbers )

このアプローチは可能ですか?どのように?数値を txt ファイルに保存してから読み取ると、プログラムの実行速度が遅くなりますか? これを行う最善の方法は何ですか?

ありがとう。

4

3 に答える 3

2

限られた時間で同じシーケンスを生成できるようにする必要がある場合は、同じシーケンスを生成するために同じ値で乱数ジェネレーターをシードすることが、最も簡単で最速の方法である可能性があります。並列スレッドが常に同じシーケンスで疑似乱数を要求することを確認してください。そうしないと、問題が発生します。

ただし、Java VMを更新したり、パッチを実行したりしても、同じシーケンスを保証するものは何もないことに注意してください。したがって、シーケンスを長期間保存したい場合、またはJavaプログラムの外部で使用できるようにしたい場合は、ファイルに保存します。

于 2012-10-07T06:20:20.203 に答える
1

サンプル例を次に示します。

public static void writeRandomDoublesToFile(String filePath, int numbersCount) throws IOException
{
    FileOutputStream fos = new FileOutputStream(new File(filePath));
    BufferedOutputStream bos = new BufferedOutputStream(fos);
    DataOutputStream dos = new DataOutputStream(bos);

    dos.writeInt(numbersCount);
    for(int i = 0; i < numbersCount; i++) dos.writeDouble(Math.random());
}

public static double[] readRandomDoublesFromFile(String filePath) throws IOException
{
    FileInputStream fis = new FileInputStream(new File(filePath));
    BufferedInputStream bis = new BufferedInputStream(fis);
    DataInputStream dis = new DataInputStream(bis);

    int numbersCount = dis.readInt();
    double[] result = new double[numbersCount];

    for(int i = 0; i < numbersCount; i++) result[i] = dis.readDouble();
    return result;
}
于 2012-10-07T06:19:52.887 に答える
1

さて、この問題に取り組むにはいくつかの方法があります。それらの 1 つは、確率変数を入力としてファイルに保存し、そのファイル名をパラメーターとしてプログラムに渡すことです。

そして、2 つの方法のいずれかでそれを行うことができます。最初の方法は、args[] パラメーターを使用することです。

import java.io.*;
import java.util.*;
public class bla {
public static void main(String[] args) {
    // You'd need to put some verification code here to make
    // sure that input was actually sent to the program. 
    Scanner in = new Scanner(new File(args[1]));
    while(in.hasNextLine()) {
        System.out.println(in.nextLine());
    }
} }

もう 1 つの方法は、Scanner を使用してコンソール入力から読み取ることです。これはすべて上記と同じコードですが、その上のScanner in = new Scanner(new File(args[1]));すべての検証コードではありません。に置き換えますScanner in = new Scanner(System.in)が、それはファイルをロードするだけです。

これらのポイントを生成するプロセスは、次の方法で実行できます。

import java.util.*;
import java.io.*;
public class generator {
    public static void main(String[] args) {
          // You'd get some user input (or not) here
          // that would ask for the file to save to,
          // and that can be done by either using the
          // scanner class like the input example above,
          // or by using args, but in this case we'll
          // just say:
          String fileName = "somefile.txt";
          FileWriter fstream = new FileWriter(fileName);
          BufferedWriter out = new BufferedWriter(fstream);
          out.write("Stuff");
          out.close();
    }
}

これらのソリューションはどちらも、Java でファイルを読み書きするための簡単な方法です。ただし、これらのソリューションのいずれかをデプロイした場合でも、何らかのデータ解析が必要になります。

私だったら、非効率な方法で情報を解析して再解析するのではなく、オブジェクトのシリアル化を行い、既に生成したデータ構造のバイナリ コピーをディスクに保存します。(通常、テキスト ファイルを使用すると、より多くのディスク領域が必要になります。)

そして、これを行う方法は次のとおりです (ここでは、既に記述されているコードを再利用し、途中でコメントします)ソース

データを保持するラッパー クラスを宣言します (ちなみに、常にこれを行う必要はありません)。

 public class Employee implements java.io.Serializable
{
   public String name;
   public String address;
   public int transient SSN;
   public int number;
   public void mailCheck()
   {
      System.out.println("Mailing a check to " + name
                           + " " + address);
   }
}

そして、シリアル化するには:

import java.io.*;

public class SerializeDemo
{
   public static void main(String [] args)
   {
      Employee e = new Employee();
      e.name = "Reyan Ali";
      e.address = "Phokka Kuan, Ambehta Peer";
      e.SSN = 11122333;
      e.number = 101;
      try
      {
         FileOutputStream fileOut =
         new FileOutputStream("employee.ser");
         ObjectOutputStream out =
                            new ObjectOutputStream(fileOut);
         out.writeObject(e);
         out.close();
          fileOut.close();
      }catch(IOException i)
      {
          i.printStackTrace();
      }
   }
}

次に、逆シリアル化します。

import java.io.*;
   public class DeserializeDemo
   {
      public static void main(String [] args)
      {
         Employee e = null;
         try
         {
            FileInputStream fileIn =
                          new FileInputStream("employee.ser");
            ObjectInputStream in = new ObjectInputStream(fileIn);
            e = (Employee) in.readObject();
            in.close();
            fileIn.close();
        }catch(IOException i)
        {
            i.printStackTrace();
            return;
        }catch(ClassNotFoundException c)
        {
            System.out.println(.Employee class not found.);
            c.printStackTrace();
            return;
        }
        System.out.println("Deserialized Employee...");
        System.out.println("Name: " + e.name);
        System.out.println("Address: " + e.address);
        System.out.println("SSN: " + e.SSN);
        System.out.println("Number: " + e.number);
    }
}

データの保存を伴わない問題の別の代替ソリューションは、ランダム値を提供する関数の遅延ジェネレーターを作成し、毎回同じシードを提供することです。そうすれば、データをまったく保存する必要はありません。

ただし、オブジェクトをディスクにシリアル化して再度ロードするよりも、まだかなり時間がかかります (私はそう思います)。(もちろん、これは非常に主観的な意見ですが、そうでない場合を列挙するつもりはありません)。これを行う利点は、いかなる種類のストレージもまったく必要としないことです。

おそらく考えもしなかったかもしれない別の方法は、出力を記憶するジェネレーター関数の周りにラッパーを作成することです。つまり、以前に生成されたデータはメモリから取得され、次の場合に再度生成する必要はありません。同じ入力が真です。ここでいくつかのリソースを見ることができます:メモ化ソース

関数呼び出しをメモ化する背後にある考え方は、ディスクに永続化せずに時間を節約することです。これは、同じ値が何度も何度も生成される場合に理想的です。もちろん、ランダムなポイントのセットの場合、すべてのポイントが一意である場合、これはうまく機能しませんが、それは頭の片隅に置いておいてください。

この投稿で説明したこれまでのすべての戦略を組み合わせる方法を考えると、非常に興味深い部分が生まれます。

2 の2ページ目で説明したように、Memoizer クラスをセットアップし、そのクラスに java.io.Serialization を実装すると興味深いでしょう。その後、シリアライゼーションとデシリアライゼーションを容易にするメソッドsave(String fileName)をmemoizer クラスに追加できるため、関数の memoize に使用されるキャッシュを永続化できます。load(String fileName)非常に便利。

とにかく、十分です。つまり、同じシード値を使用して、同じポイント ペアをオンザフライで生成するだけです。

于 2012-10-07T06:55:15.833 に答える