C++自己实现abs

         之前没有注意过这个问题,刚好做题遇到了abs( -2147483648)= -2147483648的情况,转一篇如下。


         这些天恰好要用到一个绝对值的函数。好吧,你会说这个直接用std::abs不就行了吗?对的,一开始我也是这样用的。但是如果去求最小的那个int的值的绝对值,就会导致输出不正确。如:

int min_int = -2147483648;
cout<<std::abs(min_int)<<endl;

    得到的结果仍然是-2147483648!恰好我的程序有可能出现这样的情况.所以需要自己去完成一个。


    1、第一个版本:

unsigned int __abs(int value)
{
    return (value >= 0) ? value : -value;
}

    仍然是std::abs的老路,不可取!


    2、第二个版本:

   

#include <limits>

unsigned int __abs(int value)

{

    return (std::numeric_limits<int>::min() == value || value >= 0) ? value : -value;

}


    这个版本比较简洁,可移植性也很高.std::numeric_limits<int>::min()返回当前系统下int值的最小值,能够自适应int的内存宽度返回准确的值.当value和最小的int值相等或者value不为负数时,我们直接进行位对位的拷贝--因为unsigned int没有符号位,所以完全可行的.当value为除最小值外的负数时,直接取相反数即可.

    但这个版本需要用到两次条件判断,能不能再优化一下呢?所以出现了:


    3、第三个版本:

   

unsigned int __abs(int value)
{
    unsigned int copyed_value = value;
    return (copyed_value > 0x80000000) ? -value : copyed_value;
}

    因为32位下最小的int值为0x80000000--最高位符号位为1.当位对位拷贝到unsigned int中时,仍然是这个值.但其他的负数除了最高位为1外,其余位置也有值,比如-1的16进制表示为:0x80000001.所以,我们先执行位对位的拷贝,到copyed_value中.所以出现了判断情况:

    (1)如果copyed_value是大于0x80000000的,说明value是负数,所以我们直接取相反数(-value);

    (2)如果copyed_value是等于0x80000000的,说明value恰好是最小的那个负数,执行位对位拷贝后,copyed_value中存放的就是value的绝对值,所以返回copyed_value;

    (3)如果copyed_value是小于0x80000000,说明value为正数.直接去alue或者copyed_value即可.

    通过分析,我们将(2)和(3)合并到一起,返回copyed_value.所以,采取第三种方案,就只有一次比较操作.比第二种方案省一次.但是这种方案第一眼看去可能易读性上不是很好.

    权衡三种方案,应该说各有利弊.三种情况各有适用的地方.如果你的函数不考虑最小int值的绝对值,可以采用std::abs即可;如果需要考虑但不必担心性能问题,那么第二种方案是你最好的选择!但如果你既要考虑最小int值的绝对值问题,又要考虑性能问题,建议采用第三个方案.

    这个问题虽然简单,但里面透射出来的东西可真不少.其实我们在编程工作中,从细节出抓起,往往能够获得很多收获.

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值