Seite 1 von 2

Inline-If

Verfasst: 06.03.2016 14:37
von Sicro

Code: Alles auswählen

Macro Iif(Expression, TrueValue, FalseValue)
  FalseValue + Bool(Expression) * (TrueValue - FalseValue)
EndMacro

Macro IifS(Expression, TrueString, FalseString, Separator = "|")
  StringField(FalseString + Separator + TrueString, Bool(Expression) + 1, Separator)
EndMacro

Debug IifS(1 = 1, "Ja", "Nein")
Debug IifS(1 = 0, "Ja", "Nein")

Debug Iif(1 = 1, 11, 55)
Debug Iif(1 = 0, 11, 55)
Eine native Implementierung wäre sicherlich performanter...

Hier noch ein Speed-Test:

Code: Alles auswählen

CompilerIf #PB_Compiler_Debugger
  CompilerError "Debugger ausschalten!"
CompilerEndIf
; !!!!!!!!! Purifier ebenfalls ausschalten !!!!!!!!!

Macro Iif(Expression, TrueValue, FalseValue)
  FalseValue + Bool(Expression) * (TrueValue - FalseValue)
EndMacro

Macro IifS(Expression, TrueString, FalseString, Separator = "|")
  StringField(FalseString + Separator + TrueString, Bool(Expression) + 1, Separator)
EndMacro

Define.s Result$
Define.i Result, Time, Time_Result_1, Time_Result_2, i

#Rounds = 100000000

Time = ElapsedMilliseconds()
For i = 1 To #Rounds
  Result$ = IifS(1 = 1, "Ja", "Nein")
  Result$ = IifS(1 = 0, "Ja", "Nein")
  Result  = Iif(1 = 1, 11, 22)
  Result  = Iif(1 = 0, 11, 22)
Next
Time_Result_1 = ElapsedMilliseconds() - Time

Time = ElapsedMilliseconds()
For i = 1 To #Rounds
  If 1 = 1 : Result$ = "Ja" : Else : Result$ = "Nein" : EndIf
  If 1 = 0 : Result$ = "Ja" : Else : Result$ = "Nein" : EndIf
  If 1 = 1 : Result = 11    : Else : Result = 22      : EndIf
  If 1 = 0 : Result = 11    : Else : Result = 22      : EndIf
Next
Time_Result_2 = ElapsedMilliseconds() - Time

MessageRequester("", Str(Time_Result_1) + #CRLF$ + Str(Time_Result_2))

Code: Alles auswählen

10931
6439

Re: Inline-If

Verfasst: 06.03.2016 14:50
von RSBasic
:allright:

Ich hoffe, dass PB das irgendwann selber kann.

Re: Inline-If

Verfasst: 06.03.2016 14:57
von mk-soft
Etwas kürzer

Code: Alles auswählen

Macro IifS(Expression, TrueString, FalseString)
  Left(TrueString, Bool(Expression) * Len(TrueString)) + Left(FalseString, Bool(Not Expression) * Len(FalseString))
EndMacro

Macro Iif(Expression, TrueValue, FalseValue)
  Bool(Expression) * TrueValue + Bool(Not (Expression)) * FalseValue
EndMacro

Debug IifS(1 = 1, "Ja", "Nein")
Debug IifS(1 = 0, "Ja", "Nein")

Debug Iif(1 = 1, 11, 55)
Debug Iif(1 = 0, 11, 55)
:wink:

Re: Inline-If

Verfasst: 06.03.2016 21:06
von NicTheQuick
Man sollte auch den Nebeneffekt beachten, dass "Expression" zweimal ausgeführt wird. Falls Expression eine Funktion ist, wird diese dann auch zweimal ausgeführt, was oftmals nicht gewünscht ist.

Re: Inline-If

Verfasst: 06.03.2016 22:33
von Sicro
@NicTheQuick:
Da hast du recht. Ich habe meinen Code durch eine bessere Version ersetzt. Nun wird die "Expression" immer nur einmal ausgeführt.
Ein Trennzeichen wollte ich eigentlich weglassen, weshalb ich bei der ersten Code-Version auf StringField() verzichtet habe, aber nun habe ich keine andere Wahl.

Re: Inline-If

Verfasst: 07.03.2016 00:14
von STARGÅTE
Ist nicht böse gemeint, aber wie ich im englischen Forum schon schrieb, halte ich nichts von diesen Inline-If Sachen (zumindest nicht in diesem selbstgemachten Zustand).
Speziell geht es um die Problematik, dass beide Zustände (True und False) immer ausgeführt werden, was in diesem Fall z.B. zu Problemen führt:

Code: Alles auswählen

Macro Iif(Expression, TrueValue, FalseValue)
  Bool(Expression) * TrueValue + Bool(Not (Expression)) * FalseValue
EndMacro

Define x.f

x.f = 2.0
Debug Iif(x<>0, 1/x, 0)

x.f = 0.0
Debug Iif(x<>0, 1/x, 0) ; sollte 0 zurückgeben
Probleme gibt es auch mit einer Prozedur, welche die Arithmetik umgeht:

Code: Alles auswählen

Procedure.f Iif_(Query, True.f, False.f)
	If Query
		ProcedureReturn True
	Else
		ProcedureReturn False
	EndIf
EndProcedure

Macro Iif(Expression, TrueValue, FalseValue)
  Iif_(Bool(Expression), TrueValue, FalseValue)
EndMacro

Define x.f

x.f = 2.0
Debug Iif(x<>0, 1/x, 0)

x.f = 0.0
Debug Iif(x<>0, 1/x, 0)
Hier bekommt man sofort die Fehlermeldung, dass nicht durch Null geteilt werden darf, weil eben beide Parameter ausgeführt werden.

Darum hier meine Bitte, doch bitte lieber auf eine echte Implementierung zu warten, statt "unechte" Tricks zu posten.

Re: Inline-If

Verfasst: 07.03.2016 08:42
von Nino
@Stargate:
Ich finde nicht, dass das was Du schreibst generell gegen das Verwenden von selbstgemachtem "Inline-If" spricht. Auch wenn man das normale "If" benutzt darf man nicht durch 0 dividieren. Ja, da gibt es zwar in PB die Kurzschlussauswertung, aber auch dabei muss man wissen was man macht.

@Sicro:
Danke für diese Vorschläge!
Die numerischew Version lässt sich noch etwas vereinfachen, indem man auf das "Not" verzichtet, und da du in der String-Version für das Trennzeichen eine Variable benutzt, muss es natürlich überall als Variable auftauchen. :-)

