Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/353.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java中不带BigInteger的双字节数组的基本算法_Java_Arrays - Fatal编程技术网

Java中不带BigInteger的双字节数组的基本算法

Java中不带BigInteger的双字节数组的基本算法,java,arrays,Java,Arrays,我有两个表示无符号256位值的字节数组,我想对它们执行简单的算术运算,比如ADD、SUB、DIV、MUL和EXP,有没有办法直接在字节数组上执行这些运算?目前,我将这些字节数组值转换为BigInteger,然后执行计算,但我有一个想法,这会降低我的性能。您如何做到这一点以获得最快的结果 例如,这是我当前的添加函数: // Both byte arrays are length 32 and represent unsigned 256-bit values public void add(byt

我有两个表示无符号256位值的字节数组,我想对它们执行简单的算术运算,比如ADD、SUB、DIV、MUL和EXP,有没有办法直接在字节数组上执行这些运算?目前,我将这些字节数组值转换为BigInteger,然后执行计算,但我有一个想法,这会降低我的性能。您如何做到这一点以获得最快的结果

例如,这是我当前的添加函数:

// Both byte arrays are length 32 and represent unsigned 256-bit values
public void add(byte[] data1, byte[] data2) {

    BigInteger value1 = new BigInteger(1, data1);
    BigInteger value2 = new BigInteger(1, data2);
    BigInteger result = value1.add(value2);

    byte[] bytes = result.toByteArray();
    ByteBuffer buffer = ByteBuffer.allocate(32);

    System.arraycopy(bytes, 0, buffer.array(), 32 - bytes.length, bytes.length);
    this.buffer = buffer.array();
}

作为一个大的无符号数,字节[]不是一个理想的解决方案,例如,考虑到添加两个数字,你必须在两个数组上循环,添加每个字节(和前一个字节的进位),然后将结果字节存储在某处。 BigInteger以适合于它提供的操作的方式在内部表示该值,因此它的操作很可能至少与使用byte[]时一样好。性能方面的一个小缺点可能是BigInteger是不可变的

就性能而言,由4个长成员组成的简单、可变的holder对象可能会做得最好:

My256BitNumber {
    long l0;
    long l1;
    long l2;
    long l3;

    public void add(My256BitNumber arg) {
        //...
    }
}
这将允许您绕过对象创建的开销(由于是可变的),以及任何潜在的数组访问开销(如数组索引边界检查)

但是考虑到这些操作都不是很容易实现的,只需使用BigInteger即可。它结合了合理的性能和合理的简单使用,最重要的是,它是一个经过测试的工作解决方案


滚动您自己的实现是否值得,取决于您的用例。考虑到你在问一个人是否能比BigInteger获得更好的性能,答案是,是的,你可以,但在代码复杂性方面付出了巨大的代价。

我不认为使用
字节[]
直接使用,而不是使用
biginger
,但为了满足您的好奇心,下面是一个如何添加大小为
32
的两字节数组的示例:

public static byte[] add(byte[] data1, byte[] data2) {
  if(data1.length!=32 || data2.length!=32)
    throw new IllegalArgumentException();
  byte[] result=new byte[32];
  for(int i=31, overflow=0; i>=0; i--) {
    int v = (data1[i]&0xff)+(data2[i]&0xff)+overflow;
    result[i]=(byte)v;
    overflow=v>>>8;
  }
  return result;
}

请注意,可以使用其中一个输入数组作为结果的目标。但是,如果这种重用对性能甚至有负面影响,也不要感到惊讶。在今天的系统中,对于“如何加速”已经没有简单的答案了……

出于某种原因,这看起来很熟悉……为什么您认为这很昂贵?这听起来像是过早的优化,如果您确实需要少量的额外速度,那么您肯定会使用一种没有Java开销的语言,或者首先将数字存储为
biginger
s。是的,在将字节数组转换为存储在
biginger
中的符号/幅度格式时,会有很小的开销(调用这些操作的频率是多少?),然而,手工实现二进制算法会花费更多的时间,并且会给你的数学带来很多可能的错误。为了得到最快的结果,我会将字节数组值转换成一个
BigInteger
,然后让它执行计算,理论上,编写该类的人已经花了数年时间使其更加优化,并且可能比我更了解他们在做什么。如果您存储/传输这些
biginger
s,这就是您将它们保留为字节数组的原因,也许序列化会对您有所帮助?所以基本上只需单独添加每个字节。这样一个简单的答案和类似的操作可以做。我做了一个性能测试,得出了4876ms对342ms(您的解决方案),迭代次数为10000000次。这似乎要快得多,与人们所说的BigInteger已经在优化的说法相反。我必须再次检查结果,但这正是我想要的。这是你自己写的,还是在某个地方有这些类型操作的开源实现?嗯
biginger
比这个简单的方法有很多事情要做,例如,它不会放弃溢出,而是分配一个更大的字节数组。因此,它还必须处理不同大小的阵列。因此,即使对
biginger
进行了优化,这种简化方法也有可能更快,但微基准的结果可能与实际应用中的结果有很大差异,在实际应用中,这种操作只会产生一小部分。它的实现和平台相关。这是我自己写的,但这并不意味着没有库来完成这项任务。我对32字节值的更多函数感兴趣,比如乘法和除法。允许溢出。我甚至会从哪里开始查找?考虑大小为n的字节数组为Base256系统中的n位数。然后试着记住基本的算术,也就是说,你是如何用大数字执行这些运算的。我链接到减法,因为它比加法文章有更多的细节。如果您将其与上述方法进行比较,您应该注意到其相似性。同样,也会导致解决方案等。