Thread: Help getting formula to work.

  1. #1
    Registered User
    Join Date
    Sep 2007
    Posts
    23

    Help getting formula to work.

    I have to write a program that can input up to 20 students name, exam 1 and 2 grades, homework average, and final exam grade. Then it says I have to calculate a final grade using the formula finalGrade=0.20*examOne+0.20*examTwo+0.35*homework +0.25*finalExam; I got the first part of the program to work but no matter what I try the final grade will only output the last student I entered instead of both students. Can anyone help me out, Please?


    Code:
    #include "stdafx.h"
    #include <iostream>
    #include <fstream>
    #include <string>
    #include <cstdlib>
    #include <iomanip>
    #include <cmath>
    #include <vector>
    #include <algorithm>
    using namespace std;
    
    class Grade
    {
    private:
    	string name;
    	int examOne, examTwo, homework, finalExam;
    	
    
    public:
    	Grade(){setGrade("Tom", 94, 92, 87 ,85);};
    	Grade(string nm, int exOne, int exTwo, int hw, int final){setGrade(nm, exOne, exTwo, hw, final);};
    	void setGrade(string nm, int exOne, int exTwo, int hw, int final){name=nm; examOne=exOne; examTwo=exTwo; homework=hw; finalExam=final;};
    	string getName(){return name;};
    	int getExamOne(){return examOne;};
    	int getExamTwo(){return examTwo;};
    	int getHomework(){return homework;};
    	int getFinalExam(){return finalExam;};
    	
    };
    
    int _tmain(int argc, _TCHAR* argv[])
    {
    	const int Grades = 2;
    	string filename = "grades.dat";
    	string name;
        ofstream outFile;
    	int i, examOne, examTwo, homework, finalExam;
    	double finalGrade;
    	Grade g;
    	
    	vector<Grade> gTable;
    
    	outFile.open(filename.c_str());
    	
        
    	for(i=0; i<Grades; i++)
    	{
    		cout <<"\nEnter students name, 1st exam grade, 2nd exam grade, homework average,"
    			 <<  "and final exam grade (type done to exit): \n";
    		cin >>name>>examOne>>examTwo>>homework>>finalExam;
        	if(name=="done")
    			break;
    
    		g=Grade(name, examOne, examTwo, homework, finalExam);
    		gTable.push_back(g);
    
    
    	}
    
        
    	
    	cout << fixed << setprecision(2) << endl;
    	cout << "Student    Exam 1     Exam 2     Homework     Final Exam     Final     Letter"<<endl;
    	cout << "Name       Grade      Grade      Average      Grade          Grade     Grade"<<endl;
    	cout << "-------    ------     ------     --------     ----------     -----     -----"<<endl;
    
    	
    	
    	for(i=0; i<Grades; i++)
        
    	{
        finalGrade=0.20*examOne+0.20*examTwo+0.35*homework+0.25*finalExam;
        	cout <<setw(8)<<gTable[i].getName()<<"  "<<setw(6)<<gTable[i].getExamOne()<<"     "
    		<<setw(6)<<gTable[i].getExamTwo()<<"    "<<setw(8)<<gTable[i].getHomework()
    		<<"     "<<setw(6)<<gTable[i].getFinalExam()<<finalGrade<<endl;
    	}
    
            
    	
        for(i=0; i<Grades; i++)
    	{
    		outFile <<gTable[i].getName()<<" "
    				<<gTable[i].getExamOne()<<" "
    				<<gTable[i].getExamTwo()<<" "
    				<<gTable[i].getHomework()<<" "
    				<<gTable[i].getFinalExam()<<endl;
    				
    	}
    
        
    	outFile.close();
    	cout << "The file " << filename
    		 << " has been successfully written." << endl;
    
    	cin.ignore();cin.ignore();
    
    	return 0;
    }

  2. #2
    Registered User
    Join Date
    Jan 2005
    Posts
    7,366
    >> finalGrade=0.20*examOne+0.20*examTwo+0.35*homework +0.25*finalExam;
    In that code you're using the variables that you used to read in the data as the basis for the final grade calculation. You should be using the data inside the object gTable[i], which will be different for the two different users.

    Good C++ practice includes declaring your variables in the smallest possible scope that you need them. In this case, you would declare name, examOne, examTwo, homework and finalExam inside the loop that reads the data from cin, and the compiler would tell you that you are using them later when you shouldn't be.

  3. #3
    Registered User
    Join Date
    Sep 2007
    Posts
    23
    So I need to put something like 0.20*gTable[i].getExamOne, etc.?

  4. #4
    Registered User
    Join Date
    Sep 2007
    Posts
    23
    OK. I got that working now. So how could I get something like this to work?

    Code:
    	for (int i = 0; i<Grades; i++)
    {
        if (finalGrade>90)
        cout<<"A";   
        else if (finalGrade>80)
        cout<<"B";   
        else if (finalGrade>70)
        cout<<"C";    
        else if (finalGrade>59)
        cout<<"D";   
        else
        cout<<"F";   
    }

  5. #5
    Registered User
    Join Date
    May 2007
    Posts
    77
    Actually, that would be good right there. However, you'd probably want to make the if...else series inside the loop into a separate function you could call, and then call it in your output loop.

    One thing I noticed about your "current" code is that if you put in the first and last names of the student, it displays an error negative integer. I don't know if you've fixed that by now, but you may want to have a look at that, and possibly have either separate "cin" lines for name and all the others, or have two name variables, one for first, and one for last.

  6. #6
    Registered User
    Join Date
    Sep 2007
    Posts
    23
    The way I have it set up now it assigns the letter grade of the second student to both students. How can I get it to assign each student their own letter grade? Also, I would rather output the letter grade to the table I have set up. How can I do that? Any help is appreciated!

    Code:
    #include "stdafx.h"
    #include <iostream>
    #include <fstream>
    #include <string>
    #include <cstdlib>
    #include <iomanip>
    #include <cmath>
    #include <vector>
    #include <algorithm>
    using namespace std;
    
    class Grade
    {
    private:
    	string name;
    	int examOne, examTwo, homework, finalExam;
    	
    
    public:
    	Grade(){setGrade("Tom", 94, 92, 87 ,85);};
    	Grade(string nm, int exOne, int exTwo, int hw, int final){setGrade(nm, exOne, exTwo, hw, final);};
    	void setGrade(string nm, int exOne, int exTwo, int hw, int final){name=nm; examOne=exOne; examTwo=exTwo; homework=hw; finalExam=final;};
    	string getName(){return name;};
    	int getExamOne(){return examOne;};
    	int getExamTwo(){return examTwo;};
    	int getHomework(){return homework;};
    	int getFinalExam(){return finalExam;};
    	
    };
    
    int _tmain(int argc, _TCHAR* argv[])
    {
    	const int Grades = 2;
    	string filename = "grades.dat";
    	string name;
        ofstream outFile;
    	int i, examOne, examTwo, homework, finalExam;
    	double finalGrade;
    	Grade g;
    	
    	vector<Grade> gTable;
    
    	outFile.open(filename.c_str());
    	
        
    	for(i=0; i<Grades; i++)
    	{
    		cout <<"\nEnter students name, 1st exam grade, 2nd exam grade, homework average,"
    			 <<  "and final exam grade (type done to exit): \n";
    		cin >>name>>examOne>>examTwo>>homework>>finalExam;
        	if(name=="done")
    			break;
    
    		g=Grade(name, examOne, examTwo, homework, finalExam);
    		gTable.push_back(g);
    
    
    	}
    
        
    	
    	cout << fixed << setprecision(2) << endl;
    	cout << "Student    Exam 1     Exam 2     Homework     Final Exam     Final     Letter"<<endl;
    	cout << "Name       Grade      Grade      Average      Grade          Grade     Grade"<<endl;
    	cout << "-------    ------     ------     --------     ----------     -----     -----"<<endl;
    
    
    	
    	for(i=0; i<gTable.size(); i++)
        
    	{
        finalGrade=0.20*gTable[i].getExamOne()+0.20*gTable[i].getExamTwo()+0.35*gTable[i].getHomework()+0.25*gTable[i].getFinalExam();
    
    	
    	   
    	
        	cout <<setw(8)<<gTable[i].getName()<<"  "<<setw(6)<<gTable[i].getExamOne()<<"     "
    		<<setw(6)<<gTable[i].getExamTwo()<<"    "<<setw(8)<<gTable[i].getHomework()
    		<<"     "<<setw(6)<<gTable[i].getFinalExam()<<"           "<<setw(5)
    		<<finalGrade<<endl<<endl;
    	
       }
    
        for(i=0; i<gTable.size(); i++)
    	{
        if (finalGrade>90)
        cout<<gTable[i].getName()<<"'s final grade is an A.\n";   
        else if (finalGrade>80)
        cout<<gTable[i].getName()<<"'s final grade is a B.\n";   
        else if (finalGrade>70)
        cout<<gTable[i].getName()<<"'s final grade is a C.\n";    
        else if (finalGrade>59)
        cout<<gTable[i].getName()<<"'s final grade is a D.\n";   
        else
        cout<<gTable[i].getName()<<"'s final grade is a F.\n";
    	}
    	
    		
        for(i=0; i<Grades; i++)
    	{
    		outFile <<gTable[i].getName()<<" "
    				<<gTable[i].getExamOne()<<" "
    				<<gTable[i].getExamTwo()<<" "
    				<<gTable[i].getHomework()<<" "
    				<<gTable[i].getFinalExam()<<endl;
    				
    	}
    
        
    	outFile.close();
    	cout << "The file " << filename
    		 << " has been successfully written." << endl;
    
    	cin.ignore();cin.ignore();
    
    	return 0;
    }

  7. #7
    Registered User
    Join Date
    Nov 2006
    Posts
    85
    Quote Originally Posted by gator6688 View Post
    Code:
    	for(i=0; i<gTable.size(); i++)
        
    	{
        finalGrade=0.20*gTable[i].getExamOne()+0.20*gTable[i].getExamTwo()+0.35*gTable[i].getHomework()+0.25*gTable[i].getFinalExam();
    
    	
    	   
    	
        	cout <<setw(8)<<gTable[i].getName()<<"  "<<setw(6)<<gTable[i].getExamOne()<<"     "
    		<<setw(6)<<gTable[i].getExamTwo()<<"    "<<setw(8)<<gTable[i].getHomework()
    		<<"     "<<setw(6)<<gTable[i].getFinalExam()<<"           "<<setw(5)
    		<<finalGrade<<endl<<endl;
    	
       }
    
        for(i=0; i<gTable.size(); i++)
    	{
        if (finalGrade>90)
        cout<<gTable[i].getName()<<"'s final grade is an A.\n";   
        else if (finalGrade>80)
        cout<<gTable[i].getName()<<"'s final grade is a B.\n";   
        else if (finalGrade>70)
        cout<<gTable[i].getName()<<"'s final grade is a C.\n";    
        else if (finalGrade>59)
        cout<<gTable[i].getName()<<"'s final grade is a D.\n";   
        else
        cout<<gTable[i].getName()<<"'s final grade is a F.\n";
    	}
    The problem is that the seconds student final grade is the last one to be calculated. Because you have two students the for loop executes twice calling the same last to be calculated value of student 2. Have your grade class store a finalGrade parameter. In your for loop you could write something like

    Code:
    if (gTable[i].getFinalGrade()>90) //after you create an get function for it.
        cout<<gTable[i].getName()<<"'s final grade is an A.\n";   
        else if (gTable[i].getFinalGrade()>80)
        cout<<gTable[i].getName()<<"'s final grade is a B.\n";   
        else if (gTable[i].getFinalGrade()>70)
        cout<<gTable[i].getName()<<"'s final grade is a C.\n";    
        else if (gTable[i].getFinalGrade()59)
        cout<<gTable[i].getName()<<"'s final grade is a D.\n";   
        else
        cout<<gTable[i].getName()<<"'s final grade is a F.\n";
    hope that helps

  8. #8
    Registered User
    Join Date
    Sep 2007
    Posts
    23
    I think I did what you told me to do but now I am getting a run time error because it is giving me a negative for my final grade.

    Code:
    #include "stdafx.h"
    #include <iostream>
    #include <fstream>
    #include <string>
    #include <cstdlib>
    #include <iomanip>
    #include <cmath>
    #include <vector>
    #include <algorithm>
    using namespace std;
    
    class Grade
    {
    private:
    	string name;
    	int examOne, examTwo, homework, finalExam;
    	double finalGrade;
    
    public:
    	Grade(){setGrade("Tom", 94, 92, 87 ,85,85.75);};
    	Grade(string nm, int exOne, int exTwo, int hw, int final, double fGrade){setGrade(nm, exOne, exTwo, hw, final, fGrade);};
    	void setGrade(string nm, int exOne, int exTwo, int hw, int final, double fGrade){name=nm; examOne=exOne; examTwo=exTwo; homework=hw; finalExam=final; finalGrade=fGrade;};
    	string getName(){return name;};
    	int getExamOne(){return examOne;};
    	int getExamTwo(){return examTwo;};
    	int getHomework(){return homework;};
    	int getFinalExam(){return finalExam;};
    	double getFinalGrade(){return finalGrade;};
    };
    
    int _tmain(int argc, _TCHAR* argv[])
    {
    	const int Grades = 2;
    	string filename = "grades.dat";
    	string name;
        ofstream outFile;
    	int i, examOne, examTwo, homework, finalExam;
    	double finalGrade;
    	Grade g;
    	
    	vector<Grade> gTable;
    
    	outFile.open(filename.c_str());
    	
        
    	for(i=0; i<Grades; i++)
    	{
    		cout <<"\nEnter students name, 1st exam grade, 2nd exam grade, homework average,"
    			 <<  "and final exam grade (type done to exit): \n";
    		cin >>name>>examOne>>examTwo>>homework>>finalExam;
        	if(name=="done")
    			break;
    
    		g=Grade(name, examOne, examTwo, homework, finalExam, finalGrade);
    		gTable.push_back(g);
    
    
    	}
    
        
    	
    	cout << fixed << setprecision(2) << endl;
    	cout << "Student    Exam 1     Exam 2     Homework     Final Exam     Final     Letter"<<endl;
    	cout << "Name       Grade      Grade      Average      Grade          Grade     Grade"<<endl;
    	cout << "-------    ------     ------     --------     ----------     -----     -----"<<endl;
    
    
    	
    	for(i=0; i<Grades; i++)
        
    	{
        
    finalGrade=0.20*gTable[i].getExamOne()+0.20*gTable[i].getExamTwo()+0.35*gTable[i].getHomework()+0.25*gTable[i].getFinalExam();
    	
    	   
    	
        	cout <<setw(8)<<gTable[i].getName()<<"  "<<setw(6)<<gTable[i].getExamOne()<<"     "
    		<<setw(6)<<gTable[i].getExamTwo()<<"    "<<setw(8)<<gTable[i].getHomework()
    		<<"     "<<setw(6)<<gTable[i].getFinalExam()<<"           "<<setw(5)
    		<<finalGrade<<endl<<endl;
    	
       }
    
        for(i=0; i<Grades; i++)
    	{
        if (gTable[i].getFinalGrade()>90) //after you create an get function for it.
        cout<<gTable[i].getName()<<"'s final grade is an A.\n";   
        else if (gTable[i].getFinalGrade()>80)
        cout<<gTable[i].getName()<<"'s final grade is a B.\n";   
        else if (gTable[i].getFinalGrade()>70)
        cout<<gTable[i].getName()<<"'s final grade is a C.\n";    
        else if (gTable[i].getFinalGrade()>59)
        cout<<gTable[i].getName()<<"'s final grade is a D.\n";   
        else
        cout<<gTable[i].getName()<<"'s final grade is a F.\n";
    	}
    	
    		
        for(i=0; i<Grades; i++)
    	{
    		outFile <<gTable[i].getName()<<" "
    				<<gTable[i].getExamOne()<<" "
    				<<gTable[i].getExamTwo()<<" "
    				<<gTable[i].getHomework()<<" "
    				<<gTable[i].getFinalExam()<<endl;
    				
    	}
    
        
    	outFile.close();
    	cout << "The file " << filename
    		 << " has been successfully written." << endl;
    
    	cin.ignore();cin.ignore();
    
    	return 0;
    }

  9. #9
    Registered User
    Join Date
    Nov 2006
    Posts
    85
    first your class needs a setFinalGrade(double).

    Code:
    int i, examOne, examTwo, homework, finalExam;
    	double finalGrade;
    those should all be doubles because you multiply them by decimals. Don't forget to make all the get functions in your class and your constructor to take double's instead of ints.

    Code:
    finalGrade=0.20*gTable[i].getExamOne()+0.20*gTable[i].getExamTwo()+0.35*gTable[i].getHomework()+0.25*gTable[i].getFinalExam();
    that first part should be: gTable[i].setFinalGrade(0.20*gTable[i].getExamOne()+0.20*gTable[i].getExamTwo()+0.35*gTable[i].getHomework()+0.25*gTable[i].getFinalExam());

    as to why finalGrade is negative:
    Code:
         	
    double finalGrade;
    
    
    
    //...
    
    if(name=="done")
    			break;
    
    		g=Grade(name, examOne, examTwo, homework, finalExam, finalGrade);
    		gTable.push_back(g);
    
    
    	}
    Your putting finalGrade into the instance of your grade class before you evaluate it. Since you didn't initiate finalGrade to anything then gTable[i].getFinalGrade() is whatever was in the memory at the time. Once you create a setFinalGrade() and use it as I instructed this bug will dissapear.

    hope that helps.

    EDIT:

    aslo don't forget to change this to

    Code:
    cout <<setw(8)<<gTable[i].getName()<<"  "<<setw(6)<<gTable[i].getExamOne()<<"     "
    		<<setw(6)<<gTable[i].getExamTwo()<<"    "<<setw(8)<<gTable[i].getHomework()
    		<<"     "<<setw(6)<<gTable[i].getFinalExam()<<"           "<<setw(5)
    		<<gTable[i].getFinalGrade()<<endl<<endl;
    Last edited by A10; 11-07-2007 at 09:31 PM. Reason: after thought

  10. #10
    Registered User
    Join Date
    Sep 2007
    Posts
    23
    It's telling me that this function does not take 1 arguement.

    Code:
    gTable[i].setFinalGrade(0.20*gTable[i].getExamOne()+0.20*gTable[i].getExamTwo()+0.35*gTable[i].getHomework()+0.25*gTable[i].getFinalExam());
    Here is the updated code so far:

    Code:
    #include "stdafx.h"
    #include <iostream>
    #include <fstream>
    #include <string>
    #include <cstdlib>
    #include <iomanip>
    #include <cmath>
    #include <vector>
    #include <algorithm>
    using namespace std;
    
    class Grade
    {
    private:
    	string name;
    	double examOne, examTwo, homework, finalExam;
    	double finalGrade;
    
    public:
    	Grade(){setGrade("Tom", 94, 92, 87 ,85, 85.75);};
    	Grade(string nm, double exOne, double exTwo, double hw, double final, double fGrade){setGrade(nm, exOne, exTwo, hw, final, fGrade);};
    	void setGrade(string nm, double exOne, double exTwo, double hw, double final, double fGrade){name=nm; examOne=exOne; examTwo=exTwo; homework=hw; finalExam=final; finalGrade=fGrade;};
    	string getName(){return name;};
    	double getExamOne(){return examOne;};
    	double getExamTwo(){return examTwo;};
    	double getHomework(){return homework;};
    	double getFinalExam(){return finalExam;};
    	double setFinalGrade(){return finalGrade;};
    };
    
    int _tmain(int argc, _TCHAR* argv[])
    {
    	const int Grades = 2;
    	string filename = "grades.dat";
    	string name;
        ofstream outFile;
    	int i; 
    	double finalGrade, examOne, examTwo, homework, finalExam;;
    	Grade g;
    	
    	vector<Grade> gTable;
    
    	outFile.open(filename.c_str());
    	
        
    	for(i=0; i<Grades; i++)
    	{
    		cout <<"\nEnter students name, 1st exam grade, 2nd exam grade, homework average,"
    			 <<  "and final exam grade (type done to exit): \n";
    		cin >>name>>examOne>>examTwo>>homework>>finalExam;
        	if(name=="done")
    			break;
    
    		g=Grade(name, examOne, examTwo, homework, finalExam, finalGrade);
    		gTable.push_back(g);
    
    
    	}
    
        
    	
    	cout << fixed << setprecision(2) << endl;
    	cout << "Student    Exam 1     Exam 2     Homework     Final Exam     Final     Letter"<<endl;
    	cout << "Name       Grade      Grade      Average      Grade          Grade     Grade"<<endl;
    	cout << "-------    ------     ------     --------     ----------     -----     -----"<<endl;
    
    
    	
    	for(i=0; i<Grades; i++)
        
    	{
        
    gTable[i].setFinalGrade(0.20*gTable[i].getExamOne()+0.20*gTable[i].getExamTwo()+0.35*gTable[i].getHomework()+0.25*gTable[i].getFinalExam());
    	
    	   
    	
        	cout <<setw(8)<<gTable[i].getName()<<"  "<<setw(6)<<gTable[i].getExamOne()<<"     "
    		<<setw(6)<<gTable[i].getExamTwo()<<"    "<<setw(8)<<gTable[i].getHomework()
    		<<"     "<<setw(6)<<gTable[i].getFinalExam()<<"           "<<setw(5)
    		<<gTable[i].getFinalGrade<<endl<<endl;
    	
       }
    
        for(i=0; i<Grades; i++)
    	{
        if (gTable[i].getFinalGrade()>90) //after you create an get function for it.
        cout<<gTable[i].getName()<<"'s final grade is an A.\n";   
        else if (gTable[i].getFinalGrade()>80)
        cout<<gTable[i].getName()<<"'s final grade is a B.\n";   
        else if (gTable[i].getFinalGrade()>70)
        cout<<gTable[i].getName()<<"'s final grade is a C.\n";    
        else if (gTable[i].getFinalGrade()>59)
        cout<<gTable[i].getName()<<"'s final grade is a D.\n";   
        else
        cout<<gTable[i].getName()<<"'s final grade is a F.\n";
    	}
    	
    		
        for(i=0; i<Grades; i++)
    	{
    		outFile <<gTable[i].getName()<<" "
    				<<gTable[i].getExamOne()<<" "
    				<<gTable[i].getExamTwo()<<" "
    				<<gTable[i].getHomework()<<" "
    				<<gTable[i].getFinalExam()<<endl;
    				
    	}
    
        
    	outFile.close();
    	cout << "The file " << filename
    		 << " has been successfully written." << endl;
    
    	cin.ignore();cin.ignore();
    
    	return 0;
    }

  11. #11
    Frequently Quite Prolix dwks's Avatar
    Join Date
    Apr 2005
    Location
    Canada
    Posts
    8,057
    Well, of course that function doesn't take one argument. It takes none!
    Code:
    double setFinalGrade(){return finalGrade;};
    Since that looks more like a "get" rather than a "set" function to me, I think you meant
    Code:
    void setFinalGrade(double grade) {
        finalGrade = grade;
    }
    I don't know about you, but I can't read a lot of that code because it's not indented very well. For example, your longest line is much more readable as
    Code:
        void setGrade(string nm, double exOne, double exTwo, double hw, double final, double fGrade) {
            name=nm;
            examOne=exOne;
            examTwo=exTwo;
            homework=hw;
            finalExam=final;
            finalGrade=fGrade;
        };
    dwk

    Seek and ye shall find. quaere et invenies.

    "Simplicity does not precede complexity, but follows it." -- Alan Perlis
    "Testing can only prove the presence of bugs, not their absence." -- Edsger Dijkstra
    "The only real mistake is the one from which we learn nothing." -- John Powell


    Other boards: DaniWeb, TPS
    Unofficial Wiki FAQ: cpwiki.sf.net

    My website: http://dwks.theprogrammingsite.com/
    Projects: codeform, xuni, atlantis, nort, etc.

  12. #12
    Registered User
    Join Date
    Nov 2006
    Posts
    85
    I have to write a program that can input up to 20 students name, exam 1 and 2 grades, homework average, and final exam grade.
    You've only told your program to do 2 students.

  13. #13
    Registered User
    Join Date
    Sep 2007
    Posts
    23
    I only told it to do 2 for now to simplify the testing purpose. When I get it running right then I will change it to 20.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Why don't the tutorials on this site work on my computer?
    By jsrig88 in forum C++ Programming
    Replies: 3
    Last Post: 05-15-2006, 10:39 PM
  2. Problems in getting OpenGL to work
    By zonf in forum C Programming
    Replies: 5
    Last Post: 02-13-2006, 04:48 AM
  3. Why won't my OpenGL work?
    By Raigne in forum C++ Programming
    Replies: 7
    Last Post: 11-26-2005, 11:53 AM
  4. DLL __cdecl doesnt seem to work?
    By Xei in forum C++ Programming
    Replies: 6
    Last Post: 08-21-2002, 04:36 PM