Детерминированный способ сказать "продвигать все до плавания перед вычислением" в С++

Учитывая, что я предпочел бы сохранить числа в моей программе как int или какой-либо интеграл, что является наиболее удобным способом выполнения произвольной арифметики с эквивалентами с плавающей запятой этих чисел?

Скажем, у меня

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

И я хочу написать

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

не превращая выражение в беспорядок, помещая конверсии всюду в анализируемые деревья дерева операторов, такие как

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

Можно ли использовать макрос C-стиля (рекурсивный или нет)? Должно ли это выполняться с помощью новых классов и перегруженных операторов?

Ответ 1

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

Это довольно сложное выражение. Лучше назовите его:

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

Теперь, когда вы вызываете это с помощью целых аргументов, поскольку параметры имеют тип double, аргументы преобразуются в double с использованием обычных арифметических преобразований:

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

С С++ 11 лямбда...

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);

... работает, но ИМО как-то выглядит неуклюжим.

Чуть лучше?

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

О, и если у вас есть интерес к макросам:

#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__)

Теперь используйте

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

Вы также можете автоматически подсчитывать количество аргументов вариационного макроса.


Но, честно говоря, IMO лучше всего написать именованную функцию.