ACM模版

abs()函数对比

在C\C++的<math.h>和<cmath>中均有abs的实现,而今天心血来潮,另外手动实现了两个abs()函数,用来做一下对比,一种是通过关系运算符判断正负求解,一种是通过位运算求解,仔细看哦,很值得回味的测试……(PS:为了增大区别,每个函数的运算次数为MAXN次)。

#include <cstdio>
#include <iostream>
#include <ctime>
#include <cmath>

using namespace std;

const int MAXN = 1000000;

int abs_1(int n)
{
    if (n < 0)
    {
        return -n;
    }
    else
    {
        return n;
    }
}

int abs_2(int n)
{
    return (n ^ (n >> 31)) - (n >> 31);
}

int main()
{
    int a, b = 0;
    while (cin >> a)
    {
        // 系统abs()函数测试
        long long start = clock();
        for (int i = 0; i < MAXN; i++)
        {
            b = abs(a);
        }
        long long end = clock();
        cout << "abs() : " << a << ' ' << b << ' ' << end - start << '\n';

        // 判断正负abs()函数实现
        start = clock();
        for (int i = 0; i < MAXN; i++)
        {
            b = abs_1(a);
        }
        end = clock();
        cout << "abs_1() : " << a << ' ' << b << ' ' << end - start << '\n';

        // 位运算abs()函数实现
        start = clock();
        for (int i = 0; i < MAXN; i++)
        {
            b = abs_2(a);
        }
        end = clock();
        cout << "abs_2() : " << a << ' ' << b << ' ' << end - start << '\n';
    }

    return 0;
}

经过多次测试,发现时间差距还是挺明显的,当然对于一次abs()而言,差距可以视为没有吧,当然这么说不太严谨。

根据数据我们不难发现,abs_1()abs_2()对于正负数的处理时间差别还是挺大的,但是令人好奇的是<cmath>中abs()对于正负数的处理时间却几乎相等,至于为什么,就麻烦好奇心比我强的人去挖掘源码吧,然后告诉我怎么实现的。

接着呢,我想abs_1()不用分析了,有脑子的都看得懂,而对于位运算搞定的abs_2()来说,可读性真的不算高,对于不经常和位运算打交道的人而言,挺绕的。首先我们定义的是4个字节的32位2进制有符号整形,也就是int型,原谅我把一个整形形容的那么复杂,好了,言归正传,因为有符号,所以我们知道第32位是符号位,所以n>>31最后得到的就是符号位的值,如果是负数,结果为-1,反之则为0。那么如果n为正数,n^0-0=n,而如果为负数,n^(-1)的结果也就是|n|-1,所以最后再-(-1)也就是n的绝对值了,我想这里不用过多解释,直接用一组数据写写画画就知道了,真的不知道,那就麻烦你去看看位运算了,因为今天关键不是要搞位运算,所以,我还是不会解释,毕竟我是一个懒人。

由于闲着也是数星星、数羊,于是我又进行了一个测试,测试<cmath>与<math.h>中abs()的区别,上面的数据已经有了前者的测试结果,所以鉴于我懒,我只再给出<math.h>的测试数据。

虽然和前边的数据对比感觉不明显,但是还是有些许区别的,我认为<math.h>的要比<cmath>的abs()稳定性差些。大概这就是为什么C++推荐使用的头文件是<cmath>,而<math.h>只是为了兼容。

当然,以上所有测试数据都是基于我的机子,我的测试样本,也许有的地方不够准确,那么我只能将其归咎于我的失责,但是一贯喜欢找客观原因的我会告诉你:测试样本不够大,测试样本分布不够均匀。但是,懒惰的我,从不会因为知道这些就去重测,因为,现在都三点了,我还有线代没看/(ㄒoㄒ)/~~,看过线代后还要看会儿代码大全……如果非要说我不够严谨,没有治学精神,那么我也不得不承认,毕竟这种放大了一百万倍后产生的差别还如此甚微的,真的没有太大锱铢必较的价值。

测试了这么大会儿,虽然测试数据上有些不够严谨,但是我们基本上可以得出,位运算是最牛逼的!!!对于某种特定的需求,这里的确可以产生可见的优化。

最后,跟上一句,倒数第三段是在浪费你们时间,我只是给自己找一个随性一些的借口,当然,这一段也是废话。