Turorial de Aritmetica
Lucrare de licență
Tutorial de aritmetică
Targoviste, 2014
Abstract
This work is intended to offer a solution for teaching Arithmetics. The application is written in JAVA programming language and it is cross-platform.
The application is user-friendly and it is uses graphic interface. Also it uses a user-system witch is implemented using a MySQL database. Also, user information like name and grades are stored in this database.
Users can read lessons and take a test for wich I used PHP programming language.. This PHP script inserts the grades into database. The main idea is to use a MySQL server for the database so that the application to work as a so-called client for this.
Users can check their situation anytime by logging into the system using the given username and passwords.
The code was written using Eclipse IDE and all programs needed for this application are free or open-source so that it can be easily implemented everywhere without other expenses.
Finnaly, a application can be written for the school so that the school situation can be easily maintained.
Cuprins
Introducere 1
Interfața grafică 2
Fereastra Login 3
Ferestrele despre 4
Fereastra Panou 5
Fereastra test 7
Ferastra admin 8
Resurse necesare 10
Structura aplicației 10
Funcționarea aplicației 11
Structura bazei de date 13
Pachetul dbConnection 15
Pachetul GUI 17
Pachetul pdf 29
Parte teoretică aritmetică 31
Divizibilitate pe N 31
Divizibilitate pe Z 31
Teorema fundamentală a aritmeticii 32
Congruențe pe Z 33
Teoreme lui Euler, Fermat și Wilson 34
Teorema chinezească a resturilor 34
Rădăcini primitive modulo un număr prim 35
Mulțimea numerelor prime 36
Ciurul lui Eratostene 37
Ecuații diofantice 37
Numere de tip Fermat 38
Numere de tip Mersenne 38
Numere de tip Fibonacci 39
Numere perfecte 39
Numere pseudo-prime, absolute pseudo-prime și Carmichael 40
Funcții aritmetice 40
Funcții multiplicative 42
Resturi pătratice 43
Concluzii 45
Bilbiografie 46
Introducere
Aplicația iși dorește să ofere o soluție pentru predarea aritmeticii dar și oferirea unei soluții pentru evidența situației școlare folosind o bază de date comună.
O problemă ce se întâlnește la folosirea acestui gen de aplicații este aceea al costului implementării. Un software costă destul de mult așa că acesta folosește numai software gratuit sau eliberat sub licență open-source.
Aplicația conține o clasă specializată pentru crearea unei conexiunei cu baza de date dar și de a menține legătura cu aceasta: trimitere de cereri și primirea răspunsurilor.
Interfața grafică a fost dezvoltată cu ajutorul unui plugin pentru mediul de dezvoltare Eclipse folosind tehnologia Swing. Fiecare dintre aceste clase are implementată și funcționarea aplicației.
Aplicația a fost concepută și creată în totalitate de către autor, nu s-au folosit niciun fel de alte surse sau șabloane.
Lucrarea de licență este structurată în două părți: în prima parte este prezentată aplicația informatică, structura și tehnologiile folosite la dezvoltarea acesteia (pag. 2) iar în partea a doua sunt prezentate elementele matematicg (pag. 31).
Partea de teorie matematică acoperă o mare parte din aritmetică începând cu divizibilitatea numerelor și teoria fundamentală a aritmeticii și încheind cu funcții multiplicative și funcții aritmetice.
În această parte sunt prezentate rezultatele matematice fără a se pune accent pe demonstrațiile acestora întrucât tema lucrării are scopul de a prezenta conținutul și a evalua cunoștințele aritmetice nu de a demonstra aceste teoreme. Demonstrațiile pot fi găsite consultând bibliografia prezentei lucrări.
Interfața grafică
Interfața grafică a aplicației a fost creată cu ajutorul tehnologiei Swing. Această tehnologie face parte dintr-un proiect mai amplu numit JFC (Java Foundation Classes) care pune la dispoziție o serie întreagă de facilități pentru scrierea de aplicații cu o interfață grafică mult imbogățită funcțional și estetic față de vechiul model AWT.
Unul din principalele deziderate ale tehnologiei Swing a fost să pună la dispoziție un set de componente GUI extensibile care să permita dezvoltarea rapida de aplicații Java cu interfață grafică competitivă din punct de vedere comercial. API-ul oferit de Swing este deosebit de complex având 17 pachete în care se găsesc sute de clase și interfețe.
Nu se poate spune că Swing înlocuiește modelul AWT ci îl extinde pe acesta din urmă adăugându-i noi componenente care fie înlocuiesc unele vechi fie sunt cu totul noi. O convenție în general respectată este prefixarea numelui unei clase AWT cu litera “J” pentru a denumi clasa corespondentă din Swing. Astfel, în locul clasei java.awt.Button putem folosi javax.swing.JButton.
Aplicațiile GUI vor avea nevoie în continuare de pachetul java.awt deoarece aici sunt definite unele clase utilitare ca de exemplu Color sau Font care nu au fost rescrise in Swing. De asemenea, pachetul java.awt.event rămâne esențial pentru tratarea evenimentelor generate de către componente, acesta fiind capabil să lucreze și Swing.
Fereastra Login
Gestionarea componentelor în fereastra se va face cu metoda setLayout() iar ca și gestionar al acestor componente am folosit GroupLayout() acesta grupând componentele pentru ca acestea să fie poziționate in fereastră. Componentele sunt adăugate cu ajutorul metodei add() fiecare respectând anumite constrângeri care sunt date ca parametrii acestei metode.
Cu ajutorul metodei setTitle(String s) vom seta titlul ferestrei care va apărea in bara acesteia.
Conține în partea superioară o bară de meniu creată cu componenta Swing JMenuBar. Această componenta permite crearea de meniuri asociate unei ferestre cadru, adaptând conceptul de bară de meniuri la platforma curentă de lucru. Componenta JMenuBar conține mai multe componente de tip JMenu care la rândul lor pot conține mai multe componente de tip JMenuItem, creându-se astfel o structura ierarhică astfel: JMenuBar -> JMenu -> JMenuItem. Defapt această structură reprezinte bara de meniu a ferestrei astfel: Fiecare componenta JMenu reprezintă un buton iar fiecare componentă JMenuItem atașată acestia reprezintă butoanele din submeniu.
Fereastra Login
După crearea obiectului JMenuBar am folosit metoda add(Component c) urmând sa adăugăm cele două componente JMenu corespondente butonului “Despre” și butonului “Ajutor”. Butonului “Ajutor” i-am asociat un actionListener pentru a putea reacționa în cazul în care utilizatorul apasă pe acest buton, vom deschide fereastra corespondentă. Submeniul butonului despre va conține la rândul său două butoane așa că vom adauga cele două componente JMenuItem corespondente butoanelor “Aplicație” și “Autor”. La apăsarea butonului “Despre” se va deschide un submeniu cu “Aplicație” și “Autor” cele doua butoane având atașate fiecare câte un eventListener pentru a putea acționa la apăsarea acestora.
În continuare există un text pe care l-am folosit ca și titlu “Login Tutorial de aritmetică”. Acest text este creat cu ajutorul unei componente de tip JLabel iar textul fiind setat cu metoda setText(String s).
Datele de logare (username-ul și parola) vor fi introduse în două câmpuri care sunt de tip JTextField pentru câmpul de userame si respectiv JPasswordField pentru cel de parola astfel încât aceasta să nu fie vizibilă la introducere.
În fereastră există si două componente de tip JButton care reprezintă butoanele de Login și resetare a campurilor text Username și Parola. Cele două butoane sunt poziționate alăturat celor două campuri.
Partea inferioară este ocupată de o componentă JLabel cu ajutorul căreia vom afișa starea curentă a conexiunii și eventualele erori ce apar la logare: validare username sau parolă, erori ce pot apărea la conectarea cu baza de date.
De menționat ar mai fi faptul că toate componentele își păstrează poziția la redimensionarea ferestrei.
Ferestrele despre
Este vorba de cele două ferestre corespondente meniului despre din bara de meniu din fereastra de Login. Componentele acestora sunt gestionate tot cu GroupLayout(). Prima este despreAutor și conține o componentă JTextArea în care este inserat textul de prezentare al autorului aplicației iar în partea dreaptă o componentă JPanel în care este afișată o poză. Pentru afișarea pozei a fost scrisă o clasă specializată. În partea inferioară un buton la a cărui apăsare se va închide fereastra.
Ferestrele Despre
Cea de-a doua este despreAplicație și conține o componenta JLabel si una JTextArea în care sunt inserate informații despre aplicație cu ajutorul metodei setText(String S).
Fereastra Panou
Este fereastra funcțională cu rolul cel mai important în aplicație fiind fereastra de bază a utilizatorului dupa login. Informațiile utilizatorului sunt afișate în partea din stânga a ferestrei cu ajutorul unor componente de tip JLabel . Informațiile afișate cu aceste componente sunt: numele și prenumele utilizatorului, numărul de teste date până în prezent, data la care a fost dat ultimu test. Tot într-o componentă JLabel e este afișat, în partea inferioară a ferestrei, username-ul cu care s-a făcut logarea în sistem. Acest lucru asigură utilizatorul ca logarea s-a facut corect. Media notelor testelor date este afișată într-o componentă de tip JTextField. Motivul pentru care am ales această componentă este acela că media are o valoare reală iar afișarea acesteia într-o astfel de componentă o îi conferă lizibilitate și asigură observarea acesteia.
Fereastra conține si 4 butoane care sunt create cu componente JButton . Două dintre acestea sunt poziționate în partea stângă a ferestrei și anume butonul care permite accesul la documentația necesară pentru a promova testul, iar cel de-al doilea este butonul care lansează in execuție un test a cărui notă va fi înregistrată în baza de date. Celelate două butoane sunt poziționate în partea inferioară a ferestrei funcționalitățile acestora fiind: primul dintre ele are rolul de a reîmprospăta datele din fereastra Panou facând posibilă o vizualizare a situației utilizatorului după ce acesta a susținut un test fără ca acesta să fie nevoit să se relogheze în sistem.
Fereastra Panou
În partea dreaptă a ferestrei există o componentă complexă care are rolul de a prezenta situația curentă a utilizatorului afișând notele și datele calendaristice la care acestea au fost obținute înregistrate în baza de date. Componenta este JTable iar despre crearea și popularea acesteia voi discuta într-un al capitol al lucrării. Redimensionarea ferestrei nu afectează în vreun fel poziționarea componentelor, tabelul cu datele preluate din baza de date redimensionându-se astfel încât fereastra să-și păstreze aspectul. De menționat ar mai fi faptul că tabelul permite redimensionarea coloanelor pe care sunt afișate datele
Închiderea ferestrei se face fie apăsând butonul Logout prezent în partea inferioară a ferestrei fie închizând pur și simplu fereastra din bara de control.
Fereastra test
Fereastra pentru susținerea unui test este compusă dintr-un buton care face posibilă reuluarea testului în cazul în care utilizatorul dorește acest lucru și zona în care este afișat testul propriu-zis.
Fereastra Test
Componenta Swing în care e afișat testul este de tip JTextPane deoarece aceasta este foarte permisivă în ceea ce privește tipul informațiilor ce pot fi afișate în interiorul ei. Permite afișarea textului în paragrafe, dar și afișarea elementelor grafice sau chiar incărcarea paginilor web ce respectă standardul HTML 3.0. Testul fiind scris în PHP și rulat pe un server ce permite interpretarea acestui limbaj a fost afișat în interiorul aplicației în această componentă.
Redimensionarea acestei ferestre nu afectează poziționarea elementelor, zona în care este afișat testul urmând redimensionarea ferestrei.
Ferastra admin
Această fereastră permite administrarea utilizatorilor înregistrați oferind posibilitatea adăugării sau ștergerii de utilizatori sau modificării parolei unui utilizator.
Structura acestei ferestre este complexă de aceeea aceasta este împărțită în două. În partea dreaptă se află un tabel în care sunt afișați utilizatorii existenți în baza de date. Acest tabel iși reîmprospătează automat datele când o modificare în baza de date este efectuată.
Partea stângă este ocupată de o componenta complexă și anume JTabbetPane o componentă în care pot fi adăugate mai multe subcomponente de tip JPane .
Fereastra Administrare
În această componentă sunt introduse 3 subcomponente, câte una pentru fiecare operație ce se poate efectua asupra utilizatorilor: Adăugare, Ștergere și Modificare parolă. În fiecare dintre aceste componente sunt inserate câmpuri text si butoane pentru a face posibilă modifcarea bazei de date.
Subcomponenta pentru adăugarea utilizatorilor are componente JTextField pentru introducerea datelor utilizatorului ce urmează a fi creat și o componentă JCheckBox care se poate bifa în cazul în care utilizatorul va avea drepturi de administrare.
Ștergerea unui utilizator se va face simplu, aplicația având nevoie doar de id-ul unic asociat fiecăruia astfel ca în subcomponenta de ștergere vom avea un singur câmp de text și un buton.
Modificarea parolei unui utilizator se face tot după id-ul unic al utilizatorului astfel că, subcomponenta de modificare va conține 2 câmpuri text, unul pentru id si celălalt pentru noua parolă.
Redimensionarea nu afectează poziționarea niciunui element component al ferestrei.
Resurse necesare
Aplicația a fost scrisă în limbajul Java folosind mediul de dezvoltare Eclipse 3.5.2 (http://www.eclipse.org) iar interfața grafică a fost creată utilizând plugin-ul gratuit Visual Swing 4 Eclipse (disponibil la http://code.google.com/p/visualswing4eclipse/). Versiunea Java minimă necesară pentru ca proiectul să funcționeze este 1.6 . Testele din cadrul aplicației au fost scrise în limbajul PHP, iar pentru compilarea lui este nevoie de un server Apache. Pentru baza de date am folosit sistemul de gestiune MySQL distribuit sub licență publică generală (GPL). Pachetul de instalare XAMPP (http://www.apachefriends.org/en/xampp.html) pune la dispoziție o soluție rapidă și distribuită sub licență publică generală (GPL) a celor două componenente. Instalând aceast pachet, pe calculator vor fi instalate un server de baze de date MySQL și un server Apache capabil să interpreteze fișiere PHP. Pentru vizualizarea documentației este nevoie de Adobe Acrobat Reader instalat (disponibil http://get.adobe.com/reader/).
Structura aplicației
Pe suportul electronic atașat lucrării de licență se găsește proiectul ce poate fi importat în mediul de programare Eclipse și un folder în care se găsesc toate pachete menționate anterior necesare funcționării aplicației.
Proiectul conține 3 pachete de clase Java: dbConnection în care se află clasele necesare conexiunii la baza de date, GUI care conține clasele interfeței grafice și funcționale și pachetul PDF în care se găsește clasa responsabilă cu lansarea aplicației de vizualizare a documentației.
De asemenea pe suportul electornic se vor mai găsi și un fișier .sql cu structura bazei de date care va trebui importat într-o bază de date de pe serverul MySQL și aplicația exportată sub forma unui fișier .JAR executabil pentru a rula aplicația fără a fi nevoie de instalarea mediului Eclipse.
Funcționarea aplicației
Un scenariu de utilizare al aplicației din perspectiva unui utilizator fără drepturi de administrare:
fiecare elev are înregistrat în baza de date un username cu o parolă
la pornirea programului, elevii se vor loga cu username și parolă
informațiile cu situația curentă (număr de teste date, notele obținute, media artimetică a acestora și data la care a fost dat ultimul test)
se va consulta documentația pusă la dispoziție în cadrul ferestrei de utilizator (teorie, exemple)
se va deschide fereastra de test unde este nevoie de reintroducerea datelor de logare pentru confirmarea utilizatorului
dupa completarea întrebărilor în fereastra de test va fi afișată nota obținută care este introdusă în baza de date
se poate reverifica situația curentă după apăsarea butonului de reîmprospătare a datelor
ieșirea din sistem (logout)
Un scenariu de utilizare al aplicației din perspectiva unui utilizator cu drepturi de administrare:
logarea cu un username care are drepturi de administrare va duce la deschiderea unei ferestre speciale
adaugarea unui nou utilizator necesită introducerea datelor acestuia (nume, user, parolă)
stergerea unui utilizator necesită introducerea ID-ului acestuia care poate fi aflat din tabelul cu utilizatori
modificarea parolei unui utilizator poate fi efectuată introducând ID-ul utilizatorului
Structura bazei de date
Aplicația folosește o baza de date unde sunt înregistrate toate infomațiile utilizatorilor. Pentru ca acest lucru să fie posibil, aceasta este împărțită în două tabele: una în care sunt reținute informațiile despre utilizatori (username, parolă, nume și ID-ul unic), iar cea de-a doua în care se rețin informațiile despre notele obținute de utilizatori (ID unic notă, ID-ul elevului, nota și data caledaristică).
Tipurile datelor din câmpurile tabelei note:
id: int(11)
id_elev: int(11)
nota: int(11)
data: timestamp*
Tipurile datelor din câmpurile tabelei useri:
id: int(11)
user: varchar(60)
pass: varchar(64)
nume: varchar(60)
admin: int(11)
La inserarea unei note, în câmpul id_elev va fi inserat id-ul elevului corespondent din tabela useri care a dat testul. Astfel există o singură tabelă cu toate notele ale tuturor userilor. De aceea este necesar ca fiecare notă să aibă și un ID unic.
*data la care s-a dat testul este generată de partea de test a aplicației. În cazul în care programul nu trimite către baza de date nicio dată calendaristică, în câmpul datai va fi inserată data curentă returnată de către serverul pe care este instalat MySQL.
Câmpurile ID din fiecare tabelă au setat atributul AUTO_INCREMENT astfel că id-ul unic va fi incrementat în mod automat atunci când se execută o inserare în tabel. Astfel nu este necesară o situație a ID-urilor pentru că nu există riscul ca la inserarea unei note în baza de date id-ul să existe deja din moment ce numerotarea acestora va fi efectuată în ordine crescătoare.
Câmpurile user și pass au atributul NOT_NULL astfel că la inserarea unui nou utilizator în baza de date, condiția necesară este ca aceste câmpuri să fie completate neputându-se executa o comandă INSERT cu aceste câmpuri conținând valoarea NULL.
Câmpul admin este de tipul int. Acesta are două valori pe care le poate lua:
0 – utilizatorul nu are drepturi de administrare
1(<>0) – utilizatorul are drepturi de administrare.
interfața grafică pune la dispoziție o componentă Checkbox care dacă este bifată va seta valoarea 1 în baza de date, astfel utilizatorul nou creat va avea drepturi de administrare și 0 în caz contrar, astfel utilizatorul nu va avea drepturi de administrare.
Pachetul dbConnection
Acest pachet conține clasa care se ocupă de conexiunea la baza de date MySQL. Această conexiune necesită folosirea unui driver JDBC nativ care transforma cererile JDBC direct în cereri către baza de date folosind protocolul de rețea al acesteia. Metoda folosită pentru realizarea conexiunii este getConnection din clasa DriverManager. Forma acesteia este următoarea
Connection c=DriverManager.getConnection(url,username,password);
Clasele necesare pentru conexiunea la baza de date de tip MySQL necesită importarea pachetului java.sql.*. Secvența de conectare la baza de date este următoarea:
try {
Class.forName("com.mysql.jdbc.Driver");
connection = DriverManager.getConnection(URL, USER, PASSWORD);
conectat=true;
} catch(ClassNotFoundException e) {
System.out.println("Eroare la incarcarea driverului de mysql");
} catch(SQLException e) {
System.out.println("Eroare la conectarea la baza de date");
System.out.println(e.getMessage());
}
Interfața Statement oferă metodele de bază pentru trimiterea de secvențe SQL către baza de date și obținerea rezultatelor. Crearea unui Statement se realizează prin intermediul metodei createStatement a clasei Connection fără niciun argument:
Statement st = connection.createStatement();
Metoda executeQuery este folosită pentru realizarea de interogări de tip SELECT. Metoda returnează un obiect de tip ResultSet ce va conține sub o formă tabelară rezulatul interogării.
Metoda executeUpdate este folosita pentru actualizarea datelor sau a structurii bazei de date. Această metoda returnează un număr întreg ce semnifică numărul de linii afectate de operațiunea de actualizare a datelor.
În urma execuției unei interogări SQL rezultatul va fi reprezentat printr-un obiect de tip ResultSet. Aceast obiect are structură tabelară și conține si meta-datele interogării cum ar fi denumirile coloanelor selectate, numărul lor, etc.
Pentru a extrage informațiile din această structură va trebui sa pargurgem tabelul linie cu linie și din fiecare să extragem valorile pe coloane. Pentru acest lucru vom folosi metode de tp getXXX, unde XXX este tipul de date al unei coloane iar argumentul primit indică fie numărul de ordine fie numele acestuia.
Un obiect ResultSet folosește un cursor pentru a parcuge articolele rezultate în urma unei interogări. Pentru parcurgere se folosește metoda next determinând trecerea la următoarea linie. Această metodă returnează false atunci când nu mai sunt linii de adus.
Închiderea unei conexiuni se face cu metoda close().Metodele descrise mai sus:
public Statement creareStatement() throws Exception{
st = connection.createStatement();
return st;
}
public ResultSet execQuery(String x) throws Exception{
rez = st.executeQuery(x);
return rez;
}
public int execUpdate(String x) throws Exception{
int update = st.executeUpdate(x);
return update;
}
public void disconnect() {
try {
connection.close();
} catch(SQLException e) {
System.out.println(e.getMessage());
}
}
Clasa DbConnection folosește șablonul de proiectare Singleton pentru a se asigura unicitatea conexiunii la baza de date. Acest șablon permite crearea unui singur obiect global de tip DbConnection astfel se va deschide o singură conexiune cu baza de date.
private static DbConnection INSTANCE = null;
public static DbConnection getInstance() {
if(INSTANCE==null)
INSTANCE=new DbConnection();
return INSTANCE;
}
Pachetul GUI
Acest pachet conține clasele ce definesc interfața grafică și cea mai importantă parte a aplicației.
Componentele interfeței grafice vor fi inițializate în metode separate pentru fiecare, astfel ușurând menținerea unei evidențe și modificarea ulterioară a acestora.
La apăsarea butonului Login se va crea obiectul de tip DbConnection cu ajutorul căruia se va inițializa conexiunea către baza de date. Într-un bloc try..catch se va crea Statement ul pentru selectarea utilizatorilor din baza de date în vederea verificării datelor de logare(username și parolă). În acest bloc se va trimite către baza de date comanda Select pentru a selecta toti utilizatorii iar în momentul în care s-a găsit utilizatorul cu numele introdus în câmpul de login se va verifica parola.
Obiectul conn este declarat public static pentru că este nevoie ca acesta să poată fi accesat din alte clase.
conn = new DbConnection();
try{
conn.creareStatement();
conn.execQuery("select * from useri");
Parcurgând rezultatele întoarse vom verifica dacă în baza de date există un utilizator cu numele introdus. Condiția de egalitate a usernameului și a parolei cu cele introduse de utilizator trebuie să fie îndeplinite simultan. În caz de succes, adică există un username și parola este corectă. se va verifica dacă utilizatorul are drepturi de administrator.
while(conn.rez.next())
{
String userdb=conn.rez.getString("user");
String passdb=conn.rez.getString("pass");
if((userdb.equals(username)) && passdb.equals(parola)){
if (conn.rez.getString("admin").equals("1"))
admin=true;
logat=true;
id=conn.rez.getString("id")ș
nume=conn.rez.getString("nume");
}
else jLabel3.setText("username sau parola gresite.");
}
Informațiile utilizatorului sunt reținute în variabile publice, exceptând însă parola utilizatorului care este declarată de tup private, aceasta neputând fi accesată din afara clasei.
Pentru a afla statutul curent al programului, utilizator logat sau niciun utilizator logat, am folosit o variabila de tip boolean inițializată cu valoarea false care-și schimbă valoarea atunci când sunt confirmate datele utilizatorului.
logat=false;
Similar am procedat pentru cazul utilizatorilor cu drepturi de administrator verificând dacă valoarea din baza de date confirmă faptul că utilizatorul are drepturi de administrare.
if (conn.rez.getString("admin").equals("1"))
admin=true;
Aceste date ne sunt folositoare pentru ca următorul pas îl reprezintă deschiderea ferestrei utilizator care diferă de la un utilizator normal la administrator.
if(logat && !admin){
Panel p=new Panel();
…}else if(logat && admin){
Admin a=new Admin();
…}
Deschiderea unei ferestre noi în cadrul aplicației se face instanțiind un obiect de tipul ferestrei respective (Panel sau Admin în cazul nostru). După instanțiere mai e nevoie de setarea unor caracteristici a ferestrei: acțiunea ce trebuie luată atunci când va fi apăsat butonul de închidere, setarea dimensiunilor ferestrei noi deschise(de obicei acestea se preiau din clasa de baza fiind predefinite), folosirea metodei pack() care dimensionează fereastra după valorile setate anterior și în final afișarea ferestrei cu metoda setVisible().
Admin a=new Admin(); a.setDefaultCloseOperation(Admin.DISPOSE_ON_CLOSE); a.getContentPane().setPreferredSize(a.getSize());
a.pack();
a.setVisible(true);
La apăsarea butonului de logout se vor reînițializa toate variabilele importante ale aplicației. Variabilei corespondente stării utilizatorului și anume logat îi va fi atribuită valoarea false asemeni variabilei admin.
Deschiderea ferestrei pentru un utilizator normal implică instanțierea clasei Panel . Această clasă conține mai multe elemente grafice care sunt populate cu informații culese din baza de date astfel că vom avea nevoie de conexiunea la baza de date pentru a putea trimite interogări și/sau comenzi.
În această fereastră sunt afișate informațiile despre utilizator astfel că la inițializarea fiecărei componente care afișează o informație din baza de date ar trebui trimisă o cerere către aceasta. Pentru a eficientiza aplicația și a nu suprasolicita serverul am redus numărul de interogări.
Numele utilizatorului este reținut în momentul logării utilizatorului, chiar înainte de afișarea ferestrei utilizator. Astfel afișarea acestuia este imediată. Celelaște componente vor fi reținute într-o altă serie de interogări după cum urmează.
Cea mai importantă componentă a ferestrei este tabelul în care sunt afișate notele și datele calendaristice ale testelor date. Clasa JTable permite crearea componentelor care să afișeze elemente într-un format tabelar, acestea fiind dispuse pe linii și coloane.
Inițializarea acestei componente se poate face în mai multe moduri. Cel folosit în aplicație este folosirea unui constructor ce primeste ca argumente elementele reținute sub forma unei matrice creată sub forma unei colecții de tip Vector și a unei colecții cu numele coloanelor.
Variabilele necesare creării tabelului sunt:
public Vector<String> coloane=new Vector<String>();
public Vector<Vector<String>> linii = new Vector<Vector<String>>();
private JTable jTable0;
În cadrul funcției de inițializare a componentei JTable (getJTable0()) vom efectua toate interogările asupra bazei de date pentru setarea tututor informațiilor, ulterior vom popula tabelul cu informații.
Data ultimului test o vom afla selectând din baza de date doar datele calendaristice ale testelor în ordine descrescătoare după care vom citi prima înregistrare întoarsă în obiectul de tip ResultSet.
Login.conn.execQuery("select data from note order by data desc");
Login.conn.rez.next();
dataUltTest=Login.conn.rez.getDate("data");
Următoarea informație este media aritmetică a notelor obținute. Acest lucru il vom afla interogând baza de date, calculul medie făcându-se de către server. Înregistrarea este preluată și afișată în interfața grafică.
Login.conn.execQuery("select avg(nota) as 'media' from note where id_elev="+Login.id);
Login.conn.rez.next();
media=Login.conn.rez.getString("media");
avg(nota) este o funcție MySQL care calculează media aritmetică a coloanei dată ca și parametru – nota în cazul nostru. Pentru a selecta rezultatul ușor am folosit și un alias pentru coloana creată și anume media.
Pentru afișarea datelor în tabel este nevoie de popularea matricei cu elemente și a vectorului ce va conține numele capetelor de coloane. Cum în baza de date există o tabelă separată pentru notele obținute și alta pentru useri, va trebui trimisă către server o comandă ce va efectua un join.
Un join între două tabele este o modalitate de a realiza o relație între aceste tabele pe baza unor informații comune. Tabela useri conține un câmp id cu id-ul unic al utilizatorilor iar tabela note conține de asemenea un câmp denumit id_utilizator în care se se va înregistra id-ul utilizatorului ce completează un test. Astfel că vom avea nevoie de un join între cele 2 câmpuri ce conțin id.ul utilizatorului.
Sintaxa comenzii SELECT este următoarea:
Login.conn.execQuery("select b.nume,a.data,a.nota from note a left join useri b on(a.id_elev=b.id) where b.id="+Login.id);
Urmează popularea colecției coloane care conține numele coloanelor din baza de date. Extragerea acestora din baza de date se realizează cu ajutorul metodei getColumnLabel().
for(int i=1;i<=rsmt.getColumnCount();i++){
coloane.add(rsmt.getColumnLabel(i));
}
Matricea de elemente, adică linii, va fi populată linie cu line într-o instrucțiune de tip while, atâta timp cât există elemente din baza de date.
while(Login.conn.rez.next()){
Vector<String> temp=new Vector<String>();
for(int i=1;i<=rsmt.getColumnCount();i++)
temp.add(Login.conn.rez.getString(i));
linii.add(temp);
}
Urmează inițializarea componentei JTable folosind constructorul ce primește ca argumente matricea de elemente și capetele coloanelor.
jTable0 = new JTable(linii,coloane);
Structura funcției de inițializare a tabelului:
if (jTable0 == null) {
…
}
else{
coloane.removeAllElements(); linii.removeAllElements();
…
}
Deoarece pe parcursul executării aplicației este nevoie de reinițializarea componenetelor datelor afișate, este posibil ca elementele necesare creării tabelului să trebuiască golite și repopulate.
Numărul testelor date este egal cu dimensiunea componentei Vector linii, adică numărul de rânduri întoarse de către interogarea MySQL.
Pentru reinițializarea datelor există un buton “Refresh date” care apelează pe rând metodele de inițializare a componetelor ferestrei. Prima apelată fiind inițializarea tabelului pentru aflarea tuturor datelor necesare.
private void jButton3ActionActionPerformed(ActionEvent event) {
jScrollPane0.setViewportView(getJTable0());
getJTextField0();
getJLabel5();
getJLabel3();
}
Pentru ca programul să reacționeze la apăsarea unui buton de pe interfață vom atașa acestora Listenere prin intermediul cărora vom putea acționa atunci când cu un buton se întâmplă un eveniment.
jButton0.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent event) {
jButton0ActionActionPerformed(event);
}
});
}
Acest lucru se realizează prin intermediul metodei addActionListener iar metoda care se va executa în momentul apariției unui evenimet este apelată. Această metodă este descrisă ulterior în cadrul programului.
Fereastra dispune si de un buton de Logout care are atașat un ascultător (Listener) și care la apăsarea lui va apela metoda prin intermediul căreia se va închide fereastra și se va distruge conexiunea la baza de date. De asemenea, variabilelor boolene din fereastra de login, care memorează starea curentă a utilizatorului (logat și administrator) li se va atribui valoarea false.
Login.logat=false;
Login.admin=false;
this.dispose();
Login.conn=null;
Login.jLabel3.setText("Neconectat.");
Un caz posibil este acela în care utilizatorul nu va folosi butonul de logout și ca închide direct fereastra folosind butonul de închidere din bara ferestrei. Dacă acest caz nu este tratat separat, la închiderea ferestrei astfel variabilele rămân cu valorile obținute la precedenta logare în sistem și pot exista și probleme la deschiderea ferestrei în sensul că se poate deschide o fereastra de administrator unui utilizator norma. Am tratat această situație adăugând un listener de această data pe starea ferestrei, programul reacționând atunci când această fereastră va fi închisă, indiferent prin ce metodă și efectuând aceleași modificări ca în cazul apăsării butonului de logout:
addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent event) {
Login.admin = false;
Login.logat = false;
Login.jLabel3.setText("Neconectat.");
}});
Fereastra de administrare se deschide instanțiind clasa Admin. Prin intermediul acestei ferestre, un administrator poate modifica strucura tabelei useri efectuând operații de bază asupra acesteia: adăugare, ștergere și modificarea parolei unui utilizator.
Pentru ca operațiile să se efectueze eficient, fereastra este împărțită în două zone. Zona din stânga conține o componentă JTabbedPane care face posibilă navigarea în tab-uri între ferestrele cu operații. Partea stângă a aplicației este folosită pentru a afișa conținutul curent al tabelei cu utilizatori.
Adăugarea unui utilizator necesită introducerea datelor acestuia: user, parola și numele. Se pot adăuga și utilizatori cu drepturi de administrator bifând o căsuță de tip checkbox. Dacă unul dintre aceste câmpuri nu este completat, adăugarea nu se va efectua. Pentru adăugare vom folosi conexiunea la baza de date și vom trimite comenzi cu ajutorul metodei executeUpdate() întrucât vom folosi comanda sql INSERT. Dacă un utilizator are drepturi de administrator, în baza de date se va insera în câmpul admin valoarea 1, altfel se va insera valoarea 0. Această valoare se determină în funcție de starea componentei de tip checkbox.
boolean eAdmin=jCheckBox0.isSelected();
int x=(eAdmin)?1:0;
if(!user.isEmpty() && !parola.isEmpty() && !nume.isEmpty() && !user.equals(" ") && !parola.equals(" ") && !nume.equals(" ")){
try{
Login.conn.creareStatement();
Login.conn.execUpdate("INSERT INTO useri(user,pass,nume,admin) VALUES ('"+user+"','"+parola+"','"+nume+"',"+x+");");
jScrollPane0.setViewportView(getJTable0());
}
catch(Exception e){
System.err.println(e.getMessage());
e.printStackTrace();
}
jLabel4.setText("Userul "+user+" adaugat.");
Pentru ștergerea unui utilizator nu vom avea nevoie de toate datele acestuia ci doar de id-ul unic. Această metodă face ștergerea foarte rapidă întrucât datele utilizatorilor sunt afișate permanent în partea dreaptă a ferestrei.
Introducerea id-ului utilizatorului de șters se face într-o componenta de tip JTextField care, în mod normal, permite introducerea oricărui tip de caractere, de aceea este nevoie de parsarea datelor introduse și de vericarea îndeplinirii condiției ca acestea să fie un număr întreg.
int id=0;
for(int i=0;i<input.length();i++)
if (Character.isDigit(input.charAt(i))) id=Integer.parseInt(input);
Modificarea bazei de date se face prin intermediul unui Statement, comanda fiind trimisă la baza de date cu ajutorul metodei execUpdate(). Această metodă întoarce un număr întreg care corespunde numărului de rânduri modificate din baza de date. Astfel, reținând valoarea întoarsă într-o variabila întreagă, vom putea verifica dacă există un username cu id-ul introdus.
Un mesaj corespunzător va fi afișat după apăsarea butonului de ștergere utilizator.
int x= Login.conn.execUpdate("delete from useri where id="+id);
if(x==1){
jLabel6.setText("Userul cu id-ul "+id+" a fost sters!");
jTextField3.setText("");
jScrollPane0.setViewportView(getJTable0());
}else jLabel6.setText("Userul cu id-ul " + id +" nu exista!");
Pentru modificarea parolei unui utilzator trebuie introduse id-ul utilizatorului a cărui parola urmează a fi schimbată și noua parolă. Validările ce trebuie făcute sunt următoarele:
id-ul introdus trebuie să fie o valoare numerică naturală iar noua parolă să nu fie un șir gol de caractere.
Metoda execUpdate() ne va întoarce numărul de rânduri modificate în baza de date astfel vom putea urmări dacă utilizatorului i-a fost schimbată parola cu succes. Un mesaj corespunzător va fi afișat în caz de eroare sau de succes, efectuându-se toate verificările necesare.
int id=0;
int update=0;
for(int i=0;i<input.length();i++)
if (Character.isDigit(input.charAt(i)))
id=Integer.parseInt(input);
int err=0;
if(parolaNoua.compareTo("")==0 || id==0)
err=1;
if(err==0){
try{
Login.conn.creareStatement();
update=Login.conn.execUpdate("UPDATE useri SET pass=\""+parolaNoua+"\" where id="+id);
jScrollPane0.setViewportView(getJTable0());
}
catch(Exception e){
System.err.println(e.getMessage());
jLabel4.setText("User inexistent.");
e.printStackTrace();
}
if (update==1)
jLabel4.setText("Parola modificata cu succes!");
else err=1;
}
else
jLabel4.setText("Verificati id-ul sau introduceti o parola noua!");
}
Crearea tabelului cu utilizatori se face cu informații preluate din baza de date, prin intermediul unei componente JTable. În funcția de creare a acestei componente am tratat cazul în care se vor actualiza informațiile în timpul rulării programului deoarece pentru o bună vizualizare a datelor, la fiecare operație efectuată tabelul va reacționa, datele din cadrul acestuia reîncărcându-se din baza de date.
De aceea este nevoie de reinițializarea elementelor în cazul în care obiectul de tip JTable este creat deja.
if (jTable0 == null) {
…
}
else{
coloane.removeAllElements(); linii.removeAllElements();
…
}
Din baza de date se vor extrage informațiile privind utilizatorii: id-ul, username, nume, admin cu ajutorul metodei executeQuery(). În câmpul admin se va reține o valoare întreagă, 0 – pentru utilizator normal și 1 – pentru administrator.
try{
Login.conn.execQuery("select id,user,nume,admin from useri");
ResultSetMetaData rs = Login.conn.rez.getMetaData();
for(int i=1;i<=rs.getColumnCount();i++)
coloane.add(rs.getColumnLabel(i));
while(Login.conn.rez.next())
{
Vector<String> temp=new Vector<String>();
for(int i=1;i<=rs.getColumnCount();i++)
temp.add(Login.conn.rez.getString(i));
linii.add(temp);
}
}
La fiecare eveniment atașat unui buton, după ce s-au efectuat modificările în baza de date, trebuie reactualizată structura tabelului cu utilizatori. Acest lucru înseamnă defapt reinițializarea aceste componente și deci a elementelor cu ajutorul căruia este construit. Cum funcția de creare a tabelului se ocupă deja de acest lucru, trebuie schimbată și componenta în care se află poziționat tabelul, care este de tip JScrollPane. Acest lucru se realizează cu ajutorul metodei setViewportView(getJTable0());, care este apelată în mod static pentru obiectul de tip JScrollPane. Ca argument se primește funcția de creare a tabelului getJTable0().
Această fereastră nu dispune de buton de logout, existând un Listener al ferestrei care reacționează atunci când fereastra este închisă distrugand conexiunea la baza de date și atribuind valoarea false variabilelor boolene din fereastra de login, care memorează starea curentă a utilizatorului.
Fereastra de test conține o componentă JTextPane care este capabilă de a afișa în interiorul ei o pagină web. Testele au fost scrise în limbajul PHP.
Pentru contectarea la baza de date am creat un fișier php de configurare în care sunt declarate și inițializate datele serverului de MySQL unde este creată conexiunea la baza de date prin intermediul funcției mysql_connect() care primește ca parametrii adresa serverului, username-ul și parola de acces la server. După conectare se va selecta baza de date cu funcția mysql_select_db() având ca argumente numele bazei de date și conexiunea creată anterior.
Un test este compus din două fișiere, primul în care sunt afișate întrebările în cadrul unei forme html, fiecare întrebare având un nume pentru a putea verifica răspunsurile. Exemplu de întrebare în cadrul formei:
<form action="resultate.php" method="post">
<p>1.) Intrebare.<br>
<input type="radio" name="q1" value="1"> Raspuns1<br>
<input type="radio" name="q1" value="2"> Raspuns2<br>
<input type="radio" name="q1" value="3"> Raspuns3<br>
<input type="radio" name="q1" value="4"> Raspuns4</p>
<input type="submit" name="submit" value="Verifica"></p>
<input type="hidden" name="qp" value="quiz00.php">
</form>
Tot în cadrul acestui fișier, utilizatorul va trebui să introducă username-ul și parola, evitând astfel posibiltatea completării testului de o persoană neautorizată.
Acțiunea acestei forme este un fișier php care va verifica răspunsul fiecărei întrebări după care se va introduce rezultatul în baza de date. Pentru acest lucru este nevoie de includerea fișierului în care este definită conexiunea cu ajutorul sintaxei include fisier.php.
Următorul pas este preluarea datelor din forma html prezentată anterior și verificarea datelor de logare ale utilizatorului.
Preluarea se face cu ajutorul funcției $_POST precizând numele câmpului care va fi preluat.
Trimiterea unei cereri la serverul MySQL se face cu funcția mysql_query() ale cărei argumente sunt comanda SQL și conexiunea la baza de date.
Rezultatele întoarse de server sunt preluate cu funcția mysql_fetch_array() verificarea existenței utilizatorului făcându-se din comanda SQL.
$sql = "select id,user,pass from useri where user='".$username."' and pass='".$pass."'";
$result=mysql_query($sql, $db);
Avem nevoie de id-ul utilizatorului pentru inserarea rezultatului obținut la test după cum vom vedea în continuare.
Verificarea răspunsurilor se face individual pentru fiecare întrebare, comparând valoarea preluată din forma html. Se va impune ca toate întrebările să aibă selectat minim un răspuns în caz contrar afisându-se mesaj corespunzător.
$punctaj = 0;
if ($q1=="1")
$punctaj+=2;
if ($q2=="2")
$punctaj+=2;
if ($q3=="3")
$punctaj+=2;
if ($q4=="4")
$punctaj+=2;
if ($q5=="4")
$punctaj+=2;
Punctajul calculat va fi inserat în baza de date, împreună cu data calendaristică si id-ul elevului. Id-ul îl vom prelua din datele selectate anterior iar pentru aflarea datei calendaristice vom folosi funcția php date()care primește ca argument formatul în care va fi afișată data: 'Y-m-d H:i:s' an-luna-zi ora:min:sec.
Inserarea se face prin intermediul metodei mysql_query() astfel:
$qry=mysql_query("insert into note(id_elev,nota,data) VALUES(".$id.",".$punctaj.",'".$data."')") or die(mysql_error());
Fereastra test mai dispune de un buton cu ajutorul căruia se poate relua testul, acesta reîncărcând fișierul php corespondent testului.
După apăsarea butonului de trimitere a testului se va verifica usernameul și parola. Dacă acestea sunt corecte se va calcula nota obținută și se va insera în baza de date. Un mesaj cu nota obținută va fi afișat.
Clasa AfiseazaImagine este o clasă specializată ce afisează o imagine în cadrului unei componente Jpanel. Această clasă extinde clasa Jpanel. În constructorul acestei clase se realizează încărcarea imaginii de pe hard-disk cu ajutorul clasei File. Pentru a face posibilă afișarea, e nevoie de încărcarea imaginii într-un buffer creat cu ajutorul clasei BufferedImage. Metoda read a clasei ImageIO transferă imaginea într-un buffer.
try {
File input = new File("test.jpg");
image = ImageIO.read(input);
} catch (Exception ie) {
System.out.println("Error:"+ie.getMessage());
Metoda paint conține un apel al metodei drawImage() care primește ca argumente imaginea de afișat ca obiect BufferedImage, coordonatele de afișare și un observator.
g.drawImage( image, 0, 0, null);
Afișarea în cadrul aplicației se face doar instanțiind un obiect de tipul AfiseazaImagine, calea către imagine fiind introdusă în clasă.
Pachetul pdf
Acest pachet conține clasa specializată pentru deschiderea unui fișier în format PDF. Cum aplicația a fost gândită să funcționeze independent de platformă, soluția aleasă este aceea de a deschide aplicația folosită de sistemul de operare în mod implicit pentru deschiderea fișierelor de acest tip. Clasa Desktop din awt permite acest lucru făcând posibilă lansarea unei aplicații înregistrate în sistemul de operare ca fiind cea implicită. Dacă nu se găsește nicio aplicație asociată va fi “aruncată” o excepție. Dacă aplicația este găsită, mecanismul de înregistrare, accesare și lansare a aplicației este dependent de platforma folosită.
Metodele disponibile în clasă sunt diverse: browse() – pentru accesarea unui url, edit() – pentru editarea unui fișier, mail() – pentru trimiterea unui mail, open() – pentru deschiderea unui fișier și print() – pentru imprimare.
Mai este necesară verificarea dispobililității accesării instanței Desktop lucru posibil cu proprietatea isDesktopSupported().
try {
File pdfFile = new File(fisier);
if (pdfFile.exists()) {
if (Desktop.isDesktopSupported()) {
Desktop.getDesktop().open(pdfFile);
} else {
System.out.println("Awt Desktop nu este suportat!");
}
} else {
System.out.println("Fisier inexistent!");
}
System.out.println("Deschis…");
} catch (Exception ex) {
ex.printStackTrace();
}
Parte teoretică aritmetică
Divizibilitate pe N
Definiție: Fie a,b , b≠0. Vom spune că b divide a și vom scrie b|a, dacă există c∊N astfel încât a=bc(nu definim divizibilitatea prin 0!). În acest caz spunem că b este divizor al lui a (sau că a este multiplu de b.)
Definiție: Un număr p∊N, p≥2 se zice prim dacă singurii săi divizori sunt 1 și p.
Teoremă 1.1: Fiind date două numere a,b∊N, există d∊N (vom nota d=(a,b) ) astfel încât d|a, d|b, iar dacă mai avem d’∊N astfel încât d’|a și d’|b, atunci d’|d (adică în mulțimea parțial ordonată (N,|) pentru orice două elemente a și b există a⋀b).
Exemplu: Dacă a=49 și b=35 avem:
49 = 1⋅35 + 15 ()
35 = 2⋅14 + 7 ()
15 = 2⋅7 ()
Observații:
Numărul d poartă numele de cel mai mare divizor comun al lui a și b;
Algoritmul de gărisre a celui mai mare diviyor comun a două numere naturale descris mai înainte poartă numele de algoritmul lui Euclid.
Daca pentru a,b∊N avem (a,b)=1, vom spune despre a și b că sunt prime între ele.
Inductiv, se arată că pentru oricare n numere naturale a1, a2…an (n≥2) există d∊N astfel încât d|ai pentru orice 1≤i≤n și dacă mai avem d’∊N astfel încât d’|ai pentru orice 1≤i≤n, atunci d’|d. Numărul d se notează prin d=(a1, a2…an) și poartă numele de cel mai mare divizor comun al numerelor a1, a2…an.
Divizibilitate pe Z
Definiție: Dacă a,b∊Z, b≠0, vom spune că b divide a (vom scrie b|a) dacă există c∊Z astfel încât a=bc.
Teoremă 2.1: (Teorema împărțirii cu rest în Z) Dacă a,b∊Z, b>0, atunci există c,r∊Z astfel încât a=cb+r, cu 0≤r<b.
Definiție: Numim ideal al inelului (Z,+,⋅) orice submulțime nevidă a⊆Z astfel încât
dacă x,y∊a, atunci x-y∊a
dacă x∊a și b∊Z, atunci bx∊a
Propoziția 2.2: Fie a∊ Z un ideal, Atunci există d∊N astfel încât a=dZ.
Propoziția 2.3: Fie a1, a2,…,an ∊ Z Dacă notăm prin < a1, a2,…,an > idealul generat de { a1, a2,…,an }, atunci < a1, a2,…,an >= {k1a1+…+knan : ki ∊ Z 1≤i≤n }
Teoremă 2.3: Fiind date n numere întregi a1, a2,…,an (n≥2), dacă notăm prin d numărul natural a cărui existență este asigurată de propoziția 2.1 pentru idealul a=< a1, a2,…,an > atunci d= ( a1, a2,…,an ).
Corolar 2.4: Fiind date n numere întregi a1, a2,…,an (n≥2), d=( a1, a2,…,an ) dacă și numai dacă există k1,..,kn ∊ Z astfel încât d= k1a1+…+knan.
Teorema fundamentală a aritmeticii
Fie a∊Z* și p∊ N, p≥2, un număr prim. În mod evident, există k∊N astfel încât pk|a și pk+1∤a (altfel zis, k este cel mai mare număr natural cu proprietatea pk|a). Convenim să notăm k=op(a) și să-l numim ordinul sau exponentul lui p în a. Dacă a=0 com lua op(0)=-∞, iar op(a)=0 <=> p∤a.
Propoziția 3.1: Orice număr natural nenul se scrie ca un produs de numere naturale prime.
Corolar 3.2: Pentru n∊Z* există numerele prime întregi p1, p2,…,pn astfel încât n=p1k1… pmkm cu k1…km ∊N
Lema 3.3: Dacă a,b,c∊Z* astfel încât (a,b)=1 și a|bc, atunci a|c.
Definiție:(definiție alternativă a numerelor prime) dacă p,a,b∊Z astfel încât p este prim și p|ab, atunci p|a sau p|b.
Corolar 3.4: Presupunem că p,a,b∊Z iar p este prim atunci op(ab)= op(a)+ op(b)
Teoriema 3.5: (Teorema fundamentală a aritmeticii) Pentru orice număr întreg nenul n, există o descompunere a lui în factori primi:
n= cu exponenții e(p) în mod unic determinați de n (de fapt e(p)= op(n))
Corolar 3.6: Pentru orice n există și sunt unice numerle prime distincte p1, p2,…,pn li numerele naturale k1, k2,…,kn astfel încât n=p1k1… pmkm (spunem că această descriere a lui n este descompunerea lui n în factori primi)
Corolar 3.7: Fie a,b,c ∊N* astfel încât (a,b)=1 și ab=. Atunci există x,y∊N* astfel încât a= și b=
Teorema 3.8: (Legendre) Dacă n∊N iar p este un număr prim, atunci exponentul lui pe în n! este dat de
Congruențe pe Z
Definiție: Fie n∊N, n≥2, un număr fixat. Vom spune că a,b ∊Z sunt congruente modulo n dacă n|a-b; în acest caz scriem a≡b(mod n)
Propoziția 4.1: Relația de congruență modulo n este o echivalență pe Z compatibilă cu operațiile de adunare și înmulțire de pe Z (adică este o congruențp pe inelul (Z,+,⋅)).
Corolar 4.2: Fie ai, bi ∊ Z astfel încât ai = bi (mod n) pentru orice i=1,2,…,k. Atunci:
și în particular, dacă a,b ∊ Z astfel încât a≡b(mod n) si k∊N*, atunci ak≡ bk(mod n).
Propoziția 4.3: (Zn,+,⋅) este un inel comutativ în care unitățile sale sunt
U(Zn,+,⋅) = {∊ Zn : (x,n)=1}
Exemplu:
U(Z12)={}
Pentru un număr natural n≥1 definim φ(1)=1 iar pentru n≥2, φ(n)=numărul numerelor naturale m<n astfel încât (m,n)=1. Astfel, φ(1) = φ(2)=1, φ(3)=2, etc, iar | U(Zn) |= φ(n).
Funcția φ:N*->N definită mai sus poartă numele de indicatprul lui Euler. Ea a fost studiată de Euler încă din anul 1760. Notarea funcției lui euler prin φ a fost făcută de Gauss în 1801
Corolar 4.4: (Zn,+,⋅) este corp <=> n este prim.
Propoziția 4.5: Ecuația are soluție în Z dacă și numai dacă d|b; dacă d|b atunci ecuația are exact d soluții în Zn.
Corolar 4.6: Dacă n este număr prim, atunci ecuația are soluție unică în Zn, dacă și numai dacă (a,n)=1.
Teoreme lui Euler, Fermat și Wilson
Lema 5.1: Dacă G este un grup (multiplicativ) finit cu n elemente (n≥2), atunci xn=1 pentru orice x∊G.
Corolar 5.2: (Teorema lui Euler) Dacă n≥2 este un număr natural iar a∊Z astfel încât (a,n)=1, atunci aφ(n)≡1(mod n) (φ fiind indicatorul Euler)
Corolar 5.3: (Mica teoremă a lui Fermat) Dacă p ≥ 2 este un număr prim, iar a∊Z astfel încât p∤a, atunci ap-1 ≡1 (mod p)
Lema 5.4: Fie G un grup (multiplicativ) finit comuntativ iar produsul tuturor elementelor din G. Atunci:
Corolar 5.5: (Wilson) Dacă p ≥ 2 este un număr prim, atunci (p-1)!+1≡0(mod p)
Teorema chinezească a resturilor
În cadrul acestui paragraf voi prezenta sub altă foră așa zisa teoremă chinezească a resturilor. Fie m1, m2,…,mt ∊ N astfel încât (mi, mj )=1 pentru orice i≠j, m= m1 m2 … mt, iar b1, b2,…,bt ∊ Z
Teorema 6.1: (Teorema chinezească a resturilor) Sistemul:
(S) are soluție în Z oricare două soluții diferă printr-un multiplu de m.
Teorema 6.2: Avem următorul izomorfism de inele:
Zm1⨯ Zm2⨯…⨯ Zmt ≈ Zm
Corolar 6.3: Cu notațiile de la teorema precedentă avem următorul izomorfism de grupuri multiplicative
U(Zm) ≈ U(Zm1) ⨯ … ⨯ U(Zmt)
Rădăcini primitive modulo un număr prim
Fie n ∊N*, a∊Z (a,n)=1. Conform teoremei Euler știm că aφ(n)≡1(mod n).
Definiție: Cel mai mic număr natural nenul m pentru care am≡1(mod n) se numește gaussian sau ordin al lui a și se notează prin . Defapt, =ord() în (U(Zm),⋅)
Lema 7.1: Fie k un corp comutativ și f ∊ K[X] cu grad(f)=n . Atunci f are cel mult n rădacini distincte.
Corolar 7.2: Dacă p≥2 este un număr prim, atunci pentru orice x∊Z avem:
xp-1-1≡(x-1)(x-2)….(x-p+1)(mod p)
Propoziția 7.3: Fie p≥2 un număr prim si d|p-1. Atunci congruența xd≡1(mod p) are exact d soluții.
Teorema 7.4: Dacă p este un număr prim, atunci U(Zp) este un grup ciclic.
Lema 7.5: Dacă p este un număr natural prim și 0≤k<p atunci p|.
Lema 7.6: Dacă n≥1 este un număr natural, p≥2 un număr prim și a,b∊Z astfel încât a≡b(mod pn), atunci ap≡ bp(mod pn+1)
Corolar 7.7: Dacă p este un număr prim, p≥3, n∊N, n≥2, atunci (1+ap)p≡1+apn-1(mod pn) pentru orice a∊Z.
Corolar 7.8: Dacă p≠2 este un număr prin astfel încât p∤a, atunci ordinul lui 1+ap modulo pn este egal cu pn-1 (n∊N,n≥2)
Teorema 7.9: Fie p≥3 un număr prim și n∊N*. Atunci U() este un grup ciclic. (adică există în acest grup rădăcini primitive modulo pn)
Teorema 7.10: Numărul 2n care are rădăcini primitive pentru n=1 sau 2 iar pentru n≥3 nu are. Dacă n≥3, atunci {(-1)a5b:a=0,1 și 0≤b≤2n-2 } constituie un sistem redus de resturi modulo 2n. Rezultă că pentru n≥3, U() este produsul direct a două grupuri ciclice (unul de ordin 2 iar celălalt de ordin 2n-2)
Teorema 7.11: Numărul n∊N posedă rădăcini primitive dacă și numai dacă n este de forma 2,4, pa sau 2pa cu a∊N iar p≥3 un număr prim.
Lema 7.12: Fie u un număr natural > 1. Oricare ar fi numărul natural a>0, există numerele naturale n, q0, q1,…,, qn-1,… a0, a1,…, an
a= uq0 + a0 , 0≤ a0<u
q0= uq1 + a1 , 0≤ a1<u
…………………………………………..
qn-2= uqn-1 + an-1 , 0≤ an-1<u
qn-1= uqn + an , 0≤ an<u
Lema 7.13: Fie u, a0, a1,…, an∊N astfel încât u>1, 0≤ ai < u pentru 0 ≤i<n si 0< an<u Atunci:
Teorema 7.14: Fie u un număr natural >1. Oricare ar fi numărul a>0, există numerele naturale n,an, an-1,…, a0 unic determinate astel încât a= anun+ an-1un-1+…..+ a1u+ a0, unde 0< a0<u și 0≤i≤n-1
Mulțimea numerelor prime
Teorema 8.1: (Euclid) Mulțimea P este infinită.
Demonstrație: Să presupunem prin absurd că mulțimea P este finită P={ p1, p2,…, pn } (numere prime). Vom considera p= p1p2…pn+1 și observăm că p>1 iar pi∤p pentru 1≤i<n. Ținând cont de teorema fundamentală a aritmeticii va exista un număr prim q>1 care să dividă pe p. Cum toate numerele prime sunt presupuse a fi doar p1, p2,…, pn deducem că q= pi pentru i∊{1,…,n} ceea ce este absurd căci pi∤p pentru orice 1≤i≤n. Deci P este mulțime infinită.
Teorema 8.2: (Dirichlet) Dacă a,b∊N* iar (a,b)=1, atunci mulțimea {an+b : n∊N} conține o infinitate de numere prime.
Teorema 8.3: Există o infinitate de numere prime de forma 4n-1 cu n∊N*
Teorema 8.4: Exista o infinitate de numere de forma 6n-1 cu n∊N*
Teorema 8.5: (A. Rotkiewicz). Fie p un număr prim fixat. Există o infinitate de numere prime de forma pn+1, cu n∊N*
Teorema 8.6: (Bertrand-Cebîșev) Dacă n∊N, n≥4, atunci între n si 2(n-1) se află cel puțin un număr natural prim.
Ciurul lui Eratostene
Dacă un număr natural n nu este divizibil prin niciun număr prim p≤, atunci numărul n este prim. Acesti criteru stă la baza ”ciurului” prin care Eratostene a stabilit care numere dintr-o mulțime finită de numere naturale sunt prime. Mai precis, el a scris de exemplu toate numerele de la 2 la n în ordine crescătoare. A taiat toți multiplii proprii ai lui 2, apoi toți multiplii proprii ai lui 3, pe urmă pe cei ai lui 5. Se observă că cel mai mic număr natural superior lui 5 care nu a fost tăiat este 7 și se taie atunci și toți multiplii lui 7. Se continuă în felul acesta procedeul de tăiere până se ajunge la etapa când cel mai mic număr natural din șirul 2,3,……,n care nu a fost tăiat este ≥ . Atunci procedeul se oprește deoarece conform criteriului enunțat mai înainte toate numerele netăiate din șirul 2,3,…,n sunt numere prime p≤.
Ecuații diofantice
ax+by+c=0, a,b,c∊Z
Lema 10.1: Ecuația( 1) are soluție în Z dacă și numai dacă d=(a,b) | c
Lema 10.2: Dacă (a,b)=1 iar (x0,y0) este soluție particularp a ecuației (1), atunc soluția generală din Z a acestei ecuații este dată de x=x0-kb și y=y0-ka, cu k∊Z
Corolar 10.3: Fie a,b,c∊Z astfel încât d=(a,b)|c, a = da’, b = db’, c = dc’. Dacă (x0, y0)∊Z2 este soluție particulară a ecuației a’x+b’y+c’=0, atunci soluția generașă a ecuației (1) este dată de x=x0-kb’, y=y0-ka’ cu k∊Z
Lema 10.4: Orice soluție particulară (x,y,z) de numere naturale (cu n par) a ecuației (2)x2+y2=z2 este de forma x=2mn, y=m2-n2 , z= m2+n2 cu m,n∊N si n<m, (n,m)=1, iar m,n au parități diferite.
Corolar 10.5: Soluția generală a ecuației (2) este x=2rmn, y=r(m2-n2), z=r(m2+n2) cu r,m,n∊Z
Numere de tip Fermat
Se numesc numere de tip Fermat numerele natural de forma cu n ∈ N; avem deci ș.a.m.d.
Fermat a ajuns la studiul numerelor de forma din mai multe considerente .
El a observant că dacă numărul este prim, atunci cu necessitate m este de forma cu n ∈ N. Într-adevăr, dacă există un divisor impar k al lui m, atunci cu t ∈ N și atunci contrazicând faptul că este prim.
Propoziția 11.1 :
Numerele Fermat sunt de forma cu k ∈ N* ;
Pentru orice număr natural n, iar ; dacă m,n∈ N, m≠n, atunci
Dacă n este par atunci ) iar dacă n este impar, atunci
Pentru nicio valoare a lui n, numărul nu este pătrat sau cub perfect;
Pentru n ≥ 2 divizorii primi p ai lui sunt de forma ;
Numere de tip Mersenne
Se numesc numere de tip Mersenne, numerele natural de forma . Astfel, , etc. În mod evident, dacă n este compus, atunci și este compus, astfel că pentru ca să fie prim cu necesitate și n trebuie să fie prim. Cum , tragem conluzia că pentru ca să fie prim nu este suficient doar ca n să fie prim
Propoziția 12.1 : Fie p ≥ 3 astfel încât este prim și p ≡ 3(mod 4 ). Atunci q | , deci este compus.
Propoziția 12.2 : Fie p ≥ 3 astfel încât q=2p+1 un număr prim, 1 ≤ h ≤ p, n = hp+1 sau . Atunci n este număr prim.
Teorema 12.3(Lucas-Lehmer): Pentru p ∈ N* număr impar, este prim dacă și numai dacă și pentru n≥1.
Numere de tip Fibonacci
Numim și Fibonacci șirul definit prin
Ținând cont că ecuația caracteristică atașată șirului Fibonacci este cu rădăcinile , deduce imediat că pentru orice n≥1,
.
Corolar 13.1:
Pentru orice n,k≥1 avem ;
Pentru orice m,n ≥ 1 avem ;
Dacă m,n≥1 și (m,n) = 1, atunci ;
Teorema 13.2: Fie p≥2 un număr prim.
Dacă p = 5k ± 1, atunci ;
Dacă p = 5k ± 2, atunci .
Numere perfecte
Un număr natural n se zice perfect dacă (adică suma a divizorilor săi strict mai mici decât n este egală cu n).
Numerele perfecte au fost studiate încă din antichitate, fiind cunoscute numerele perfecte mai mici decât 10000 și anume 6, 28, 496 și 8128.
Caracterizare numerelor perfecte este dată de:
Teorema 14.1 Un număr natural n este perfect dacă și numai dacă este număr prim.
Numere pseudo-prime, absolute pseudo-prime și Carmichael
Un număr natural compus n se zice:
Pseudo-prim dacă ;
Absolute pseudo-prim dacă pentru orice întreg a avem ;
Număr Carmichael dacă pentru orice întreg a pentru care
Teorema 15.1 Dacă n este impar pseudo-prim, atunci și este pseudoprim.
Teorema 15.2 Un număr compus este nume Carmichael dacă și numai dacă sunt îndeplinite următoarele condiții:
n este impar;
k≥3;
Funcții aritmetice
Definiția 16.1: Numim funcție aritmetică orice funcție . În cadrul acestui capitol vom prezenta mai multe exemple de astfel de funcții. Fie mulțimea funcțiilor aritmetice. Pentru astfel:
și
Observație. poartă numele de produsul hibrid Dirichlet de convoluție al lui .
Propoziția 16.2: este inel comutativ unitar.
Elementul neutru pentru * este se verifică imediat că , pentru orice .
Propoziția 16.3: .
Se verifică imediat că
Iată câteva exemple de funcții aritmetice:
Funcția a lui euler definită in pargraful 4 de la Capitolul 1.
Pentru
În particular se va nota cu (deci
Dacă
3.Funcția Se verifică imediat că dacă atunci .
Observație. Conform propoziției 1 funcția zeta are inversă îni nelul A; se notează cu și poartă numele de funcția Möbius. Deoarece , deducem că
În particular, dacă p este un număr prim iar Astfel
Observație. Dacă Acest fapt este cunoscut sub numele de formula clasică de inversare a lui Möbius.
Dacă: scriem explicit obținem:
Propoziția 16.4: Dacă sunt funcții aritmetice atunci
Lema 16.5 Pentru
Corolar 1.6 Cum
Funcții multiplicative
Definiția 17.1 O funcție aritmetică se zice funcție multiplicativă dacă
Observație: Dacă este multiplicativă atunci din există un și cum este descompunerea în factori primi a lui , atunci , astfel că o funcție multiplicativă este complet determinată de valorile ei pe mulțimile de forma cu prim și Să notăm cu M familia funcțiilor multiplicative.
Observație : Cum funcția zeta este multiplicativă, inversa sa, care este funcția lui Möbius, este multiplicativă. Astfel:
Avem în felul acesta o altă definire a funcției Möbius.
Propoziția 17.2: Dacă
Observație:
Deoarece este multiplicativă și deducem că și este multiplicativă. Astfel, dacă ¸este număr prim iar . În particular, Deoarece .
Cum funcția lui Euler atunci pentru orice
Funcția a lui Euler este o funcție calculabilă (adică pentru orice
Resturi pătratice
Generalități. Simbolul lui Legendre
Definiția 18.1: Un număr se zice rest pătratic modulo m dacă ecuația are soluție in . În caz contrar se zice non+rest pătratic modulo .
În mod evident, dacă , atunci este rest pătratic modulo este rest pătratic modulo .
Observație.
Fie un număr prim; dacă este impar atunci ecuația are soluție pentru . Deci orice număr impar este rest pătratic modulo 2.
Dacă este impar, atunci este rest pătratic modulo , atunci există este rest pătratic modulo restul împărțirii lui la este din ). Aici .
Cum ∊N, funcția : -> , este morfism de grupuri muliplicative. Cum =1 deducem că
Mai mult
= -1 pentru un anumit x ∊
Dacă x=t2∊, atunci
Definiția 18.2: Numim simbolul Legendre morfismul de grupuri multiplicative .
Deci , pentru orice a∊ (evident p∤a, căci a∊)
Lema 18.3:(Gauss) Fie , unde X= iar Y==. Pentru . Atunci unde g= | |
Corolar 18.4: Pentru orice număr prim p impar avem
Concluzii
Dezvoltând această aplicație am dorit implementarea eficientă a unui sistem de administrare și menținere situației scolare. Mergând mai departe, se poate implementa o aplicație asemănătoare pentru fiecare materie din aria curriculară și folosindu-se o baza de date comună se poate ușor dezvolta un sistem complet de adminsitrare a șolarității.
Având acces la baza de date cu structura menționată in conținut, aplicația poate fi folosită pe orice sistem de operare sub forma unui client.
De asemenea aplicația oferă și o soluție ce se poate implementa ușor pentru predarea aritmeticii dar și pentru testare. Se poate ține o evidență a elevilor și a notelor obținute de aceștia.
Din partea de teorie matematică și anume aritmetică, am făcut o selecție a celor mai importante teoreme și rezultate care sunt prezentate și în cadrul aplicației la secțiunea documentație. Testele ce urmează a fi date de către utilizator conțin întrebări formulate pe baza acestei părți de teorie.
Bilbiografie
[1] FRĂSINARU Cristian, Curs practic de Java, Iași
[2] TĂNASĂ Ștefan, ANDREI Ștefan, OLARU Cristian, Java de la 0 la expert, Polirom, 2007
[3] FLANAGAN David, Java in a nutshell, O’Reilly Media, 1999
[4] MELTON Jim, EISENBERG Andrew, Understanding SQL and Java together, Morgan Kaufmann, 2000
[5] BĂLĂNESCU Tudor, MOCANU Ștefan, Interfețe grafice în Java, Editura Fundației România de Mâine, 2005
[6] RUSU Eugen, Aritmetica și teoria numerelor, Editura Tehnică, București, 1963
[7] BUȘNEAG Dumitru, CHIRTEȘ Florentina, PICIU Dana, Complemenet de aritmetică și teoria elementară a numerelor, GIL, 2007
Bilbiografie
[1] FRĂSINARU Cristian, Curs practic de Java, Iași
[2] TĂNASĂ Ștefan, ANDREI Ștefan, OLARU Cristian, Java de la 0 la expert, Polirom, 2007
[3] FLANAGAN David, Java in a nutshell, O’Reilly Media, 1999
[4] MELTON Jim, EISENBERG Andrew, Understanding SQL and Java together, Morgan Kaufmann, 2000
[5] BĂLĂNESCU Tudor, MOCANU Ștefan, Interfețe grafice în Java, Editura Fundației România de Mâine, 2005
Copyright Notice
© Licențiada.org respectă drepturile de proprietate intelectuală și așteaptă ca toți utilizatorii să facă același lucru. Dacă consideri că un conținut de pe site încalcă drepturile tale de autor, te rugăm să trimiți o notificare DMCA.
Acest articol: Turorial de Aritmetica (ID: 124681)
Dacă considerați că acest conținut vă încalcă drepturile de autor, vă rugăm să depuneți o cerere pe pagina noastră Copyright Takedown.
