# Absolut Betrag "ausrechnen"



## Krumnix (4 Dezember 2018)

Hallo.

Ich hab hier ne Steuerung (iTNC530) welche keinen ABS Befehl kennt. 
Gibt es eine Möglichkeit mit einer Formel den "Abstand" zu Null, also den absolut Betrag zu errechnen?

Ich möchte keine IF Bedingung erstellen, da ich die Auswertung auch an andere Stelle brauche, wo IF nicht funktioniert.

Jemand einen Tipp?
Danke!


----------



## holgermaik (4 Dezember 2018)

du könntest das Quadrat bilden und daraus die Wurzel ziehen.


----------



## Krumnix (4 Dezember 2018)

Hab ich leider nicht. Also den Wurzel-Befehl.


----------



## Rüdesheim (4 Dezember 2018)

Nimm doch deinen Wert und den mit -1 multiplizierten Wert und bilde daraus eine Maxauswahl.
Das Ergebnis sollte dann dein Betragswert sein.


----------



## Onkel Dagobert (4 Dezember 2018)

Wie sieht es mit "Schieben" aus? Einmal nach links und einmal nach rechts?


----------



## Heinileini (4 Dezember 2018)

Onkel Dagobert schrieb:


> Wie sieht es mit "Schieben" aus? Einmal nach links und einmal nach rechts?


Gaaanz schlecht, Onkel Dagobert!
Sogar, wenn man zwei Arten von RechtsSchieben zur Auswahl hat: 
- mit Vorzeichen: damit machst Du u.U. aus einer positiven Zahl eine negative, nämlich, wenn das zweithöchstwertige Bit 1 ist.  
- ohne Vorzeichen: damit machst Du u.U. aus einer negativen Zahl eine positive.
Aber in beiden Fällen: mit dem Betrag der so bearbeiteten Zahl hat das nix zu tun!
Das sogenannte VorzeichenBit heisst nur so, weil man an dem Bit ablesen kann, ob die Zahl positiv oder negativ ist.
Das "Umkippsen" des VorzeichenBits verändert aber in jedem Fall den Betrag der Zahl und nicht nur das Vorzeichen!

Ansatz:
Zahl*(Zahl>(-Zahl))+ Zahl*(Zahl<(-Zahl)) // funktioniert in Excel, da True 1 entspricht und False 0
Wenn allerdings True -1 entspricht, müsste man z.B.
-Zahl*(Zahl>(-Zahl)) - Zahl*(Zahl<(-Zahl)) 
schreiben.

Korrektur:
Sorry, es war so gut gemeint, aber trotzdem so falsch! Also, jetzt mit ohne TippFehler (hoffentlich):
Zahl*(Zahl>(-Zahl)) - Zahl*(Zahl<(-Zahl)) // funktioniert in Excel (TabellenBlatt), da True 1 entspricht und False 0
Wenn allerdings True -1 entspricht, müsste man z.B.
Zahl*(Zahl<(-Zahl)) - Zahl*(Zahl>(-Zahl)) // z.B. in VBA
schreiben!

​


----------



## PN/DP (4 Dezember 2018)

In Step7 bedeutet "*ABS*": Absolutwert einer *Gleitpunktzahl*
Da funktioniert die Betragsbildung tatsächlich so, daß das höchste Bit .31 (das Vorzeichenbit) auf 0 gebracht wird, weil bei Gleitkommazahlen nach IEEE 754 (REAL) das Vorzeichen und der Betrag der Zahl getrennt gespeichert sind.

Bei Ganzzahlen (Festpunktzahlen) funktioniert das nicht, weil die im Zweierkomplement gespeichert sind und es kein isoliertes Vorzeichenbit gibt.

Das höchste Bit auf 0 setzen kann man durch maskieren/ausblenden: "AbsBetrag := realValue AND DW#16#7FFFFFFF"
oder auch durch das vom Onkel erwähnte 1 Bit Links- und nachfolgend 1 Bit Rechtsschieben. Wichtig: das Rechtsschieben muß ein 0-Bit einschieben.

Die Max-Funktion halte ich für am besten, weil die mit Gleitpunktzahlen und auch mit Ganzzahlen gleich funktionieren würde. (SCL, ST, FUP, KOP, CFC) Welche Anweisungen die hier verwendete NC-Steuerung kann, weiß ich aber nicht. Vermutlich läßt sich da auch eine Rechenformel ohne IF (ohne Sprünge) finden.

Harald


----------



## LargoD (5 Dezember 2018)

