Issue #17257 has been updated by universato (Yoshimine Sato).


sawa (Tsuyoshi Sawada) wrote in #note-10:
> I cannot follow the discussion because of the expression "multiplying `x % m` to 1 `y` times." What does that mean?

"multiplying x % m to 1 y times"の意味は、「1に対して(x % m)をy回乗じること(又は、その値)」ですかね。

想像以上に議論が活発で嬉しいですが慣れない英語で疲れたし読み誤っているかもしれないので、自分のために日本語で整理します。

nobuさんが、最初に#1で「x.pow(y, m)は1に(x % m)をy回乗じた値に等しいから、y == 0のときは1でいいのではないでしょうか」と言ってます。

そして、自分の#9を言い直すと「`3.pow(2, 4)`が1に対して、`1に(3 % 4)`を2回乗じた値は9であるため、`x.pow(y, m)`は1に`(x % m)`を`y`回乗じた値に等しいとは限りません。powの計算結果はm未満になるはずです。x.pow(0, 1)の挙動に合わせるために、現状のシンプルな定義`(x**y) % m`から`x.pow(0, 1)`だけ例外的に1を返す特別な理由を付け加えたり変更することは難しいと思いました。」と言いたかったです。

midnightさんの#7の意見もおそらく同様で「ドキュメントを"1に対して`(x % m)`を`y`回乗じること"に変更するのですか。私の考えでは、`% m`とは空間であり、その空間の中で掛け算が行われるから、計算結果は空間に収まるべきです(≒`m`未満になるべき)。」と言ってます。

......

あと話が変わりますが、「mod 1を使うケースは普通ない」という意見もあり、半分同意です。ただ、あらゆるmodのケースを想定して最小正数の1でもテストしたら自分が詰まったので決してmod 1を使うケースは0ではないはずで、小さいけどバグだと思ったので変更されてもいいはずと思い、今回提案しました。また、変更するにあたってのデメリットも小さいはずと考えました。x.pow(0, 1)の挙動を積極的に使う人はいないはずで後方互換性の影響を気にしなくても大丈夫だと思います。また、コードの修正も基本的には`if(m == 1){ return 0 }`を加えるだけだと想像しました。このあたりは、コードを書いた担当者のmrknさんの意見も聞きたいところです。その他の提案理由は、Pythonのmod_powは正しい動作をしてる気がするのに悔しいなぐらいです。

Sorry for writing only in Japanese

----------------------------------------
Bug #17257: Integer#pow(0, 1) returns 1, which is incorrect
https://bugs.ruby-lang.org/issues/17257#change-87986

* Author: universato (Yoshimine Sato)
* Status: Assigned
* Priority: Normal
* Assignee: mrkn (Kenta Murata)
* Backport: 2.5: UNKNOWN, 2.6: UNKNOWN, 2.7: UNKNOWN
----------------------------------------
Ruby 2.5.8, 2.6.6, 2.7.1


```ruby
p -1.pow(0, 1) #=> 1
p  0.pow(0, 1) #=> 1
p  1.pow(0, 1) #=> 1
p 1234567890.pow(0, 1) #=> 1
```

These return values should be 0.


Patch for test:

Let's add some boundary value tests to `test_pow` of [test_numeric.rb](https://github.com/ruby/ruby/blob/e014e6bf6685f681998238ff005f6d161d43ce51/test/ruby/test_numeric.rb).

```ruby
integers = [-2, -1, 0, 1, 2, 3, 6, 1234567890123456789]
integers.each do |i|
  assert_equal(0, i.pow(0, 1), '[Bug #17257]')
  assert_equal(1, i.pow(0, 2))
  assert_equal(1, i.pow(0, 3))
  assert_equal(1, i.pow(0, 6))
  assert_equal(1, i.pow(0, 1234567890123456789))
  
  assert_equal(0,  i.pow(0, -1))
  assert_equal(-1, i.pow(0, -2))
  assert_equal(-2, i.pow(0, -3))
  assert_equal(-5, i.pow(0, -6))
  assert_equal(-1234567890123456788, i.pow(0, -1234567890123456789))
end

assert_equal(0,  0.pow(2, 1))
assert_equal(0,  0.pow(3, 1))
assert_equal(0,  2.pow(3, 1))
assert_equal(0, -2.pow(3, 1))



-- 
https://bugs.ruby-lang.org/

Unsubscribe: <mailto:ruby-core-request / ruby-lang.org?subject=unsubscribe>
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-core>