我在Internet上搜索了一种使用scala编程语言查找BigInt确切平方根的函数。我没有一个,但是看到一个Java程序,然后将该函数转换为Scala版本。它正在工作,但是我不确定它是否可以处理很大的BigInt。但是它仅返回BigInt。不是BigDecimal作为平方根。它显示了在代码中完成了一些操作,例如对数字shiftRight(5), BigInt("8") and shiftRight(1)
进行了硬编码。我可以清楚地理解逻辑,但是不能对这些移位数字和数字8进行硬编码。也许这些移位函数在scala中不可用,这就是为什么在几个地方都需要将其转换为Java BigInteger的原因。这些硬编码的数字可能会影响结果的精度。我只是将Java代码更改为scala代码,只是复制了精确的算法。这是我在scala中编写的代码:
def sqt(n:BigInt):BigInt = {
var a = BigInt(1)
var b = (n>>5)+BigInt(8)
while((b-a) >= 0) {
var mid:BigInt = (a+b)>>1
if(mid*mid-n> 0) b = mid-1
else a = mid+1
}
a-1
}
我的积分是:
shiftRight(5), shiftRight(1) and 8
是如何关联的
精确到结果。我在scala REPL中测试了一个数字:函数sqt
给出平方数的确切平方根。而不是实际数字,如下所示:
scala> sqt(BigInt("19928937494873929279191794189"))
res9: BigInt = 141169888768369
scala> res9*res9
res10: scala.math.BigInt = 19928937494873675935734920161
scala> sqt(res10)
res11: BigInt = 141169888768369
scala>
我了解shiftRight(5) means divide by 2^5 ie.by 32 in decimal
等等。但是为什么在移位操作后在此处添加8?为什么恰好是5个班次?作为第一个猜测?
答案 0 :(得分:3)
您的问题1和问题3实际上是同一个问题。
- 这些移位如何影响结果的精度?
他们没有。
- 这些硬编码数字与结果的精确度有何关系?
不是。
有许多不同的方法/算法可用于估算/计算数字的平方根(如here所示)。您发布的算法似乎是非常简单的二进制搜索。
a
,保证它小于目标数(n
的平方根)。b
,保证其大于目标值(n
的平方根)。mid
,即a
和b
之间的整数中点。mid
大于(或等于)目标,则将b
移至mid
(-1,因为我们知道它太大了)。mid
小于目标,则将a
移至mid
(+ 1,因为我们知道它太小了。)a
不小于b
。a-1
的平方根取整后返回n
。位移和硬编码数字用于选择b
的初始值。但是b
仅大于目标。我们本可以完成var b = n
。为什么要打扰?
一切都与效率有关。 b
离目标越近,找到结果所需的迭代次数就越少。为什么在班次后加8?因为31 >> 5为零,因此不大于目标值。作者选择了(n>>5)+8
,但是他/她可能选择了(n>>7)+12
。需要权衡。
- 我们不能返回BigDecimal而不是BigInt吗?我们该怎么做?
这是做到这一点的一种方法。
def sqt(n:BigInt) :BigDecimal = {
val d = BigDecimal(n)
var a = BigDecimal(1.0)
var b = d
while(b-a >= 0) {
val mid = (a+b)/2
if (mid*mid-d > 0) b = mid-0.0001 //adjust down
else a = mid+0.0001 //adjust up
}
b
}
有更好的算法来计算浮点平方根值。在这种情况下,使用较小的调整值可以提高精度,但效率会大大降低。
答案 1 :(得分:0)
我们不能返回BigDecimal而不是BigInt吗?我们该怎么做?
如果您想要精确的根,则没有任何意义:如果BigInt
的平方根可以由BigDecimal
精确表示,则可以由BigInt
表示。如果您不希望确切的根,则需要指定精度并修改算法(在大多数情况下,Double
会足够好,并且比BigDecimal
快得多)。>
我理解shiftRight(5)表示除以2 ^ 5,即以十进制除以32,依此类推..但是为什么在进行移位运算后在此处加上8?为什么恰好是5个班次?作为第一个猜测?
这些不是唯一的选择。关键是对于每个正数n
,n/32 + 8 >= sqrt(n)
(其中sqrt
是数学平方根)。通过一点演算(或仅通过建立差异图)就可以最容易地显示出这一点。因此,一开始我们就知道a <= sqrt(n) <= b
(除非n == 0
可以单独检查),并且您可以在每一步中验证其是否成立。