ONP (RPN) -> Łączność operatora '^' (potęgi)

ONP (RPN) -> Łączność operatora '^' (potęgi)
mpaw
  • Rejestracja:około 9 lat
  • Ostatnio:14 dni
  • Postów:530
0

Dzień dobry.

Mam już napisany parser wyrażenia, który liczy wartość działania na liczbach całkowitych. Jednak jest jeden problem. Podobno potęga ma łączność prawostronną. Jak można to zaimplementować? Bo mi liczy 2^2^2^2 jako 256 a powinno 65536. Jak można to wyrazić?

Dzięki
M.


That's all folks ;)
enedil
  • Rejestracja:ponad 11 lat
  • Ostatnio:4 dni
  • Postów:1027
0

No to zależy od tego jak zaimplementowałeś parser. Jak masz wyrażenie 2+2*7 to wychodzi Ci 28 czy 16? Problem dość podobny. Zgaduję, że zamiast zrobić najpierw drzewo parsowania takiej składni, od razu wykonujesz ewaluację?

lion137
  • Rejestracja:około 8 lat
  • Ostatnio:około 12 godzin
  • Postów:4884
0

W ONP właśnie o to chodzi, żeby nie robić drzewa, 2 + 2 * 7, to nie jest kwestia priorytetu operatorów?


enedil
2 + 2 * 7 to w ogóle nie jest wyrażenie w ONP
mpaw
priorytety mam dobre, chodzi o łączność
mpaw
  • Rejestracja:około 9 lat
  • Ostatnio:14 dni
  • Postów:530
0

Wychodzi mi 16. Mam funkcje:

Kopiuj
var dzialanie = "2+2*7";
var tok = rozczlonkuj(dzialanie);
var onp = naONP(tok);
var wyn = obliczZONP(onp);

Najpierw usuwam spacje i dziele stringa na pojedyncze znaki, które następnie zamieniam na Tokeny, z informacją, czy to liczba, czy zmienna, czy operator, czy funkcja.
Potem Tokeny zamieniam na ONP
Potem obliczam.

Listing kolejnych etapów:

Kopiuj
2*(3+7*2)^2

---- PRZED ONP
0: Token {typ: "Liczba", wartosc: "2", prior: -1}
1: Token {typ: "Operacja", wartosc: "*", prior: 2}
2: Token {typ: "NawiasO", wartosc: "(", prior: 0}
3: Token {typ: "Liczba", wartosc: "3", prior: -1}
4: Token {typ: "Operacja", wartosc: "+", prior: 1}
5: Token {typ: "Liczba", wartosc: "7", prior: -1}
6: Token {typ: "Operacja", wartosc: "*", prior: 2}
7: Token {typ: "Liczba", wartosc: "2", prior: -1}
8: Token {typ: "NawiasZ", wartosc: ")", prior: 0}
9: Token {typ: "Operacja", wartosc: "^", prior: 3}
10: Token {typ: "Liczba", wartosc: "2", prior: -1}l

----PO ONP
0: Token {typ: "Liczba", wartosc: "2", prior: -1}
1: Token {typ: "Liczba", wartosc: "3", prior: -1}
2: Token {typ: "Liczba", wartosc: "7", prior: -1}
3: Token {typ: "Liczba", wartosc: "2", prior: -1}
4: Token {typ: "Operacja", wartosc: "*", prior: 2}
5: Token {typ: "Operacja", wartosc: "+", prior: 1}
6: Token {typ: "Liczba", wartosc: "2", prior: -1}
7: Token {typ: "Operacja", wartosc: "^", prior: 3}
8: Token {typ: "Operacja", wartosc: "*", prior: 2}

wynik
 578

That's all folks ;)
edytowany 1x, ostatnio: mpaw
enedil
  • Rejestracja:ponad 11 lat
  • Ostatnio:4 dni
  • Postów:1027
0

No ale to znaczy, że źle przekształcasz na ONP. Stos powinien być taki: 2 2 2 2 ^ ^ ^.

mpaw
  • Rejestracja:około 9 lat
  • Ostatnio:14 dni
  • Postów:530
0

Przekształcam, tylko stos mam: 2 2 ^ 2 ^ 2 ^
bo chodzi o łączność, nie wiem jak ją zaimplementować


