# Arithmetik doppelter Genauigkeit

**URL:** <https://oscat.discourse.group/t/arithmetik-doppelter-genauigkeit/707>\
**Category:** oscat.lib fuer Step 7\
**Created:** [2. November 2009 um 15:06 UTC](https://oscat.discourse.group/t/arithmetik-doppelter-genauigkeit/707 "2009-11-02T15:06:47Z")\
**Posts on this page:** 13\
**Page:** 1

<div class="post-metadata">

**Author:** ![system](https://global.discourse-cdn.com/free1/uploads/oscat/original/1X/2efdfb9c592ff9a666c94dff124ee84fa863dae5.jpeg) [@system](https://oscat.discourse.group/u/system)\
**Post date:** [2. November 2009 um 15:06 UTC](https://oscat.discourse.group/t/arithmetik-doppelter-genauigkeit/707/1 "2009-11-02T15:06:47Z")

</div>

[Hallo,

wer hat mit diesen Bausteinen schon einmal gearbeitet. Ich habe das Problem, dass ich bei einer Mittelwertberechnung über folgende Formel arbeiten muss, um die Zyklusbelastung nicht zu groß werden zu lassen:

MW := MW + (Rohwert - buffer[j]); mit j:= 1 bis 3600

Wenn ich jedesmal alle Werte aufaddiere dann ist der Zyklus zu lang.

Leider gibt es bei dieser Berechnung unvermeidbare Rundungsfehler. Also wollte ich das mal mit dem Format REAL2 probieren, erhalte aber immer wieder das selbe Ergebnis, ohne dass die höhere Genauigkeit genutzt wird, der Bereich \*.R1 ist immer 0.

Gruß

---

<div class="post-metadata">

**Author:** ![hugo](https://yyz2.discourse-cdn.com/free1/user_avatar/oscat.discourse.group/hugo/32/133_2.png) [@hugo](https://oscat.discourse.group/u/hugo)\
**Post date:** [2. November 2009 um 17:50 UTC](https://oscat.discourse.group/t/arithmetik-doppelter-genauigkeit/707/2 "2009-11-02T17:50:49Z")

</div>

kannst du mal ein kleines projekt posten das den fehler aufweist

---

<div class="post-metadata">

**Author:** ![system](https://global.discourse-cdn.com/free1/uploads/oscat/original/1X/2efdfb9c592ff9a666c94dff124ee84fa863dae5.jpeg) [@system](https://oscat.discourse.group/u/system)\
**Post date:** [2. November 2009 um 18:35 UTC](https://oscat.discourse.group/t/arithmetik-doppelter-genauigkeit/707/3 "2009-11-02T18:35:11Z")

</div>

> [@hugo post:2](#):
>
> kannst du mal ein kleines projekt posten das den fehler aufweist

Ja, poste doch bitte mal ein kleines Projekt.  
Kannst Du deine Berechnung nicht auf mehre Zyklen aufteilen?

Gruss Daniel

---

<div class="post-metadata">

**Author:** ![hugo](https://yyz2.discourse-cdn.com/free1/user_avatar/oscat.discourse.group/hugo/32/133_2.png) [@hugo](https://oscat.discourse.group/u/hugo)\
**Post date:** [3. November 2009 um 21:40 UTC](https://oscat.discourse.group/t/arithmetik-doppelter-genauigkeit/707/4 "2009-11-03T21:40:47Z")

</div>

in deinem Beispiel oben schreibst du z.b. MW + Rohwert …

mit dem Datentyp REAL2 geht das so nicht, du musst zwingend R2\_ADD(MW, ROHWERT) als funktion benutzen.  
dasselbe gilt für alle anderen operationen

---

<div class="post-metadata">

**Author:** ![system](https://global.discourse-cdn.com/free1/uploads/oscat/original/1X/2efdfb9c592ff9a666c94dff124ee84fa863dae5.jpeg) [@system](https://oscat.discourse.group/u/system)\
**Post date:** [3. November 2009 um 23:31 UTC](https://oscat.discourse.group/t/arithmetik-doppelter-genauigkeit/707/5 "2009-11-03T23:31:45Z")

</div>

wird bei 3600 Aufrufen aber auch schwierig. :o

Gruss Daniel

---

<div class="post-metadata">

**Author:** ![system](https://global.discourse-cdn.com/free1/uploads/oscat/original/1X/2efdfb9c592ff9a666c94dff124ee84fa863dae5.jpeg) [@system](https://oscat.discourse.group/u/system)\
**Post date:** [4. November 2009 um 13:17 UTC](https://oscat.discourse.group/t/arithmetik-doppelter-genauigkeit/707/6 "2009-11-04T13:17:23Z")

</div>

Hallo,

hier nun endlich die benötigten Infos.

die Programmierung mit Real-Zahlen sieht so aus:

i := (i + 1) MOD Zyklen;  
MW := MW + (Rohwert - buffer[i]) / INT\_TO\_REAL(Zyklen);  
buffer[i] := Rohwert;

wobei diese Befehle nur einmal pro Bausteinaufruf bearbeitet werden.

Dann habe ich das auf REAL2 umgesetzt:

i:= (i + 1) MOD Zyklen;  
MW\_Double:= R2\_ADD2(X:= MW\_Double, Y:= R2\_MUL(X:= (R2\_ADD2(X:= Rohwert\_Double, Y:= R2\_MUL(X:= buffer[i], Y:= -1))), Y:= Eins\_Zyklen));  
buffer[i]:= Rohwert\_Double;

. Das Ergebnis ist in beiden fällen identisch, auch der \*.R1 Anteil bleibt 0.

Die “fehlerfreie” Variante wäre:

FOR k:= 0 TO 3599 DO  
STD\_MW\_neu:= STD\_MW\_neu + STD\_buffer[k] / 3600;  
END\_FOR;

und das dauert zu lange.

Inzwischen habe ich mit den Funktionen von REAL2 etwas experimentiert und habe ein kleines Testprojekt aufgesetzt. In der Doku steht:  
“Möchte man bis zu Mehreren Mwh (Megawattstunden) an Gesamtverbrauch Aufsummieren und dabei eine kleinste Leistung von 1mW (Milliwatt) im Abstand von 10ms Messen und berücksichtigen, so benötigt man eine Auflösung von 3.6 \* 10^7 (entspricht 10MWs) und dabei würde man 1 \* 10^-5 Ws aufaddieren wollen.  
Um dies zu bewerkstelligen benötigt man eine Auflösung von 12 Stellen.”

Also habe ich folgendes programmiert:  
CALL “R2\_SET”  
X :=1.0 E-5  
RET\_VAL:=“Test”.Eingang1

```
  CALL "R2_SET"
   X :=3.6 E7
   RET_VAL:="Test".Eingang2

  CALL "R2_ADD2"
   X :="Test".Ergebnis
   Y :="Test".Eingang2
   RET_VAL:="Test".Ergebnis

```

und habe das im OB1 zyklisch mit 1 ms laufen lassen. Das läuft jetzt schon 48 Stunden. Dann hätte eigentlich der Ausgangswert sich um 172.800.000, also sichtbar verändern müssen. Aber der ausgang steht immer noch bei RX=3.6 E7 und R1=0.

Was habe ich dabei falsch gemacht ?

Danke und Gruß

---

<div class="post-metadata">

**Author:** ![system](https://global.discourse-cdn.com/free1/uploads/oscat/original/1X/2efdfb9c592ff9a666c94dff124ee84fa863dae5.jpeg) [@system](https://oscat.discourse.group/u/system)\
**Post date:** [4. November 2009 um 21:36 UTC](https://oscat.discourse.group/t/arithmetik-doppelter-genauigkeit/707/7 "2009-11-04T21:36:52Z")

</div>

Hallo,

was soll “Test”.Eingang1 machen der ist in Deiner berechnung ja gar nicht verwendet?

Der Typ REAL2 ist folgender maßen definiert:  
\*.R1 : REAL Grobteil der Doppelzahl  
\*.RX : REAL Feinteil der Doppelzahl

R2\_SET beschreibt lediglich \*.RX mit dem Wert von X \*.R1 ist immer 0.0, somit hast Du an Deinen Ausgang “Test”.Ergebnis.RX immer die 3.6 E7 stehen “Test”.Ergebnis.R1 bleibt natürlich 0.  
R2\_ADD2 addiert X.R1 mit Y.R1 und X.RX mit Y.RX.

Gruss Daniel

---

<div class="post-metadata">

**Author:** ![system](https://global.discourse-cdn.com/free1/uploads/oscat/original/1X/2efdfb9c592ff9a666c94dff124ee84fa863dae5.jpeg) [@system](https://oscat.discourse.group/u/system)\
**Post date:** [4. November 2009 um 23:05 UTC](https://oscat.discourse.group/t/arithmetik-doppelter-genauigkeit/707/8 "2009-11-04T23:05:23Z")

</div>

Halt das ist natürlich Käse  
“immer die 3.6 E7 stehen” → im ersten Zyklus im zweiten sind es dann 3.6E7 + 3.6E7 = 7.2E7 …

Gruss Daniel

---

<div class="post-metadata">

**Author:** ![system](https://global.discourse-cdn.com/free1/uploads/oscat/original/1X/2efdfb9c592ff9a666c94dff124ee84fa863dae5.jpeg) [@system](https://oscat.discourse.group/u/system)\
**Post date:** [5. November 2009 um 06:43 UTC](https://oscat.discourse.group/t/arithmetik-doppelter-genauigkeit/707/9 "2009-11-05T06:43:58Z")

</div>

Hallo,

sorry, da ist mir ein Tippfehler unterlaufen, aber nur hier im posting.

Programmiert ist:

```
  CALL "R2_SET"
   X :=MD50
   RET_VAL:="Test".Eingang1

  CALL "R2_SET"
   X :=MD54
   RET_VAL:="Test".Eingang2

  CALL "R2_ADD2"
   X :="Test".Ergebnis
   Y :="Test".Eingang2
   RET_VAL:="Test".Ergebnis

```

wobei MD50:= 3.6 E07 und MD54:= 1,0E-05 gesetzt ist. Damit Test.Ergebnis überhaupt initialisert ist, habe ich zum starten den Eingang X von “R2\_ADD” einmalig mit Test.Eingang1 beschaltet, so daß Test.Ergebnis mit 3,6E07 initialisiert war.

Ich hoffe, so wird es klarer.

Gruß Peter

---

<div class="post-metadata">

**Author:** ![system](https://global.discourse-cdn.com/free1/uploads/oscat/original/1X/2efdfb9c592ff9a666c94dff124ee84fa863dae5.jpeg) [@system](https://oscat.discourse.group/u/system)\
**Post date:** [5. November 2009 um 20:08 UTC](https://oscat.discourse.group/t/arithmetik-doppelter-genauigkeit/707/10 "2009-11-05T20:08:39Z")

</div>

Hallo,

R2\_ADD ist nicht gleich R2\_ADD2 nimm mal R2\_ADD.

Gruss Daniel

---

<div class="post-metadata">

**Author:** ![system](https://global.discourse-cdn.com/free1/uploads/oscat/original/1X/2efdfb9c592ff9a666c94dff124ee84fa863dae5.jpeg) [@system](https://oscat.discourse.group/u/system)\
**Post date:** [9. November 2009 um 10:55 UTC](https://oscat.discourse.group/t/arithmetik-doppelter-genauigkeit/707/11 "2009-11-09T10:55:13Z")

</div>

Hallo,

das habe ich gemacht:

```
  CALL "R2_ADD"
   X :="Test".Ergebnis
   Y :=MD54
   RET_VAL:="Test".Ergebnis

```

und Test.Ergebnis mit der Funktion R2\_SET einmalig auf 3.6 E07 gesetzt.

Jetzt ist das Verhalten anders, in Test.Ergebnis.R1 wird pro Zyklus die in MD54 stehenden 1.0E-05 dazuaddiert. Das sieht schon gut aus, aber wenn die Zahl bei ca 1.8 E00 ankommt, wird das Ergebnis plötzlich negativ und es wird von -1,8 wieder auf 1,8 hochgezählt.

Gruß  
Peter

---

<div class="post-metadata">

**Author:** ![system](https://global.discourse-cdn.com/free1/uploads/oscat/original/1X/2efdfb9c592ff9a666c94dff124ee84fa863dae5.jpeg) [@system](https://oscat.discourse.group/u/system)\
**Post date:** [10. Januar 2013 um 14:02 UTC](https://oscat.discourse.group/t/arithmetik-doppelter-genauigkeit/707/12 "2013-01-10T14:02:36Z")

</div>

Hi,  
ich möchte das Thema noch mal aufgreifen.  
Den die Funktionen zur doppelten Genauigkeit erfüllen meiner Meinung nach nicht ihren Zweck, bzw. die Erwartungen an Korrektheit.

Aus der Funktion R2\_ADD2:

```auto
tR2_ADD2.R1 := X.R1 + Y.R1;
tR2_ADD2.RX := X.RX + Y.RX;

```

Da wird ja nur jeweils der Grob- und Feinanteil für sich alleinstehend aufsummiert. Ein Übertrag von Feinanteil zum Grobanteil findet nicht statt. Soll das so gewollt sein?

Ohne einen Übertrag zu den übergeordneten Stellen ergibt das mathematisch für mich keinen Sinn.

Für Aufklärung wäre ich durchaus dankbar,

mfG

e3

---

<div class="post-metadata">

**Author:** ![system](https://global.discourse-cdn.com/free1/uploads/oscat/original/1X/2efdfb9c592ff9a666c94dff124ee84fa863dae5.jpeg) [@system](https://oscat.discourse.group/u/system)\
**Post date:** [16. Februar 2016 um 10:25 UTC](https://oscat.discourse.group/t/arithmetik-doppelter-genauigkeit/707/13 "2016-02-16T10:25:54Z")

</div>

I’m sorry for resurrecting an old topic, but I figured it’s worth posting since I couldn’t find any similar solution on the forum. I hope someone finds this useful while S7-1500 with native double float is gaining traction.

If I understood e3’s post correctly, he saw similar problem in R2\_ADD2 function as we did. My colleague “mme” came up with this solution based on R2\_ADD:

```auto
tR2_ADD2.RX = Y.R1 + Y.RX + X.RX + X.R1;
tR2_ADD2.R1 = X.RX + Y.RX - tR2_ADD2.RX + Y.R1 + X.R1

```

I did a quick and dirty test in C# using floats in place of S7 Real and with double as a reference. The code above appears to be working as expected.  
Test code:

```auto
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Real2Test
{
    class Program
    {
        static void Main(string[] args)
        {
            float a = 10000000F;
            float b = 0.00123F;

            double c = a;
            Real2 d = new Real2();
            d.RX = a;
            d.R1 = 0F;

            Real2 e = new Real2();
            e.RX = b;
            e.R1 = 0F;

            for (int i = 0; i < 3333333; i++)
            {
                c -= (double)b;
                d = R2AddNew(d, R2Mul(e, -1F));
            }
            Console.WriteLine("Double: {0:F8}\tR2: {1:F8}\t{2:F8}", c, d.RX, d.R1);

            for (int i = 0; i < 3333333; i++)
            {
                c += (double)b;
                d = R2AddNew(d, R2Mul(e, 1F));
            }
            Console.WriteLine("Double: {0:F8}\tR2: {1:F8}\t{2:F8}", c, d.RX, d.R1);

            for (int i = 0; i < 3333333; i++)
            {
                c += (double)b;
                d = R2AddNew(d, R2Mul(e, 1F));
            }
            Console.WriteLine("Double: {0:F8}\tR2: {1:F8}\t{2:F8}", c, d.RX, d.R1);
            Console.ReadKey();
        }

        static Real2 R2Mul(Real2 x, float y)
        {
            Real2 tmp = new Real2();
            tmp.RX = x.RX * y;
            tmp.R1 = x.R1 * y;

            return tmp;
        }

        static Real2 R2AddNew(Real2 x, Real2 y)
        {
            Real2 z = new Real2();
            z.RX = y.R1 + y.RX + x.RX + x.R1;
            z.R1 = x.RX + y.RX - z.RX + y.R1 + x.R1;
            return z;
        }
        
    }

    class Real2
    {
        public float R1 { get; set; }
        public float RX { get; set; }
    }
}

```

Thank you for this great library!  
W
