biginteger 原理_Java BigInteger踩坑

本文通过对比Python和Java中BigInteger对同一字符串解码后的不同,探讨了Java BigInteger在处理字节数组时的原理。16进制结果相同,但10进制Java显示为负数,原因是Java在存储数值时使用补码形式。通过补码计算步骤验证了Java BigInteger的处理方式,并介绍了如何正确构造正负数的BigInteger实例。
摘要由CSDN通过智能技术生成

学习burpsuite的loader-kengen原理的时候,以下字符通过Java BigInteger表示输出和pyhon里的不一致

tdq99QBI3DtnQQ7rRJLR0uAdOXT69SUfAB/8O2zi0lsk4/bXkM58TP6cuhOzeYyrVUJrM11IsJhWrv8SiomzJ/rqledlx+P1G5B3MxFVfjML9xQz0ocZi3N+7dHMjf9/jPuFO7KmGfwjWdU4ItXSHFneqGBccCDHEy4bhXKuQrA=

pyhon下10进制和16进制

127702545355297024333429959781587858069905393473141316912736602016763456807823073371201714045389225082875078977073188987293761060998601431076147712924734841376044806737149037405159346208103921670369951829058878599971903611447448880396085184296375054850055720027341118913696701387622975160908648039096593040048

0xb5dabdf50048dc3b67410eeb4492d1d2e01d3974faf5251f001ffc3b6ce2d25b24e3f6d790ce7c4cfe9cba13b3798cab55426b335d48b09856aeff128a89b327faea95e765c7e3f51b90773311557e330bf71433d287198b737eedd1cc8dff7f8cfb853bb2a619fc2359d53822d5d21c59dea8605c7020c7132e1b8572ae42b0

Java下

String str = "tdq99QBI3DtnQQ7rRJLR0uAdOXT69SUfAB/8O2zi0lsk4/bXkM58TP6cuhOzeYyrVUJrM11IsJhWrv8SiomzJ/rqledlx+P1G5B3MxFVfjML9xQz0ocZi3N+7dHMjf9/jPuFO7KmGfwjWdU4ItXSHFneqGBccCDHEy4bhXKuQrA=";

byte[] data = Base64.getDecoder().decode(str);

BigInteger b1 = new BigInteger(data);

System.out.println(b1);

System.out.println(DatatypeConverter.printHexBinary(b1.toByteArray()));

输出

-52066768130934566439500559297314615291892304421089340360693479140969218997677889761506763277018310938245034902798204370365028707815815191416699717714739283001723086687716447871142873393142172449083131123026127168866247070895014001077827926244452182313294790657245179326250544550856741143926708290527631097168

B5DABDF50048DC3B67410EEB4492D1D2E01D3974FAF5251F001FFC3B6CE2D25B24E3F6D790CE7C4CFE9CBA13B3798CAB55426B335D48B09856AEFF128A89B327FAEA95E765C7E3F51B90773311557E330BF71433D287198B737EEDD1CC8DFF7F8CFB853BB2A619FC2359D53822D5D21C59DEA8605C7020C7132E1B8572AE42B0

发现16进制结果是一样的,只是10进制一个是负数,到时后面的结果也对应不起来。

对于BigInteger详细介绍可以看这里,对于计算机二进制数据编码方式也做了介绍。

这里只是引用其中一部分:

计算机中存储的数值都是补码的形式

正数的补码与原码相同

负数的补码是他的原码取反再加一

即补码的补码等于原码

原码,符号位+数值位,符号位为0 表示正数,符号位为1 表示负数,数值位就是真值的绝对值

根据上面规则再看原文给出的计算步骤:

补码计算步骤

第一步求原码: 先写出来她的原码--->符号位+数值位(绝对值)

第二步求反码:

如果是正数 反码与原码一样

如果是负数 反码为原码取反(除符号位外,逐位翻转)

第三步求补码:

如果是正数 补码与原码一样

如果是负数 补码为反码 + 1

第四步扩充:

如果不足数据类型的宽度,将需要填充到指定宽度

符号位扩充,也就是正数补0  负数补1

总结

不管什么形式,第一位始终都是符号位,0 表示正数, 1表示负数

正数原码/反码/补码 全都一样,知道一种就直接得到另外的形式

负数如果知道补码,想要得到他的原码,只需要对补码再一次的求补码即可

默认原始数据给出的是正数,然而Java没有无符号的类型,没有当做正数处理,我们这里转换一下

//创建一个数组,并添加符号位,正数符号为0,默认数据初始化为0,所以只需把数据复制过去就好了

byte[] test=new byte[data.length+1];

System.arraycopy(data,0,test,1,data.length);

BigInteger b4=new BigInteger(test);

System.out.println(DatatypeConverter.printHexBinary(b4.toByteArray()));

System.out.println(b4);

然后我们看一下输出

127702545355297024333429959781587858069905393473141316912736602016763456807823073371201714045389225082875078977073188987293761060998601431076147712924734841376044806737149037405159346208103921670369951829058878599971903611447448880396085184296375054850055720027341118913696701387622975160908648039096593040048

