calculate molecular weight

i cant figure out why that my program is not correctly calculating the molecular weight of atoms. it may be in line 89 where it just gives me what is in there for the molecular weight answer. any help would be appriceated
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
#include <cctype>      // Provides toupper
#include <cstdlib>     // Provides EXIT_SUCCESS and size_t
#include <iostream>    // Provides cin, cout
#include "table.h"    // Provides the table class
#include <fstream>
#include <cstring>    // Provides strchr
#include <string>
#include <sstream>

using namespace std;

void read_in_table(table& hash_table, string line_input);
double get_total_weight(table& hash_table, string line_input, int i);

int main()
{
	string line_input;
	table hash_table;
	char dataFileName[] = "PeriodicTableElements.txt";

	// I've got the file name, now try to open the file for reading
	ifstream fileData;
	fileData.open(dataFileName, 0);
	if (fileData.good() == false)
	{
		cout << "ERROR: can't open data file: " << dataFileName << endl;

		// wait for the user to press enter to quit
		cout << endl << "Press the [Enter] key to quit...";
		getchar();
		return -1;
	}

	char dataFileName1[] = "formulas.txt";

	// I've got the file name, now try to open the file for reading
	ifstream fileData1;
	fileData1.open(dataFileName1, 0);
	if (fileData1.good() == false)
	{
		cout << "ERROR: can't open data file: " << dataFileName1 << endl;

		// wait for the user to press enter to quit
		cout << endl << "Press the [Enter] key to quit...";
		getchar();
		return -1;
	}


	// I've got the data file open.
	// read and use the data
	string hash;
	while (getline(fileData, hash))
	{
		cout  << "" << hash << endl;	
		cout << endl;
	}
	fileData1.close();
	fileData1.open(dataFileName1, 0);
	while (getline(fileData1, hash))
	{
		cout << hash << endl;
		getline(fileData, line_input, '\n');
		double total_weight = get_total_weight(hash_table, line_input, 0);
		cout << line_input << "=" << " " << total_weight << endl;
	}

	fileData.close();
	cout << endl << "Press the [Enter] key to quit...";
	getchar();
}

void read_in_table(table& hash_table, string line_input)
{
	double weight;
	int i = 0;
	while (line_input[i] != ' ')
		++i;
	string element = line_input.substr(0, i);
	int element_number = element[0] - 0;
	int weight_length = line_input.size() - i;
	string weight_string = line_input.substr(i, weight_length);
	istringstream convert(weight_string);
	if (!(convert >> weight))
		weight = 0;
}
double get_total_weight(table& hash_table, string line_input, int i)
{
	int j;
	int multiplier;
	double total_weight = 0.0;
	double weight;
	while (line_input[i] != '\0')
	{
		j = i;
		if (line_input[i] == '(')
		{
			++i;
			int k = i;
			while (line_input[k + 1] != ')')
				k++;
			string line_help = line_input.substr(i, k - i + 1);
			weight = get_total_weight(hash_table, line_help, 0);
			i = k + 2;
			if (line_input[i] == '\0')
				total_weight = total_weight + weight * 1;
		}
		else
		{
			while (islower(line_input[i + 1]))
				i++;
			int k = i - j + 1;
			string element = line_input.substr(j, k);
			double element_number = element[0] - 0;
			weight = hash_table.retrieve(element_number, element);
			++i;
			if (!(isdigit(line_input[i])))
				total_weight = total_weight + weight * 1;
		}
		j = i;
		while (isdigit(line_input[i]))
			i++;
		int k = i - j;
		string line_input_passer = line_input.substr(j, k);
		istringstream convert(line_input_passer);
		if (!(convert >> multiplier)) //give the value to weight using the characters in the stream
			multiplier = 0;
		total_weight = total_weight + weight * multiplier;
	}
	return total_weight;
}
//table.cpp
#include "table.h"
#include <iostream>

table::table()
{
	for (int i = 0; i < SIZE; i++)
	{
		array[i] = new node(-1, "");
	}
}

void table::decon_help(node * n)
{
	if (n->next != NULL)
	{
		decon_help(n->next);
	}
	delete n;
	return;
}

table::~table()
{
	for (int i = 0; i < SIZE; i++)
	{
		if (array[i]->next != NULL)
		{
			decon_help(array[i]->next);
		}
		delete array[i];
	}
}

