C语言如何实现浮点数的四舍五入?

play123456 2005-02-03 02:10:10
C语言对浮点数的支持总是显得比较奇怪,与0比较的时候已经相当麻烦,没想到连简单的四舍五入也总是得不到应有的结果,向高手请教:C语言中有正确的浮点数四舍五入函数么?如果没有,哪位大侠能提供这么一个函数?别告诉我floor之类的哦,它们都不能得到正确结果。谢谢!
...全文
18390 19 打赏 收藏 转发到动态 举报
写回复
用AI写文章
19 条回复
切换为时间正序
请发表友善的回复…
发表回复
play123456 2005-02-17
  • 打赏
  • 举报
回复
再多问一句,什么情况下拥到了相对误差,能不能给个实例?我测试了很多数据进行比较都用不到相对误差。
melonliu 2005-02-16
  • 打赏
  • 举报
回复
Rubi(2005上半年c,c++学习)的解答很详尽了,精度问题是在竞赛中经常遇到的,赞一个!

absError 绝对误差允许值
relError 相对误差允许值
play123456 2005-02-16
  • 打赏
  • 举报
回复
还有,您的函数bool IsEqual(float a, float b, float absError, float relError )中参数absError,relError作什么用,能解释一下吗?
play123456 2005-02-16
  • 打赏
  • 举报
回复
to Rubi(2005上半年c,c++学习) :
你的文章中讲述的很透彻,只是实现中有一点疑问:用到了除法但并没有对除数做判断,会不会出现被0除的情况导致溢出的情况?谢谢!
Rubi 2005-02-05
  • 打赏
  • 举报
回复
转贴一文章,供大家参考

浮点数的比较
在数学运算当中经常会涉及到判断两个数是否相等的情况
对于整数很好处理 A==B这样的一个语句就可以解决全部的问题
但是对于浮点数是不同的

首先,浮点数在计算机当中的二进制表达方式就决定了大多数浮点数都是无法精确的表达的
现在的计算机大部分都是数字计算机,不是模拟机,数字机的离散化的数据表示方法自然无法精确表达大部分的数据量的。

其次计算机浮点数的精度在单精度float类型下,只有7位,在进行浮点运算的时候,这个精度往往会导致运算的结果和实际期望的结果之间有误差

因为前两个原因,我们很难用 A==B来判定两个浮点数是否相同

很自然,我们可以想到 fabs(A-B) < epsilon 这样的一种判别方法
但是这种判别方法稳妥吗?
它也不稳妥。

首先, epsilon是一个绝对的数据,也就是误差分析当中说说的绝对误差
使用一个固定的数值,对于float类型可以表达的整个数域来说是不可以的
比如epsilon取值为0.0001,而a和b的数值大小也是0.0001附近的,那么显然不合适
另外对于a和b大小是10000这样的数据的时候,它也不合适,因为10000和10001也可以认为是相等的呢
适合它的情况只是a或者b在1或者0附近的时候

既然绝对误差不可以,那么自然的我们就会想到了相对误差
bool IsEqual(float a, float b, float relError ) {
return ( fabs ( (a-b)/a ) < relError ) ? true : false;
}
这样写还不完善,因为是拿固定的第一个参数做比较的,那么在调用
IsEqual(a, b, relError ) 和 IsEqual(b, a, relError ) 的时候,可能得到不同的结果
同时如果第一个参数是0的话,就有可能是除0溢出
这个可以改造
把除数选取为a和b当中绝对数值较大的即可
bool IsEqual(float a, float b, relError )
{
if (fabs(a)<fabs(b)) return ( fabs((a-b)/a) > relError ) ? true : false;
return (fabs( (a-b)/b) > relError ) ? true : false;
};

