如何在Golang中使用Math.Pow函数处理整数

16
我一直收到这个错误信息:
cannot use a (type int) as type float64 in argument to math.Pow, cannot use x (type int) as type float64 in argument to math.Pow, 
invalid operation: math.Pow(a, x) % n (mismatched types float64 and int)

func pPrime(n int) bool {
    var nm1 int = n - 1
    var x int = nm1/2
    a := 1;
    for  a < n {
        if  (math.Pow(a, x)) % n == nm1 {
            return true
        }
    }
    return false
}

4
将你的整数转换为浮点数,以便在接受浮点数的函数中使用。 - Adrian
2
我是唯一一个惊讶地发现Go没有整数math.Pow的人吗?作为新手,这让我怀疑是否要转向其他编程语言。 - ibarrond
5个回答

15
func powInt(x, y int) int {
    return int(math.Pow(float64(x), float64(y)))
}

倘若您需要重复使用它并使其更加整洁。


5
虽然这样做可以使代码更加简洁,但如果你想编写一个接受整型参数并返回整型的自定义函数的话,最好避免使用math.Pow。正如我在答案中提到的那样,使用循环来进行乘法运算不仅可以提高性能,还可以消除对外部包的依赖。 - Chris Concannon

12
如果你的输入是int类型,期望输出也始终为int类型,则你正在处理32位数字。编写自己的函数来处理乘法比使用math.Pow更有效。如其他答案所述,math.Pow预期64位值。
这里是15^15的基准比较(接近32位表示的上限):
// IntPow calculates n to the mth power. Since the result is an int, it is assumed that m is a positive power
func IntPow(n, m int) int {
    if m == 0 {
        return 1
    }
    result := n
    for i := 2; i <= m; i++ {
        result *= n
    }
    return result
}

// MathPow calculates n to the mth power with the math.Pow() function
func MathPow(n, m int) int {
    return int(math.Pow(float64(n), float64(m)))
}

结果:
go test -cpu=1 -bench=.
goos: darwin
goarch: amd64
pkg: pow
BenchmarkIntPow15   195415786            6.06 ns/op
BenchmarkMathPow15  40776524            27.8 ns/op

我认为最好的解决方案是编写自己的函数,类似于上面展示的IntPow(m, n int)。我的基准测试显示,与使用math.Pow相比,在单个CPU内核上运行速度快了4倍以上。


你会如何处理幂次运算的负指数?例如:2^-1。 - cesartalves
1
@cesartalves 如果存在负指数,则预期结果不会是整数,因此将值转换为float64并使用math.Pow是适当的。 - Chris Concannon
1
有道理。我只是想改进一下答案,允许将值0传递给m,因为x ^ 0 = 1 :) - cesartalves
啊,我明白你的意思了。我会详细说明IntPow()的描述以澄清约束条件。 - Chris Concannon
5
Go 不包含 IntPow 是很糟糕的。你的实现的时间复杂度是线性的,而像样的标准库应该提供对数复杂度的简单实现。 - Cthulhu

9

如果你想自己实现,而且要以对数级别的高效方式计算整数 xnPow(x, n),可以使用以下方法:

// Assumption: n >= 0
func PowInts(x, n int) int {
   if n == 0 { return 1 }
   if n == 1 { return x }
   y := PowInts(x, n/2)
   if n % 2 == 0 { return y*y }
   return x*y*y
}

2

虽然Eissa提供的上述答案在技术上是正确的高效解决方案,但递归可能会影响性能。请参见实现基于整数的幂函数pow(int, int)最有效的方法以获取更优化的解决方案。这里是C语言解决方案翻译成Go语言:

func IntPow(base, exp int) int {
    result := 1
    for {
        if exp & 1 == 1 {
            result *= base
        }
        exp >>= 1
        if exp == 0 {
            break
        }
        base *= base
    }

    return result
}


在我的基准测试中,这个版本的速度几乎是递归版本的两倍。

过于追求细节:C语言的解决方案应该使用 exp & 1 == 1 --> exp % 2exp >>= 1 --> exp /= 2 来正确处理所有三种可能的int编码,并让编译器发出高效的代码。当然,exp < 0 仍然是一个问题。 - chux - Reinstate Monica

1

如果您需要精确计算整数的乘方,请使用(*big.Int).Exp。当幂大于二时,int64 很快就会溢出。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接