Write a C++ program to find kernel in boolean expression - c++

I am a college student, and I have a programming assignment asked us to find kernels in boolean expression. The document teacher provide has a sample pseudo code to guide us how to write a program. The pseudo code is as below.
// Kernel Algorithm
FindKernels(cube-free SOP expression F) // F: input Boolean function
{
K = empty; // K: list of kernel(s)
for(each variable x in F)
{
if(there are at least 2 cubes in F that have variable x)
{
let S = {cubes in F that have variable x in them};
let co = cube that results from intersection of all cubes
in S, this will be the product of just those literals that appear in
each of these cubes in S;
K = K ∪ FindKernels(F / co);
}
}
K = K ∪ F ;
return( K )
}
But I don.t know what is the meaning of the definition of "co". As what I understand S is those terms that have the variable X. Take "abc + abd + bcd = b(ac + ad + cd)" for example, S = {abc, abd, bcd}. But what is co??
I also write another program
#include <iostream>
#include <fstream>
#include <cstdlib>
#include <iomanip>
#include <vector>
#include <string>
#include <algorithm>
using namespace std;
void find_kernels(vector<string> &terms);
bool eliminate_char(string &doing, char eliminate);
void eliminate_char_complete(vector<string> &terms, char eliminate);
int main()
{
string file_name;
vector<string> expression;
vector<string> expression_name;
string expression_temp, expression_name_temp, input_untruncated;
vector<vector<string>> terms;//break each expression into each term
here:
cout << "Please enter the file name that you want to load: ";
cin >> file_name;
ifstream load_file(file_name, ios::in);
if(!load_file)
{
cout << "The file you choose cannot be opened!\n";
goto here;
}
there:
cout << "Please enter the name of the output file: ";
cin >> file_name;
ofstream output_file(file_name, ios::out);
if(!output_file)
{
cout << "The file cannot be created!\n";
goto there;
}
while(load_file >> input_untruncated)
{
expression_name_temp = input_untruncated.substr(0, input_untruncated.find("="));
expression_temp = input_untruncated.substr(input_untruncated.find("=") + 1);
expression_name.push_back(expression_name_temp);
expression.push_back(expression_temp);
}
//start to truncate every terms
for(int i = 0 ; i < (int)expression.size() ; i++)
{
int j = 0;
int k = 0;//k >> last time location
vector<string> terms_temp_vector;
string terms_temp;
string expression_trans = expression[i];
while(j < (int)expression[i].size())
{
if(expression_trans[j] == '+' || expression_trans[j] == '-')
{
terms_temp = expression_trans.substr(k, j - k);
terms_temp_vector.push_back(terms_temp);
k = j + 1;
}
j++;
}
terms_temp = expression_trans.substr(k);
terms_temp_vector.push_back(terms_temp);
terms.push_back(terms_temp_vector);
}
/*for(int i = 0 ; i < (int)expression.size() ; i++)
{
cout << "expression_name: " << expression_name[i] << endl;
cout << expression[i] << endl;
cout << "terms: ";
for(int j = 0 ; j < (int)terms[i].size() ; j++)
{
cout << terms[i][j] << " ";
}
cout << endl;
}*/
cout << endl;
for(int i = 0 ; i < (int)expression.size() ; i++)
{
//output_file << expression_name[i] << endl;
//output_file << expression[i] << endl;
cout << "*";
while(terms[i].size() != 0)
{
find_kernels(terms[i]);
if(terms[i].size() != 0)
{
cout << "terms: ";
for(int j = 0 ; j < (int)terms[i].size() ; j++)
{
cout << terms[i][j] << " ";
}
cout << endl;
}
}
cout << endl;
}
/*for(int i = 0 ; i < (int)expression.size() ; i++)
{
cout << "expression_name: " << expression_name[i] << endl;
cout << expression[i] << endl;
cout << "terms: ";
for(int j = 0 ; j < (int)terms[i].size() ; j++)
{
cout << terms[i][j] << " ";
}
cout << endl;
}*/
return 0;
}
void find_kernels(vector<string> &terms)
{
int a = 0, b = 0, c = 0, d = 0, e = 0, g = 0;
for(int i = 0 ; i < (int)terms.size() ; i++)
{
string terms_temp = terms[i];
for(int j = 0 ; j < (int)terms_temp.size() ; j++)
{
switch(terms_temp[j])
{
case 'a':
a++;
break;
case 'b':
b++;
break;
case 'c':
c++;
break;
case 'd':
d++;
break;
case 'e':
e++;
break;
case 'g':
g++;
break;
}
}
}
int compare[] = {a, b, c, d, e, g};
int biggest = 0;
char eliminate;
for(int i = 0 ; i < 6 ; i++)
{
if(compare[i] > biggest)
{
biggest = compare[i];
}
}
if(biggest == 1)
{
terms.erase(terms.begin(), terms.end());
return;
}
if(biggest == a)
{
eliminate = 'a';
eliminate_char_complete(terms, eliminate);
}
if(biggest == b)
{
eliminate = 'b';
eliminate_char_complete(terms, eliminate);
}
if(biggest == c)
{
eliminate = 'c';
eliminate_char_complete(terms, eliminate);
}
if(biggest == d)
{
eliminate = 'd';
eliminate_char_complete(terms, eliminate);
}
if(biggest == e)
{
eliminate = 'e';
eliminate_char_complete(terms, eliminate);
}
if(biggest == g)
{
eliminate = 'g';
eliminate_char_complete(terms, eliminate);
}
}
bool eliminate_char(string &doing, char eliminate)
{
for(int i = 0 ; i < (int)doing.size() ; i++)
{
if(doing[i] == eliminate)
{
doing.erase (i, 1);
return 1;
}
}
return 0;
}
void eliminate_char_complete(vector<string> &terms, char eliminate)//delete unrelated terms
{
for(int i = 0 ; i < (int)terms.size() ; i++)
{
if(!eliminate_char(terms[i], eliminate))
{
terms.erase(terms.begin() + i);
}
}
}
input file be like
F1=ace+bce+de+g
F2=abc+abd+bcd
I don't obey the pseudo code above.
First, I break them into single terms and push them into a two dimention vector called terms.
terms[expression number][how many terms in one expression]
Second, I call find_kernels. The founction calculate every letters appear how many times in one expression. ps: only a, b, c, d, e, g will appear.
Third, take out the letter that appear the most time. ex: a, ab, abc...
Then, eliminate them in every terms of the same expression. If a terms do not have those letters, then delete the term directly.
Continue doing the same thing....
However, the question is that if F1 is abc+abd+bcd, I should output ac+ad+cd c+d a+c a+d, but my program will output ac+ad+cd only, cause abc+abd+bcd = b(ac+ad+cd) >> next round ac+ad+cd. a, c, d all apear twice, so there are deleted together. Nothing left.
Any suggestion to my code or further explination of the pseudo code will be appreciate. Thank you.

