Zuviel Werbung? - > Hier kostenlos beim SPS-Forum registrieren

Page 5 of 5 FirstFirst ... 345
Results 41 to 45 of 45

Thread: Nach-Neujahrsrätsel

  1. #41
    Thomas_v2.1's Avatar
    Thomas_v2.1 is offline Erfahrener Benutzer
    Themenstarter
    Join Date
    29.03.2004
    Posts
    6,554
    Danke
    160
    Erhielt 1,993 Danke für 1,416 Beiträge

    Default


    Zuviel Werbung?
    -> Hier kostenlos registrieren
    Ich habe das Verfahren von Jesper mal so angepasst, dass die Reste der Division in Form von 65536steln aufsummiert werden, und anschließend zu Gesamtwert hinzu addiert werden.
    Sieht allerdings nicht sehr schön aus, außerdem gibt es einen Korrekturwert um den die summierten Reste angehoben werden müssen, um diese passend aufzurunden.
    Wobei die Schleife an sich nur 8 Durchläufe besitzt.

    Code:
    FUNCTION FC200 : VOID
    
    VAR_INPUT
        IN : INT;
    END_VAR
    
    VAR_OUTPUT
        OUT : INT;
    END_VAR
    
    VAR_TEMP
        i : INT;
        r : DINT;
        g : DINT;
        tmp : DWORD;
        mask : DWORD;
    END_VAR
    
    BEGIN
    r := 0;
    g := 0;
    mask := 16#ffff;
    
    FOR i := 16 TO 2 BY -2 DO
        g := g + (WORD_TO_DINT(SHR(IN := INT_TO_WORD(IN), N := i)));
        // Rest der Division erfassen und in 65536stel aufsummieren
        tmp := SHL(IN := INT_TO_DWORD(IN) AND mask, N := 16 - i);
        r := r + DWORD_TO_DINT(tmp);
        mask := SHR(IN := mask, N := 2);
    END_FOR;
    // Aufsummierte Reste von 65536stel in ganze Zahl, dabei Anpassung zur Aufrundung + 1/3 = 65536 / 3 = 21845.
    // Der größte Fehler bei dem noch nicht "aufgerundet" werden darf entsteht bei 2, dann ist der Rest 2/3.
    r := DWORD_TO_DINT(SHR(IN := DINT_TO_DWORD(r + 21845), N := 16));
    OUT := DINT_TO_INT(g + r);
    
    END_FUNCTION
    Die Genialität einer Konstruktion liegt in ihrer Einfachheit – Kompliziert bauen kann jeder.

    (Sergei Pawlowitsch Koroljow, sowjetischer Konstrukteur von Raketen und Weltraumpionier)

  2. #42
    Join Date
    25.06.2017
    Location
    Oerlinghausen
    Posts
    1,472
    Danke
    129
    Erhielt 262 Danke für 211 Beiträge

    Default

    Quote Originally Posted by Thomas_v2.1 View Post
    Ich habe das Verfahren von Jesper mal so angepasst . . .
    . . . und ich so:
    Code:
    L    #IN   // Division einer positiven DINT-Zahl (aber: Werte 0 bis 32767) durch 3
    SLD  16
    T    #TMP
    SRD  1
    L    #TMP
    SRD  3
    -I   
    L    #TMP
    SRD  5
    -I   
    L    #TMP
    SRD  7
    -I   
    L    #TMP
    SRD  9
    -I   
    L    #TMP
    SRD  11
    -I   
    L    #TMP
    SRD  13
    -I   
    L    #TMP
    SRD  15
    -I   
    SRD  16
    T    #OUT
    Jesper multipliziert mit einem NäherungsWert von 1/3 nämlich
    0.010101010101010 und ich auch, aber mit einem anderen nämlich 0.1 - 0.001010101010101 =
    0.010101010101011.
    1/3 stellt im DezimalSystem und im BinärSystem einen unendlichen periodischen Bruch dar.
    Jespers Approximation ist zu klein und meine ist zu gross, um "genau" 1/3 darzustellen.
    Das führt einerseits dazu, dass Jespers Ergebnisse ein winziges Bisschen zu klein sind und durch das Abrunden (= die "Beschränkung" auf 16 Bit) alle Divisionen, die den Rest 0 hätten, ein zu kleines Ergebnis liefern.
    Das führt andererseits dazu, dass meine Ergebnisse ein winziges Bisschen zu gross sind und durch das Abrunden (= die "Beschränkung" auf 16 Bit) alle Divisionen, auch die, die den Rest 0 hätten, zum passenden Ergebnis kommen.

    Vielsten Dank für die vielen interessanten Beiträge!

    Gruss, Heinileini

    PS:
    Man stelle sich vor, es wäre nicht möglich, eine Division durch Addition bzw. Subtraktion und durch Schieben der Bits im Akku zu realisieren . . .
    Gäbe es dieses Forum dann gar nicht (weil es keine Computer gäbe)? Oder hätten dann 99% der Beiträge "Divisions-WorkArounds" zum Thema?

    PPS:
    Die "VideoLösung" ist gar nicht so unraffiniert, aber im EndEffekt zu aufwändig.

    Edit:
    Habe meinen Code jetzt so erweitert, dass vorab die EingangsVariable um 16 Bit nach links und abschliessend das Ergebnis um 16 Bit nach rechts geschoben wird. Ich hoffe, der jetzige Versuch der Umsetzung in AWL kommt dem näher, was in der Excel-Simulation so gut aussah. Das werde ich in Excel noch testen . . .


    Last edited by Heinileini; 12.01.2019 at 09:33.

  3. #43
    Thomas_v2.1's Avatar
    Thomas_v2.1 is offline Erfahrener Benutzer
    Themenstarter
    Join Date
    29.03.2004
    Posts
    6,554
    Danke
    160
    Erhielt 1,993 Danke für 1,416 Beiträge

    Default

    Heinileini, in der SPS gibt dein Code an OUT immer Null zurück.
    Ich hatte auch ein paar Versuche mit Excel gemacht, aber da Excel immer Gleitkomma rechnet gibt es da schon Unterschiede.
    Die Genialität einer Konstruktion liegt in ihrer Einfachheit – Kompliziert bauen kann jeder.

    (Sergei Pawlowitsch Koroljow, sowjetischer Konstrukteur von Raketen und Weltraumpionier)

  4. #44
    Join Date
    25.06.2017
    Location
    Oerlinghausen
    Posts
    1,472
    Danke
    129
    Erhielt 262 Danke für 211 Beiträge

    Default

    Quote Originally Posted by Thomas_v2.1 View Post
    Heinileini, in der SPS gibt dein Code an OUT immer Null zurück.
    Hallo Thomas, ich hatte vergessen, zu betonen, dass #Tmp 32 Bit haben muss.
    Aber es hilft alles nichts - das Ergebnis ist niederschmetternd und voll daneben.
    Das kommt davon, wenn man versucht, wider besseren Wissens einen Weg zu beschreiten, der eigentlich nicht zur Aufgabenstellung passt.
    Die Multiplikation mit dem Kehrwert des Divisors muss einfach abenteuerlich werden, wenn der Divisor keine reine ZweierPotenz ist.
    Da kann man noch so viele Bits hinzunehmen, um die Genauigkeit zu verbessern . . .

    Mein Favorit sieht in der jetzigen Excel-VBA-TestVersion so aus:
    Code:
    Function Divi(ByVal x1, ByVal x2)
    xRest& = Abs(x1)
    xDivisor& = Abs(x2)
    If xDivisor& = 0 Then
        Divi = "Div/0"
    Else
        xBitPos& = 1
        Do While xRest& > xDivisor&
            xBitPos& = xBitPos& + xBitPos&    ' << ShiftLeft
            xDivisor& = xDivisor& + xDivisor& ' << ShiftLeft
            Loop
        xQuotient& = 0
        Do While xRest& > 0 And xBitPos& > 0
            If xRest& >= xDivisor& Then
                xRest& = xRest& - xDivisor&
                xQuotient& = xQuotient& + xBitPos&
                End If
            xBitPos& = Int(xBitPos& / 2)   ' ShiftRight >>
            xDivisor& = Int(xDivisor& / 2) ' ShiftRight >>
            Loop
        Divi = xQuotient& & " " & xRest&
    End Function
    Dividend und Divisor müssen positiv sein und alle Variablen sinnvollerweise gleichen Typs (alle INT oder alle DINT oder . . .). Der Divisor ist frei wählbar (zweiter Parameter) und die Anzahl der SchleifenDurchläufe hält sich in Grenzen.
    Das Ergebnis ist ein String, der den Quotienten und den Rest enthält, getrennt durch ein Leerzeichen.
    Die Funktion enthält notgedrungen Divisionen, allerdings nur durch 2, um die RechtsSchiebeBefehle zu "realisieren" (übrigens ein MusterBeispiel dafür, dass VBA bei Divisionen von Ganzzahlen rundet und nicht abschneidet - deshalb INT(x/2)).

    Gruss, Heinileini
    Last edited by Heinileini; 12.01.2019 at 20:01.

  5. #45
    Join Date
    22.06.2009
    Location
    Sassnitz
    Posts
    13,550
    Danke
    1,088
    Erhielt 3,997 Danke für 3,229 Beiträge

    Default


    Zuviel Werbung?
    -> Hier kostenlos registrieren
    Man muß die Ungenauigkeiten nicht aufsummieren, man kann sie auch korrigieren, indem man am Ende das vorläufige Ergebnis (wie bei einer Kontrollrechnung) mit 3 multipliziert (q + q + q), vom Ausgangswert abzieht, und den verbleibenden kleinen Rest mit einer Näherungsformel mit Zweierpotenz-Division durch 3 dividiert (z.B. 11*r/32, oder 5*(r+1)/16) und zum vorläufigen Ergebnis addiert. So wie hier in dem Algorithmus von Hacker's Delight.
    Quote Originally Posted by PN/DP View Post
    32 Bit signed Division (durch 3) mittels Multiplikation mit dem Kehrwert (Reziproke) (mal 1/3 = binär 0.010101...)
    PS: Der Algorithmus funktioniert für alle 32-Bit signed Integer. Was mich dabei fasziniert: am Anfang 2 addieren, falls der Dividend negativ ist.

    Harald
    Es ist immer wieder überraschend, wie etwas plötzlich funktioniert, sobald man alles richtig macht.

    FAQ: Linkliste SIMATIC-Kommunikation über Ethernet

Similar Threads

  1. Replies: 2
    Last Post: 31.08.2018, 11:23
  2. Replies: 3
    Last Post: 02.10.2015, 07:50
  3. Replies: 4
    Last Post: 25.02.2015, 12:11
  4. Replies: 6
    Last Post: 21.11.2014, 09:23
  5. Beispiele einer automatischen Querübersetzung von ST nach IL bzw. nach FBS
    By sps freak in forum Werbung und Produktneuheiten
    Replies: 1
    Last Post: 04.07.2008, 21:52

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •