Autor Beitrag
Mathematiker
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 2622
Erhaltene Danke: 1448

Win 7, 8.1, 10
Delphi 5, 7, 10.1
BeitragVerfasst: So 12.08.12 18:09 
Hallo,
nachdem Lelf sein superschnelles Faktorisierungsprogramm hier www.entwickler-ecke....ewtopic.php?t=109998 veröffentlichte, habe ich versucht den Quelltext unter Delphi 5 zu compilieren.
Dabei ist eine kuriose Situaton entstanden. In der UVarInt_Q tritt am Ende der 2.Prozedur sqroot

ausblenden volle Höhe Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76:
77:
78:
79:
80:
81:
82:
83:
84:
85:
86:
87:
88:
89:
90:
91:
92:
93:
94:
95:
96:
97:
98:
99:
100:
101:
102:
103:
104:
105:
106:
107:
108:
109:
110:
111:
112:
113:
114:
115:
116:
117:
118:
119:
120:
121:
122:
123:
124:
125:
126:
127:
128:
129:
130:
131:
132:
133:
134:
135:
136:
137:
138:
139:
140:
141:
142:
143:
144:
145:
146:
147:
148:
149:
150:
151:
152:
153:
154:
155:
156:
157:
158:
159:
160:
161:
162:
163:
164:
165:
166:
167:
168:
169:
170:
171:
172:
173:
174:
175:
176:
177:
178:
179:
180:
181:
182:
183:
184:
185:
186:
187:
188:
189:
190:
191:
192:
193:
194:
195:
196:
197:
198:
199:
200:
201:
202:
203:
204:
205:
206:
207:
208:
209:
210:
211:
212:
213:
214:
215:
216:
217:
218:
219:
220:
221:
222:
223:
224:
225:
226:
227:
  function TVarInt.Sqroot: boolean;
  var qRest: TVarInt;
  begin
    qRest:= TVarInt.Create;
    try
      self.Sqroot(qRest);
      result:=(qRest.RLen = 0);
    finally
      qRest.Free;
    end;
  end;

  function TVarInt.Sqroot(var qREM: TVarInt; mitRest: boolean=false): boolean;
  var
    xNorm, xBit, x: integer;
    q4, {a3,} aL, xrem, w: int64;
    a3Ext, q4Ext: Extended;
    j, hQ: integer;
    i, n, m, q: integer;
    qminREM: TDig_V;
    aC, qDivisor, spSelf: TVarInt;
  //-----------
      procedure product(var x, y: TDig_V; f, a: integer); //x = y*f
      var i,j: integer;
        temp, carry: int64;
      begin
        carry:=0; j:=a + a;
        for i:=a to a + m -1 do begin
          temp:=int64(y[i])*f + carry;
          carry:=temp shr LOGBASE_V;
          x[j]:=temp and MODMASK_V; //temp - (carry shl LOGBASE_V); //
          j:=j+1;
        end;
         x[j]:=carry;
         x[j+1]:=0;
      end;
  //-----------
      procedure differenz(var x, y: TDig_V; k, a: integer); //x = x-y
      var i: integer;                                       //x > y
      begin
        for i:=k to k + a do begin
          if(x[i] >= y[i])then
            x[i]:=x[i] - y[i]
          else begin
            x[i]:=x[i] or BASE_V - y[i];
            y[i+1]:=y[i+1] + 1;
          end;
        end;
      end;
  //-----------
      procedure add(var x: TDig_V; k, a: integer); //x = x+k
      begin
        x[a]:=x[a] + k;
        if(x[a] and BASE_V <> 0)then begin
          while(x[a] and BASE_V <> 0)do begin
            x[a]:=x[a] - BASE_V; //and MODMASK_V; //
            a:=a + 1;
            x[a]:=x[a] + 1;
          end;
        end;
      end;
  //-----------
      function Compare(var i1, i2: TDig_V; a, b:integer): boolean;
      var i: integer;                                       //true, wenn i1 > i2
      begin
        result:=false;
        for i:=a + b downto a do begin
          if i1[i] < i2[i] then
            exit
          else
            if i1[i] > i2[i] then begin
              result:=true; exit;
            end;
        end;
      end;
  //------------
    procedure anpassenW;
    begin
      qDivisor.RNum[hQ shr 1]:=w;
      product(qminREM, qDivisor.RNum, w, hQ shr 1);//qminREM = qDivisor.RNum * w
    end;
  //------------
  begin
    if not(RSig)then begin    //wie Wurzelziehen von Hand
     // raise ERangeError.Create(' Radikant darf nicht negativ sein! (TVarInt.Sqroot)');
     // Erg.Fehler(111); 12060478383186831971436118892604006569990026212581001918540970352126506291069610672437
      result:=false;
    end
    else begin
      IF(self.isInt64)THEN BEGIN //if(RLen < 3)
        self.ConvertToInt64(aL);
        w:=trunc(Sqrt(aL/1));
        xrem:=aL - int64(w*w);   //qREM
        self.ToVar(w);
        qREM.ToVar(xrem);
        result:=(xrem = 0);
      END
      ELSE BEGIN
        a3Ext:=0// a3:=0;
       // uTest:=0;
        xNorm:=0;
        qDivisor:=TVarInt.Create;
        qREM.Assign(self);  //direkt Weitergeben an qREM

        if(qREM.RLen mod 2 = 1)then begin //wenn self.RLen ungerade
          qREM.LeftShiftbyBASE(1);
          xNorm:=xNorm + 15;             //qREM.RLen immer gerade machen
        end;

        xBit:=GetHighestBitIndex30(qREM.RNum[qREM.RLen-1]);  //highest digit
        case xBit of
           0..25begin
                    x:=(27 - xBit) shr 1;
                    xNorm:=xNorm + x;
                    qREM.LeftShift(x shl 1);
                  end;
          2627: ;
          else
            xNorm:=xNorm + 29;     //ab (2^28) wird qDivisor > BASE_V
            qREM.LeftShift(58);
            //qREM.RightShift(2);
            //xNorm:=xNorm -1;   //schwieriger zu realisieren
        end;
  //jetzt ist highest digit 2^26 .. (2^28)-1  und qREM.RLen gerade
                    //67 108 864 .. 268 435 455  optimal; wenige Korrekturen

        hQ:=qREM.RLen -1//high(FNumber);                  //[hQ --> ungerade]
        aL:=int64(qREM.RNum[hQ]);    //die 2 ersten self-Ziffern convertieren !!
        aL:=aL shl LOGBASE_V + int64(qREM.RNum[hQ-1]);

        w:=trunc(Sqrt(aL/1));     //1.Ergebnis-FNum der Länge 1
        qDivisor.ToVar(w + w);//doppeltes, 1.Ergebnis muss ebenso 1 lang sein

        xrem:=aL - int64(w*w);      //1.qREM