In general you should be clear about the problem you want to solve and the applied definitions. Otherwise you will always run into severe troubles.
Here you want to calculate the kernels of a boolean expression given in SOP (sum over products form, e.g., abc+cde).
A kernel of a boolean expression F is a cube-free expression that results when you divide F by a single cube.
That single cube is called a co-kernel. (This is the co in the pseudo code)
From a cube-free expression you cannot factor out a single cube that leaves behind no remainder.
Examples
F=ae+be+cde+ab
Kernel Co-Kernel
{a,b,cd} e
{e,b} a
{e,cd} b
{ae,be, cde, ab} 1
F=ace+bce+de+g
Kernel Co-Kernel
{a,b} c
{ac, bc, d} e
As you can see the co-kernel is the variable that you eliminate plus all other common variables that occur in the cubes containing the variable.
To implement that you apply this procedure now recursicely for each variable and store all kernel you create. Essentially thats all!
Practically, for an implementation I would propose to use some more handy encoding of the terms and not strings. As your input seems to only single letter variables you can map it to single bits in uint64 (or even uint32 when only lower case is considered). This will give an straight forward implementation like that (thought, it is optimzed for simplicity not performance):
#include <iostream>
#include <vector>
#include <string>
#inlcude <set>
void read_terms();
uint64_t parse_term(string sterm);
void get_kernels(vector<uint64_t>& terms, vector<pair<vector<uint64_t>, uint64_t> >& kernels);
string format_kernel(vector<uint64_t>& kernel);
int main()
{
read_terms();
return 0;
}
/*
Convert a cube into a string
*/
string cube_to_string(uint64_t cube) {
string res;
char ch = 'a';
for (uint64_t curr = 1; curr <= cube && ch <= 'z'; curr <<= 1, ch++) {
if ((curr & cube) == 0) {
continue;
}
res += ch;
}
ch = 'A';
for (uint64_t curr = (1<<26); curr <= cube && ch <= 'Z'; curr <<= 1, ch++) {
if ((curr & cube) == 0) {
continue;
}
res += ch;
}
return res;
}
/*
Convert a kernel or some other SOP expression into into a string
*/
string format_kernel(vector<uint64_t>& kernel) {
string res = "";
for (uint64_t k : kernel) {
string t = cube_to_string(k) + "+";
if (t.size() > 1) {
res += t;
}
}
if (res.size() > 0) {
res.resize(res.size() - 1);
}
return res;
}
/*
Queries the expression from the stdin and triggers the kernel calculcation.
*/
void read_terms() {
cout << "Please enter the terms in SOP form (0 to end input):" << endl;
vector<uint64_t> terms;
vector<pair<vector<uint64_t>, uint64_t> > kernels;
string sterm;
cout << "Term: ";
while (cin >> sterm) {
if (sterm == "0") {
break;
}
cout << "Term: ";
terms.push_back(parse_term(sterm));
}
get_kernels(terms, kernels);
set<string> set_kernels;
for (pair<vector<uint64_t>, uint64_t>k : kernels) {
set_kernels.insert(format_kernel(k.first));
}
for (string k : set_kernels) {
cout << k << endl;
}
return;
}
/*
Convert a term given as string into a bit vector.
*/
uint64_t parse_term(string sterm) {
uint64_t res = 0;
for (char c : sterm) {
if (c >= 'a' && c <= 'z') {
res |= 1ull << uint64_t(c - 'a');
}
else if (c >= 'A' && c <= 'Z') {
res |= 1ull << uint64_t(c - 'A' + 26);
}
}
return res;
}
/*
Returns a bitvector having a for a each variable occuring in one or more of the cubes.
*/
uint64_t get_all_vars(vector<uint64_t>& terms) {
uint64_t res = 0;
for (uint64_t t : terms) {
res |= t;
}
return res;
}
/*
Returns a bitvector having a one for each variable that is shared between all cubes.
*/
uint64_t get_common_vars(vector<uint64_t>& terms) {
if( terms.size() == 0 ) {
return 0ull;
}
uint64_t res = terms[0];
for (uint64_t t : terms) {
res &= t;
}
return res;
}
/*
Divides all set variables from the cubes and returns then in a new vector.
*/
void div_terms(vector<uint64_t>& terms, uint64_t vars, vector<uint64_t>& result) {
result.resize(terms.size());
uint64_t rvars = vars ^ ~0ull; //flip all vars
for (size_t i = 0; i < terms.size(); i++) {
result[i] = terms[i] & rvars;
}
}
/*
Core calculation to get the kernels out of an expression.
*/
void get_kernels(vector<uint64_t>& terms, vector<pair<vector<uint64_t>, uint64_t> >& kernels ) {
uint64_t vars = get_all_vars(terms);
for (uint64_t curr = 1; curr <= vars; curr <<= 1) {
if ((curr & vars) == 0) {
continue;
}
vector<uint64_t> curr_terms, curr_div_terms;
for (uint64_t uterm : terms) {
if ((uterm & curr) != 0ull) {
curr_terms.push_back(uterm);
}
}
if (curr_terms.size() > 1) {
uint64_t new_kernel = 0ull;
uint64_t new_co = get_common_vars(curr_terms); // calculate the new co-kernel
div_terms(curr_terms, new_co, curr_div_terms);//divide cubes with new co-kernel
kernels.push_back(pair<vector<uint64_t>, uint64_t>(curr_div_terms, new_co));
get_kernels(curr_div_terms, kernels);
}
}
}
Especially the elimination of kernels that occur several times is not very efficient, as it just happens at the end. Usually you would do this earlier and prevent multiple calculation.
This implementation takes the inputs from the stdin and writes the results to the stdout. So you might change it for using files when using it as your homework.
Thought other implementations like counting the number of occurences and making use out of that is also possible.