void table::insert(string passed_ele, double passed_weight, double key)
{
	int index = hash(key);
	if (array[index]->data == -1 || array[index]->data == -2)
	{
		array[index]->data = passed_weight;
		array[index]->element = passed_ele;
	}
	else
	{
		insert(array[index]->next, passed_ele, passed_weight);
	}
}

void table::insert(node *& n, string passed_ele, double passed_weight)
{
	if (n == NULL)
	{
		n = new node(passed_weight, passed_ele);
	}
	else
	{
		insert(n->next, passed_ele, passed_weight);
	}
}

double table::retrieve(double d, string element)
{
	int index = hash(d);
	if (array[index]->element == element)
	{
		return array[index]->data;
	}
	else
	{
		return retrieve(d, element, array[index]->next);
	}
}

double table::retrieve(double d, string element, node * n)
{
	if (n->element == element)
	{
		return n->data;
	}
	return retrieve(d, element, n->next);
}

int table::hash(double d)
{
	int ret = (int)(d / .05555) % SIZE;
	return ret;
}
//table.h

#pragma once
#include <cstdlib>    // Provides size_t
#include <string>
using namespace std;
struct node
{
	double data;
	string element;
	node* next;
	node(double d, string ele)
	{
		data = d;
		element = ele;
		next = NULL;
	}
};
const int SIZE = 50;
class table
{
	node* array[SIZE];
public:
	//constructor
	//pre:none
	//post: creates array of nodes of size 50 and initialized each value to -1
	table();
	//deconstructor
	//deletes all dynamic memory
	~table();
	//helps to delete dynamic alloc memory
	void decon_help(node* n);
	//inserts an element from periodic table into a hash table
	void insert(string, double, double);
	//inserts an element from periodic table into hash table when there is a collision
	void insert(node*& n, string passed_ele, double passed_weight);
	//returns the value for the element
	double retrieve(double d, string element);
	//returns value for element when there is a collision
	double retrieve(double d, string element, node* n);
	//hash function to spread out the entries
	int hash(double);
	//overload the [] brackets
	table operator[](int);
	//Clear (remove all from hash table)
	void clear(node* array[]) { table::~table(); }

};
Last edited on
here is the formulas.txt
H2SO4
Al2(SO4)3
H2O
CH4
C6H12O6
(CH3)3
C3H7
AuI3
Bi2O3
Ga(C2H3O2)3
Cu3(PO4)2
In(OH)3
Li(AlSi2O6)
Sb2OS2

here is the PeriodicTableElements.txt
1 H 1.008
2 He 4.0026
3 Li 6.94
4 Be 9.0122
5 B 10.81
6 C 12.011
7 N 14.007
8 O 15.999
9 F 18.998
10 Ne 20.180
11 Na 22.990
12 Mg 24.305
13 Al 26.982
14 Si 28.085
15 P 30.974
16 S 32.06
17 Cl 35.45
18 Ar 39.948
19 K 39.098
20 Ca 40.078
21 Sc 44.956
22 Ti 47.867
23 V 50.942
24 Cr 51.996
25 Mn 54.938
26 Fe 55.845
27 Co 58.933
28 Ni 58.693
29 Cu 63.546
30 Zn 65.38
31 Ga 69.723
32 Ge 72.63
33 As 74.922
34 Se 78.96
35 Br 79.904
36 Kr 83.798
37 Rb 85.468
38 Sr 87.62
39 Y 88.906
40 Zr 91.224
41 Nb 92.906
42 Mo 95.96
43 Tc 97.91
44 Ru 101.07
45 Rh 102.91
46 Pd 106.42
47 Ag 107.87
48 Cd 112.41
49 In 114.82
50 Sn 118.71
51 Sb 121.76
52 Te 127.60
53 I 126.90
54 Xe 131.29
55 Cs 132.91
56 Ba 137.33
57 La 138.91
58 Ce 140.12
59 Pr 140.91
60 Nd 144.24
61 Pm 144.91
62 Sm 150.36
63 Eu 151.96
64 Gd 157.25
65 Tb 158.92
66 Dy 162.50
67 Ho 164.93
68 Er 167.26
69 Tm 168.93
70 Yb 173.05
71 Lu 174.97
72 Hf 178.49
73 Ta 180.95
74 W 183.84
75 Re 186.21
76 Os 190.23
77 Ir 192.22
78 Pt 195.08
79 Au 196.97
80 Hg 200.59
81 Tl 204.38
82 Pb 207.20
83 Bi 208.98
84 Po 208.98
85 At 209.99
86 Rn 222.02
87 Fr 223.02
88 Ra 226.03
89 Ac 22.03
90 Th 232.04
91 Pa 231.04
92 U 238.03
93 Np 237.05
94 Pu 244.06
95 Am 243.06
96 Cm 247.07
97 Bk 247.07
98 Cf 251.08
99 Es 252.08
100 Fm 257.10
101 Md 258.10
102 No 259.10
103 Lr 262.11
104 Rf 265.12
105 Db 268.13
106 Sg 271.13
107 Bh 270.00
108 Hs 277.15
109 Mt 276.15
110 Ds 281.16
111 Rg 280.16
112 Cn 285.17
113 Uut 284.18
114 Fl 289.19
115 Uup 288.19
116 Lv 293
117 Uus 294
118 Uuo 294
Last edited on
closed account (NCRLwA7f)
I'm no expert but after running your code on my machine, it looks like when you get to line 91, the while loop, string line_input looks to always be empty so the while loop is just skipped every time.
what would you suggest i do in order to fix this?
closed account (NCRLwA7f)
Once again, I'm by far a novice too. I actually did a similar program for one of my classes a while back. It took the formula, for example, H2O and calculated what the molecular weight was by adding two hydrogens and one oxygen to calculate total weight. Anyway, when you did the while loop back on line 53:
1
2
3
4
5
6
7
  
