如何将浮点数(例如37.777779)舍入到C中的两位小数(37.78)?
答案 0 :(得分:377)
如果您只想将数字四舍五入以进行输出,那么"%.2f"
格式字符串确实是正确的答案。但是,如果您实际上想要对浮点值进行舍入以进行进一步计算,则可能会出现以下情况:
#include <math.h>
float val = 37.777779;
float rounded_down = floorf(val * 100) / 100; /* Result: 37.77 */
float nearest = roundf(val * 100) / 100; /* Result: 37.78 */
float rounded_up = ceilf(val * 100) / 100; /* Result: 37.78 */
请注意,您可能要选择三种不同的舍入规则:向下舍入(即,在两位小数后截断),四舍五入到最接近,并向上舍入。通常,你想要舍入到最近的。
正如其他几个人所指出的,由于浮点表示的怪癖,这些舍入值可能不是“明显的”十进制值,但它们将非常接近。
关于四舍五入的更多(更多!)信息,尤其是关于舍入到最近的打破平局规则,请参阅the Wikipedia article on Rounding。
答案 1 :(得分:67)
printf("%.2f", 37.777779);
答案 2 :(得分:39)
假设您正在讨论打印值,那么Andrew Coleson和AraK的回答是正确的:
printf("%.2f", 37.777779);
但请注意,如果你的目标是将数字四舍五入到内部使用的37.78(例如与另一个值进行比较),那么这不是一个好主意,因为浮点数的工作方式:你通常不希望对浮点进行相等比较,而是使用目标值+/- sigma值。或者将数字编码为具有已知精度的字符串,并进行比较。
请参阅Greg Hewgill's answer to a related question中的链接,其中还列出了您不应使用浮点进行财务计算的原因。
答案 3 :(得分:23)
这个怎么样:
float value = 37.777779;
float rounded = ((int)(value * 100 + .5) / 100.0);
答案 4 :(得分:19)
printf("%.2f", 37.777779);
如果你想写C-string:
char number[24]; // dummy size, you should take care of the size!
sprintf(number, "%.2f", 37.777779);
答案 5 :(得分:11)
没有办法将float
舍入到另一个float
,因为舍入的float
可能无法表示(浮点数的限制)。例如,假设您将37.777779舍入到37.78,但最接近的可表示数字是37.781。
但是,可以使用格式字符串函数“舍入”float
。
答案 6 :(得分:8)
另外,如果你使用的是C ++,你可以创建一个这样的函数:
string prd(const double x, const int decDigits) {
stringstream ss;
ss << fixed;
ss.precision(decDigits); // set # places after decimal
ss << x;
return ss.str();
}
然后,您可以在小数点后输出任意两个myDouble
n
个位置,代码如下:
std::cout << prd(myDouble,n);
答案 7 :(得分:7)
您仍然可以使用:
float ceilf(float x); // don't forget #include <math.h> and link with -lm.
示例:
float valueToRound = 37.777779;
float roundedValue = ceilf(valueToRound * 100) / 100;
答案 8 :(得分:6)
在C ++中(或在C中使用C风格的强制转换),您可以创建函数:
/* Function to control # of decimal places to be output for x */
double showDecimals(const double& x, const int& numDecimals) {
int y=x;
double z=x-y;
double m=pow(10,numDecimals);
double q=z*m;
double r=round(q);
return static_cast<double>(y)+(1.0/m)*r;
}
然后std::cout << showDecimals(37.777779,2);
会产生:37.78。
显然你并不需要在该函数中创建所有5个变量,但我将它们留在那里以便您可以看到逻辑。可能有更简单的解决方案,但这对我很有用 - 特别是因为它允许我根据需要调整小数位后的位数。
答案 9 :(得分:5)
为此始终使用printf
函数家族。即使您希望以浮点数的形式获取值,也最好使用snprintf
将舍入后的值作为字符串获取,然后使用atof
解析回去:
#include <math.h>
#include <stdio.h>
#include <stddef.h>
#include <stdlib.h>
double dround(double val, int dp) {
int charsNeeded = 1 + snprintf(NULL, 0, "%.*f", dp, val);
char *buffer = malloc(charsNeeded);
snprintf(buffer, charsNeeded, "%.*f", dp, val);
double result = atof(buffer);
free(buffer);
return result;
}
之所以这样说,是因为currently top-voted answer和其他几种方法所显示的方法- 乘以100,四舍五入为最接近的整数,然后再除以100,则存在两种缺陷:
为说明第一种错误-舍入方向有时是错误的-尝试运行此程序:
int main(void) {
// This number is EXACTLY representable as a double
double x = 0.01499999999999999944488848768742172978818416595458984375;
printf("x: %.50f\n", x);
double res1 = dround(x, 2);
double res2 = round(100 * x) / 100;
printf("Rounded with snprintf: %.50f\n", res1);
printf("Rounded with round, then divided: %.50f\n", res2);
}
您将看到以下输出:
x: 0.01499999999999999944488848768742172978818416595459
Rounded with snprintf: 0.01000000000000000020816681711721685132943093776703
Rounded with round, then divided: 0.02000000000000000041633363423443370265886187553406
请注意,我们开始使用的值小于0.015,因此将其舍入到小数点后两位的数学正确答案为0.01。当然,0.01不能精确地表示为double,但是我们希望我们的结果是最接近0.01的double。使用snprintf
可以得到结果,但是使用round(100 * x) / 100
可以得到0.02,这是错误的。为什么?因为100 * x
的结果恰好是1.5。因此,乘以100会更改正确的取整方向。
为说明第二种错误-由于* 100
和/ 100
并非真正相反,有时结果是错误的-我们可以做一个类似的练习数量很大:
int main(void) {
double x = 8631192423766613.0;
printf("x: %.1f\n", x);
double res1 = dround(x, 2);
double res2 = round(100 * x) / 100;
printf("Rounded with snprintf: %.1f\n", res1);
printf("Rounded with round, then divided: %.1f\n", res2);
}
我们的数字现在甚至没有分数。它是一个整数值,仅以double
类型存储。因此,四舍五入后的结果应该与开始时的数字相同,对吧?
如果您运行上述程序,则会看到:
x: 8631192423766613.0
Rounded with snprintf: 8631192423766613.0
Rounded with round, then divided: 8631192423766612.0
糟糕。我们的snprintf
方法再次返回正确的结果,但是“乘-然后-舍入-然后-除”方法失败。这是因为8631192423766613.0 * 100
的数学正确值863119242376661300.0
不能精确表示为双精度;最接近的值为863119242376661248.0
。将其除以100后,得到8631192423766612.0
-与开始时的数字不同。
希望这足以证明,使用roundf
舍入到小数位数是无效的,而应该使用snprintf
。如果您觉得这是骇人听闻的骇客,也许您会以basically what CPython does为前提而放心。
答案 10 :(得分:4)
double f_round(double dval, int n)
{
char l_fmtp[32], l_buf[64];
char *p_str;
sprintf (l_fmtp, "%%.%df", n);
if (dval>=0)
sprintf (l_buf, l_fmtp, dval);
else
sprintf (l_buf, l_fmtp, dval);
return ((double)strtod(l_buf, &p_str));
}
此处n
是小数位数
示例:
double d = 100.23456;
printf("%f", f_round(d, 4));// result: 100.2346
printf("%f", f_round(d, 2));// result: 100.23
答案 11 :(得分:4)
使用float roundf(float x)
。
“舍入函数将它们的参数围绕浮点格式的最接近的整数值进行处理,将中间情况从零点四舍五入,无论当前的舍入方向如何。” C11dr§7.12.9.5
#include <math.h>
float y = roundf(x * 100.0f) / 100.0f;
根据您的float
实施情况,可能看似中途的数字不是。因为浮点通常是基于2的。此外,在所有“中途”情况下精确舍入到最接近的0.01
是最具挑战性的。
void r100(const char *s) {
float x, y;
sscanf(s, "%f", &x);
y = round(x*100.0)/100.0;
printf("%6s %.12e %.12e\n", s, x, y);
}
int main(void) {
r100("1.115");
r100("1.125");
r100("1.135");
return 0;
}
1.115 1.115000009537e+00 1.120000004768e+00
1.125 1.125000000000e+00 1.129999995232e+00
1.135 1.134999990463e+00 1.139999985695e+00
虽然“1.115”在1.11和1.12之间是“中途”,但当转换为float
时,该值为1.115000009537...
并且不再是“中途”,而是接近1.12并且舍入到最近的float
1.120000004768...
“1.125”在1.12和1.13之间是“中途”,当转换为float
时,该值正好是1.125
并且是“中途”。由于与偶数规则的联系并向最近float
1.129999995232...
的{{1}}进行轮次,它向1.13方向转向
虽然“1.135”在1.13和1.14之间是“中途”,但当转换为float
时,该值为1.134999990463...
并且不再是“中途”,而是接近1.13和舍入到最近的float
1.129999995232...
如果使用代码
y = roundf(x*100.0f)/100.0f;
虽然“1.135”在1.13和1.14之间是“中途”,但当转换为float
时,该值为1.134999990463...
并且不再是“中途”,但接近1.13但是由于float
与1.139999985695...
的精确度较为有限,错误会轮到float
double
。根据编码目标,可能会将此错误值视为正确。
答案 12 :(得分:3)
我用这个宏来舍入浮点数。 将其添加到标题/文件
中#define ROUNDF(f, c) (((float)((int)((f) * (c))) / (c)))
以下是一个例子:
float x = ROUNDF(3.141592, 100)
x等于3.14:)
答案 13 :(得分:2)
#define roundz(x,d) ((floor(((x)*pow(10,d))+.5))/pow(10,d))
a = 8.000000
sqrt(a) = r = 2.828427
roundz(r,2) = 2.830000
roundz(r,3) = 2.828000
roundz(r,5) = 2.828430
答案 14 :(得分:0)
让我首先尝试证明我为这个问题添加另一个答案的理由。在一个理想的世界里,四舍五入并不是什么大问题。但是,在实际系统中,您可能需要应对可能导致舍入的几个问题,这可能与您的预期不符。例如,您可能正在执行财务计算,其中最终结果被舍入并以2位小数显示给用户;这些相同的值以固定的精度存储在一个数据库中,该数据库可能包含2个以上的小数位(由于各种原因;没有最佳的位置数量......取决于每个系统必须支持的特定情况,例如价格很小的物品是每单位一分钱的分数);并且,对结果为正/负epsilon的值执行浮点计算。多年来,我一直在面对这些问题并制定自己的战略。我不会声称我已经面对每一个场景或得到了最好的答案,但下面是我迄今为止克服这些问题的方法的一个例子:
假设使用以下舍入函数/方法,6个小数位被认为是用于计算浮点数/双精度(特定应用程序的任意决定)的足够精度:
double Round(double x, int p)
{
if (x != 0.0) {
return ((floor((fabs(x)*pow(double(10.0),p))+0.5))/pow(double(10.0),p))*(x/fabs(x));
} else {
return 0.0;
}
}
为了呈现结果,舍入到2个小数位可以执行:
double val;
// ...perform calculations on val
String(Round(Round(Round(val,8),6),2));
对于val = 6.825
,结果为预期的6.83
。
对于val = 6.824999
,结果为6.82
。这里假设计算结果恰好是6.824999
,小数点后7位为零。
对于val = 6.8249999
,结果为6.83
。在这种情况下,第7个小数位为9
会导致Round(val,6)
函数给出预期结果。对于这种情况,可能有任意数量的尾随9
。
对于val = 6.824999499999
,结果为6.83
。舍入到第8个小数位作为第一步,即Round(val,8)
,处理一个令人讨厌的情况,其中计算的浮点结果计算为6.8249995
,但在内部表示为6.824999499999...
。
最后,问题... val = 37.777779
中的示例会产生37.78
。
这种方法可以进一步概括为:
double val;
// ...perform calculations on val
String(Round(Round(Round(val,N+2),N),2));
其中N是浮点数/双精度数上所有中间计算的精度。这也适用于负值。我不知道这种方法在数学上是否适用于所有可能性。
答案 15 :(得分:0)
...或者您可以在没有任何库的情况下以老式的方式进行操作:
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return tableView == tableViewQR ? qRinstructionList.count : instructionList.count
}
如果要从号码中删除多余的信息,当然可以。
答案 16 :(得分:0)
用于舍入数字的简单C代码:
float n = 3.56;
printf("%.f", n);
这将输出:
4
答案 17 :(得分:-1)
此函数获取数字和精度并返回舍入的数字
float roundoff(float num,int precision)
{
int temp=(int )(num*pow(10,precision));
int num1=num*pow(10,precision+1);
temp*=10;
temp+=5;
if(num1>=temp)
num1+=10;
num1/=10;
num1*=10;
num=num1/pow(10,precision+1);
return num;
}
通过左移点并检查大于5的条件,将浮点数转换为int。