Related

Visual C++ assert- String subscript out of range

My program is a solution for the Day 6 question in Advent of Code 2015. I get an error when I use "Start Without Debugging" and enter the puzzle input in the output window.The image contains the exact error I received. The error is related to "string subscript out of range". I would like help in resolving this error.
const int r = 1000;//global variable
const int c = 1000;//global variable
int lights[r][c];//global array
void instruction(string inp)//extracting OFF, ON, or toggle indication from the instruction
{
int* loc;
int coord[4] = { 0 };
char cond = inp[7];
loc = &coord[3];
switch (cond)
{
case 'f':
coordinates(loc, inp);
execute(coord, cond);
break;
case 'n':
coordinates(loc, inp);
execute(coord, cond);
break;
default:
coordinates(loc, inp);
execute(coord, cond);
break;
}
}
void coordinates(int* loc, string inp)//extracting coordinates from the instruction
{
int i, k = 0, l;
l = inp.length()-1;
for (i = l; inp[i] != ','; i--)
{
*loc += (inp[i]-'0') * pow(10,k);
k++;
}
i--;
loc--;
k = 0;
for (; inp[i] != ' '; i--)
{
*loc += (inp[i]-'0') * pow(10,k);
k++;
}
i = i - 9;
loc--;
k = 0;
for (; inp[i] != ','; i--)
{
*loc += (inp[i]-'0') * pow(10,k);
k++;
}
i--;
loc--;
k = 0;
for (; inp[i] != ' '; i--)
{
*loc += (inp[i]-'0') * pow(10,k);
k++;
}
}
void execute(int coord[], char cond)
{
int i, j;
for (i = coord[0]; i <= coord[2]; i++)
{
for (j = coord[1]; j <= coord[3]; j++)
{
if (cond == 'f')
lights[i][j] &= 0;
else if (cond == 'n')
lights[i][j] |= 1;
else
lights[i][j] = ~lights[i][j];
}
}
}
int main()
{
int i, j, k, count = 0;
string inp;
for (i = 0;;i++)
{
cout << "Enter an instruction" << endl;
cin >> inp;
if (inp != "xx")//To manually move to counting the number of lights turned ON
instruction(inp);
else
{
for (j = 0; j < r; j++)
{
for (k = 0; k < c; k++)
{
if (lights[j][k])
count++;
}
}
cout << endl << "Number of lights lit " << count;
break;
}
}
return 0;
}
The problem is most likely this loop (from the coordinates function):
l = inp.length()-1;
for (i = l; inp[i] != ','; i--)
{
*loc += int(inp[i]) * (10 ^ k);
k++;
}
In the very first iteration of the loop then i will be equal to l which is the length of the string, which is out of bounds.
You also don't check if you go out of bounds in the second direction (i becomes negative). You have this problem in all your loops in the coordinates function.
On another note, casting a character to int will not convert a digit character to its corresponding integer value.
Assuming ASCII encoding (the most common encoding available) then the character '2' (for example) will have the integer value 50.
Also the ^ operator it bitwise exclusive OR, not any kind of "power" or "raises" operator. It seems you could need to spend some more times with some of the basics of C++.

