инициализировать переменную статически (во время компиляции)

1) В моем алгоритме C много констант. 2) мой код работает как с плавающей запятой, так и с фиксированной точкой.

Прямо сейчас эти константы инициализируются функцией float2fixed, при этом в случае с плавающей запятой она ничего не делает, а в случае с фиксированной точкой находит их представление с фиксированной точкой. Например, 0,5f остается 0,5f при работе с плавающей запятой, тогда как он использует процедуру pow() и становится 32768 при работе с фиксированной запятой, а представление с фиксированной запятой равно Qx.16.

Это легко поддерживать, но на самом деле требуется много времени, чтобы вычислить эти константы в фиксированной точке (pow — это функция с плавающей запятой). В C++ я бы использовал некоторое метапрограммирование, поэтому компилятор вычисляет эти значения во время компиляции, поэтому во время выполнения не происходит попадания. Но в C это невозможно. Или это? Кто-нибудь знает такой трюк? Достаточно ли умен какой-либо компилятор, чтобы сделать это?

С нетерпением жду любых ответов.

A


person vectorizor    schedule 10.06.2009    source источник
comment
C не поддерживает макросы препроцессора?   -  person CookieOfFortune    schedule 11.06.2009
comment
@CookieOfFortune: макросы не так эффективны, как шаблоны C ++ (они даже не полны по Тьюрингу), но это может быть возможно.   -  person Zifre    schedule 11.06.2009


Ответы (4)


Вместо того, чтобы использовать (unsigned)(x*pow(2,16)) для преобразования с фиксированной точкой, запишите его как (unsigned)(0.5f * (1 << 16))

Это должно быть приемлемым выражением константы времени компиляции, поскольку оно включает только встроенные операторы.

person puetzk    schedule 10.06.2009

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

Одним из преимуществ этого будет то, что вы можете затем определить и объявить свои константы с помощью const, чтобы они не изменялись во время выполнения, тогда как с функциями инициализации, конечно, значения должны быть модифицируемыми, потому что они вычисляются один раз.


Я имею в виду написать простую программу, которая может сканировать шаблонные строки, которые могут выглядеть так:

const double somename = 3.14159;

он прочитает это и сгенерирует:

const fixedpoint_t somename = { ...whatever is needed... };

Вы разрабатываете операцию так, чтобы упростить управление обеими нотациями, поэтому, возможно, ваш преобразователь всегда читает файл и иногда перезаписывает его.

datafile.c:   datafile.constants converter
        converter datafile.constants > datafile.c
person Jonathan Leffler    schedule 10.06.2009
comment
слишком хлопотно. Мне нужно разработать уже для 6 платформ, и это только начало. - person vectorizor; 11.06.2009
comment
Итак, используйте для этого общий код — ведь в любом случае материал с фиксированной точкой постоянен на разных платформах? В любом случае, если это слишком сложно сделать во время компиляции, вам, вероятно, придется принять удар во время выполнения. Удачи. (6 платформ — это не так уж плохо — это обычная практика для моей работы — и я считаю Linux на IA32, IA64, Itanium, zLinux, PPC одной платформой, а не пятью.) - person Jonathan Leffler; 11.06.2009
comment
ну, не для того, чтобы играть, у кого больше :D, но я должен работать на ARM, x86, графических процессорах ... т.е. сильно и мучительно разных процессорах. Я выиграю? :) - person vectorizor; 12.06.2009

В последних версиях GCC (около 4.3) добавлена ​​возможность использовать GMP и MPFR для оптимизации времени компиляции путем оценки более сложных функций, которые являются постоянными. Такой подход делает ваш код простым и переносимым, и вы можете доверить компилятору всю тяжелую работу.

Конечно, есть ограничения на то, что он может сделать, и было бы трудно понять, оптимизирует ли он данный экземпляр, не взглянув на сборку. Но, возможно, стоит проверить. Вот ссылка на описание в журнале изменений

person Chris Arguin    schedule 11.06.2009
comment
Но он будет переносимым только до того момента, когда компилятор, на который вы переносите, поддерживает те же оптимизации. В противном случае он может скомпилироваться для другой платформы, но производительность во время выполнения может оказаться неприемлемой. Представьте себе перенос чего-то подобного на встроенную систему с компилятором, который не поддерживает расширенные оптимизации GCC. - person VoidPointer; 25.07.2009

В простом C вы мало что можете сделать. В какой-то момент вам нужно выполнить преобразование, и компилятор не дает вам никакого доступа для вызова интересных пользовательских функций во время компиляции. Теоретически вы можете попытаться уговорить препроцессор сделать это за вас, но это быстрый путь к полному безумию (т. е. вам придется реализовать pow() в макросах, что довольно отвратительно).

Некоторые варианты, которые я могу придумать:

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

  2. Как упоминалось в другом комментарии, в любом случае используйте метапрограммирование шаблонов и компилируйте с помощью компилятора C++. Большинство C прекрасно работает (возможно, даже лучше) с компилятором C++.

Хм, пожалуй, это все, о чем я могу думать. Удачи.

person C Pirate    schedule 10.06.2009