C语言符号之最终章


在这里插入图片描述

🌈操作符++

  • 细节

🚀比如a++,我们经常听到有人这么说:先使用,后++(自增)。 但其实a++要不要使用取决于有没有人用。如下图:

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int main()
{
	int a = 0;
	int b = 1;

	a++;//没有人用

	int c = b++;//有人用
	return 0;
}

在这里插入图片描述

🚀结论:a++完整的含义是先使用,在自增。如果没有变量接收,那么直接自增(或者所谓使用,就是读取进寄存器,然后没有
然后)

🌈复杂表达式

🚀像(++i)+(++i)+(++i)这个表达式的结果,不同编译器下的结果可能不一样 。下面以VS为例:

  • 代码和反汇编
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int main()
{
	int i = 1;
	int j = (++i) + (++i) + (++i);
	printf("%d\n", j);
	return 0;
}

在这里插入图片描述

🚀但在Linux下,结果为10.
在这里插入图片描述

  • 本质

🚀本质:是因为上面表达式的"计算路径不唯一"(为什么?编译器识别表达式,是同时加载至寄存器,还是分批加载,完全不确定)导致的

  • 贪心算法(用于表达式匹配)

🚀C语言有这样一个规定:每个符号应该包含尽可能多的字符。方向从左向右。下面我会演示。

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int main()
{
	int a = 0;
	int j = 1;
	printf("%d", a+++j);//如a++ + j
	return 0;
}

在这里插入图片描述

🚀贪心算法是一种规则,他并不一定保证你一定正确。从编译器角度出发,它不管你,只是让你尽可能占字符。

🌈理解取余/取模运算

🌳取整方式

  • 向0取整

🚀接下来我会使用一个函数trunc。用来向0取整。
在这里插入图片描述

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <math.h>
//demo 1
int main()
{
	//本质是向0取整
	int i = -2.9;
	int j = 2.9;
	printf("i=%d\n", i); //结果是:-2
	printf("j=%d\n", j); //结果是:2
	return 0;
}

在这里插入图片描述

在这里插入图片描述

  • 向-∞取整

🚀接下来需要floor函数。在这里插入图片描述

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <math.h>
int main()
{
	//本质是向-∞取整,注意输出格式要不然看不到结果
	printf("%.1f\n", floor(-2.9)); //-3
	printf("%.1f\n", floor(-2.1)); //-3
	printf("%.1f\n", floor(2.9)); //2
	printf("%.1f\n", floor(2.1)); //2
	return 0;
}

在这里插入图片描述

  • 向+∞取整

🚀接下来有请ceil函数登场!!!
在这里插入图片描述

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <math.h>
int main()
{
	//本质是向+∞取整,注意输出格式要不然看不到结果
	printf("%.1f\n", ceil(-2.9)); //-2
	printf("%.1f\n", ceil(-2.1)); //-2
	printf("%.1f\n", ceil(2.9)); //3
	printf("%.1f\n", ceil(2.1)); //3
	return 0;
}

在这里插入图片描述

  • 四舍五入取整

🚀掌声欢迎round函数👏👏👏

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <math.h>
int main()
{
	//本质是四舍五入
	printf("%.1f\n", round(2.1));
	printf("%.1f\n", round(2.9));
	printf("%.1f\n", round(-2.1));
	printf("%.1f\n", round(-2.9));
	return 0;
}
  • 汇总例子
    代码及运行结果
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <math.h>
int main()
{
	const char* format = "%.1f \t%.1f \t%.1f \t%.1f \t%.1f\n";
	printf("value\tround\tfloor\tceil\ttrunc\n");
	printf("-----\t-----\t-----\t----\t-----\n");
	printf(format, 2.3, round(2.3), floor(2.3), ceil(2.3), trunc(2.3));
	printf(format, 3.8, round(3.8), floor(3.8), ceil(3.8), trunc(3.8));
	printf(format, 5.5, round(5.5), floor(5.5), ceil(5.5), trunc(5.5));
	printf(format, -2.3, round(-2.3), floor(-2.3), ceil(-2.3), trunc(-2.3));
	printf(format, -3.8, round(-3.8), floor(-3.8), ceil(-3.8), trunc(-3.8));
	printf(format, -5.5, round(-5.5), floor(-5.5), ceil(-5.5), trunc(-5.5));
	return 0;
}

在这里插入图片描述

🌳取模

🍁什么是取模?

🚀如果a和d是两个自然数,d非零,可以证明存在两个唯一的整数 q 和 r,满足 a = q*d + r 且0 ≤ r < d。其中,q
被称为商,r 被称为余数。如下面代码:

//对应代码
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int main()
{
	int a = 10;
	int d = 3;
	printf("%d\n", a % d); //结果是1
	//因为:a=10,d=3,q=3,r=1 0<=r<d(3)
	//所以:a = q*d+r -> 10=3*3+1
	return 0;
}

🤡但是,这不能解决全部。如下面代码:

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int main()
{
	int a = -10;
	int d = 3;
	//printf("%d\n", a/d); //C语言中是-3,很好理解。C语言中除法是向0取整的。
	printf("%d\n", a % d);//结果为-1.负数
	return 0;
}

🚀因为在C中,现在-10%3出现了负数,根据定义:满足 a = q * d + r 且0 ≤ r < d,C语言中的余数,是不满足定义的,
因为,r<0了。
故,大家对取模有了一个修订版的定义:
如果a和d是两个自然数,d非零,可以证明存在两个唯一的整数 q 和 r,满足 a = q*d + r , q 为整数,且0 ≤ |r|
< |d|。其中,q 被称为商,r 被称为余数。
👉 上面的-10/3—> -(10)= (-3) *3 +(-1)

