1

I want to serialize an into into a Byte array or array buffer.

I realise that I can use 'java.nio.ByteBuffer' but I am experimenting for fun and trying to do it myself.

The following code works for positive Int but goes wrong when I serialize a negative Int. Can anyone explain why or show me a correction?

import scala.collection.mutable.ArrayBuffer

object b {
  val INTBYTES:Int = 4 // int is 4 bytes

  def toArrayBuf(x:Int): ArrayBuffer[Byte] = {
    val buf = new ArrayBuffer[Byte](INTBYTES)
    for(i <- 0 until INTBYTES) {
      buf += ((x >>> (INTBYTES - i - 1 << 3)) & 0xFF).toByte
    }
    buf
  }
}

the following test works as expected:- int the REPL it prints:-

scala> val test:Int = 0x4f0f0f0f
test: Int = 1326386959

scala> println(test.toBinaryString)
1001111000011110000111100001111

scala> val t1 = b.toArrayBuf(test)
t1: scala.collection.mutable.ArrayBuffer[Byte] = ArrayBuffer(79, 15, 15, 15)

scala> t1.foreach( it => printf("%s ",it.toInt.toBinaryString))
1001111 1111 1111 1111 

but this with a negative int does something wierd:-

scala> val test2:Int = 0x8f0f0f0f
test2: Int = -1894838513

scala> println(test2.toBinaryString)
10001111000011110000111100001111

scala> val t2 = b.toArrayBuf(test2)
t2: scala.collection.mutable.ArrayBuffer[Byte] = ArrayBuffer(-113, 15, 15, 15)

scala> t2.foreach( it => printf("%s ",it.toInt.toBinaryString))
11111111111111111111111110001111 1111 1111 1111

notice that the first byte has been 1 filled for the whole int it shoild be '10001111'

Any ideas?

FYI Im using :-

scala -version
Scala code runner version 2.10.1 -- Copyright 2002-2013, LAMP/EPFL
java -fullversion
java full version "1.7.0_40-b31"
with OpenJDK

Thanks

4

2 回答 2

3

Scala 的toBinaryString方法在Integer. 从这些文件中:

公共静态字符串 toBinaryString(int i)

将整数参数的字符串表示形式返回为以 2 为底的无符号整数。无符号整数值是参数加上 2^32(如果参数为负数);否则它等于参数。此值被转换为二进制(以 2 为基数)的 ASCII 数字字符串,没有额外的前导 0。

换句话说,它按规定工作。您的位旋转似乎没问题,但是当您打印出数字时,您需要意识到字符数取决于数据类型的长度。(例如 -1:二进制中的 Int 是 11111111111111111111111111111111,而 -1:字节是 11111111。)您只因不显示前导零而避免使用正数,如上所述。

解决方案:自己toBinaryString制作字节,或者只从 Int 版本中取最右边的 8 位数字应该可以工作(虽然效率较低),即

it.toInt.toBinaryString.takeRight(8)
于 2013-07-26T02:39:32.890 回答
2

接受 Luigi 的建议,我为 Byte 开发了一个 pimp,它提供了一个正常工作的 toBinaryString,以防其他人在这里遇到类似的问题,这就是我所做的。

object b {
  val INTBYTES:Int = 4 // int is 4 bytes
  val SIZEBYTE:Short = 8

  def toArrayBuf(x:Int): ArrayBuffer[Byte] = {
    val buf = new ArrayBuffer[Byte](INTBYTES)
    for(i <- 0 until INTBYTES) {
      buf += ((x >>> (INTBYTES - i - 1 << 3)) & 0xFF).toByte
    }
    buf
  }

  def toBinaryString(x: Byte): String = {
    val buf = new StringBuilder(SIZEBYTE)
    for(i <- 0 until SIZEBYTE) {
      buf.append((x >>> (SIZEBYTE - i - 1)) & 0x01)
    }
    buf.toString()
  }
}

//pimp Byte
implicit def fooBar(byte: Byte) = new {def toBinaryString = b.toBinaryString(byte)}

现在,当我运行上一个实验时,它可以正常工作

scala> val test:Int = 0x4f0f0f0f
test: Int = 1326386959

scala> println(test.toBinaryString)
1001111000011110000111100001111

scala> val t1 = toArrayBuf(test)
t1: scala.collection.mutable.ArrayBuffer[Byte] = ArrayBuffer(79, 15, 15, 15)

scala> t1.foreach( it => printf("%s ",it.toBinaryString))
01001111 00001111 00001111 00001111 

scala> val test2:Int = 0x8f0f0f0f
test2: Int = -1894838513

scala> println(test2.toBinaryString)
10001111000011110000111100001111

scala> val t2 = toArrayBuf(test2)
t2: scala.collection.mutable.ArrayBuffer[Byte] = ArrayBuffer(-113, 15, 15, 15)

scala> t2.foreach( it => printf("%s ",it.toBinaryString))
10001111 00001111 00001111 00001111

谢谢路易吉

于 2013-07-26T14:18:27.520 回答