【问题标题】:Most efficient way to Add 2or more array of decimal/hex/binary添加 2 个或更多十进制/十六进制/二进制数组的最有效方法
【发布时间】:2021-07-24 07:22:42
【问题描述】:

假设我在 dart 中有一个字符串“compute”,

String = "计算机";

它在数组中有一些二进制/十六进制/十进制值表示

二进制 = [01100011 01101111 01101101 01110000 01110101 01110100 01100101 01110010]

十六进制 = [63 6F 6D 70 75 74 65 72]

十进制 = [99 111 109 112 117 116 101 114]

以编程方式获取每 4 个字节 (Dword) 总和的最佳方法是什么?

二进制计算数组

  01100011 01101111 01101101 01110000

+ 01110101 01110100 01100101 01110010

(          sum here                  )

如果字符串增长,例如“这是计算机”,它仍然必须获取每 4 个字节的总和

ASCII - 这是计算机

十六进制 - 74 68 69 73 20 69 73 20 63 6F 6D 70 75 74 65 72

二进制 - 01110100 01101000 01101001 01110011 00100000 01101001 01110011 00100000 01100011 01101111 01101101 01110000 01110101 01110100 01100101 01110010

十进制 - 116 104 105 115 32 105 115 32 99 111 109 112 117 116 101 114

二进制计算数组

  01110100 01101000 01101001 01110011

  00100000 01101001 01110011 00100000

  01100011 01101111 01101101 01110000

+ 01110101 01110100 01100101 01110010

(          sum here                  )

【问题讨论】:

  • 您能否举例说明您的示例中的预期总和应该是多少?总和是否也限制为 4 个字节?如果是这样的话,我猜我们可以溢出?
  • 是的,总和也限制为 4 个字节。

标签: arrays dart


【解决方案1】:

如果我们假设输入是 8 位字母(例如,仅 ASCII),那么我会这样做:

import "dart:typed_data";
int sumOfFourChars(String input) {
  var bytes = Uint8List((input.length + 3) & ~3); // round up to multiple of 4.
  bytes.setRange(0, input.length, input.codeUnits);
  var words = bytes.buffer.asUint32List();
  return words.fold<int>(0, (a, b) => a + b) & 0xFFFFFFFF; // If you want to drop overflows.
}

已针对可读性和简洁性进行了优化。如果追求性能,我可能会在本地计算总和:

  var result = 0;
  for (var i = 0; i < words.length; i++) result += words[i];
  return result;

这个总和使用平台字节序(通常是英特尔芯片上的小字节序)。如果你需要不同平台上的结果相同,你可能想用ByteData代替,这样你就可以控制字节序:

  var words = bytes.buffer.asByteData();
  var result = 0;
  for (var i = 0; i < words.lengthInBytes; i += 4) {
    result += words.getUint32(i, Endian.little);
  }
  return result;

这些方法都依赖于首先将字节复制到类型化数据列表中。 为避免这种情况,您可以自己做。

int sumOfFourChars(String input) {
  var result = 0;
  var i = 0;
  while (i + 4 <= input.length) {
    result += input.codeUnitAt(i);
    result += input.codeUnitAt(i + 1) << 8;
    result += input.codeUnitAt(i + 2) << 16;
    result += input.codeUnitAt(i + 3) << 24;
    i += 4;
  }
  if (i < input.length) {
    result += input.codeUnitAt(i);
    if (i + 1 < input.length) {
      result += input.codeUnitAt(i + 1) << 8;
      if (i + 2 < input.length) {
        result += input.codeUnitAt(i + 2) << 16;
      }
    }
  }
  return result & 0xFFFFFFFF;
}

这仍然假定所有字符都是字节(否则您可能需要转换为 UTF-8)。

依赖计算移位的替代方案(英特尔 CPU 传统上会慢一点)是:

int sumOfFourChars(String input) {
  var result = 0;
  var shift = 0;
  for (var i = 0; i < input.length; i++) {
    result = result + (input.codeUnitAt(i) << shift) & 0xFFFFFFFF;
    shift = (shift + 8) & 0x1f;
  }
  return result;
}

需要针对真实数据和目标平台测量实际性能。我自己可能会选择最后一个,因为代码简洁本身就是一个优势,并且只有在测量表明代码成为实践中的瓶颈之后才会做一些更复杂的事情。


如果想要的结果是一个四字节数组,其中每个字节是独立添加的(不会溢出到下一个字节),最简单的方法是:

Uint8List addFourBytes(Uint8List input) {
  var result = Uint8List(4);
  for (var i = 0; i < input.length; i++) result[i & 3] += input[i];
  return result;
}

使用 SIMD 操作可能会比这更快,但 Dart 不提供任何 Uint8x16 类型,就像它提供 Int32x4 一样,所以它不是直接支持的东西,

【讨论】:

  • 嗨!感谢您的回复,我们有没有办法在flutter中检查两者之间的执行时间?
  • 除非我测量到代码主导了应用程序的其余部分,否则我不会为性能的微小改进而烦恼。除非您在 lot 或非常大的字符串上执行它,否则它不太可能是可测量的 - 在后一种情况下,我会做一些完全不同的事情来避免复制字节。
  • 感谢您的帮助,顺便说一句,它会抛出一个错误 return words.fold(0, (a, b) => a + b) & 0xFFFFFFFF; "message": "不能无条件调用运算符 '+',因为接收者可以是 'null'。\n尝试向目标 ('!') 添加一个 null 检查。",
  • 很好,添加了明确的&lt;int&gt; 来帮助类型推断。
  • 得到结果后,将其转换回字节数组的正确方法是什么?我尝试了 .codeUnit 和 asInt32List,可能不是正确的方法,因为两者都没有显示我想要的列表中的 4 个字节
猜你喜欢
  • 2014-10-30
  • 1970-01-01
  • 2015-01-21
  • 1970-01-01
  • 1970-01-01
  • 2018-01-19
  • 1970-01-01
  • 1970-01-01
  • 2014-01-07
相关资源
最近更新 更多