20

How can I represent integer as Binary?

so I can print 7 as 111

fl00r
  • 82,987
  • 33
  • 217
  • 237

10 Answers10

16

You write a function to do this.

num=7
function toBits(num)
    -- returns a table of bits, least significant first.
    local t={} -- will contain the bits
    while num>0 do
        rest=math.fmod(num,2)
        t[#t+1]=rest
        num=(num-rest)/2
    end
    return t
end
bits=toBits(num)
print(table.concat(bits))

In Lua 5.2 you've already have bitwise functions which can help you ( bit32 )


Here is the most-significant-first version, with optional leading 0 padding to a specified number of bits:

function toBits(num,bits)
    -- returns a table of bits, most significant first.
    bits = bits or math.max(1, select(2, math.frexp(num)))
    local t = {} -- will contain the bits        
    for b = bits, 1, -1 do
        t[b] = math.fmod(num, 2)
        num = math.floor((num - t[b]) / 2)
    end
    return t
end
Dave Yarwood
  • 2,866
  • 1
  • 17
  • 29
jpjacobs
  • 9,359
  • 36
  • 45
  • 2
    you have got reversed bits in your function, so `20` will return `00101`, not `10100` – fl00r Jan 31 '12 at 13:56
  • 1
    you did not state whether you wanted big or little endian. The example didn't give it away either, since 111 is a palindrome ;). Anyway, adapting it is easy: just use `nBits=ceiling(select(2,math.frexp(num)))` and use a for-loop starting at nBits going to 1. – jpjacobs Jan 31 '12 at 13:59
  • my fault, sorry, nevertheless the answer is right and useful, thank you! – fl00r Jan 31 '12 at 14:00
  • I've added a most-significant version to your answer. I left off the call to `math.ceil()` because, as far as I can tell, frexp always returns an integer for the second value. Is there an edge case that I have missed? – Phrogz Sep 26 '14 at 03:45
  • No indeed, as per [the manual on math.frexp](http://www.lua.org/manual/5.2/manual.html#pdf-math.frexp), the second return value should be always integer. Thanks for the edit! – jpjacobs Sep 29 '14 at 09:52
  • Why .fmod rather than %? I assume it's to do with the rounding behavior? – Daniel B. Nov 01 '14 at 04:52
  • The Manual for `math.fmod` reads: "Returns the remainder of the division of x by y that rounds the quotient towards zero." `%` on the other hand, is specified as: "the remainder of a division that rounds the quotient towards minus infinity". So behavior will be the same for both on positive numbers. Negative numbers are not covered anyhow, since it would require 2-complement etc... – jpjacobs Nov 02 '14 at 08:46
  • The second function doesn't works, an end is missing, see my answer for a version writing table of bits in the right order. – Ben Nov 02 '14 at 18:30
  • You're right, thanks for pointing it out. I fixed it, and now it should work as expected. – jpjacobs Nov 03 '14 at 09:31
  • This implementation has two bugs: 1) `bits` ends up being 0 for the input 0, resulting in bits being `{}` instead of `{0}` as expected. – Dave Yarwood Mar 14 '17 at 12:44
  • and 2) `(num-t[b])/2` results in a float instead of an integer because of how division works in Lua. In Lua 5.3+, you can use the floor division (`//`) operator. Otherwise, this expression needs to be wrapped in a call to `math.floor`. – Dave Yarwood Mar 14 '17 at 12:46
9

There's a faster way to do this that takes advantage of string.format, which converts numbers to base 8. It's trivial to then convert base 8 to binary.

--create lookup table for octal to binary
oct2bin = {
    ['0'] = '000',
    ['1'] = '001',
    ['2'] = '010',
    ['3'] = '011',
    ['4'] = '100',
    ['5'] = '101',
    ['6'] = '110',
    ['7'] = '111'
}
function getOct2bin(a) return oct2bin[a] end
function convertBin(n)
    local s = string.format('%o', n)
    s = s:gsub('.', getOct2bin)
    return s
end

If you want to keep them all the same size, then do

s = string.format('%.22o', n)

Which gets you 66 bits. That's two extra bits at the end, since octal works in groups of 3 bits, and 64 isn't divisible by 3. If you want 33 bits, change it to 11.

If you have the BitOp library, which is available by default in LuaJIT, then you can do this:

function convertBin(n)
    local t = {}
    for i = 1, 32 do
        n = bit.rol(n, 1)
        table.insert(t, bit.band(n, 1))
    end
    return table.concat(t)
end

But note this only does the first 32 bits! If your number is larger than 2^32, the result wont' be correct.

Houshalter
  • 2,508
  • 1
  • 18
  • 20
4
function bits(num)
    local t={}
    while num>0 do
        rest=num%2
        table.insert(t,1,rest)
        num=(num-rest)/2
    end return table.concat(t)
end

Since nobody wants to use table.insert while it's useful here

