Warum kann PB kein unsigned long bzw. int ?

Für allgemeine Fragen zur Programmierung mit PureBasic.
berie
Beiträge: 75
Registriert: 17.01.2018 08:52
Computerausstattung: Windows 11 64 bit, i7, 16GB RAM
Wohnort: Wesertal in Nordhessen

Warum kann PB kein unsigned long bzw. int ?

Beitrag von berie »

Moin,

ich habe keine Lust, im englischen Forum rumzusuchen, vielleicht weiss es jemand aus dem Forum:
Why the hell kann PB kein unsigned bei Datentypen, die >= Long sind ???

Kann man unsigned simulieren ?

Gute Nacht.
formerly known as bizzl
Benutzeravatar
tft
Beiträge: 605
Registriert: 08.09.2004 20:18
Computerausstattung: GTX Titan , i9 9900K , 32 GB Ram , 500 GB SSD , 3 ASUS FullHD Monitore and more
Wohnort: Dachsen
Kontaktdaten:

Re: Warum kann PB kein unsigned long bzw. int ?

Beitrag von tft »

mmmmmmmmm .........

Wenn du grössere ganze Zahlen als 9.223.372.036.854.775.807 (.q) brauchst ......... läuft glaub ich etwas falsch. Dir stehen immerhin 63 Bit zur Verfügung.

Gruss TFT
TFT seid 1989 , Turgut Frank Temucin , Dachsen/Berlin/Antalya
Aktuelles Projekte : Driving School Evergarden
YouTube : Pure Basic to go
FaceBook : Temuçin SourceMAgic Games
DISCORD : SourceMagic
W10 , i9 9900K ,32 GB Ram , GTX Titan , 3 Monitore FHD
ARDUINO Freak :-)
Benutzeravatar
mk-soft
Beiträge: 3701
Registriert: 24.11.2004 13:12
Wohnort: Germany

Re: Warum kann PB kein unsigned long bzw. int ?

Beitrag von mk-soft »

Wurde nicht mit aufgenommen und fehlt manchmal ...

Mathematisch ist es bei Addition und Subtration das Vorzeichen nicht relevant. Nur die Ausgabe und die Vergleiche müssen angepasst werden.

Code: Alles auswählen

a.l = $80000000
Debug Str(a)
Debug StrU(a, #PB_Long)

a + 1
Debug Str(a)
Debug StrU(a, #PB_Long)
Für die Vergleiche als Unsigned habe ich schon mal dies als ASM umgesetzt
Link: Unsigned Compare

Erweiterung für Bit Funktionen findest du hier
Link: Bitshift and Rotation
Alles ist möglich, fragt sich nur wie...
Projekte ThreadToGUI / EventDesigner V3 / OOP-BaseClass-Modul
Downloads auf MyWebspace / OneDrive
ccode_new
Beiträge: 1214
Registriert: 27.11.2016 18:13
Wohnort: Erzgebirge

Re: Warum kann PB kein unsigned long bzw. int ?

Beitrag von ccode_new »

Hallo berie!

Das Problem ist das ein Vergleich oder eine Berechnungen mit gemischten Wertebereichen (unsigned long vs long) zu unerwarteten Problemen führt.

Lese dazu einmal diesen Beitrag:
https://www.purebasic.fr/english/viewto ... f=3&t=6896

Unter C würde man z.B. bei diesem simplen Beispiel eigentlich rein logisch etwas anderes erwarten.

Code: Alles auswählen

#include <stdlib.h>
#include <stdio.h>

int main()
{
	unsigned int one = 1;
	int minus_one = -1;
	if(one < minus_one)
		printf("Wahr!");
	return 0;
}

PureBasic führt viele interne Konvertierungen durch und da stören diese Unterschiede.

Das ganze Thema ist echt komplex und teilweise verwirrend.

Diese Erklärung trifft für x86 (32bit) zu und ist auf x64 erweiterbar.
Ein Short hat eine Bitbreite von 16.
Wertebereich von -32768 bis+32767

Der int hat 32 Bits also bei einem signed int -2147483648 bis +2147483647

-1 wird in signed 16 Bit als 0xFFFF dargestellt.
-1 mit 32 Bit ist 0xFFFFFFFF

+12 ist in 16 Bit 0x000C
+12 in 32 Bit ist 0x00000000C

Die Abfrage:
if (0xFFFF < 0x000C) würde FALSE ergeben, wenn die Werte ohne Vorzeichen behandele würden,
denn 65535 ist NICHT kleiner als 12
TRUE wenn die Vorzeichen beachtet würden, weil -1 nunmal kleiner ist als +12.
Das Ergebnis des Compilers ist richtig, er liefert TRUE, hat also anscheinend das Vorzeichen richtig beachtet.
Würde er ohne Vorzeichen arbeiten wäre das Ergebnis FALSE weil 65535 NICHT kleiner ist als 12
Also ist das Ergebnis einwandfrei bei 16 Bit Operationen.

Nun der Fall für 32 Bit:
if (0xFFFFFFFF < 0x000000C) würde FALSE ergeben, wenn die Werte ohne Vorzeichen behandele würden.
TRUE wenn die Vorzeichen beachte würden.
Das Ergebnis des Compilers ist aber FALSCH, er behandelt das Vorzeichen anscheinend nicht
und deshalb ist 4294967296 nicht kleiner als 12 und damit liefert er FALSE, was halt FALSCH ist.

...Weiter gedacht...

'<' ist ein normaler Operator wie auch '+', '-', etc. Das bedeutet, dass für ihn auch die Integer-Promotion-Rules gelten. Im wesentlichen ist das:
1) Die Typen der Operanden werden auf die selbe Größe gebracht. Der Größte "gibt den Takt vor", mindestens aber int.
2) Haben die Typen bereits die selbe Größe, aber eine unterschiedliche Signedness, wird in unsigned gerechnet.

