ModulusOperandi
Declarative, multi-algorithm modular arithmetic for Swift Integers and Floating-Point types.
Modular arithmetic algorithms come in variants that use either Euclidean, truncating, or flooring division. Furthermore, Swift's built-in % operator — while used as a modulus in some languages — is strictly used as a remainder operator.
These nuances can lead modular arithmetic code that's ambiguous in both intent and correctness — which is what ModulusOperandi attempts to solve.
Features
- ✅ Declarative API that allows for choosing between Euclidean, Truncating, or Flooring Modular Arithmetic.
- ✅ Euclidean by default.
- ✅ Support for conformances to
BinaryInteger
andFloatingPointInteger
. - ✅ Command Line tool for performing calculations in the Terminal.
Installation
Xcode Projects
Select File
-> Swift Packages
-> Add Package Dependency
and enter https://github.com/CypherPoet/ModulusOperandi
.
Swift Package Manager Projects
You can add ModulusOperandi
as a dependency in your Package.swift
file:
let package = Package(
//...
dependencies: [
.package(url: "https://github.com/CypherPoet/ModulusOperandi", from: "0.2.2"),
],
//...
)
Then simply import ModulusOperandi
wherever you’d like to use it.
Usage
After importing ModulusOperandi
in a file, types that conform to BinaryInteger
and FloatingPointInteger
will be extended with a modulus
function.
This function treats its value as the dividend
and takes a divisor
of the same type. It also takes an optional mode
argument to choose between Euclidean, Truncating, or Flooring Modular Arithmetic.
By default, the mode
will be Euclidean
import ModulusOperandi
let dividend = 5
let divisor = 3
dividend.modulo(divisor) // 2
dividend.modulo(-divisor) // 2
-dividend.modulo(divisor) // -2
-dividend.modulo(-divisor) // -2
// Same as...
dividend.modulo(divisor, mode: .euclidean) // 2
dividend.modulo(-divisor, mode: .euclidean) // 2
-dividend.modulo(divisor, mode: .euclidean) // -2
-dividend.modulo(-divisor, mode: .euclidean) // -2
import ModulusOperandi
let dividend = 5
let divisor = 3
dividend.modulo(3, mode: .flooring) // 2
dividend.modulo(-3, mode: .flooring) // -1
-dividend.modulo(3, mode: .flooring) // -2
-dividend.modulo(-3, mode: .flooring) // 1
import ModulusOperandi
let dividend = 5
let divisor = 3
dividend.modulo(3, mode: .truncating) // 2
dividend.modulo(-3, mode: .truncating) // 2
-dividend.modulo(3, mode: .truncating) // -2
-dividend.modulo(-3, mode: .truncating) // -2
Command Line Tool
ModulusOperandi
also ships with a command line tool that lets you perform calculations directly from the command line.
To install it, clone the project and run make
:
$ git clone [email protected]:CypherPoet/ModulusOperandi.git
$ cd ModulusOperandiCLI
$ make
The command line tool will be installed as modulo
, and running modulo --help
will present some helpful usage instructions:
See Help Menu
modulo --help
OVERVIEW: Multi-algorithm modular arithmetic for Swift integers and
floating-Point types.
Modular arithmetic algorithms come in variants that use either Euclidean,
truncating, or flooring division.
This tool acts as a CLI for the `ModulusOperandi` Swift package -- which allows
you to perform modular arithmetic according to your desired algorithm.
? Note on Negative Numbers
----------------------------------------------
To use negative numbers, prefix the argument with `\ ` (including the space).
For example, -5 mod 4 would be passed as:
modulo \ -5 4
-5 mod -4 would be passed as:
modulo \ -5 \ -4
? More Info On Modular Arithmetic
----------------------------------------------
- https://en.wikipedia.org/wiki/Modulo_operation#Variants_of_the_definition
USAGE: modulo [--euclidean] [--flooring] [--truncating]
ARGUMENTS:
The dividend to perform division against.
The divisor to use as a "modulus".
OPTIONS:
--euclidean/--flooring/--truncating
The algorithm to use for computing results. (default:
euclidean)
--version Show the version.
-h, --help Show help information.
Negative Numbers
Disambiguating negative numbers from argument flags is a notorious challenge for Command Line interfaces. Currently, support for this in Swift's Argument Parser appears to be an ongoing area of development, In the meantime, though, the modulo
command can take negative-number arguments via some clever escape syntax.
Simply prefix any negative number with \
(including the space). Like so:
-5 mod 4
:
modulo \ -5 4
-5 mod -4
:
modulo \ -5 \ -4
5 mod -4
:
modulo 5 \ -4