[elektro] Modulo "szorzás"???
Papp Zoltán
zombi at c2.hu
Sat Sep 20 03:54:01 CEST 2008
2008.09.19. 09:49:33 dátumon Pyrograph Office <office at pyrograph.hu> írta:
> Hello, Lista!
>
> Kellene nekem valami nagyon frappáns algoritmus a következőre:
>
> Adott mondjuk 3 paraméter, a következő pozitiv egész értéktartományokkal:
>
> A3 [0..2]
> A5 [0..4]
> A7 [0..6]
>
> Egy konkrét példa a feladatra:
>
> A3 = 2
> A5 = 1
> A7 = 3
>
> A lehető legegyszerübb algoritmust keresném (csak összeadás, kivonás és
> szorzás műveletekből álljon), amivel meg tudnám keresni azt a LEGKISEBB
> pozitiv egész számot (M), amire igaz, hogy a
> 3-mal osztott maradéka 2 (vagyis M mod 3 = 2)
> 5-tel osztott maradéka 1 (vagyis M mod 5 = 1)
> 7-tel osztott maradéka 3 (vagyis M mod 7 = 3)
> (tehát az A3, A5 és A7 jelzik, hogy az M számnak mennyi legyen a maradéka
> 3, 5 és 7-tel való osztáskor)
>
> Jelen példában ugye az M = 101 lenne. De milyen algoritmussal tudnám ezt
> korrektül, paraméterezhetően, gyorsan kiszámolni bármilyen esetre?
>
> Általános (univerzális) algoritmus kellene, mert ez csak egy példa volt,
> a
> valóságban azonban nem 3 db. paraméter lesz, hanem 8-10 db. (vagy
> mégtöbb), és a paraméterek értékeinek minden lehetséges variációja
> előfordulhat a saját értéktartományukon belül.
>
> Még egy fontos kitétel lenne:
> Ez az algoritmus uC-ben futna; így jó lenne (a fenti példánál maradva) ha
> a számításhoz használt egyik belső változó sem lépné át számítás közben a
> 3*5*7=105 értéket, vagy maximum a 105*7=735 értéket (7 = a legmagasabb
> paraméter a számításban). Ez több paraméternél már lényeges szempont
> lehet
> azért, hogy ne kelljen a számításhoz szükséges belső változóknak
> különösen
> hosszabb változótípust létrehozni.
>
> Előre is köszönöm, ha valaki tudna valami egyszerűen nagyszerű és jó
> ötletet adni.
>
> Nyári Viktor
>
> -----------------------------------------
> elektro[-flame|-etc]
Hali!
Mindent nem fogok matematikailag bebizonyítani, de működik az alábbi cucc:
Az alapja az egésznek, hogy ha N db osztód (d[0]..d[N-1]) és N db
maradékod (m[0]..m[N-1]) van, akkor igaz az alábbi:
M=x[i]*d[i]+m[i], ahol i=0..N-1, és x[i] természetes szám
M-et keressük.
Ha veszed az első két tagot, és megkeresed azt a legkisebb K számot, amire
igaz, hogy:
K=x[0]*d[0]+m[0]
K=x[1]*d[1]+m[1]
Ha K létezik, akkor biztos, hogy K<LKT(d[0],d[1]) (LKT: legkisebb közös
többszörös)
Ha d[0] és d[1] relatív prímek, akkor biztos, hogy K létezik. Ekkor
LKT(d[0],d[1])=d[0]*d[1]
Ha nem voltak relatív prímek, akkor vagy létezik megoldás, vagy nem. Ekkor
d[0]*d[1] számpár létezik, de csak LKT(d[0],d[1]) alkalommal van megoldás.
(pl. ha a két szám 8 és 12, akkor 8*12=96 féle számpár létezik, de ebből
csak 24 esetben van megoldás, a többinél nem létezik megoldás; pl. nem
találsz olyan számot, amire K mod 8=1 és K mod 12=2)
A fentiekből adódóan igaz a következő:
M=y*d[0]*d[1]+K, ahol y természetes szám
Ha most elvégzed az alábbi behelyettesítést:
d[0]=LKT(d[0],d[1])
m[0]=K
akkor tovább mehetsz a d[0] és d[2] párokra, majd újra és újra, míg véget
nem érnek a számok, a végén az m[0]-ban lesz a végeredmény.
K megtalálásához egyszerűen az m[0] és m[1] párokból mindig a kisebbhez
hozzá kell adni értelemszerűen a d[0] vagy d[1] értékeket, egészen addig,
míg m[0] egyenlő lesz m[1]-el, vagy az újabb érték túl nem lépi a
LKT(d[0],d[1])-et.
ALGORITMUS :
Kindulási adatok ('egyenlő' után a kezdeti értékek):
N : ennyi db osztóm van (N>=2)
m[N] : itt vannak a maradékok 0..N-1-ig
d[N] : itt vannak az osztók 0..N-1-ig
i=1 : index
top=LKT(d[0],d[1]) : aktuális legkisebb közös többszöröse d[0] és d[i]-nek
START:
IF (m[0]==m[i]) THEN GOTO NEXTDIV //ha egyformák, akkor megvan a
keresett érték, mehetünk a következőre
IF (m[0]<m[i]) THEN (m[0]=m[0]+d[0]) ELSE (m[i]=m[i]+d[i]) //a kettő
közül a kisebbet növeljük az osztójával
IF ((m[0]>=top) OR (m[i]>=top)) THEN GOTO ERROR //d[i] valamivel nem
voltak relatív prím -> hiba
GOTO START //tovább keresünk
NEXTDIV:
i=i+1 //következő szám jön a sorban
IF (i==N) THEN GOTO END //ha ez volt az utolsó -> megvan a keresett
érték
//új kezdő értékek beállítása, m[0] már a helyén van
d[0]=top // a régi top érték az új osztó
top=LKT(d[0],d[i]) //új maximum érték
GOTO START
ERROR:
// hibakezelés vagy egyszerűen csak:
RETURN(0)
END:
RETURN(m[0])
Ha biztos vagy benne, hogy bármely két d[i] érték relatív prím, akkor
LKT(d[0],d[i]) helyett egyszerűen a d[0]*d[i] képlet használható.
Egyébként az LKT-t a legegyszerűbben az LKO (legnagyobb közös osztó)
segítségével lehet megtalálni, mert:
LKT(a,b)=a*b/LKO(a,b)
Az LKO(a,b) megtalálása a legegyszerűbben az Eukledeszi-algoritmussal
lehetséges, azaz:
START:
IF (a>b) THEN c=a;a=b;b=c; //mindig legyen 'a' a nagyobb
WHILE (a>=b) DO a=a-b //amíg a nagyobb vagy egyenlő b-vel, addig
kivonjuk az a-ból a b-t
IF (a<>0) THEN GOTO START //újra kezdjük
RETURN(b) //megoldás a b-ben
Egyébként a példád így futna le az algoritmuson:
Ez volt a kiinduló adatod:
A3 = 2
A5 = 1
A7 = 3
Ez behelyettesítve az algoritmusba:
N=3
d[0]=3; m[0]=2
d[1]=5; m[1]=1
d[2]=7; m[2]=3
Az értékek változása sorrendben:
i=1
top=LKT(3,5)=15
//0 és 1 megoldása:
m[0]=2; m[1]=6
m[0]=5; m[1]=6
m[0]=8; m[1]=6
m[0]=8; m[1]=11
m[0]=11; m[1]=11
//új értékek:
i=2
d[0]=15
top=LKT(15,7)=105
//0+1 és 2 megoldása:
m[0]=11; m[2]=10
m[0]=11; m[2]=17
m[0]=26; m[2]=17
m[0]=26; m[2]=24
m[0]=26; m[2]=31
m[0]=41; m[2]=31
m[0]=41; m[2]=38
m[0]=41; m[2]=45
m[0]=56; m[2]=45
m[0]=56; m[2]=52
m[0]=56; m[2]=59
m[0]=71; m[2]=59
m[0]=71; m[2]=66
m[0]=71; m[2]=73
m[0]=86; m[2]=73
m[0]=86; m[2]=80
m[0]=86; m[2]=87
m[0]=101; m[2]=87
m[0]=101; m[2]=94
m[0]=101; m[2]=101
RETURN(101)
Mint a kiskutya, úgy működik! :-) :-D
Megj.: gyorsítani lehet az algoritmust, ha az m[0]=m[0]+d[0] képlet
helyett m[0]=m[0]+d képletet használod, ahol d=((m[i]-m[0]) DIV d[0])+1.
Értelemszerűen a fordítottja ugyanez. Ez főleg akkor hatásos, ha d[0] és
d[i] között már jelentős különbség van. Pl. ha az előző példánál más lenne
a sorrend, és a d[0]=7,d[1]=5 és d[2]=3 lenne, akkor az első kör után
d[0]=35 lenne, míg d[2]=3. Ekkor a 101-ig 3-as lépésekben alapvetően menne
fel a számláló. Az új képlettel fent lenne nemistom 2 vagy 3 lépésben.
Hát remélem, beválik, kb. 6 órát gyököltem ezen :-)
Üdv
--
Papp Zoltán
OneWay Electronics Kft
Hangszerviz
szkájpi: oneway[aláhúzás]papp[aláhúzás]zoltan
More information about the Elektro
mailing list