So, a couple bugs: Phrogz wrote: > # Low-order bytes appear first in the string. Not necessarily > if pack_code = { 1=>'C', 2=>'S', 4=>'L' }[ num_chars ] in Array.pack, 'S', and 'L', use system-endian order. To use little endian order use 'v' and 'V', respectively. Personally, I think it's cleaner to just leave out the clause altogether. [...] > unless num_chars > bits_needed = Math.log( self ) / Math::LOG2 > num_chars = ( bits_needed / 8.0 ).ceil > end You're ignoring a bunch of edge cases here. 0 and 1, for example. For 0, Math.log(0) == -Infinity, which will throw an error when 'ceil' is called. For 1, Math.log(1) == 0, so num_chars == 0, which isn't quite right either. You'll run into the same issue at other powers of 256, as well. What you should actually do, instead of taking the ceiling, is round down and add one. You're also ignoring negative integers. Math.log doesn't like negative numbers either, so you'll need to take the absolute value. This doesn't solve the problem when you're reading back in, of differentiating between positive and negative integers that have the same byte code. Here's my code. I ignore the positive/negative reading back in problem. #!/usr/bin/env ruby -w # The natural log of 256 (for base-256 logarithms) Math::LOG256 = Math.log( 256 ) class Integer # Converts the integer into a string, where the value of each # character is a byte in the bit representation of the integer, # low order bytes first. # # If the number of characters is not specified, the fewest number of # characters that can represent the integer is used. def to_bytestring( num_octets=nil ) # find out how many octets are required to encode it num_octets ||= (self == 0) ? 1 : ( Math.log(self.abs) / Math::LOG256 ).to_i + 1 # encode the low num_octets bytes of the integer. shifted = (self << 8) Array.new(num_octets).map do ((shifted >>= 8) & 0xFF).chr end.join end # Creates an integer from a byte string. # See Integer#to_bytestring for more information. # NOTE: reads in negative integers as positive def self.from_bytestring( str ) str.reverse.split(//).inject(0) do |val, char| (val << 8) | char[0] end end end [ -1, 0x0, 0x1, 255, 256, -255, -256, 0x48, 26952, 0x6948, 0x646c726f57206f6c6c6548, 0x217962755220666f207463657073612074656577732061207369206d756e676942 ].each{ |i| begin p [i, i.to_bytestring, Integer.from_bytestring(i.to_bytestring)] rescue StandardError => err p err end }