Problem: Elixir does not have a (guard-safe) Floored Modulo Remainder function `mod`.
Proposed solution: Implement with floored division, as follows:
mod(a, n) === a - (n * floor_div(a, n))
Subproblem: Elixir does not have (guard-safe) Floored Division.
Proposed solution: Implement Floored Division by using the existing Truncated Division BIF `div/2`.
To change Truncated Division to Floored Division,
we need to add (-1) to the result, iff one of the signs of `a` and `n` is negative,
Six cases: (n == 0 is invalid input as it would result in a division by 0)
a | n | div(a,n) + ?
+ | + | 0
- | + | -1
+ | - | -1
- | - | 0
0 | + | 0
0 | - | 0
New Subproblem: Find a function that produces these outputs, given `a` and `n`.
The approach I took, was to adapt the `sign` function.
x => sign(x)
+ => +1
- => -1
0 -> 0
a | n => sign(a * n)
+ | + => +1
- | + => -1
+ | - => -1
- | - => +1
0 | + => 0
0 | - => 0
Now we need to find the transforming function that maps the output of sign(a*n) to the requested format:
Solution: div(sign(x) - 1, 2)
Truth table:
div(+1 - 1, 2) => 0
div(0 - 1, 2) => 0
div(-1 - 1, 2) => -1
New Subproblem: Elixir does not have a (guard-safe) `sign/1` function.
Solution: `sign/1` can be constructed from dividing the number by its absolute value:
`div(x, abs(x))`
However, special care has to be taken to prevent division-by-zero!
This was where I was stuck for some time, but I found out we can circumvent this problem by 'cheating' a little:
Observe:
a) 0 / 1 == 0 which is the wanted output for sign(0).
b) forall x != 0, abs(x) >= 1
Therefore, we can write the definition of `sign` as:
New Subproblem: Elixir does not have a guard-safe `max/2` function.
Solution: The implementation of this function is straightforward:
max(a, b) === div((a + b) + abs(a - b), 2)
I will now continue on making a pull request out of this.
This approach introduces quite a few intermediate steps, so `mod` is going to be less efficient than `rem`; fully expanded, `mod` will be:
div(a, n) + div(div(a * n, div((abs(a * n) + 1) + abs(abs(a * n) - 1), 2)) - 1, 2)
that is four `div/2` three `abs/1`, and a couple of +, - and * operations.
I am wondering: What should we do with the guard-safe `max` and `sign` implementations (and maybe `floor_div`) I found while attempting to make this?
Their advantage is that they work inside guard clauses. We could use this version of `max` inside a guards, similar as how `in` has a different implementation inside guards vs inside function bodies.
Their disadvantage is that they only work for integer operands, which might maybe confuse newcomers.
Inside the PR I could either:
- make full-fledged macros out of them that are documented and publicly visible. ( I would then also add a `min` variant, of course).
- make private macros out of them that are only used for `mod`.
- Not even make private macros out of them, but mention them inline in the implementation of `mod`.
What do you think?