Hier steht die Formel für INT.
Gruß
Erich


----------



## UNI (6 Dezember 2018)

-----------------


----------



## Heinileini (6 Dezember 2018)

PN/DP schrieb:


> Vermutlich läßt sich da auch eine Rechenformel ohne IF (ohne Sprünge) finden.


Davon gehe ich auch aus und das hatte ich in #6 gemeint. Leider hatte ich dort + und - verwechselt 
Hab dort die Korrektur angefügt.
Die beiden dortigen Formeln habe ich nun zu einer zusammengefasst, durch Hinzufügen von "* (0=0)", wodurch nun egal ist, ob TRUE ProgrammierSprachen-abhängig den ZahlenWert 1 oder -1 hat:

AbsVonZahl = (Zahl * (Zahl > (-Zahl)) - Zahl * (Zahl < (-Zahl)) * (0 = 0)

Natürlich geht das auch noch etwas kompakter, da ABS(Zahl) = SGN(Zahl) * Zahl ist:
Mit
SgnVonZahl = ((Zahl > 0) - (Zahl < 0)) * (0 = 0)
erhält man
AbsVonZahl = ((Zahl > 0) - (Zahl < 0)) * (0 = 0) * Zahl

Vorausgesetzt wird aber weiterhin, dass die ProgrammierSprache mit den Bool-Ergebnissen der Vergleiche weiterrechnen kann, also automatisch die TypKonvertierung durchführt oder grosszügig über den TypenMischMasch hinwegsieht. Falls nicht, müsste man die 3 TypKonvertierungen noch ergänzen - sofern sie in der ProgrammierSprache nicht auch noch wegrationalisiert wurden.

Apropos Typ: Zahl kann eine Ganzzahl oder GleitKommaZahl sein.


----------



## LargoD (7 Dezember 2018)

Den Algorithmus aus dem Beitrag #8 habe ich jetzt mal in AWL umgesetzt.
Ist erstaunlich kurz geworden.

```
FUNCTION "MyAbs2" : DINT
TITLE =Abs von DInt ohne Sprung

VAR_INPUT
  v : DINT ;    
END_VAR
BEGIN
NETWORK
TITLE =

      L     #v; 
      SSD   31; // Vorzeichen in alle Bits kopieren (mask)
      L     #v; 
      XOD   ; // XOR mit dem Eingangswert
      TAK   ; 
      -D    ; // mask subtrahieren
      T     #RET_VAL; // das war's

END_FUNCTION
```
 In SCL wird es etwas länger weil man wegen der Typprüfung mehrmals von DINT nach DWORD und umgekehrt umwandeln muss.
Gruß
Erich


----------



## Heinileini (7 Dezember 2018)

LargoD schrieb:


> Ist erstaunlich kurz geworden.
> . . .
> In SCL wird es etwas länger weil man wegen der Typprüfung mehrmals von DINT nach DWORD und umgekehrt umwandeln muss.


Wen erstaunt das?

Ein "bedingter NEGD" also, aber eben ohne SprungBefehl.

Das ist ja das "perverse", dass die vermeintlichen TypKonvertierungen in diesem Fall nichts anderes tun, als "nur" die TypPrüfung zu befriedigen.
Wirkliche Konvertierungen finden nicht statt, weil sich das BitMuster nicht verändert.
Der ganze Aufwand dient lediglich dazu, zu testen, ob der Programmierer schon am einnicken ist.

PS:


Krumnix schrieb:


> Ich möchte keine IF Bedingung erstellen, da ich die Auswertung auch an andere Stelle brauche, wo IF nicht funktioniert.


Nur aus reiner Neugier: Was ist denn an anderen Stellen so anders, dass an denen IF nicht funktioniert?


----------



## LargoD (7 Dezember 2018)

Heinileini schrieb:


> ... dass die vermeintlichen TypKonvertierungen in diesem Fall nichts anderes tun, als "nur" die TypPrüfung zu befriedigen.
> Wirkliche Konvertierungen finden nicht statt, weil sich das BitMuster nicht verändert.
> Der ganze Aufwand dient lediglich dazu, zu testen, ob der Programmierer schon am einnicken ist.


Ich mag das, wahrscheinlich deshalb, weil ich schon immer lieber Pascal/Delphi als C programmiere. Ich sehe diese Typumwandlungen die nichts umwandeln so, dass damit der Programmierer dem Compiler sagt: Schweig, ich weiß was ich tue.
Gruß
Erich


----------



## Krumnix (11 Dezember 2018)

Mein Problem dabei ist, dass die Steuerung mit nur + - * / anbietet sowie die Standard-Funktionen  A O AN ON XOR ...

Im Moment mache ich das alles über eine IF-Abfrage. Sprich, wenn der Wert <0 dann * -1.
Ein IF kann ich aber später in einem IF-Kopf nicht wieder verwenden und suche hier eine andere Lösung.

Beispiel:

```
L   Var1
ABS                 <--- Das ist ein "Marko"
> 20
IFT
   BlaBlaBla
ENDI
```

ABS-Makro:

```
PL
<0
IFT
  * -1
ENDI
PS
```

Das IFT in einen IF-Kopf geht leider nicht. Suche noch Lösungen dazu


----------



## PN/DP (11 Dezember 2018)

Welche Datentypen kann die Steuerung? Kann sie TypeCasts oder Typ-Konvertierungen? Was passiert wenn bei einer Operation ein Datentyp-Überlauf auftritt (z.B. Int: 32000 + 10000, oder 60000 + 10000)?
Mit welchem Datentyp oder welchen Datentypen soll Dein ABS-Makro funktionieren?
Kann die Steuerung "MOD"?

(Bist Du sicher, daß die Steuerung keine ABS-Funktion hat?)

Harald


----------



## Krumnix (7 Januar 2019)

@PN/DP
Ja, bin mir sicher, dass sie kein ABS kann. Aussage vom Hersteller. ABS für INT/WORD/DINT/DWORD gibt es nicht.
Nur für Real/Float, eingeführt vor ein paar Jahren...

Die Steuerung, bzw. der Compiler bietet einem an, Funktionen, welche man mehrmals benötig als sogenannte Makros zu schreiben und diese können dann überall mit einem kurzen Aufruf gestartet werden.
Dabei wird jedoch nicht eine Übergabe an eine Funktion ausgeführt (z.B. bei C++ oder ein FB/FC bei Siemens, welcher dann abgearbeitet wird), sondern der in dem Makro geschrieben Code einfach nur eingefügt wird.

Wenn ich z.B. eine Berechnung mehrmals machen möchte, die Formel dazu aber immer gleich ist, erstelle ich ein Makro und nutze dies dann immer.

Beispiel:
Formel: r = a + b + c + d

Makro:

```
#define /m Formal1(value_a,value_b,value_c,value_d,result_r)
  L (value_a)
  + (value_b)
  + (value_c)
  + (value_d)
  = (result_r)
```

Wenn ich das nun im Programm einfüge wäre das z.B. so:

```
Formel1(10,20,30,40,M_Ergebnis)
L M_Ergebnis
.....
```

Der Compiler macht danach in der fertig zu übertragenen Datei folgendes:

```
L 10
  + 20
  + 30
  + 40
  = M_Ergebnis
L M_Ergebnis
.....
```

Wenn ich das nun mit einem Vergleich mache, ob eine Zahl kleiner Null ist und ich sie dann Multipliziere mit -1, dann habe ich ein IF in einem IF-Kopf:

```
L  AABBCC
A  BBCCDD
> ABS(TestZahlABS)
  L TestZahlABS
  < 0
  IFT
    L  TestZahlABS
    X  K-1
    =  TestZahlABS
  ENDI
IFT
  BlaBlaBla
ENDI
```

Das funktioniert aber nicht...

Daher bin ich auf der Suche nach einer Lösung, welche nur mit + - * / zum Ergebnis kommt....


----------



## Heinileini (7 Januar 2019)

Krumnix schrieb:


> Daher bin ich auf der Suche nach einer Lösung, welche nur mit + - * / zum Ergebnis kommt....


Bedeutet dass etwa, dass Du immer noch auf der Suche danach bist?
Hast Du denn schon mal das eine oder andere ausprobiert, was wir Dir vorgeschlagen hatten, so ganz mit ohne IF und "kopflos"?


----------



## Krumnix (7 Januar 2019)

@Heinileini:
Sonst würde ich nicht weiterhin hier fragen...
Deine Vorschläge funktionieren auf der iTNC530 nicht, da diese einen Vergleich in einer Formel ohne Einsatz von IFT nicht auswertet.


----------



## DeltaMikeAir (7 Januar 2019)

> Sonst würde ich nicht weiterhin hier fragen...
> Deine Vorschläge funktionieren auf der iTNC530 nicht, da diese einen  Vergleich in einer Formel ohne Einsatz von IFT nicht auswertet.



Diesen Beitrag hätte man als Weihnachtsrätsel 2018 nehmen können


----------



## Heinileini (7 Januar 2019)

@Krumnix
Ich bin leider etwas schwer von Begriff und habe immer noch nicht verstanden, was mit "IF im IF-Kopf" gemeint ist.
Bedeutet das, dass IF-Abfragen nicht verschachtelt werden können?
Kann man denn IF-Abfragen in Makros nicht verwenden?
Gibt es (wider Erwarten) eine SIGN-Funktion?
Was ist das überhaupt für eine Sprache? Erinnert mich an (optisch aufgepeppte) AWL.
Ich hatte zum Thema iTNC530 einiges bei Heidenhain gefunden, aber bisher noch nichts, was Deinen Beispielen ähnelt.
Gibt's da was "für zum" Runterladen als pdf?

@Michael
Nach Weihnachten ist vor Weihnachten, also könnten wir dieses Thema vormerken.


----------



## PN/DP (7 Januar 2019)

Wir wissen immer noch nicht, was Deine Steuerung außer + - * / kann.
Kann sie MOD, WORD-OR und/oder Schiebebefehle?

Geht vielleicht sowas:

```
#define ABS(TestZahlABS)
  L  TestZahlABS
  OR 1
  MOD 2
  * TestZahlABS
```

Harald


----------



## Krumnix (7 Januar 2019)

@Heinileini:
Ja, die Sprache ich etwas komisch. Erinnert ein wenig an AWL. Nennt sich Heidenhain ST.
Der Anfang beginnt immer mit einem L (Lade/Load).
Danach kann man A (AND) O (OR) und was es noch alles gibt, einsetzen.
A, AN (AND NOT), O, ON, XO (exkl. ODER), XON, +, -, X (Multi), /, MOD, >> (schieben), <<, = (zuweisen)

IF sieht dann so aus:
IFT (Abfrage, ob Akku = TRUE ist)
IFF (Abfrage, ob Akku = FALSE ist)
...
...
ENDI

Im IF-Kopf meinte ich damit, dass ein ENDI nicht vor ein IFT stehen kann, ohne dass die vorherige Bedingung sicher ausgewertet wurde.

```
L   A
A   B
A[
    L   K+5
    >  K+4
]
IFT
ENDI
```
Dies würde funktionieren.


```
L   A
A   B
A[
    L   K+5
    >  K+4
    IFT
       L   K+20
       =  C
    ENDI
]
IFT
ENDI
```
Dies funktioniert nicht, würde aber die derzeitige ABS-Lösung sein. 
Aktuell lege ich mir in jedem Baustein ein Dummy an, und schreibe mir das Ergebnis des derzeitigen ABS (mit IFT) darein und werte diesen dann in meinen darauffolgenden IF-Kopf aus.

Nun bin ich an dem Punkt, wo ich 2 ABS gleichzeitig benötigte und ggf. bald 3 brauche. Ich will aber nicht noch mehr Dummys anlegen, sondern suche eine Lösung, ohne das Ergebnis in eine Dummy-Variable zu speichern. 
Damit das funktioniert, erlaubt mit Heidenhain in dem Moment leider nicht den Einsatz von IFT/ENDI


----------



## PN/DP (7 Januar 2019)

LargoD schrieb:


> Hier steht die Formel für INT.





LargoD schrieb:


> Den Algorithmus aus dem Beitrag #8 habe ich jetzt mal in AWL umgesetzt.
> Ist erstaunlich kurz geworden.
> 
> ```
> ...


Leider ist das die (möglicherweise unzulässig) patentierte Variante des Algorithmus.
So 'rum ist es nicht patentiert:

```
[COLOR="#008000"]// r = (v + mask) ^ mask;[/COLOR]
      L     #v;
      SSD   31; [COLOR="#008000"]// Vorzeichen in alle Bits kopieren (mask)[/COLOR]

      L     #v;
[COLOR="#008000"]//[/COLOR]    [COLOR="#0000FF"]ENT[/COLOR]   ;   [COLOR="#008000"]// bei PLCSIM und CPU mit 4 AKKUs[/COLOR]
      +D    ;   [COLOR="#008000"]// mask addieren[/COLOR]

      XOD   ;   [COLOR="#008000"]// XOR mit mask[/COLOR]
      T     #RET_VAL;
```


----------



## Heinileini (7 Januar 2019)

Wenn RechtsSchieben das Vorzeichen mitnimmt:

L #V   // Variable laden​>> 31  // bei DINT um 32 bzw. bei INT um 16 Bit-Positionen nach rechts schieben​* 2    // mit 2 multiplizieren (oder um 1 Bit-Position nach links schieben)​+ 1    // 1 addieren​L #V   // ZwischenErgebnis mit Variable multiplizieren​*​​


----------



## Krumnix (7 Januar 2019)

Da kommt leider der .... Compiler von Heidenhain dazwischen.
Die Lade-Befehl schreibt ein Byte, Word, Int, DWord, DInt immer in den 32 Bit Akku und wandelt in diesem Moment ein 16 Bit in ein 32 Bit.
Die Zuweisung = macht das ganze dann in die andere Richtung.
Sprich, bei Word-Zuweisung würden dann die ersten 16 Bit genommen, die anderen "verfallen".
Bei einem DWord wären die 32 dann "voll". 
Irgendwie scheint die Heidenhain aber das Vorzeichen in diesem Fall nicht zu beachten, sprich es bliebt auf dem 16. Bit stehen, wenn ich schiebe im 32er Akku, dann interessiert das leider niemand 
Sobald ich eine "Überprüfung" mache, ob 16 oder 32 Bit Wert, habe ich wieder mein IFT...
Ein Teufelskreis.

Sprich, bei einem DInt funktioniert es, bei einem INT leider nicht  

Daher vor ja meine "Vorgabe" nur mit den Grundrechenarten eine Lösung finden. Heidenhain selbst löst das im übrigen auf mit einem Zwischenmerker...


----------



## Heinileini (7 Januar 2019)

Krumnix schrieb:


> Sprich, bei einem DInt funktioniert es, bei einem INT leider nicht


Wenn ich nicht schon graue Haare hätte . . .
Bei Dint funktioniert's, aber Du hast keine Chance eine IntZahl "artgerecht" in eine gleichbedeutende DintZahl umzuwandeln bzw. umgekehrt?

Ich ahne was:
Int in den Akku laden, dann 16 BitPositionen nach links schieben und dann wieder 16 Positionen nach rechts, danach sollte aber die Int Zahl im Dint-Format im Akku stehen.


----------



## PN/DP (7 Januar 2019)

Krumnix schrieb:


> Sprich, bei einem DInt funktioniert es, bei einem INT leider nicht


Auf welche Lösung beziehst Du Dich?
Gibt es in der Heidenhain keine INT zu DINT Umwandlung (ITD, INT_TO_DINT, ...)?

Harald


----------



## Krumnix (7 Januar 2019)

PN/DP schrieb:


> Auf welche Lösung beziehst Du Dich?
> Gibt es in der Heidenhain keine INT zu DINT Umwandlung (ITD, INT_TO_DINT, ...)?
> 
> Harald



Das wäre traumhaft. Nein, leider nicht 

Ich beziehe mich auf das Schieben des Wertes.
Wenn ich ein Dint habe und die 32. Stell "rausschiebe" und dann mit einer Null zurückschiebe, dann funktioniert es. Ich kann auch eine Maske auf die Stelle setzen, gleicher Erfolg.
Bei einem INT leider nicht. 
Da ich keine Auswertung ohne ein IF machen kann, müsste ich für INT und DINT zwei Makros schreiben. Mag ich aber nicht. 
Wenn schon, denn schon


----------



## Heinileini (7 Januar 2019)

Heinileini schrieb:


> . . . Int in den Akku laden, dann 16 BitPositionen nach links schieben und dann wieder 16 Positionen nach rechts, danach sollte aber die Int Zahl im Dint-Format im Akku stehen.


Das obige funktioniert nicht, um Int in Dint zu wandeln???


----------



## PN/DP (7 Januar 2019)

Krumnix schrieb:


> Wenn ich ein Dint habe und die 32. Stell "rausschiebe" und dann mit einer Null zurückschiebe, dann funktioniert es. Ich kann auch eine Maske auf die Stelle setzen, gleicher Erfolg.



Meinst Du wirklich *DINT*? Das dürfte mit einem DINT nicht funktionieren. Ich hatte schon in #7 erklärt daß das nur bei REAL funktioniert.

INT = Festpunktzahl (Ganzzahl) 16 Bit, Format: Zweierkomplement
DINT = Festpunktzahl (Ganzzahl) 32 Bit, Format: Zweierkomplement
REAL = Gleitpunktzahl 32 Bit, Format: IEEE754

Harald


----------