//in sehr seltenen Fällen wird xrem < 0, was eigentlich nicht sein dürfte.
//Ursache ist eine fehlerhafte Berechnung von trunc(Sqrt(aL/1)): trunced- Fehler
//bei z.B. sqrt(288230376151711743) = 536870911,999999999068677
//                                --> 536870912, anstatt 536870911
//dieses Phänomen tritt nur bei bestimmten Aktionen auf wie z.B. Memo1.MouseDown
if(xrem < 0)then begin
 // showMessage('Rundungs-FEHLER bei Sqrt-Berechnung wird behoben: bitte OK drücken.');
  w:=w -1;
  qDivisor.RNum[0]:=w + w;
  qDivisor.RNum[1]:=0;
  xrem:=aL - int64(w*w);
end;

        aC:=TVarInt.Create(xrem);  //aC --> qREM
        SetLength(qminREM, hQ+1);


//Aufbereitung von qREM:
        for j:=hQ-1 to hQ do            //die 2 ersten Ziffern in qREM -->
          qREM.RNum[j]:=aC.RNum[j+1-hQ];       //--> ersetzen von 2 Ziffern aC

        q:=(hQ + 1)shr 1;
        qDivisor.LenTest(q);
        qDivisor.LeftShiftbyBASE(q -1);

