ルビーにjavafloatToRawIntBits/ intBitsToFloat(またはdoubleToRawLongBits / longBitsToDouble)に相当するものはありますか?
1 に答える
floatToRawIntBits
関数などの単純な代替手段はありませんが、基になるビットを使用Array#pack
して取得することができます。String#unpack
bytes = [3.14].pack('D').each_byte.map { |byte| byte.ord.to_s(2) }
=> ["11111", "10000101", "11101011", "1010001", "10111000", "11110", "1001",
"1000000"]
bytes.map { |byte| byte.to_i(2).chr }.join.unpack('D')
=> [3.14]
ここで何が起こっているのかというと、配列をパックしているということです(単一の要素を持つ配列を使用しているので、実際には要素だけ、つまり3.14をパックしています)。各バイトをASCII文字で表す文字列にパックします。次に、文字列の各バイトを取得し(ASCII文字を使用しているため、各文字と同じです)、String#ord
文字のを取得します。Ruby 1.9では、文字は単一要素の文字String#ord
列であり、単一文字列の序数を返します。を引数として使用するInteger#to_s
と2
、序数のバイナリ表現が得られます。これは、検索対象であり、floatのすべてのバイトのシングルビットです。
に渡すということは、配列の要素をネイティブマシン形式でdoubleとして表すバイト(取得するのは文字列内の文字ですが、メソッドは実際にはバイトの観点から考えるのに十分な低レベルです)が必要であること'D'
を意味することに注意してください。Array#pack
バイトは単なるバイトであるため、数値を取得するときに同じパラメータを渡すことが重要String#unpack
です。メソッドはエンディアンやデータ型について何も知りません。
詳細については、 Array#packおよびString#unpackのドキュメントを確認してください(特に正しいバイト順序に関して)。
編集:文字列形式で基になるビットを取得することもできます:
bytes = [3.14].pack('D').each_byte.
map { |byte| ('0' * 7 + byte.ord.to_s(2))[-8,8] }
=> ["00011111", "10000101", "11101011", "01010001", "10111000", "00011110",
"00001001", "01000000"]
bits = bytes.join(' ')
=> "00011111 10000101 11101011 01010001 10111000 00011110 00001001 01000000"
bits.gsub(' ', '')
=> "0001111110000101111010110101000110111000000111100000100101000000"
bits.split(' ').map { |byte| byte.to_i(2).chr }.join.unpack('D')
=> [3.14]
編集2:ファイルから文字列を読み取った場合は、次のコマンドを試すことができます。
# You'll probably read each_line from a file, and get a bunch of strings like:
from_file = 0001111110000101111010110101000110111000000111100000100101000000
# If you've no byte separator in your file, the trick is to scan the string
# for 8 digits groups, that is bytes:
bytes = from_file.scan(/\d{8}/)
=>["00011111", "10000101", "11101011", "01010001", "10111000", "00011110",
"00001001", "01000000"]
# Then, we can go on unpacking:
bytes.map { |byte| byte.to_i(2).chr }.join.unpack('D')
=> [3.14]