Pred(0) liefert 65535 bei Word-Typen normal oder bug?

Für Fragen zur Programmiersprache auf welcher Lazarus aufbaut
Antworten
Soner
Beiträge: 623
Registriert: Do 27. Sep 2012, 00:07
OS, Lazarus, FPC: Win10Pro-64Bit, Immer letzte Lazarus Release mit SVN-Fixes
CPU-Target: x86_64-win64
Wohnort: Hamburg

Pred(0) liefert 65535 bei Word-Typen normal oder bug?

Beitrag von Soner »

Hallo Leute,
Ich erkläre das Problem am besten mit Beispiel lies bitte kommentare:

Code: Alles auswählen

 
 
{.$MODE DELPHI} //Auch bei {$MODE DELPHI} ist das ergebnis gleich
{.$R+} //pred(word(0)) erzeugt ERangeError -> es ist normal.
var w: word;
    i: integer;
    s: string;
begin
  i:=0;
  w:=0;
  if i<pred(w) then
    //fpc führt nächste Zeile aus
    s:=IntToStr(Pred(w))  //s=65535  ist auch gleich high(w)=65535
  else
   //TurboDelphi2006 führt nächste Zeile aus
   s:=IntToStr(Pred(w)); //s=-1
 
  Writeln(s);
end;
 


Also Delphi und Freepascal liefern verschiedene Erbgebnisse, ist es jetzt normal oder bug?

.

wp_xyz
Beiträge: 4889
Registriert: Fr 8. Apr 2011, 09:01

Re: Pred(0) liefert 65535 bei Word-Typen normal oder bug?

Beitrag von wp_xyz »

Ich finde, das FPC-Ergebnis ist "ehrlicher": word ist nun mal ein vorzeichenloser Integer, und da darf $FFFF als Vorgänger von $0000 nicht als negative Zahl ausgegeben werden. Viele Leute verwenden die vorzeichenlosen Integer-Typen, weil die Zahl ja "nicht negativ sein kann", aber sobald man subtrahiert oder pred verwendet, stimmt das nicht mehr und man erlebt eine böse Überraschung. Besser wäre, du würdest w als Integer oder als SmallInt deklarieren. Ansonsten ist es eine gute Idee, während der Entwicklung [%R+} eingeschaltet zu haben (geht ja ganz einfach mit den Build-Modes).

Soner
Beiträge: 623
Registriert: Do 27. Sep 2012, 00:07
OS, Lazarus, FPC: Win10Pro-64Bit, Immer letzte Lazarus Release mit SVN-Fixes
CPU-Target: x86_64-win64
Wohnort: Hamburg

Re: Pred(0) liefert 65535 bei Word-Typen normal oder bug?

Beitrag von Soner »

Naja so "ehrlicher" finde ich es nicht, weil 65535 nicht Vorgänger von 0 ist, sondern die größte Word-Zahl ist.
Vorgänger von 0 ist nunmal -1 und wenn es schon unsinningen Wert liefert dann gleich 32769 (-1 als Word)
Ich wollte es umändern aber finde in RTL die funktion nicht.

Ich selbst verwende solche Funktionen nie, ich verwende immer arithmetische operatoren (x-1), es steckt in einem Programm das ich zur Lazarus portiere und es wurde massig von diesen Funktionen (pred, succ) gebrauch gemacht.

Warf
Beiträge: 1910
Registriert: Di 23. Sep 2014, 17:46
OS, Lazarus, FPC: Win10 | Linux
CPU-Target: x86_64

Re: Pred(0) liefert 65535 bei Word-Typen normal oder bug?

Beitrag von Warf »

Soner hat geschrieben:Naja so "ehrlicher" finde ich es nicht, weil 65535 nicht Vorgänger von 0 ist, sondern die größte Word-Zahl ist.
Vorgänger von 0 ist nunmal -1 und wenn es schon unsinningen Wert liefert dann gleich 32769 (-1 als Word)
Ich wollte es umändern aber finde in RTL die funktion nicht.

Ich selbst verwende solche Funktionen nie, ich verwende immer arithmetische operatoren (x-1), es steckt in einem Programm das ich zur Lazarus portiere und es wurde massig von diesen Funktionen (pred, succ) gebrauch gemacht.


Seit wann ist 32769 das -1 als Word? In einem Vorzeichenbehafteten Integer wäre -1 wie folgt(Beispiel mit Byte, da kürzer): Das Bitinverse von 1: not 1 = %11111110 und das ganze +1 also not 1 + 1 = %11111111 (oder $FF als Hex) und ist somit in einem Vorzeichenlosen Typ die größtmögliche Zahl.

