In A Tour of C++ by Bjarne Stroustrup, some advice is listed at the end of each chapter. At the end of the first chapter one of them reads:
Avoid ‘‘magic constants;’’ use symbolic constants;
What are magic and symbolic constants?
somethingElse = something * 1440; // a magic constant
somethingElse = something * TWIPS_PER_INCH; // a symbolic one
The first is an example of the magic constant, it conveys no other information other than its value.
The latter is far more useful since the intent is clear.
Using symbolic constant also helps a great deal if you have multiple things with the same value:
static const int TWIPS_PER_INCH = 1440;
static const int SECTORS_PER_FLOPPY = 1440; // showing my age here :-)
That way, if one of them changes, you can easily identify which single 1440 in the code has to change. With magic 1440s scattered throughout the code, you have to change it in multiple places and figure out which are the twips and which are the sectors.
A magic constant would be a numeric value that you just type into some code with no explanation about why it is there. Coming up with a good example is challenging. But let's try this:
float areaOfCircle(float radius) {
return radius * radius * 3.14159
}
Here I've used a "magic constant" of 3.14159 without any explanation of where it comes from. It would be better style to say
const float pi = 3.14159
float areaOfCircle(float radius) {
return radius * radius * pi;
}
Here I've given the person reading the code some idea about where the constant came from and why it was used... it didn't seem to "magically" appear out of nowhere.
Magic:
int DeepThought() { return 42; }
Symbolic:
const int TheAnswerToTheUltimateQuestionOfLifeTheUniverseAndEverything = 42;
int DeepThought() { return TheAnswerToTheUltimateQuestionOfLifeTheUniverseAndEverything; }
Related
my solution to find area of a triangle when base and height is given(the question specifically asked to also use float typcasting):
#include <iostream>
using namespace std;
int area()
{
int b=7,h=5;
float area;
area=(float)b*h/2;
return area;//Write a expression to find Area as float using typecasting
}
correct solution:
#include<iostream>
using namespace std;
void area()
{
int b=7,h=5;
float area;
area=(float)b*h/2;
cout<<area;
}
what's wrong with my code?
By itself I would say nothing much.
When you want to calculate a floating point number, makes sure ALL you values are floating point. Eg. not 2 but 2.0f
Casting in C++ is usually done with static_cast (or one of the other cast functions). The notation you use is more "C" style type casting
I am not a big fan of using, "using namespace" specially in larger projects. In source it can be ok, NEVER do this in header files though.
I would code it like this:
float calculate_triangle_area(const int b, const int h) noexcept
{
float area = static_cast<float>(b) * static_cast<float>(h) / 2.0f;
return area;
}
std::cout << calculate_triangle_area(5,7);
Some more notes:
I always make things functions as soon as I can give it a name. This has the added benefit of making your code more "self explaining".
The "const int" this mean you promise you won't change the values of b and h in your calculations.
The noexcept is another promise, but that's a whole topic on its own ;)
I'm trying to use the GNU Scientific Library and am having trouble understanding its documentation. Here's the sample program from the page on gsl_rng_env_setup:
#include <stdio.h>
#include <gsl/gsl_rng.h>
gsl_rng * r; /* global generator */
int
main (void)
{
const gsl_rng_type * T;
gsl_rng_env_setup();
T = gsl_rng_default;
r = gsl_rng_alloc (T);
printf ("generator type: %s\n", gsl_rng_name (r));
printf ("seed = %lu\n", gsl_rng_default_seed);
printf ("first value = %lu\n", gsl_rng_get (r));
gsl_rng_free (r);
return 0;
}
My problems start with the third line, gsl_rng * r. This is clearly not multiplication (neither variable defined yet), so it must be pointer notation. However from the C++ tutorial on pointers, I would expect something like gsl_rng = *r, which would take the value of r and store that as gsl_rng. My guess is that gsl_rng isn't a variable, but some GNU Scientific library command; however I don't understand the documentation page for it also: this command is clearly not of the form gsl_rng * gsl_rng_alloc (const gsl_rng_type * T) - even if r = gsl_rng_alloc, this command doesn't have brackets.
It doesn't help that a bit further down we have the line const gsl_rng_type * T which is of the same form but also clearly does something different. This line seems to be defining gsl_rng_type as a constant, and assigning it the value of *T - but this is missing an assignment operator. Yet T must be a variable, since a few lines later it's assigned the value of gsl_rng_default ...
My problems seem to be extremely basic which is troubling. Can anyone point me in the right direction?
gsl_rng is a type. The statement gsl_rng * r; declares a global variable named r with type pointer to gsl_rng.
Later, there is this line r = gsl_rng_alloc (T);, which assigns some value to that declared variable.
This is basic C++, so maybe you should start with some good book, if you want to understand such code.
The trick is to remember that there are different kinds of random number generators. Each one is its' own class. The gsl_rng_alloc method will create a random number generator object for you but wants to know what class to use. You tell it what class to use by passing the class. Then the method uses that class to instantiate an object for you. It returns to you a pointer to the object that it created for you.
My professor gave us two examples of code in which both pass the int
values, x & y, into a function with float parameters as examples of
how to pass a different type of variable into a function by reference. I've ran them both, and neither work, unless of course I change int x, y; to float x, y;. The programs are written in C.
In his notes, following the 2nd program, he makes his point regarding the comparison of the 2:
"It (both programs) prints out: normalized vector = ( .12, .16 )
This code is nearly identical to the code of the previous example. The difference is in the way the parameters are declared in the normalizeVector function. By using the "&" operator, the normalizeVector function has access to the variables being passed to it, not just access to the values of those variables, access to the original location. This is functionally the same as having the address of those variables, but the syntax is nicer for those not used to using C pointers. Since the "&" is used, all of the work de-referencing the variables using the "*", as in the previous example, can be avoided."
While I am not questioning the rule or technique, I can't run them and am dying to know what stupid little mistake I am making or what crazy (and probably very simple) detail I am missing. I have done much more than just copy and paste them. Not to mention, when I used int float to make them work, I had to remove the sqrt before (xWork*xWork + yWork*yWork) in order to get the correct answers. (And by the way, he is a great professor.) Should these programs work? And how do I pass int into float parameters by reference, if they don't?
Program 1
main()
{
int x, y;
x = 3;
y = 4;
normalizeVector(&x, &y);
printf(“normalized vector = ( %f, %f ) \n”, x, y);
}
void normalizeVector(float *x, float *y)
{
float magnitude;
float xWork, yWork;
xWork = *x;
yWork = *y;
magnitude = sqrt(xWork*xWork + yWork*yWork);
*x = xWork/magnitude;
*y = yWork/magnitude;
}
Program 2
main()
{
int x, y;
x = 3;
y = 4;
normalizeVector(x, y);
printf(“normalized vector = ( %f, %f ) \n”, x, y);
}
void normalizeVector(float &x, float &y)
{
float magnitude;
float xWork, yWork;
xWork = x;
yWork = y;
magnitude = sqrt(xWork*xWork + yWork*yWork);
x = xWork/magnitude;
y = yWork/magnitude;
}
Either this code was copied wrongly or the professor is confused.
C and C++ both have some limited rules allowing built in type numeric arguments to functions which are passed by value to be implicitly converted to the needed type, if they are compatible according to a set of parameters explained in the spec (which I wont go into here due to their complexity).
This does not apply to parameters passed by pointer or reference, you need to pass in a pointer to the exact type the function needs if it is passed by reference (there are a few implementation defined tricks involving reinterpret casts but this is unimportant for this case).
So yes, you are correct, the only way this code could possibly work is if you change the variables to the correct type or change the type the function requires.
I'm starting to learn C++. Here is a problem that I have:
#include <iostream>
using namespace std;
#define PI 3.14;
int main(){
double r = 5.0;
double circle;
double inp;
circle = 2 * PI * r;
cout << circle;
cin >> inp;
}
It shows error: error C2100: illegal indirection.
I've googled but found no answer. Thanks
#define PI 3.14;
The ; is wrong, delete it.
btw, your line expands to circle = 2 * 3.14; * r;
So the compiler is then complaining about the *r, which explains the error message.
Macros are (relatively) simple substitutions so, when you write:
#define PI 3.14;
circle = 2 * PI * r;
it actually ends up as:
circle = 2 * 3.14; * r;
effectively the two statements:
circle = 2 * 3.14;
* r;
That last line would be a perfectly valid expression (albeit it not a very useful one) if r were a pointer of some description. However, given it's a double, that's where you're getting the illegal indirection from.
The use of macros is something you should generally avoid nowadays except in very specific circumstances. The use of them to provide inline functions has been subsumed mostly by the inline keyword ("mostly", because the inline keyword is only a suggestion).
In addition, using it to provide constants can be better done (with the advantage of full type support and usually better debugging) with the const keyword.
In other words, your PI constant would be better written as something like:
const double PI = 3.141592653589;
Just about the only place I use the pre-processor nowadays is for conditional compilation.
As an aside, you probably meant circumference rather than circle. The former is the length around the outside of the circle, the latter isn't really a length value at all.
I am looking for a solution using the C++03 standard (I am constrained to using this version of the standard for several years yet). Solutions for C++11 are also welcome, but will not be "accepted" as the answer to this question.
What is a simple, concise way that I can represent a set of related constant floating point values as a single type (similar to an enum) to ensure type-safety without incurring significant overhead and still allow me to operate on the values as floats directly?
The end result is that I would like to be able to do something like the following:
enum FloatingPointEnum
{
VALUE1 = 0.1234f,
...
VALUEN = 0.6789f
};
float SomeFunction(FloatingPointEnum value)
{
float new_value;
/* perform some operation using "value" to calculate "new_value" */
new_value = static_cast<float>(value); // <- a simplistic example
return new_value;
}
While I can think of several solutions, none of them are as clean/simple/straightforward as I would like and I figure that someone must already have an elegant solution to this problem (yet I cannot seem to find one in my searching).
EDIT:
I would like the following call to SomeFunction with a value that is not specified directly as a value from the enumerated type to fail to compile:
float nonEnumeratedValue = 5.0f
SomeFunction(nonEnumeratedValue);
someone must already have an elegant solution to this problem
There are lots of problems that have no elegant solution (and many that have no solution at all). What makes you think this problem has one? The closest you can get is to use a wrapper class.
class FloatingPointEnum {
float f;
FloatingPointEnum(float arg) : f(arg) {}
public:
static const FloatingPointEnum Value1;
static const FloatingPointEnum Value2;
operator float() const { return f; }
};
const FloatingPointEnum FloatingPointEnum::Value1(0.1234f);
const FloatingPointEnum FloatingPointEnum::Value2(0.6789f);
A possible alternative solution, not always applicable but very clean, is to use fixed precision.
Lets imagine you have you enum containing some distance in meters
enum DistancesMeter{
A = 0.25,
b = 0.05,
};
then you may simply switch to use mm
enum DistancesMM{
A = 250,
b = 50,
};
In C++11 you can use constexpr to achieve what you want.
constexpr - specifies that the value of a variable or function can appear in constant expressions
http://en.cppreference.com/w/cpp/language/constexpr
With constexpr you define a compile-time constant. This only works for literal types, such as float. Since at the same time we want
float nonEnumeratedValue = 5.0f;
SomeFunction(nonEnumeratedValue);
to fail, we cannot use a simple typedef. Instead we use Boost’s BOOST_STRONG_TYPEDEF.
#include <boost/serialization/strong_typedef.hpp>
BOOST_STRONG_TYPEDEF(float, FloatingPointEnum);
constexpr float VALUE1 = 0.1234f;
constexpr float VALUEN = 0.6789f;
float SomeFunction(FloatingPointEnum value)
{
float new_value;
/* perform some operation using "value" to calculate "new_value" */
new_value = static_cast<float>(value); // <- a simplistic example
return new_value;
}
Now you can call the function only with instances of FloatingPointEnum. Unfortunately, the instantiation syntax is not so nice anymore
FloatingPointEnum f {VALUEN};
Alternatively, you can simply use the D programming language, where floating point enums are supported and the following code works as expected:
enum FloatingPointEnum
{
VALUE1 = 0.1234f,
//...
VALUEN = 0.6789f
};
float SomeFunction(FloatingPointEnum value)
{
float new_value;
new_value = value; // No cast needed, welcome to D!
return new_value;
}
Calling SomeFunction with a float results in
Error: function test.SomeFunction (FloatingPointEnum value) is not callable using argument types (float)