使用场景
在进行通信的时候,经常会遇到数据过大传输丢失的问题,因为我们的串口和网口都是按照一个字节(byte)的大小进行传输,但是如果一个数据非常大,一个字节根本不够用呢?这时我们就需要使用数据分离,将大数据分为几个字节分别进行传输, 然后在使用的时候再进行合并。
如何分离
说起如何分离数据高位和低位,我们第一想到的就是这两个符号,‘/’除法和‘%’取余,符号虽然很简单, 但是用起来经常会犯迷糊,哎,我这个时候到底是应该用除法呢,还是应该取余呢?
我会教大家一些小技巧来快速掌握这个简单的小算法。
除法‘/’的用法
在编程里面的除法‘/’和我们日常生活的除法是有区别的,例如5/2,日常生活中的除法是5/2=2.5,编程中则是5/2=2,小数点后面的所有数据都会被舍弃,可不会遵循四舍五入原则,切记。
好了,准备工作做完了,我们依旧简单点,直接先摆结论,然后再来论证,毕竟这需要一个认可的过程。
当对一个数a进行分离高低位操作的时候,将这个数a除以10,就是把这个数的10进制数进行右移1位,也就是丢掉10进制数最右边的1位数。当然,如果除以1000(10 * 10 * 10),则是把这个数的10进制数右移3位,也就是丢掉10进制数最右边的3位数。
例如12345,想要获得这个数据的‘12’两位,那么是不是应该把这个数右移三位,也就是除以1000,右边的‘345’就被丢掉了,只留下我们需要的‘12’,这是很好理解的对吧。
好,那增加一点难度,现在我有一个数,十进制是1000001,十六进制是0xF4241,如图,我想要获得0XF42,那么我应该怎么做呢?还是照着公式套除以1000吗?那肯定是不对的,很明显,我们现在是以16进制的角度来讨论数据分离了,之前的结论都是以10进制的数作为标准的,这里需要做一点小小的调整,很简单,把除以10改为16即可。
所以我们要对这个结论做一下扩展。
当对一个数a进行分离高低位操作的时候,将这个数a除以16,就是把这个数的16进制数进行右移1位,也就是丢掉16进制数最右边的1位数。当然,如果除以256(16 * 16),则是把这个数的16进制数右移2位,也就是丢掉16进制数最右边的2位数。
简单的说,只需要记得几个关键词:
- 除法
- 你现在需要的是多少进制
- 需要10进制除以10,需要16进制则除以16
- 除了几次 = 右移几位
回到这个例子 1000001,十六进制是0XF4241,要获得0XF42,是不是需要把16进制的数右移2位,移动一位除以16,移动两位除以16*16=256,所以只需要把这个数除以256即可。
是不是非常正确,那么又有小伙伴要问了,我听你说除以256,然后我去除了,发现是错的!!!为什么??有图有真相!!
咋一看,没错啊,确实是除以256,要除的数也是0XF4241,但是我这个结果怎么差这么大呢?这里也有要注意的点,用0xF4241除以的这个256啊,它不是真正的256,它是16进制的256,转为10进制是598,你看,不同进制的除法也要注意区别。
所以在使用的时候也要注意,你除以的到底是10进制的16呢,还是16进制的0x16呢?那区别可太大了,我说的可都是10进制哦。
取余‘%’的用法
除法可以很好的将数据进行移位,把低位丢掉,获取高位。但是!那我刚好需要低位呢?,你看,除法一直都在丢低位,都没有留低位,例如10进制的123,我无论怎么除以10,‘3’首先就会被丢掉,可是如果我想要留它呢。刚才的12345也是,我们只在关注‘12’怎么留下,那如果我要获得中间的‘23’呢?除以100,留下了123,那‘1’怎么处理呢?好像无论怎么除都搞不定!!
这个时候它就来了,也就我们的取余 ‘%’操作!!!
它和除法的作用完全相反,除法是从右往左丢数据,但是取余是从右往左保留数据,至于你要留几个数据,也看你取余的次数!!
当对一个数a进行取余操作的时候,将这个数a%10,就是把这个数的10进制数最右边的1位数保留!当然,如果a%1000(10 * 10 * 10),则是把这个数的10进制数最右边的3位数保留,其他的丢弃。
看!这次是不是把‘345’留下来了,‘12’则是被舍弃掉了!!
16进制其实是一样的,还是用我们刚才的数据举例,十进制1000001,十六进制也就是0XF4241,
我想要获取0X41,该怎么操作呢?让我们按照结论来套。
当对一个数a进行取余操作的时候,将这个数a%16,就是把这个数的16进制数最右边的1位数保留!当然,如果a%256(16 * 16),则是把这个数的16进制数最右边的2位数保留,其他的丢弃。
现在我们需要的是0X41,我们需要保留最低位的两位,关键词:
- 取余
- 需要保留几位
- 什么进制(10进制或者是16进制,或者是任意进制)
- 取余几次 = 保留几位
关键词也提取到了,取余,16进制,保留两位,取余两次(16*16=256),那么结果对吗?
果然不出所料,真的是太不可思议了!!
做个小结
在我最开始做数据分离的时候,我是真的犯迷糊,看着程序上的‘/’和‘%’总是不知道到底在干嘛,可能我自己用的时候会用,但是要理清楚却要很久,然后我想着,如何找出内在规律,然后简化我的工作量呢?于是我做了大量的运算, 终于总结了这个傻瓜方法,如果你理解了真的超级简单, 文章里面的主要是10进制和16进制,其实任意进制都是适用的,至少我还测过8进制,也没有问题。
小结一下:
除法:
10进制 12345 16进制 0X3039
12345 / 10 = (10进制)12345 右移一位 = 1234
12345 / 1000 = (10进制)12345 右移三位 = 12
12345 / 16 = (16进制) 0X3039 右移一位 = 0X303
12345 / 256 = (16进制)0X3039 右移两位 = 0X30
取余:
10进制 12345 16进制 0X3039
12345 % 10 = (10进制)12345 保留一位 = 5
12345 %1000 = (10进制)12345 保留三位 = 345
12345 %16 = (16进制) 0X3039 保留一位 = 0X9
12345 % 256 = (16进制)0X3039 保留两位 = 0X39
其他进制都是一样的。
小数的扩展
现在我们运算的数都是整数,但是如果我们要传输一个小数呢,例如123.456,是不是在我们的传输中也很常见,在我们正常的数据传输中,小数是会被舍弃的,这是由于数据结构决定的,那怕你是浮点型,在传输的时候也会自动转为byte类型,或者无符号字符型,如果你理解了我这种方法,传输小数是不是也超级简单。
既然小数点后面的数据会被舍弃,那我让它不为小数不就行了嘛?给123.456扩大1000倍,不就成一个整数123456了嘛,既然都是整数,我只需要保留后面三位就可以了,保留用取余就可以做到,123.456 * 1000 % 1000 = 456,呃,不是我不想写出全过程,因为计算器不太允许,虽然它不允许我们写,但是方法就是这样嘛。
后续
好了,今天的小知识就介绍到这里了,看了看博客,已经好久没有更新了,心血来潮突然想写点东西。虽然这次的知识点比较简单,但我觉得在你需要的时候真的很实用!!!
会水的芝麻
2022年7月4日
黄石市-大冶市