Von der Technischen Sicht macht alles andere als 65535 als Vorgänger von 0 keinen Sinn. Aber wenn man mit diesen Overflow Effekten nicht vertraut ist sollte man eh eher Integer bzw Int64 verwenden. Es gibt sowieso eher wenige Fälle in denen man kleine Typen verwenden sollte, da Speicher nicht Teuer ist, aber die Performance unter nicht nativen Typen leidet. Und Vorzeichenlose Typen sollte man auch nur verwenden wenn man weiß was passiert, sonst fliegt es schnell um die Ohren

wp_xyz
Beiträge: 4889
Registriert: Fr 8. Apr 2011, 09:01

Re: Pred(0) liefert 65535 bei Word-Typen normal oder bug?

Beitrag von wp_xyz »

Soner hat geschrieben:Ich selbst verwende solche Funktionen nie, ich verwende immer arithmetische operatoren (x-1).

Das hat nichts mit der Prozedur "pred()" zu tun, auch mit der Operation "x-1" wirst du Probleme bekommen, wenn x ein Word ist.

Soner
Beiträge: 623
Registriert: Do 27. Sep 2012, 00:07
OS, Lazarus, FPC: Win10Pro-64Bit, Immer letzte Lazarus Release mit SVN-Fixes
CPU-Target: x86_64-win64
Wohnort: Hamburg

Re: Pred(0) liefert 65535 bei Word-Typen normal oder bug?

Beitrag von Soner »

@Warf:
Ja du hast Recht, ich habe Gedankenfehler gemacht, danke für den Hinweis.

@wp_xyz
Fpc macht aus (w-1) gleich -1, bei w gleich 0 und als Word definiert. Also wie bei Delphi.

Code: Alles auswählen

 
var w: word;
    x,i: integer;
begin
  x:=0;
  w:=0;
  i:=(w-1); //i ist -1
  if 0>(w-1) then  //wenn man 0 durch x ersetzt ändert sich auch nicht
    caption:=IntToStr(i); //wird ausgeführt
 


Also es bleibt dann nichts anders übrig den Quelltex nach Pred() zu kontrollieren.
Danke Jungs.

Warf
Beiträge: 1910
Registriert: Di 23. Sep 2014, 17:46
OS, Lazarus, FPC: Win10 | Linux
CPU-Target: x86_64

Re: Pred(0) liefert 65535 bei Word-Typen normal oder bug?

Beitrag von Warf »

Soner hat geschrieben:@Warf:
Ja du hast Recht, ich habe Gedankenfehler gemacht, danke für den Hinweis.

@wp_xyz
Fpc macht aus (w-1) gleich -1, bei w gleich 0 und als Word definiert. Also wie bei Delphi.

Code: Alles auswählen

 
var w: word;
    x,i: integer;
begin
  x:=0;
  w:=0;
  i:=(w-1); //i ist -1
  if 0>(w-1) then  //wenn man 0 durch x ersetzt ändert sich auch nicht
    caption:=IntToStr(i); //wird ausgeführt
 


Also es bleibt dann nichts anders übrig den Quelltex nach Pred() zu kontrollieren.
Danke Jungs.


Das liegt daran dass der Typ von i Integer ist. Bei Cardinal (LongWord) ist das ergebnis High(Cardinal) und bei QWord wird es High QWord. Bei Byte würde es High(Byte) werden, und bei Vorzeichenbehafteten Typen halt -1. Aber egal wie auch immer, auf Technischer ebene ist die Zahl einfach %1..1 (n mal mit n = Bitanzahl)

Soner
Beiträge: 623
Registriert: Do 27. Sep 2012, 00:07
OS, Lazarus, FPC: Win10Pro-64Bit, Immer letzte Lazarus Release mit SVN-Fixes
CPU-Target: x86_64-win64
Wohnort: Hamburg

Re: Pred(0) liefert 65535 bei Word-Typen normal oder bug?

Beitrag von Soner »

@Warf:
Ich glaube du hast die 0 bei Vergleich nicht gesehen, fpc wertet das als Wahr also auch wei bei Delphi -1:
if 0>(w-1) then..

Und wenn du für 0 eine Word Variable nimmt wertet fpc das auch als wahr aus, hat in diesem Fall mit integer nicht zu tun, hier gestet:

