2015-03-19 1 views
0

В алгоритмах я использую такие константы:Что лучше, макросы или встроенные функции для квадратных или sqrt констант?

sqrt(3) 
pow(M_PI, 2) 

К сожалению, препроцессор C не достаточно умен, чтобы предварительно вычислить эти константы. Есть ли дополнительный уровень предварительной обработки, который можно использовать с GCC или любым другим компилятором C?

Я в настоящее время реализованы эти две константы, как:

#define SQRT3 1.7320508 
#define PIPI (M_PI*M_PI) 

Но я чувствую, используя малоизвестные имена, как PIPI (что также означает, что мочиться на французском) не является лучшим решением. Я думаю, было бы лучше написать:

inline float square(float x) { 
    return x * x; 
} 

Однако это невозможно для квадратного корня. По крайней мере, я могу получить достаточное приближение с этим:

inline float sqrt_approx(float z) 
{ 
    int val_int = *(int*)&z; 
    val_int -= 1 << 23; 
    val_int >>= 1; 
    val_int += 1 << 29; 
    return *(float*)&val_int; 
} 

К сожалению, и опять же, компилятор не достаточно умен, чтобы интерпретировать sqrt_approx(3) в 1,73

Есть ли лучший способ справиться с этими ограничениями C ?

Мы находимся в 2015 году, у нас есть роверы, которые бродят по Марсу, и мы по-прежнему имеем дело с компиляторами C, которые заставляют нас чувствовать себя в 80-х годах. Я ошибаюсь?

+3

Вы пытались назвать константу 'PI_SQUARED' вместо этого? Я не понимаю, что не так с определением короткого числа констант, поскольку они не должны сильно меняться. – moooeeeep

+0

Где вы нуждаетесь в них, рассчитанные препроцессором? – mafso

+1

@moooeeeep Ну, это нужно рассматривать как более общий пример. Я чувствую себя более читаемым, чтобы видеть 'sqrt (3)/2' где-то в коде, чем' HALF_SQRT3'. – nowox

ответ

1

Поскольку эти константы истинные константы (не следует путать с const переменных). Вы хотите, чтобы ваш код использовал их непосредственно во время выполнения, и вы, разумеется, не хотите иметь вызов функции sqrt или pow, которая в основном бесполезна, потому что вы уже знаете результат во время компиляции.

Если вы хотите быть уверенным, что бесполезных вызовов нет, вы должны использовать макросы с предварительным процессором C для этого. И вы не ошибаетесь, компиляторы C иногда могут сделать нас чувствовать себя в 80-х годах. Существует много других современных языков программирования.

Однако, поскольку компиляторы становятся более современными при оптимизации прогорок, также возможно, что компилятор может встроить функции, а затем предварительно вычислить их во время компиляции. Единственный способ узнать, возможно ли это, - проверить и посмотреть на генераторную сборку. Например, в моей тестовой программе:

static inline int twice(int x) 
{ 
    return 2*x; 
} 

int main() 
{ 
    int i = twice(2); 
    i += twice(4); 
    printf("Result is %d\n", twice(i)); 
    return 0; 
} 

компилировать с последней НКОЙ и -Os свернул на:

main: 
    sub  rsp, 40 
    .seh_stackalloc 40 
    .seh_endprologue 
    call __main 
    lea  rcx, .LC0[rip] 
    mov  edx, 24 
    call printf 
    xor  eax, eax 
    add  rsp, 40 
    ret 

Как вы можете видеть, результат, 24 предварительно вычисленный в коде сборки. С типом double это менее очевидно для проецирования из-за того, что число с плавающей запятой не появляется сразу в сборке, однако я проверил и оптимизация также сделана.Тогда не обязательно использовать предварительный процессор C для констант.. Но если вы хотите производительности, всегда проверяйте код сборки.

+3

Кроме того, не используйте 'PIPI', это оскорбительно на французском языке :) – Bregalad

1

Я бы предложил использовать константы, которые компилятор знает об этом. И выберите более явные имена для ваших констант.

const float SQRT_OF_3 = 1.7320508; 
const float PI_SQUARE = M_PI*M_PI; 
2

Без -ffreestanding и т. Д., Gcc вычисляет их во время компиляции, по крайней мере, с включенными оптимизациями. Таким образом, вряд ли будет вызов функции.

Если используется -ffreestanding, я не вижу лучшего способа, чем определение констант вручную для таких случаев, как sqrt, если самодельная встроенная функция оказывается недостаточно быстрой. Gcc const attribute может помочь избежать повторных вычислений (но, я думаю, Gcc может это сделать сам по себе, если определение видимо).

Вопрос в том, что они должны быть рассчитаны препроцессором. Я не вижу причины для этого, единственное, что можно сделать с константами с плавающей запятой в препроцессоре, - это сведение или объединение их. Если это действительно необходимо, они также должны быть жестко закодированы. Префикс также не может быть вызван встроенной функцией.

Смежные вопросы