Algorithmensammlung: Zahlentheorie: Signum

Algorithmensammlung: Zahlentheorie

Die Signum-Funktion („ Vorzeichenfunktion“) ist definiert als

CBearbeiten

Der GCC 10.1 erzeugt ab Intel Core2 / AMD K8 (Athlon 64) und eingeschalteter Optimierung (außer -Os) aus folgender Funktion Code ohne Sprünge (branchless code):

int sign(int num)
{
  if(num > 0){
    return 1;
  } 
  else if(num < 0){
    return -1;
  }
  else{
    return 0;
  }
}

FreePascalBearbeiten

FreePascal liefert in math.sign bereits eine Signumfunktion mit.

type
	signumCodomain = -1..1;
 
{**
	returns the sign of an integer
	
	\param x the integer to inspect
	\return 1 on positive integers, 0 on zero,
	        and -1 on negative integers
}
function signum({$ifndef CPUx86_64} const {$endif} x: longint): signumCodomain;
{$ifdef CPUx86_64}
assembler;
{$asmMode intel}
asm
	xor rax, rax         // ensure result is not wrong, because of residue
	
	test x, x            // x = 0 ?
	setnz al             // al := not ZF
	
	sar x, 63            // propagate sign-bit throughout register
	cmovs rax, x         // if SF then rax := -1
end;
{$else}
begin
	// This is what virtually math.sign does.
	// The compiled code requires _two_ cmp instructions, though. 
	if x > 0 then
	begin
		signum := 1;
	end
	else if x < 0 then
	begin
		signum := -1;
	end
	else
	begin
		signum := 0;
	end;
end;
{$endif}

Generell will man die test-Instruktion nutzen. Während die cmp-Instruktion tatsächlich rechnet, also einen Tucken länger braucht, ist die test-Instruktion ein banales and, anhanddessen Ergebnis die Flaggen gesetzt werden. Zudem kommt die asm-Implementation ohne Sprünge aus, was der BPU (“branch prediction unit”) zugute kommt.