Why does the code below causes Segmentation Fault (SIGSEGV)?

PROBLEM STATEMENT
You are given a strictly increasing sequence of integers A1,A2,…,AN. Your task is to compress this sequence.
The compressed form of this sequence is a sequence of ranges separated by commas (characters ','). A range is either an integer or a pair of integers separated by three dots (the string "..."). When each range a...b in the compressed form is decompressed into the subsequence (a,a+1,…,b), we should obtain the (comma-separated) sequence A again.
For each maximal contiguous subsequence (a,a+1,…,b) of A such that b≥a+2, the compressed form of A must contain the range a...b; if b≤a+1, such a sequence should not be compressed into a range. A contiguous subsequence is maximal if it cannot be extended by at least one element of A next to it. It can be proved that the compressed form of any sequence is unique (i.e. well-defined).
Input
The first line of the input contains a single integer T denoting the number of test cases. The description of T test cases follows.
The first line of each test case contains a single integer N.
The second line contains N space-separated integers A1,A2,…,AN.
Output
For each test case, print a single line containing one string ― the compressed form of the given sequence.
Constraints
1≤T≤100
1≤N≤100
1 ≤ Ai ≤ 1000 for each valid i
A1 < A2 < …... <AN
Subtasks
Subtask #1 (100 points): Original constraints
Example Input
3
12
1 2 3 5 6 8 9 10 11 12 15 17
4
4 5 7 8
1
4
Example Output
1...3,5,6,8...12,15,17
4,5,7,8
4
MY Code:
#include <bits/stdc++.h>
using namespace std;
bool b[1005];
int a[1005];
int main()
{
int test, i, j, size, count;
cin >> test;
while (test--)
{
for (i = 0; i < 1005; i++)
b[i] = false;
cin >> size;
for (i = 0; i < size; i++)
{
cin >> a[i];
b[a[i]] = true;
}
for (i = 0; i < 1005; i++)
{
if (b[i] == true)
{
cout << i;
j = i;
count = 0;
while (b[j] == true)
{
count++;
j++;
}
if (count > 2)
{
i = j;
if ((j - 1) != a[size - 1])
cout << "..." << i - 1 << ",";
else
cout << "..." << i - 1;
}
if (count == 2)
{
i = j;
if ((j - 1) != a[size - 1])
cout << "," << i - 1 << ",";
else
cout << "," << i - 1;
}
if (count == 1 && ((j - 1) != a[size - 1]))
cout << ",";
}
}
}
return 0;
}
}
MY Question:
Above code runs perfectly on my device giving desired output. But when I am submitting this solution to
Online Judge , it says segmentation fault. It's sure that fundamentally I am accessing the memory incorrectly. Could you please show me where it is?
b is defined a bool[1005]
In this part
for(i=0 ; i<4000 ; i++)
b[i] = false;
You are writing false value 4000 times, exceeding the array size.
Overwriting past the array is allowed on the compiler but will have undefined behaviour in runtime.
In short: it can or can not cause a segfault.
Here is another approach given that the input data is in a file input.txt:
#include <fstream>
#include <iostream>
#include <string>
#include <vector>
class Reader {
public:
Reader(const std::string& filename) :
filename_(std::move(filename)), is_(filename_)
{
is_.exceptions( std::ifstream::failbit | std::ifstream::badbit );
}
int get_N() {
int N;
is_ >> N;
return N;
}
std::vector<int> get_ints(int N) {
std::vector<int> v;
v.reserve(N);
for (int i = 0; i < N; i++ ) {
int value;
is_ >> value;
v.push_back(value);
}
return v;
}
int get_num_cases() {
int num_cases;
is_ >> num_cases;
return num_cases;
}
private:
std::string filename_;
std::ifstream is_;
};
bool start_range_cur( std::vector<int> &v, int j, int N )
{
if ( j>= (N - 2) ) return false;
return ((v[j+1] - v[j]) == 1) && ((v[j+2] - v[j+1]) == 1);
}
bool in_range_cur( std::vector<int> &v, int j )
{
return (v[j+1] - v[j]) == 1;
}
void print_range( int min, int max, bool print_comma)
{
std::cout << min << ".." << max;
if (print_comma) std::cout << ",";
}
void print_single(int val, bool print_comma)
{
std::cout << val;
if (print_comma) {
std::cout << ",";
}
}
int main() {
Reader is {"input.txt"};
int num_cases = is.get_num_cases();
for (int i = 0; i < num_cases; i++) {
int N = is.get_N();
std::vector<int> v = is.get_ints(N);
bool in_range = false;
int range_start;
for( int j = 0; j< N; j++ ) {
if (in_range) {
if (j == (N - 1)) {
print_range(range_start, v[j], false);
}
else if (in_range_cur(v, j)) {
continue;
}
else {
print_range(range_start, v[j], true);
in_range = false;
}
}
else {
if (j == (N - 1)) {
print_single(v[j], false);
}
else if (start_range_cur(v, j, N)) {
in_range = true;
range_start = v[j];
}
else {
print_single(v[j], true);
}
}
}
std::cout << '\n';
}
return 0;
}

