Frage zur Division durch Konstanten

Anfängerfragen zum Programmieren mit PureBasic.
Benutzeravatar
Gezuppel
Beiträge: 29
Registriert: 18.09.2004 06:43
Computerausstattung: Intel Core i7 2600 / Asus P8P67 Rev. 3 / 8GB DDR3 / Geforce GTX570
Wohnort: Niedersachsen

Frage zur Division durch Konstanten

Beitrag von Gezuppel »

Habe folgende Verständnisfrage:

Code: Alles auswählen

#FTTicks_per_Day = 864000000000
dummy1.q         = 864000000000
dummy2.q         = #FTTicks_per_Day

Debug dummy1.q / dummy2.q
Debug dummy1.q / #FTTicks_per_Day
Das erste Debug gibt mir wie erwartet 1 aus
Das Zweite 1214
Warum gibt es unterschiedliche Ergebnisse? :shock:
PureBasic 4.61 / 4.70 Beta1
Windows 7 Ultimate x64
Benutzeravatar
Mok
BotHunter
Beiträge: 1484
Registriert: 26.12.2005 14:14
Computerausstattung: MSI GX780R
Intel Core i5-2410M
Nvidia GT 555M
Windows 7 Home Premium 64 bit
Wohnort:   

Re: Frage zur Division durch Konstanten

Beitrag von Mok »

Bei mir auch... aber nur bei der x64-Version.
Ich guck mir mal den Asm-Code an und meld' mich dann zurück.
Zuletzt geändert von Mok am 04.08.2012 09:48, insgesamt 1-mal geändert.
Win 7 Home Premium 64 bit | PureBasic 5.20 - x86 und x86-64 | Firefox [aktuelle stable-Version hier einfügen]
"Jeder macht irgendwann mal Fehler, darum gibt's auch Bleistifte mit Radiergummi." --Carl
Benutzeravatar
ts-soft
Beiträge: 22292
Registriert: 08.09.2004 00:57
Computerausstattung: Mainboard: MSI 970A-G43
CPU: AMD FX-6300 Six-Core Processor
GraKa: GeForce GTX 750 Ti, 2 GB
Memory: 16 GB DDR3-1600 - Dual Channel
Wohnort: Berlin

Re: Frage zur Division durch Konstanten

Beitrag von ts-soft »

Gezuppel hat geschrieben:Warum gibt es unterschiedliche Ergebnisse? :shock:
Dein PC kaputt? Bei mir kommt immer 1 heraus.
PureBasic 5.73 LTS | SpiderBasic 2.30 | Windows 10 Pro (x64) | Linux Mint 20.1 (x64)
Nutella hat nur sehr wenig Vitamine. Deswegen muss man davon relativ viel essen.
Bild
Benutzeravatar
Gezuppel
Beiträge: 29
Registriert: 18.09.2004 06:43
Computerausstattung: Intel Core i7 2600 / Asus P8P67 Rev. 3 / 8GB DDR3 / Geforce GTX570
Wohnort: Niedersachsen

Re: Frage zur Division durch Konstanten

Beitrag von Gezuppel »

Dein PC kaputt? Bei mir kommt immer 1 heraus.
Dann ist der von Mok wohl auch kaputt :wink:

Habe gerade die 32Bit (PB 4.61 & PB 4.70 Beta 1) Versionen auch getestet, da funktioniert es wie erwartet.
Also wie bei Mok nur die 64Bit Versionen liefern 1214 statt 1.
PureBasic 4.61 / 4.70 Beta1
Windows 7 Ultimate x64
Benutzeravatar
Mok
BotHunter
Beiträge: 1484
Registriert: 26.12.2005 14:14
Computerausstattung: MSI GX780R
Intel Core i5-2410M
Nvidia GT 555M
Windows 7 Home Premium 64 bit
Wohnort:   

Re: Frage zur Division durch Konstanten

Beitrag von Mok »

Ooookay, das Ergebnis meiner fast forensischen, wenn auch nur ziemlich schnellen/kurzen(?) Untersuchungen sieht wie folgt aus:

Code: Alles auswählen

Assemblierung des x86-Codes

