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

View File

@ -2221,33 +2221,71 @@ end;
{$ifndef FPC_MATH_HAS_DIVMOD} {$ifndef FPC_MATH_HAS_DIVMOD}
procedure DivMod(Dividend: Integer; Divisor: Word; var Result, Remainder: Word); procedure DivMod(Dividend: Integer; Divisor: Word; var Result, Remainder: Word);
begin begin
Result:=Dividend Div Divisor; if Dividend < 0 then
Remainder:=Dividend -(Result*Divisor); 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; end;
procedure DivMod(Dividend: Integer; Divisor: Word; var Result, Remainder: SmallInt); procedure DivMod(Dividend: Integer; Divisor: Word; var Result, Remainder: SmallInt);
var
UnsignedResult: Word absolute Result;
UnsignedRemainder: Word absolute Remainder;
begin 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; end;
procedure DivMod(Dividend: DWord; Divisor: DWord; var Result, Remainder: DWord); procedure DivMod(Dividend: DWord; Divisor: DWord; var Result, Remainder: DWord);
begin begin
Result:=Dividend Div Divisor; Result:=Dividend Div Divisor;
Remainder:=Dividend -(Result*Divisor); Remainder:=Dividend-(Result*Divisor);
end; end;
procedure DivMod(Dividend: Integer; Divisor: Integer; var Result, Remainder: Integer); procedure DivMod(Dividend: Integer; Divisor: Integer; var Result, Remainder: Integer);
var
UnsignedResult: DWord absolute Result;
UnsignedRemainder: DWord absolute Remainder;
begin 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; end;
{$endif FPC_MATH_HAS_DIVMOD} {$endif FPC_MATH_HAS_DIVMOD}

View File

@ -1,3 +1,4 @@
{$mode objfpc}
uses uses
math; math;
{ tests: { tests:
@ -55,5 +56,18 @@ begin
doerror(3003); doerror(3003);
if RemainderInteger<>15 then if RemainderInteger<>15 then
doerror(3004); 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. end.