# Save octal & binary in varible

Hi
code in Python

``````input = "Input1337"
encode = input.encode("utf-8")
hex = encode.hex()
oct = oct(int(hex, 16))
binary = " ".join(f"{ord(i):08b}" for i in input)

print("input  :", input)
print("octal  :", oct)
print("binary :", binary)
``````

out:

``````input  : Input1337
octal  : 0o222671603527206114631467
binary : 01001001 01101110 01110000 01110101 01110100 00110001 00110011 00110011 00110111
``````

in elixir:

``````input = "Input1337"
hex = Base.encode16(input)
IO.puts("Input  : #{input}")
IO.inspect(hex, base: :binary)
IO.inspect(hex, base: :octal)
``````

out:

``````Input  : Input1337
<<0b1001001, 0b1101110, 0b1110000, 0b1110101, 0b1110100, 0b110001, 0b110011,
0b110011, 0b110111>>
<<0o111, 0o156, 0o160, 0o165, 0o164, 0o61, 0o63, 0o63, 0o67>>
``````

I was only able to convert using IO.inspect
But I feel that I have made a mistake again
How can I save it in a variable like the Python code above?

Thanks

Iâ€™m not sure what youâ€™re trying to achieve here since binary, hex and octal are just different representations of the string, not necessarily â€śconversionsâ€ť. I think you are looking to store the binary (Elixir string) representations of input formatted as hex and octal. In which case `inspect/2` may be what you are after:

``````iex> input = "Input1337"
"Input1337"
iex> binary = inspect(input, base: :binary)
"<<0b1001001, 0b1101110, 0b1110000, 0b1110101, 0b1110100, 0b110001, 0b110011, 0b110011, 0b110111>>"
iex> hex = inspect(input, base: :hex)
"<<0x49, 0x6E, 0x70, 0x75, 0x74, 0x31, 0x33, 0x33, 0x37>>"
iex> octal = inspect(input, base: :octal)
"<<0o111, 0o156, 0o160, 0o165, 0o164, 0o61, 0o63, 0o63, 0o67>>"
``````

Note that the output is itself executable code showing different representations of input:

``````iex> <<0b1001001, 0b1101110, 0b1110000, 0b1110101, 0b1110100, 0b110001, 0b110011, 0b110011, 0b110111>>
"Input1337"
iex> <<0x49, 0x6E, 0x70, 0x75, 0x74, 0x31, 0x33, 0x33, 0x37>>
"Input1337"
iex> <<0o111, 0o156, 0o160, 0o165, 0o164, 0o61, 0o63, 0o63, 0o67>>
"Input1337"
``````
5 Likes

Thatâ€™s right, thank you

Do you have a solution to display as below?

``````<<0b1001001, 0b1101110, 0b1110000, 0b1110101, 0b1110100, 0b110001, 0b110011,
0b110011, 0b110111>>
``````

to:

``````010010010110111001110000011101010111010000110001001100110011001100110111
``````

thanks

What I mean is to out of bitstrings mode and display as string

This should do the trick:

``````for << byte :: unsigned-integer-8 <- "Input1337" >>, reduce: [] do
acc ->
bin = Integer.to_string(byte, 2)
[String.duplicate("0", 8 - String.length(bin)) <> bin | acc]
end
|> Enum.reverse()
|> Enum.join()
``````

### Explanation

• decompose the string into 8 bit unsigned integers
• for each integer, print it as a base 2 string
• pad the string to 8 digits
• reverse the list of string (because we were inserted each byte at the head of the list
• join the strings together
2 Likes

Hereâ€™s another version that works just on binaries, but building binaries might not be as efficient as working with lists (not checked):

``````for << byte :: unsigned-integer-8 <- "Input1337" >>, reduce: <<>> do
acc ->
bin = Integer.to_string(byte, 2)
acc <> String.duplicate("0", 8 - String.length(bin)) <> bin
end
``````
2 Likes

very good
thank you

Just for fun, hereâ€™s one more that I think it more expressive:

``````for << bit :: 1 <- "Input1337" >>, reduce: <<>> do
acc -> acc <> Integer.to_string(bit)
end
``````

### Performance

After benchmarking, this implementation is the most performant (by between 12% and 17% percent over the others) at the expense of about 30% higher memory usage. 10kb versus 7.5kb for the original string in this post.

2 Likes

``````for <<byte <- "Input1337">>, into: "", do: Integer.to_string(byte, 2)
``````

Benchmark:

``````Name           ips        average  deviation         median         99th %
adam        1.88 M        0.53 ÎĽs  Â±5159.76%        0.46 ÎĽs        0.63 ÎĽs
kip         0.30 M        3.31 ÎĽs   Â±332.77%        3.08 ÎĽs        7.08 ÎĽs

Comparison:
kip         0.30 M - 6.23x slower +2.78 ÎĽs

Operating System: macOS
CPU Information: Apple M1 Pro
Number of Available Cores: 10
Available memory: 16 GB
Elixir 1.13.4
Erlang 25.0.2
``````

Edit: the above is buggy because it doesnâ€™t pad the strings with leading zeros. Correct but slower version:

``````    for <<byte <- input>>, into: "" do
end
``````
4 Likes

Oh, yes, much better! Great work.

1 Like

Hereâ€™s a generic version that works for all bases.

``````def to_base(binary, base) do
bits = :math.log2(base) |> round()
for <<nibble::size(bits) <- binary>>, into: "", do: <<?0 + nibble>>
end
``````
``````Name              ips        average  deviation         median         99th %
adam           1.94 M      514.63 ns  Â±3751.97%         458 ns         625 ns
to_base        1.09 M      913.44 ns  Â±2482.01%         833 ns        1000 ns
kip            0.30 M     3310.78 ns   Â±369.75%        3083 ns        7084 ns

Comparison:
to_base        1.09 M - 1.77x slower +398.82 ns
kip            0.30 M - 6.43x slower +2796.15 ns
``````

Edit: Actually only works up to base 10 because after that there arenâ€™t enough decimal digits to display the serialized value, so might be better avoid calculating the bit size and hardcode it:

binary: `for <<bit::1 <- binary>>, into: "", do: <<?0 + bit>>`
octal: `for <<nibble::3 <- binary>>, into: "", do: <<?0 + nibble>>`

Edit 2: Also only works properly when the `base` is a power of 2

Edit 3: hmm something is wrong because the results differ between my two versions. Will come back to this later!

4 Likes

Thanks

Back again

There was an error in my first reply: I forgot to pad the integers with 0s. Adding that brings it to about the same performance as Kipâ€™s suggestion.

But the above suggestion is still about 4 times faster on my machine.

TLDR:

``````def to_binary(input) do
for <<bit::1 <- input>>, into: "", do: <<?0 + bit>>
end

def to_octal(input) do
for <<nibble::3 <- input>>, into: "", do: <<?0 + nibble>>
end
``````
3 Likes

I tried all methods
And I found a new way

``````hex = Base.encode16(input, case: :lower)
{decimal, _} = Integer.parse(hex, 16)
binary = Integer.to_string(decimal, 2)
octal = Integer.to_string(decimal, 8)
``````