2010-02-09 40 views

回答

2

效率更高,並且(在我看來)更清晰的paxdiablo的morphNumericString()形式。抱歉沒有編譯或測試。

void morphNumericString(char *s) 
{ 
    char *p, *end, *decimal, *nonzero; 

    // Find the last decimal point and non zero character 
    end = p = strchr(s,'\0'); 
    decimal = nonzero = NULL; 
    while(p > s) 
    { 
     p--; 
     if(!nonzero && *p!='0') 
     { 
      nonzero = p; 
     } 
     if(!decimal && *p=='.') 
     { 
      decimal = p; 
      break; // nonzero must also be non NULL, so stop early 
     } 
    } 

    // eg "4.3000" -> "4.3" 
    if(decimal && nonzero && nonzero>decimal) 
     *(nonzero+1) = '\0'; 

    // eg if(decimal) "4.0000" -> "4.0" 
    // if(!decimal) "4" -> "4.0" 
    else 
     strcpy(decimal?decimal:end, ".0"); 
} 
+0

順便說一句,@ Bill。我們必須同意對清晰度持不同意見:-) – paxdiablo 2010-02-09 04:26:33

+0

是否有可能爲sprintf()模式創建自己的函數,以便我可以將此函數與自己的代碼(如%F等)一起使用?所以%F會使用這個morphNumericString()函數來輸出它在sprintf() – Newbie 2010-02-09 12:33:19

+0

@Newbie中輸出的字符串。對不起,我發佈了,然後離開,所以沒有看到你的問題。對不起,有趣的想法,但據我所知,你不能那樣做。 – 2010-02-09 21:05:16

2

,這是不可能用標準的printf語義。在過去,我必須通過輸出到字符串(類似"%.20f")然後對字符串進行後處理來完成此操作。

像這樣的東西可能是你在找什麼:

#include <stdio.h> 

void morphNumericString (char *s) { 
    char *p; 
    int count; 

    // Find decimal point, if any. 
    p = strchr (s,'.'); 

    if (p == NULL) { 
     // No decimal, just add one fractional position. 

     strcat (s, ".0"); 
    } else { 
     // Decimal, start stripping off trailing zeros. 

     while (s[strlen(s)-1] == '0') { 
      s[strlen(s)-1] = '\0'; 
     } 

     // If all fractional positions were zero, add one. 

     if (s[strlen(s)-1] == '.') { 
      strcat (s, "0"); 
     } 
    } 
} 

 

int main (int argc, char *argv[]) { 
    char str[100]; 
    int i; 

    for (i = 1; i < argc; i++) { 
     strcpy (str, argv[i]); 
     morphNumericString (str); 
     printf ("[%s] -> [%s]\n", argv[i], str); 
    } 

    return 0; 
} 

代碼貫穿每一個它的參數,變形每一個設置。下面的記錄表明它是如何工作:

pax> ./qq 3.750000 12 12.507 47.90 56.0000000 76.0 0 

[3.750000] -> [3.75] 
[12] -> [12.0] 
[12.507] -> [12.507] 
[47.90] -> [47.9] 
[56.0000000] -> [56.0] 
[76.0] -> [76.0] 
[0] -> [0.0] 

你應該知道但是,如果使用浮點或雙精度,你得提防正常浮點錯誤。在我的系統上,3.57實際上是3.5699999999999998401,根本不會被截斷。

當然,您可以通過在sprintf中使用較少數量的輸出數字來避開該問題,這比浮點數的實際精度要低。例如,我的系統輸出爲"%.10f" 3.5700000000,其中截斷。添加以下行main

sprintf (str, "%.10f", 3.57); 
morphNumericString (str); 
printf ("[%.10f] -> [%s]\n", 3.57, str); 

sprintf (str, "%.10f", 3.0); 
morphNumericString (str); 
printf ("[%.10f] -> [%s]\n", 3.0, str); 

將導致以下補充輸出:

[3.5700000000] -> [3.57] 
[3.0000000000] -> [3.0] 

按照您的測試數據。

另一種可能性(如果您的輸入範圍和精度可以控制)是使用g格式說明符。這可以輸出f格式,其中精度爲最大數字位數(而不是像f這樣的固定數字)或指數格式(e)。

基本上,只要顯示所有信息,它就更喜歡非指數輸出格式。它只有在提供更多信息時纔會切換到指數。一個簡單的例子是格式字符串"%.4g"3.7.0000000004。前者將打印爲3.7,後者爲4e-10


更新:對於那些更關心的是性能較穩健性和可讀性,你可以嘗試以下的(不必要的在我的意見,但各有所愛):