while (getline(fileData, hash))
	{
		cout << hash << endl;	
		cout << endl;
	}
 


you read the data in fileData all the way to the end. So when you tried to read the file again in line 61: getline(fileData, line_input, '\n'); the file was already at the end so you did not bring in any more data. One quick (maybe not the best fix) fix you can do is just close and reopen the file after the while loop on line 53
1
2
3
4
5
6
7
8
9
while (getline(fileData, hash))
	{
		cout << hash << endl;	
		cout << endl;
	}

        fileData.close();
	fileData.open(dataFileName, 0);


this will reset the file for reading again.....now this brings us to the next issue.
once the loop gets going the program fails on line 113
weight = hash_table.retrieve(element_number, element);

maybe you can figure it out, otherwise maybe some more comments or explanation on how you are wanting that area of your code to work. Since I am also a student, the code can be a little difficult to follow.
Last edited on
i am doing the same kind of homework that you were.
this is what i want it to do:
Example: H2O
First look at the ‘H’ -> retrieve the weight in the hash table
Look at the ‘2’ multiply the previous weight by 2
Look at the O -> retrieve the weight stored for ‘O’
Add this weight to the previous total
so the result should be something like this H2S04 molar mass is 98.079.
if this does not make much sense then please let me know
closed account (NCRLwA7f)
I can send you my program so you can take a look at it if you like, to see if it helps you with yours, just turn on your private message.
i have my private message turned on now
Your 'table' is dandy, but is that part of the "have to do myself to learn"?
There is already std::map for that.


The different challenge is to parse a formula into its components.
How complex can the formulas get? The samples are rather simple.
For some ideas: https://stackoverflow.com/questions/2974362/parsing-a-chemical-formula
closed account (NCRLwA7f)
Bump....still needing help
This looked like a fun problem. I used a regex to remove/expand parentheses and then delegate actual calculation work to another method. This other method, expanded_mass, *verrrrrrry* carefully looks ahead to see if two-character strings are found in the map, of the form Mg, otherwise it sticks with single-character strings like H. Similarly, it checks for 1-2 numbers following this string. I used a limited version of what you wrote. I didn't care to support the stupid three-char elements like Uup, lol.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
#include <iostream>
#include <sstream>
#include <map>
#include <regex>

using namespace std;

// Repeats an input string n times 
string repeat(string s, int n)
{
    ostringstream oss;
    for(int x=1; x<=n; ++x)
        oss << s;
    return oss.str();
}

