如何在不使用”/”和”%”的情况下有效地获取商和余数?

huangapple go评论129阅读模式
英文:

How to get the quotient and remainder effectively without using "/" and "%"?

问题

我已经实现了一个简单的函数,当除数是10的幂时,它返回商和余数:

  1. func getQuotientAndRemainder(num int64, digits uint) (int64, int64) {
  2. divisor := int64(math.Pow(10, float64(digits)))
  3. if num >= divisor {
  4. return num / divisor, num % divisor
  5. } else {
  6. return 0, num
  7. }
  8. }

只是好奇,除了直接使用/%运算符,是否有更好的算法来获取商和余数?或者只有在除数是10的幂的情况下才适用?

英文:

I have implemented a simple function which returns the quotient and remainder when the divisor is the power of 10:

  1. func getQuotientAndRemainder(num int64, digits uint) (int64, int64) {
  2. divisor := int64(math.Pow(10, float64(digits)))
  3. if num >= divisor {
  4. return num / divisor, num % divisor
  5. } else {
  6. return 0, num
  7. }
  8. }

Just curious, except using directly / and % operators, is there any better algorithm to get the the quotient and remainder? Or only in the case when the divisor is the power of 10?

答案1

得分: 1

  1. 返回 num / divisor, num % divisor
  2. 算法是可靠的并且以一种可以说是最好的方式编写表达性强如果有什么问题可能是你的代码这部分过于复杂
  3. int64(math.Pow(10, float64(digits)))
  4. 转换为和从 `float64` 的类型可能不是最佳选择而且10 的任何大于 18 的次方都会导致 `int64` 溢出我建议你添加一个合理性检查并用一个乘法循环替换这段代码并测量其性能
  5. 但是如果性能是你关心的问题那就直接用汇编语言实现吧
英文:
  1. return num / divisor, num % divisor

The "algorithm" is sound and written in arguably the best way possible: expressively. If anything, this part of your code may be overly complicated:

  1. int64(math.Pow(10, float64(digits)))

Converting to and from float64 is arguably sub-optimal. Also, 10 to the power of anything greater than 18 will overflow int64. I suggest you add a sanity check and replace the code with a multiplying loop and measure its performance.

But then: if performance is your concern, just implement it in assembly.

答案2

得分: 1

显然,你应该运行一些Go基准测试:基准测试,测试包

你的解决方案看起来不太高效。试试这个:

  1. package main
  2. import "fmt"
  3. func pow(base, exp int64) int64 {
  4. p := int64(1)
  5. for exp > 0 {
  6. if exp&1 != 0 {
  7. p *= base
  8. }
  9. exp >>= 1
  10. base *= base
  11. }
  12. return p
  13. }
  14. func divPow(n, base, exp int64) (q int64, r int64) {
  15. p := pow(base, exp)
  16. q = n / p
  17. r = n - q*p
  18. return q, r
  19. }
  20. func main() {
  21. fmt.Println(divPow(42, 10, 1))
  22. fmt.Println(divPow(-42, 10, 1))
  23. }

输出:

  1. 4 2
  2. -4 -2

基准测试:

  1. BenchmarkDivPow 20000000 77.4 ns/op
  2. BenchmarkGetQuotientAndRemainder 5000000 296 ns/op
英文:

Obviously, you should run some Go benchmarks: Benchmarks, Package testing.

Your solution doesn't look very efficient. Try this:

  1. package main
  2. import "fmt"
  3. func pow(base, exp int64) int64 {
  4. p := int64(1)
  5. for exp > 0 {
  6. if exp&1 != 0 {
  7. p *= base
  8. }
  9. exp >>= 1
  10. base *= base
  11. }
  12. return p
  13. }
  14. func divPow(n, base, exp int64) (q int64, r int64) {
  15. p := pow(base, exp)
  16. q = n / p
  17. r = n - q*p
  18. return q, r
  19. }
  20. func main() {
  21. fmt.Println(divPow(42, 10, 1))
  22. fmt.Println(divPow(-42, 10, 1))
  23. }

Output:

  1. 4 2
  2. -4 -2

Benchmark:

  1. BenchmarkDivPow 20000000 77.4 ns/op
  2. BenchmarkGetQuotientAndRemainder 5000000 296 ns/op

huangapple
  • 本文由 发表于 2016年3月3日 11:19:30
  • 转载请务必保留本文链接:https://go.coder-hub.com/35762564.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定