我可以用任何字节数组(Scala)构造 BigInt 吗?

发布于 2024-08-09 03:56:28 字数 483 浏览 6 评论 0原文

我试图用尽可能短的字符串表示 MD5 哈希的结果。仅仅将其变成十六进制字符串并让 G 到 Z 浪费似乎是一种浪费。

我的一个想法是获取输入的 MD5 哈希值作为字节数组,并用它构造一个 BigInt。然后我可以调用 toString(36),并以字符串 (-?[0-9a-z]*) 的形式获取以 36 为基数的数字,该数字可以为正或负)。这对我有用。

问题是,我不确定 BigInt 是否可以用任何字节数组构造,并且我无法通过测试证明这一点(至少不能及时!)。我这么认为,因为我知道 BigInt 可以是任意大小。在我确定该方法适用于所有可能的输出之前,我无法使用该方法。那么,谁能告诉我它是否适用于所有输入(或者如何轻松转换字节数组以便可以用 36 进制表示)。

说明:我有实现,我询问整个域的行为(即 00000000000000000000000000000000 到 FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF)

I'm trying to represent the result of an MD5 hash in the shortest possible string. It seems a waste to just turn it into a hex string and let G through Z go to waste.

One idea I have had is getting the MD5 hash of my input as an array of bytes and constructing a BigInt with it. I can then call toString(36), and get the number as a base-36 in a string (-?[0-9a-z]*, the number can be positive or negative). It works for me.

Problem is, I'm not sure that a BigInt can be constructed with any array of bytes, and I can't prove it with testing (at least not in a timely way!). I assume so, because I understand that a BigInt can be of arbitrary size. I can't use this method until I know for sure that it will work for all possible outputs. So, can anyone tell me whether it will work for all inputs (or how to easily convert a byte array so it can be represented in base 36).

Clarification: I have the implementation, I'm asking about the behaviour over the whole domain (i.e. 00000000000000000000000000000000 to FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

一身骄傲 2024-08-16 03:56:28

根据您上面的反馈,以下实现将可靠地对任意字节数组进行编码/解码:

package blevins.example

object BigIntEncoder {
  val radix = 36

  implicit def byteArrayToString(ba: Array[Byte]): String = {
    new java.math.BigInteger(addByte(ba)).toString(radix)
  }

  implicit def stringToByteArray(s: String): Array[Byte] = {
    stripByte(new java.math.BigInteger(s, radix).toByteArray)
  }

  def addByte(ba: Array[Byte]): Array[Byte] = {
    val h = new Array[Byte](1)
    h(0) = 0x01
    h ++ ba
  }

  def stripByte(ba: Array[Byte]): Array[Byte] = {
    ba.slice(1,ba.size)
  }

}

请注意,我们在数组的头部添加了一个额外的 0x01 字节,以避免采用字节数组的两个补码产生任何副作用。

编辑:证明这一点所涉及的测试记录在此处: http://cleverlytitled.blogspot .com/2009/10/scalacheck.html

Building on your feedback above, the following implementation will reliably encode/decode an arbitrary byte array:

package blevins.example

object BigIntEncoder {
  val radix = 36

  implicit def byteArrayToString(ba: Array[Byte]): String = {
    new java.math.BigInteger(addByte(ba)).toString(radix)
  }

  implicit def stringToByteArray(s: String): Array[Byte] = {
    stripByte(new java.math.BigInteger(s, radix).toByteArray)
  }

  def addByte(ba: Array[Byte]): Array[Byte] = {
    val h = new Array[Byte](1)
    h(0) = 0x01
    h ++ ba
  }

  def stripByte(ba: Array[Byte]): Array[Byte] = {
    ba.slice(1,ba.size)
  }

}

Note that we are adding an extra 0x01 byte to the head of the array to avoid any side effects from taking the two-complement of the byte array.

EDIT: The testing involved to prove this out is documented here: http://cleverlytitled.blogspot.com/2009/10/scalacheck.html

你的往事 2024-08-16 03:56:28

Base64编码不是比Base36短吗?您可以找到大量的实现。

但是,要真正回答这个问题:

  // Make a big randomly-filled byte array
  val random = scala.util.Random
  val arraySize = 8543
  val bytes: Array[Byte] = new Array[Byte](arraySize) // make some big array
  random.nextBytes(bytes) // fill it randomly

  // Make a BigInt out of it and the corresponding base36 string representation
  val bi: BigInt = new BigInt(new java.math.BigInteger(bytes))
  val strRep: String = bi.toString(36)

  // Make a new BigInt out of the string rep.  Does it match?
  val bi2: BigInt = new BigInt(new java.math.BigInteger(strRep, 36))
  if (bi == bi2) {
      println("yippee!!")
  }

  // Make a new byte array out of the BigInt.  Does it match the original array?
  val bytes2: Array[Byte] = bi2.toByteArray
  if (bytes deepEquals bytes2) {
      println("yippee again!!")
  }

Wouldn't Base64 encoding be shorter than Base36? You can find plenty of implementations around.

But, to actually answer the question:

  // Make a big randomly-filled byte array
  val random = scala.util.Random
  val arraySize = 8543
  val bytes: Array[Byte] = new Array[Byte](arraySize) // make some big array
  random.nextBytes(bytes) // fill it randomly

  // Make a BigInt out of it and the corresponding base36 string representation
  val bi: BigInt = new BigInt(new java.math.BigInteger(bytes))
  val strRep: String = bi.toString(36)

  // Make a new BigInt out of the string rep.  Does it match?
  val bi2: BigInt = new BigInt(new java.math.BigInteger(strRep, 36))
  if (bi == bi2) {
      println("yippee!!")
  }

  // Make a new byte array out of the BigInt.  Does it match the original array?
  val bytes2: Array[Byte] = bi2.toByteArray
  if (bytes deepEquals bytes2) {
      println("yippee again!!")
  }
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文