Anyway, just wondering what people's opinions are on having the alternate modulo available (as a separate key word such as "modulo")?Personally, I like the suggestion and I particularly like how well you showed that there are good reasons for it (only one example was needed... well exposed. :) )
Thanks 440bx. :)You're welcome. One thing that comes to mind is to code it like this "(n + abs(expression)) mod d", that way the mod is always used with positive numbers ensuring the result will be consistent.
Any ideas on the most efficient work around?
The problem is comparing "n1 mod d" with other similar terms like "n2 mod d" to see if they are the same. They could be the same, but a simple "mod d" comparison might not reveal it (like in the base 12 example where one mod returns 4 and the other returns -8, but they are really the same thing).wouldn't evaluating "abs(n1) mod d" and "abs(n2) mod d" allow you to determine the expressions are equal for any n1 = x * d and n2 = y * d for the same d regardless of whether x, y or both are negative ? What I'm saying is, I don't see the case where taking the absolute value of the expression wouldn't give you results that you can use to determine the two expressions are equivalent.
Or just think in terms of finding a way to always get the lowest non-negative member of the equivalence class.
One work around is to use ((n mod d) + d) mod d in place of n mod d. It's a bit unwieldy, but it does always give the desired (lowest non-negative) result.If this one always has your desired result, why not write your own operator "modulo"?
wouldn't evaluating "abs(n1) mod d" and "abs(n2) mod d" allow you to determine the expressions are equal?
Isn't (x mod y)*Sign sufficient to obtain number theory compliant mod? Maybe faster than ABS()..
Why must it be another operator and thus a language extension? We don't want to end up like Perl (https://www.ozonehouse.com/mark/periodic/)
Also, just thinking about the way integer division works at the asm level (at least on the x86 and x64 platforms), the native asm instruction IDIV produces quotients and remainders that are exactly consistent with the way Pascal does div and mod.
Use Math.DivMod.
<snip> Take for example n1=16 and n2=-8I understand what you're saying, what I'm saying is, do (abs(n1) mod 12) and (abs(n2) mod 12). IOW, apply the absolute to the expression whose sign isn't predictable. I believe that should do it and, I believe that using "abs" is likely to be the "cheapest" way of solving the problem.
I'm thinking that the conditional add is probably the most efficient?
I understand what you're saying, what I'm saying is, do (abs(n1) mod 12) and (abs(n2) mod 12).
I missed the point until now. I finally see what you're looking for. Makes sense.I understand what you're saying, what I'm saying is, do (abs(n1) mod 12) and (abs(n2) mod 12).
No, abs definitely doesn't do what I need here. I need for example (-20 mod 12) to be positive 4. The reason the desired result is positive 4 is because that is the smallest positive integer that differs from -20 by only multiples of 12.
If you apply abs then all you get is (abs(-20) mod 12) = (20 mod 12) = 8.
function ModuloEx(x, y: Integer): Integer; begin Result := abs(x) mod abs(y); if abs(x) <> x then Result := abs(y) - Result; end;
The following three all give the same results for all valid range of parameters.
1:156
2:125
3:218
1:156
2:125
3:218
Your modulo3 would be my choice since it is branchless. I would write it slightly different, though:
{$mode delphi}{$H+}{$I-} function modulo3(const a,b : integer) : integer;inline; // Double modulo algorithm. begin Result:=abs(b); Result := ((a mod result) + result) mod result; end; begin writeln(Modulo3(-20,12)); end.
In the CPU I have, this inplementation seems slightly faster:But this is a non-working version. For B < 0, the Result is not defined at all.
Doesn't {$modeswitch ISOMOD} do what you want?
Those involve float operations and will slow down even further. modulo operations are quite expensive. (Also note I introduced a fmod like mod operator already in 3.2.0 I have to look if that satisfies the rules suggested too. It is in math )The purpose of my example is to demonstrate the difference from a mathematical point of view in the clearest manner (trunc vs floor). It is not meant to provide the fastest solution.
Doesn't {$modeswitch ISOMOD} do what you want?
Doesn't {$modeswitch ISOMOD} do what you want?
What version of FPC implements this?
Doesn't {$modeswitch ISOMOD} do what you want?
What version of FPC implements this?
3.2 and newer.
Unfortunately, Pascal's mod does not satisfy the above property.
For example: 16 mod 12 = 4
however: (16 - 3*12) mod 12 = -8
... (should be)
(16 + abs(-3 *12)) mod 12 = 4
It seems that the "other thread" MarkMLI mentioned (but forgot to link to it) is this one: https://forum.lazarus.freepascal.org/index.php/topic,52772.msg389763.html#msg389763 (https://forum.lazarus.freepascal.org/index.php/topic,52772.msg389763.html#msg389763).