That's all folks ;)
edytowany 2x, ostatnio: mpaw
lion137
  • Rejestracja:około 8 lat
  • Ostatnio:około 12 godzin
  • Postów:4884
0

Pokaż jeszcze jak to ewaluujesz.


mpaw
  • Rejestracja:około 9 lat
  • Ostatnio:14 dni
  • Postów:530
0
Kopiuj
function obliczZONP(tokenyONP) {
    var wynik = [];
    
    for (var i = 0; i < tokenyONP.length; i++) {
        if (tokenyONP[i].typ === Typ.Liczba || tokenyONP[i].typ === Typ.Zmienna)
            wynik.push(tokenyONP[i]);
        
        if (tokenyONP[i].typ === Typ.Operacja) {
            var a = wynik.pop().wartosc;
            var b = wynik.pop().wartosc;
            
            if (tokenyONP[i].wartosc === "+")
                wynik.push(new Token(Typ.Liczba, String(parseInt(b) + parseInt(a))));
            
            if (tokenyONP[i].wartosc === "-")
                wynik.push(new Token(Typ.Liczba, String(parseInt(b) - parseInt(a))));
            
            if (tokenyONP[i].wartosc === "*")
                wynik.push(new Token(Typ.Liczba, String(parseInt(b) * parseInt(a))));
            
            if (tokenyONP[i].wartosc === "/")
                wynik.push(new Token(Typ.Liczba, String(parseInt(b) / parseInt(a))));
            
            if (tokenyONP[i].wartosc === "^")
                wynik.push(new Token(Typ.Liczba, String(parseInt(b) ** parseInt(a))));
        }
    }
    
    return wynik[0].wartosc;
}

That's all folks ;)
enedil
  • Rejestracja:ponad 11 lat
  • Ostatnio:4 dni
  • Postów:1027
0

Ewaluacja tutaj nie ma wielkiego znaczenia, pokaż jak robisz parsowanie na ONP, bo to jest to co widocznie kuleje. Btw. zupełnie nie rozumiem, dlaczego od razu cały kod się tutaj nie znalazł, tylko poświęciliśmy 10 postów na to, by wyłuskać od Ciebie te informacje

edytowany 1x, ostatnio: enedil
mpaw
Zadałem pytanie jak zaimplementować łączność. Wiem, że tu leży problem, ale jak mi nie wierzycie, to wysyłam kod
enedil
Problem polega na tym, że można implementować na wiele sposobów, i to zależy od tego jak to zrobiłeś
mpaw
wystarczy mi ogólna rada, dostosuję ją do swojego kodu.
mpaw
@enedil: czy mógłbyś podać jeden z tych sposobów, skoro znasz ich aż kilka?
mpaw
  • Rejestracja:około 9 lat
  • Ostatnio:14 dni
  • Postów:530
0
Kopiuj
function naONP(tokeny) {
    var dzialania = [];
    var wyjscie = [];
    
    var dodajOper = function (oper) {
        if (dzialania.length == 0 || dzialania[dzialania.length - 1].prior < oper.prior)
            dzialania.push(oper);
        
        else if (dzialania.length > 0 && oper.typ !== Typ.NawiasZ) {
            while (dzialania.length > 0 && dzialania[dzialania.length - 1].prior >= oper.prior && oper.typ !== Typ.NawiasO && oper.typ !== Typ.Przecinek)
                wyjscie.push(dzialania.pop());
            
            if (oper.typ !== Typ.Przecinek)
                dzialania.push(oper);
        }
        
        else if (dzialania.length > 0 && oper.typ === Typ.NawiasZ) {
            while (dzialania.length > 0 && dzialania[dzialania.length - 1].typ !== Typ.NawiasO)
                wyjscie.push(dzialania.pop());
            
            dzialania.pop(); // NawiasO
            
            if (dzialania.length > 0 && dzialania[dzialania.length - 1].typ == Typ.Funkcja)
                wyjscie.push(dzialania.pop());
        }
    };
    
    var dodajStalaLubZmienna = function (el) {
        wyjscie.push(el);
    };
    
    for (var i = 0; i < tokeny.length; i++) {
        if (tokeny[i].typ === Typ.Liczba || tokeny[i].typ === Typ.Zmienna)
            dodajStalaLubZmienna(tokeny[i]);
        
        else
            dodajOper(tokeny[i]);
    }
    
    while (dzialania.length > 0)
        wyjscie.push(dzialania.pop());
    
    return wyjscie;
}