00B5DABDF50048DC3B67410EEB4492D1D2E01D3974FAF5251F001FFC3B6CE2D25B24E3F6D790CE7C4CFE9CBA13B3798CAB55426B335D48B09856AEFF128A89B327FAEA95E765C7E3F51B90773311557E330BF71433D287198B737EEDD1CC8DFF7F8CFB853BB2A619FC2359D53822D5D21C59DEA8605C7020C7132E1B8572AE42B0

发现10进制数据一致了,也不是负数了,只不过16进制多补了一个符号位0,不影响数值大小。

这样做是不是太麻烦了,自己每次转换,其实有默认的构造方法的,这里可以传入1和-1代表正负数

BigInteger b2 = new BigInteger(1, data);

System.out.println(b2);

System.out.println(DatatypeConverter.printHexBinary(b2.toByteArray()));

输出是一致的

127702545355297024333429959781587858069905393473141316912736602016763456807823073371201714045389225082875078977073188987293761060998601431076147712924734841376044806737149037405159346208103921670369951829058878599971903611447448880396085184296375054850055720027341118913696701387622975160908648039096593040048

00B5DABDF50048DC3B67410EEB4492D1D2E01D3974FAF5251F001FFC3B6CE2D25B24E3F6D790CE7C4CFE9CBA13B3798CAB55426B335D48B09856AEFF128A89B327FAEA95E765C7E3F51B90773311557E330BF71433D287198B737EEDD1CC8DFF7F8CFB853BB2A619FC2359D53822D5D21C59DEA8605C7020C7132E1B8572AE42B0

下面验证一下补码计算,创建一个负数的,然后通过b2正数的来计算一下这个负数的,比较一下结果

BigInteger b3 = new BigInteger(-1, data);

System.out.println(b3);

System.out.println(DatatypeConverter.printHexBinary(b3.toByteArray()));

BigInteger b6 = b2.not().add(BigInteger.ONE);

System.out.println(b6);

System.out.println(DatatypeConverter.printHexBinary(b6.toByteArray()));

--------------b3--------------

-127702545355297024333429959781587858069905393473141316912736602016763456807823073371201714045389225082875078977073188987293761060998601431076147712924734841376044806737149037405159346208103921670369951829058878599971903611447448880396085184296375054850055720027341118913696701387622975160908648039096593040048

FF4A25420AFFB723C498BEF114BB6D2E2D1FE2C68B050ADAE0FFE003C4931D2DA4DB1C09286F3183B3016345EC4C867354AABD94CCA2B74F67A95100ED75764CD805156A189A381C0AE46F88CCEEAA81CCF408EBCC2D78E6748C81122E3372008073047AC44D59E603DCA62AC7DD2A2DE3A621579FA38FDF38ECD1E47A8D51BD50

--------------b6--------------

-127702545355297024333429959781587858069905393473141316912736602016763456807823073371201714045389225082875078977073188987293761060998601431076147712924734841376044806737149037405159346208103921670369951829058878599971903611447448880396085184296375054850055720027341118913696701387622975160908648039096593040048

FF4A25420AFFB723C498BEF114BB6D2E2D1FE2C68B050ADAE0FFE003C4931D2DA4DB1C09286F3183B3016345EC4C867354AABD94CCA2B74F67A95100ED75764CD805156A189A381C0AE46F88CCEEAA81CCF408EBCC2D78E6748C81122E3372008073047AC44D59E603DCA62AC7DD2A2DE3A621579FA38FDF38ECD1E47A8D51BD50

二者结果一致,所以说明Java BigInteger处理byte[]数组时直接把数据存储的,没有符号位的概念。我们要么构造的时候传入符号位的参数,要么自己添加数组符号位。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Java中的BigInteger类是用于处理大数的类。它可以处理比long类型更大的整数。BigInteger类的原理是使用一个int类型的数组来存储大数的每个位。数组中的每个元素都是大数的一部分。这个数组被称为mag[]。 1. 按位取反:BigInteger类提供了not()方法来实现按位取反的操作。该方法首先创建一个与原始BigInteger对象相同长度的int数组result[]。然后,通过循环遍历result[]数组,将mag[]数组中的每个元素取反并存储到result[]数组中。最后,使用valueOf()方法将result[]数组转换为一个新的BigInteger对象并返回。 示例代码如下: ```java public BigInteger not() { int[] result = new int[intLength()]; for (int i = 0; i < result.length; i++) { result[i] = ~getInt(result.length - i - 1); } return valueOf(result); } ``` 2. 按位与操作:BigInteger类提供了and()方法来实现按位与操作。该方法首先创建一个长度为两个BigInteger对象中较大的int数组result[]。然后,通过循环遍历result[]数组,将mag[]数组和另一个BigInteger对象的mag[]数组中对应位置的元素进行按位与操作,并将结果存储到result[]数组中。最后,使用valueOf()方法将result[]数组转换为一个新的BigInteger对象并返回。 示例代码如下: ```java public BigInteger and(BigInteger val) { int[] result = new int[Math.max(intLength(), val.intLength())]; for (int i = 0; i < result.length; i++) { result[i] = (getInt(result.length - i - 1) & val.getInt(result.length - i - 1)); } return valueOf(result); } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值