Как получить битовое представление чисел с плавающей запятой в Ruby? [Дубликат]

При запуске response-native. Если вы установили 23.0.3 и запрашиваете 23.0.1 просто в своем каталоге проектов приложений. Откройте anroid/app/build.gradle и измените buildToolsVersion "23.0.3"

5
задан John Feminella 10 September 2014 в 17:42
поделиться

2 ответа

Битовые данные могут быть выставлены через Arrays pack, так как 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"]

Это немного «вокруг дома», чтобы вытащить его из строкового представления. Я уверен, что есть более эффективный способ вытащить данные из оригинала bytes ...


Изменить Манипуляция на уровне бит изменила мой интерес, так что я пошевелился. Чтобы использовать операции в Ruby, вам необходимо иметь Integer, поэтому для float требуется еще unpack ing для преобразования в 64-битный int. Документальное представление большого конца / ieee754 довольно тривиально. Маленькое представление конца я не так уверен. Это немного странно, так как вы не на полных байтовых границах с 11-разрядным показателем и 52-битной мантиссой. Это становится нерешительным, чтобы вытащить биты и поменять их на то, чтобы получить то, что похоже на маленькое endian, и не уверен, правильно ли это, потому что я не видел никакой ссылки на макет. Таким образом, 64-битное значение мало endian, я не слишком уверен, как это относится к компонентам 64-битного значения, пока вы не сохраните их в другом месте, например, 16 бит int для мантиссы.

В качестве примера для 11-битного значения от little> large, я делал это, чтобы перенести самый старший байт слева 3 на фронт, затем на OR с наименее значимыми 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, exponent, 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[1], 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 мой мозг большой эндиан! Вы заметите, что ints, с которыми работает, имеют большой эндиант. Я потерпел неудачу, немного переместившись в другую сторону.

4
ответ дан Matt 24 August 2018 в 21:42
поделиться

Используйте frexp из модуля Math. Из doc :

fraction, exponent = Math.frexp(1234)   #=> [0.6025390625, 11]
fraction * 2**exponent                  #=> 1234.0

Знаковый бит легко найти сам по себе.

3
ответ дан Patrice Gahide 24 August 2018 в 21:42
поделиться
Другие вопросы по тегам:

Похожие вопросы: