我正在处理中制作动画。我正在使用随机点,我需要为立体视觉执行两次代码。我的代码中有很多随机变量,所以我应该将它保存在某个地方以供第二次运行,或者在我运行程序的任何时候重新生成相同的“随机”数字字符串。(如这里所说:http: //www.coderanch.com/t/372076/java/java/save-random-numbers)
这种方法可行吗?如何?如果我将数字保存在 txt 文件中然后读取它,我的程序会运行得更慢吗?最好的方法是什么?
谢谢。
我正在处理中制作动画。我正在使用随机点,我需要为立体视觉执行两次代码。我的代码中有很多随机变量,所以我应该将它保存在某个地方以供第二次运行,或者在我运行程序的任何时候重新生成相同的“随机”数字字符串。(如这里所说:http: //www.coderanch.com/t/372076/java/java/save-random-numbers)
这种方法可行吗?如何?如果我将数字保存在 txt 文件中然后读取它,我的程序会运行得更慢吗?最好的方法是什么?
谢谢。
如果您只需要能够在有限的时间内生成相同的序列,那么使用相同值的随机数生成器来生成相同的序列很可能是最简单和最快的方法。只要确保任何并行线程总是以相同的顺序请求它们的伪随机数,否则你会遇到麻烦。
请注意,如果您更新 Java VM 甚至运行补丁,afaik 并不能保证相同的序列,所以如果您想要长时间存储您的序列,或者希望能够在您的 Java 程序之外使用它,您需要将其保存到文件中。
这是一个示例:
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;
}
嗯,有几种方法可以解决这个问题。其中之一是将随机变量作为输入保存到文件中,并将该文件名作为参数传递给您的程序。
您可以通过以下两种方式之一来做到这一点,第一种是使用 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());
}
} }
另一种方法是使用 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);
}
}
另一个不涉及存储数据的问题的替代解决方案是为任何为您提供随机值的函数创建一个惰性生成器,并且每次都提供相同的种子。这样,您根本不必存储任何数据。
但是,这仍然比将对象序列化到磁盘并再次加载它要慢得多(我认为)。(当然,这是一个非常主观的陈述,但我不会列举不正确的情况)。这样做的好处是它根本不需要任何类型的存储。
您可能没有想到的另一种方法是围绕您的生成器函数创建一个包装器来记忆输出 - 这意味着之前已经生成的数据将从内存中检索并且不必再次生成如果相同的输入是正确的。你可以在这里看到一些资源:Memoization source
记忆你的函数调用背后的想法是你可以节省时间而不需要持久化到磁盘上。如果一遍又一遍地生成相同的值,这是理想的。当然,对于一组随机点,如果每个点都是唯一的,这将不会很好地工作,但请记住这一点。
考虑到我在这篇文章中描述的所有先前策略可以组合在一起的方式时,真正有趣的部分出现了。
设置一个 Memoizer 类会很有趣,如2的第二页中所述,然后在该类中实现 java.io.Serialization。之后,您可以在 memoizer 类中添加方法save(String fileName)
和load(String fileName)
使序列化和反序列化更容易,这样您就可以持久化用于 memoize 函数的缓存。很有用。
不管怎样,够了就够了。简而言之,只需使用相同的种子值,并即时生成相同的点对。