Code: Alles auswählen

 
d,w: Word;
i:integer;
i:=0;
d:=0;
w:=0;
if d>(w-1) then  ist_wahr_bei_fpc; //rechte seite wird -1
if d>pred(w-1) then  ist_nicht_wahr_bei_fpc; //rechte seite wird 65535
if i>pred(w-1) then  ist_nicht_wahr_bei_fpc; //rechte seite wird 65535
d:=(w-1); //bei fpc=65535
 


Also bei If-Vergleichen wertet fpc Pred und (word0-1) anders aus.

Warf
Beiträge: 1910
Registriert: Di 23. Sep 2014, 17:46
OS, Lazarus, FPC: Win10 | Linux
CPU-Target: x86_64

Re: Pred(0) liefert 65535 bei Word-Typen normal oder bug?

Beitrag von Warf »

Soner hat geschrieben:@Warf:
Ich glaube du hast die 0 bei Vergleich nicht gesehen, fpc wertet das als Wahr also auch wei bei Delphi -1:
if 0>(w-1) then..

Und wenn du für 0 eine Word Variable nimmt wertet fpc das auch als wahr aus, hat in diesem Fall mit integer nicht zu tun, hier gestet:

Code: Alles auswählen

 
d,w: Word;
i:integer;
i:=0;
d:=0;
w:=0;
if d>(w-1) then  ist_wahr_bei_fpc; //rechte seite wird -1
if d>pred(w-1) then  ist_nicht_wahr_bei_fpc; //rechte seite wird 65535
if i>pred(w-1) then  ist_nicht_wahr_bei_fpc; //rechte seite wird 65535
d:=(w-1); //bei fpc=65535
 


Also bei If-Vergleichen wertet fpc Pred und (word0-1) anders aus.



Wie gesagt es kommt auf den Typen an, der Interne arbeitstyp ist Integer bzw Int64, wenn keine Typzuweisung stattfindet, während pred auf dem Typen selbst arbeitet. Das Ergebnis einer Arithmetischen Operation ist auch zunächst ein Integer und wird erst bei der Zuweisung zu einer Variable in den entsprechenden Wert gecastet

Ein kleines Beispiel:

Code: Alles auswählen

var w1, w2: Integer;
begin
  WriteLn(SizeOf(w1)); // 2 Byte - Word größe
  WriteLn(SizeOf(w1-1)); // 4 Byte - 32 Bit Integer bzw 8, 64 Bit auf 64 Bit system
  WriteLn(SizeOf(w1-w2)); // 4 Byte - 32 Bit Integer, 64 Bit auf 64 Bit system
end;


Das liegt daran das das System intern für die Berechnung von Typen diese zunächst in die Nativen Typen (also Integer für 32 Bit System und Int64 für 64 Bit System) castet, dann die Berechnung ausführt, und danach das Ergebnis erst bei der Zuweisung in die entsprechenden Daten gecastet wird. Daher wird auch für QWord das ergebnis High(QWord), für Cardinal das ergebnis High(Cardinal), etc, da es intern ein -1 ist und dann erst bei der Zuweisung gecastet wird.

Ich hoffe das war halbwegs verständlich.

Das ganze wird erst richtig interessant wenn man mit Compileroptimierungen arbeitet, ich weiß zwar nicht wie es beim FPC ist, aber z.B. C verwendet dann Statt der Arithmetischen Operationen (z.B. ADD in Assembler) optimierte Prozessorbefehle (z.B. INC falls eine Zuweisung der Form x=x+1), grade bei CISC Prozessoren gibt es davon viele, und diese verhalten sich auch nochmal anders, und dann kann es richtig spaßig werden rauszufinden welcher Typ zu welchem Zeitpunkt verwendet wird. Darum sollte man sich von diesen Overflows immer fern halten.

marcov
Beiträge: 1100
Registriert: Di 5. Aug 2008, 09:37
OS, Lazarus, FPC: Windows ,Linux,FreeBSD,Dos (L trunk FPC trunk)
CPU-Target: 32/64,PPC(+64), ARM
Wohnort: Eindhoven (Niederlande)

Re: Pred(0) liefert 65535 bei Word-Typen normal oder bug?

Beitrag von marcov »

Soner hat geschrieben:Naja so "ehrlicher" finde ich es nicht, weil 65535 nicht Vorgänger von 0 ist, sondern die größte Word-Zahl ist.
Vorgänger von 0 ist nunmal -1 und wenn es schon unsinningen Wert liefert dann gleich 32769 (-1 als Word)
Ich wollte es umändern aber finde in RTL die funktion nicht.


Delphi macht das nicht darum, aber weil es offenbar keine pred(word) hat, und dann der Word einfachweg nach integer umwandelt.

