All right! It took most of today, but I've solved the problem!

*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:
      -1 -> -1 
 {0, +1} ->  0

*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:
div(x, max(abs(x), 1)))


*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?


On Monday, August 8, 2016 at 10:24:12 AM UTC+2, Wiebe-Marten Wijnja wrote:
>
> Elixir has `rem(dividend, divisor)` to calculate the remainder of an 
> integer division. However, as you probably know, there are different ways 
> to handle remainders with negative numbers:
>
> `rem` will take the remainder, but use the sign of the dividend, which 
> means that the following function definition:
>
> def is_odd(n)
>   rem(n, 2) == 1
> end
>
> will fail for -1, -3, etc, as `rem(-3, 2)`, for instance, has as answer 
> *-1*.
>
> It is also possible to make a *modulo* function, which uses the sign of 
> the divisor. This has the advantage over the remainder function that it 
> maps the whole domain of integers unto a smaller, cyclic, range of numbers. 
> This is highly useful in many algorithms dealing with numbers or indices.
>
> Many programming languages both have a remainder and a modulo function. I 
> have seen multiple people roll their own definitions of `mod` in their 
> Elixir libraries, because they needed it. 
>
> I propose the addition of the modulo function, `mod(a, n)` to Elixir.
>
> A possible implementation is as follows:
>
> defmacro mod(a, n) do
>   quote do
>     unquote(a) - (unquote(n) * div(unquote(a), unquote(n))
>   end
> end
>
> This implementation is guard-safe, so it can be used anywhere where `div` 
> and `rem` are also allowed.
>
>

-- 
You received this message because you are subscribed to the Google Groups 
"elixir-lang-core" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/elixir-lang-core/4b6a452f-c5e9-47af-b0f1-f12618d65d42%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to