# Wandlung 32Bit Real nach 16Bit Gleitkomma



## BadTaste (2 Februar 2010)

*Wandlung 32Bit Gleitkomma nach 16Bit Gleitkomma*

Hallo,
hat jemand schon mal Codesys dazu bewegt eine 32Bit Real in einen 16Bit Real Wert (ja das gibt es wirklich!) zu wandeln, zur besseren Verständigung:

16Bit Real soll sein:

 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
 S  E  E  E  E  M M M M M M M M M M M
  WERT := (-1)^S * (0.01*M) * 2^(E)

Nun muß ich aber leider andersrum :-( 
Mach ich mir das zu schwer oder ist das so kompliziert?

Danke für Tips
Michael


----------



## Ralle (2 Februar 2010)

Hier http://de.wikipedia.org/wiki/Gleitkommazahl ist ja eine ganze Menge zum Thema zu lesen, inkl. einiger Rechenbeispiele. Reicht das vielleicht schon?


----------



## Chräshe (2 Februar 2010)

*Wieso einfach wenn's auch schwierig geht...*

Hallo BadTaste,

 das hört sich nach einer schönen Aufgabe an. *ROFL* 
Aber was ist der Hintergrund?
 Hat das die Marketing-Abteilung versprochen, 
oder hat es technische Hintergründe?

 Letzteres kann ich mir schwer vorstellen, da es 
auf 2 Byte inzwischen ja nicht mehr so sehr ankommt. 

 Als ganz einfache Lösung würde ich mit Interger arbeiten. 
Sofern der Zahlenraum ausreicht mit einem Faktor 100 
oder 1000 rechnen. Das sind dann indirekt deine 2 oder 3 
Nachkommastellen...

 Wenn das zu einfach ist, hilft nur dem Link von Ralle zu folgen...  :wink:

 Gruß
 Chräshe


----------



## BoxHead (2 Februar 2010)

Hier ein Thread mit einem ganz ähnlichen Thema, aber auch ohne Ergebnis:
http://sps-forum.net/showthread.php?p=217071


----------



## BadTaste (2 Februar 2010)

Neinnein ich lese ein komisches Gerät über Modbus aus und die Japaner fanden das sie es nicht zu einfach für die Europäer machen sollten und nutzten das alte 16Bit Real Format. 
@Ralle
Da habe ich auch schon geschaut aber bei log2(wert) hörte es dann mit codesys auf, dann dachte ich ist doch nicht so schlimm nehme ich eben die Bits aus der Real 32Bit und swap die auf den 16Bit... Mantisse zu Mantisse und Exp zu Exp Vorzeichen ist ja einfach. 
Nun habe ich aber das Problem das ich die Realzahl in Codesys gar nicht in Bits zerlegt bekomme. Dann habe ich (weil Wago841) gedacht da ja MD0 Bit x der Merker MX0.x sein  muß kann ich ja dann die zahl selber zusammenbauen. Nun habe ich also folgendes gemacht:


```
FUNCTION_BLOCK FB_REA
VAR_INPUT
    REAL32 AT %MD0 :REAL;
END_VAR
VAR_OUTPUT
    REAL32_to_REAL16:WORD;
END_VAR
VAR
    WORD_TEMP: WORD;
    E_OUT_TEMP:DWORD;
END_VAR


E_OUT_TEMP:=%MD0;

(*        ### Vorzeichen ###        *)
WORD_TEMP.15:=%MX0.15;
(*        ### Exponent ###            *)
WORD_TEMP.14:=%MX1.14;
WORD_TEMP.13:=%MX1.13;
WORD_TEMP.12:=%MX1.12;
WORD_TEMP.11:=%MX1.11;
(*        ### Mantisse ###            *)
WORD_TEMP.10:=%MX0.10;
WORD_TEMP.9:=%MX0.9;
WORD_TEMP.8:=%MX0.8;
WORD_TEMP.7:=%MX0.7;
WORD_TEMP.6:=%MX0.6;
WORD_TEMP.5:=%MX0.5;
WORD_TEMP.4:=%MX0.4;
WORD_TEMP.3:=%MX0.3;
WORD_TEMP.2:=%MX0.2;
WORD_TEMP.1:=%MX0.1;
WORD_TEMP.0:=%MX0.0;

REAL32_to_REAL16:=WORD_TEMP;
```
Was aber komisch ist das das Bitmuster von E_OUT_TEMP unterschiedlich ist als REAL32

Ich steh komplett auf dem Schlauch, mir würde schon reichen wie ich Bitx aus einer realzahl bekomme.

schönen Abend
 Michael


----------



## Ralle (2 Februar 2010)

Irgendwie glaube ich nicht daran, daß man das so einfach ummappen kann, denn Mantisse und Exponent beziehen sich ja bei jedem Gleitkommaformat auf unterschiedliche Formeln. Bei Codesys sollte es ja auch IEEE 754 sein oder?

32-Bit Gleitkomma:

Die Formel wäre: 
	

	
	
		
		

		
			





und für 64-Bit: 
	

	
	
		
		

		
		
	


	




Im Prinzip mußt du also die Formel für deine 16-Bit-Gleitpunkt kennen und daraus mit der zugehörigen Formel deinen Dezimalzahl berechnen. Anders herum mußt die nach dem Schema bei Wikipedia die Dezimalzahl in Mantisse und Exponent zerlegen, da kommst du um den log wohl nicht herum.


----------



## BadTaste (3 Februar 2010)

Hi,
kann man denn den log zur Basis 2 mit codesys rechnen? Oder was mich auch brennend intressiert kann man ein Bit aus einer Realzahl separieren?

schönen Tag
Michael


----------



## Werner29 (3 Februar 2010)

BadTaste schrieb:


> Hi,
> kann man denn den log zur Basis 2 mit codesys rechnen? Oder was mich auch brennend intressiert kann man ein Bit aus einer Realzahl separieren?
> 
> schönen Tag
> Michael



Bitzugriffe, Rotate und Shift (Funktionen die du vermutlich brauchst) werden tatsächlich nicht für Real unterstützt. Aber CoDeSys unterstützt Pointer, bau dir doch deine Real Zahl in einem DWORD zusammen und verwende dieses DWORD dann über einen POINTER TO REAL,
ptReal := ADR(dword);
Dann kannst du entweder über den Pointer arbeiten oder mit
realvar := ptReal^; 
den Wert in eine Realzahl kopieren. Umgekehrt geht das natürlich genauso.
ptDword := ADR(real);
dwordVar := ptDword^;
Dann hast du das real in deinem DWORD und mit dem kannst du alles machen, was du willst.
Ich würde mal im Internet nach C-Code suchen, der das erledigt, sowas muss eigentlich zu finden sein. Und wenn du's hinbekommst wäre das wohl ein guter Beitrag zur Veröffentlichung hier im Forum.
Nachtrag: LOG2 gibts nicht in CoDeSys, aber ich kann mir fast nicht vorstellen, dass der notwendig sein wird. Eigentlich bin ich der Meinung, dass es reichen
müsste den Exponent anzupassen und die Mantisse zu kopieren (sofern der Wertebereich passt).


----------



## Oberchefe (3 Februar 2010)

> kann man denn den log zur Basis 2 mit codesys rechnen?



Sicher, zwar nicht direkt, aber indirekt.
Codesys kann mit dem natürlichen Logarithmus rechnen, das reicht aus. Die Formel sieht dann so aus:

```
Ergebnis:=LN(Eingangszahl)/LN(2);
```

Natürlich sicherstellen dass nur mit Positiven Zahlen <> 0 gerechnet wird!


----------



## BadTaste (3 Februar 2010)

Hallo werner29,
danke für die guten Tips, so bekomme ich das hin!
Auf den Pointer bin ich nicht gekommen dabei liegt es auf der Hand, inzwischen habe ich mir auch eine Lösung gebastelt, da ich eine temperatur übertrage und die sich nur zwischen 18 und 50°C liegt habe ich den Exp fest auf 4 eingestellt und arbeite dann mit multiplikation den Wert wieder richtig, da die zeit mich drängt werde ich mich später noch einmal damit befassen... ist ja nicht uninteressant.

@Obercheffe
na dann kann ich ja alles zusammenbauen... Thx
Danke
Michael


----------



## Werner29 (3 Februar 2010)

Folgendes funktioniert für Wandlung von real nach lreal, ich habs mal schnell in CoDeSys V3 eingehackt. Ich weiss nicht ob das auch auf Motorola-Systemen funktioniert.

FUNCTION realtolreal : LREAL
VAR_INPUT
    rlin : REAL;
END_VAR
VAR
    ptrl : POINTER TO REAL;
    pdw : POINTER TO DWORD;
    dw : DWORD;
    lw : LWORD;

    bvz : BOOL;
    dwMantissa : DWORD;
    dwExp : DWORD;

    lwExp : LWORD;
    lwMantissa : LWORD;
    ptrlr: POINTER TO LREAL;
END_VAR
pdw := ADR(rlin);

dw := pdw^;
bvz := dw.31;
dw.31 := 0;
dwExp := SHR(dw, 23);
dwMantissa := SHR(SHL(dw, 9), 9);

lwExp := (dwExp-127) + 1023;
lwExp := SHL(lwExp, 52);
lwMantissa := dwMantissa;
lwMantissa := SHL(lwMantissa, 52 - 23);

lw := lwExp OR lwMantissa;
lw.63 := bvz;

ptrlr := ADR(lw);
realtolreal := ptrlr^;


----------



## W1z4rd64 (4 Oktober 2017)

Hallo Zusammen

Ich beschäftige mich auch schon einweilchen mit diesem Thema 32Bit Real to 16 Bit Real.

Ich habe schon folgendes ausprobiert:


```
FUNCTION_BLOCK Real_To_RealWord
VAR_INPUT
    rData:REAL;
END_VAR
VAR_OUTPUT
    wOut:WORD;
    iZaehler:INT;
END_VAR
VAR
    stelle: INT:= 15;
    dwData:DWORD;
    baData_temp: ARRAY [0..20] OF BOOL;
    iaData_temp: ARRAY [0..30] OF INT;
    rest: INT;
    iZaehler_temp: INT;
END_VAR
```


```
dwData := REAL_TO_DWORD (rData) ;

iZaehler := TRUNC(rData * 100) / 100; (* Kommastellen bschneiden*)

WHILE NOT (iZaehler=1 OR stelle<10 OR stelle <=1)  DO
 iZaehler_temp :=  iZaehler/2;

IF(iZaehler_temp*2 = iZaehler)
THEN baData_temp[stelle]:= FALSE; iaData_temp[stelle]:=4;
ELSE baData_temp[stelle]:= TRUE; iaData_temp[stelle+10]:=3;
END_IF;

iZaehler:=iZaehler_temp;
 stelle:= stelle-1;
iaData_temp[20]:=stelle;
END_WHILE



IF(dwData.0 OR dwData.1 OR dwData.2 OR dwData.3 OR dwData.4 OR dwData.5 OR dwData.6 OR dwData.7 OR dwData.8 OR dwData.9 OR dwData.10 OR dwData.11 OR dwData.12 AND NOT dwData.13 )
THEN wOut.0 := TRUE;            (* Exponent 10 *)
ELSE wOut.0 := FALSE;            (* Exponent 10 *)
END_IF;

IF(dwData.28 OR dwData.29 OR dwData.30 )
THEN
wOut.10 := TRUE;            (* Mantisse 5 *)
wOut.11 := TRUE;            (* Mantisse 4 *)
wOut.12 := TRUE;            (* Mantisse 3 *)
wOut.13 := TRUE;            (* Mantisse 2 *)
wOut.14 := TRUE;            (* Mantisse 1 *)
ELSE
wOut.10 := dwData.23;            (* Mantisse 5 *)
wOut.11 := dwData.24;            (* Mantisse 4 *)
wOut.12 := dwData.25;            (* Mantisse 3 *)
wOut.13 := dwData.26;            (* Mantisse 2 *)
wOut.14 := dwData.27;            (* Mantisse 1 *)
END_IF;

wOut.1 := dwData.14;            (* Exponent 9 *)
wOut.2 := dwData.15;            (* Exponent 8 *)
wOut.3 := dwData.16;            (* Exponent 7 *)
wOut.4 := dwData.17;            (* Exponent 6 *)
wOut.5 := dwData.18;            (* Exponent 5 *)
wOut.6 := dwData.19;            (* Exponent 4 *)
wOut.7 := dwData.20;            (* Exponent 3 *)
wOut.8 := dwData.21;            (* Exponent 2 *)
wOut.9 := dwData.30;            (* Exponent 1 *)
wOut.15 := dwData.31;        (* Wert +/- *)
```

Ich bin mir aber nicht wirklich sicher ob dies der richtige Ansatz für dieses Problem ist.

evtl. kann mir jemand noch einen Tipp oder hilfestellung beim Code geben ?

Ich arbeite mit Codesys 2.3 an diesem Problem.

Danke Gruss W1z7rd64


----------