einsteinK
  • 49
  • 1
  • 1
    Actually, using table.insert increases the complexity of the algorithm **from O(n)** to **O(n^2)**. Doing what **jpjacobs** said in his comment, first determine the length of the number and then fill the array backwards, is much more efficient. Especially for large numbers. The only changes would be to replace `while num>0 do` by `for i=math.ceil(select(2,math.frexp(num))),1,-1 do` and `t[#t+1]` by `t[i]`. – RPFeltz Aug 23 '14 at 12:22
3

Here is a function inspired by the accepted answer with a correct syntax which returns a table of bits in wriiten from right to left.

num=255
bits=8
function toBits(num, bits)
    -- returns a table of bits
    local t={} -- will contain the bits
    for b=bits,1,-1 do
        rest=math.fmod(num,2)
        t[b]=rest
        num=(num-rest)/2
    end
    if num==0 then return t else return {'Not enough bits to represent this number'}end
end
bits=toBits(num, bits)
print(table.concat(bits))

>>11111111
Ben
  • 1,241
  • 1
  • 15
  • 22
2

This function uses a lookup table to print a binary number extracted from a hex representation. All using string manipulation essentially. Tested in lua 5.1.

local bin_lookup = {
    ["0"] = "0000",
    ["1"] = "0001",
    ["2"] = "0010",
    ["3"] = "0011",
    ["4"] = "0100",
    ["5"] = "0101",
    ["6"] = "0110",
    ["7"] = "0111",
    ["8"] = "1000",
    ["9"] = "1001",
    ["A"] = "1010",
    ["B"] = "1011",
    ["C"] = "1100",
    ["D"] = "1101",
    ["E"] = "1110",
    ["F"] = "1111"
}

local print_binary = function(value)
    local hs = string.format("%.2X", value) -- convert number to HEX
    local ln, str = hs:len(), "" -- get length of string
    for i = 1, ln do -- loop through each hex character
        local index = hs:sub(i, i) -- each character in order
        str = str .. bin_lookup[index] -- lookup a table
        str = str .. " " -- add a space
    end
    return str
end

print(print_binary(45))
#0010 1101
print(print_binary(65000))
#1111 1101 1110 1000
dnaldoog
  • 39
  • 2
1
local function tobinary( number )
  local str = ""
  if number == 0 then
      return 0
  elseif number < 0 then
      number = - number
      str = "-"
  end
  local power = 0
  while true do
      if 2^power > number then break end
      power = power + 1
  end
  local dot = true
  while true do
      power = power - 1
      if dot and power < 0 then
          str = str .. "."
          dot = false
      end
      if 2^power <= number then
          number = number - 2^power
          str = str .. "1"
      else
          str = str .. "0"
      end
      if number == 0 and power < 1 then break end
  end
  return str
end

May seem more verbose but it is actually faster than other functions that use the math library functions. Works with any number, be it positive/negative/fractional...

lucullus
  • 187
  • 1
  • 11
1
local function tobits(num, str) -- tail call
    str = str or "B"
    if num == 0 then return str end 
    return tobits( 
          num >> 1 , -- right shift
          ((num & 1)==1 and "1" or "0") .. str   )
end          
Shewer Lu
  • 11
  • 2
1
function reverse(t)
  local nt = {} -- new table
  local size = #t + 1
  for k,v in ipairs(t) do
    nt[size - k] = v
  end
  return nt
end

function tobits(num)
    local t={}
    while num>0 do
        rest=num%2
        t[#t+1]=rest
        num=(num-rest)/2
    end
    t = reverse(t)
    return table.concat(t)
end
print(tobits(7))
# 111
print(tobits(33))
# 100001
print(tobits(20))
# 10100
fl00r
  • 82,987
  • 33
  • 217
  • 237
0

This maybe not work in lua that has no bit32 library

    function toBinary(number, bits)
        local bin = {}
        bits = bits - 1
        while bits >= 0 do --As bit32.extract(1, 0) will return number 1 and bit32.extract(1, 1) will return number 0
                       --I do this in reverse order because binary should like that
            table.insert(bin, bit32.extract(number, bits))
            bits = bits - 1
        end
        return bin
    end
    --Expected result 00000011
    print(table.concat(toBinary(3, 8)))

This need at least lua 5.2 (because the code need bit32 library)

Blanket Fox
  • 377
  • 4
  • 15
0

As by Dave, but with filled empty bits:

local function toBits(num, bits)
    -- returns a table of bits, least significant first.
    local t={} -- will contain the bits
    bits = bits or 8
    while num>0 do
        rest=math.fmod(num,2)
        t[#t+1]=rest
        num=math.floor((num-rest)/2)
    end
    for i = #t+1, bits do -- fill empty bits with 0
        t[i] = 0
    end
    return t
end

for i = 0, 255 do
    local bits = toBits(i)
    print(table.concat(bits, '  '))
end

Result:

  0   0   0   0   0   0   0   0
  1   0   0   0   0   0   0   0
  0   1   0   0   0   0   0   0
  1   1   0   0   0   0   0   0
  0   0   1   0   0   0   0   0
  1   0   1   0   0   0   0   0
  ...
  0   1   1   1   1   1   1   1
  1   1   1   1   1   1   1   1
darkfrei
  • 122
  • 5