我想输出我的浮点数而没有结尾的零。
示例:float 3.570000应输出为3.57
并且浮动3.00000应该输出为3.0(所以这里将是例外!)
答案 0 :(得分: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
)。< / p>
基本上,只要显示所有信息,它就更喜欢非指数输出格式。只有当它能提供更多信息时,它才会切换到指数。一个简单的示例是带有"%.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 :(得分: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" );
}
答案 2 :(得分: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");
}
}
当输入以小数点结束时,这将失败,但在大多数情况下,它将适当地截断(或追加)。
答案 3 :(得分:0)
我的方法是:
实现一个函数trim(char c)来消除跟踪'c',例如:
void trim(std :: string&amp; str,char c){ 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);
}
char buf [32]; printf(buf,“%f”,0.01); std :: string s(buf); 修剪(buf,'0');
答案 4 :(得分: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一样。留给读者的练习; v)
答案 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 figs。即使有双打,也保证不会溢出。
格式化分数应该很简单。