Elixir treats numbers with special care. Whether you're doing basic arithmetic, handling financial calculations, or working with binary data, understanding how Elixir deals with numbers is essential for writing efficient and reliable applications.
Note: The examples in this article use Elixir 1.17.3. While most numeric operations should work across different versions, some functionality might vary.
Table of Contents
- Introduction
- Basic Number Types
- Number Literals and Bases
- Basic Operations
- Mathematical Functions
- Working with Binary Numbers
- Money and Decimal Operations
- Number Formatting
- Common Patterns and Best Practices
- Performance Considerations
- Conclusion
- Further Reading
- Next Steps
Introduction
Numbers are fundamental to any programming language, and Elixir provides robust support for various numeric types and operations. In this article, we'll explore everything from basic integer operations to complex mathematical computations and binary number manipulations.
Basic Number Types
Integers
Elixir integers have no limit on their size, automatically expanding to accommodate any number:
iex> integer = 42
42
iex> big_number = 123456789123456789
123456789123456789
iex> negative = -42
-42
# Testing integer size
iex> really_big = 12345678901234567890123456789
12345678901234567890123456789
iex> is_integer(really_big)
true
Floating-Point Numbers
Floating-point numbers in Elixir are double-precision 64-bit IEEE 754. Like in most programming languages, they can suffer from precision issues due to their binary representation:
iex> 0.1 + 0.2 == 0.3
false
iex> 0.1 + 0.2
0.30000000000000004
iex> float = 3.14
3.14
iex> scientific = 1.0e-10
1.0e-10
iex> another_float = 1.0e10
10000000000.0
Number Literals and Bases
Elixir supports various number representations:
# Decimal (base 10)
iex> decimal = 42
42
# Binary (base 2)
iex> binary = 0b101010 # = 42
42
iex> binary = 0b1111_1111 # Using underscore for readability
255
# Octal (base 8)
iex> octal = 0o52 # = 42
42
# Hexadecimal (base 16)
iex> hex = 0xFF # = 255
255
iex> hex = 0xFF_FF # = 65535
65535
# Using underscore for readability in large numbers
iex> million = 1_000_000
1000000
iex> billion = 1_000_000_000
1000000000
Basic Operations
Arithmetic Operations
iex> 5 + 5 # Addition
10
iex> 10 - 5 # Subtraction
5
iex> 4 * 3 # Multiplication
12
iex> 10 / 2 # Division (always returns float)
5.0
# Integer Division and Remainder
iex> div(10, 3) # Integer division
3
iex> rem(10, 3) # Remainder
1
# Demonstration of automatic type conversion
iex> 5 + 5.0 # Integer + Float = Float
10.0
iex> 10 / 2 # Division always returns float
5.0
iex> div(10, 2) # div always returns integer
5
Number Comparison
iex> 1 < 2 # Less than
true
iex> 2 > 1 # Greater than
true
iex> 2 >= 2 # Greater than or equal
true
iex> 2 <= 2 # Less than or equal
true
iex> 2 == 2 # Equality
true
iex> 2 != 3 # Inequality
true
# Type-specific comparison
iex> 2 == 2.0 # Value equality
true
iex> 2 === 2.0 # Strict equality
false
Mathematical Functions
Basic Math Module Functions
iex> abs(-42) # Absolute value
42
iex> round(3.58) # Round to nearest integer
4
iex> trunc(3.58) # Truncate decimal part
3
iex> floor(3.58) # Floor value
3
iex> ceil(3.58) # Ceiling value
4
# Power operations
iex> :math.pow(2, 3) # 2 to the power of 3
8.0
iex> :math.sqrt(16) # Square root
4.0
Trigonometric Functions
iex> :math.pi() # π constant
3.141592653589793
iex> :math.sin(2) # Sine
0.9092974268256817
iex> :math.cos(2) # Cosine
-0.4161468365471424
iex> :math.tan(2) # Tangent
-2.185039863261519
# Using degrees instead of radians
iex> rad = fn degrees -> degrees * :math.pi() / 180 end
iex> :math.sin(rad.(90)) # Sine of 90 degrees
1.0
Working with Binary Numbers
Binary numbers are particularly important in the Elixir/Erlang ecosystem. Here are some practical use cases:
# Binary to Integer conversion
iex> binary = "110"
iex> String.to_integer(binary, 2)
6
# Integer to Binary string
iex> Integer.to_string(6, 2)
"110"
# Import Bitwise module for binary operations
iex> import Bitwise
# Binary operations
iex> Bitwise.band(0b1010, 0b1100) # Bitwise AND
8
iex> Bitwise.bor(0b1010, 0b1100) # Bitwise OR
14
iex> Bitwise.bxor(0b1010, 0b1100) # Bitwise XOR
6
iex> Bitwise.bnot(0b1010) # Bitwise NOT
-11
# Bit shifting
iex> Bitwise.bsl(0b1010, 1) # Shift left
20
iex> Bitwise.bsr(0b1010, 1) # Shift right
5
# If you really need operators (not recommended for new code)
iex> 0b1010 &&& 0b1100 # AND
8
iex> 0b1010 ||| 0b1100 # OR
14
# Pattern matching with binary
iex> <<1, 2, 3>> = <<1, 2, 3>>
<<1, 2, 3>>
iex> <<a, b, c>> = <<1, 2, 3>>
<<1, 2, 3>>
iex> a
1
Money and Decimal Operations
When working with financial calculations, always use the Decimal library:
# Add Decimal to your project dependencies:
# {:decimal, "~> 2.3.0"}
# Or use Mix.install to install for the current IEx session
iex> Mix.install([{:decimal, "~> 2.3.0"}, {:number, "~> 1.0.5"}])
# After installation, you can use all Decimal functions!
# No Mix project needed
# Basic Decimal operations
iex> Decimal.new("0.1")
#Decimal<0.1>
iex> Decimal.add(Decimal.new("0.1"), Decimal.new("0.2"))
#Decimal<0.3>
# Avoiding floating-point errors
iex> 0.1 + 0.2
0.30000000000000004 # Float precision issue
iex> Decimal.add(Decimal.new("0.1"), Decimal.new("0.2"))
#Decimal<0.3> # Exact decimal arithmetic
# Currency calculations
iex> price = Decimal.new("29.99")
iex> tax_rate = Decimal.new("0.08")
iex> tax = Decimal.mult(price, tax_rate)
#Decimal<2.3992>
iex> total = Decimal.add(price, tax)
#Decimal<32.3892>
# Rounding decimals
iex> Decimal.round(total, 2)
#Decimal<32.39>
Number Formatting
Elixir provides several ways to format numbers:
# Integer to String
iex> Integer.to_string(1234)
"1234"
# Float to String
iex> Float.to_string(3.14159)
"3.14159"
iex> :io_lib.format("~.2f", [3.14159])
'3.14'
# Custom formatting
# For more advanced formatting, you can use the 'number' library:
iex> Number.Currency.number_to_currency(1234.56)
"$1,234.56"
iex> Number.Human.number_to_human(1234)
"1.23 Thousand"
iex> Number.Percentage.number_to_percentage(0.34)
"34.00%"
# Using String.pad_leading for alignment
iex> number = 42
iex> String.pad_leading(Integer.to_string(number), 5, "0")
"00042"
Common Patterns and Best Practices
Handling Division by Zero
defmodule SafeMath do
def divide(a, b) do
try do
a / b
rescue
ArithmeticError -> {:error, :division_by_zero}
end
end
end
# Usage
iex> SafeMath.divide(10, 2)
5.0
iex> SafeMath.divide(10, 0)
{:error, :division_by_zero}
Working with Large Numbers
# Factorial calculation with large numbers
defmodule Math do
def factorial(0), do: 1
def factorial(n) when n > 0 do
Enum.reduce(1..n, &*/2)
end
end
iex> Math.factorial(100) # Works with large numbers!
93326215443944152681699238856266700490715968264381621468592963895217599993229915608941463976156518286253697920827223758251185210916864000000000000000000000000
Performance Considerations
Integer vs Float Operations
# Integer operations are generally faster
# :timer.tc measures execution time in microseconds
iex> :timer.tc(fn -> Enum.sum(1..1_000_000) end)
{3, 500000500000}
# Float operations are slower
iex> :timer.tc(fn -> Enum.sum(1..1_000_000 |> Enum.map(&(&1/1))) end)
{244433, 500000500000.0}
Memory Usage
# Integers use less memory than floats
# Comparing memory size of different number types
iex> :erts_debug.flat_size(123456)
0
iex> :erts_debug.flat_size(123.456)
2
Conclusion
In this article, we explored the comprehensive number system in Elixir, covering everything from basic integers and floats to complex decimal operations. We learned that Elixir provides:
- Arbitrary-precision integers that can handle numbers of any size
- IEEE 754 double-precision floating-point numbers
- Support for different number bases and readable number literals
- Rich mathematical functions through the built-in
:math
module - Precise decimal arithmetic via the Decimal library
- Efficient number formatting options
- Robust handling of edge cases like division by zero
Understanding these numeric foundations is essential for building reliable Elixir applications, especially when dealing with financial calculations or performance-critical operations.
Further Reading
Official Documentation
- Elixir Basic Types - Official documentation covering numbers and other basic types
- Decimal - Documentation for the Decimal library
- Erlang Math Module - Complete reference for mathematical functions
- Elixir Integer Module - Documentation for integer operations
- Elixir Float Module - Documentation for float operations
Next Steps
In the upcoming articles, we'll explore:
- Deep Dive into Strings
Top comments (0)