Sti*_*ers 7 delphi math inline-assembly basm
如果我这样做
var
a,b,c:cardinal;
begin
a:=$80000000;
b:=$80000000;
c:=a+b;
end;
Run Code Online (Sandbox Code Playgroud)
c将等于0,因为加法溢出.捕获这个溢出的布尔值的最佳方法是什么?(a+b<a) or (a+b<b)?一个非常好的方法是使用内联汇编程序,但我不是那么多的汇编程序(虽然我猜它会包含类似的内容JO)
在汇编中,该术语Overflow通常指有符号算术,意味着总和的符号与两个操作数的符号不同; 对于无符号算术,该术语Carry是优选的.
你可以在pure pascal中使用Overflow(Carry)检查来实现添加:
// signed add - returns True if no overflow produced
function SAdd(A, B: integer; out C: integer): Boolean;
begin
C:= A + B;
Result:= (A xor B < 0) // operands have different signs
or (C xor A >= 0); // sum has the same sign as operands
end;
// unsigned add - returns True if no carry produced
function UAdd(A, B: Cardinal; out C: Cardinal): Boolean;
begin
C:= A + B;
Result:= (C >= A);
end;
Run Code Online (Sandbox Code Playgroud)
装配中的相同功能 - Andreas解决方案的优化变体:
// Signed Add
function SAdd(A, B: Integer; out C: Integer): Boolean;
asm
ADD EAX,EDX
MOV [ECX],EAX
SETNO AL
end;
// Unsigned Add
function UAdd(A, B: Cardinal; out C: Cardinal): Boolean;
asm
ADD EAX,EDX
MOV [ECX],EAX
SETNC AL
end;
Run Code Online (Sandbox Code Playgroud)
我也不是集会专家,但我认为这有效:
签名版本:
function TryAdd(a, b: integer; out c: integer): boolean;
asm
ADD EAX, EDX // EAX := a + b;
MOV [c], EAX // c := EAX;
JO @@END // if overflow goto end;
MOV EAX, true // result := true
RET // Exit;
@@END:
XOR EAX, EAX // result := false;
end;
procedure TForm1.Button1Click(Sender: TObject);
var
c: integer;
begin
if TryAdd(MaxInt - 5, 6, c) then
ShowMessage(IntToHex(c, 8))
else
ShowMessage('Overflowed!');
end;
Run Code Online (Sandbox Code Playgroud)
未签名版本:
function TryAdd(a, b: cardinal; out c: cardinal): boolean;
asm
ADD EAX, EDX // EAX := a + b;
MOV [c], EAX // c := EAX;
JC @@END // if overflow goto end;
MOV EAX, true // result := true
RET // Exit;
@@END:
XOR EAX, EAX // result := false;
end;
procedure TForm1.Button1Click(Sender: TObject);
var
c: cardinal;
begin
if TryAdd($A0000000, $C0000000, c) then
ShowMessage(IntToHex(c, 8))
else
ShowMessage('Overflowed!');
end;
Run Code Online (Sandbox Code Playgroud)
Andreas 在纯 pascal 中的解决方案(在评论中建议使用固定的 TryAdd)。
function TryAdd(a, b: integer; out c: integer): boolean; overload;
var
sum: int64;
begin
sum := int64(a) + int64(b);
Result := (Low(integer) <= sum) and (sum <= High(integer));
c := integer(Int64Rec(sum).Lo);
end;
function TryAdd(a, b: cardinal; out c: cardinal): boolean; overload;
var
sum: int64;
begin
sum := int64(a) + int64(b);
Result := sum <= High(cardinal);
c := Int64Rec(sum).Lo;
end;
procedure TForm32.Button1Click(Sender: TObject);
var
c: integer;
begin
if TryAdd(MaxInt - 5, 6, c) then
ShowMessage(IntToHex(c, 8))
else
ShowMessage('Overflowed!');
end;
Run Code Online (Sandbox Code Playgroud)