spSelf:= TVarInt.Create(self);
        RLen:=q;
        RNum[q-1]:=w; // shr LOGBASE; //div BASE;  //1.Ergebnis-Ziffer
        TRY
          dec(hQ, 2);
          n:=hQ + 1;  //Length(self.FNum); //n immer gerade
          m:=1//Length(qDivisor.FNum);  //m anfangs immer Länge 1, wegen *****
          WHILE(hQ > 0)DO BEGIN   //Berechnung
            n:=n - 2;
            m:=m + 1;
            if(m < 4)then begin   //nur die ersten 2 Durchgänge
                      //a3:=qDivisor.RNum[q-1];
              a3Ext:=qDivisor.RNum[q-1] + qDivisor.RNum[q-2]/BASE_V
            end;
            q4:=0;
            for i:=n + m downto n + m -1 do
              q4:=q4 shl LOGBASE_V + qREM.RNum[i];

            q4Ext:=q4 + qREM.RNum[n+m-2]/BASE_V;
                      //w:=q4 div a3; //Probedivision
            w:=trunc(q4Ext/a3Ext);
            if(w = 0)then begin
              RNum[hQ shr 1]:=0;
              hQ:=hQ - 2;
              continue;
            end;
            if(w >= BASE_V)then     //+1198898461484465545599392243
              w:=high(TBase_V);
            anpassenW;
            while(Compare(qminREM, qREM.RNum, n, m))do begin //Korrektur nötig
              w:= w -1//inc(uTest);
              anpassenW;
            end;
            differenz(qREM.RNum, qminREM, n, m);
            RNum[hQ shr 1]:=w;              //weitere Ergebnis-RNums
            hQ:=hQ - 2;
            add(qDivisor.RNum, w, q - m);  //oder doppeltes, bisheriges Ergebnis
          END;

          if(xNorm > 0)then
            self.RightShift(xNorm);

          qREM.Trim;
          result:=(qREM.RLen = 0);  //max 2*Ergebnis

          if(not result)and(mitRest)then //qRest braucht nur dann berechnet zu werden,
            if(xNorm > 0)then begin //...wenn er tatsächlich verlangt wird(mitRest=true)
              xNorm:=xNorm shl 1;
              if(qREM.isSelf_mod_2k_ZERO(xNorm))then begin  //qREM durch xNorm teilbar ?
                qREM.RightShift(xNorm);
              end
              else begin
                aC.Assign(self);
                aC.Square;
                qREM.Sub(spSelf, aC);
              end;
            end;

        FINALLY
          aC.Free;
          qDivisor.Free;
         // if(assigned(spSelf))then
            spSelf.Free;
//hier tritt der Fehler auf !!!!!!!!!!!!!!!!!
        END;
      END;
    end;
  end;

der "Interne Fehler C1093" auf. Was dieser Fehler bedeutet, weiß ich nicht, und im WWW habe ich auch nur Kryptisches gefunden.
Das Kuriose ist nun: Compiliere ich Lelfs Text anschließend noch einmal, ohne etwas zu ändern, dann geht es, geschätzt, in 20% der Fälle. Das Einfügen oder Ändern eines Kommentars, ja selbst ein einzelnes Leerzeichen führt zum Fehler C1093. Sofortiges neues Übersetzen funktioniert beim 3., 4.Fall oder erst, wenn ich die Änderung rückgängig gemacht habe. :nut:
Hat jemand eine Ahnung, was hier los ist? Ich bin absolut ratlos.
Lelf vermutet, dass es an meinem Delphi 5 liegt, aber es geht ja manchmal. Weiterhin hat Delphi_Laie vollkommen richtig darauf hingewiesen, das der Compiler deterministisch ist. Und alle anderen Programme lassen sich weiterhin problemlos übersetzen.
Beste Grüße
ein verzweifelnder Mathematiker :eyecrazy:

_________________
Töten im Krieg ist nach meiner Auffassung um nichts besser als gewöhnlicher Mord. Albert Einstein


Zuletzt bearbeitet von Mathematiker am So 12.08.12 23:11, insgesamt 1-mal bearbeitet
Martok
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 3661
Erhaltene Danke: 604

Win 8.1, Win 10 x64
Pascal: Lazarus Snapshot, Delphi 7,2007; PHP, JS: WebStorm
BeitragVerfasst: So 12.08.12 20:45 
Der Compiler ist zwar theoretisch deterministisch, aber nicht bugfrei. Interner Fehler bedeutet meistens, dass im Compiler eine Exception aufgetreten ist, eine Assertion fehlgeschlagen ist oder sonstige Späße.
Sehr gerne passiert das auch, wenn sich der Optimizer ausmanövriert hat.

