function ModuloEx(x, y: Integer): Integer;
begin
Result := abs(x) mod abs(y);
if abs(x) <> x then Result := abs(y) - Result;
end;
Thanks Frank.
You algorithm nearly works, but it does fail for some cases where the result should be zero. I have fixed that below.
For my current application I'm not really interested in negative values of the second parameter.
However I can confirm that your modulo function (after fixing the one bug) does work correctly and is equivalent to doing modulo(x,abs(y)) for either of my two proposed algorithms. (Those being either the double modulo or the conditional add methods that I outlined previously).
The following three all give the same results for all valid range of parameters.
function modulo1(a,b : integer) : integer; // Frank's algorithm (fixed).
begin
Result := abs(a) mod abs(b);
if (a < 0) and (Result<>0) then Result := abs(b) - Result;
end;
function modulo2(a,b : integer) : integer; // Conditional add algorithm.
begin
b:=abs(b);
Result := a mod b;
if a<0 then Result := Result + b;
end;
function modulo3(a,b : integer) : integer; // Double modulo algorithm.
begin
b:=abs(b);
Result := ((a mod b) + b) mod b;
end;
Notes.
- As well as the fix, I also modified your code to compare
a<0 rather than
abs(a)<>a. It's the same thing but I think the first one is a bit more transparent.
- At present my algorithms (modulo2 and modulo3) don't really include the line
b:=abs(b) (because I'm not using any negatives in the second parameter), but I just included them here to make it a fair comparison to your algorithm.