//edit: evtl. missverständliche Formulierung geändert

Code: Alles auswählen

Macro Iif(Expression, TrueValue, FalseValue)
   FalseValue + Bool(Expression) * (TrueValue - FalseValue)
EndMacro

Macro IifS(Expression, TrueString, FalseString, Separator = "|")
   StringField(FalseString + Separator + TrueString, Bool(Expression) + 1, Separator)
EndMacro

Re: Inline-If

Verfasst: 07.03.2016 09:03
von mhs
Im einem anderen Thread (http://purebasic.fr/german/viewtopic.ph ... 0&start=10) hatte ich schon mal meine Variante gepostet. Total simpel, dafür nicht komplett Inline, weil die Result Variable mit als Paramter übergeben werden muss... dafür ohne Performanceverlust, doppelter Ausführung der Expression... ist ja schließlich nur ein simples If : Else :lol:

Code: Alles auswählen

Macro If_set(Result, Expression, TrueValue, FalseValue)

  If Expression
    Result = TrueValue
  Else
    Result = FalseValue
  EndIf

EndMacro

Define a.s, b.i

If_set(a, 1 = 1, "Ja", "Nein") : Debug a
If_set(a, 1 = 0, "Ja", "Nein") : Debug a

If_set(b, 1 = 1, 11, 55) : Debug b
If_set(b, 1 = 0, 11, 55) : Debug b
Auch wenn ich gerne komplizierte Sachen mache, in dem Fall finde ich einfacher ist smarter :)
Eine nativle Implementation komplett inline wäre mich aber auch sehr recht...

Re: Inline-If

Verfasst: 07.03.2016 09:13
von uweb
Ich finde Stargate hat im Prinzip recht. Wenn es doch aber Spaß macht ... :)
Außerdem weiß man nie was raus kommt solange man es nicht probiert.

Gestern ist Ray Tomlinson gestorben.
Ich möchte nicht wissen was seine Zeitgenossen damals dachten als er die E-Mail erfand.

Wenn es möglich ist mit festen Ergebnissen zu arbeiten kann man auch ein Array oder Konstanten verwenden.
Irgendwo habe ich gelesen, dass Konstanten schneller als Variablen seien.
Wenn man die Reihenfolge der Messungen ändert, ändert sich aber auch das Ergebnis.

Code: Alles auswählen

CompilerIf #PB_Compiler_Debugger
  CompilerError "Debugger ausschalten!"
CompilerEndIf
; !!!!!!!!! Purifier ebenfalls ausschalten !!!!!!!!!

Define.s Result$
Define.i Result, Time, Time_Result_1, Time_Result_2, Time_Result_3, i

#Rounds = 100000000

Dim ResultArray(1)
ResultArray(0) = 11
ResultArray(1) = 22
#T=11
#F=22

Macro Iif(Expression, TrueValue, FalseValue)
  TrueValue + Bool(Not (Expression)) * (FalseValue - TrueValue)
EndMacro

Macro IifA(Expression)
  ResultArray(Bool(Expression)) 
EndMacro

Macro IifK(Expression)
  #T + Bool(Not (Expression)) * (#F - #T)
EndMacro


x.f = 0.0
MessageRequester("", Str(Iif(x<>0, 1/x, 11)) + #CRLF$ + Str(IifA(x<>0))+ #CRLF$ + Str(IifK(x<>0)))


Time = ElapsedMilliseconds()
For i = 1 To #Rounds
  Result  = Iif(1 = 1, 11, 22)
  Result  = Iif(1 = 0, 11, 22)
Next
Time_Result_1 = ElapsedMilliseconds() - Time

Time = ElapsedMilliseconds()
For i = 1 To #Rounds
  Result = IifA(1 = 1)
  Result = IifA(1 = 0)
Next
Time_Result_2 = ElapsedMilliseconds() - Time

Time = ElapsedMilliseconds()
For i = 1 To #Rounds
  Result = IifK(1 = 1)
  Result = IifK(1 = 0)
Next
Time_Result_3 = ElapsedMilliseconds() - Time

MessageRequester("", Str(Time_Result_1) + #CRLF$ + Str(Time_Result_2)+ #CRLF$ + Str(Time_Result_3))

Re: Inline-If

Verfasst: 07.03.2016 12:19
von STARGÅTE
@Nino:
>> "Auch wenn man das normale "If" benutzt darf man nicht durch 0 dividieren."
Richtig, aber beim normalen If, frage ich das ja vorher auch ab, ob x<>0 und lasse dann nur 1/x zu!
Bei deinem Inline-If wird das 1/x leider in jedem Fall ausgeführt.

@mhs:
Deine Variante ist wiederum nicht Inline, somit scheiden Zuweisungen und arithmetische Verschachtelungen aus.