tio407
Bitwise operator in Elixir - need help understanding it
I’m failing to grasp what the Bitwise module is doing. The documentation doesn’t have much (see for yourself). I have a decent understanding of binary already. Not sure what the &&& is doing though.
Any explanation to help me understand the following code (just a practice problem off Exercism) would be immensely helpful. I have 2 weeks to get off the ground and start an Elixir project at work so trying to learn as much as I can.
defmodule SecretHandshake do
@doc """
Determine the actions of a secret handshake based on the binary
representation of the given `code`.
If the following bits are set, include the corresponding action in your list
of commands, in order from lowest to highest.
1 = wink
10 = double blink
100 = close your eyes
1000 = jump
10000 = Reverse the order of the operations in the secret handshake
"""
use Bitwise
@spec commands(code :: integer) :: list(String.t())
def commands(code) do
[]
|> handshake(code &&& 0b00001)
|> handshake(code &&& 0b00010)
|> handshake(code &&& 0b00100)
|> handshake(code &&& 0b01000)
|> handshake(code &&& 0b10000)
end
def handshake(list, 0b00001), do: list ++ ["wink"]
def handshake(list, 0b00010), do: list ++ ["double blink"]
def handshake(list, 0b00100), do: list ++ ["close your eyes"]
def handshake(list, 0b01000), do: list ++ ["jump"]
def handshake(list, 0b10000), do: Enum.reverse(list)
def handshake(list, _), do: list
end
Most Liked
cmkarlsson
I find it easier to show it using bits
5 = 0b0101
6 = 0b0110
The Bitwise.band (&&&) is a bitwise and, meaning only if the bit is set on both sides it is kept.
5 = 0b0101
6 = 0b0110
# The position with both bit sets (1) results in the position being set (1).
4 = 0b0100 = 0b0110 &&& 0b0101
The ||| is the bitwise or where you get a 1 if there is a bit set in the same position on either or both side.
The ^^^is the xor (exclusive or) where you get a 1 only if the bit is set on either side. `
A simple demonstration:
iex(30)> [ 0 ^^^ 1, 1 ^^^ 0, 0 ^^^ 0, 1 ^^^ 1 ]
[1, 1, 0, 0]
iex(31)> [ 0 &&& 1, 1 &&& 0, 0 &&& 0, 1 &&& 1 ]
[0, 0, 0, 1]
iex(32)> [ 0 ||| 1, 1 ||| 0, 0 ||| 0, 1 ||| 1 ]
[1, 1, 0, 1]
kokolegorille
You can get binary representation of an integer with Integer.to_string x, 2
&&& is and operation, which copy a bit if it exists in both bit representation of numbers
As an example, 5 &&& 6 returns 4, as expected.
iex> Integer.to_string 5, 2
"101"
iex> Integer.to_string 6, 2
"110"
iex> Integer.to_string 4, 2
"100"
iex> use Bitwise
Bitwise
iex> 5 &&& 6
4
BTW if You have a binary like this
0b01101
it will returns a list like that
["wink", "close your eyes", "jump"]
cmkarlsson
If a bit is set, it is 1. Otherwise 0.
In this case 1, 10, 100, 1000, 10000 are not decimal numbers. They are the bit position. If a bit is set you should include the specific action.
0b00001 = 'wink'
0b00010 = 'double blink'
0b00100 = 'close your eyes'
0b01000 = 'jump'
0b10000 = 'reverse'
This is a common way to deal with flags in a binary format.
Above you have 5 bits (0-31).
Lets take decimal number 10. This is 0b01010. The bits at position 2 and 4 are set. Which means double-wink and jump
So. you start by checking if the wink bit is set, and then go through all the other commands
I’ll do this imperatively.
## This is not good elixir! Don't do this
commands = []
commands = if (10 &&& 0b00001) == 1, do: commands ++ ["wink"], else: commands
commands = if (10 &&& 0b00010) == 2, do: commands ++ ["double blink"], else: commands
commands = if (10 &&& 0b00100) == 4, do: commands ++ [ "close your eyes"], else: commands
commands = if (10 &&& 0b01000) == 8, do: commands ++ ["jump"], else: commands
commands = if (10 &&& 0b10000) == 16, do: Enum.reverse(commands), else: commands
Basicially we check each individual bit to see if it is set with the Bitwise.&&& operator. If it is set we add the command the the command list or reverse it in case the most significant bit it set.
Your initial solution uses elixir pipes and function pattern matching to do the same thing.
Last Post!
belgoros
Yep, seeing it all together clarifies the solution. Thank you!
As for re-submitting a new version, you can always do it by running
exercism submit lib/secret_handshake.ex from your terminal (excersism CLI should be installed first).
Popular in Questions
Other popular topics
Categories:
Sub Categories:
Forums
Popular Tags
- #ecto
- #liveview
- #troubleshooting
- #learning-elixir
- #deployment
- #library
- #erlang
- #testing
- #genserver
- #mix
- #absinthe
- #remote-other
- #otp
- #plug
- #how-to-question
- #macros
- #postgres
- #channels
- #elixirconf
- #exunit
- #discussion
- #code-sync
- #javascript
- #podcasts
- #onsite
- #dialyzer
- #docker
- #authentication
- #umbrella
- #full-time-contract
- #podcasts-by-brainlid
- #ecto-query
- #elixir-ls
- #phoenix_html
- #iex
- #blog-post
- #graphql
- #genstage
- #ai
- #websockets
- #supervisor
- #elixirconf-us
- #advent-of-code
- #distillery
- #processes
- #forms
- #api
- #metaprogramming
- #hex
- #security