C++ binary input as a string to a decimal

I am trying to write a code that takes a binary number input as a string and will only accept 1's or 0's if not there should be an error message displayed. Then it should go through a loop digit by digit to convert the binary number as a string to decimal. I cant seem to get it right I have the fact that it will only accept 1's or 0's correct. But then when it gets into the calculations something messes up and I cant seem to get it correct. Currently this is the closest I believe I have to getting it working. could anyone give me a hint or help me with what i am doing wrong?
#include <iostream>
#include <string>
using namespace std;
string a;
int input();
int main()
{
input();
int decimal, x= 0, length, total = 0;
length = a.length();
// atempting to make it put the digits through a formula backwords.
for (int i = length; i >= 0; i--)
{
// Trying to make it only add the 2^x if the number is 1
if (a[i] = '1')
{
//should make total equal to the old total plus 2^x if a[i] = 1
total = total + pow(x,2);
}
//trying to let the power start at 0 and go up each run of the loop
x++;
}
cout << endl << total;
int stop;
cin >> stop;
return 0;
}
int input()
{
int x, x2, count, repeat = 0;
while (repeat == 0)
{
cout << "Enter a string representing a binary number => ";
cin >> a;
count = a.length();
for (x = 0; x < count; x++)
{
if (a[x] != '0' && a[x] != '1')
{
cout << a << " is not a string representing a binary number>" << endl;
repeat = 0;
break;
}
else
repeat = 1;
}
}
return 0;
}
I don't think that pow suits for integer calculation. In this case, you can use shift operator.
a[i] = '1' sets the value of a[i] to '1' and return '1', which is always true.
You shouldn't access a[length], which should be meaningless.
fixed code:
int main()
{
input();
int decimal, x= 0, length, total = 0;
length = a.length();
// atempting to make it put the digits through a formula backwords.
for (int i = length - 1; i >= 0; i--)
{
// Trying to make it only add the 2^x if the number is 1
if (a[i] == '1')
{
//should make total equal to the old total plus 2^x if a[i] = 1
total = total + (1 << x);
}
//trying to let the power start at 0 and go up each run of the loop
x++;
}
cout << endl << total;
int stop;
cin >> stop;
return 0;
}
I would use this approach...
#include <iostream>
using namespace std;
int main()
{
string str{ "10110011" }; // max length can be sizeof(int) X 8
int dec = 0, mask = 1;
for (int i = str.length() - 1; i >= 0; i--) {
if (str[i] == '1') {
dec |= mask;
}
mask <<= 1;
}
cout << "Decimal number is: " << dec;
// system("pause");
return 0;
}
Works for binary strings up to 32 bits. Swap out integer for long to get 64 bits.
#include <iostream>
#include <stdio.h>
#include <string>
using namespace std;
string getBinaryString(int value, unsigned int length, bool reverse) {
string output = string(length, '0');
if (!reverse) {
for (unsigned int i = 0; i < length; i++) {
if ((value & (1 << i)) != 0) {
output[i] = '1';
}
}
}
else {
for (unsigned int i = 0; i < length; i++) {
if ((value & (1 << (length - i - 1))) != 0) {
output[i] = '1';
}
}
}
return output;
}
unsigned long getInteger(const string& input, size_t lsbindex, size_t msbindex) {
unsigned long val = 0;
unsigned int offset = 0;
if (lsbindex > msbindex) {
size_t length = lsbindex - msbindex;
for (size_t i = msbindex; i <= lsbindex; i++, offset++) {
if (input[i] == '1') {
val |= (1 << (length - offset));
}
}
}
else { //lsbindex < msbindex
for (size_t i = lsbindex; i <= msbindex; i++, offset++) {
if (input[i] == '1') {
val |= (1 << offset);
}
}
}
return val;
}
int main() {
int value = 23;
cout << value << ": " << getBinaryString(value, 5, false) << endl;
string str = "01011";
cout << str << ": " << getInteger(str, 1, 3) << endl;
}
I see multiple misstages in your code.
Your for-loop should start at i = length - 1 instead of i = length.
a[i] = '1' sets a[i] to '1' and does not compare it.
pow(x,2) means and not . pow is also not designed for integer operations. Use 2*2*... or 1<<e instead.
Also there are shorter ways to achieve it. Here is a example how I would do it:
std::size_t fromBinaryString(const std::string &str)
{
std::size_t result = 0;
for (std::size_t i = 0; i < str.size(); ++i)
{
// '0' - '0' == 0 and '1' - '0' == 1.
// If you don't want to assume that, you can use if or switch
result = (result << 1) + str[i] - '0';
}
return result;
}

