Seite 1 von 2
Abs() für Ganzzahlen
Verfasst: 16.03.2014 10:50
von Sicro
Eigentlich einfach, aber vielleicht kommt nicht jeder drauf, dass man vor Variablen-Namen einfach ein Minuszeichen voranstellen kann.
Das geht übrigens auch bei Klammern "-(40 - 80)".
Code: Alles auswählen
Procedure.i AbsInt(Number.i)
If Number < 0
ProcedureReturn -Number
Else
ProcedureReturn Number
EndIf
EndProcedure
Debug AbsInt(50) ; gibt "50" aus
Debug AbsInt(-50) ; gibt "50" aus
Re: Abs() für Ganzzahlen
Verfasst: 19.03.2014 22:06
von _sivizius
Code: Alles auswählen
intValue.q = intValue!(intValue>>63)+((intValue>>63)&1)
Re: Abs() für Ganzzahlen
Verfasst: 19.03.2014 23:14
von NicTheQuick
Wenn man rein auf den erzeugten ASM-Output schaut, dann ist es mit einem "If" am schnellsten. Ich habe noch eine ASM-Lösung dazu gepackt, die genauso lang ist wie die PB-Version mit dem If, da man die Sprungmarke nicht mitzählen darf.
Code: Alles auswählen
Macro BM1(var) ;Bits Minus 1
(SizeOf(var) * 8 - 1)
EndMacro
intValue.i = -1
#VERSION = 5
CompilerSelect #VERSION
CompilerCase 1
intValue = intValue ! (intValue >> BM1(intValue)) + ((intValue >> BM1(intValue)) & 1)
; MOV r15,qword [v_intValue]
; MOV r14,qword [v_intValue]
; SAR r14,63
; XOr r15,r14
; MOV r14,qword [v_intValue]
; SAR r14,63
; And r14,1
; ADD r15,r14
; MOV qword [v_intValue],r15
CompilerCase 2
intValue = intValue * -((((intValue >> BM1(intValue)) & 1) << 1) - 1)
; MOV r15,qword [v_intValue]
; MOV r14,qword [v_intValue]
; SAR r14,63
; And r14,1
; SAL r14,1
; DEC r14
; NEG r14
; IMUL r15,r14
; MOV qword [v_intValue],r15
CompilerCase 3
intValue = intValue * (((intValue >> BM1(intValue)) & 1) * -2 + 1)
; MOV r15,qword [v_intValue]
; MOV r14,qword [v_intValue]
; SAR r14,63
; And r14,1
; IMUL r14,-2
; INC r14
; IMUL r15,r14
; MOV qword [v_intValue],r15
CompilerCase 4
If (intValue < 0)
intValue = -intValue
EndIf
; MOV r15,qword [v_intValue]
; And r15,r15
; JGE _EndIf2
; MOV r15,qword [v_intValue]
; NEG r15
; MOV qword [v_intValue],r15
; _EndIf2:
CompilerCase 5
; CompilerIf Not #PB_Compiler_InlineAssembly
; CompilerError "Bitte zuerst InlineASM in den Compiler-Optionen aktivieren."
; CompilerEndIf
CompilerIf SizeOf(intValue) <> 8
CompilerError "Der ASM-Code funktioniert nur auf einem 64-Bit-System mit einer 64-Bit-Ganzzahlvariablen."
CompilerEndIf
!MOV r15, qword [v_intValue]
!MOV r14, r15
!SAR r14, 63
!XOR r15, r14
!SUB r15, r14
!MOV qword [v_intValue], r15
CompilerEndSelect
Debug intValue
Re: Abs() für Ganzzahlen
Verfasst: 20.03.2014 18:18
von _sivizius
stimmt nicht ganz, denn AbsI() ist eine Procedure, damit wäre ein call, ein ret und und noch ein pop, etc notwendig :P
meine Lösung ist einfach kürzer als reiner Text.
Re: Abs() für Ganzzahlen
Verfasst: 17.04.2016 15:24
von GPI
Die Procedure ist trotzdem schneller
Code: Alles auswählen
x=ElapsedMilliseconds()
Procedure.i AbsI(Number.i)
If number<0
ProcedureReturn -Number
EndIf
ProcedureReturn Number
EndProcedure
For i=-100000000 To 100000000
result=AbsI(i)
Next
a$+"AbsI:"+Str(x-ElapsedMilliseconds())+Chr(10)
x=ElapsedMilliseconds()
Macro mAbsI(intValue)
intValue!(intValue>>63)+((intValue>>63)&1)
EndMacro
For i=-100000000 To 100000000
result=mAbsI(i)
Next
a$+"mAbsI:"+Str(x-ElapsedMilliseconds())+Chr(10)
x=ElapsedMilliseconds()
MessageRequester("Results",a$)
zumindest auf meinen PC - Debugger ausschalten nicht vergessen.
Wird in Codearchiv unter Maths\AbsI.pb auftauchen.
Re: Abs() für Ganzzahlen
Verfasst: 17.04.2016 19:00
von Nino
GPI hat geschrieben:Wird in Codearchiv unter Maths\AbsI.pb auftauchen.
Und wozu ist das erforderlich?

