关于数字存储和byte[]数组的一些心得

2024-09-01 00:28
文章标签 数组 存储 心得 数字 byte

本文主要是介绍关于数字存储和byte[]数组的一些心得,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

前言

最近做项目,发现一些规律,比如数字的存储和字符串的存储,先说数字吧,最常见的整数,就涉及反码和补码,根据这些规则,甚至我们自己也能造一种数据存储结构,比如1个字节8bit,在byte里面就是一半正数一半负数,但是在二进制却是我们不理解的一种方式。计算机存储都是字节存储,字符实际上也是字节,那么byte[]数组在很多时候就很关键,比如grpc算法那一期:grpc Java demo与Springboot改造支持grpc通信_grpc-client-spring-boot-starter-CSDN博客

准备demo

demo解说

比如byte 127表示01111111,byte是8bit,所以有一个符号位,但是负数呢

-128就是10000000,这里转int了,4个字节而byte是一个字节,实际上byte=字节,就是直译的

那么我们把int强转为byte呢

这就涉及数据的存储了,计算机不能运算减法,使用加法做减法,那么负数就需要一种表现形式,即符号位,但是bit2进制存储,并不是我们理解的存储方式,这就涉及反码和补码了,数据以补码的形式存储。

原码、反码、补码

数据都是2进制存储,计算机为了做减法,对每个字节的从左到右第一个bit定义为符号位,为什么从左到右,实际上在看UTF-16的编码设计,就有高位和低位的说法,真难懂,字节byte的第一bit为符号位定义清晰。

原码

原码是使用数据本身的定义存储,即符号位1bit,其他是我们真实的数据,非常符合我们的认知。

正整数二进制原码负整数二进制原码
10000 0001-11000 0001
20000 0010-21000 0010
30000 0011-31000 0011
40000 0100-41000 0100
50000 0101-51000 0101

但是原码有个问题:1+ (-1) ≠ 0,这是不允许的。

反码

既然原码1 + (-1) ≠ 0那么,按位取反,就可以了,表示负数

整数的反码与原码一致,负数的反码是除了符号bit,其余bit位按位取反,毕竟反码就是为负数做加法设计的。但是因为负数是按位取反,所以1+(-1) ≠ 0。

正整数二进制反码负整数二进制反码
10000 0001-11111 1110
20000 0010-21111 1101
30000 0011-31111 1100
40000 0100-41111 1011
50000 0101-51111 1010

补码 

负数除了符号位按位取反后,虽然语义清晰了,但是做加法运算仍然是有问题的:

1+(-1)≠ 0,这就需要补码了

正数的原码、反码、补码一致;负数的补码=反码+1bit

正整数二进制补码负整数二进制补码
10000 0001-11111 1111
20000 0010-21111 1110
30000 0011-31111 1101
40000 0100-41111 1100
50000 0101-51111 1011

 实际上数据就是补码存储的,但是每个字节做加法也有问题

1+(-1) = 1 0000 0000

就是超限了,计算机就把超限的bit位舍弃,来达到1+(-1)=0的计算,所以-1就是1111 1111了,但是对于byte来说-128呢,毕竟0111 1111 = 127,即一个字节,所以-128没有原码,当然也没有反码了,只有补码,毕竟0这个特殊的数据,不存在+0和-0的说法。

-128原码= 1 1000 0000 超限byte了,byte只有8bit,去掉符号位只有7位,即原码最大-127

-128反码= 1 0111 1111  原码没有就没有反码了

-128补码= 1 1000 0000 补码

说说0

-0的原码=1 000 0000

-0的反码=1 111 1111

-0的补码=0 000 0000 = +0

神奇的设计。

byte[]数组

那么byte[]数组呢,奇特的地方是每个byte是-128~127,但是多个字节时只有开始的一个bit是符号位,对于多个字节的整个bit位是遵循补码存储的思路,但是对于单个字节就会出现负数表示255的情况。

可以看到255刚好够一个byte存储,转为byte看看

 -1,相当于-1表示255,128表示-128

相当于考虑符号位和多字节不考虑字节本身符号位的表示规则:

127后是-128,然后依次递增+1,知道255=-1

当然,int转byte[]就涉及高低位顺序了,类似utf-16编码。

上次grpc的算法

grpc Java demo与Springboot改造支持grpc通信_grpc-client-spring-boot-starter-CSDN博客 

package org.springframework.http.converter.protobuf;public class LengthBytesUtils {public static byte[] intToBytes(int length, int size) {byte[] bytes = new byte[size];int temp;for (int i = size - 1; i > -1; i--) {temp = (int) ((length / (Math.pow(253, (size - 1 - i)))) % 253);if (temp > 127) {temp = -128 + 1 + temp - 127 + 1;}bytes[i] = (byte) temp;}return bytes;}public static int bytesToInt(byte[] bytes) {int length = 0;int size = bytes.length;for (int i = 0; i < size; i++) {if (bytes[i] == 0){continue;}if (bytes[i] > 0) {length += bytes[i] * Math.pow(253, size-1-i);} else {length += (127-1 + bytes[i] + 128-1) * Math.pow(253, size-1-i);}}return length;}
}

 实际上是剔除了一些byte数据表示,但是grpc把长度从int的4字节提升到5字节,相当于创造了一种正整数 数据类型,实际上可以优化为

    public static byte[] intToBytes2(int length, int size) {byte[] bytes = new byte[size];int temp;for (int i = size - 1; i > -1; i--) {temp = (byte) ((length / (Math.pow(253, (size - 1 - i)))) % 253);if (temp < 0) {temp = 3 + temp;}bytes[i] = (byte) temp;}return bytes;}public static int bytesToInt2(byte[] bytes) {int length = 0;int size = bytes.length;for (int i = 0; i < size; i++) {if (bytes[i] == 0) {continue;}if (bytes[i] > 0) {length += bytes[i] * Math.pow(253, size - 1 - i);} else {length += (bytes[i] + 253) * Math.pow(253, size - 1 - i);}}return length;}

