I am trying to learn some basic DS2 programming by writing a program that calculates BMI. I have written a program but I am getting 'ERROR: Line 47: Attempt to obtain a value from a void expression.'. What am I doing wrong?
Here is my program:
proc ds2;
data _null_;
dcl double bmi;
method bmi_calc(double height, double weight);
dcl double bmi;
bmi = weight/(height * height);
end;
method init();
weight = 70.5;
height = 1.68;
end;
method run();
bmi = bmi_calc(height, weight);
put 'BMI IS: ' bmi;
end;
method term();
put bmi;
end;
enddata;
run;
quit;
You need to do two things with custom methods in ds2:
Declare the type of value that you are going to return
Return the value
For example, this method returns the value 10.
method foo() returns double;
return 10;
end;
To make your method work, you simply need to state what type of variable you are returning and then return that value.
method bmi_calc(double height, double weight) returns double;
dcl double bmi;
bmi = weight/(height * height);
return bmi;
end;
Related
I currently have the coding to create a CONT plot from an inputted set of data
const int NbinX = 45;
const double binXlow = 0.0;
const double binXhigh = 2.0;
const int NbinY = 45;
const double binYlow = 0.0;
const double binYhigh = 200.0;
TH2D* hist3 = new TH2D("hist", "hist", NbinX, binXlow, binXhigh, NbinY, binYlow, binYhigh);
// read in your file
ifstream fin("data.dat");
// while loop to read in file (checks the input is good )
// ( x-val y-val z-val )
double x3 =-999.0; double y3=-999.0; double z3 = -999.0;
while(fin.good()) {
fin >> x3 >> y3 >> z3;
if( !fin.good()) { break;}
// must check if good after reading and before using
hist3->Fill( x3 , y3 , z3) ;
// Note: here I just did everything in the while loop
}
TCanvas *c3 = new TCanvas("c3", "c3");
hist->Draw("CONT4")
However unlike other colour plots I've done using this have a colour scale for the height of the z-axis. What do I need to do to get for a CONT plot?
To get a contour plot with lines (and not colors), you need
hist->Draw("CONT1");
or
hist->Draw("CONT2");
instead of
hist->Draw("CONT4");
See this for more info on the contour plots.
The function that return the values is this
float calcVelocity(float xacceleration, float yacceleration,sf::Clock clock, float originalDistance){
sf::Time time = clock.getElapsedTime(); //get current time and store in variable called time
float xvelocity = xacceleration*time.asSeconds();
float yvelocity = yacceleration*time.asSeconds();
while (!(originalDistance + calcDisplacement(yacceleration, clock, originalDistance) <= 0)) {
time = clock.getElapsedTime(); //get current time and store in variable called time
xvelocity = xacceleration*time.asSeconds();//Calculates velocity from acceleration and time
yvelocity = yacceleration*time.asSeconds();
cout << xvelocity<<endl;//print velocity
cout << yvelocity << endl;
system("cls");//clear console
}
return xvelocity;
return yvelocity;
}
I then want them to print as finalXvelocity = blah and finalYvelocity = blah after the while loop is finised. In the main code when I call the function and output the result, it prints both values together. E.g finalXvelocity = blahblah.
I was thinking I could separate the values returned into the main code and then print them using those but I don't know how to do that.
Thanks
Use a struct:
struct velocity
{
float x_component; /*ToDo - do you really need a float*/
float y_component;
};
This will be the most extensible option. You can extend to provide a constructor and other niceties such as computing the speed. Perhaps a class is more natural, where the data members are private by default.
If you have more than one return value, since C++11 you can return them as a std::tuple. No need to explicit declare a data struct.
e.g.
tuple<float,float> calcVelocity(/*parameters*/) {
// your code
return make_tuple(xvelocity,yvelocity);
}
Outside the function you can access the values by:
tuple mytuple = calcVelocity(/*parameters*/);
float xvelocity = get<0>(my_tuple);
float yvelocity = get<1>(my_tuple);
For pre-C++11 std::pair is also an option for just 2 values. But in this case the struct solution is more explicit.
I am reading in a temperature value every 1 second/minute (this rate is not crucial). I want to measure this temperature so that if it begins to rise rapidly above a certain threshold I perform an action.
If the temperature rises above 30 degrees ( at any rate ) I increase the fan speed.
I think I must do something like set old temperature to new temp and then each time it loops set old temp to the current temp of the engine. But I am not sure if I need to use arrays for the engine temp or not.
Of course you can store just one old sample, then check difference like in:
bool isHot(int sample) {
static int oldSample = sample;
return ((sample > 30) || (sample - oldSample > threshold));
}
It's OK from C point of view, but very bad from metrology point of view. You should consider some conditioning of your signal (in this case temperature) to smothen out any spikes.
Of course you can add signal conditioning letter on. For (easy) example look at Simple Moving Avarage: https://en.wikipedia.org/wiki/Moving_average
If you want control the fan speed "right way" you should consider learning a bit about PID controller: https://en.wikipedia.org/wiki/PID_controller
Simple discrete PID:
PidController.h:
class PidController
{
public:
PidController();
double sim(double y);
void UpdateParams(double kp, double ki, double kd);
void setSP(double setPoint) { m_setPoint = setPoint; } //set current value of r(t)
private:
double m_setPoint; //current value of r(t)
double m_kp;
double m_ki;
double m_kd;
double m_outPrev;
double m_errPrev[2];
};
PidController.cpp
#include "PidController.h"
PidController::PidController():ControllerObject()
{
m_errPrev[0] = 0;
m_errPrev[1] = 0;
m_outPrev = 0;
}
void PidController::UpdateParams(double kp, double ki, double kd)
{
m_kp = kp;
m_ki = ki;
m_kd = kd;
}
//calculates PID output
//y - sample of y(t)
//returns sample of u(t)
double PidController::sim(double y)
{
double out; //u(t) sample
double e = m_setPoint - y; //error
out = m_outPrev + m_kp * (e - m_errPrev[0] + m_kd * (e - 2 * m_errPrev[0] + m_errPrev[1]) + m_ki * e);
m_outPrev = out; //store previous output
//store previous errors
m_errPrev[1] = m_errPrev[0];
m_errPrev[0] = e;
return out;
}
I am working on MPI on C. I have this custom struct that I want to serialize and send to other nodes using MPI Collective communication (Gather, Scatter, Broadcast)
The struct is as following
typedef struct {
double x[2]; /* Old and new X-axis coordinates */
double y[2]; /* Old and new Y-axis coordinates */
double xf; /* force along X-axis */
double yf; /* force along Y-axis */
double xv; /* velocity along X-axis */
double yv; /* velocity along Y-axis */
double mass; /* Mass of the body */
double radius; /* width (derived from mass) */
} bodyType;
I have tried to understand serialization of custom structs on MPI but could not really understand the process. If some one can help me out here it would be great
Thank You
Your struct is just ten contiguous doubles. You don't need to inform MPI about your type, therefore, as it can be treated as an array. If you have an array of seven of your structs, just tell MPI you have an array of 70 doubles. You should tell your compiler to "pack" your struct (e.g. __attribute__((__packed__)) in GCC or Clang) so that it has no padding.
Ok so I was able to go through documents and wrote this
const int nitems=8;
int blocklengths[8] = {2,2,1,1,1,1,1,1};
MPI_Datatype types[8] = {MPI_DOUBLE,MPI_DOUBLE,MPI_DOUBLE,MPI_DOUBLE,MPI_DOUBLE,MPI_DOUBLE,MPI_DOUBLE,MPI_DOUBLE};
MPI_Datatype mpi_body_type;
MPI_Aint offsets[8];
offsets[0] = offsetof(bodyType, x);
offsets[1] = offsetof(bodyType, y);
offsets[2] = offsetof(bodyType, xf);
offsets[3] = offsetof(bodyType, yf);
offsets[4] = offsetof(bodyType, xv);
offsets[5] = offsetof(bodyType, yv);
offsets[6] = offsetof(bodyType, mass);
offsets[7] = offsetof(bodyType, radius);
MPI_Type_create_struct(nitems, blocklengths, offsets, types, &mpi_body_type);
MPI_Type_commit(&mpi_body_type);
I'm working on a program that calculates time based off of distance and speed and when I out put the final time it would take to get from point a to point b instead of getting 100 miles I'm getting either nan or inf depending on how my class is set up. Can someone help me out here?
Part of my class:
class Trip
{
private:
string chicago, illinois, destCity, destState;
double distance, time, rate;
public:
Trip()
{
chicago = "Chicago";
illinois = "Illinois";
destCity = "";
destState = "";
distance = 0.0;
time = 0.0;
rate = 0.0;
}
Trip(string city, string state, double distance)
{
chicago = "Chicago";
illinois = "Illinois";
destCity = city;
destState = state;
distance = 0.0;
time = 0.0;
rate = 0.0;
}
This is what a constructor would look like in my main method:
Trip atlanta("Atlanta", "Georgia", 587);
and then here are some mutator methods that could be part of the problem:
void Trip::setRate(double mph)
{
mph = rate;
}
void Trip::calcTime()
{
time = distance/rate;
}
now if i set up my class like so
this->city = "";
this->distance = 0.0;
when I use an accesor method to retrieve time, distance, etc is prints as "nan" but if I have my class set up like it
city = "";
distance = 0.0;
then I get "inf".
When I debug the program the trip object shows up with all the variables being 0 even after I pass values to the class members with the constructor. I don't know what's going wrong.
In this function:
Trip(string city, string state, double distance)
{
// ...
distance = 0.0;
that last line sets the function parameter distance. Not the class member. The class member remains uninitalized , so you get garbage when you print it out sometimes.
To fix this you could write this->distance = 0.0;, or preferably use constructor initialization lists:
Trip(string city, string state, double distance)
: chicago("Chicago")
, distance(distance)
, // etc.
{
}
And/or use different names for the parameters than you use for the class members.
In the initialization list, distance(distance) means that this->distance is initialized to the parameter distance, because the thing outside the parentheses has to be the name of a class member.
In C++11 you can set default values in the class definition, which avoids you having to repeat them in every constructor:
class Trip
{
private:
string chicago, illinois, destCity, destState;
double distance = 0.0;
double time = 0.0;
double rate = 0.0;
Note that there is no need to initialize strings to blank; they have a default constructor, so uninitialized strings are guaranteed to be empty strings, not garbage.