给出
Ruby Float值,例如,
f = 12.125
我想结束一个包含浮点数符号(1位),指数(11位)和分数(52位)的3元素数组. (Ruby的浮点数是IEEE 754双精度64位表示.)
最好的方法是什么?位级操作似乎不是Ruby的强项.
请注意,我想要的是比特,而不是它们对应的数值.例如,为浮点值1.0得到[0,-127,1]不是我想要的 – 我想要字符串形式的实际位或等效表示,如[“0”,“0ff” “,”000 0000 0000“].
解决方法
位数据可以通过Arrays包公开,因为Float不在内部提供功能.
str = [12.125].pack('D').bytes.reverse.map{|n| "%08b" %n }.join => "0100000000101000010000000000000000000000000000000000000000000000" [ str[0],str[1..11],str[12..63] ] => ["0","10000000010","1000010000000000000000000000000000000000000000000000"]
这有点’围绕房子’从字符串表示中拉出来.我确信有一种更有效的方法从原始字节中提取数据……
编辑位级操作调整了我的兴趣所以我有一个戳.要在Ruby中使用这些操作,你需要有一个Integer,因此float需要更多的解包才能转换为64位int. big endian / ieee754记录的表示非常简单.小端表示我不太确定.这有点奇怪,因为你没有使用11位指数和52位尾数的完整字节边界.将这些位拉出并交换它们以获得类似于小端的东西变得非常繁琐,并且不确定它是否正确,因为我没有看到任何对布局的引用.所以64位值是小端,我不太确定64bit值的组件如何适用于其他地方,直到将它们存储在其他地方,如尾数的16位int.
作为来自小> 1的11位值的示例.我正在做的事情是将最重要的字节3左移到前面,然后用最不重要的3位移位.
v = 0x4F2 ((v & 0xFF) << 3) | ( v >> 8 ))
无论如何,这是有用的.
class Float Float::LITTLE_ENDIAN = [1.0].pack("E") == [1.0].pack("D") # Returns a sign,exponent and mantissa as integers def ieee745_binary64 # Build a big end int representation so we can use bit operations tb = [self].pack('D').unpack('Q>').first # Check what we are if Float::LITTLE_ENDIAN ieee745_binary64_little_endian tb else ieee745_binary64_big_endian tb end end # Force a little end calc def ieee745_binary64_little ieee745_binary64_little_endian [self].pack('E').unpack('Q>').first end # Force a big end calc def ieee745_binary64_big ieee745_binary64_big_endian [self].pack('G').unpack('Q>').first end # Little def ieee745_binary64_little_endian big_end_int #puts "big #{big_end_int.to_s(2)}" sign = ( big_end_int & 0x80 ) >> 7 exp_a = ( big_end_int & 0x7F ) << 1 # get the last 7 bits,make it more significant exp_b = ( big_end_int & 0x8000 ) >> 15 # get the 9th bit,to fill the sign gap exp_c = ( big_end_int & 0x7000 ) >> 4 # get the 10-12th bit to stick on the front exponent = exp_a | exp_b | exp_c mant_a = ( big_end_int & 0xFFFFFFFFFFFF0000 ) >> 12 # F000 was taken above mant_b = ( big_end_int & 0x0000000000000F00 ) >> 8 # F00 was left over mantissa = mant_a | mant_b [ sign,exponent,mantissa ] end # Big def ieee745_binary64_big_endian big_end_int sign = ( big_end_int & 0x8000000000000000 ) >> 63 exponent = ( big_end_int & 0x7FF0000000000000 ) >> 52 mantissa = ( big_end_int & 0x000FFFFFFFFFFFFF ) >> 0 [ sign,mantissa ] end end
和测试……
def printer val,vals printf "%-15s sign|%01b|\n",val,vals[0] printf " hex e|%3x| m|%013x|\n",vals[1],vals[2] printf " bin e|%011b| m|%052b|\n\n",vals[2] end floats = [ 12.125,-12.125,1.0/3,-1.0/3,1.0,-1.0,1.131313131313,-1.131313131313 ] floats.each do |v| printer v,v.ieee745_binary64 printer v,v.ieee745_binary64_big end
TIL我的大脑是大端!你会注意到正在使用的int都是big endian.我在另一个方向转移失败了.
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。