int abs(int n)实现对比

本文对比了C/C++中不同实现方式的abs()函数,包括标准库<cmath>和<math.h>的实现,以及两种手动实现的方法:通过关系运算符判断正负和位运算求解绝对值。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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ㄒ)/~~,看过线代后还要看会儿代码大全……如果非要说我不够严谨,没有治学精神,那么我也不得不承认,毕竟这种放大了一百万倍后产生的差别还如此甚微的,真的没有太大锱铢必较的价值。

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

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

#include<bits/stdc++.h> using namespace std; class INT { private: bool isNeg, isNumber; std::vector<int> num; public: INT() { num.clear(); isNeg = false; isNumber = false; } INT& check() { while (num.size() > 1 && num.back() == 0)num.pop_back(); if (num[0] == 0 && num.size() == 1)isNeg = false; if (num.back() == 0)return *this; for (size_t i = 1; i < num.size(); i++) { if (num[i - 1] < 0) { num[i - 1] += 10; num[i]--; } num[i] += num[i - 1] / 10; num[i - 1] %= 10; } while (num.back() >= 10) { num.push_back(num.back() / 10); num[num.size() - 2] %= 10; } while (num.size() > 1 && num.back() == 0)num.pop_back(); return *this; } INT(int x) { num.clear(); if (x < 0)x = -x, isNeg = true; else isNeg = false; int x2 = x; while (x2 != 0) { num.push_back(x2 % 10); x2 /= 10; } isNumber = true; if (x == 0)num.push_back(0); } INT(long x) { num.clear(); if (x < 0)x = -x, isNeg = true; else isNeg = false; long x2 = x; while (x2 != 0) { num.push_back(x2 % 10); x2 /= 10; } isNumber = true; if (x == 0)num.push_back(0); } INT(long long x) { num.clear(); if (x < 0)x = -x, isNeg = true; else isNeg = false; long long x2 = x; while (x2 != 0) { num.push_back(x2 % 10); x2 /= 10; } isNumber = true; if (x == 0)num.push_back(0); } INT(unsigned x) { num.clear(); unsigned x2 = x; while (x2 != 0) { num.push_back(x2 % 10); x2 /= 10; } isNumber = true; if (x == 0)num.push_back(0); } INT(unsigned long x) { num.clear(); unsigned long x2 = x; while (x2 != 0) { num.push_back(x2 % 10); x2 /= 10; } isNumber = true; if (x == 0)num.push_back(0); } INT(unsigned long long x) { num.clear(); unsigned long long x2 = x; while (x2 != 0) { num.push_back(x2 % 10); x2 /= 10; } isNumber = true; if (x == 0)num.push_back(0); } INT(char x) { num.clear(); num.push_back(x); check(); isNumber = true; if (x == 0)num.push_back(0); } INT(std::string s) { num.clear(); isNeg = false; int leftIndex = 0, i = s.size() - 1; while (s[leftIndex] > '9' || s[leftIndex] < '0') { if (s[leftIndex] == '-')isNeg = !isNeg; leftIndex++; } num.clear(); bool flag = true; for (i = s.size() - 1; i >= leftIndex; i--) { if (s[i] > '9' || s[i] < '0') { flag = false; break; } num.push_back(s[i] - '0'); } if (flag)isNumber = true; } INT operator+() { INT res = *this; return res; } INT operator-() { INT res = *this; res.isNeg = !res.isNeg; return res; } size_t size() { return num.size(); } friend INT operator+=(INT&, INT); friend INT operator+(INT, INT); friend INT operator-=(INT&, INT); friend INT operator-(INT, INT); friend INT operator*(INT, INT); friend INT operator*=(INT&, INT); friend INT operator/(INT, INT); friend INT operator/=(INT&, INT); friend INT operator%(INT, INT); friend INT operator%=(INT&, INT); friend INT tobinary(INT); friend INT todecimal(INT); friend INT operator&(INT, INT); friend INT operator&=(INT&, INT); friend INT operator|(INT, INT); friend INT operator|=(INT&, INT); friend INT operator~(INT); friend INT operator^(INT, INT); friend INT operator^=(INT&, INT); friend INT operator<<(INT, INT); friend INT operator<<=(INT&, INT); friend INT operator>>(INT, INT); friend INT operator>>=(INT&, INT); friend std::ostream& operator<<(std::ostream&, const INT&); friend std::istream& operator>>(std::istream&, INT&); friend bool operator==(const INT &a, const INT &b); friend bool operator!=(const INT &a, const INT &b); friend bool operator<(const INT &a, const INT &b); friend bool operator>(const INT &a, const INT &b); friend bool operator<=(const INT &a, const INT &b); friend bool operator>=(const INT &a, const INT &b); friend bool operator&&(const INT &a, const INT &b); friend bool operator||(const INT &a, const INT &b); friend bool operator!(const INT &a); friend INT pow(INT, INT); friend INT abs(INT); protected: friend INT div(INT, INT, bool); }; std::istream& operator>>(std::istream& is, INT& n) { std::string s; is >> s; n.isNeg = false; int leftIndex = 0, i = s.size() - 1; while (s[leftIndex] > '9' || s[leftIndex] < '0') { if (s[leftIndex] == '-')n.isNeg = !n.isNeg; leftIndex++; } n.num.clear(); for (i = s.size() - 1; i >= leftIndex; i--) { if (s[i] > '9' || s[i] < '0') { break; } n.num.push_back(s[i] - '0'); } if (i <= leftIndex)n.isNumber = true; return is; } std::ostream& operator<<(std::ostream& os, const INT& n) { if (!n.isNumber)os << "error"; else { if (n.isNeg)os << "-"; for (int i = n.num.size() - 1; i >= 0; i--)os << n.num[i]; } return os; } bool operator==(const INT& a, const INT& b) { if (a.num.size() != b.num.size())return false; if (a.isNeg != b.isNeg)return false; for (int i = a.num.size() - 1; i >= 0; i--) if (a.num[i] != b.num[i])return false; return true; } bool operator!=(const INT &a, const INT &b) { return !(a == b); } bool operator<(const INT &a, const INT &b) { if (a.isNeg || b.isNeg) { if (a.isNeg && !b.isNeg)return true; if (!a.isNeg && b.isNeg)return false; if (a.num.size() != b.num.size())return a.num.size() > b.num.size(); for (int i = a.num.size() - 1; i >= 0; i--) if (a.num[i] != b.num[i])return a.num[i] > b.num[i]; } else { if (a.num.size() != b.num.size())return a.num.size() < b.num.size(); for (int i = a.num.size() - 1; i >= 0; i--) if (a.num[i] != b.num[i])return a.num[i] < b.num[i]; } return 0; } bool operator>(const INT &a, const INT &b) { return b < a; } bool operator<=(const INT &a, const INT &b) { return !(a > b); } bool operator>=(const INT &a, const INT &b) { return !(a < b); } bool operator&&(const INT &a, const INT &b) { return (a != 0) && (b != 0); } bool operator||(const INT &a, const INT &b) { return (a != 0) || (b != 0); } bool operator!(const INT &a) { return !(a != 0); } INT operator+=(INT &a, INT b) { if (!a.isNeg && b.isNeg)return a = (a -= (-b)); if (a.isNeg && !b.isNeg)return a = (b -= (-a)); if (a.num.size() < b.num.size())a.num.resize((int)b.num.size(), 0); for (size_t i = 0; i != b.num.size(); i++)a.num[i] += b.num[i]; return a.check(); } INT operator+(INT a, INT b) { return a += b; } INT operator-=(INT &a, INT b) { if (b.isNeg)return a = (a + (-b)); if (a.isNeg)return a = -((-a) + b); if (a < b) { INT t; t = a; a = b; b = t; a.isNeg = true; } if (a.num.size() < b.num.size())a.num.resize((int)b.num.size(), 0); for (size_t i = 0; i != b.num.size(); i++) { a.num[i] -= b.num[i]; if (a.num[i] < 0) { a.num[i] += 10; a.num[i + 1]--; } } return a.check(); } INT operator-(INT a, INT b) { return a -= b; } INT operator*(INT a, INT b) { INT ans(0); if (a.isNeg == b.isNeg)ans.isNeg = false; else ans.isNeg = true; ans.num.resize((int)a.num.size() + b.num.size(), 0); for (size_t i = 0; i < a.num.size(); i++) { for (size_t j = 0; j < b.num.size(); j++) { ans.num[i + j] += a.num[i] * b.num[j]; } } return ans.check(); } INT operator*=(INT& a, INT b) { return a = a*b; } INT div(INT a, INT b, bool mode) { INT cur(0); INT quo(0); cur.num.pop_back(); quo.isNumber = true; if (a.isNeg == b.isNeg)quo.isNeg = false; else quo.isNeg = true; cur.isNeg = a.isNeg; quo.num.resize((int)a.num.size(), 0); for (int i = a.num.size() - 1; i >= 0; i--) { cur = cur * 10 + a.num[i]; while (cur >= b) { cur -= b; quo.num[i]++; } } if (quo == 0)quo.isNeg = false; if (cur == 0)cur.isNeg = false; if (!mode)return quo.check(); else return cur.check(); } INT operator/(INT a, INT b) { return div(a, b, 0); } INT operator/=(INT& a, INT b) { return a = div(a, b, 0); } INT operator%(INT a, INT b) { return div(a, b, 1); } INT operator%=(INT& a, INT b) { return a = div(a, b, 1); } INT operator++(INT &a) { return a += 1; } INT operator--(INT &a) { return a -= 1; } INT operator++(INT &a, int) { INT t = a; a += 1; return t; } INT operator--(INT &a, int) { INT t = a; a -= 1; return t; } INT tobinary(INT a) { INT ret; ret.isNeg = a.isNeg; ret.isNumber = a.isNumber; while (a != 0) { ret.num.push_back(a.num[0] % 2); a /= 2; } if (ret.isNeg) { for (size_t i = 0; i < ret.num.size(); i++)ret.num[i] = !ret.num[i]; ret.num[0]++; size_t i = 0; while (ret.num[i] > 1 && i + 1 < ret.num.size())ret.num[i + 1]++, ret.num[i++] %= 2; if (ret.num.back() > 1)ret.num.push_back(1), ret.num[ret.num.size() - 2] = ret.num.back() % 2; } return ret; } INT todecimal(INT a) { INT res(0); if (a.isNeg) { a.num[0]--; int i = 0; while (res.num[i] < 0)res.num[i + 1]--, res.num[i++] += 2; for (size_t i = 0; i < a.num.size(); i++)a.num[i] = !a.num[i]; } for (int i = a.num.size() - 1; i >= 0; i--)res = res * 2 + a.num[i]; res.isNeg = a.isNeg; return res.check(); } INT operator&(INT a, INT b) { a = tobinary(a); b = tobinary(b); INT res = a; if (!res.isNeg)res.num.resize((int)b.num.size(), 0); else res.num.resize((int)b.num.size(), 1); for (size_t i = 0; i < res.num.size(); i++)res.num[i] &= b.num[i]; res.isNeg &= b.isNeg; res = todecimal(res); return res.check(); } INT operator&=(INT& a, INT b) { return a = a&b; } INT operator|(INT a, INT b) { a = tobinary(a); b = tobinary(b); INT res = a; if (!res.isNeg)res.num.resize((int)b.num.size(), 0); else res.num.resize((int)b.num.size(), 1); for (size_t i = 0; i < res.num.size(); i++)res.num[i] |= b.num[i]; res.isNeg |= b.isNeg; res = todecimal(res); return res.check(); } INT operator|=(INT& a, INT b) { return a = a | b; } INT operator~(INT a) { a = tobinary(a); INT res = a; for (size_t i = 0; i < res.num.size(); i++)res.num[i] = !res.num[i]; res.isNeg = !res.isNeg; res = todecimal(res); return res.check(); } INT operator^(INT a, INT b) { a = tobinary(a); b = tobinary(b); INT res = a; if (!res.isNeg)res.num.resize((int)b.num.size(), 0); else res.num.resize((int)b.num.size(), 1); for (size_t i = 0; i < res.num.size(); i++)res.num[i] ^= b.num[i]; res.isNeg ^= b.isNeg; res = todecimal(res); return res.check(); } INT operator^=(INT& a, INT b) { return a = a^b; } INT abs(INT a) { return a < 0 ? -a : a; } INT pow(INT a, INT b) { INT res = 1; while (b != 0) { if (b.num[0] % 2)res *= a; a *= a; b /= 2; } return res; } INT operator<<(INT a, INT b) { return a*pow(2, b); } INT operator<<=(INT& a, INT b) { return a = a << b; } INT operator>>(INT a, INT b) { return a / pow(2, b); } INT operator>>=(INT& a, INT b) { return a = a >> b; } INT a,b; INT _gcd(INT a,INT b){ while(a%b!=0){ INT x=a%b; a=b; b=x; } return b; } 给此代码添加压位功能
最新发布
07-14
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值