#include <iomanip>
#include <string>
#include <fstream>
#include <cmath>
#include "Utility.h"
using std::ostream;
using std::cout;
using std::cin;
using std::endl;
using std::istream;
using std::string;
using std::setw;
using std::ofstream;
using std::ios;
/*
2 hằng số mặc định của giới hạn trên và dưới
*/
const int LOWER_BOUND = 2,
UPPER_BOUND = 100;
/*
USER_CHOICE sẽ là lựa chọn ghi ra file hoặc xuất ra màn hình
Sử dụng enum chỗ này phản ánh rõ ý nghĩa nội dung của chương trình
*/
enum USER_CHOICE{ WRITE, PRINT };
/*
Khai báo 1 struct PrimeInfo gồm 4 dữ liệu :
lower_range : giới hạn dưới
upper_range : giới hạn trên.
total : tổng số nguyên tố
twins : tổng các số nguyên tố song sinh
*/
struct PrimeInfo
{
int lower_range,
upper_range,
total,
twins;
PrimeInfo( int lr = 0, int ur = 0, int tt = 0, int tw = 0 )
:lower_range( lr ),
upper_range( ur ),
total( tt ),
twins( tw )
{ }
};
/*
------------------------
- Khai báo của các hàm -
------------------------
*/
// #1
void printNameHeader( ostream& out );
// #2
void showProgramInfo( ostream& out );
// #3
void getStartEndValues( int& startNum, int& endNum );
// #4
bool isPrimeNumber( int number );
// #5
void printMessagesInstruction( const char* mess );
// #6
bool changeDefaultRange();
// #7
PrimeInfo generateAndShowsPrimes( int starting, int ending, ostream& out );
// #8
USER_CHOICE writeToFileOrPrintOut();
// #9
void showStatisticOfPrime( std::ostream& out, const PrimeInfo& pr );
// #10
void restoreDefaultColor( std::ostream& out );
// #11
string getOutFileName();
/*
--------------------------
- Định nghĩa của các hàm -
--------------------------
*/
/*
#1 :
In ra thông tin lớp và khóa học
*/
void printNameHeader( ostream& out )
{
out << "\n";
out << "------------------------------------------" << endl;
out << "- Rox Rook -" << endl;
out << "- Program Assignment Lab09 -" << endl;
out << "- CS.M10A Spring 2008 -" << endl;
out << "- Due Date : Thurs.Mar.06 -" << endl;
out << "------------------------------------------" << endl;
}
/*
#2 :
In ra thông tin của chương trình
*/
void showProgramInfo( ostream& out )
{
out << endl;
out << "-------------------------------------------------------" << endl;
out << "- Welcome the Prime Number List Program -" << endl;
out << "- This program will generate the number of Primes -" << endl;
out << "- on the interval given, by default is (2 - 100) -" << endl;
out << "- Also, you can change the range of starting and -" << endl;
out << "- ending value, validate user input included -" << endl;
out << "- Have fun ! -" << endl;
out << "-------------------------------------------------------" << endl;
}
/*
#3 :
Hàm này yêu cầu người dùng nhập vào 2 giá trị của 2 số giới hạn trên
và dưới của các số nguyên tố. Nếu nhập sai chúng ta
sẽ yêu thông báo 1 thông điệp yêu cầu nhập lại
*/
void getStartEndValues( int& start_num, int& end_num )
{
do
{
cout << "Enter the starting and ending value : " << endl;
cin >> start_num >> end_num;
if( start_num > end_num )
{
cout << "...Error dectected !\n";
cout << "Starting value must be less than or equal to ending value.\n\n";
}
if( start_num <= 1 || end_num <= 1 )
{
cout << "...Error dectected !\n";
cout << "Starting value and ending value must strictly greater than 1.\n\n";
}
}
while( start_num <= 1 || end_num <= 1 || start_num > end_num );
}
/*
#4 :
Hàm kiểm tra số nguyên tố
*/
bool isPrimeNumber( int number )
{
if( number == 2 || number == 3 )
return true;
if( number % 2 == 0 || number % 3 == 0 )
return 0;
int variable = 5,
factor = 2,
limit_factor = static_cast< int >(sqrt( static_cast< double >( number ) ) );
while( variable <= limit_factor )
{
if( number % variable == 0 )
return false;
/*
----------------------------------------------------------------------
- Mọi số nguyên tố đều có dạng : -
- + 1 mod( 6 ) -
- + 5 mod( 6 ) -
- Do đó thay vì ta kiểm tra lần lượt các số lẻ bằng cách += 2 -
- ta sẽ tăng các số cần kiểm tra lên theo qui luật sau : -
- +2, +4, +2, +4, +2... -
- Và điều này sẽ giảm 1 số lượng lớn số phần tử cần kiểm tra. -
----------------------------------------------------------------------
*/
variable += factor;
factor = 6 - factor;
}
return true;
}
/*
#5 :
Hàm này in ra các thông báo hướng dẫn người dùng sử dụng chương trình
và màu của chữ trong instruction sẽ là màu đỏ, và ta sẽ dể dàng nhận ra
khi nào là thông điệp sử dụng.
*/
void printMessagesInstruction( ostream& out, const char* mess )
{
out << red << mess << "\n\n";
restoreDefaultColor( out );
}
/*
#6 :
Hàm này hỏi xem người dùng có muốn thay đổi giá trị mặc định của
giới hạn trên và giới hạn dưới hay không.
*/
bool changeDefaultRange()
{
string user_choice;
cout << "The default interval of Prime is "
<< LOWER_BOUND
<< "-"
<< UPPER_BOUND
<< "\n";
cout << "Would you like to change it (y, n) ?\n";
while( true )
{
cin >> user_choice;
if( user_choice[ 0 ] == 'y' || user_choice[ 0 ] == 'Y' )
return true;
if( user_choice[ 0 ] == 'n' || user_choice[ 0 ] == 'N' )
return false;
else
cout << "Invalid answer. Please try again !\n";
}
}
/*
#7 :
Hàm này là hàm 9 của chương trình, các nhiệm vụ của nó bao gồm :
+ Kiểm tra số nguyên tố.
+ Tính tổng các số nguyên tố.
+ Tính các số nguyên tố song sinh.
+ Và ostream& out sẽ hoặc là ghi ra file hoặc là xuất ra màn hình
+ Và giá trị trả về của nó là struct PrimeInfo, và từ đối tượng
này ta có thể tính xuất ra các thông kê về số nguyên tố thông
qua hàm showStatisticOfPrime
*/
PrimeInfo generateAndShowsPrimes( int starting, int ending, std::ostream& out )
{
/*
Các cục bộ chỉ tồn tại trong hàm
*/
int hold_value = 0; // Biến tạm
int total_primes = 0; // Tổng các số nguyên tố
int last_prime = 0; // Số nguyên tố kế trước, dùng để tính số ngyên tố cặp
int twin_prime = 0; // Các số nguyên tố cặp
int format_pos = 0; // Vị trí in xuống dòng
/*
Trường hợp ngoại lệ : 2 là số nguyên tố chẵn duy nhất
*/
if( starting == 2 )
{
total_primes++;
}
/*
Kiểm tra xem số đầu tiên ( starting ) là chẵn hay lẻ
và ta dựa vào đó để tăng biến đếm
*/
if( ( starting %2 ) == 0 )
{
hold_value = starting + 1;
}
else
{
hold_value = starting;
}
/*
Bắt đầu sinh số nguyên tố và in ra
*/
for( int i = hold_value; i <= ending; i += 2 )
{
++format_pos;
/*
Nếu không phải số nguyên tố, giữ nguyên màu
*/
if( !isPrimeNumber( i ) )
{
out << white << setw( 6 ) << i;
}
/*
Nếu là số nguyên tố thì có màu vàng
*/
else
{
out << yellow << setw( 6 ) << i;
total_primes++;
if( ( i <= ending - 2 ) && ( ( i - 2 ) == last_prime ) )
{
twin_prime++;
last_prime = i;
}
}
/*
Cứ 7 số ta sẽ xuống 1 hàng
*/
if( format_pos % 7 == 0 )
out << endl;
}
/*
Trả về 1 struct có với dữ liệu tính toán ở trên
*/
return PrimeInfo( starting, ending, total_primes, twin_prime );
}
/*
#8 :
Hàm này hỏi người dùng xem có muốn ghi ra dữ liệu ra tệp hay
là xuất ra màn hình
*/
USER_CHOICE writeToFileOrPrintOut()
{
string user_choice;
cout << "Would you like to write these content to file or print out ( w, p ) ? \n";
while( true )
{
cin >> user_choice;
if( user_choice[ 0 ] == 'w' || user_choice[ 0 ] == 'W' )
return WRITE;
if( user_choice[ 0 ] == 'p' || user_choice[ 0 ] == 'p' )
return PRINT;
else
cout << "Invalid answer. Please try again !\n";
}
}
/*
#9 :
Hàm này sẽ in ra các thông kê về số nguyên tố của chúng ta
*/
void showStatisticOfPrime( std::ostream& out, const PrimeInfo& pr )
{
out << endl << endl;
out << "There are " << pr.total << " primes between "
<< pr.lower_range << " and " << pr.upper_range << ".\n";
out << "There are " << pr.twins << " twin-primes between "
<< pr.lower_range << " and " << pr.upper_range << ".\n";
}
/*
#10 :
Hàm này sẽ trả về màu mặc định của console( màu trắng ), trong
trường hợp ta đang set các màu khác cho chương trình
*/
void restoreDefaultColor( ostream& out )
{
out << white;
}
/*
#11 :
Hàm này sẽ yêu cầu người dùng nhập vào tên của tệp mà chúng ta
muốn ghi ra
*/
string getOutFileName()
{
std::string fn;
cout << "Enter a file name that you want to write : ";
cin >> fn;
return fn;
}
/*
----------------------
- Chương trình chính -
----------------------
*/
int main()
{
int starting_value = LOWER_BOUND;
int ending_value = UPPER_BOUND;
printNameHeader( cout );
showProgramInfo( cout );
if( changeDefaultRange() == true )
{
getStartEndValues( starting_value, ending_value );
}
/*
Khởi tạo 1 đối tượng PrimeInfo có tên p_i_object
để khi thông tin của Prime
*/
PrimeInfo p_i_object;
/*
Hoặc là ghi ra file, hoặc là xuất thông tin ra màn hình
*/
if( writeToFileOrPrintOut() == PRINT )
{
printMessagesInstruction(
cout,
" ------------------------------ \n" \
" - The entire table of prime - \n" \
" ------------------------------ \n"
);
restoreDefaultColor( cout );
p_i_object = generateAndShowsPrimes( starting_value, ending_value, cout );
showStatisticOfPrime( cout, p_i_object );
}
else
{
ofstream outfile;
string file_name = getOutFileName();
/* Mở tệp */
outfile.open( file_name.c_str(), ios::out );
p_i_object = generateAndShowsPrimes( starting_value, ending_value, outfile );
showStatisticOfPrime( outfile, p_i_object );
printMessagesInstruction(
cout,
"\n...data is writing to file."
);
/* Đóng tệp */
outfile.close();
}
printMessagesInstruction( cout, "\n\n Thanks a lot for your time.\n" );
return 0;
}