🤔在不同的语言下结果又是不一样的。如python语言:
在这里插入图片描述
可以解释为: -10 ==(-4)*3+2。商向-∞取整。而C语言是向0取整🪐🪐🪐

🍁是什么决定了这种现象?

🚀由上面的例子可以看出,具体余数r的大小,本质是取决于商q的。
而商,又取决谁呢?取决于除法计算的时候,取整规则。

🍁取余和取模一样吗?

🚀本质 1 取整:
取余:尽可能让商,进行向0取整。
取模:尽可能让商,向-∞方向取整。
故:
C中%,本质其实是取余。
Python中%,本质其实是取模。
🚀理解链:
对任何一个大于0的数,对其进行0向取整和-∞取整,取整方向是一致的。故取模等价于取余
对任何一个小于0的数,对其进行0向取整和-∞取整,取整方向是相反的。故取模不等价于取余
同符号数据相除,得到的商,一定是正数(正数vs正整数),即大于0!
故,在对其商进行取整的时候,取模等价于取余。
🚀本质 2 符号:
参与取余的两个数据,如果同符号,取模等价于取余

  • demo1(符号相同)

1.VS下

int main()
{
	printf("%d\n", 10 / 3);//3
	//10 = 3*3+1
	printf("%d\n\n", 10 % 3);//1
	printf("%d\n", -10 / -3);//3
	//-10 = (-3)*3 +(-1)
	printf("%d\n\n", -10 % -3);//-1
	return 0;
}

在这里插入图片描述
2.python下


>>> 10//3
3
>>> 10%3
1
>>> -10//-3
3
>>> -10%-3
-1
>>> 

🚀结论:通过对比试验,更加验证了,参与取余的两个数据,如果同符号,取模等价于取余

  • demo2(符号不同)

1.VS下

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int main()
{
printf("%d\n", -10 / 3); //结果:-3
printf("%d\n\n", -10 % 3); //结果:-1 为什么? -10=(-3)*3+(-1)
printf("%d\n", 10 / -3); //结果:-3
printf("%d\n\n", 10 % -3); //结果:1 为什么?10=(-3)*(-3)+1
return 0;
}

🚀明显结论:如果不同符号,余数的求法,参考之前定义。而余数符号,与被除数相同。

😎😎😎 真的吗???😎😎😎

2.python下


>>> -10//3
-4
>>> 10//-3
-4
>>> -10%3
2
>>> 10%-3
-2
>>> 

🛰️ 为了解决这一问题,我打算利用数学证明来解释。这仅是个人观点,若有雷同,纯属巧合!

🚀重新看看定义:
如果a和d是两个自然数,d非零,可以证明存在两个唯一的整数 q 和 r,满足 a = q * d + r , q 为整数,且0 ≤ |r|
< |d|。其中,q 被称为商,r 被称为余数。
a = q * d + r 变换成 r = a - q * d 变换成 r = a + (-q * d)
对于:x = y + z,这样的表达式,x的符号 与 |y|、|z|中大的数据一致(不好意思蛤,这是自己这么想的定义)
而r = a + (-q * d)中,|a| 和 |-q * d|的绝对值谁大,取决于商q的取整方式。
c是向0取整的,也就是q本身的绝对值是减小的。
如:
-10/3=-3.333.33 向0取整 -3. a=-10 |10|, -q * d=-(-3)3=9 |9|
10/-3=-3.333.33 向0取整 -3. a=10 |10|, -q * d=-(-3)
(-3)=-9 |9|
绝对值都变小了
python是向-∞取整的,也就是q本身的绝对值是增大的。
-10/3=-3.333.33 '//'向-∞取整 -4. a=-10 |10|, -q * d=-(-4)3=12 |12|
10/-3=–3.333.33 '//'向-∞取整 -4. a=10 |10|, -q * d=-(-4)
(-3)=-12 |12|
绝对值都变大了
结论:如果参与取余的两个数据符号不同,在C语言中(或者其他采用向0取整的语言如:C++,Java),余数符号,与被除数
相同。

🍁总结

🚀1.浮点数(或者整数相除),是有很多的取整方式的。

🚀2.如果a和d是两个自然数,d非零,可以证明存在两个唯一的整数 q 和 r,满足 a = q*d + r , q 为整数,且0 ≤ |r|
< |d|。其中,q 被称为商,r 被称为余数。

🚀3.在不同语言,同一个计算表达式,“取模”结果是不同的。我们可以称之为分别叫做正余数 和 负余数

🚀4.具体余数r的大小,本质是取决于商q的。而商,又取决于除法计算的时候,取整规则。

🚀5.取余vs取模: 取余尽可能让商,进行向0取整。取模尽可能让商,向-∞方向取整。

🚀6.参与取余的两个数据,如果同符号,取模等价于取余。

🚀7.如果参与取余的两个数据符号不同,在C语言中(或者其他采用向0取整的语言如:C++,Java),余数符号,与被
除数相同。(因为采用的向0取整)

🌈符号优先级

🚀 请查表!勤查表!

在这里插入图片描述

🌈结尾

🚀今天就分享到这啦!欢迎在评论区留言😁😁😁

在这里插入图片描述

  • 10
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 7
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值