回答
效率更高,並且(在我看來)更清晰的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");
}
,這是不可能用標準的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同樣適用於性能和功能)。
+1因爲我喜歡你的概念。但我不喜歡你的代碼。我知道性能很少是一個問題,但仍然strlen()的內部循環讓一位老程序員不寒而慄(想想O(n^2))。爲什麼strcat(s,「。0「)兩次有效地實現相同的條件?爲什麼strcat()在所有的情況下,因爲它必須找到字符串的末尾,並且我們從結尾進行掃描,所以我們知道它在哪裏? 我不能很好在評論中寫入替代代碼,所以我已經在我自己的回答中加入了 – 2010-02-09 03:45:00
@Bill,你應該把它當作概念來考慮,那麼我通常只會在出現問題時進行優化, 20個字符的字符串已經足夠接近零而不會造成堵塞答案,我沒有兩次跟蹤同一個事件,一個是沒有句點的字符串爲「.0」,另一個爲「0」我將發佈一個「優化」版本,以保持你的快樂:-) – paxdiablo 2010-02-09 04:20:29
你不能也使用'p =&( p [strlen(p)] - 1)',所以你不必迭代和'strchr'呢? – dreamlax 2010-02-09 04:52:13
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");
}
}
當輸入與一個小數點結束這將失敗,但是在大多數情況下,它將截斷(或附加)適當。
我的做法是:
實現一個函數裝飾(焦三)消除痕跡 '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);
}
炭的buf [32]; printf(buf,「%f」,0.01); std :: string s(buf); trim(buf,'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)
可能更容易直接計算的小數部分:
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的無花果的分數。即使有雙打,這也保證不會溢出。
格式化分數應該很簡單。
- 1. 爲什麼它總是給零輸出?
- 2. 爲什麼sprintf()不輸出任何內容?
- 3. 「結束」是什麼意思?
- 4. 「浮出」是什麼意思?
- 5. c#中的sprintf是什麼?
- 6. 爲什麼不String.format()給我一個左零填充浮點輸出?
- 7. 爲什麼clojure在輸出結束時會出現「nil」
- 8. 什麼是嵌入式零?
- 9. 爲什麼rake任務輸出總是以測試單元結果結束?
- 10. 爲什麼Perl的sprintf不能正確地舍入浮點數?
- 11. singleInstance啓動模式:爲什麼在活動結束前調用onCreate?
- 12. 從腳本輸出結果的標準R方式是什麼?
- 13. 爲什麼FtpWebRequest恰恰在長傳輸結束時拋出WebException?
- 14. 輸出是不是有什麼期望
- 15. com.android.ide.common.process.ProcessException:用非零退出值結束1
- 16. zipalign.exe''以非零退出值結束
- 17. Matlab以多種形式輸出數字,而不是以浮點形式輸出
- 18. SphinxSearch indextool dumpdict什麼是輸出格式?
- 19. xmllint ls的輸出格式是什麼?
- 20. boost.serialization的輸出格式是什麼
- 21. mpi輸出的格式是什麼?
- 22. JModelica result_file_name輸出的格式是什麼?
- 23. 爲什麼是代理模式的結構模式,爲什麼是狀態模式的行爲模式?
- 24. 除以零的結果是什麼?
- 25. 預計{在輸出結束
- 26. sprintf代表什麼?
- 27. 輸出是什麼? (VISUAL C++在調試模式下)
- 28. 這段代碼段的輸出結果是什麼?爲什麼?
- 29. 浮動移動視圖結束後不回位
- 30. 爲什麼我在開發模式不輸出Rails.logger.info UserMailer?
順便說一句,@ Bill。我們必須同意對清晰度持不同意見:-) – paxdiablo 2010-02-09 04:26:33
是否有可能爲sprintf()模式創建自己的函數,以便我可以將此函數與自己的代碼(如%F等)一起使用?所以%F會使用這個morphNumericString()函數來輸出它在sprintf() – Newbie 2010-02-09 12:33:19
@Newbie中輸出的字符串。對不起,我發佈了,然後離開,所以沒有看到你的問題。對不起,有趣的想法,但據我所知,你不能那樣做。 – 2010-02-09 21:05:16