Was ist pred(uint64) mit Delphi und FPC ? Da kann man nicht nach ein groesser Integertyp umwandeln.

Soner
Beiträge: 623
Registriert: Do 27. Sep 2012, 00:07
OS, Lazarus, FPC: Win10Pro-64Bit, Immer letzte Lazarus Release mit SVN-Fixes
CPU-Target: x86_64-win64
Wohnort: Hamburg

Re: Pred(0) liefert 65535 bei Word-Typen normal oder bug?

Beitrag von Soner »

marcov hat geschrieben:
Soner hat geschrieben:Naja so "ehrlicher" finde ich es nicht, weil 65535 nicht Vorgänger von 0 ist, sondern die größte Word-Zahl ist.
Vorgänger von 0 ist nunmal -1 und wenn es schon unsinningen Wert liefert dann gleich 32769 (-1 als Word)
Ich wollte es umändern aber finde in RTL die funktion nicht.


Delphi macht das nicht darum, aber weil es offenbar keine pred(word) hat, und dann der Word einfachweg nach integer umwandelt.

Was ist pred(uint64) mit Delphi und FPC ? Da kann man nicht nach ein groesser Integertyp umwandeln.


Das hängt davon ab was du mit Pred(wordtyp(0)) machst.
Wenn du es zu linken Seite zuweist Verhält es sich zu dem Typ was auf der linken Seite steht.
Hier hast du Beispielprogramm mit Ergebnisse:

Code: Alles auswählen

 
{$apptype console}
program Project1;
var w,v: word;
    u: uint64;
    i: integer;
begin
  w:=0;
  v:=pred(w);     //v=65535 mit delhi und fcp
  Writeln('v:=pred(w) : ',pred(v));
 
  if 0<pred(w) then               //pred(w) ist bei delphi -1 bei fpc 65535
      Writeln('0<pred(Word(0)) = true :', pred(w))    // fpc führt das aus
  else
     Writeln('0<pred(Word(0)) = false :', pred(w));   // delphi führt das aus
 
  u:=0;
  if 0<pred(u) then               //pred(u) ist bei delphi -1 bei fpc high(uint)=18446744073709551615
      Writeln('0<pred(uint64(0)) = true : ',pred(u))   // fpc führt das aus
  else
      Writeln('0<pred(uint64(0)) = false : ',Pred(u))// delphi führt das aus
 
  i:=pred(w);
  Writeln('i:=pred(w) =  ',i);   //bei delphi -1 bei fpc 65535 bug bei fpc?
  readln;
 
end.
 


Siehst du den letzten Vergleich?
Pred(Word(0)) wird zum Integer zugewiesen und fpc macht trotzdem 65535 daraus:
i:=pred(w); wird als 65535 ausgewertet, das sieht nach einem bug aus.

Ich hätte Pred(Wordtyp(0))=65535 nie bei Pascal erwartet höchstens bei C, man sagt ja Pascal ist akademische, typsichere Sprache undPred(Wordtyp(0)) ist ja mathematisch undefiniert, es könnte doch gleich ERangeError ausgelöst werden, wie bei DivisonError.

Warf
Beiträge: 1910
Registriert: Di 23. Sep 2014, 17:46
OS, Lazarus, FPC: Win10 | Linux
CPU-Target: x86_64

Re: Pred(0) liefert 65535 bei Word-Typen normal oder bug?

Beitrag von Warf »

Soner hat geschrieben:
marcov hat geschrieben:
Soner hat geschrieben:Naja so "ehrlicher" finde ich es nicht, weil 65535 nicht Vorgänger von 0 ist, sondern die größte Word-Zahl ist.
Vorgänger von 0 ist nunmal -1 und wenn es schon unsinningen Wert liefert dann gleich 32769 (-1 als Word)
Ich wollte es umändern aber finde in RTL die funktion nicht.


Delphi macht das nicht darum, aber weil es offenbar keine pred(word) hat, und dann der Word einfachweg nach integer umwandelt.

Was ist pred(uint64) mit Delphi und FPC ? Da kann man nicht nach ein groesser Integertyp umwandeln.


Das hängt davon ab was du mit Pred(wordtyp(0)) machst.
Wenn du es zu linken Seite zuweist Verhält es sich zu dem Typ was auf der linken Seite steht.
Hier hast du Beispielprogramm mit Ergebnisse:

Code: Alles auswählen

 
{$apptype console}
program Project1;
var w,v: word;
    u: uint64;
    i: integer;