因为int转byte,符号位生效,byte会认为第一个bit是符号位,但是对int的字节数组的每个字节就不一定了,只有最高位bit是符号位,其他都是数据位

int 4个字节

0 0000000  00000000  00000000 10000000 = int 128 = byte[]{0, 0, 0, -128}

但是byte -128转int还是-128,因为是向上转型,是byte类型一定是int类型,反之则不对。

总结

实际上这次是一些碎碎念,核心还是计算机的原理,计算机因为电气性能只设计有0、1,所以是2进制,存算都是2进制。而且计算机在设计之初只设计了加法,没设计或者设计减法有问题,导致数据相减运算都是加运算,所以需要存储和运算负数,那么就需要定义负数的存储和相加逻辑,就设计了反码和补码来存储负数。

另外一个字节存储能力有限,往往需要很多字节来存储一个内容,那么符号位的定义在总体结构很明晰,但是对于字节数组的单个字节就会存在歧义,造成数据可读性很迷惑,因为符号位的特殊意义。同时,我们可以根据需要自定义数据类型,但是字节数组存储会有读取顺序的高低位问题,类似UTF-16编码的左右读取模式。

这篇关于关于数字存储和byte[]数组的一些心得的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1125420

相关文章

异构存储(冷热数据分离)

异构存储主要解决不同的数据,存储在不同类型的硬盘中,达到最佳性能的问题。 异构存储Shell操作 (1)查看当前有哪些存储策略可以用 [lytfly@hadoop102 hadoop-3.1.4]$ hdfs storagepolicies -listPolicies (2)为指定路径(数据存储目录)设置指定的存储策略 hdfs storagepolicies -setStoragePo

HDFS—存储优化(纠删码)

纠删码原理 HDFS 默认情况下,一个文件有3个副本,这样提高了数据的可靠性,但也带来了2倍的冗余开销。 Hadoop3.x 引入了纠删码,采用计算的方式,可以节省约50%左右的存储空间。 此种方式节约了空间,但是会增加 cpu 的计算。 纠删码策略是给具体一个路径设置。所有往此路径下存储的文件,都会执行此策略。 默认只开启对 RS-6-3-1024k

从去中心化到智能化:Web3如何与AI共同塑造数字生态

在数字时代的演进中,Web3和人工智能(AI)正成为塑造未来互联网的两大核心力量。Web3的去中心化理念与AI的智能化技术,正相互交织,共同推动数字生态的变革。本文将探讨Web3与AI的融合如何改变数字世界,并展望这一新兴组合如何重塑我们的在线体验。 Web3的去中心化愿景 Web3代表了互联网的第三代发展,它基于去中心化的区块链技术,旨在创建一个开放、透明且用户主导的数字生态。不同于传统

hdu2241(二分+合并数组)

题意:判断是否存在a+b+c = x,a,b,c分别属于集合A,B,C 如果用暴力会超时,所以这里用到了数组合并,将b,c数组合并成d,d数组存的是b,c数组元素的和,然后对d数组进行二分就可以了 代码如下(附注释): #include<iostream>#include<algorithm>#include<cstring>#include<stack>#include<que

usaco 1.2 Name That Number(数字字母转化)

巧妙的利用code[b[0]-'A'] 将字符ABC...Z转换为数字 需要注意的是重新开一个数组 c [ ] 存储字符串 应人为的在末尾附上 ‘ \ 0 ’ 详见代码: /*ID: who jayLANG: C++TASK: namenum*/#include<stdio.h>#include<string.h>int main(){FILE *fin = fopen (

hdu 1166 敌兵布阵(树状数组 or 线段树)

题意是求一个线段的和,在线段上可以进行加减的修改。 树状数组的模板题。 代码: #include <stdio.h>#include <string.h>const int maxn = 50000 + 1;int c[maxn];int n;int lowbit(int x){return x & -x;}void add(int x, int num){while

C语言:柔性数组

数组定义 柔性数组 err int arr[0] = {0}; // ERROR 柔性数组 // 常见struct Test{int len;char arr[1024];} // 柔性数组struct Test{int len;char arr[0];}struct Test *t;t = malloc(sizeof(Test) + 11);strcpy(t->arr,

速了解MySQL 数据库不同存储引擎

快速了解MySQL 数据库不同存储引擎 MySQL 提供了多种存储引擎,每种存储引擎都有其特定的特性和适用场景。了解这些存储引擎的特性,有助于在设计数据库时做出合理的选择。以下是 MySQL 中几种常用存储引擎的详细介绍。 1. InnoDB 特点: 事务支持:InnoDB 是一个支持 ACID(原子性、一致性、隔离性、持久性)事务的存储引擎。行级锁:使用行级锁来提高并发性,减少锁竞争

C 语言基础之数组

文章目录 什么是数组数组变量的声明多维数组 什么是数组 数组,顾名思义,就是一组数。 假如班上有 30 个同学,让你编程统计每个人的分数,求最高分、最低分、平均分等。如果不知道数组,你只能这样写代码: int ZhangSan_score = 95;int LiSi_score = 90;......int LiuDong_score = 100;int Zhou

计算数组的斜率,偏移,R2

模拟Excel中的R2的计算。         public bool fnCheckRear_R2(List<double[]> lRear, int iMinRear, int iMaxRear, ref double dR2)         {             bool bResult = true;             int n = 0;             dou