the biggest common divisor of 2 numbers using arrays

How could I find the biggest common divisor of 2 numbers using array? I tried to solve it using 2 arrays and I couldn't finish it. How could I improve this program?
#include <iostream>
using namespace std;
int main()
{
unsigned int A[2][10], B[2][10], a, b, c_exp, d, i1, P, x;
bool apartine = false;
cout << "a="; cin >> a;
cout << "b="; cin >> b;
P = 1;
c_exp = 0;
i1 = 0;
while (a % 2 == 0)
{
c_exp++;
a = a/2;
}
if (c_exp != 0)
{
A[i1][0] = 2;
A[i1][1] = c_exp;
i1++;
}
d = 3;
while (a != 1 && d <= a)
{
c_exp=0;
while (a % d == 0)
{
c_exp++;
a = a/d;
}
if (c_exp!=0)
{
A[i1][0] = d;
A[i1][1] = c_exp;
i1++;
}
d = d+2;
}
cout << "\nMatricea A contine:";
for (int i = 0; i < i1; i++)
{
cout << "\n";
for (int j = 0; j < 2; j++)
cout << A[i][j] << ",";
}
c_exp = 0;
i1 = 0;
while (b % 2 == 0)
{
c_exp++;
b = b/2;
}
if (c_exp != 0)
{
B[i1][0] = 2;
B[i1][1] = c_exp;
i1++;
}
d = 3;
while (b != 1 && d <= b)
{
c_exp = 0;
while (b % d == 0)
{
c_exp++;
b = b/d;
}
if (c_exp != 0)
{
B[i1][0] = d;
B[i1][1] = c_exp;
i1++;
}
d = d+2;
}
cout << "\nMatricea B contine:";
for (int i = 0; i < i1; i++)
{
cout << "\n";
for (int j = 0; j < 2; j++)
cout << B[i][j] << ",";
}
return 0;
}
From now on I have to find if the first number of first array exist in the second array and after this I have to compare the exponents of the same number of both array and the lowest one I have to add it to product. After this I have to repeat the same proccess with the second number to the last one of the first array. The problem is that I don't know how to write this.I have to mention that this program isn't complete.
Any ideas?
If you need better solution then you can avoid array and use the below logic.
int main()
{
int a =12 ,b = 20;
int min = a>b ? a:b; // finding minimum
if(min > 1)
{
for (int i=min/2; i>1; i--)//Reverse loop from min/2 to 1
{
if(a%i==0 && b%i==0)
{
cout<<i;
break;
}
}
}
else if(min == 1)
{
cout<<"GCD is 1";
}
else
cout<<"NO GCD";
return 0;
}
You can also check the working example Greatest Common Divisor
I am not quite sure what you are trying to achieve with your code. It looks over complicated. If I were to find the biggest common divisor of two numbers I would do something like the following:
## This is not a correct implementation in C++ (but close to it) ##
Read the two integers **a** and **b**
int max_div(int a, int b){
int div = a > b ? a : b;
while (div != 1 && (a%div != 0 && b%div != 0)){
div--;
}
return div;
}
This function starts with the minimum of a and b as the highest possible common divisor and then works its way backwards until one of two possible outcomes:
It finds a common divisor (a%div == 0 and b%div == 0)
It reaches one (always a common divisor)
EDIT : Now returns one if no higher divisor is found. (Was returning zero which made no sense)

