こんにちは。うっかりじゅうべえ(@u-10bei)と申します。
R言語とPythonを用途によって使い分けていると、時々言語のお作法や文法がごっちゃになって混乱してしまうことがあります。
そこで、色々気になることを備忘録としてまとめてみました。
はじめに
今回は、基礎の基礎というべき、四則演算についてです。
環境
Google colaboratoryを使用して確認をしています。
1. 同じ数式で同じ結果が出る場合
Rの場合
%%script R --vanilla --quiet
print(1 * 2 + 2 / 4 - 1)
print(1 * (2 + 2) / 4 - 1)
を実行すると、
>print(1 * 2 + 2 / 4 - 1)
[1] 1.5
>print(1 * (2 + 2) / 4 - 1)
[1] 0
と返ってきます。
Pythonの場合
# 実行コード
print(1 * 2 + 2 / 4 - 1)
print(1 * (2 + 2) / 4 - 1)
を実行すると、
1.5
0.0
と同じ結果が返ってきます。(小数点のありなしは後で説明します。)
2. 【脱線】colabで同一セル内でprint関数を使わなかった時のふるまい
Rの場合
ただ、そもそも演算結果を表示するだけなら、R関数にprint関数は不要です。
%%script R --vanilla --quiet
1 * 2 + 2 / 4 - 1
1 * (2 + 2) / 4 - 1
を実行しても、
>1 * 2 + 2 / 4 - 1
[1] 1.5
>1 * (2 + 2) / 4 - 1
[1] 0
1と同じ結果が返ってきます。
Pythonの場合
では、Pythonで同じことをやってみます。
1 * 2 + 2 / 4 - 1
1 * (2 + 2) / 4 - 1
を実行すると、
実行結果
0.0
が返ってきます。
colabでは、pythonはprint関数を使わないと、最後の結果だけが表示されるようです。
3. 文法が違う場合
次に、RとPythonで文法が違う場合を試してみます。
Rの場合
%%script R --vanilla --quiet
5 %% 3 # 5割る3の余り
5 %/% 3 # 整数除算
1.0 + 2 * 3 # 浮動小数点型の計算
を実行すると、
> 5 %% 3 # 5割る3の余り
[1] 2
> 5 %/% 3 # 整数除算
[1] 1
> 1.0 + 2 * 3 # 浮動小数点型の計算
[1] 7
が返ってきます。
Pythonの場合
同じことを、Pythonでやる場合は、演算子が違います。
print(5 % 3) # 5割る3の余り
print(5 // 3) # 整数除算
print(1.0 + 2 * 3) # 浮動小数点型の計算
とすると、同じ実行結果が返ってきます。
2
1
7.0
4. 【脱線】浮動小数点型と整数型
現時点では細かいことになりますが、RとPythonでは浮動小数点型と整数型を意識する場合は、ずいぶん文法が違います。
Rの場合
たとえば、Rでは、
%%script R --vanilla --quiet
a = 1 + 2 * 3
b = 1.0 + 2 * 3
typeof(a) # Rでの変数型を確認する
typeof(b)
を実行すると、
> a = 1 + 2 * 3
> b = 1.0 + 2 * 3
> typeof(a) # Rでの変数型を確認する
[1] "double"
> typeof(b)
[1] "double"
が返ってきます。明示しない限り、実数型の変数になるようです。
あえて整数型の変数に格納したい場合は、
%%script R --vanilla --quiet
c = 1L + 2L * 3L
typeof(c)
のように、整数の後にLをつけてあげると、
> c = 1L + 2L * 3L
> typeof(c)
[1] "integer"
と整数型で格納されます。
Pythonの場合
同じことを、Pythonでやると結果が変わります。
a = 1 + 2 * 3
b = 1.0 + 2 * 3
print(type(a)) # Pythonでの変数型を確認する
print(type(b))
とすると、
<class 'int'>
<class 'float'>
と返ってきます。入力した結果に応じて、浮動小数点型と整数型に分かれた変数になるようです。
5. 【更に脱線】割り算の罠
ただし、割り算をする場合は注意が必要です。
Rの場合
%%script R --vanilla --quiet
d = (2L + 2L) / 4L
d
typeof(d)
e = floor((2L + 2L) / 4L)
e
typeof(e)
を実行すると、
> d = (2L + 2L) / 4L
> d
[1] 1
> typeof(d)
[1] "double"
> e = floor((2L + 2L) / 4L)
> e
[1] 1
> typeof(e)
[1] "double"
>
のように整数の後にLをつけたり、floor関数で整数を取り出しても、実数型で格納されます。
あえて整数型の変数に格納したい場合は、
%%script R --vanilla --quiet
f = (2L + 2L) %/% 4L
f
typeof(f)
のように、整数演算を使うと、
> f = (2L + 2L) %/% 4L
> f
[1] 1
> typeof(f)
[1] "integer"
>
と、整数型で格納されます。
Pythonの場合
Pythonの場合も、同じことが起こります。
d = (2 + 2) / 4
print(d)
print(type(d))
e = int(2 + 2) / 4
print(e)
print(type(e))
を実行すると、
1.0
<class 'float'>
1.0
<class 'float'>
のように整数の後にLをつけたり、int関数で整数を取り出しても、実数型で格納されます。
あえて整数型の変数に格納したい場合は、
f = (2 + 2) // 4
print(f)
print(type(f))
のように、整数演算を使うと、
1
<class 'int'>
と、整数型で格納されます。
6. 同じ数式で違う結果が出る場合
最後に、同じ数式で違う結果が返ってくる場合や、その他四則演算に関する文法の違いを試してみます。
Rの場合
%%script R --vanilla --quiet
print(12 ^ 12) # べき乗
print((-2) ** 0.5) # 虚数計算できない
print(6 / 0) # ゼロで割ると無限大が返ってくる
を実行すると、
> print(12 ^ 12) # べき乗
[1] 8.9161e+12
> print((-2) ** 0.5) # 虚数計算できない
[1] NaN
> print(6 / 0) # ゼロで割ると無限大が返ってくる
[1] Inf
>
と、コメントで書いた結果が返されます。
Rでは基本的に計算できない場合は、非数値の値が返ってきます。
Pythonの場合
Pythonで全く同じ計算式を入力してみます。
print(12 ^ 12) # ビット単位の排他的論理和
print((-2) ** 0.5) # 虚数計算できる
print(6 / 0) # ゼロで割るとエラー
を実行すると、
0
(8.659560562354934e-17+1.4142135623730951j)
---------------------------------------------------------------------------
ZeroDivisionError Traceback (most recent call last)
<ipython-input-37-cf077fd4dc77> in <module>
1 print(12 ^ 12) # ビット単位の排他的論理和
2 print((-2) ** 0.5) # 虚数計算できる
----> 3 print(6 / 0) # ゼロで割るとエラー
ZeroDivisionError: division by zero
と、コメントで書いたように全然違う計算結果が返ってきます。
特に、ゼロ除算はその後の処理に大きく影響するので、忘れないようにします。
おわりに
今回はここまでにします。どちらかというと、お作法ではなく文法の違いになりました。
(@Wolfmoonさん、ご指摘ありがとうございます。)
次回は変数と代入をやりたいと思います。