// Es bestand die Aufgabe von mehreren hundert überlangen Strings
//
(welche Ziffern enthalten), die jeweilige nichtalternierende (einfache)
// Quersumme zu ermitteln. Außerdem sollte festgestellt werden, ob
// ein String fälschlicherweise leer ist oder Zeichen unterhalb von
// "0" bzw. oberhalb von "9" enthält. Das ganze sollte so schnell
// wie möglich von statten gehen.
// Die schnellste Methode, die ich ausgeknobelt habe, ist folgende:


// Getestet mit D2010 unter W7

function QuerSumme(s: PWideChar): integer; 
asm 
  test eax, eax 
  jz @leer 
  mov edx, eax 
  xor eax, eax 
  xor ecx, ecx 
 @loop: 
  mov cl, [edx] 
  jecxz @raus 
  cmp cl, 48 
  jl @zuklein 
  cmp cl, 57 
  jg @zugross 
  add eax, ecx 
  sub eax, 48 
  add edx, 2    // inc edx falls "s" kein WideChar
  jmp @loop 
 @leer: 
  mov eax, -1 
  jmp @raus 
 @zuklein: 
  mov eax, -2 
  jmp @raus 
 @zugross: 
  mov eax, -3 
 @raus: 
  mov @result, eax     
end; 
 
// Beispielaufruf (zugegebenermaßen mit einem kurzen String) 
 
procedure TForm1.Button11Click(Sender: TObject); 
var 
  i: integer; 
  s: string; 
begin 
  s := '13634092364834527633130104834523263746107343928251190912'; 
  i := QuerSumme(PWideChar(s)); 
  case i of 
    -1: raise exception.create('String ist leer'); 
    -2: raise exception.create('Zeichen unterhalb von "0"'); 
    -3: raise exception.create('Zeichen oberhalb von "9"'); 
  else showmessage('Quersumme: ' + inttostr(i));              // 211
  end; 
end;

// ------------------------------------------------------------


// Hier noch eine Möglichkeit die alternierende Quersumme zu ermitteln:

function aQuerSumme(const s: string): integer; 
var x, y, i: integer; 
begin 
  if s = '' then result := -maxint else begin 
    result := 0; 
    y := 1; 
    for x := length(s) downto 1 do begin 
      i := ord(s[x]) - 48; 
      if i < 0 then begin 
        result := 1 - maxint; 
        exit; 
      end; 
      if i > 9 then begin 
        result := 2 - maxint; 
        exit; 
      end; 
      if odd(y) then 
        result := i mod 10 + result else 
        result := result - i; 
      inc(y); 
    end; 
  end; 
end; 
 
// Beispielaufruf 
 
procedure TForm1.Button1Click(Sender: TObject); 
var 
  i: integer; 
  s: string; 
begin 
  s := '13634092364834527633130104834523263746107343928251190192'; 
  i := aQuerSumme(s); 
  case i of 
    -maxint: raise exception.create('String ist leer'); 
    1 - maxint: raise exception.create('Zeichen unterhalb von "0"'); 
    2 - maxint: raise exception.create('Zeichen oberhalb von "9"'); 
  else showmessage('Alternierende Quersumme: ' + inttostr(i));        // -15 
  end; 
end;

// ------------------------------------------------------------


// Und hier noch eine Möglichkeit, wie man aus der nichtalternierenden
//
(einfachen) Quersumme die einstellige Quersumme bilden kann. Dafür
// wird die Funktion "QuerSumme" aus dem ersten Beispiel benutzt.

function eQuerSumme(const s: string): integer; 
var 
  i: integer; 
begin 
  result := QuerSumme(s); 
  if result > 0 then 
    while result > 9 do 
      result := QuerSumme(inttostr(result)); 
end; 
 
// Beispielaufruf 
 
procedure TForm1.Button11Click(Sender: TObject); 
var 
  i: integer; 
  s: string; 
begin 
  s := '13634092364834527633130104834523263746107343928251190912'; 
  i := eQuerSumme(s); 
  case i of 
    -1: raise exception.create('String ist leer'); 
    -2: raise exception.create('Zeichen unterhalb von "0"'); 
    -3: raise exception.create('Zeichen oberhalb von "9"'); 
  else showmessage('Einstellige Quersumme: ' + inttostr(i));         // 4
  end; 
end;

// ------------------------------------------------------------


// Um das ganze abzurunden, hier noch die Quersummenbildung aus Zahlen:

function EinfacheQuersumme(zahl: cardinal): word; 
begin 
  result := 0; 
  while zahl > 0 do begin 
    result := result + zahl mod 10; 
    zahl := zahl div 10; 
  end; 
end; 
 
function IterierteQuersumme(zahl: cardinal): word; 
begin 
  while zahl >= 10 do begin 
    result := 0; 
    while zahl > 0 do begin 
      result := result + zahl mod 10; 
      zahl := zahl div 10; 
    end; 
    zahl := result; 
  end; 
  result := zahl; 
end; 
 
function AlternierendeQuerSumme(zahl: integer): integer; 
var x: integer; 
begin 
  result := 0; 
  x := 1; 
  while zahl > 0 do begin 
    if odd(x) then 
      result := zahl mod 10 + result else 
      result := result - zahl mod 10; 
    zahl := zahl div 10; 
    x := x xor 1; 
  end; 
end; 
 
 
// Beispielaufruf 
 
procedure TForm1.Button1Click(Sender: TObject); 
var 
  i, s: integer; 
begin 
  s := 9791; 
  i := AlternierendeQuerSumme(s); 
  showmessage(inttostr(i));                // -10 
end; 


 

Zugriffe seit 6.9.2001 auf Delphi-Ecke