That's all folks ;)
edytowany 1x, ostatnio: mpaw
BraVolt
  • Rejestracja:prawie 6 lat
  • Ostatnio:prawie 4 lata
  • Lokalizacja:Warszawa
  • Postów:2918
0
mpaw napisał(a):

mi liczy 2^2^2^2 jako 256 a powinno 65536. Jak można to wyrazić?

Poprawnie RPN to będzie zapisane 2222^^^

Kolejno na stos dwójki
Na stosie będzie

Kopiuj
2
2
2
2

Pierwszy ^, to zdejmujesz ze stosu 2 i 2, wykonujesz 2^2, dostajesz 4, 4 na stos, masz na stosie

Kopiuj
4
2
2

Zdejmujesz 4 i 2 ze stosu, liczysz 2^4, dostajesz 16, wrzucasz na stos 16, masz teraz na stosie

Kopiuj
16
2

Zdejmujesz ze stosu 2 i 16, liczysz 2^16, dostajesz 65536
Wrzucasz 65536 na stos
Nie masz już nic do parsowania
Zdejmujesz 65536 ze stosu - to jest twój rezultat obliczeń

(pisane z głowy i z tego co zostało z wykładów WDI i ASD)
Nie będę się upierać, że
Wrzucasz 65536 na stos
Nie masz już nic do parsowania
Zdejmujesz 65536 ze stosu - to jest twój rezultat obliczeń

trzeba robić kiedy nie ma już nic do parsowania, czy od razu podliczenie 2^16 = 65536 to wynik


"Kiedy wiedzieć czy zacząć nauke Springa? bo w czystej Javie to nic ciekawego nie zrobie chyba"
Ein Volk, ein Reich, ein Kwa-Kwa ***** ***
mpaw
  • Rejestracja:około 9 lat
  • Ostatnio:14 dni
  • Postów:530
0

Ja to wszystko wiem, powtarzam jeszcze raz NIE wiem tylko JAK zaimpelementować łączność prawostronną podczas generowania RPN

Do tworzenia algorytmu używałem http://www.infoceram.agh.edu.pl/files/onp.pdf a tu nie ma potęg

Pan @enedil zasugerował w komentarzu, że łączność można zaimplementować na wiele sposobów. Czy mógłby podać jeden z nich?


That's all folks ;)
edytowany 3x, ostatnio: mpaw
vpiotr
  • Rejestracja:ponad 13 lat
  • Ostatnio:prawie 3 lata
2
lion137
  • Rejestracja:około 8 lat
  • Ostatnio:około 12 godzin
  • Postów:4884
2

@mpaw: 2 2 ^ 2 ^ 2 ^ ten stos wygląda dobrze:
https://runestone.academy/runestone/books/published/pythonds/BasicDS/InfixPrefixandPostfixExpressions.html#general-infix-to-postfix-conversion
A odwróć kolejność potęgowania i powinno być pozamiatane:
wynik.push(new Token(Typ.Liczba, String(parseInt(b) ** parseInt(a)))); -> wynik.push(new Token(Typ.Liczba, String(parseInt(a) ** parseInt(b))));


mpaw
WOW! Faktycznie! Ale dlaczego?
mpaw
Aaaa, już rozumiem :) Dzięki :)
lion137
Właśnie :) Należało by to jeszcze potestować i się zastanowić, czy rzeczywiście odwrócenie wykonania działania zmienia łączność.
mpaw
  • Rejestracja:około 9 lat
  • Ostatnio:14 dni
  • Postów:530
0

@lion137: Dzięki! Jednak na stronie https://www.dcode.fr/reverse-polish-notation generuje RPN taki, jak powiedziały chłopaki, tj. 2 2 2 2 ^ ^ ^