Optimizing conversion algorithm

I have recently been working on a exercise in a book I have been reading. The task was to create a program that prints all the numbers between 1-256 in their binary, octal and hexadecimal equivalents. We were only supposed to use methods we had learned so far in the book, which meant only using for, while and do..while loops, if and else if statements, converting integers to ASCII equivalents and some more basic stuff (e.g. cmath and iomanip).
So after some work, here is my result. However, it is messy and un-elegant and obfuscated. Does anyone have any suggestions to increase code efficiency (or elegance... :P) and performance?
#include <iostream>
#include <iomanip>
#include <cmath>
using namespace std;
int main()
{
int decimalValue, binaryValue, octalValue, hexadecimalValue, numberOfDigits;
cout << "Decimal\t\tBinary\t\tOctal\t\tHexadecimal\n\n";
for (int i = 1; i <= 256; i++)
{
binaryValue = 0;
octalValue = 0;
hexadecimalValue = 0;
if (i != 0)
{
int x, j, e, c, r = i, tempBinary, powOfTwo, tempOctal, tempDecimal;
for (j = 0; j <=8; j++) //Starts to convert to binary equivalent
{
x = pow(2.0, j);
if (x == i)
{
powOfTwo = 1;
binaryValue = pow(10.0, j);
break;
}
else if (x > i)
{
powOfTwo = 0;
x /= 2;
break;
}
}
if (powOfTwo == 0)
{
for (int k = j-1; k >= 0; k--)
{
if ((r-x)>=0)
{
r -= x;
tempBinary = pow(10.0, k);
x /= 2;
}
else if ((r-x)<0)
{
tempBinary = 0;
x /= 2;
}
binaryValue += tempBinary;
}
} //Finished converting
int counter = ceil(log10(binaryValue+1)); //Starts on octal equivalent
int iter;
if (counter%3 == 0)
{
iter = counter/3;
}
else if (counter%3 != 0)
{
iter = (counter/3)+1;
}
c = binaryValue;
for (int h = 0; h < iter; h++)
{
tempOctal = c%1000;
int count = ceil(log10(tempOctal+1));
tempDecimal = 0;
for (int counterr = 0; counterr < count; counterr++)
{
if (tempOctal%10 != 0)
{
e = pow(2.0, counterr);
tempDecimal += e;
}
tempOctal /= 10;
}
octalValue += (tempDecimal * pow(10.0, h));
c /= 1000;
}//Finished Octal conversion
cout << i << "\t\t" << binaryValue << setw(21-counter) << octalValue << "\t\t";
int c1, tempHex, tempDecimal1, e1, powOf;
char letter;
if (counter%4 == 0)//Hexadecimal equivalent
{
iter = counter/4;
}
else if (counter%4 != 0)
{
iter = (counter/4)+1;
}
c1 = binaryValue;
for (int h = 0, g = iter-1; h < iter; h++, g--)
{
powOf = g*4;
if (h == 0)
{
tempHex = c1 / pow(10.0, powOf);
}
else if (h > 0)
{
tempHex = c1 / pow(10.0, powOf);
tempHex %= 10000;
}
int count = ceil(log10(tempHex+1));
tempDecimal1 = 0;
for (int counterr = 0; counterr < count; counterr++)
{
if (tempHex%10 != 0)
{
e1 = pow(2.0, counterr);
tempDecimal1 += e1;
}
tempHex /= 10;
}
if (tempDecimal1 <= 9)
{
cout << tempDecimal1;
}
else if (tempDecimal1 > 9)
{
cout << char(tempDecimal1+55); //ASCII's numerical value for A is 65. Since 10-15 are supposed to be letters you just add 55
}
}
cout << endl;
}
}
system("pause");
return 0;
}
Any recommendations for improvement will be appreciated.
You have already covered 'iomanip', which infers you've already covered 'iostream'.
If that's the case, have a look at the following:
#include <iostream>
#include <iomanip>
using namespace std;
int x = 250;
cout << dec << x << " "
<< oct << x << " "
<< hex << x << "\n"
<< x << "\n"; // This will still be in HEX
Break out the functions for each output type, then loop through the integer list and output each in turn by calling the function for each different format.
for (int i = 1; i <= 256; ++i)
{
printBin(i);
printHex(i);
printOct(i);
}
Fundamental problem is that a function this long needs refactoring to be more modular. Imagine you are writing the code for someone else to use. How can they call your main? How do they understand what each section of code is doing? They can't. If you make each section of code that has a particular job to do callable as a function then it's easier to understand its intent, and to reuse later.
Have you considered writing a general function that works with any base?
Converting a non-negative number to a generic base is simple... you just need to compute number % base and you get the least significant digit, then divide number by base and repeat to get other digits...
std::string converted_number;
do {
int digit = number % base;
converted_number = digits[digit] + converted_number;
number = number / base;
} while (number != 0);
Once you have a generic conversion function then solving your problem is easy... just call it with base=2, 8 and 16 to get the results you need as strings.
My answer may be a bit tongue in cheek, but
printf ("%u %o %x \n", value, value, value);
will do the trick for the octal and hexadecimal versions ;)
For the binary version, i'd use a flag initialized to 256, and compare it to your number with the AND operator. If true, print a 1, if not, print a 0. Then divide the flag by two. Repeat until the flag is 1.
Pseudocode for the conversion from integer to binary
int flag = 256
do
{
if (flag && value)
print "1"
else
print "0"
flag = flag >> 1 // aka divide by two, if my memory serves well
} while flag > 1
For the octal and hex values, i'm a bit rusty but looking around should guide you to samples you may adapt
Why make it any harder than it really is.
for (int i = 1; i <= 256; ++i)
{
std::cout << std::dec << i << "\t" << std::oct << i << "\t" << std::hex << i << std::endl;
}
Try this
using namespace std;
template <typename T>
inline void ShiftMask(T& mask) {
mask = (mask >> 1) & ~mask;
}
template < typename T >
std::ostream& bin(T& value, std::ostream &o)
{
T mask = 1 << (sizeof(T) * 8 - 1);
while (!(value & mask) && (mask != 0)) ShiftMask(mask);
while (mask) {
o << (value & mask ? '1' : '0');
ShiftMask(mask);
}
return o;
}
int main(void) {
for (int i=0; i<256;i++) {
bin(a, std::cout);
cout << " " << oct << i;
cout << " " << dec << i;
cout << " " << hex << i;
cout << ""
}
}
Maybe something like this?
#include "stdio.h"
int main(){
char Chars[16]= {48,49,50,51,52,53,54,55,56,57,65,66,67,68,69,70};
for(int n = 1;n != 256; n++)
{
{//decimal
printf("%i\t", n);
}
{//Hexadecimal
char L, R;
R = (n & 0x0F) >> 0;
L = (n & 0xF0) >> 4;
printf("%c%c\t", Chars[L], Chars[R]);
}
{//Octal
char L, M, R;
R = (n & 0x07) >> 0;
M = (n & 0x38) >> 3;
L = (n & 0xC0) >> 6;
printf("%c%c%c\t", Chars[L], Chars[M], Chars[R]);
}
{//Binary
char B0, B1, B2, B3, B4, B5, B6, B7;
B0 = (n & 0x01) >> 0;
B1 = (n & 0x02) >> 1;
B2 = (n & 0x04) >> 2;
B3 = (n & 0x08) >> 3;
B4 = (n & 0x10) >> 4;
B5 = (n & 0x20) >> 5;
B6 = (n & 0x40) >> 6;
B7 = (n & 0x80) >> 7;
printf("%c%c%c%c%c%c%c%c\n", Chars[B0], Chars[B1], Chars[B2], Chars[B3], Chars[B4], Chars[B5], Chars[B6], Chars[B7]);
}
printf("256\t100\t400\t100000000\n");
}
}