写在前面:
读本篇文章可以解决以下问题:如何利用C语言进行算术运算?如何利用位运算来给自己的代码提速?实战代码中如何巧妙利用位运算?实现同一功能的多种写法。
1. 运算符
运算符 | 说明 | 例子 |
---|---|---|
= | 赋值运算符 | a = b; |
+ 、- 、* 、/、() | 基本四则运 | a = (b + c) * d; |
% | 求余运算符 | a = b % 2; |
&、 |、 ^、 ~ | 位运算(非常重要的一类) | a = ~b | c; |
<<、>> | 左移和右移 | a = b >>2; |
1.1 位运算
位运算均是在二进制情况下完成运算的。
1.1.1 按位与(&)
二进制位全为1结果为1,有一个为0,则为0。位数不足时,前面补0。
如:
- 2&3 --> 10 & 11 --> 10,转为十进制为2
- 8 & 3 --> 1000 & 11 --> 1000 & 0011–>0,转为十进制为0
运用场景:
判断数字n能否整除2,n & 1为1则不能整除,为0则能整除
1.1.2 按位或(|)
二进制位有一个为1,则为1,全为0则为0。位数不足时,前面补0。
如:
- 2|3 --> 10 | 11 --> 11,转为十进制为3
- 8 | 3 --> 1000 | 11 --> 1000 | 0011 -->1011,转为十进制为11
1.1.3 按位异或运算符(^)
二进制位相同为0,不同为1。位数不足时,前面补0。
如:
- 2^3 --> 10 ^ 11 --> 01,转为十进制为1
- 8 ^ 3 --> 1000 ^ 11 --> 1000 ^ 0011–>1011,转为十进制为11。
运用场景:
- ^ 是 ^ 的逆运算。
- a ^ b = c,则 c ^ b = a和c ^ a = b。
- a ^ a = 0。
- 0 ^ a = a。
1.1.4 按位取反(~)
二进制位0变为1,1变为0
如:
- ~3 --> ~11 -->11(30个1)00[补码],转为十进制为-4
补码 = ~原码 + 1
原码取反时,符号位不变
举例:
1的原码:0…0(31个0)1, ~原码: 01…1(30个1)0,补码:01…1(31个1)
-1的原码: 10…0(30个0)1, ~原码: 1…1(31个1)0,补码:1…1(32个1)
-1的补码=1原码全部取反+1
1.2 左移和右移
1.2.1 左移
左移:低位补0
左移1位,相当于扩大两倍。
如: 2 << 1,转为十进制为4.
1.2.2 右移
右移:高位补符号位
如:3 >> 1, 转为十进制为1.
2.数据类型转换
数据类型转换分为两种:强转换和弱转换
强转换:使用int,double等函数进行转换,会丢失精度。
弱转换: 使用类似3*1.0/2方法,将int类型转为double。
3.进制转换
3.1 二进制转十进制
10010=12**4+12**1=18
3.2 十六进制转十进制
8F=816**1+1516**0=143
3.3 十进制转二进制
方法1:使用短除法,直到为0,然后从下往上写;
方法2:凑数
27=16+8+2+1=24+23+21+20=11010
4.math常用的函数
写在前面:
使用下列函数,需要导入math库;
在编译时,使用一下命令
gcc test.c -lm
4.1 pow函数:指数函数
原型: double pow(double a, double b);
例子:pow(4,2)=16.0000
4.2 sqrt函数:开平方函数
原型: double sqrt(double X);
例子:pow(16)=4.0000
4.3 ceil函数:向上取整函数
原型: double ceil(double X);
例子:ceil(2.79)=3.0000
4.4 floor函数:向下取整函数
原型: double floor(double X);
例子:floor(2.79)=2.0000
4.5 abs函数:整数绝对值函数
原型:int abs(int X);
例子:abs(-2)=2
4.6 fabs函数:实数绝对值函数
原型:double fabs(double X);
例子:fabs(-2.6)=2.6
4.7 log函数:以e为底对数函数
原型:double log(double X);
例子:log(4)=1.386294
4.8 log10函数:以e为底对数函数
原型:double log10(double X);
例子:log10(4)= 0.602060
4.9 acos函数:arccos函数
原型:double acos(double X);
X为角度的弧度值
例子:acos(-1)=3.1415926
5.定宽整数类型
#include <stdio.h>
#include <inttypes.h>
int main(){
printf("%zu\n", sizeof(int64_t)); //查看内存大小
printf("%s\n", PRId64); //格式宏常量
printf("INT32_MIN : %" PRId32 ", INT32_MAX : %" PRId32 "\n", INT32_MIN, INT32_MAX); //32位整形最小最大值
printf("INT64_MIN : %" PRId64 ", INT64_MAX : %" PRId64 "\n", INT64_MIN, INT64_MAX); //64位整形最小最大值
int64_t n = 7;
printf("%+"PRId64"\n", n);
return 0;
}
6.练习题
题目1
输入一个数字a,输出其立方根。点击查看答案
题目2:
求π的值。点击查看答案
题目3:
输入一个角度值,并将其转为弧度值。点击查看答案
题目4:
循环读入两个数字a,b,并交换两个值。点击查看答案
参考答案
题目1答案
// 题目1
#include<stdio.h>
#include<math.h>
int main(){
double a;
scanf("%lf", &a);
//解法1,领会思想
printf("%lf\n", pow(a, 1.0 / 3));
//解法2
printf("%lf\n", cbrt(a));
return 0;
}
题目2答案
#include<stdio.h>
#include<math.h>
#define pi acos(-1)
// #define pi 3.14
int main(){
double a;
scanf("%lf", &a);
printf("%lf\n", a * pi / 180);
return 0;
}
题目3答案
#include<stdio.h>
#include<math.h>
#define pi acos(-1)
// #define pi 3.14
int main(){
double a;
scanf("%lf", &a);
printf("%lf\n", a * pi / 180);
return 0;
}
题目4答案
// 方法1
#include<stdio.h>
int main(){
int a, b;
while (~scanf("%d%d", &a, &b)){
printf("a is %d, b is %d\n", a, b);
int c;
c = a;
a = b;
b = c;
printf("after change: a is %d, b is %d\n", a, b);
}
return 0;
}
// 方法2
#include<stdio.h>
int main(){
int a, b;
while (~scanf("%d%d", &a, &b)){
printf("a is %d, b is %d\n", a, b);
a = a + b;
b = a - b;
a = a - b;
printf("after change: a is %d, b is %d\n", a, b);
}
return 0;
}
// 方法3
#include<stdio.h>
int main(){
int a, b;
while (~scanf("%d%d", &a, &b)){
printf("a is %d, b is %d\n", a, b);
b ^= a;
a ^= b;
printf("after change: a is %d, b is %d\n", a, b);
}
return 0;
}