// Calculates mass from a string not containing parentheses
float expanded_mass(const map<string,float>& m, string& formula)
{
    float sum = 0.0f;
    string one_s, two_s;
    int multiplier;
  
    // Finding correct token, preferring two chars
    //cout <<"[DEBUG] entering expanded_mass\n";
    for (int i=0; i<formula.size(); ++i)
    {
        one_s = formula.substr(i,1);
        two_s = formula.substr(i,2);
        //cout <<"[DEBUG]   one_s is \""<< one_s <<"\"; two_s is \""<<two_s<<"\"\n";  
        if (two_s == one_s)
        {
            // we're at the end
            try
            {
                sum += m.at(one_s);
            }
            catch (std::out_of_range& ex)
            {
                cout << "[39]Couldn't find \""<<one_s<<"\" in the map\n";
            }
            break;
        }

        // Valid two-character symbol
        if (m.count(two_s) != 0)
        {
            // Check third char for a number, as in Mg2
            multiplier = 1;
            if (i+2 < formula.size())
            {
                char third = formula[i+2];
                if (isdigit(third))
                {
                    // Check fourth char for another number, as in Mg12
                    if (i+3 < formula.size())
                    {
                        char fourth = formula[i+3];
                        if (isdigit(fourth))
                        {
                            multiplier = (third-'0')*10 + (fourth-'0');
                            sum += m.at(two_s)*multiplier;
                            i+=3;
                            continue;
                        }
                    }
                    multiplier = third - '0';
                    sum += m.at(two_s)*multiplier;
                    i+=2;
                    continue;
                }
                else 
                {
                    // Third is just another element
                    sum += m.at(two_s);
                    i+=1;
                    continue;
                }
            }
            else
            {
                sum += m.at(two_s);
                break;
            }
        }
        // Valid single-char symbol
        else if (m.count(one_s) != 0)
        {
            // Check second char for a number, as in H2
            multiplier = 1;
            if (i+1 < formula.size())
            {
                char second = formula[i+1];
                if (isdigit(second))
                {
                    // Check third char for another number, as in H12
                    if (i+2 < formula.size())
                    {
                        char third = formula[i+2];
                        if (isdigit(third))
                        {
                            multiplier = (second-'0')*10 + (third-'0');
                            sum += m.at(one_s)*multiplier;
                            i+=2;
                            continue;
                        }
                    }
                    multiplier = second - '0';
                    sum += m.at(one_s)*multiplier;
                    i+=1;
                    continue;
                } 
                else
                {
                    // Second is just another element
                    sum += m.at(one_s);
                    continue;
                }
            }
        }
    } // End of for
    
    //cout <<"[DEBUG]   returning sum of \""<< sum <<"\"\n";  
    return sum;
}

float calc_mass(const map<string,float>& m, string formula)
{
    // This is the regex (\(([A-Za-z\d]+)\)(\d+)) with raw wrappings, 
    //  Group 1: fully matched expression, e.g. (OH)6, for substitution size
    //  Group 2: inside the parenthesis, e.g. OH
    //  Group 3: count, e.g. 6 
    // Test at http://regex101.com/ 
    
    regex parens( R"((\(([A-Za-z\d]+)\)(\d+)))" );
    smatch parens_matches;
    size_t start_pos;
    ostringstream oss;
    string full_expression, inside;
    size_t len;
    int multiplier;
    string expansions;
    
    while (regex_search(formula, parens_matches, parens))
    {
        full_expression = parens_matches[1];
        start_pos = parens_matches.position(0);
        len = full_expression.length();
        inside = parens_matches[2];
        multiplier = stoi(parens_matches[3]);
        
        formula.replace(start_pos, len, "");
        expansions += repeat(inside, multiplier);
    }
    //cout << "[DEBUG] expansions is '" <<expansions << "'\n";
    //cout << "[DEBUG] formula after expansions: '" << formula << "'\n";
    
    return expanded_mass(m, formula) + expanded_mass(m, expansions);
}

int main() 
{
    const char* periodic_mass_text = R"LITERAL(
H 1.008
He 4.0026
Li 6.94
Be 9.0122
B 10.81
C 12.011
N 14.007
O 15.999
F 18.998
Ne 20.180
Na 22.990
Mg 24.305
Al 26.982
Si 28.085
P 30.974
S 32.06
Cl 35.45
Ar 39.948
K 39.098
Ca 40.078
)LITERAL";
  
    const char* formulas_text = R"LITERAL(
