У меня есть программа, написанная на C ++, которая генерирует исходный код C для математических расчетов. Я заметил, что константы занимают очень много места в сгенерированном коде и ищут более компактное представление.
Для генерации констант я сейчас использую:
double v = ...
cfile << std::scientific << std::setprecision(std::numeric_limits<double>::digits10 + 1) << v;
Я почти уверен, что это представление без потерь, но оно также очень раздутое. Например, ноль и единица будут представлены как что-то вроде 0,0000000000000000e + 00 и 1.0000000000000000e + 00. И «0» или «1» несет столько же информации.
Есть ли способ напечатать константы в файл более компактным, но все же без потерь способом? Он не должен хорошо выглядеть для читателя-человека, просто компилировать, когда он представлен в простом C-коде (если C99, я бы предпочел, чтобы это также был C ++). Шестнадцатеричный может быть в порядке, если он переносим.
РЕДАКТИРОВАТЬ: Удалено std::fixed
во фрагменте кода.
Это не проблема представления, языка или стандартной библиотеки, а алгоритма. Если у вас есть генератор кода, то … почему бы вам изменить сгенерированный код быть лучшим (= самым коротким с требуемой точностью) представления? Это то, что вы делаете, когда пишете код от руки.
В гипотетическом put_constant(double value)
рутина вы можете проверьте, какое значение вы должны написать:
std::fixed
а также set_precision
, просто приведите к целому числу и добавьте точку.double
Если ничего не изменилось, то представление по умолчанию (короткое) достаточно хорошо.Возможное (короткое) представление для чисел с плавающей запятой, когда они имеют много цифр, состоит в том, чтобы использовать их представление памяти. При этом у вас довольно фиксированные накладные расходы, и длина никогда не изменится, поэтому вы должны применять его только для очень длинных чисел. Наивный пример, чтобы показать, как это может работать:
#define USE_L2D __int64 ___tmp = 0;
#define L2D(x) (double&)(___tmp=x)
int main(int argc, char* argv[])
{
// 2.2 = in memory it is 0x400199999999999A
USE_L2D
double f1 = L2D(0x400199999999999A);
double f2 = 123456.1234567891234567;
return 0;
}
Вы можете использовать шестнадцатеричное число с плавающей запятой (Спецификатор формата% a для printf () в C); он определен, чтобы сохранить все биты точности (C11, 7.21.6.1p8, a,A
спецификаторы).
cfile << std::hexfloat << v;
Если ваш компилятор / стандартная библиотека не поддерживает hexfloat
, вы можете использовать C99 %a
спецификатор printf (это эквивалентно, как указано в таблице 88 C ++ 11 в разделе 22.4.2.2.2):
printf("%a", v);
Например, следующая программа действительна C99:
#include <stdio.h>
int main() {
double v = 0x1.8p+1;
printf("%a\n", v);
}
Ваш сгенерированный исходный файл не будет действительным C ++ 11, так как довольно нелепо C ++ 11 не поддерживает шестнадцатеричные литералы с плавающей точкой. Однако многие компиляторы C ++ 11 поддерживают шестнадцатеричные литералы с плавающей запятой C99 в качестве расширения.
Во-первых, вы противоречите себе, когда вы впервые говорите
std::scientific
, а потом std::fixed
, А во-вторых, ты
наверное тоже не хочу. Формат по умолчанию обычно
разработан, чтобы сделать это лучше всего. Формат по умолчанию не
есть имя или манипулятор, но это то, что вы получите, если нет других
формат был указан и может быть установлен (в случае, если другой код
установил другой формат) используя:
cfile.setf( std::ios_base::fmtflags(), std::ios_base::floatfield );
Я бы рекомендовал использовать это. (Вам все еще нужна точность,
курс.)
Я не уверен, что ты Можно проходите плавающие точки без потерь, как это. Плавающие точки обязательно с потерями. Хотя они могут точно представлять подмножество значений, вы не можете включать ВСЕ значимые цифры — разное оборудование может иметь разные представления, поэтому вы не можете гарантировать отсутствие потери информации. Даже если вы могли бы передать все это, поскольку значение не может быть представлено принимающим оборудованием.
Равнина ofstream :: operator<< Тем не менее, можно было бы распечатать столько цифр, сколько необходимо, поэтому нет необходимости усложнять ситуацию.