That's all folks ;)
edytowany 1x, ostatnio: mpaw
lion137
A na stronie którą podesłałem generuje taki jak Twój, tzreba by to przeanalizować
lion137
Jak dam 2 2 2 2 ^ ^ ^ do ewaluacji, dla parsera, który podesłąłem, to trzeba zmienić kolejność do poprzedniej, żeby dawał 65536 :)
mpaw
@lion137: ta strona, co przesłał @vpiotr jest chyba dobra, ale muszę na spokojnie przeanalizować ten kod
lion137
Obydwa algorytmy są dobre, tylko ten co ja podesłałem jest prostszy, nie ma w nim nic o łączności w parserze.,
mpaw
  • Rejestracja:około 9 lat
  • Ostatnio:14 dni
  • Postów:530
0

That's all folks ;)
lion137
  • Rejestracja:około 8 lat
  • Ostatnio:około 12 godzin
  • Postów:4884
1

@mpaw: Sprawdziłem, trzeba parsować już z wiedzą o łączności, wersja, którą podałem nie zadziała dla, np.: 2 ** 3 ** 4.


mpaw
Dzięki, jednak ten gotowiec jest "zwalony", i nie działa do końca, będę musiał napisać go sam od początku. Dzięki :)
lion137
A co jest nie tak na Rosetta Code? Spróbuj z linka, który podał @vpiotr , tam jest implementacja w Pythobie, powinno się łatwo do JS - a przepisać
mpaw
Jak wpisuje się np. (3+4)^7 to wypisuje 3 4 + 7 + ^ o + za dużo.
mpaw
@lion137: Przepisałem ten kod od @vpiotr Działa Dzięki! :)
vpiotr
@mpaw: 👍
Kliknij, aby dodać treść...

Pomoc 1.18.8

Typografia

Edytor obsługuje składnie Markdown, w której pojedynczy akcent *kursywa* oraz _kursywa_ to pochylenie. Z kolei podwójny akcent **pogrubienie** oraz __pogrubienie__ to pogrubienie. Dodanie znaczników ~~strike~~ to przekreślenie.

Możesz dodać formatowanie komendami , , oraz .

Ponieważ dekoracja podkreślenia jest przeznaczona na linki, markdown nie zawiera specjalnej składni dla podkreślenia. Dlatego by dodać podkreślenie, użyj <u>underline</u>.

Komendy formatujące reagują na skróty klawiszowe: Ctrl+B, Ctrl+I, Ctrl+U oraz Ctrl+S.

Linki

By dodać link w edytorze użyj komendy lub użyj składni [title](link). URL umieszczony w linku lub nawet URL umieszczony bezpośrednio w tekście będzie aktywny i klikalny.

Jeżeli chcesz, możesz samodzielnie dodać link: <a href="link">title</a>.

Wewnętrzne odnośniki

Możesz umieścić odnośnik do wewnętrznej podstrony, używając następującej składni: [[Delphi/Kompendium]] lub [[Delphi/Kompendium|kliknij, aby przejść do kompendium]]. Odnośniki mogą prowadzić do Forum 4programmers.net lub np. do Kompendium.

Wspomnienia użytkowników

By wspomnieć użytkownika forum, wpisz w formularzu znak @. Zobaczysz okienko samouzupełniające nazwy użytkowników. Samouzupełnienie dobierze odpowiedni format wspomnienia, zależnie od tego czy w nazwie użytkownika znajduje się spacja.

Znaczniki HTML

Dozwolone jest używanie niektórych znaczników HTML: <a>, <b>, <i>, <kbd>, <del>, <strong>, <dfn>, <pre>, <blockquote>, <hr/>, <sub>, <sup> oraz <img/>.

Skróty klawiszowe

Dodaj kombinację klawiszy komendą notacji klawiszy lub skrótem klawiszowym Alt+K.

Reprezentuj kombinacje klawiszowe używając taga <kbd>. Oddziel od siebie klawisze znakiem plus, np <kbd>Alt+Tab</kbd>.

Indeks górny oraz dolny

Przykład: wpisując H<sub>2</sub>O i m<sup>2</sup> otrzymasz: H2O i m2.

Składnia Tex

By precyzyjnie wyrazić działanie matematyczne, użyj składni Tex.

<tex>arcctg(x) = argtan(\frac{1}{x}) = arcsin(\frac{1}{\sqrt{1+x^2}})</tex>

Kod źródłowy

Krótkie fragmenty kodu

