大量の浮動小数点数のデータをRubyからバイナリ出力してJavaで読み込む

Rubyで処理して作成した大量の浮動小数点数のデータをバイナリでファイル出力して、それをJavaで読み込む方法を確認しました。

Rubyからはpackメソッドで書き出し、Javaでは DataInputStream で読み込みます。

JavaDataInputStream はハードウェアのバイトオーダーに依存せず、ビッグエンディアンで処理することになっています。従って、Rubyからの出力時もビッグエンディアンで書き出すことにします。

翌日追記:翌日にも似たことを書いてます。

書き出し側サンプルコード

sample1.rb

dataFilePath = "data.dat"

# 適当な12個の浮動小数点数を作成
arr = []
for i in 0..11
  th = Math::PI / 6 * i
  x = Math.sin(th)
  arr.push(x)
end

# 確認のため標準出力
arr.each do |x|
  puts(x)
end

# 倍精度浮動小数点数をビッグエンディアンでファイルに書き出し
buf = arr.pack("G12") # Gはビッグエンディアンの倍精度浮動小数点数の意味
File.open(dataFilePath, "w") do |fp|
  fp.write(buf)
end

実行します。

$ ruby sample1.rb
0.0
0.49999999999999994
0.8660254037844386
1.0
0.8660254037844387
0.5000000000000003
1.2246467991473532e-16
-0.4999999999999997
-0.8660254037844384
-1.0
-0.866025403784439
-0.5000000000000004

data.dat が生成されます。サイズを確認すると96バイト。倍精度浮動小数点数は8バイトでそれが12個ですので、あってます。

$ wc -c data.dat
96 data.dat

読み込み側サンプルコード

JavaといいつつサンプルコードはScalaです。Javaでもやりかたは同じです。

sample2.scala

import java.io.BufferedInputStream;
import java.io.DataInputStream;
import java.io.FileInputStream;

val dataFilePath = "data.dat";

// ファイルから読み込んで確認のため標準出力
val input = new DataInputStream(new BufferedInputStream(new FileInputStream(dataFilePath)));
(0 until 12).foreach { _ =>
  val x = input.readDouble();
  println(x);
}

実行します。

$ scala sample2.scala
0.0
0.49999999999999994
0.8660254037844386
1.0
0.8660254037844387
0.5000000000000003
1.2246467991473532E-16
-0.4999999999999997
-0.8660254037844384
-1.0
-0.866025403784439
-0.5000000000000004

RubyからJavaに受け渡しできていそうです。