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

Seite 5 von 5 ErsteErste ... 345
Ergebnis 41 bis 45 von 45

Thema: Nach-Neujahrsrätsel

  1. #41
    Avatar von Thomas_v2.1
    Thomas_v2.1 ist offline Erfahrener Benutzer
    Themenstarter
    Registriert seit
    29.03.2004
    Beiträge
    6.370
    Danke
    157
    Erhielt 1.914 Danke für 1.379 Beiträge

    Standard


    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
    Registriert seit
    25.06.2017
    Ort
    Oerlinghausen
    Beiträge
    1.107
    Danke
    93
    Erhielt 186 Danke für 157 Beiträge

    Standard

    Zitat Zitat von Thomas_v2.1 Beitrag anzeigen
    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 . . .


    Geändert von Heinileini (12.01.2019 um 11:33 Uhr)

  3. #43
    Avatar von Thomas_v2.1
    Thomas_v2.1 ist offline Erfahrener Benutzer
    Themenstarter
    Registriert seit
    29.03.2004
    Beiträge
    6.370
    Danke
    157
    Erhielt 1.914 Danke für 1.379 Beiträge

    Standard

    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
    Registriert seit
    25.06.2017
    Ort
    Oerlinghausen
    Beiträge
    1.107
    Danke
    93
    Erhielt 186 Danke für 157 Beiträge

    Standard

    Zitat Zitat von Thomas_v2.1 Beitrag anzeigen
    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
    Geändert von Heinileini (12.01.2019 um 22:01 Uhr)

  5. #45
    Registriert seit
    23.06.2009
    Ort
    Sassnitz
    Beiträge
    12.889
    Danke
    1.056
    Erhielt 3.807 Danke für 3.072 Beiträge

    Standard


    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.
    Zitat Zitat von PN/DP Beitrag anzeigen
    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

Ähnliche Themen

  1. Antworten: 2
    Letzter Beitrag: 31.08.2018, 13:23
  2. Antworten: 3
    Letzter Beitrag: 02.10.2015, 09:50
  3. Antworten: 4
    Letzter Beitrag: 25.02.2015, 14:11
  4. Antworten: 6
    Letzter Beitrag: 21.11.2014, 11:23
  5. Beispiele einer automatischen Querübersetzung von ST nach IL bzw. nach FBS
    Von sps freak im Forum Werbung und Produktneuheiten
    Antworten: 1
    Letzter Beitrag: 04.07.2008, 23:52

Lesezeichen

Berechtigungen

  • Neue Themen erstellen: Nein
  • Themen beantworten: Nein
  • Anhänge hochladen: Nein
  • Beiträge bearbeiten: Nein
  •