如何让Scala处理大数字

问题描述 投票:0回答:1

我有一个Python函数,我试图转换为Scala:

蟒蛇:

def pseudoRandom(value):
  loops = (value & 0x7F) + 21
  for index in range(loops):
    value += ((value * 7) ^ (value << 15)) + 8 * index - (value >> 5)
    value &= ((1 << 64) - 1)
  return value

在Scala中,我将其定义如下:

def pseudoRandom(value: Long): Long = {
  val loops = (value & 0x7F) + 21L
  var v = value
  (0L to loops).foreach { index =>
    v += ((v * 7) ^ (v << 15)) + 8 * index - (v >> 5)
    v &= ((1 << 64) -1)
  }
  v
}

据推测,这会因溢出而失败,但我不确定如何修复它。我尝试过如下使用BigInt:

def pseudoRandom(value: Long): BigInt = {
  val loops = (value & 0x7F) + 21L
  var v = BigInt(value)
  (0L to loops).foreach { index =>
    v += ((v * 7) ^ (v << 15)) + 8 * index - (v >> 5)
    v &= ((1 << 64) -1)
  }
  v
}

这也失败了。

我期望的行为(基于python代码):

Input      Output
1          7979149037415411353
2          934307080801911839
3          9329215801069440317

我的scala代码的实际输出

Input      Output
1          0
2          0
3          0
python scala bigint
1个回答
3
投票

这有效:

def pseudoRandom(value: Long): BigInt = {
  val loops = (value & 0x7F).toInt + 21
  val mask = (BigInt(1) << 64) - 1
  var v = BigInt(value)
  for (i <- 0 until loops) {
    v += ((v * 7) ^ (v << 15)) + 8 * i - (v >> 5)
    v &= mask
  }
  v
}

未排序的代码枚举枚举:

  • 一旦你截断到& 0x7F,它肯定是一个小int,而不是很长
  • range(n)对应0 until n,而不是0 to n
  • 1 << 64不会给你任何理智,而是定义一次BigInt面具
  • foreach是非惯用的,使用简单的for-loop糖。

前十个正整数的输出:

7979149037415411353
934307080801911839
9329215801069440317
8332103895783241284
1972840215733196111
9936661750801020912
9568736274889204650
13195389261695658308
3299225817465251241
3456601764545139813

零出现是因为(1 << 64) - 1 = 0

© www.soinside.com 2019 - 2024. All rights reserved.