; #FTTicks_per_Day = 864000000000
; dummy1.q         = 864000000000
  MOV    dword [v_dummy1],711573504
  MOV    dword [v_dummy1+4],201
; dummy2.q         = #FTTicks_per_Day
  MOV    dword [v_dummy2],711573504
  MOV    dword [v_dummy2+4],201
; 
; var1 = dummy1.q / dummy2.q
  PUSH   dword [v_dummy1+4]
  PUSH   dword [v_dummy1]
  LEA    eax,[v_dummy2]
  PUSH   dword [eax+4]
  PUSH   dword [eax]
  PUSH   dword [esp+12]
  PUSH   dword [esp+12]
  CALL   Div64
  MOV    [esp],eax
  MOV    [esp+4],edx
  POP    eax
  POP    edx
  MOV    dword [v_var1],eax
; var2 = dummy1.q / #FTTicks_per_Day
  PUSH   dword [v_dummy1+4]
  PUSH   dword [v_dummy1]
  PUSH   dword 201
  PUSH   dword 711573504
  PUSH   dword [esp+12]
  PUSH   dword [esp+12]
  CALL   Div64
  MOV    [esp],eax
  MOV    [esp+4],edx
  POP    eax
  POP    edx
  MOV    dword [v_var2],eax

Code: Alles auswählen

Assemblierung des x86-64-Codes (x64)
; #FTTicks_per_Day = 864000000000
; dummy1.q         = 864000000000
  MOV    rax,864000000000
  MOV    qword [v_dummy1],rax
; dummy2.q         = #FTTicks_per_Day
  MOV    rax,864000000000
  MOV    qword [v_dummy2],rax

; var1 = dummy1.q / dummy2.q
  MOV    r15,qword [v_dummy1]
  PUSH   qword [v_dummy2]
  MOV    rax,r15
  POP    rcx
  CQO
  IDIV   rcx
  MOV    r15,rax
  MOV    qword [v_var1],r15
; var2 = dummy1.q / #FTTicks_per_Day
  MOV    r15,qword [v_dummy1]
  MOV    rax,r15
  MOV    rcx,711573504
  CQO
  IDIV   rcx
  MOV    r15,rax
  MOV    qword [v_var2],r15
Anmerkung: Nur die relevanten Ausschnitte wurden gepostet, kein vollständiger Code.

Wie unschwer zu erkennen ist, greift PB bei x86-Code auf eine externe Funktion zurück (Div64) - keine Ahnung warum und was damit erreicht wird, aber es funktioniert. Beim x64-Code sieht das anders aus (da wurde "direkt" also im IDIV dividiert), daher kann man beide nicht miteinander vergleichen.
Was allerdings beim x64-Code auffällt, ist, dass der Divisor beide Male in rcx gespeichert wird (IDIV rcx bedeutet: Ganzzahl-Division RAX / RCX), wenn man 2 Zeilen darüber schaut, lässt sich erkennen, dass bei der Division durch die Variable klarerweise der Wert der Variable in RCX gespeichert wird (PUSH dword [dummy2] {...} POP rcx). Bei der Division durch einen konstanten Wert wird RCX allerdings auf den Wert 711573504 gestellt, was garnicht funktionieren kann. Rechnet man 864000000000 / 711573504 kommen die erwarteten 1214 raus.
Was heißt das? Das heißt, dass beim x64 4.70 Beta-Release irgendjemand die Idee hatte, bei konstanten Division den vom Programmierer festgelegten Divisor durch die Zahl 711573504 zu ersetzen. (Die Zahl bleibt von Programm zu Programm scheinbar gleich).

Ein Mysterium, welches ich nicht lösen konnte ist, dass auch in der X86-Version auf den Wert 711573504 zurückgegriffen wurde. Warum es dennoch funktioniert, kann ich nicht sagen, da ich den Code für die Prozedur 'Div64' nicht kenne. Scheinbar ist 711573504 eine Art magische Zahl, welche das Dividieren auf unterster Ebene erleichtern soll, nur wurde (falls meine Annahmen stimmen) die Zahl bei 64-Bit-Code falsch verwendet.

Also @PB-Entwickerteam: Kloppt mal ganz schnell einen Patch raus.