Wszelkie jednolinijkowe instrukcje języka programowania powinny być zawarte pomiędzy obróconymi apostrofami: `kod instrukcji` lub ``console.log(`string`);``.

Kod wielolinijkowy

Dodaj fragment kodu komendą . Fragmenty kodu zajmujące całą lub więcej linijek powinny być umieszczone w wielolinijkowym fragmencie kodu. Znaczniki ``` lub ~~~ umożliwiają kolorowanie różnych języków programowania. Możemy nadać nazwę języka programowania używając auto-uzupełnienia, kod został pokolorowany używając konkretnych ustawień kolorowania składni:

```javascript
document.write('Hello World');
```

Możesz zaznaczyć również już wklejony kod w edytorze, i użyć komendy  by zamienić go w kod. Użyj kombinacji Ctrl+`, by dodać fragment kodu bez oznaczników języka.

Tabelki

Dodaj przykładową tabelkę używając komendy . Przykładowa tabelka składa się z dwóch kolumn, nagłówka i jednego wiersza.

Wygeneruj tabelkę na podstawie szablonu. Oddziel komórki separatorem ; lub |, a następnie zaznacz szablonu.

nazwisko;dziedzina;odkrycie
Pitagoras;mathematics;Pythagorean Theorem
Albert Einstein;physics;General Relativity
Marie Curie, Pierre Curie;chemistry;Radium, Polonium

Użyj komendy by zamienić zaznaczony szablon na tabelkę Markdown.

Lista uporządkowana i nieuporządkowana

Możliwe jest tworzenie listy numerowanych oraz wypunktowanych. Wystarczy, że pierwszym znakiem linii będzie * lub - dla listy nieuporządkowanej oraz 1. dla listy uporządkowanej.

Użyj komendy by dodać listę uporządkowaną.

1. Lista numerowana
2. Lista numerowana

Użyj komendy by dodać listę nieuporządkowaną.

* Lista wypunktowana
* Lista wypunktowana
** Lista wypunktowana (drugi poziom)

Składnia Markdown

Edytor obsługuje składnię Markdown, która składa się ze znaków specjalnych. Dostępne komendy, jak formatowanie , dodanie tabelki lub fragmentu kodu są w pewnym sensie świadome otaczającej jej składni, i postarają się unikać uszkodzenia jej.

Dla przykładu, używając tylko dostępnych komend, nie możemy dodać formatowania pogrubienia do kodu wielolinijkowego, albo dodać listy do tabelki - mogłoby to doprowadzić do uszkodzenia składni.

W pewnych odosobnionych przypadkach brak nowej linii przed elementami markdown również mógłby uszkodzić składnie, dlatego edytor dodaje brakujące nowe linie. Dla przykładu, dodanie formatowania pochylenia zaraz po tabelce, mogłoby zostać błędne zinterpretowane, więc edytor doda oddzielającą nową linię pomiędzy tabelką, a pochyleniem.

Skróty klawiszowe

Skróty formatujące, kiedy w edytorze znajduje się pojedynczy kursor, wstawiają sformatowany tekst przykładowy. Jeśli w edytorze znajduje się zaznaczenie (słowo, linijka, paragraf), wtedy zaznaczenie zostaje sformatowane.

  • Ctrl+B - dodaj pogrubienie lub pogrub zaznaczenie
  • Ctrl+I - dodaj pochylenie lub pochyl zaznaczenie
  • Ctrl+U - dodaj podkreślenie lub podkreśl zaznaczenie
  • Ctrl+S - dodaj przekreślenie lub przekreśl zaznaczenie

Notacja Klawiszy

  • Alt+K - dodaj notację klawiszy

Fragment kodu bez oznacznika

  • Alt+C - dodaj pusty fragment kodu

Skróty operujące na kodzie i linijkach:

  • Alt+L - zaznaczenie całej linii
  • Alt+, Alt+ - przeniesienie linijki w której znajduje się kursor w górę/dół.
  • Tab/⌘+] - dodaj wcięcie (wcięcie w prawo)
  • Shit+Tab/⌘+[ - usunięcie wcięcia (wycięcie w lewo)

Dodawanie postów:

  • Ctrl+Enter - dodaj post
  • ⌘+Enter - dodaj post (MacOS)