Die eingebaute Abs()-Funktion kann doch auch Ganzzahlen verarbeiten, oder habe ich da etwas übersehen?
Re: Abs() für Ganzzahlen
Verfasst: 17.04.2016 19:41
von Sicro
Nino hat geschrieben:Die eingebaute Abs()-Funktion kann doch auch Ganzzahlen verarbeiten, oder habe ich da etwas übersehen?
PB-Hilfe hat geschrieben:Zahl.f
Die Zahl, von welcher der absolute Wert ermittelt werden soll.
Diese Funktion arbeitet nur korrekt mit Fließkomma-Zahlen. Mit Integer (Ganzzahlen) schlägt sie fehl, wenn die Integerzahl zu groß ist (wegen Verlust der Präzision).
Veranschaulichung:
Code: Alles auswählen
; min. Quad: -9223372036854775808
Define.q Value = Abs(-77777777777777777)
Debug Value ; 77777777777777776
Re: Abs() für Ganzzahlen
Verfasst: 17.04.2016 20:31
von Nino
Danke, Sicro!
Ich hatte zwar die Hilfe zu Abs() gelesen, aber nachdem ich irgendwann mal
diesen Thread gelesen hatte dachte ich dass Abs() auch mit Ganzzahlen funktioniert.
Jetzt nehme ich an, dass sich die Aussage von freak in dem Thread wohl nur auf das dort angegebene Beispiel bezog, und nicht auf Abs() und Ganzzahlen im Allgemeinen.
Und die Aussage von BasicallyPure "It does work for integers but the hex value must be within the range of the variable type you are using." trifft eben so allgemein offenbar nicht zu.
Sicro hat geschrieben:Code: Alles auswählen
; min. Quad: -9223372036854775808
Define.q Value = Abs(-77777777777777777)
Debug Value ; 77777777777777776
Dieses Beispiel ist ja wirklich sehr überzeugend.
Danke nochmal!
Re: Abs() für Ganzzahlen
Verfasst: 17.04.2016 22:30
von Sicro
Hallo Nino,
bitte bitte
Ich habe es in den von dir genannten Thread des englischen Forums nun auch mal gepostet.
Hier noch der Code für Long:
Code: Alles auswählen
Define.l Value
; min. Long: -2147483648
Value = Abs(-2147483648)
Debug Value ; -2147483648 => Wegen Überlauf
Debug Bin(Value, #PB_Long) ; 10000000000000000000000000000000
; min. Long: -2147483648
Value = Abs(-2147483647)
Debug Value ; 2147483647
Debug Bin(Value, #PB_Long) ; 1111111111111111111111111111111
Re: Abs() für Ganzzahlen
Verfasst: 18.04.2016 10:30
von NicTheQuick
GPI hat geschrieben:Die Procedure ist trotzdem schneller
zumindest auf meinen PC - Debugger ausschalten nicht vergessen.
Also bei mir ist das Makro 130 ms schneller.