Codeへの愛とCuriosity

CodeIQ への出題・解説解題・その周辺について、思いつくままに。

直角を探せ! 〜ピタゴラスさんありがとう〜 の解説・解題

問題

問題は
直角を探せ! 〜ピタゴラスさんありがとう〜
に置いた。

三辺の長さを与えるので、どこに直角があるのかを求めようという問題。
タイトルに「ピタゴラスさん」とあるので、三平方の定理を使うというところまでヒントがある。

出題意図など

この問題も、浮動小数点を使ったら負けるということを意図している。
テストケースの最後にある

5048.5204,8157.7159,9593.5336

は、浮動小数点をつかって計算すると

#ruby
[5048.5204,8157.7159].map{|x| x**2 }.sum #=> 92035886.93432897
9593.5336**2 #=> 92035886.93432897

となり、直角三角形であるように見えてしまう。
しかしこれは誤差なしで計算すると

#ruby
require "bigdecimal"
["5048.5204","8157.7159"].map{|x| BigDecimal(x)**2 }.sum #=> 0.9203588693432897e8
BigDecimal("9593.5336")**2 #=> 0.9203588693432896e8

あるいは

#ruby
[5048.5204r,8157.7159r].map{|x| x**2 }.sum #=> (9203588693432897/100000000)
9593.5336r**2 #=> (143806073334889/1562500)

なので、ほんの少し直角ではない。

というわけで、JavaScript の人には厳しい問題だったわけだけど、言語の選択は自由なので rubypython のような有理数型がある言語を選べば良いと思う。

実装例

まあ ruby で。
主要部分のみだけど

def solve(x)
  lens=x.split(",").map( &:to_r)
  m=lens.max
  r=(lens-[m]).inject( m*m ){ |acc,e| acc-e*e }
  if r==0
    (lens.index(m)+?A.ord).chr
  else
    "x"
  end
end

こんな感じ。
「map」の中の「to_r」がポイント。ruby 便利だね。