Chinaunix首页 | 论坛 | 博客
  • 博客访问: 298319
  • 博文数量: 63
  • 博客积分: 814
  • 博客等级: 军士长
  • 技术积分: 700
  • 用 户 组: 普通用户
  • 注册时间: 2010-05-09 15:46
文章分类

全部博文(63)

文章存档

2017年(1)

2016年(4)

2015年(13)

2014年(9)

2012年(3)

2011年(33)

分类: C/C++

2011-09-28 17:38:18

这是 C 语言中最经常被提出的问题之一,这个问题在 C FAQ 列表中的问题 14.6 中有过简短的讨论。其中的解答给出了如下的表达式:
    (int)(x+0.5)
但也指出这种方法对负数无效。此外,一个更为明智的方法是用 long 替代 int。

下面我们来更进一步地解释这个问题。

首先,这个问题的解决方案取决于我们所需要的转换方式:是截断转换还是舍入转换;另一方面,它基本与我们需要转换的浮点数类型无关──无论是 float 还是 double,甚至是 long double。

有时人们觉得一个浮点变量的值和一个整型变量的值可以完全一样地可表示,你可能相信 x 值为 100.0 时我们只要把它转换为整型就会得到整数 100。但在任何时候,你都不应依赖于期望一个浮点数的值能够与一个整型数的值完全相等,你真正所需要的可能是四舍五入。

截 断转换的意思是抛弃所有的小数部分,例如 3.9 将被转换为 3,这种转换是 C 语言中将浮点数转换为整型数的默认方式,也就是说无论在什么时候,只要将浮点数转换为整型数,采用的都是这种方式。关于这种转换何时发生,有一些特殊的规 定,这里我们仅指出赋值时所发生的转换,比如
    i = x;
其中 i 是一个整型数,x 是一个浮点数。当然,在显式类型转换的情况下,这样的转换也会发生,比如
    (int) x

舍入转换是指获取与给定浮点数最为接近的整型数,因此 3.9 应被转换为 4,这才是人们提出我们正在解决的这个问题时所真正需要的。对于舍入转换,我们没有直接的工具(比如运算符或者库函数),严格地说,舍入转换并非与 C 标准里所定义的转换在同一意义下的转换。

对于正的浮点数,最简单的四舍五入方法就是用这样的一个表达式
    (long) (x+0.5)
但是如果表达式对负数有效的话会更好,即使在你看来负数的情况不会发生。这意味着你可以用一个条件表达式:
    x >= 0 ? (long)(x+0.5) : (long)(x-0.5)
这个表达式的返回值就是与浮点变量 x 的值最接近的整数值。

如果需要大量地使用舍入转换,则可以写这样的一个宏:
    #define round(x) ((x)>=0?(long)((x)+0.5):(long)((x)-0.5))
这可以在某种程度上使代码更具可读性。

注意到这样的转换会将 1.5 变为 2 但却将 -1.5 变为 -2,那么对于这样正好处于两个整数之间的浮点数,你可能需要做一些其它的处理,但这在实际当中并不十分重要。

需要小心的是,将一个浮点数转换为一个整型数可能导致上溢,但大多数的实现都没有进行相关的判断。用 long 替代 int 会给出一个更宽的范围(建议使用 long),但仍然比浮点数的范围要小得多。

如果效率不是至关重要的话,则可以定义这样的一个函数(而不是简单地写一个 #define),使你的程序更具鲁棒性:
    long round(double x) {
       assert(x >= LONG_MIN-0.5);
       assert(x <= LONG_MAX+0.5);
       if (x >= 0)
          return (long) (x+0.5);
       return (long) (x-0.5);
    }
如果在意效率的话,可以写这样一个宏
    #define round(x) ((x) < LONG_MIN-0.5 || (x) > LONG_MAX+0.5 ?\
    error() : ((x)>=0?(long)((x)+0.5):(long)((x)-0.5))
这要求在程序中有 #include ,并且有一个处理错误的函数 error,其返回值为 long 类型。
阅读(1034) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~