The binary type represents a sequence of bits.
A binary literal looks like << term,… >>.
The simplest term is just a number from 0 to 255. The numbers are stored as successive bytes in the binary.
| iex> b = << 1, 2, 3 >> |
| <<1, 2, 3>> |
| iex> byte_size b |
| 3 |
| iex> bit_size b |
| 24 |
You can specify modifiers to set any term’s size (in bits). This is useful when working with binary formats such as media files and network packets.
| iex> b = << 1::size(2), 1::size(3) >> # 01 001 |
| <<9::size(5)>> # = 9 (base 10) |
| iex> byte_size b |
| 1 |
| iex> bit_size b |
| 5 |
You can store integers, floats, and other binaries in binaries.
| iex> int = << 1 >> |
| <<1>> |
| iex> float = << 2.5 :: float >> |
| <<64, 4, 0, 0, 0, 0, 0, 0>> |
| iex> mix = << int :: binary, float :: binary >> |
| <<1, 64, 4, 0, 0, 0, 0, 0, 0>> |
Let’s finish an initial look at binaries with an example of bit extraction. An IEEE 754 float has a sign bit, 11 bits of exponent, and 52 bits of mantissa. The exponent is biased by 1023, and the mantissa is a fraction with the top bit assumed to be 1. So we can extract the fields and then use :math.pow, which performs exponentiation, to reassemble the number:
| iex> << sign::size(1), exp::size(11), mantissa::size(52) >> = << 3.14159::float >> |
| iex> (1 + mantissa / :math.pow(2, 52)) * :math.pow(2, exp-1023) * (1 - 2*sign) |
| 3.14159 |