# [wie] CEIL oder FRAC mit Codesys Boardmitteln



## Kurt (27 Dezember 2005)

Hallo,

entweder bin ich blind oder habe die Feiertage zu viel gegessen.

Bei Codesys habe ich kein CEIL (immer aufrunden) oder FRAC (Nachkommawert einer Real).
Wie kann man das zykluszeitschonend mit Codesys realisieren.
Das Zeug steht in einer FOR Schleife...

TRUNC rundet immer ab.

Mache jetzt sowas wie (Pseudocode)

if (Wert > Trunc(Wert))
then Ergebnis = Trunc(Wert)+1
else Ergebnis = Trunc(Wert)

gibt es was Gescheiteres?
Habe eine SchmalspurSPS die nicht wirklich REAL Zeug mag und aus dem letzten Loch pfeift.

Kurt  :shock:


----------



## Zottel (27 Dezember 2005)

Kurt schrieb:
			
		

> Hallo,
> if (Wert > Trunc(Wert))


Das dürfte ein integer in real zurückwandeln und den Vergleich dann in real ausführen...


> then Ergebnis = Trunc(Wert)+1
> else Ergebnis = Trunc(Wert)


und hier wird dann nochmal die nicht-triviale Funktion trunc aufgerufen. Kürzer wäre:

```
Ergebnis=Trunc(Wert)
if Wert >Ergebnis then Ergebnuis=Ergebnis+1

Ansonsten: Wie genau brauchst du es? Ich gehe mal davon aus, daß du glaubst, daß ceil() immer den nächsthöheren Wert liefert außer wenn die Zahl wirklich exakt mit dem Integer übereinstimmt, also:
7.000000001 >8
7.000000000 >7
Die Rechengenauigkeit in IEEE-32-Bit-Float ist aber etwas geringer. (23bit/ln10*ln2) gibt fast 7 Zehnerstellen. 
Also ergibt erst ceil(7.0000014) oder so 8.
Da deine Nachkommastellen wahrscheinlich eh mit den Rechenfehlern einer vorhergehenden Rechnung behaftet sind, könntest du nicht auch damit leben, auch 7.0 aufzurunden?
Ergebnis=Trunc(Wert)+1 ??
```


----------



## Kurt (27 Dezember 2005)

Hallo,

hast natürlich recht!
in meinem SPS-Code habe ich nur einmal 'geTRUNCen'.
Und jetzt habe ich auch noch die Zwischenvariable gekübelt.

Die Kommastellen zu kürzen, oder mit Fixwerten also DINT zu rechen ist (vermutlich) zu ungenau. Es geht um einen Vergleich in der Formel und 7.000000001 ist eben auch schon fast  zu groß.
Die Formel ist nicht von mir sondern von einem Technologen und ich baue Diese nur nach und muss kontrollieren ob das Gleiche rauskommt.

Im source der VCL (Delphi) habe ich mir angesehen wie es da realisiert ist. CEIL und TRUNC bauen auf FRAC auf und FRAC wurde in Assembler mit einer Latte von FLOAT Befehlen realisiert.

Das kann man mit einem 166er Derivat + SPS  so nicht machen.

Danke von 
  Kurt


----------



## Zottel (28 Dezember 2005)

Kurt schrieb:
			
		

> Die Kommastellen zu kürzen, oder mit Fixwerten also DINT zu rechen ist (vermutlich) zu ungenau. Es geht um einen Vergleich in der Formel und 7.000000001 ist eben auch schon fast  zu groß.
> Die Formel ist nicht von mir sondern von einem Technologen und ich baue Diese nur nach und muss kontrollieren ob das Gleiche rauskommt.


1. Wenn es eine Formel ist, die eine stetige Funktion der Eingangsgröße liefert, wozu brauchst du überhaupt ceil()? Prinzipbedingt fügt ceil() einem Wert einen Fehler zwischen 0 und +1 hinzu.
2. Wenn der Technologe ceil() verwendet und du zeigen mußt, daß das Gleiche rauskommt, hast du zwar das Problem, daß sein ceil() vielleicht noch 7 liefert während 1+trunc() schon 8 gibt (in einem vernachlässigbar schmalen Intervall) aber selbst mit ceil() auf einer anderen Rechnerarchitektur passiert dir das auch, wenn die interne Rechengenauigkeit verschieden ist.

Vorschlag: Rechne trunc(wert-k)+1 wobei du die Konstante k durch Versuche ermittelst. Sie muß 0.999.... sein.

Vorschlag: 
1. Hole dir die Bits für Exponenten und Mantisse aus der Float-Zahl.
2. Multipliziere die Mantisse mit dem zweier-Exponenten. Auf einer SPS (da sie Sprünge in Abhängigkeit von Bits ausführen kann) ist der schnellste Code:
2a. Exponenten auf ein MB kopieren, z.B. MB20
2b. Bei gelöschtem Bit des Exponenten überspringst du Schiebebefehle, die um die entsprechende Wertigkeit links schieben. Als S7-Code:
UN M20.0
SPB =NICHT_MAL_2
SLD 1
NICHT_MAL_2: UN M20.1
SPB =NICHT_MAL_4
SLD 2
NICHT_MAL_4:

u.s.w.
2c. Schiebebefehle, die etwas links aus deinem Ganzzahl-Wort herausschieben, darfst du nicht ausführen. Es liegt dann ein Überlauf vor.
2d. Nach Verarbeitung aller Exponenten-Bits hast du den ganzzahligen Teil im obersten Bit der ursprünglichen Mantisse und den Positionen links davon. Sind die Bits rechts davon 0, ist frac 0. Sind sie es nicht, mußt du die Ganzzahl um 1 erhöhen. Damit hast du genau das, was ceil() macht.


----------



## Kurt (28 Dezember 2005)

Hallo,

danke für die interessanten Lösungsansätze.
Werde ich durchackern.

Kurt


----------

