Sign in Join

Live chat for Free Pascal, Lazarus, Delphi and every Pascal programmer.

Mailing lists / fpc-devel / 2006-03

Math.DivMod results should be signed

13 messages · 8 people · –

Reply by email Subscribe to this list Your subscription

Read-only archive. Use j and k to move between messages.

Michalis Kamburelis

Hi

I'm concerned with using DivMod in cases when Dividend is < 0. DivMod declaration is

   procedure DivMod(Dividend: Integer; Divisor: Word;  var Result,
Remainder: Word);

which means that it doesn't allow for Result and Remainder to be < 0. But when Dividend is < 0, Result and/or Remainder sometimes have to be <
0. For example,

var
   UnsignedDivResult, UnsignedModResult: Word;
   DivResult: SmallInt absolute UnsignedDivResult;
   ModResult: SmallInt absolute UnsignedModResult;
begin
   DivMod(-39, 20, UnsignedDivResult, UnsignedModResult);
end;

gets me UnsignedDivResult = 65535 and UnsignedModResult = 65517. Of course when treating memory as signed values (DivResult and ModResult), I can "decipher" correct values (-1 and -19) but that's obviously unclean. Sure I can also just use "div" and "mod" operators, they always get me correct values, but I understand that doing div and mod separately may be slower than DivMod on some processors.

I know that DivMod arguments have to stay as Word for Delphi compat. But in the light of the above, it seems like a good idea to add overloaded DivMod version that returns Result and Remainder as signed values ?

Michalis

Reply by email

Vinzent Hoefler
to Michalis Kamburelis
Michalis Kamburelis wrote 7 lines
I'm concerned with using DivMod in cases when Dividend is < 0. DivMod declaration is procedure DivMod(Dividend: Integer; Divisor: Word; var Result, Remainder: Word); which means that it doesn't allow for Result and Remainder to be < 0.

Which would seem correct, if this were really a modulo-operation.

Unfortunately, DivMod should really be called DivRem, because it does not calculate the modulus, but rather the remainder of the division operation. But at least the name of the result variable suggests so.

Show quoted text 15 lines
But when Dividend is < 0, Result and/or Remainder sometimes have to be < 0. For example, var UnsignedDivResult, UnsignedModResult: Word; DivResult: SmallInt absolute UnsignedDivResult; ModResult: SmallInt absolute UnsignedModResult; begin DivMod(-39, 20, UnsignedDivResult, UnsignedModResult); end; gets me UnsignedDivResult = 65535 and UnsignedModResult = 65517. Of course when treating memory as signed values (DivResult and ModResult), I can "decipher" correct values (-1 and -19) but that's obviously unclean.

Agreed. This result proves, that on an x86 the IDIV instruction is used, which is a signed integer operation with _signed_ results. So if Delphi does it the same way, they really screwed up the interface, because then it only works correctly for non-negative Dividends and Divisors less than 32768.

Sure I can also just use "div" and "mod" operators, they always get me correct values, but I understand that doing div and mod separately may be slower than DivMod on some processors.

Yes, just because you would do exactly the same operation twice.

I know that DivMod arguments have to stay as Word for Delphi compat.

