negative numbers and binary formats

Discussion in 'Ruby' started by Paul, Sep 22, 2004.

  1. Paul

    Paul Guest

    Im trying to take a negative integer value, convert it to its binary
    equivalent, and save its hex value

    -7 -> 1111 1001 -> F9


    I was hoping to use sprintf, but:

    irb(main):017:0> b = sprintf("%4b" , a)
    => "..1001"
    irb(main):018:0>

    The .. that appear break any further processing. So my questions are:

    Why the dots, and what are they?
    How do I do what Im trying to do - given my -7 in the example may be a
    1 byte, 2 byte or 4 byte value. ( Im sure its some magic with
    pack....)

    Thanks

    Paul
     
    Paul, Sep 22, 2004
    #1
    1. Advertisements

  2. Paul wrote:

    Moin!
    Does this help?

    irb(main):032:0> [-7].pack("c").unpack("H*").first
    => "f9"
    Regards,
    Florian Gross
     
    Florian Gross, Sep 22, 2004
    #2
    1. Advertisements

  3. Paul

    Ara.T.Howard Guest

    you have a couple of options:

    the [] method of Fixnum returns the bit:

    harp:~ > cat a.rb
    class Fixnum
    def to_bin
    packed = [self].pack 'N'
    n_bytes = packed.size
    n_bits = n_bytes * 8
    s = ''
    n_bits.times{|bit| s << self[n_bits - bit].to_s}
    s
    end
    end

    p 42.to_bin
    p -7.to_bin

    harp:~ > ruby a.rb
    "00000000000000000000000000010101"
    "11111111111111111111111111111100"

    but perhaps only printf will suffice?

    irb(main):003:0> printf "%32.32b", -7
    11111111111111111111111111111001=> nil

    irb(main):009:0> printf "%4.4o", -7
    7771=> nil

    but i'm not exactly sure where you are headed with this.

    the '...' above is just showing you the extension of the sign bit.

    -a
    --
    ===============================================================================
    | EMAIL :: Ara [dot] T [dot] Howard [at] noaa [dot] gov
    | PHONE :: 303.497.6469
    | A flower falls, even though we love it;
    | and a weed grows, even though we do not love it.
    | --Dogen
    ===============================================================================
     
    Ara.T.Howard, Sep 22, 2004
    #3
  4. Paul

    Markus Guest

    So, are you wanting it in binary or in hex?

    Assuming (from your context) that you're wanting it in hexadecimal
    (base 16) instead of binary (base 2) you could write:

    (a & 0xff).to_s(16)

    for one byte values,

    (a & 0xffff).to_s(16)

    for two byte values, etc.

    If you are wanting it in binary you would instead write:

    (a & 0xff).to_s(2)
    If you don't know at code-time how large the value will be, but can
    determine it at run-time, you could write:

    (a & (((1 << (8*n)) - 1)).to_s(16)

    where n is the number of bytes in a and the expression involving a makes
    a mask if the proper size. Alternatively, you could mess with the
    result instead, by writing:

    ("0"*8 + (a & 0xffffffff).to_s(16))[-n*2..-1]

    which pads the result with zeros and then takes the least significant 2n
    hexits (i.e, the bottom n bytes).

    -- Markus
     
    Markus, Sep 22, 2004
    #4
  5. Paul

    Mark Hubbart Guest

    well, if all you need is the hex part, here you go:

    class Integer
    def internal_hex
    # choose a packing strategy
    case self
    when (-128..127) # char
    [self].pack('c').unpack('C').first.to_s 16
    when (-32768..32767) # short
    [self].pack('s').unpack('S').first.to_s 16
    when (-2147483648..2147483647) # long
    [self].pack('l').unpack('L').first.to_s 16
    else
    "too big!" # :)
    end
    end
    end

    -7.internal_hex #=>"f9"


    the hex string will be in big-endian (network) byte-order; that's the
    way to_s(16) does it.

    cheers
    Mark
     
    Mark Hubbart, Sep 22, 2004
    #5
  6. Hm...

    10:25:20 [source]: irb
    irb(main):001:0> printf "%32.32b", -7
    00000000000000000000000000001001=> nil
    irb(main):002:0> RUBY_VERSION
    => "1.8.1"

    robert
     
    Robert Klemme, Sep 23, 2004
    #6
  7. That's nice although it is somewhat limited regarding the size of values:
    => "a8"

    After a bit experimenting I came up with this:
    => "f953040"

    Florian, what do you think?

    Kind regards

    robert
     
    Robert Klemme, Sep 23, 2004
    #7
  8. Very nice, thank you. I wasn't aware of the range limit at first. Only
    thing I would change is using .first instead of .shift. (For clarity)
    More regards,
    Florian Gross
     
    Florian Gross, Sep 23, 2004
    #8
  9. :)) I deliberately choose #shift in order to make the array a bit
    smaller and remove all unnecessary references to the string - kind of GC
    paranoid. :)

    Regards

    robert
     
    Robert Klemme, Sep 23, 2004
    #9
  10. Paul

    Markus Guest

    [-7000000].pack("i").unpack("h*").shift.reverse.gsub(/^f+(?=f)/, '')
    But:
    1. the array can't be referenced after the first/shift returns
    (since it was an anonymous link in a message chain), so the
    whole array is subject to GC from that point
    2. shift can be significantly slower than first
    3. how do you know that shift isn't doing something like:

    def Array.shift
    result = @hypothetical_primitive_array[0]
    @hypothetical_primitive_array = @hypothetical_primitive_array[1..-1]
    result
    end

    ...in which case you'd still have the (scavengable) copy around
    just as if you'd done it yourself?

    It only pays to be paranoid if you can trust yourself more than you can
    trust "them".

    -- Markus
     
    Markus, Sep 23, 2004
    #10
  11. LOL

    Lession taken. Thanks! Of course you're right. Now I just need to find
    out who is "me" and "them"...

    robert
     
    Robert Klemme, Sep 23, 2004
    #11
    1. Advertisements

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments (here). After that, you can post your question and our members will help you out.