使用相对误差就很完善吗?
也不是, 在某些特殊情况下, 相对误差也不能代表全部
比如在判断空间三点是否共线的时候,使用判断点到另外两个点形成的线段的距离的方法的时候
只用相对误差是不够的,应为线段距离可能很段,也可能很长,点到线段的距离,以及线段的长度做综合比较的时候,需要相对误差和绝对误差结合的方式才可以
相对完整的比较算法应该如下:
bool IsEqual(float a, float b, float absError, float relError )
{
if (a==b) return true;
if (fabs(a-b)<absError ) return true;
if (fabs(a>b) return (fabs((a-b)/a>relError ) ? true : false;
return (fabs((a-b)/b>relError ) ? true : false;
}
这样才相对完整
htar 2005-02-05
  • 打赏
  • 举报
回复
好东西 学了
pcboyxhy 2005-02-03
  • 打赏
  • 举报
回复
考虑负数和精度是一定要的
Svny 2005-02-03
  • 打赏
  • 举报
回复
good
play123456 2005-02-03
  • 打赏
  • 举报
回复
cy_FloatCompare是浮点数与0比较的函数,假设它存在。返回值与strcmp相同。
play123456 2005-02-03
  • 打赏
  • 举报
回复
不好意思,错了。应该是:

int myround(double indata,int precision,double *outdata)
{
long pre=1,i;

for (i=0;i<precision;i++) pre=pre*10;
if ( cy_FloatCompare(indata,0.00)>0 )
*outdata=(int)((indata*pre)+0.5)/100.00;
else
*outdata=(int)((indata*pre)-0.5)/100.00;
return 0;
}
play123456 2005-02-03
  • 打赏
  • 举报
回复
感谢大伙的热心。4楼的方法很巧妙。但在负数时有问题,例如-4.9999,精确到2位小数进行四舍五入,应该是-5.00,使用4楼的方法得到-4.99。因此应当判断输入浮点数是负数还是正数,区别处理,如下:

int myround(double indata,int precision,double outdata)
{
if ( indata>0.00 )
*outdata=(int)((indata*precision*10)+0.5)/100.00;
else
*outdata=(int)((indata*precision*10)-0.5)/100.00;
return 0;
}

但是问题是浮点数与0比较的时候不能这么写,应该写成类似下面的:
int myround(double indata,int precision,double outdata)
{
if ( indata>0.005 )
*outdata=(int)((indata*precision*10)+0.5)/100.00;
else if ( indata<-0.005 )
*outdata=(int)((indata*precision*10)-0.5)/100.00;
else *outdata=0.00;
return 0;
}
这样写就对精确度提出挑战,怎样才能形成一个比较通用的比较方法呢?请高手赐教!
chinaboson 2005-02-03
  • 打赏
  • 举报
回复
被抢先,支持4楼的!
caibob 2005-02-03
  • 打赏
  • 举报
回复
outdate = ceil(indata);
jorsef1984 2005-02-03
  • 打赏
  • 举报
回复
同意4楼的,二楼的应用范围稍窄
biebie 2005-02-03
  • 打赏
  • 举报
回复
2、4楼有什么区别?
junnyfeng 2005-02-03
  • 打赏
  • 举报
回复
楼上正解
snow810211 2005-02-03
  • 打赏
  • 举报
回复
float a = 3.456; //保留到小数点后两位
float b =(int)((a * 100) + 0.5) / 100.0;

//output b = 3.46;


爱摸鱼de老邪 2005-02-03
  • 打赏
  • 举报
回复
厉害,又被抢先了
晨星 2005-02-03
  • 打赏
  • 举报
回复
float f = .....;
int i = (int)(f + 0.5);
i就是f四舍五入的结果。
课程背景Modbus 协议是工业自动化控制系统中常见的通信协议,协议的全面理解是个痛点。本课程主讲老师集10多年在Modbus协议学习、使用中的经验心得,结合当前物联网浪潮下Modbus协议开发的痛点,推出这套面向Modbus 协议初学者的课程。本课程不同于以往市面课程只是协议讲解无实现代码,而是采用讲解与实践并重的方式,结合STM32F103ZET6开发板进行手把手编程实践,十分有利于初学者学习。涵盖了学习者在Modbus协议方面会遇到的方方面面的问题,是目前全网首个对Modbus协议进行全面总结的课程。课程名称   协议讲解及实现>>课程内容1、Modbus 协议的基础。2、Modbus协议栈函数编程实现。3、Modbus协议在串行链路编程实现。4、Modbus协议在以太网链路编程实现。5、常见问题的解决方法。带给您的价值通过学习本课程,您可以做到如下:1、全面彻底的理解Modbus协议。2、理解在串行链路,以太网链路的实现。3、掌握Modbus协议解析的函数编程方法,调试工具的使用。4、掌握多个串口,网口同时运行同一个Modbus协议栈的方法。5、掌握Modbus协议下,负数,浮点数等处理方法。讲师简介许孝刚,山东大学工程硕士,副高职称,技术总监。10多年丰富嵌入式系统开发经验,国家软考“嵌入式系统设计师”。2017年获得“华为开发者社区杰出贡献者”奖励。

69,371

社区成员

发帖
与我相关
我的任务
社区描述
C语言相关问题讨论
社区管理员
  • C语言
  • 花神庙码农
  • 架构师李肯
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