2014-10-03 371 views
4

當R以科學計數法將大數轉換爲字符串時,它將包含所有有效數字並且不包含尾隨零。是否有可能用sprintf在C中完成這項工作?以sprintf科學計數法打印所有有效數字

> as.character(12345e11) 
[1] "1.2345e+15" 
> as.character(1234500000e6) 
[1] "1.2345e+15" 
> as.character(1234500001e6) 
[1] "1.234500001e+15" 

我試過sprintf(buf, "%g", val)但這似乎最多包含5個十進制數字。我還試圖用sprintf(buf, "%.18g", val)設置更高的精度,但這將包括非有效數字和尾隨零。

有沒有辦法獲得sprintf(buf, "%g", val)的行爲,但增加5位數的限制?

+3

尾隨零實際上是非常顯著。 – 5gon12eder 2014-10-03 17:57:40

+0

我不認爲這是可能的,至少根據[這](https://stackoverflow.com/questions/277772/avoid-trailing-zeroes-in-printf)後,你可能是重複的。讓我感到不安的是''printf''的man頁面對'%g'格式表示:*「結果的小數部分除去了尾部零」*我無法觀察到這種記錄的行爲。 – 5gon12eder 2014-10-03 18:10:25

+1

@ 5gon12eder - 如「n = 58.375」這樣的精心編制的數字如何?用'printf(「%。18g \ n」,n)'給我'58打印。375',而'n = 58.374'的結果是'58.3740000000000023'注意.375等於3/8,所以它具有精確的浮點表示。大多數任意選擇的小數部分不會**具有精確的浮點表示。因此,'%g'不符合您對這些數字的期望。 – user3386109 2014-10-03 18:48:13

回答

1

代碼可以使用"%.18e""%.18g",但問題是「18」應該有多大? 18是最好的價值嗎?答案在於DBL_DECIMAL_DIG

DBL_DECIMAL_DIG是顯著的最小位數打印到保證的double往返到完全相同的double所有double

使用格式說明符"%.*e"推薦。

請注意,"%.18e"中的「18」是之後的有效位數小數點後的位數。所以"%.18e"打印19位有效數字。


使用printf("%a", x);打印在十六進制輸出。
對於小數輸出:

#include <float.h> 

// sign + digit + dp +  digits   + e + sign + expo + \0 
char buf[1 + 1 +  1 + (DBL_DECIMAL_DIG - 1) + 1 + 1 + 5 + 1]; 
sprintf(buf, "%.*e", DBL_DECIMAL_DIG - 1, x); 

Printf width specificer to maintain precision of floating-point value


使用典型doublebinary64格式需要看到約53個十進制數字來查看其確切值的數字像y = 1.0/3.0。但是,成功的往返不需要許多尾隨數字。


現在我們知道了數字打印,使用下面擺脫那些煩人的拖尾0數字。

#include <float.h> 
#include <math.h> 
#include <stdio.h> 
#include <string.h> 

char *trim0(double x, char *buf) { 
    sprintf(buf, "% .*e", DBL_DECIMAL_DIG - 1, x); 
    if (isfinite(x)) { 
    char *p = &buf[DBL_DECIMAL_DIG + 1]; // address of last significand digit 
    char *t; 
    for (t=p; *t == '0'; t--); 
    memmove(t+1, p+1, strlen(p+1)+1); 
    } 
    return buf; 
} 

int main(void) { 
    char buf[1 + 1 + 1 + (DBL_DECIMAL_DIG - 1) + 1 + 1 + 5 + 1]; 
    printf("%s\n", trim0(1.2, buf)); 
    printf("%s\n", trim0(1.0/7, buf)); 
    return 0; 
} 

輸出

1.2e+00 
1.4285714285714285e-01