Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Deterministic way of saying "promote everything to floating before calculation" in C++

Given that I'd prefer to keep numbers in my program as ints or whatever integral, what is the most convenient way of doing an arbitrary arithmetic with floating point equivalents of those numbers?

Say, I have

int a,b,c,d;
double x;

And I want to write

x=a/b/c/d+c/d+a;

without turning the expression into mess by putting conversions everywhere in parsed operator tree leafs like

x=(double)a/b/c/d+(double)c/d+a;

Is it doable with C-style macro (recursive or not)? Should it be done with new class and overloaded operators?

like image 927
Euri Pinhollow Avatar asked Oct 06 '16 08:10

Euri Pinhollow


1 Answers

x=a/b/c/d+c/d+a;

This is a pretty complex expression. Better give it a name:

double complex_expression(double a, double b, double c, double d) {
  return a/b/c/d+c/d+a;
}

Now when you call that with integer arguments, since the parameters are of type double the arguments get converted to double using the usual arithmetic conversions:

int a,b,c,d;
// Init them somehow
double x = complex_expression(a,b,c,d);

With a C++11 lambda ...

int a,b,c,d;
// Init them somehow
double x = [](double a, double b, double c, double d) {
  return a/b/c/d+c/d+a; }(a,b,c,d);

... works, but IMO somehow looks clumsy.

Slightly better?

double x = [a = (double)a, b = (double)b, c = (double)c, d = (double) d] {
    return a/b/c/d+c/d+a; }();

Oh, and if you're in for some macro fun:

#define SPLICE_2(l,r) l##r
#define SPLICE_1(l,r) SPLICE_2(l,r)
#define SPLICE(l,r) SPLICE_1(l,r)

#define TREAT_AS(type, name) name = static_cast<type>(name)

#define TREAT_ALL_AS_HELPER_0(type)
#define TREAT_ALL_AS_HELPER_1(type, name)  TREAT_AS(type, name)
#define TREAT_ALL_AS_HELPER_2(type, name, ...) TREAT_AS(type, name), TREAT_ALL_AS_HELPER_1(type, __VA_ARGS__)
#define TREAT_ALL_AS_HELPER_3(type, name, ...) TREAT_AS(type, name), TREAT_ALL_AS_HELPER_2(type, __VA_ARGS__)
#define TREAT_ALL_AS_HELPER_4(type, name, ...) TREAT_AS(type, name), TREAT_ALL_AS_HELPER_3(type, __VA_ARGS__)
#define TREAT_ALL_AS_HELPER_5(type, name, ...) TREAT_AS(type, name), TREAT_ALL_AS_HELPER_4(type, __VA_ARGS__)
// expand as you will

#define TREAT_ALL_AS(type, count, ...) SPLICE(TREAT_ALL_AS_HELPER_, count)(type, __VA_ARGS__)

Now use as

double x = [TREAT_ALL_AS(double, 4, a, b, c, d)] {
  return a/b/c/d+c/d+a; }();

You can also automatically count the number of variadic macro arguments.


But to be honest, IMO its best to just write a named function.

like image 110
Daniel Jour Avatar answered Sep 27 '22 17:09

Daniel Jour