begin
  w:=0;
  v:=pred(w);     //v=65535 mit delhi und fcp
  Writeln('v:=pred(w) : ',pred(v));
 
  if 0<pred(w) then               //pred(w) ist bei delphi -1 bei fpc 65535
      Writeln('0<pred(Word(0)) = true :', pred(w))    // fpc führt das aus
  else
     Writeln('0<pred(Word(0)) = false :', pred(w));   // delphi führt das aus
 
  u:=0;
  if 0<pred(u) then               //pred(u) ist bei delphi -1 bei fpc high(uint)=18446744073709551615
      Writeln('0<pred(uint64(0)) = true : ',pred(u))   // fpc führt das aus
  else
      Writeln('0<pred(uint64(0)) = false : ',Pred(u))// delphi führt das aus
 
  i:=pred(w);
  Writeln('i:=pred(w) =  ',i);   //bei delphi -1 bei fpc 65535 bug bei fpc?
  readln;
 
end.
 


Siehst du den letzten Vergleich?
Pred(Word(0)) wird zum Integer zugewiesen und fpc macht trotzdem 65535 daraus:
i:=pred(w); wird als 65535 ausgewertet, das sieht nach einem bug aus.

Ich hätte Pred(Wordtyp(0))=65535 nie bei Pascal erwartet höchstens bei C, man sagt ja Pascal ist akademische, typsichere Sprache undPred(Wordtyp(0)) ist ja mathematisch undefiniert, es könnte doch gleich ERangeError ausgelöst werden, wie bei DivisonError.


das lässt sich sehr simpel erklären: pred auf Word liefert Word zurück, und das wird dann in integer gecastet, und da Word kleiner als integer ist kommt 65535 raus.
Bei einer arithmetmetischen Operation kommt allerdings integer raus was dann Nicht gecastet werden muss daher -1

Da Delphi pred auf Word nicht definiert arbeitet Delphi arbeitet Delphi immer auf integer, weshalb nie ein Word rauskommt und daher kommt -1 raus

Pred(w) in Delphi entspräche Pred(Integer(w)) im fpc. Und aus diesem Gesichtspunkt macht das meines Erachtens nach vollkommen sinn

marcov
Beiträge: 1100
Registriert: Di 5. Aug 2008, 09:37
OS, Lazarus, FPC: Windows ,Linux,FreeBSD,Dos (L trunk FPC trunk)
CPU-Target: 32/64,PPC(+64), ARM
Wohnort: Eindhoven (Niederlande)

Re: Pred(0) liefert 65535 bei Word-Typen normal oder bug?

Beitrag von marcov »

Soner hat geschrieben:

Code: Alles auswählen

 
{$apptype console}
program Project1;
var w,v: word;
    u: uint64;
    i: integer;
begin
  w:=0;
  v:=pred(w);     //v=65535 mit delhi und fcp
  Writeln('v:=pred(w) : ',pred(v));
 
  if 0<pred(w) then               //pred(w) ist bei delphi -1 bei fpc 65535
      Writeln('0<pred(Word(0)) = true :', pred(w))    // fpc führt das aus
  else
     Writeln('0<pred(Word(0)) = false :', pred(w));   // delphi führt das aus
 
  u:=0;
  if 0<pred(u) then               //pred(u) ist bei delphi -1 bei fpc high(uint)=18446744073709551615
      Writeln('0<pred(uint64(0)) = true : ',pred(u))   // fpc führt das aus
  else
      Writeln('0<pred(uint64(0)) = false : ',Pred(u))// delphi führt das aus
 
  i:=pred(w);
  Writeln('i:=pred(w) =  ',i);   //bei delphi -1 bei fpc 65535 bug bei fpc?
  readln;
 
end.
 



Hier nicht (XE4):

Code: Alles auswählen

 
v:=pred(w) : 65534
0<pred(Word(0)) = false :-1
0<pred(uint64(0)) = true : 18446744073709551615
i:=pred(w) =  -1
 


Also Delphi ist da inkonsequent. Besser gesagt, im Delphi Model ist solche Arithmetik zustehen auf uint64 inkonsequent weil es int128 dafür benötigt. Aber Delphi Entwickler sind einfachweg faul. Sie wollen das unsigned Arithmetik nicht ganz ausreifen, aber müssen uint64 zustehen weil vielen Programme (und winapi) es nutzen. Und auch zu faul um eine gute Randfälle Abwicklung u machen, alsokeine Operationen zustehen die int128 brauchen um dasselbe wie uint32 zu funktionieren.

FPC ist konsequent weil es in beide Faelle ein unsigned Zahl ausgibt (zwei mal true)

Antworten