• ベストアンサー

if文を使わずに小数の符号を取れるか

if文を使わずに、値が正なら1、0なら0、負なら-1を出力する方法はありますか? if文(とできれば掛け算)を使わずに、変数a(1か-1が入る)と変数b(小数が入る)の符号が違ったらカウントを増やすプログラムを作らないといけないのですが、 変数bを1,0,-1に分けることができれば楽になると考えたのですが、 符号を取り出す関数を見つけることができませんでした。 b/fabs(b)も考えたのですが、これだとb=0の場合に0/0となるためうまくいきません。

質問者が選んだベストアンサー

  • ベストアンサー
回答No.7

No.6 です。 よく見たら、値の制限がかなり強いのですね。まあ、それなら、それ用の手もありかもしれません。 int cntGT[3] = {0}; int cntEQ[3] = {0}; int cntAll = 0; cntGT[a + 1] += (b > 0); cntEQ[a + 1] += (b == 0); cntAll ++; ここで最終的に cntEQ[0] + cntEQ[2] が、b == 0 の数 cntGT[0] が、a == -1 で、b > 0 の数 cntGT[2] が、a == 1 で、b > 0 の数 だから、処理が終わった後で、 cntEQ[0] + cntEQ[2] (ここまで b == 0) + cnt[0] + (cntAll - cnGT[2]) (ここまで、b != 0 で a b が異符号) で合計が出るような気がする。 3つもカウントアップするのがいやかもしれません。

その他の回答 (19)

  • titokani
  • ベストアンサー率19% (341/1726)
回答No.10

>bが0のときはカウントを増やさないといけません。 bが0のときは、aの値とは無関係にカウント増やすということでしょうか? だとすれは、おそらくは単純に、 if( ( b == 0 )|| ((a<0)&&(b<0)) || ((a>0)&&(b>0)) )cnt++; で、十分早いと思います。 これ以上はアセンブリ出力と実際に測定した結果を見ながらカリカリやるしかないですね。 #aおよびbの符号の出現確率によって、条件式の順番を入れ替えることは効果があるかと思います。

回答No.9

訂正です。 まあ、わかるとは思いますが……。 ((b == 0) && (++cntEQ)) || ((b > 0) && (++cntBPlus[a + 1])) || ((b > 0) && (++cntBMinus[a + 1])); は、 ((b == 0) && (++cntEQ)) || ((b > 0) && (++cntBPlus[a + 1])) || ((b < 0) && (++cntBMinus[a + 1])); if (b == 0) cntEQ++; else if (b > 0) cntBPlus[a + 1]++; else if (b > 0) cntBMinus[a + 1]++; は、 if (b == 0) cntEQ++; else if (b > 0) cntBPlus[a + 1]++; else if (b < 0) cntBMinus[a + 1]++; です。 ※最後の b の比較が反対。

回答No.8

No.7 です。 さらに修正。 よく見れば、cntEQは配列である必要はありません。 で、どうせ3回カウントアップするのなら、 int cntBPlus[3] = {0}; int cntBMinus[3] = {0}; int cntEQ = 0; cntEQ += (b == 0); cntBPlus[a + 1] += (b > 0); cntBPMinus[a + 1] += (b < 0); で、cntEQ + cntBPlus[0] + cntBMinus[2] が答えになるかと。 さらには、 int cntBPlus[3] = {0}; int cntBMinus[3] = {0}; int cntEQ = 0; ((b == 0) && (++cntEQ)) || ((b > 0) && (++cntBPlus[a + 1])) || ((b > 0) && (++cntBMinus[a + 1])); で、答えは、cntEQ + cntBPlus[0] + cntBMinus[2] ですというのも、ありかもしれません。 ちなみに、上の式は、 if (b == 0) cntEQ++; else if (b > 0) cntBPlus[a + 1]++; else if (b > 0) cntBMinus[a + 1]++; と、概ね、同じ動きをします。(ちょっとちがいます)

回答No.6

> 数百、数千万回とループさせる場合、if文や掛け算 > 処理に時間がかかるからなるべく使うな、 あ、これは、今では迷信に近いです。 特に、「最適化」という技術が発達していますから、 C言語くらいだったら、 ・やりたいことをなるべくシンプルに ・あとは、コンパイラにお願い というのが正しいやり方です。 もしくは、 かけ算や比較の時間を稼ぐ前に、アルゴリズムを見直そう というのが、正しいやり方である可能性は非常に高いです。 ちなみに、普通のパソコンであれば、 ・if による比較は、浮動小数点のかけ算よりは  速い ・if を文面から追い出すと、(例えば、 cnt += (a < 0) * ( b > 0) + (a > 0) * ( b < 0) + (b == 0); など……a, b の符号の組み合わせを確認してみよう) 見えないところで、一杯 if が発生する ・浮動小数点は、乗除より、加減のほうが、「遅い」 ・人間が小手先で最適化すると、コンパイラの最適化を邪魔する おまけ。 ・3日かかる処理を1日で終わらせようとして、4日かかったら、時間の無駄 ・スピードアップは、感覚ではなく「計測」から というのを意識すると良いでしょう。 ただし、「3日かかる処理を……」というのは、それによって得られる知的な成果を含めれば、一概にそうとはいえません。

hirai2912
質問者

補足

数百、数千万回とループするプログラムでもコンパイラが自動的に最適化してくれるのなら、 あまり深く考えすぎる必要はなさそうですね。 単純に、符号が違う数を掛けると負になるのを利用して、 if(a*b<=0)count++ とかでいいのでしょうか。

  • Tacosan
  • ベストアンサー率23% (3656/15482)
回答No.5

#1 と同感. なぜ if を使いたくないのか. まあ, そもそも「変数a(1か-1が入る)と変数b(小数が入る)の符号が違ったらカウントを増やすプログラム」というのがよくわからんのだが. あと, b が 0 のときにはどうするつもりなのか.

hirai2912
質問者

補足

すみません、書き忘れていました。 bが0のときはカウントを増やさないといけません。 ただ、bの符号を取ることができればこの部分は自力でできると思います。

回答No.4

#include <stdio.h> int main(void) { double a; for(a = -5; a <= 5; ++ a) printf("%f %d\n", a, -1 + (a >= 0) + (a > 0)); return 0; }

  • titokani
  • ベストアンサー率19% (341/1726)
回答No.3

三項演算子を使うのはだめですか? ((b==0)?0:((b<0)?-1:1))

hirai2912
質問者

補足

三項演算子ですか。 if文と比べて処理が速くなるのかわかりませんが、これが使えれば一番楽みたいです。 とりあえず調べてみます。

  • taunamlz
  • ベストアンサー率20% (175/843)
回答No.2

>if文(とできれば掛け算)を使わずに、変数a(1か-1が入る)と変数b(小数が入る)の符号が違ったらカウントを増やすプログラムを作らないといけないのですが、 これだけならばビットシフトとexorを使えばよいかと。 負の数というのは最上位ビットが1である事を利用すると良いと思います。

hirai2912
質問者

補足

なるほど、ビットシフトを使えば処理を速くできそうです。 変数aはint型なので15ビット右にシフトすればよさそうですが、 double型の変数bは何ビットシフトすればいいのでしょうか。

  • koko_u_u
  • ベストアンサー率18% (216/1139)
回答No.1

そもそも何故 if 文を使いたくないのか補足にどうぞ。

hirai2912
質問者

補足

この部分は課題として作成するプログラムの一部なのですが、 数百、数千万回とループさせる場合、if文や掛け算は処理に時間がかかるからなるべく使うな、 この部分も処理を軽くするためにif文を使わないで書け、と言われたのです。

関連するQ&A