Bei den int-Operanden sorgt 2) für das unerwartete Ergebnis.
Bei den short-Operanden spielt 2) keine Rolle mehr, nachdem 1) angewendet wurde.
Das Schlüsselwort ist: "Integer-Promotion-Rules"
Daher gibt es auch ein .w und einen .u Typ, aber keinen unsigned long Typ.
Bei .w und .u wird anscheinend (wenn ich das richtig verstanden habe) der Speicherbereich bei Vergleiche auf ein INT erhöht und nur mit signed (Vorzeichen) verglichen.

Und zum Schluss:
Wenn du nicht auf die 4 Byte beschränkt bist, dann nehme einfach z.B. ein QUAD-Typ.

Code: Alles auswählen

Define var1.u = $FFFF ;Unsigned (max. positiver Wert)
Define var2.w = $FFFF >> 1 ;Signed (max. positiver Wert)

Define var3.q = $FFFFFFFF ;max. Wert eines vorzeichenlosen LONG passt problemlos in ein QUAD.
Define var4.l = $FFFFFFFF >> 1 ;Signed (max. positiver Wert)

Debug "VAR1: "+var1
Debug "VAR2: "+var2

Debug "VAR3: "+var3
Debug "VAR4: "+var4
Zuletzt geändert von ccode_new am 22.11.2020 22:50, insgesamt 1-mal geändert.
Betriebssysteme: div. Windows, Linux, Unix - Systeme

no Keyboard, press any key
no mouse, you need a cat
Benutzeravatar
STARGÅTE
Kommando SG1
Beiträge: 6999
Registriert: 01.11.2005 13:34
Wohnort: Glienicke
Kontaktdaten:

Re: Warum kann PB kein unsigned long bzw. int ?

Beitrag von STARGÅTE »

@mk-soft:
Weil ich mir dein Beitrag gerade durchlese zu den Unsigned Compare:
Freak hatte dich doch damals darauf aufmerksam gemacht, dass man nicht-volatile Register in jedem Fall schützen muss, wenn man sie ändert. (Das musste ich selbst auch schmerzlich einsehen, als ich "falschen" ASM code in einem Callback von PB verwendet hatte). In deinem Fall ist das bei der r15 Register, den du da einfach beschreibst, welcher aber nicht flüchtig ist.
Könntest du ja ggf. mal updaten.
Btw. könnte auch ein CMOVcc den einen Sprung vermeiden, zumal du ja das Label ja sogar statisch benannt hast, was auch gefährlich sein könnte, wenn das jemand schon nutzt. Hier mal meine Idee:

Code: Alles auswählen

Procedure Above(a.q, b.q)
	
	! MOV    rax, 0
	! MOV    rcx, 1
	! MOV    rdx, qword [p.v_a]
	! CMP    rdx, qword [p.v_b]
	! CMOVA  rax, rcx
	ProcedureReturn
	
EndProcedure
  
Debug Above($9000000000000000, $8000000000000000)
Debug Above($7000000000000000, $C000000000000000)
PB 6.01 ― Win 10, 21H2 ― Ryzen 9 3900X, 32 GB ― NVIDIA GeForce RTX 3080 ― Vivaldi 6.0 ― www.unionbytes.de
Aktuelles Projekt: Lizard - Skriptsprache für symbolische Berechnungen und mehr
Benutzeravatar
mk-soft
Beiträge: 3701
Registriert: 24.11.2004 13:12
Wohnort: Germany

Re: Warum kann PB kein unsigned long bzw. int ?

Beitrag von mk-soft »

@stargate

mit dem Register r15 hast du recht, ich habe es aber mir leicht gemacht und genau so umgesetzt wie es der Compiler erstellt und nur den Sprungbefehl angepasst. Der Compiler verwendet auch das gleiche Register r15.

Mit dem Labels hast du recht, sollte aber in den wenigsten fällen zu Problemen führen.
Alles ist möglich, fragt sich nur wie...
Projekte ThreadToGUI / EventDesigner V3 / OOP-BaseClass-Modul
Downloads auf MyWebspace / OneDrive
Benutzeravatar
tft
Beiträge: 605
Registriert: 08.09.2004 20:18
Computerausstattung: GTX Titan , i9 9900K , 32 GB Ram , 500 GB SSD , 3 ASUS FullHD Monitore and more
Wohnort: Dachsen
Kontaktdaten:

Re: Warum kann PB kein unsigned long bzw. int ?

Beitrag von tft »

Hallo,

ein sehr aufschlussreiche Diskussion. Allerdings erschliesst sich mir der Sinn nicht.
Beim Rechnen mit Zahlen kann es immer mal zu Ergebnissen kommen. Die <0 sind.
Daher muss die Variable doch damit umgehen können. Das reduziert den Zahlenbereich
beim Rechen nun-mal um die hälfte. Da es keine Grösseren Wert als .q (8 Byte = 64 Bit)
gibt. Müssen Rechnungen so gestaltet sein. Das diese Grenzen nicht überschritten werden.
Ich habe auf 8 Bit Rechnern gelernt. Da gabs dann das überlauf flag. Und das Register mit dem Rest.
Das Register für das Ergebniss war Doppelt so gross und in High und Low geteilt.
Ich bin kein Informatiker , und mein wissen über das rechnen mit Zahlen ist nur auf Hauptschul Niveo.
Wo genau bracht man solche Zahlen im Altag , 64 Bit ohne Vorzeichen als Ergebnis?
Und wenn man Grössere Zahlen benötigt. Mussten die Berechnungen immer in mehreren schritten erfolgen.

Die Frage ist rein Informativ und dient nur meinem Verstehen.

Gruss TFT
TFT seid 1989 , Turgut Frank Temucin , Dachsen/Berlin/Antalya
Aktuelles Projekte : Driving School Evergarden
YouTube : Pure Basic to go
FaceBook : Temuçin SourceMAgic Games
DISCORD : SourceMagic
W10 , i9 9900K ,32 GB Ram , GTX Titan , 3 Monitore FHD
ARDUINO Freak :-)
Benutzeravatar
NicTheQuick
Ein Admin
Beiträge: 8679
Registriert: 29.08.2004 20:20
Computerausstattung: Ryzen 7 5800X, 32 GB DDR4-3200
Ubuntu 22.04.3 LTS
GeForce RTX 3080 Ti
Wohnort: Saarbrücken
Kontaktdaten:

Re: Warum kann PB kein unsigned long bzw. int ?

Beitrag von NicTheQuick »

@tft:
Wenn du wüsstest wie viele Sicherheitslücken es gab und gibt, weil Programmierer genau so gedacht haben, dann würdest du dich wundern.
Tatsächlich zeugt es von gutem Programmierstil, wenn man z.B. Zählvariablen, die bei 0 beginnen und irgendwo aufhören, auch als unsigned definiert. Das Problem ist hier oftmals wo die obere Grenze herkommt. Es gab schon Sicherheitslücken, da wurde diese Grenze aus einer manipulierten Datei gelesen und bewusst so hoch gesetzt, dass sie negativ interpretiert wurde. Dadurch wurde die Schleife dann gar nicht ausgeführt, was fatal war. Da dann Daten nicht aus der Datei gelesen wurden, die aber eigentlich gelesen werden sollten. Wäre die gelesene Zahl aus der Datei als unsigned interpretiert worden, hätte es kein Problem gegeben.
Oder ein anderes Problem ist, wenn du zwei große Zahlen multiplizieren willst und sie dann plötzlich negativ sind. Weitere Berechnungen können dadurch zu Fehlern würden. Oder wenn du dann Modulo rechnen willst. Bei kryptografischen Verfahren ist das ein wichtiger Bestandteil.
Auch virtuelle Speicheradressen können so groß sein, dass sie negativ sind, wenn man sie signed betrachtet. Aber Speicheradressen (Pointer) können niemals negativ sein. Das ergibt keinen Sinn.

Du findest auch jede Menge Artikel über derartige Probleme. Die meisten leider auf Englisch:
Bild
Benutzeravatar
tft
Beiträge: 605
Registriert: 08.09.2004 20:18
Computerausstattung: GTX Titan , i9 9900K , 32 GB Ram , 500 GB SSD , 3 ASUS FullHD Monitore and more
Wohnort: Dachsen
Kontaktdaten:

Re: Warum kann PB kein unsigned long bzw. int ?

Beitrag von tft »

Danke für die Ausführung.
TFT seid 1989 , Turgut Frank Temucin , Dachsen/Berlin/Antalya
Aktuelles Projekte : Driving School Evergarden
YouTube : Pure Basic to go
FaceBook : Temuçin SourceMAgic Games
DISCORD : SourceMagic
W10 , i9 9900K ,32 GB Ram , GTX Titan , 3 Monitore FHD
ARDUINO Freak :-)
berie
Beiträge: 75
Registriert: 17.01.2018 08:52
Computerausstattung: Windows 11 64 bit, i7, 16GB RAM
Wohnort: Wesertal in Nordhessen

Re: Warum kann PB kein unsigned long bzw. int ?

Beitrag von berie »

Vielen Dank für eure Antworten !
Ich werde mich da mal reinarbeiten.
formerly known as bizzl
Antworten