H2SO4
Al2(SO4)3
H2O
CH4
C6H12O6
C6(H)12O6
(C1H2)6O6
(CH2)6O6
(C)6(H)12(O)6
(CH3)3
C3H7
)LITERAL";

#if 0 // Simple example
  const char* formulas_text = R"LITERAL(
(C)6H12(O)6
)LITERAL";
#endif

    // Imitate file stream
    istringstream iss(periodic_mass_text);
    
    string element;
    float mass;
    map<string, float> hash;
    
    while (iss >> element >> mass)
    {
        hash[element] = mass;
    }
    
    cout << "Elements in table:\n";
    for (auto const& entry : hash)
    {
        cout << entry.first << ": " << entry.second << endl;
    }
    
    cout << "...done\n\n";
    
    iss.clear();
    iss.str(formulas_text);
    
    string formula;
    float total;
    cout << "Mass of formulas:\n";
    while (iss >> formula)
    {
        total = calc_mass(hash, formula);
        cout << formula << " is " << total << "g" << endl;
    }
    return 0;
}

In action: https://repl.it/repls/DimTestyAdaware
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
#include <iostream>
#include <fstream>
#include <iomanip>
#include <cctype>
#include <string>
#include <map>
#include <vector>
using namespace std;

map<string,double> RAM;                               // Relative Atomic Mass

//======================================================================

void readWeights()                                    // Read and map relative atomic masses
{
   int atomicNumber;
   string element;
   double ram;

   ifstream in( "PeriodicTableElements.txt" );
   while ( in >> atomicNumber >> element >> ram ) RAM[element] = ram;
   in.close();
}

//======================================================================

vector<string> tokenise( string molecule )            // Break at either opening bracket or upper-case letter
{
   vector<string> parts;
   string s;
   for ( char c : molecule ) if ( c != ' ' ) s += c;  // Remove blanks

   int p = 0, q = 1;                                  // Unit is [p,q)
   if ( s[0] == '(' ) q = s.find( q, ')' );
   while ( p < s.size() )
   {
      while ( q < s.size() && !isupper( s[q] ) && s[q] != '(' ) q++;
      parts.push_back( s.substr( p, q - p ) );
      p = q;
      if ( q < s.size() && s[q] == '(' ) q = s.find( q, ')' );
      else                               q++;
   }
   return parts;
}

//======================================================================

double weight( string molecule )
{                                   
   double wt = 0.0;
   int pos;

   vector<string> parts = tokenise( molecule );       // Split into units

   for ( string s : parts )
   {
      int valency = 1;
      if ( s[0] == '(' )                              // Subgroup
      {
         pos = s.find( ')' );
         string group = s.substr( 1, pos - 1 );
         if ( pos < s.size() - 1 ) valency = stoi( s.substr( pos + 1, s.size() - pos - 1 ) );
         wt += weight( group ) * valency;             // Recursive call
      }
      else                                            // Element
      {
         string element;
         pos = s.find_first_of( "123456789" );
         if ( pos == string::npos ) 
         {
            element = s;
         }
         else
         {
            element = s.substr( 0, pos );
            valency = stoi( s.substr( pos, s.size() - pos ) );
         }

         if ( !RAM.count( element ) )
         {
            cout << "ERROR: " << element << " not recognised\n";
            return 0.0;
         }

         wt += RAM[element] * valency;
      }
   }

   return wt;
}

//======================================================================

int main()
{                                   
   string molecule;

   readWeights();

   ifstream in( "formulas.txt" );
   while ( getline( in, molecule ) ) cout << setw( 20 ) << left << molecule << setw( 10 ) << weight( molecule ) << '\n';
   in.close();
}

//====================================================================== 

H2SO4               98.072    
Al2(SO4)3           342.132   
H2O                 18.015    
CH4                 16.043    
C6H12O6             180.156   
(CH3)3              45.105    
C3H7                43.089    
AuI3                577.67    
Bi2O3               465.957   
Ga(C2H3O2)3         246.855   
Cu3(PO4)2           380.578   
In(OH)3             165.841   
Li(AlSi2O6)         186.086   
Sb2OS2              323.639 


Some of those molecules aren't plausible.
Last edited on
Topic archived. No new replies allowed.