I am required to develop a program to solve linear equations. The programs
reads first an integer n which is the number of equations.
Then the program reads n lines containing the equations.
For example, the input to the program is like:
3
2x1+3x2+4x3=16
1x1+2x2+1x3=8
3x1+1x2+2x3=13
Any operation should first convert every equation to
the proper form. The equation proper should have the following properties
Variables are ordered alphabetically from left to right:
3x2+2x1+4x3=16
Should be
2x1+3x2+4x3=16
Any variable should appear only once:
4x1+3x2-2x1+4x3=16
Should be
2x1+3x2+4x3=16
Only one constant term should appear in the equation and it should be
on the right hand side:
2x1+3x2+5+4x3-11=10
Should be
2x1+3x2+4x3=16
Coefficient when equals to one or -1 the digit 1 is optional:
1x1+3x2-1x3=10
Can be input as be
x1+3x2-x3=10
What I have done so far is as follows:
#include<iostream>
#include<string>
#include<sstream>
#include<cstdlib>
using namespace std;
int main() {
int n;
cin >> n;
string eqn[100];
//get eq from user
for (int i = 0; i < n; i++) {
cin >> eqn[i];
}
size_t s = 0;
size_t y = 0;
for (int i = 0; i < n; i++) {
for (int x = 1; x <= ((eqn[i].length() - ((eqn[i].length() - 3) / 4)) / 3); x++)
{
int counter = 0;
ostringstream ss;
ss << x;
string j = ss.str();
for (int t = 0; t < eqn[i].length(); t++) {
y = eqn[t].find("x" + j, y + 1);
if (y < eqn[i].length()) { counter++; }
}
for (int o = 1; o <= counter; o++) {
s = eqn[i].find("x" + j, s + 1);
string x1 = eqn[i].substr(s - 1, 3);
string x2 = x2 + x1;
cout << x1;
}
}
cout << endl;
}
int k; cin >> k;
return 0;
}
but things became over complicated, and I am not sure if that is the right approach..
Is there a better way to operate on a string equation other than find(), substr()?
How should I approach the problem?
I started with a Syntax Diagram to define (I wouldn't call it) a language:
Then I translated this into a hand-written parser.
parse-equation.cc:
#include <iostream>
#include <algorithm>
int parseDigit(const char *&la)
{
switch (*la) {
case '0': ++la; return 0;
case '1': ++la; return 1;
case '2': ++la; return 2;
case '3': ++la; return 3;
case '4': ++la; return 4;
case '5': ++la; return 5;
case '6': ++la; return 6;
case '7': ++la; return 7;
case '8': ++la; return 8;
case '9': ++la; return 9;
default: return -1; // ERROR!
}
}
int parseNumber(const char *&la)
{
int value = parseDigit(la);
if (value < 0) return -1; // ERROR!
for (;;) {
const int digit = parseDigit(la);
if (digit < 0) return value;
value *= 10; value += digit;
}
}
struct Term {
int coeff; // -1 ... missing
int expon; // -1 ... missing -> ERROR
Term(int coeff = -1, int expon = 0): coeff(coeff), expon(expon) { }
};
Term parseTerm(const char *&la)
{
Term term;
term.coeff = parseNumber(la);
if (*la == 'x') {
++la;
term.expon = parseDigit(la);
if (term.coeff < 0) term.coeff = 1; // tolerate missing coeff. for x
}
return term;
}
struct Expression {
bool error;
int coeffs[10];
Expression(bool error = false): error(error)
{
std::fill(std::begin(coeffs), std::end(coeffs), 0);
}
};
Expression parseExpression(const char *&la)
{
Expression expr;
int sign = +1;
do {
const Term term = parseTerm(la);
if (term.expon < 0) return Expression(true); // ERROR!
expr.coeffs[term.expon] += sign * term.coeff;
switch (*la) {
case '+': sign = +1; ++la; break;
case '-': sign = -1; ++la; break;
case '=': break;
default: return Expression(true); // ERROR!
}
} while (*la != '=');
++la;
// parse right hand side
const int result = parseNumber(la);
if (result < 0) return Expression(true); // ERROR!
expr.coeffs[0] -= result;
// check for extra chars
switch (*la) {
case '\n': ++la;
case '\0': break;
default: return Expression(true); // ERROR!
}
return expr;
}
std::ostream& operator<<(std::ostream &out, const Expression &expr)
{
if (expr.error) out << "ERROR!";
else {
bool empty = true;
for (size_t i = 9; i; --i) {
const int coeff = expr.coeffs[i];
if (coeff) out << coeff << 'x' << i << std::showpos, empty = false;
}
if (empty) out << 0;
out << std::noshowpos << '=' << -expr.coeffs[0];
}
return out;
}
int main()
{
const char *samples[] = {
"2x1+3x2+4x3=16",
"1x1+2x2+1x3=8",
"3x1+1x2+2x3=13",
"2x1+3x2+5+4x3-11=10",
"x1+3x2-x3=10"
};
enum { nSamples = sizeof samples / sizeof *samples };
for (size_t i = 0; i < nSamples; ++i) {
std::cout << "Parse '" << samples[i] << "'\n";
const char *la = samples[i];
std::cout << "Got " << parseExpression(la) << std::endl;
}
return 0;
}
Compiled with g++ and tested in cygwin:
$ g++ -std=c++11 -o parse-equation parse-equation.cc
$ ./parse-equation
Parse '2x1+3x2+4x3=16'
Got 4x3+3x2+2x1=16
Parse '1x1+2x2+1x3=8'
Got 1x3+2x2+1x1=8
Parse '3x1+1x2+2x3=13'
Got 2x3+1x2+3x1=13
Parse '2x1+3x2+5+4x3-11=10'
Got 4x3+3x2+2x1=16
Parse 'x1+3x2-x3=10'
Got -1x3+3x2+1x1=10
$
Life Demo on Coliru
Note:
Instead of parseDigit() and parseNumber(), std::strtol() could be used. This would reduce the code significantly.
I used const char* for the "read head" la (... abbr. for "look ahead"). The pure C++ way might have been a std::stringstream or a std::string::iterator but, may be, I'm not used enough to these new fancy things. For me, the const char* was the most intuitive way...
The result on right hand side is simply subtracted from the coefficient for x0. So, either the right hand side is 0, or the negative coefficient for x0 becomes right hand side. For my pretty-printing operator<<(), I chose the latter option.
The error handling is rather poor and could be enhanced with more detailed infos about the reason of failed parsing. I left this out to not to "blow" the code even more.
The parser could be enhanced easily to skip white space at any appropriate place. This would improve the convenience.
In the current state, the result on right hand side might not be a negative number. I leave this extension as exercise.
Related
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.
I need following char packet[] = {0x00,0x14}; to send over a TCP/IP, this is the only way I got it to work. With that char I would send the number 20, another possible example would be char packet[] = {0x4e,0x20}; that would be 20000. I am Starting to think that I am approaching this completely wrong.
With this code I can print the Hex value of an Int out.
#include <iostream>
using namespace std;
int main() {
int num, temp, i = 1, j,k=1, r;
char hex[50] = {};
char paket[7] = {'0','x'};
cout << "Input?";
cin >> num;
temp = num;
while (temp != 0) {
r = temp % 16;
if (r < 10)
hex[i++] = r + 48;
else
hex[i++] = r + 55;
temp = temp / 16;
}
cout << i << endl;
cout << "\nHex = ";
for (j = i; j > 0; j--) {
cout << hex[j];
switch (k)
{
case 1:
paket[2] = { hex[j] };
break;
case 2:
paket[3] = { hex[j] };
break;
case 3:
paket[4] = { hex[j] };
break;
case 4:
paket[5] = { hex[j] };
break;
}
k++;
}
cout << endl << paket;
return 0;
This part is how I am trying to get the format I need, but sadly it's not working.
switch (k)
{
case 1:
paket[2] = { hex[j] };
break;
case 2:
paket[3] = { hex[j] };
break;
case 3:
paket[4] = { hex[j] };
break;
case 4:
paket[5] = { hex[j] };
break;
}
k++;
If you just want to convert a number than can be expressed in 16-bits into an array of 2 bytes using network byte order as you imply.
int num = 20000; // or any number for that matter
char packet[2];
packet[0] = (num & 0xff00)>>8; // 0x4E
packet[1] = (num & 0x00ff); // 0x20
Done.
Alternatively, most network programming uses memcpy to byte-pack integers into byte arrays:
uint16_t num = 20000;
char packet[2];
memcpy(packet, &num, 2);
The only problem is that on Little Endian platforms, such as all Intel chips, the above code will write {0x20, 0x4E} into the array. The bytes will be in the wrong order. There's a helper function that swaps those bytes out called htons. The header files to import htons and similar functions vary between OS platform, but is available everywhere.
uint16_t num = 20000;
char packet[2];
num = htons(num); // swaps bytes on little endian, no-op on big-endian
memcpy(packet, &num, 2);
Here is my code. First, I want to say, I have been experimenting, so if you see unnecessary variables here and there, that's why. But the main part of my code is in the function decimal in my class romanType. When I input certain roman numerals, I am not getting the exact numbers I want and it might be in my logic somewhere in my if/else statements.
By the way, to show how I traverse the string - I do it by reverse traversing. I go from the very end of the string to the very beginning of the string, which I think is easier with roman numerals. By the way, I also made an enum type so I could compare the roman numerals seeing which one is lesser, which one is greater etc. Then I used a map to be able to compare the enum values with the char value.
So the problem: For instance, when I type in CCC, I get 290 instead of 300. If you know what is wrong in my logic, I would greatly appreciate that! Thank you.
Furthermore, I am quite new to programming and would greatly appreciate any stylistic tips or anything I can learn about classes etc that I missed in writing this code? Please let me know what is best. Thank you.
#include <iostream>
#include <string>
#include <map>
using namespace std;
class romanType {
string numeral;
int k;
public:
romanType();
void rnumeral (string b) {numeral = b;}
int decimal(string num, char b, int temp) {
num = "";
enum RomanNumerals {I, V, X, L, C, D, M };
map<char, RomanNumerals> m;
m['I'] = I;
m['V'] = V;
m['X'] = X;
m['L'] = L;
m['C'] = C;
m['D'] = D;
m['M'] = M;
RomanNumerals roman1;
RomanNumerals roman2;
cout << "Please type in your roman numeral:" ;
cin >> num;
for (int i =0; i <num.length()-1; i++){
}
for(long i = num.length()-1; i>=0; i--)
{
b = num[i];
if (islower(b)) b=toupper(b);
roman1 = m[num[i]];
roman2 = m[num[i-1]];
switch(b){
case 'I':
if(num[i] == num.length()-1){
temp += 1;
}
break;
case 'V':
if(roman1 > roman2){
temp += 4;
continue;
}
else {
temp += 5;
}
break;
case 'X':
if(roman1 > roman2){
temp += 9;
continue;
}
else {
temp += 10;
}
break;
case 'L' :
if(roman1 > roman2){
temp += 40;
continue;
}
else {
temp += 50;
}
break;
case 'C':
if(roman1 > roman2){
temp += 90;
continue;
}
else {
temp += 100;
}
break;
case 'D' :
if(roman1 > roman2){
temp += 400;
continue;
}
else {
temp += 500;
}
break;
case 'M':
if(roman1 > roman2){
temp += 900;
continue;
}
else {
temp += 1000;
}
break;
}
}
return temp;
}
};
romanType::romanType () {
numeral = "";
}
int main() {
string k = "";
char b = ' ';
int temp = 0;
romanType type;
type.rnumeral(k);
int c = type.decimal(k, b, temp);
cout << c;
return 0;
}
EDIT: _____________________________________________________________________________
I found the solution to my problem. Here is my new code:
#include <iostream>
#include <string>
#include <map>
using namespace std;
string acceptRN();
class romanType {
string numeral;
int temp2;
int l;
// VARIABLES
public:
romanType();
//DEFAULT CONSTRUCTOR
void getRnumeral (string b)
{
numeral = b;
}
//SETTER
void decimal(string num, int temp, char b) {
num = numeral;
enum RomanNumerals {I, V, X, L, C, D, M };
map<char, RomanNumerals> m;
m['I'] = I;
m['V'] = V;
m['X'] = X;
m['L'] = L;
m['C'] = C;
m['D'] = D;
m['M'] = M;
RomanNumerals roman1;
RomanNumerals roman2;
RomanNumerals roman3;
for(long i = num.length()-1; i>=0; i--)
{
b = num[i];
if (islower(b)) b=toupper(b);
roman1 = m[num[i]];
roman2 = m[num[i-1]];
roman3 = m[num[i+1]];
switch(b){
case 'I':
if( roman3 > roman1 && i != num.length()-1){
continue;
}
else {
temp += 1;
break;
}
case 'V':
if(roman1 > roman2 && i != 0){
temp += 4;
continue;
}
else {
temp += 5;
}
break;
case 'X':
if( roman3 > roman1 && i != num.length()-1)
continue;
if(roman1 > roman2 && i!= 0){
temp += 9;
continue;
}
else {
temp += 10;
}
break;
case 'L' :
if(roman1 > roman2 && i!= 0){
temp += 40;
continue;
}
else {
temp += 50;
}
break;
case 'C':
if( roman3 > roman1 && i != num.length()-1)
continue;
if(roman2 == X && i!= 0){
temp += 90;
continue;
}
else {
temp += 100;
}
break;
case 'D' :
if(roman2 == C && i!= 0){
temp += 400;
continue;
}
else {
temp += 500;
}
break;
case 'M':
if(roman2 == C && i!= 0){
temp += 900;
continue;
}
else {
temp += 1000;
}
break;
}
}
temp2 = temp;
}
void showDecimal() {
cout << "Here is your roman numeral in decimal format:";
cout << temp2 << " \n \n \n";
}
};
romanType::romanType () {
numeral = "";
}
int main() {
string k = acceptRN();
int m = 0;
char l= ' ';
romanType type;
type.getRnumeral(k);
type.decimal(k, m, l);
type.showDecimal();
return 0;
}
string acceptRN(){
string num = "";
cout << "Please type in your roman numeral:" ;
cin >> num;
return num;
}
When I done the stuff from my comment and tweaked your code a bit I got this:
//---------------------------------------------------------------------------
int roman_ix[256]={-1};
const int roman_val[]={ 1 , 5 ,10 ,50 ,100,500,1000,0};
const char roman_chr[]={'I','V','X','L','C','D', 'M',0};
//---------------------------------------------------------------------------
int roman2int(char *s)
{
int i,x=0,v=0,v0;
// init table (just once)
if (roman_ix[0]<0)
{
for (i=0;i<256;i++) roman_ix[i]=0;
for (i=0;roman_chr[i];i++) roman_ix[roman_chr[i]]=i;
}
// find end of string
for (i=0;s[i];i++);
// proccess string in reverse
for (i--;i>=0;i--)
{
v0=v; // remember last digit
v=roman_val[roman_ix[s[i]]]; // new digit
if (!v) break; // stop on non supported character
if (v0>v) x-=v; else x+=v; // add or sub
}
return x;
}
//---------------------------------------------------------------------------
I tested on these:
1776 1776 MDCCLXXVI
1954 1954 MCMLIV
1990 1990 MCMXC
2014 2014 MMXIV
300 300 CCC
first number is converted from string, second is what it should be and last is the roman string.
If 256 entry table is too big you can shrink it to range A-Z which is significantly smaller but that require one more substraction in the code. It can be also hardcoded to get rid of the initialization:
//---------------------------------------------------------------------------
int roman2int(char *s)
{
// init
int i,x=0,v=0,v0; // A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
const int val['Z'-'A'+1]={ 0, 0, 100, 500, 0, 0, 0, 0, 1, 0, 0, 50, 1000, 0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 10, 0, 0 };
// find end of string
for (i=0;s[i];i++);
// process string in reverse
for (i--;i>=0;i--)
{
if ((s[i]<'A')||(s[i]>'Z')) break; // stop on non supported character
v0=v; v=val[s[i]-'A'];
if (v0>v) x-=v; else x+=v;
}
return x;
}
//---------------------------------------------------------------------------
As I got rid of your temp and roman1,roman2 and the switch if/else conditions and the code worked from the first compilation ... I am assuming that you are doing something fishy with them (got lost in the if/else combinations missing some edge case).
I have a terrible program in C++ when I try to assign a enum value.
The error exists when I try to assign Wall or Free etc to sokoban.board[j,i].
bool loadLevel(ifstream &stream, tSokoban &sokoban, int level) {
bool ok = false;
string levelStr, levelFile = " ", prove;
int j = 0;
levelStr = "Level " + to_string(level);
while (levelFile != levelStr && EOF) {
getline(stream, levelFile);
}
if (levelFile == levelStr) {
ok = true;
getline(stream, prove);
sokoban.ncol = prove.size();
while (prove != "Level " + to_string(level + 1)) {
for (int i = 0; i < prove.size(); i++) {
switch (prove[i]) {
case '#':
sokoban.board[j, i] = Wall;
break;
case ' ':
sokoban.board[j, i] = Free;
break;
case '$':
sokoban.board[j, i] = Box;
break;
case '.':
sokoban.board[j, i] = GoalFree;
break;
case '#':
sokoban.board[j, i] = Player;
break;
}
}
getline(stream, prove);
j++;
}
sokoban.nrows = j - 1;
}
return ok;
}
It's hard to know where is the problem because these are the declarations:
typedef tTile tBoard[MAX][MAX];
typedef struct {
tBoard board;
int nrows;
int ncol;
int rowPlayer;
int colPlayer;
int numBoxes;
int goalBoxes;
}tSokoban;
typedef struct {
tSokoban sokoban;
int numMoves;
string nFileName;
int level;
}tGame;
And if I write in the code: sokoban.board[j,i] this error dissapeared, could anyone tell me why this error happen?
Sorry about this mess but I don't know how to use properly this task.
The data member
tBoard board;
has the array type tTile[MAX][MAX] due to the typedef
typedef tTile tBoard[MAX][MAX];
So to access an element of the two-dimensional array you should use the postfix expression like
sokoban.board[j][i] = Wall;
where the expression sokoban.board[j][i] yields an lvalue of type tTile.
As for this expression
sokoban.board[j, i] = Wall;
then there is used the comma operator in the square braces. In fact it is equivalent to
sokoban.board[i] = Wall;
The expression sokoban.board[i] has the one-dimensional array type tTile[MAX] (see the typedef above) and is not a modifiable lvalue.
I was trying to make a calculator with infinite inputs which I kinda did but I have a problem...
#include <iostream>
using namespace std;
int main()
{
double a, b, c, sum = 0.0;
char op;
cout << sum;
while (op != '=')
{
cin >> op >> a;
switch(op)
{
case '+':
sum = sum+a;
cout << sum;
break;
case '-':
sum = sum-a;
cout << sum;
break;
case '/':
sum = sum/a;
cout << sum;
break;
case '*':
sum= sum*a;
cout << sum;
break;
case '=':
cout << sum;
break;
}
}
return 0;
}
To finish the first calculation you need to type not only the operator but also an int. So it would look something like this:
0+3
3=[random int]
sum
I would like to get rid of the [random int] to finish.
Thanks in advance.
#Some programmer dude is completely correct. A proper parser is the only reliable way to go. Below is an example of a brittle , that is to say 'easily broken', parser for the kind of input I think you're expecting. Cleverer people than I could probably write it better. Note the required error checking and assumptions within the code.
I've also taken the liberty to clean up your original main() a small bit.
Hope this inspires you to learn boost::spirit or any of the excellent C++ parsers out there.
using namespace std;
bool
get_input_from_cin(char & op, double & d)
{
static const char * OPERATORS="+-/*=";
char lc ='\0';
char d_buffer[64]; // where we'll store the number
size_t d_buffer_counter = 0;
memset(d_buffer,'\0',sizeof(d_buffer)); // initialize it to nulls
for (char lc = ' '; lc != '\n'; cin.get(lc))
{ // loop gathering characters until you get a newline.
if ( strchr(OPERATORS,lc) != nullptr)
{ // if we're expecting an operator and we find it then save it
op = lc; // what happens if we get more than one operator before a new line?
}
else if ( ' ' == lc )
{
; // No Operation : consume spaces with no action
}
else
{ // we assume a double, save the digits. Check they are digits using isdigit(..) or some call.
d_buffer[d_buffer_counter++] = lc;
if ( d_buffer_counter == sizeof(d_buffer) )
{ // issue a warning in here somehow
return false;
}
}
}
if ( '\0' == op )
{ // no operator included!
return false;
}
if ( '\0' == d_buffer[0] )
{ // no number included!
return false;
}
d = atof(d_buffer);
return true;
}
int main()
{
double a = 0.0, sum = 0.0; // you're not using b or c, better not to declare them
char op;
cout << sum;
op = '\0'; // initialize
while (op != '=')
{
if (false == get_input_from_cin(op, a))
{
if ('=' == op)
{
cout << sum;
return 0;
}
cerr << "Input parse error." << endl;
return -1;
}
switch (op)
{
case '+':
sum = sum + a;
cout << sum;
break;
case '-':
sum = sum - a;
cout << sum;
break;
case '/':
sum = sum / a;
cout << sum;
break;
case '*':
sum = sum*a;
cout << sum;
break;
case '=':
cout << sum;
break;
}
}
return 0;
}
This is how you store an entire line in a string (you must #include<string>)
string line;
getline(cin, line);
string op;
string a;
Then you can get the data from the string:
if(string.length > 1)
{
op = line.substr(0,1);
a = line.substr(1,string.length);
}
else op = line.substr(0,1)
Then you convert the op to char:
char chOp = line[0];
Convert the string a to int:
int intA = std::stoi(a);