* fixes i386 DivMod with negative numbers with a patch from Jonas
* fixes generic DivMod with negative numbers
* test updated

git-svn-id: trunk@14532 -
This commit is contained in:
florian 2010-01-03 14:59:01 +00:00
parent a8a332e029
commit 31e2f16484
3 changed files with 82 additions and 31 deletions

View File

@ -61,29 +61,27 @@ function cotan(x : float) : float;assembler;
{$define FPC_MATH_HAS_DIVMOD}
procedure DivMod(Dividend: Integer; Divisor: Word; var Result, Remainder: Word);assembler;
asm
pushw %di
movw %dx,%di
movl %eax,%edx
shrl $16,%edx
div %di
movw %ax,(%ecx)
movl Remainder,%ecx
movw %dx,(%ecx)
popw %di
pushl %edi
movzwl %dx,%edi
cltd
idiv %edi
movw %ax,(%ecx)
movl Remainder,%ecx
movw %dx,(%ecx)
popl %edi
end;
procedure DivMod(Dividend: Integer; Divisor: Word; var Result, Remainder: SmallInt);assembler;
asm
pushw %di
movw %dx,%di
movl %eax,%edx
shrl $16,%edx
div %di
movw %ax,(%ecx)
movl Remainder,%ecx
movw %dx,(%ecx)
popw %di
pushl %edi
movzwl %dx,%edi
cltd
idiv %edi
movw %ax,(%ecx)
movl Remainder,%ecx
movw %dx,(%ecx)
popl %edi
end;
@ -92,7 +90,7 @@ asm
pushl %edi
movl %edx,%edi
xorl %edx,%edx
div %edi
div %edi
movl %eax,(%ecx)
movl Remainder,%ecx
movl %edx,(%ecx)
@ -104,7 +102,7 @@ procedure DivMod(Dividend: Integer; Divisor: Integer; var Result, Remainder: Int
asm
pushl %edi
movl %edx,%edi
xorl %edx,%edx
cltd
idiv %edi
movl %eax,(%ecx)
movl Remainder,%ecx
@ -112,6 +110,7 @@ asm
popl %edi
end;
function GetRoundMode: TFPURoundingMode;
begin
Result := TFPURoundingMode((Get8087CW shr 10) and 3);

View File

@ -2221,33 +2221,71 @@ end;
{$ifndef FPC_MATH_HAS_DIVMOD}
procedure DivMod(Dividend: Integer; Divisor: Word; var Result, Remainder: Word);
begin
Result:=Dividend Div Divisor;
Remainder:=Dividend -(Result*Divisor);
if Dividend < 0 then
begin
{ Use DivMod with >=0 dividend }
Dividend:=-Dividend;
{ The documented behavior of Pascal's div/mod operators and DivMod
on negative dividends is to return Result closer to zero and
a negative Remainder. Which means that we can just negate both
Result and Remainder, and all it's Ok. }
Result:=-(Dividend Div Divisor);
Remainder:=-(Dividend+(Result*Divisor));
end
else
begin
Result:=Dividend Div Divisor;
Remainder:=Dividend-(Result*Divisor);
end;
end;
procedure DivMod(Dividend: Integer; Divisor: Word; var Result, Remainder: SmallInt);
var
UnsignedResult: Word absolute Result;
UnsignedRemainder: Word absolute Remainder;
begin
DivMod(Dividend, Divisor, UnsignedResult, UnsignedRemainder);
if Dividend < 0 then
begin
{ Use DivMod with >=0 dividend }
Dividend:=-Dividend;
{ The documented behavior of Pascal's div/mod operators and DivMod
on negative dividends is to return Result closer to zero and
a negative Remainder. Which means that we can just negate both
Result and Remainder, and all it's Ok. }
Result:=-(Dividend Div Divisor);
Remainder:=-(Dividend+(Result*Divisor));
end
else
begin
Result:=Dividend Div Divisor;
Remainder:=Dividend-(Result*Divisor);
end;
end;
procedure DivMod(Dividend: DWord; Divisor: DWord; var Result, Remainder: DWord);
begin
Result:=Dividend Div Divisor;
Remainder:=Dividend -(Result*Divisor);
Remainder:=Dividend-(Result*Divisor);
end;
procedure DivMod(Dividend: Integer; Divisor: Integer; var Result, Remainder: Integer);
var
UnsignedResult: DWord absolute Result;
UnsignedRemainder: DWord absolute Remainder;
begin
DivMod(Dividend, Divisor, UnsignedResult, UnsignedRemainder);
if Dividend < 0 then
begin
{ Use DivMod with >=0 dividend }
Dividend:=-Dividend;
{ The documented behavior of Pascal's div/mod operators and DivMod
on negative dividends is to return Result closer to zero and
a negative Remainder. Which means that we can just negate both
Result and Remainder, and all it's Ok. }
Result:=-(Dividend Div Divisor);
Remainder:=-(Dividend+(Result*Divisor));
end
else
begin
Result:=Dividend Div Divisor;
Remainder:=Dividend-(Result*Divisor);
end;
end;
{$endif FPC_MATH_HAS_DIVMOD}

View File

@ -1,3 +1,4 @@
{$mode objfpc}
uses
math;
{ tests:
@ -55,5 +56,18 @@ begin
doerror(3003);
if RemainderInteger<>15 then
doerror(3004);
DivMod(-9, 5, QuotientInteger,RemainderInteger);
if QuotientInteger<>-1 then
doerror(3005);
if RemainderInteger<>-4 then
doerror(3006);
DivMod(-9, -5, QuotientInteger,RemainderInteger);
if QuotientInteger<>1 then
doerror(3007);
if RemainderInteger<>-4 then
doerror(3008);
end.