【问题标题】:Modulo of negative integers in GoGo中负整数的模
【发布时间】:2017-08-18 11:54:18
【问题描述】:

我目前正在学习 GoLang,我来自 Python 背景。

最近,我偶然发现了 %(modulo) 运算符的一种行为,它与 Python 中的相应运算符不同。与modular operation和余数的定义完全相反,负整数与正整数的模返回负值。

例子:

Python

a, b, n = -5, 5, 3
for i in range(a, b):
    print(i%n)    

输出:

1
2
0
1
2
0
1
2
0
1

a, b, n := -5, 5, 3
for i:=a; i<b; i++ {
    fmt.Println(i%n)
}

输出:

-2
-1
0
-2
-1
0
1
2
0
1

在阅读了Modulo operator 和少数类似的questions 后询问了这些差异背后的原因,我了解到这些是由于相关语言的设计目标造成的。

第一季度。我想知道为什么 Go 在这里遵循 C/C++ 的协议而不是 Python。任何相关讨论的链接都会有所帮助。

第二季度。 Go 中是否有一个内置功能可以复制 Python 的模运算?
替代:是否有计算“模数”而不是“余数”的内部方法?

【问题讨论】:

    标签: python go modulo


    【解决方案1】:

    this comment by one of the language designers:

    目前的定义有几个原因:

    • 由于 x86 架构,当前的 % 语义可直接使用
    • 更改基本运算符 % 的含义而不更改其名称会令人困惑
    • 从 % 结果计算另一个模数相当容易

    请注意,% 计算的是“余数”而不是“模数”。

    标准库中没有复制 Python 的模运算的运算符或函数。

    可以编写一个复制 Python 取模运算的函数:

    func modLikePython(d, m int) int {
       var res int = d % m
       if ((res < 0 && m > 0) || (res > 0 && m < 0)) {
          return res + m
       }
       return res
    }
    

    请注意,在 Python 中 5 % -3-1 并且此代码也复制了该行为。如果您不希望这样,请删除 if 语句中 || 之后的第二部分。

    【讨论】:

    • 感谢您的参考。自从它关闭以来,这个问题就从我身边溜走了。我将更新我的问题以反映这一点。
    • 您可以将 Go to Python Modulus 代码简化为:(i % n) + n) % n。已验证here
    【解决方案2】:

    你的第二季度

    是否有计算“模数”而不是“余数”的内部方法?

    以及最热门答案引用的评论...

    请注意,% 计算的是“余数”而不是“模数”。

    有点误导...

    查找“模”的任何定义,总的来说,它会说它是除法后的余数。问题是当我们说“余数”时,它意味着只有一个。当涉及负数时,可能有超过 1 个不同的余数。在Remainder 的维基百科页面上,它区分了least positive remainderleast absolute remainder。您还可以添加least negative remainder(最小的负数表示负数,但最接近 0)。

    通常对于模数运算符,如果返回正值,则为least positive remainder,如果返回负值,则为least negative remainder。返回值的符号可以通过多种方式确定。例如给定c = a mod b,您可以将c 的符号定义为

    • a 的符号(% 在 Go 中的作用)
    • b 的符号(% 在 Python 中的作用)
    • 总是非负数

    这里是编程语言列表及其以这种方式定义的模实现https://en.wikipedia.org/wiki/Modulo_operation#In_programming_languages

    无论如何,这是一种使用 Go 函数复制 Python 的 % 运算符的无分支方式

    func mod(a, b int) int {
        return (a % b + b) % b
    }
    

    重申一下,这符合规则

    给定c = a mod bc 的符号将是 b 的符号。 或者换句话说,模数结果与除数具有相同的符号

    【讨论】:

      【解决方案3】:

      Python 是一种特殊的语言,Guido Guido van Rossum 是 BDFL。以下是他对他决定与众不同的原因的解释:

      The History of Python: Why Python's Integer Division Floors

      【讨论】:

      • 我不确定是否有异质性,rubylua 的行为方式相同。
      【解决方案4】:

      math/big 做欧几里得模数:

      package main
      import "math/big"
      
      func mod(x, y int64) int64 {
         bx, by := big.NewInt(x), big.NewInt(y)
         return new(big.Int).Mod(bx, by).Int64()
      }
      
      func main() {
         z := mod(-5, 3)
         println(z == 1)
      }
      

      https://golang.org/pkg/math/big#Int.Mod

      【讨论】:

        【解决方案5】:

        在第二季度,您可以使用:

        func modNeg(v, m int) int {
            return (v%m + m) % m
        }
        

        会输出:

        modNeg(-1, 5) => 4
        modNeg(-2, 3) => 0
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2016-02-04
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2015-10-31
          • 2020-10-01
          • 1970-01-01
          相关资源
          最近更新 更多