Im Zweifelsfall solange Delphi neustarten bis es funktioniert.

Sowas finde ich immer noch besser, als wenn direkt falscher Code generiert wird ;) Da hab ich nämlich gestern eine Sache in D7 gefunden, wo reproduzierbar Blödsinn generiert wird. Habs aber grad mal in XE getestet, da haut das wieder hin.

_________________
"The phoenix's price isn't inevitable. It's not part of some deep balance built into the universe. It's just the parts of the game where you haven't figured out yet how to cheat."

Für diesen Beitrag haben gedankt: Mathematiker
Mathematiker Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 2622
Erhaltene Danke: 1448

Win 7, 8.1, 10
Delphi 5, 7, 10.1
BeitragVerfasst: So 12.08.12 21:51 
Hallo Martok,
user profile iconMartok hat folgendes geschrieben Zum zitierten Posting springen:
Sehr gerne passiert das auch, wenn sich der Optimizer ausmanövriert hat.

Genau das ist es! :zustimm: Ich habe die Codeoptimierung abgeschaltet und schon ist alles wieder ok.
Besten Dank
Mathematiker

_________________
Töten im Krieg ist nach meiner Auffassung um nichts besser als gewöhnlicher Mord. Albert Einstein
Delphi-Laie
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 1600
Erhaltene Danke: 232


Delphi 2 - RAD-Studio 10.1 Berlin
BeitragVerfasst: So 12.08.12 22:35 
user profile iconMathematiker hat folgendes geschrieben Zum zitierten Posting springen:
user profile iconMartok hat folgendes geschrieben Zum zitierten Posting springen:
Sehr gerne passiert das auch, wenn sich der Optimizer ausmanövriert hat.

Genau das ist es! :zustimm: Ich habe die Codeoptimierung abgeschaltet und schon ist alles wieder ok.


Darf ich fragen, wo man diese findet?

Vielleicht ist das eine mit Delphi 5 neuhinzugekommene Eigenschaft des Delphis. Aus Delphi 4 ist mir das unbekannt, aber ich bin andererseits kein Maulwurf und habe deshalb nicht den Spürsinn, in alle erreichbaren Tiefen auch tatsächlich zu gelangen.

Compiler hin, Optimierung her, ich bin überzeugt, daß da etwas am Quelltext "unsauber" ist. Einen solchen wahrscheinlich subtilen Fehler zu finden, zudem noch, daß etliche Units infragekommen und dann auch noch in fremden Quelltexten, ist eine in der gesamten, prall bis an die Decke gefüllte Scheune versteckte Stecknadel. Schon im eigenen Quelltext wäre das ein schwer zu gewinnendes Heimspiel.
Mathematiker Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 2622
Erhaltene Danke: 1448

Win 7, 8.1, 10
Delphi 5, 7, 10.1
BeitragVerfasst: So 12.08.12 22:38 
Hallo Delphi_Laie,
user profile iconDelphi-Laie hat folgendes geschrieben Zum zitierten Posting springen:
Darf ich fragen, wo man diese findet?

in Delphi 5 findest Du das unter Projekt | Optionen | Compiler und dann Codeerzeugung | Optimierung.
Ob es das unter Delphi 4 gibt, weiß ich aber nicht.
Beste Grüße
Mathematiker

_________________
Töten im Krieg ist nach meiner Auffassung um nichts besser als gewöhnlicher Mord. Albert Einstein

Für diesen Beitrag haben gedankt: Delphi-Laie
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19314
Erhaltene Danke: 1747

W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: So 12.08.12 22:40 
Bei aktuellen Delphiversionen führt die Verwendung von Generics jetzt ganz gerne zu solchen internen Fehlern (z.B. URW913, ...), insbesondere, wenn man dabei auf Features kommt, die so gar nicht gedacht waren (aber trotzdem zufällig funktionieren). (Ja, ich nutze die dann auch ganz gerne mal. ;-))

Dafür hatte ich ohne Generics keine solchen Probleme mehr.
Delphi-Laie
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 1600
Erhaltene Danke: 232


