LoginSignup
97
29

More than 1 year has passed since last update.

-3の2乗 という計算

Last updated at Posted at 2022-05-16

これは何?

指数演算子が ** だとして。

-3**2 という文字列を評価する場合。

  • (-3)**2
  • -(3**2)

という二通りの解釈があり得る。

一方。
数学では $-3^{2}$ は $-(3^{2})$ と評価するのが常識となっている。
プログラミング言語ではどうなっているだろうという調査。

各言語の対応

ruby

この調査を始めようと思ったきっかけ。

ruby3.1
p( -3**2 ) #=> -9

つまり、 -3**2-(3**2) となる。
Ruby 3.1 リファレンスマニュアル 演算子式 を見ると、単項 - より ** の優先順位が上なのでそうだよね。
……という簡単な話ではない。

ruby3.1
p( -2[3] ) #=> 1
p( (-2)[3] ) #=> 1
p( -(2[3]) ) #=> 0                

[] の優先順位は最高。
なので、 -2[3]-(2[3]) になりそうなもんだけど、 (-2)[3] になる。
これは、-2[3] の先頭にある - は、単項 - 演算子ではなく、整数リテラルの一部だからだと思う。

実際。 - がリテラルの一部ではありえないようにすれば

ruby3.1
a=2;p( -a[3] ) #=> 0
p( -(2)[3] ) #=> 0

と、 -a[3]-(a[3]) とおなじになるし、-(2)[3]-((2)[3]) とおなじになる。

じゃあなんで -3**2(-3)**2 にならないんだという話だけれども、おそらく、数学の $-3^{2}$ と同じ結果にしたいために指数演算子があとに続く場合は特別扱い、というコードが仕込んであるんだと思う。(思うだけ、調べてない)

→ 2022年5月21日追記: HMMNRST 様の調査によると、やはり特別扱いのコードが仕込まれている模様。

そんな特別扱いのコード仕込まないで -3- をリテラルの一部とみなさなければいいのに、ということにならないのは。
たぶんそうしてしまうと -3 と書くたびにメソッド呼び出しが発生してしまうのでそれも避けたいんじゃないかなと思う(思うだけ、調べてない)。

蛇足

式内にある - には、単項演算子、二項演算子、リテラルの一部、という3つの異なる意味があり得る(文字列の一部など、他にもあるけど)。

下記の通り、わかりにくく、難しい。

ruby3.1
p( -2[3] ) # - は、リテラルの一部
#=> 1
p( 10-2[3] ) # - は、二項演算子
#=> 10
p( 10--2[3] ) # - は、二項演算子・リテラルの一部
#=> 9
p( 10--(2[3]) ) # - は、二項演算子・単項演算子
#=> 10           
p( 10---2[3] ) # - は、二項演算子・単項演算子・リテラルの一部
#=> 11

JavaScript

JavaScript の場合、なんと

JavaScript
console.log(-3**2);
// Error: unparenthesized unary expression can't appear on the left-hand side of '**'

エラーになる。 ** の左辺にマイナスがついているとエラー。びっくりした。

-3**2 のような式が 9 になる言語/ツール

公開当初は

Python3、Perl、Groovy、VB.NET、PHP なんかを調べたけど、調べた範囲では、みんな数学に合わせてあった。
-3^2 のような式が $(-3)^{2}$ という意味になる言語があると思って探したんだけど、見つからなかった。残念。

と書いていたが、 -3**2 のような式が 9 になる言語/ツール を教えていただいたので、確認し次第追記していく。

bash / zsh

※ scivola 様 ありがとうございます

bash と zsh では

bash_or_zsh
$ echo $((-3**2))
9
$ echo $((-(3)**2))
9

と、単項 - 演算子が ** よりも優先順位が上なので -3**2 が 9 になる模様。
というか。 bash に指数演算子があることに驚いた。

それと。
mattn 様 のツイート で気づいたんだけど、

bash_or_zsh
$ echo $((1-3**2))
-8
$ echo $((1--3**2))
-8
$ echo $((1---3**2))
-8

と、ちょっとおもしろいことになる。

bc

※ fujitanozomu 様 ありがとうございます

bash
$ echo "-3^2" | bc 
9
$ echo "-(3)^2" | bc 
9
$ echo "a=3;-a^2" | bc
9

bc の場合、単項 -^ より優先順位が高い模様。

tcl

※ fujitanozomu 様 ありがとうございます

tcl
puts [expr -3**2];   # 9
puts [expr -(3)**2]; # 9
set a {3};
puts [expr -$a**2];   # 9

tcl も、単項 -** より優先順位が高い模様。

Pangaea

※ syuparn 様ありがとうございます。

syuparn 様 の ツイート によると、 Pangea も -3**2 が 9 になるとのこと。(私自身は未確認)

ツイートに

話題の「-3の2乗」、Pangaeaでは9になります😇
(-3はリテラルとして扱われるので)

とあるとおり、 -3- がリテラルの一部であることに起因するとのこと。(私自身は未確認)

Excel ・ Google スプレッドシートの数式

※ tueda 様 ありがとうございます

VB.NET の -3^2-9 になる。
しかし、 Excel の数式はそうではない。
以下、セル A1 に 3 が入っているとして

セルの式 セルの値
=-3^2 9
=-(3)^2 9
=-"3"^2 9
=-A1^2 9
=LAMBDA(-3^2)() 9
=LAMBDA(-(3)^2)() 9
=LAMBDA(x,-x^2)(3) 9

となるので、単項マイナス演算子 - が、指数演算子 ^ より優先順位が上なんだということなんだろう。
LAMBDA 内も同様。

数式を含む Excel ブックを読まなければならない他のアプリケーション・サービスもこのルールに巻き込まれているようで、Google スプレッドシート も同様である。悲しいね。

Excel VBA に関しては試していないけど、 tueda 様のコメントによると VB.NET と同様、つまり Excel の数式とは異なる結果らしい。私も罠だと思う。

97
29
12

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
97
29