[英]Compact lossless representation of floating point constants in C/C++
我有一個用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
。
您可以使用十六進制浮點( C中的printf()的格式說明符%a ; 它被定義為保留所有精度位(C11,7.21.6.1p8, a,A
說明符)。
cfile << std::hexfloat << v;
如果你的編譯器/標准庫不支持hexfloat
,你可以使用C99 %a
printf說明符(這是等效的,如C ++ 11表88中第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十六進制浮點文字作為擴展。
這不是表示,語言或標准庫的問題,而是算法的問題。 如果你有一個代碼生成器,那么...為什么不將生成的代碼更改為最佳(=最短,具有所需精度)表示? 這是你手工編寫代碼時所做的。
在假設的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;
}
首先,當你第一次說std::scientific
,然后std::fixed
時,你就是自相矛盾的。 第二,你可能也不想要。 默認格式通常旨在實現此目的。 默認格式沒有名稱,也沒有操縱器,但如果沒有指定其他格式,則可以獲得,並且可以設置(如果其他代碼設置了不同的格式),使用:
cfile.setf( std::ios_base::fmtflags(), std::ios_base::floatfield );
我建議用這個。 (當然,你仍然需要精確度。)
我不確定你能像這樣毫無損失地通過浮動點。 浮點必然是有損的。 雖然它們可以精確地表示值的子集,但您不能包含所有有效數字 - 不同的硬件可能具有不同的表示,因此您無法保證不會丟失信息。 即使您可以將其全部傳遞,因為接收硬件可能無法表示該值。
但是,普通的ofstream :: operator <<會打印出所需的數字,因此實際上並不需要使問題復雜化。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.