2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

平方根をとった数字が整数かどうかを判断するのに恐ろしく手間をかけていた話

Last updated at Posted at 2019-11-03

##はじめに

本日は題名の通り、私がAtcoderの問題を解いていてたまに出てくる、
ある値の平方根が、整数になるかどうか、という判定の為に書いたソースについて
説明していこうと思います。

##失敗例

平方根をどうやって計算しても良いかわからない私は、
とりあえずググって出てきたMath.sqtr(x)を使って平方根を求めることを覚えました。

それをどうやって整数か判断するか、と考えた時、私の頭の中では、
「整数 = 小数点が存在しない数」という式を思いついた為、
そのように書いてみることにしました。

sample.rb
x = gets.split(' ').map(&:to_i)
count = 0
x.times do |n|
 a = Math.sqrt(n)
 #以下で、小数が存在しないことを判定
 if a(-1) == nil
  count += 1
 end
end

aの-1桁目、小数第一位が存在しない=整数、と言うことを考えていましたが、
見事にこれは不正解となりました。

##何が問題だったのか

上記のソース何が悪かったか、と言いますと、
Math.sqrtを使って、平方根をとった数字は、float型となってしまう点です。
そのため、答えが整数であっても1とはならず、1.0となってしまうので、
小数第一位がどの数字にも、存在することになってしまうのです。

##どうやって解決したか

###失敗した解決策

またしても失敗例となりますが、上記を試してダメだった私は、
「小数が存在しない=小数第一位で切り上げしても数字が変わらない」と考えたため、
切り上げのceilを使って以下のように変更してみました。

sample.rb
x = gets.split(' ').map(&:to_i)
count = 0
x.times do |n|
 #以下で、平方根をとった数字に小数が存在しないことを判定
 if Math.sqrt(n).ceil == Math.sqrt(n)
  count += 1
 end
end

ですがこちらも案の定不正解です。
小数第一位が0であっても、x.012395995...となり、
整数とならない可能性を考慮できていませんでした。

###成功した解決策
では、どうやって整数かを判定したのか。
正直私の中では、数字をどう使って判定すれば良いかわかりませんでした。
結果として、最善策でないのは百も承知で、以下のような方法で判定してきました。

sample.rb
x = gets.split(' ').map(&:to_i)
count = 0
x.times do |n|
 #以下で、平方根をとった数字に小数が存在しないことを判定
 a = Math.sqrt(n).to_s
 index = a.index('.')
 if a[index+2] == nil
  count += 1
 end
end

平方根をとった数字を一回文字列に変換します。
そして、'.'が何番目に存在するかを取得し、
'.'の位置から+2番目、つまり小数第2位に当たる数が存在するかどうかを判定し、
存在した場合は、整数でない、存在しない場合は、整数という風に判別しました。

##もうちょっと改善

一応、求めたかった答えを得ることはできましたが、
あまりにもまどろっこしいやり方なため、
もう少しスマートに解きたい、と思っていたところ、
ある方から頂いた助言により、できたのが以下のソースです。

sample.rb
x = gets.split(' ').map(&:to_i)
count = 0
x.times do |n|
 #以下で、平方根をとった数字に小数が存在しないことを判定
 a = Math.sqrt(n)
 if a%1 == 0
  count += 1
 end
end

平方根をとった数字を1で割って余りが出るかどうか、を判定して、
整数かどうかを見分ける方法ですね。

何を思ったか、私は小数以下は1で割ったら無視されると考えていました。

##最後に

かなり苦しめられた問題でしたが、
自分で不恰好なりにも、一つ斬新?な発想で解を用意し、
最終的には文字列に変えずに、整数を判定する方法がわかったので、
大きな収穫だったと思います。

競技プログラミングをすることで、
コーディングが上達するのかはよくわかりませんが、
与えらた条件をうまく使って、
文字・数値・配列などを自由に扱えるようになれれば、と思います!

2
1
3

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
2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?