Edit: Außerdem ist werden im Divisionscode überflüssige Zuweisungen gemacht. Jaja, es ist nur eine Beta, aber gesagt ist gesagt.

Code: Alles auswählen

; var2 = dummy1.q / #FTTicks_per_Day
  MOV    r15,qword [v_dummy1]
  MOV    rax,r15
  MOV    rcx,711573504
  CQO
  IDIV   rcx
  MOV    r15,rax
  MOV    qword [v_var2],r15
Wäre ersetzbar durch

Code: Alles auswählen

; var2 = dummy1.q / #FTTicks_per_Day
  MOV    rax,qword [v_dummy1]
  MOV    rcx,864000000000 ;Edit2: der Richtigkeit halber wurde der richtige Wert eingesetzt EndEdit2
  IDIV   rcx
  MOV    qword [v_var2],rax
CQO scheint eine Convert Quoad to O (?) Instruktion zu sein, allerdings hat das Löschen jener Instruktion bei mir keinen Unterschied gemacht.
EndEdit
Zuletzt geändert von Mok am 04.08.2012 10:21, insgesamt 5-mal geändert.
Win 7 Home Premium 64 bit | PureBasic 5.20 - x86 und x86-64 | Firefox [aktuelle stable-Version hier einfügen]
"Jeder macht irgendwann mal Fehler, darum gibt's auch Bleistifte mit Radiergummi." --Carl
Benutzeravatar
Gezuppel
Beiträge: 29
Registriert: 18.09.2004 06:43
Computerausstattung: Intel Core i7 2600 / Asus P8P67 Rev. 3 / 8GB DDR3 / Geforce GTX570
Wohnort: Niedersachsen

Re: Frage zur Division durch Konstanten

Beitrag von Gezuppel »

Hallo Mok,
schneller gehts kaum! Danke dafür!
PureBasic 4.61 / 4.70 Beta1
Windows 7 Ultimate x64
Benutzeravatar
ts-soft
Beiträge: 22292
Registriert: 08.09.2004 00:57
Computerausstattung: Mainboard: MSI 970A-G43
CPU: AMD FX-6300 Six-Core Processor
GraKa: GeForce GTX 750 Ti, 2 GB
Memory: 16 GB DDR3-1600 - Dual Channel
Wohnort: Berlin

Re: Frage zur Division durch Konstanten

Beitrag von ts-soft »

PureBasic 5.73 LTS | SpiderBasic 2.30 | Windows 10 Pro (x64) | Linux Mint 20.1 (x64)
Nutella hat nur sehr wenig Vitamine. Deswegen muss man davon relativ viel essen.
Bild
Benutzeravatar
Helle
Beiträge: 566
Registriert: 11.11.2004 16:13
Wohnort: Magdeburg

Re: Frage zur Division durch Konstanten

Beitrag von Helle »

711573504 ist keine "magische" Zahl :mrgreen: , sondern 864.000.000.000 = 201*(2^32)+711.573.504. Wenn der Quadwert in 2 DoubleWords aufgeteilt wird ist Hi-DWord = 201, Lo-DWord = 711.573.504.
CQO kannste nicht einfach weglassen, das funktioniert nur wenn RDX zufälligerweise gerade Null ist: 64-Bit-(I)DIV = RDX:RAX div Reg/Mem64. CQO (Quad to Oct) setzt RDX, und zwar alle Bits RDX = MSB von RAX.
Trotzdem natürlich ein Bug.
Gruß
Helle
Benutzeravatar
Mok
BotHunter
Beiträge: 1484
Registriert: 26.12.2005 14:14
Computerausstattung: MSI GX780R
Intel Core i5-2410M
Nvidia GT 555M
Windows 7 Home Premium 64 bit
Wohnort:   

Re: Frage zur Division durch Konstanten

Beitrag von Mok »

@Helle: Alles klar, Chef. Dann hab ich mal wieder Schwachsinn geschrieben und 15 Minuten verkackt.
Win 7 Home Premium 64 bit | PureBasic 5.20 - x86 und x86-64 | Firefox [aktuelle stable-Version hier einfügen]
"Jeder macht irgendwann mal Fehler, darum gibt's auch Bleistifte mit Radiergummi." --Carl
Antworten