I've been looking all over to find if there is a method that converts a float number(ex: 123.456) into a binary32. I've found a lot of solutions that go from binary32 to float, but not vice versa.
3 Answers
The "funky" y\xE9\xF6B value is the actual binary value represented as a string.
If you want to convert that to a string representation of the binary value:
"%032b" % [123.456].pack('e').reverse.each_char.inject(0) { |sum,c| sum = (sum << 8) + c.ord }
=> "01000010111101101110100101111001"
So breaking it down, this gives you the "funky" binary value packed into a string:
[123.456].pack('e')
The rest converts the "binary string" into a an integer (the appropriate binary digits of the float "casted" to integer):
reverse # Handles the endian-ness
each_char # Grabs each character in the reversed string
inject # Concatenates the chars converted directly to binary
And then the "%032b" % displays it as a binary string so you can look at it.
EDIT: As @looby astutely observed, 'g' can be used in pack instead of 'e' to avoid the reverse step, shortening this solution to: [123.456].pack('g').each_char.inject(0) { |sum,c| sum = (sum << 8) + c.ord } (and use "%032b" %... as before in order to display it).
Comments
The above is awesome but I have a few simplifications:
[123.456].pack('g').bytes.map{|n| "%08b" % n}.join
Using the 'g' flag instead of 'e' avoids having to reverse the output from pack.
The bytes method does the same thing as calling .ord on each character does.
Then instead of taking the 4 integers and doing the sum/bit shift you map each to an 8 character binary string and join them together.
1 Comment
g option is a great catch and does get rid of the reverse. However, the solution you're showing doesn't have, as an intermediate value, the entire binary value I thought @TakaGoto desired (versus just the ASCII binary string). that's what the inject does in the solution I proposed. So the solution that outputs binary would be [123.456].pack('g').each_char.inject(0) { |sum,c| sum = (sum << 8) + c.ord }.You should use String#unpack and Array#pack :
[123.456].pack('g').unpack('B*').first
#=> "01000010111101101110100101111001"
packandunpackare useful for converting between binary formats. It doesn't matter that everything's an object, even floating point numbers. To reverse the process of anunpackyou usually just callpackwith the same specification.[123.456].pack('e')? Exactly what format of output are you looking for?