Condensing functions to go two ways in C++ - c++

Apparently, I should be able to condense these six functions into three simpler functions that go two ways, using bool logic, but I have no idea where to start!
void footToMeter(int inputfeet) {
double outputMeter = ((inputfeet) / (3.281));
cout << outputMeter;
}
void meterToFoot(int inputmeter) {
double outputFoot = ((inputmeter)*(3.281));
cout << outputFoot;
}
void CtoF(int inputC) {
double outputF = 32 + (inputC*(9.0 / 5.0));
cout << outputF;
}
void FtoC(int inputF) {
double outputC = (5.0 / 9)*(inputF - 32);
cout << outputC;
}
void cMtocF(int inputcM) {
double outputcF = ((inputcM)*(35.315));
cout << outputcF;
}
void cFtocM(int inputcF) {
double outputcM = ((inputcF) / (35.315));
cout << outputcM;
}

One approach would be to add an extra parameter for each function to determine which direction you want to convert.
Example:
void lengthConversion(int inputLength, bool toFeet)
{
double output;
if (toFeet)
output = inputLength * 3.281;
else
output = inputLength / 3.281
cout << output;
}
#forthe has a point though - enum would make it a bit nicer.

To make it into 3 simpler functions. First try and bundle up the similarities between the current functions:
// Put the foot to meter and meter to foot functions into one, with 2 extra boolean values.
void fAndMConversion(int measurement , bool footToMeter , bool meterToFoot) {
if(footToMeter){
double fTm = ((measurement) / (3.281));
cout << fTm;
}
if(meterToFoot){
double mTf = ((measurement)*(3.281));
cout << mTf;
}
}
These are the first two functions. This also allows us to get foot to meter and meter to foot conversion in one call to the function: fAndMConversion(11 , true , true). You can bundle it up even further into a conversions() function with 7 args in total, 6 being booleans.

Related

CPP: why is dereferencing a pointer to a template type not populating a variable?