void morphNumericString (char *s) { 
    char *p = strchr (s,'.'); 
    if (p == NULL) { 
     strcat (s, ".0"); 
     return; 
    } 

    p = &(p[strlen(p)-1]); 
    while ((p != s) && (*p == '0') && (*(p-1) != '.')) 
     *p-- = '\0'; 
} 

可能速度會更快,但鑑於我看到現代編譯器所做的極端優化,您永遠不能太確定。我傾向於首先對可讀性進行編碼,並且只在成爲問題時擔心速度(YAGNI同樣適用於性能和功能)。

+2

+1因爲我喜歡你的概念。但我不喜歡你的代碼。我知道性能很少是一個問題,但仍然strlen()的內部循環讓一位老程序員不寒而慄(想想O(n^2))。爲什麼strcat(s,「。0「)兩次有效地實現相同的條件?爲什麼strcat()在所有的情況下,因爲它必須找到字符串的末尾,並且我們從結尾進行掃描,所以我們知道它在哪裏? 我不能很好在評論中寫入替代代碼,所以我已經在我自己的回答中加入了 – 2010-02-09 03:45:00

+0

@Bill,你應該把它當作概念來考慮,那麼我通常只會在出現問題時進行優化, 20個字符的字符串已經足夠接近零而不會造成堵塞答案,我沒有兩次跟蹤同一個事件,一個是沒有句點的字符串爲「.0」,另一個爲「0」我將發佈一個「優化」版本,以保持你的快樂:-) – paxdiablo 2010-02-09 04:20:29

+0

你不能也使用'p =&( p [strlen(p)] - 1)',所以你不必迭代和'strchr'呢? – dreamlax 2010-02-09 04:52:13

0
void tidyFloatRepresentation(char *s) 
{ 
    size_t end = strlen (s); 
    size_t i = end - 1; 
    char *lastZero = NULL; 

    while (i && s[i] == '0') lastZero = &s[i--]; 
    while (i && s[i] != '.') i--; 

    if (lastZero && s[i] == '.') 
    { 
     if (lastZero == &s[i] + 1) 
      *(lastZero + 1) = '\0'; 
     else 
      *lastZero = '\0'; 
    } 
    else 
    { 
     strcpy (&s[end + 1], ".0"); 
    } 
} 

當輸入與一個小數點結束這將失敗,但是在大多數情況下,它將截斷(或附加)適當。

0

我的做法是:

  1. 實現一個函數裝飾(焦三)消除痕跡 'C',爲examaple:

    無效修剪(的std :: string &海峽,焦炭Ç ){ size_t len = str.length();

    const char *s = str.c_str(); 
    const char *p = s + len - 1; 
    while (p != s && *p == c) { 
        -- p; 
    } 
    ++ p; 
    size_t end = p - s; 
    
    str = str.substr(0, end); 
    

    }

  2. 炭的buf [32]; printf(buf,「%f」,0.01); std :: string s(buf); trim(buf,'0');

0

這是另一個字符串修改函數。我做了測試。

它比比爾和暗黑破壞神的長,但它處理尾隨9和0,並應該表現良好。

在圓點後留下一個尾隨零。你必須截斷使用sprintf才能得到正確的結尾9。

void morphNumericString(char *s) { 
    char *point = s; 
    while (* point && * point != '.') ++ point; 
    char *last = strchr(point, 0); 
    if (point == last) { 
     * point = '.'; 
     ++ last; 
    } 
    if (point == last - 1) { 
     * last = '0'; 

    } else { 
     -- last; 
     if (* last == '0') { 
      while (* last == '0') -- last; 

     } else if (* last == '9') { 
      while (* last == '9' || * last == '.') { 
       if (* last == '9') * last = '0'; 
       -- last; 
      } 
      (* last) ++; 
     } 
     if (last < point + 1) last = point + 1; 
    } 
    * ++ last = 0; 
} 

編輯:哎呀,失敗像999.999輸入。作爲練習留給讀者; 5)

0

可能更容易直接計算的小數部分:

double value= -3.57; 

double int_part; 
double frac= modf(value, &int_part); 

int64 int_part_as_int= int_part; 
int significant_digits= 10; 
int64 fractional_scale= pow(10., significant_digits); 
int64 fraction_magnitude= fabs(frac)*fractional_scale + 0.5; 

fractional_magnitude/fractional_scale將四捨五入爲significant_digits SIG的無花果的分數。即使有雙打,這也保證不會溢出。

格式化分數應該很簡單。

相關問題