I suppose so, although it is wrong (or let's say: very restricted) anyway.

But in the light of the above, it seems like a good idea to add overloaded DivMod version that returns Result and Remainder as signed values ?

It would be, definitely. Especially because it does seem to calculate it that way.

Vinzent.

Reply by email

Unknown author
to Michalis Kamburelis: Hi I'm concerned with using DivMod in cases when Dividend is < 0. DivMod declaration is…

I just read your posting on Delphi's DivMod. It doesn't work very well, not on LongInt (Integer) values and negatives, not on Delphi 6, that I'm using, anyway.

I wrote an alternative that handles LongInt and negatives. It takes only Integer parameters. It's a function, rather than a procedure. You pass Value (the number that you will divide), Divisor by value. You pass Remainder (Mod-value) by ref, and it returns the Result (Div-Value).

It is almost as fast as DivMod, I have an alternative SmallInt-version that matches DivMod in speed, but handles negatives correctly.

function DivWithRemainder(Value, Divisor: Integer; var Remainder: Integer): Integer; {
In:
EAX = Value
ECX = @Remainder
EDX = Divisor

Out:
EAX = Result
ECX = @Remainder
}
asm
PUSH EBX { Save EBX - this register is not free to use } MOV EBX , EDX { Copy Divisor to EBX, using it as a store } TEST EAX , $80000000 { Test if Value is signed }
JNZ @Signed { If Value is negative, prepare signed EDX } MOV EDX , 0 { If Value is positive, prepare unsigned EDX (Clear it) } @Continue:
IDIV EBX { Divides Value (actually EDX + EAX (64 bit)) by EBX. Result -> EAX, remainder -> EDX } MOV [ECX], EDX { Copies EDX to ECX^ (Remainder) } POP EBX { Restore EBX }
RET
@Signed:
MOV EDX , -1 { Fill EDX with $FFFFFFFF if Value was signed } JMP @Continue
end;

This message was sent on behalf

Reply by email

Florian Klaempfl
to Unknown author
Show quoted text 25 lines
function DivWithRemainder(Value, Divisor: Integer; var Remainder: Integer): Integer; { In: EAX = Value ECX = @Remainder EDX = Divisor Out: EAX = Result ECX = @Remainder } asm PUSH EBX { Save EBX - this register is not free to use } MOV EBX , EDX { Copy Divisor to EBX, using it as a store } TEST EAX , $80000000 { Test if Value is signed } JNZ @Signed { If Value is negative, prepare signed EDX } MOV EDX , 0 { If Value is positive, prepare unsigned EDX (Clear it) } @Continue: IDIV EBX { Divides Value (actually EDX + EAX (64 bit)) by EBX. Result -> EAX, remainder -> EDX } MOV [ECX], EDX { Copies EDX to ECX^ (Remainder) } POP EBX { Restore EBX } RET @Signed: MOV EDX , -1 { Fill EDX with $FFFFFFFF if Value was signed } JMP @Continue

Is this really faster than using CDQ?

Reply by email

Kai Olav Fredriksen
to Florian Klaempfl: Is this really faster than using CDQ?

Thanks for CDQ info, I didn't know it existed :)

I just made the algotithm because I needed speedy div and mod, that could handle signed and unsigned Int32, also with a Int32 as divisor. And the one in Delphi6/7 doesn't do that.
I haven't used assembler since 1985 on a Dragon32, so I have a lot to catch up with.

It might be that it could be a lot better, I hope someone could tell me how. But as it is now, it runs about 90% faster than using div and then mod in Delphi code.

Kai

Earlier message 47 lines
----- Original Message ----- From: "Florian Klaempfl" To: ; "FPC developers' list" Sent: Thursday, November 09, 2006 8:42 AM Subject: Re: [fpc-devel] Math.DivMod results should be signed >> function DivWithRemainder(Value, Divisor: Integer; var Remainder: >> Integer): Integer; >> { >> In: >> EAX = Value >> ECX = @Remainder >> EDX = Divisor >> >> Out: >> EAX = Result >> ECX = @Remainder >> } >> asm >> PUSH EBX { Save EBX - this register is not free to use } >> MOV EBX , EDX { Copy Divisor to EBX, using it as a store } >> TEST EAX , $80000000 { Test if Value is signed } >> JNZ @Signed { If Value is negative, prepare signed EDX } >> MOV EDX , 0 { If Value is positive, prepare unsigned EDX >> (Clear it) } >> @Continue: >> IDIV EBX { Divides Value (actually EDX + EAX (64 bit)) by >> EBX. Result -> EAX, remainder -> EDX } >> MOV [ECX], EDX { Copies EDX to ECX^ (Remainder) } >> POP EBX { Restore EBX } >> RET >> @Signed: >> MOV EDX , -1 { Fill EDX with $FFFFFFFF if Value was signed } >> JMP @Continue > > Is this really faster than using CDQ? > > > > -- > No virus found in this incoming message. > Checked by AVG Free Edition. > Version: 7.1.409 / Virus Database: 268.14.0/524 - Release Date: 08.11.2006 > >

Reply by email

Peter Vreman
to Kai Olav Fredriksen: Thanks for CDQ info, I didn't know it existed :) I just made the algotithm because I…
Show quoted text 14 lines
Thanks for CDQ info, I didn't know it existed :) I just made the algotithm because I needed speedy div and mod, that could handle signed and unsigned Int32, also with a Int32 as divisor. And the one in Delphi6/7 doesn't do that. I haven't used assembler since 1985 on a Dragon32, so I have a lot to catch up with. It might be that it could be a lot better, I hope someone could tell me how. But as it is now, it runs about 90% faster than using div and then mod in Delphi code.

If you need both the div and mod you can use a single divsion and subtraction:

oldval:=value
divval:=value div divider
modval:=oldval-divval

This will work on all platforms and normally the oldval can be kept in a register.

Reply by email

Kai Olav Fredriksen
to Florian Klaempfl: Is this really faster than using CDQ?

It got beautiful with CDQ. And faster, more than twice as fast as using div then mod (in my environment)

function DivWithRemainder(Value, Divisor: Integer; out Remainder: Integer): Integer;
{In:
EAX = Value
EDX = Divisor

Out:
EAX = Result
ECX = @Remainder}
asm
PUSH EBX { Save EBX - this register is not free to use } MOV EBX , EDX { Copy Divisor to EBX, using it as a store } CDQ { Convert EAX to 64-bit EDX:EAX } IDIV EBX { Divides Value (actually EDX:EAX)) by EBX. Result -> EAX, remainder -> EDX }
MOV [ECX], EDX { Copies EDX to ECX^ (Remainder) } POP EBX { Restore EBX }
end;

Earlier message 16 lines
----- Original Message ----- From: "Florian Klaempfl" To: ; "FPC developers' list" Sent: Thursday, November 09, 2006 8:42 AM Subject: Re: [fpc-devel] Math.DivMod results should be signed > Is this really faster than using CDQ? > > > > -- > No virus found in this incoming message. > Checked by AVG Free Edition. > Version: 7.1.409 / Virus Database: 268.14.0/524 - Release Date: 08.11.2006 > >

Reply by email

Unknown author
to Peter Vreman: If you need both the div and mod you can use a single divsion and subtraction:…

of course... :) it lost 2 milliseconds on the assembly code in 100 million iterations. Thank you Peter and Daniël

Kai

-- Peter Vreman wrote :
If you need both the div and mod you can use a single divsion and subtraction:

oldval:=value
divval:=value div divider
modval:=oldval-divval

This will work on all platforms and normally the oldval can be kept in a register.

Reply by email