I do a lot of modeling and simulation and I am writing a sim_logger in CPP. The basics of it are this: a user constructs the class with a logging frequency and an output path. They can then "register" any number of variables which gives the logger a reference to the desired variable (its not incredibly safe right now but I'll work on that later, focused on the issue at hand). I've created a template type called "variable" which contains three things, T *var, T last_val, and string ID. My problem is this, whenever I set the last_val equivalent to the var, the last_val inside the variable does not actually change. I am setting this value in line 180 of sim_logger.h. I feel like this is a silly problem, probably due to some misunderstanding I have of pointers. However, I've tried several different things and cannot seem to solve this problem.
sim_logger.h
#include <iostream>
#include <iomanip>
#include <fstream>
#include <vector>
#include <variant>
#include <type_traits>
#include <math.h>
pragma once
// a class to log simulation data
// specifically for logging time dependent differential functions
class sim_logger
{
private:
// a type that represents a variable
/*
meant to contain anything, but limited by the variadic type
"poly_var_types" below
*/
template <typename T>
struct variable
{
T *var; // pointer to the variable itself
T last_val; // the last value of the variable
std::string ident; // the identity of the variable
};
// a variadic type
template <typename ... T>
using poly_var_types = std::variant<T...>;
// defined variable types
// these are the typical types that are logged, feel free to add more
using var_types = poly_var_types<
variable<double>,
variable<float>
// variable<int>,
// variable<bool>,
// variable<std::string>
>;
// class members
std::vector<var_types> registered_variables; // container of all variables
std::ofstream file; // output file stream
double dt; // the logging time step in seconds
double clock = 0.0; // the logging clock in seconds
double last_sim_time = clock; // the last sim time for interp
bool is_time_to_log = false; // flag for log function
const double EPSILON = 0.000000001; // rounding error
// a linear interpolation method
// only returns floating point values
double lin_interp(double x, double x1, double x2, double y1, double y2)
{
return (y1+(x-x1)*((y2-y1)/(x2-x1)));
}
public:
// constructor which sets the logging frequency and output path
// log_dt is a floating point value in units of seconds
// path_to_file is a string representation of the desired output path
sim_logger(double log_dt, std::string path_to_file)
{
dt = log_dt;
file.open(path_to_file);
file << std::setprecision(16) << std::fixed;
}
// method to register a variable with the logger
template <typename T>
void register_variable(std::string ident, T *aVar)
{
variable<T> v;
v.ident = ident;
v.var = aVar;
registered_variables.push_back(v);
};
// a method to write the log file header and log sim time 0.0 data
void write_header_and_log_init_data()
{
// write header
file << "sim_time" << " ";
for (int i = 0; i < registered_variables.size(); i++)
{
std::visit([&](auto rv)
{
if (i == registered_variables.size()-1)
file << rv.ident << "\n";
else
file << rv.ident << " ";
}, registered_variables[i]);
}
// log all registered variables
file << clock << " ";
for (int i = 0; i < registered_variables.size(); i++)
{
std::visit([&](auto rv)
{
if (i == registered_variables.size()-1)
file << *rv.var << "\n";
else
file << *rv.var << " ";
}, registered_variables[i]);
}
}
// method to log all registered variables
void log_data(double sim_time)
{
// check the timing
if (sim_time > (clock + dt))
{
is_time_to_log = true;
}
// check if its time to log
if (is_time_to_log)
{
// update the clock
clock += dt;
// debug
std::cout << "\n";
// log all registered variables
file << clock << " ";
for (int i = 0; i < registered_variables.size(); i++)
{
std::visit([&](auto rv)
{
// instantiate the value to be logged
double log_val;
// debug
std::cout << rv.last_val << " " << *rv.var << std::endl;
// if sim time is even with clock time, log at time
if (fabs(sim_time - clock) < EPSILON)
// if (true)
{
log_val = *rv.var;
}
// if sim time is past clock time, interpolate
else
{
log_val = lin_interp(sim_time, last_sim_time,
clock, rv.last_val, *rv.var);
}
// if last variable in vector create new line
if (i == registered_variables.size()-1)
file << log_val << "\n";
// otherwise just whitespace
else
file << log_val << " ";
}, registered_variables[i]);
}
// debug
std::cout << "\n";
// reset flag
is_time_to_log = false;
}
// get all the last values
for (int i = 0; i < registered_variables.size(); i++)
{
std::visit([&](auto rv)
{
// have to get last value at every update call
// This works in scope but the memory does not actually change?
// I am very confuse.
rv.last_val = *rv.var;
// debug
std::cout << rv.last_val << " " << *rv.var << std::endl;
}, registered_variables[i]);
}
// set the last sim time
last_sim_time = sim_time;
}
};
main.cpp
include <iostream>
include "sim_logger.h"
int main()
{
sim_logger logger(0.1, "sim_logger/log.dat");
double test1 = 100.0;
double test2 = 100.0;
double test3 = 100.0;
logger.register_variable("test1", &test1);
logger.register_variable("test2", &test2);
logger.register_variable("test3", &test3);
logger.write_header_and_log_init_data();
double simTime = 0.0;
double simDt = 1.0 / 20.0;
for (int i = 0; i < 3; i++)
{
simTime += simDt;
test1 += 1.0;
test2 += 2.0;
test3 += 3.0;
logger.log_data(simTime);
}
return 0;
};
output
101 101
102 102
103 103
102 102
104 104
106 106
1.88705e-26 103
1.88705e-26 106
1.88705e-26 109
103 103
106 106
109 109
std::visit([&](auto rv)
rv is, effectively, a parameter to this function (the closure, for the purposes of this answer, is effectively a function).
As you know: in C++ function parameters get passed by value. For example, using a simple function:
void func(int x)
{
x=5;
}
This func can set x to 5 as often as it wants. Whatever actually gets passed in, by anyone that calls func(), will remain unaffected:
int z=7;
func(z);
z is still 7. Even though func set its parameter to 5. This is fundamental to C++:
std::visit([&](auto rv)
{
rv.last_val = *rv.var;
So, this sets rv.last_val. Great. But this has no effect on whatever gets passed into here.
}, registered_variables[i]);
The visited instance of this variant is still what it is. It hasn't changed. Why would it change? C++ does not work this way.
So, if your intent, here, is to modify registered_variables[i], it should be passed by reference:
std::visit([&](auto &rv)
Now, the object referenced by rv gets modified.

I wrote a class. And when I specified the function, it failed

class equation
{
public :
int k;
int l;
int t;
float x1_value;
float x2_value;
float b1 = sqrt(l^2 -4*k*t);
float equation1;
equation();
~equation();
};
float void equation::equation1() {
if (b1 == 0)
{
float x1_value = -l/2*k;
cout << " joongen. " <<x1_value <<endl;
}
else if (b1 > 0)
{
float x1_value = ((-l + sqrt(b1) / (2*k));
float x2_value = ((-l - sqrt(b1) / (2*k));
cout << "x is 2"<< x1_value < " x 2 is "<< x2_value <<endl;
}
else
{
cout <<"imagine number ."<<endl;
}
return (0);
};
The code produces this error:
error: two or more data types in declaration of 'equation1'
float void equation::equation1() {
^
I can make out two problems.
First you define equation1 as a member variable with type float. You might want to change that into a function declaration.
// ...
float equation1();
// ...
The second problem is pointed out in the comments. If you implement your function, you should only use one return type. As I can only guess, what return type you would really want, I take float, since it is in your faulty function declaration.
// ...
float equation::equation1() {
// ...
}
// ...
One extra thing, that disturbs me every time I see someone who is new with C++. Please, please, please, don't use using namespace std;. I assume you do so, because of the missing std::. You open up an fastly huge namespace. You may end up defining a function, with the same name and parameters and encounter a very cryptic error, which is nearly impossible to figure out.

Overloading c++ operators int/float(..)

I'm working on operators in C++ now, but i have one problem. Well I'm trying to overloard int/float operators, I have 2 variables in class
class Zespolona{
public:
float re;
float im;
}
I've done all of my operators but when i do
operator int const(){
this->re = (int)this->re;
this->im = (int)this->im;
return *this;
}
then it gets an infinite loop.
My main
int main(){
Zespolona z1;
z1.re = 1.2;
z1.im = 34.9;
z1 = (int)z1;
cout << z1 << endl;
}
What can i do, to get int of two of those variables?
I am not completely sure what you are trying to achieve. I am guessing one of the following two possibilities:
1) Covert the two floats of your class (re, im) into integers:
This is rather simple. Since the two members are public you can access them directly:
#include <iostream>
int main()
{
Zespolona Z1;
Z1.re = 1.2;
Z1.im = 34.9;
std::cout << "Re: " << (int) Z1.re << std::endl;
std::cout << "Im: " << (int) Z1.im << std::endl;
return 0;
}
The output of this program should be:
Re: 1
Im: 34
Note: When you convert a float to an integer everything after the decimal dot is omitted (at least that is the behavior using g++ under Ubuntu).
If you want the two floats to be private or protected you would have to create methods like int GetRe() and int GetIm().
2) Convert the two floats of your class (re, im) into one integer using the integer conversion operator operator int const(). This operator has to return exactly one int. For the following example I decided to return the absolute value (magnitude) of the complex number (since your members are called re and im I am guessing the class is used for complex numbers):
class Zespolona
{
public:
float re;
float im;
operator int const()
{
return (int) sqrt(re*re + im*im);
}
};
int main()
{
Zespolona Z1;
Z1.re = 1.2;
Z1.im = 34.9;
std::cout << "Z1: " << (int) Z1 << std::endl;
return 0;
}
The output should now be:
Z1: 34
Note: Again the correct (float) result 34.92... is converted into the integer 34.
The code you mentioned in your questions returns a reference to your class Zespolona when you try to convert it into int. Thus, the compiler again tries to convert that reference into an int. But all it gets is again a reference to Zespolona, and so on. Hence, you get an infinite loop.

Access struct variable by its name

im trying to create program which will work with data provided in CSV file.
So far, i've made a structure of this CSV file and able to populate vector with its data.
What im trying to achieve is to allow user to enter Sensor Name and check it with given list of Sensors.
What i want to do is to after user have entered Sensors Name, access already created vector with data and display data of that particular sensor.
Here is the structure i've made:
typedef struct SensorReadings {
int Month;
int Day;
double Dp; // Dew Point Temperature
double Dta; // Wind Direction (10min Avg)
double Dts; // Wind Direction (10min SD)
double EV; // Evaporation (Year to Date)
double QFE; // Barometric Pressure
double QFF; // Barometric Pressure (QFE*Kqff)
double QNH; // Barometric Pressure (Aviation Standard)
double RF; // Rainfall (Year to Date)
} SensorReadings;
And here is the code, where i prompt user to enter Sensor Name:
std::cout << std::endl << std::endl << "Available Sensors: " << std::endl;
std::cout << "Dp Dta Dts EV QFE QFF QNH RF" << std::endl << std::endl;
do {
std::cout << "Please select Sensor you want to work with: ";
std::cin >> selectedSensor;
isSensorValid = std::find(std::begin(availableSensors), std::end(availableSensors), selectedSensor) != std::end(availableSensors);
} while(!isSensorValid);
I also made a method to get Average Daily Value for whole year of data:
double getAverageReadings(int wDay, int wMonth) {
std::vector<SensorReadings> pData = fm.parsedFile;
double DewPointTemperature = 0.0;
for(int r = 0; r < pData.size(); r++) {
if(pData[r].Month == wMonth) {
if(pData[r].Day == wDay) {
if(pData[r].Dp >= 100)
DewPointTemperature = DewPointTemperature + cWTKW(pData[r].Dp);
}
}
}
return DewPointTemperature;
}
This function allows me to get daily average for each day in each month for Dew Point Temperature, what i want to do tho, is to be able do something like this:
double getAverageReadings(int wDay, int wMonth, std::string selectedSensor) {
/*
Magic to convert std::string to actual Structure parameter
Pseudo:
param Sensor = convert(selectedSensor, to SensorReadingsParam);
*/
std::vector<SensorReadings> pData = fm.parsedFile;
double averageReadingsForSensor = 0.0;
for(int r = 0; r < pData.size(); r++) {
if(pData[r].Month == wMonth) {
if(pData[r].Day == wDay) {
if(pData[r].Sensor >= 100)
averageReadingsForSensor = averageReadingsForSensor + cWTKW(pData[r].Sensor);
}
}
}
return averageReadingsForSensor;
}
I've never used to work with 'dynamic' parameters before, so im seeking help on this one.
Thank you for your attention, and for any help on this topic!
You have two basic options:
Instead of declaring an explicit variable for each "sensor", use a std::map.
typedef struct SensorReadings {
int Month;
int Day;
std::map<std::string, double> sensor_value;
} SensorReadings;
And store each sensor value in the map, keyed by sensor name, i.e. sensor_value["Dp"], sensor_value["Dta"], and so on.
Then, given a sensor name std::string sensor_name, you can easily looked up the value of that sensor in the map (after checking that it exists, of course).
The second option is to maintain a separate list of sensor names, and a pointer to the corresponding class member, something like:
static struct {
const char *name;
double SensorReadings::*value;
} sensor_names[]={
{ "Dp", &SensorReadings::Dp },
{ "Dta", &SensorReadings::Dta },
};
And you can use this table to map sensor names to class members. This is a bit more uglier, but it's doable. I would prefer using the first option, myself.

Having a problem writing a class in C++; undeclared identifiers

I am coding a class for the quadratic equation. I have been given the .h file, and have to write it based on that. I experience problems when I am trying to establish the "display" function, where I am getting undeclared identifier areas (as shown here):
'my_a' : undeclared identifier
'my_b' : undeclared identifier
'my_c' : undeclared identifier
'display' : function-style initializer appears to be a function definition
I would appreciate a little direction in my code. I am including the .h file at the bottom.
#include <iostream> // for cout, cin, istream, ostream
#include <cmath> // for floor
#include <string> // for class string
#include "quad.h"
using namespace std;
quadraticEquation::quadraticEquation (double initA,
double initB, double initC)
{
my_a = initA;
my_b = initB;
my_c = initC;
}
double quadraticEquation:: root1() const
{
double result = 0.0;
result= ((-1* my_b)+(sqrt((my_b*my_b)- (4*my_a*my_c)))/(2*my_a));
return result;
}
double quadraticEquation:: root2() const
{
double result = 0.0;
result= ((-1*my_b)- (sqrt((my_b*my_b)- (4*my_a*my_c)))/(2*my_a));
return result;
}
bool hasRealRoots(double root1 , double root2)
// post: returns true if an only if b*b-4*a*c >= 0.0, otherwise return false
{
bool result;
{
if (root1 >= 0.0) {
if (root2 >= 0.0){
result = true;
}
else
{
return false;}
}
}
}
void display (my_a, my_b, my_c)
// post: shows the quadratic equation like -1x^2 + 3x - 9.7
// when my_a == -1, my_b = 3, and my_c == -9.7
{
if (my_a >= 0)
cout <<my_a<< "x^2"<<;
else
cout <<"-"<< abs(my_a)<<"x^2"<<;
if(my_b >= 0)
cout << " + " << my_b << "x";
else
cout << " - " << abs(my_b) << "x";
if (my_c >= 0)
cout <<" + "<<my_c<< endl;
else
cout << " - "<<my_c<< endl;
return display;
}
And
#ifndef _QUAD_H
#define _QUAD_H
// file name: quad.h (the file on disk lists pre- and post-conditions)
class quadraticEquation {
public:
//--constructor (no default constructor for quadraticEquation)
quadraticEquation(double initA, double initB, double initC);
// post: initialize coefficients of quadratic equation initA*x*x + initB + c
//--accessors
double root1() const;
// pre: there is at least one real root: b*b-4*a*c >= 0.0
// post: returns one real root as (-b+sqrt(b*b-4*a*c)) / (2*a)
double root2() const;
// pre: there is at least one real root: b*b-4*a*c >= 0.0
// post: returns one real root as (-b-sqrt(b*b-4*a*c)) / (2*a)
bool hasRealRoots() const;
// post: returns true if an only if b*b-4*a*c >= 0.0, otherwise return false
void display() const;
// post: shows the quadratic equation like -1x^2 + 3x - 9.7
// when my_a == -1, my_b = 3, and my_c == -9.7
private:
double my_a, my_b, my_c; // the three coefficients of the quadratic equation
};
#endif
The header file shows display() taking no parameters. You've coded one that takes parameters, but you haven't included their types:
void display (my_a, my_b, my_c)
Start by making those brackets empty and things should get a lot better.
Second, display should be a member function of the class. That's how it will get access to my_a, my_b, and my_c.
void quadraticEquation::display()
Third, hasRealRoots should also be a member function of the class, taking no parameters - and your code should not just see if both numbers are positive (which makes no sense) but actually evaluate the b^2-4ac term and see if it's positive (meaning the roots of the equation will be real rather than complex.)
the use of your display function is wrong(in cpp file). just use it as
void display()
since it doesnt need params and all the params it needs are already initialised.
missed a point..
write it as void quadraticEquation::display() rather than void display()
void quadraticEquation::display (double my_a, double my_b, double my_c)
// post: shows the quadratic equation like -1x^2 + 3x - 9.7
// when my_a == -1, my_b = 3, and my_c == -9.7
{
if (my_a >= 0)
cout <<my_a<< "x^2"<<;
else
cout <<"-"<< abs(my_a)<<"x^2"<<;
if(my_b >= 0)
cout << " + " << my_b << "x";
else
cout << " - " << abs(my_b) << "x";
if (my_c >= 0)
cout <<" + "<<my_c<< endl;
else
cout << " - "<<my_c<< endl;
return display;
}