Delphi 2 - RAD-Studio 10.1 Berlin
BeitragVerfasst: So 12.08.12 22:54 
user profile iconMathematiker hat folgendes geschrieben Zum zitierten Posting springen:
Hallo Delphi_Laie,
user profile iconDelphi-Laie hat folgendes geschrieben Zum zitierten Posting springen:
Darf ich fragen, wo man diese findet?

in Delphi 5 findest Du das unter Projekt | Optionen | Compiler und dann Codeerzeugung | Optimierung.
Ob es das unter Delphi 4 gibt, weiß ich aber nicht.


Jippie, danke, gibt es auch dort, fiel mir bis heute noch nie auf.

"Codeerzeugung", ein einzelnes, unscheinbares Häkchen, empfinde ich allerdings schon als ein wenig oberflächlich. Was mag dort wohl alles (in welcher Hinsicht auch immer) "optimiert" werden und was alles nicht? Sogar der C++-Builder der Version 3 bietet mehr (und daß es dort so etwas gibt, weiß ich hingegen):

Codeoptimierung:
-aus
-Geschwindigkeit
-ausgewählte:
. -Pentium-Befehlsplan
. -Intrinsische Funktionen als Inline
. -Induzierte Variablen
. -Gemeinsame Teilausdrücke entfernen.

Da beide Compiler aus gleichem Hause stammen, ist mir unklar, warum man die Delphianer diesbezüglich an der kurzen Leine hält. Naja, vielleicht liegt es an grundverschiedenen Compilern (deren Architektur, Funktionsweise o.ä.).

Ergänzung: Diese Codeoptmierung gibt es auch schon in Delphi 3 und sogar in Delphi 2. Sollte mich nicht wundern, wenn sogar Delphi 1 sie schon beinhaltete...


Zuletzt bearbeitet von Delphi-Laie am Mo 13.08.12 12:07, insgesamt 1-mal bearbeitet
Mathematiker Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 2622
Erhaltene Danke: 1448

Win 7, 8.1, 10
Delphi 5, 7, 10.1
BeitragVerfasst: Mo 13.08.12 10:04 
Hallo,
man muss nicht die ganze Codeoptimierung für das Programm abschalten.
Es genügt offensichtlich vor der kritischen Methode {$O-} und nach ihrem Ende {$O+} einzufügen. Dann wird der Großteil des Quelltextes optimiert und die sich "bösartig" verhaltende Methode eben nicht.
Ergebnis: Die Exe wird wieder kleiner und scheinbar auch der Programmablauf schneller.
Beste Grüße
Mathematiker

_________________
Töten im Krieg ist nach meiner Auffassung um nichts besser als gewöhnlicher Mord. Albert Einstein
Delphi-Laie
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 1600
Erhaltene Danke: 232


Delphi 2 - RAD-Studio 10.1 Berlin
BeitragVerfasst: Mo 13.08.12 17:19 
user profile iconMathematiker hat folgendes geschrieben Zum zitierten Posting springen:
Hallo,
man muss nicht die ganze Codeoptimierung für das Programm abschalten.
Es genügt offensichtlich vor der kritischen Methode {$O-} und nach ihrem Ende {$O+} einzufügen. Dann wird der Großteil des Quelltextes optimiert und die sich "bösartig" verhaltende Methode eben nicht.


Ja klar, Quelltextanweisung übstimmt generelle Anweisung in den Projektoptionen.

Wenn Du schon diese Möglichkeit hast, dann ist es doch nur noch eine Fleißaufgabe, den Fehler im Quelltext soweit einzugrenzen, bis er schließlich umzingelt ist (die entscheidende(n) Anweisung(en)) - oder muß man immer für eine komplette Routine die Optimierung an-/zu- bzw. abschalten?

user profile iconMathematiker hat folgendes geschrieben Zum zitierten Posting springen:
Ergebnis: Die Exe wird wieder kleiner und scheinbar auch der Programmablauf schneller.


Scheinbar? Läßt sich das nicht - wenigstens grob - messen und bestätigen?
Kleine Exe mag ich immer (scheue allerdings den Aufwand, den Luckie mit seinem NonVCL-Hinauswurf betreibt, das ist schon "Hardcore"), schnelle Exe mag ich noch viel mehr - wer nicht?