• ベストアンサー

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)

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

No.19です。 よく考えたらそれぞれビットシフトする必要はありませんでしたね。 よって i = i + (((int)b ^ a) >> 15); の方がちょっと早くなるかもしれませんね。

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

>なるほど、ビットシフトを使えば処理を速くできそうです。 >変数aはint型なので15ビット右にシフトすればよさそうですが、 >double型の変数bは何ビットシフトすればいいのでしょうか。 (int)b コレでintに変換できます。 -0.3とかが入っていたら0になったかもしれませんので、その場合は (int)(b-1) とすればa.bどちらもint型となり、負の場合は最上位ビットが1になります。 具体的には i = i + ((int)b >> 15) ^ (a >> 15); コンパイルしてないので動くか分かりませんが、こんな感じで良いと思います。

回答No.18

No.13です。 >授業の課題として、データを大量に集めて確率などを求めるためのプログラムを作っているので、 >数百、数千万回、またはそれ以上繰り返すのが前提になっています。 では、別のアプローチの解も書いておきましょう。 「地球シミュレータ」の有償利用サービスの拡大について http://www.jamstec.go.jp/j/about/press_release/20070614/ 成果の占有を前提とした場合でも、一時間4000円程度で借りれます。 これなら、ちょっとやそっとのコード増加なんて屁でもない。 なにせ、過去には「世界一」もとったことのある後継機なのだから。 という冗談(あながち冗談てはないけど)はさておき、 個人的にいえば、 全体から見たら(言い方は悪いけど)ゴミみたいな部分に神経使うよりは、まずは設計されたものを「設計通り」に作りこむことに注力すべきだと思う。 この時、後の修正や変更が楽になるように「見やすく・わかりやすく」作りこむことも重要。 経験からいえば、些細な処理の書き方一つより、統合した全体として遅延問題を誘発する可能性の方がはるかに大きい。 同じことを触れられている方がいるけど、 そのif文の処理は「データを収集し確立を計算する1回の処理」に対してどれだけの処理時間を占めるの? 「チリも積もれば……」も真実の一つだけど、返答から見るとそれだけで解決できる問題ではないと思う。

回答No.17

No.12の回答者です。 実際に測ってみればということで (1)No.12に示した関数 (2) inline int signf( double x ){ if ( x<0.0 ) return -1; else if ( x>0.0 ) return 1; else return 0; } を関数 void signfa( double x[], int y[], const int n) { for ( int i=0; i<n; i++ ) y[i]=signf( x[i] ); } から呼んで所要時間を計りました。 Visual Studio 2008のQueryPerformanceCounter()を使い、n=10,000からn=10,000,000までx[]には正負ほぼ同数の乱数(値0もわずかに含まれています)を与えました。 release ビルドで実行させたところ、(1)と(2)の所要時間の比はnによらずおおむね1:1.2程度で、(1)のほうが短時間で処理できました。 n=10,000,000のときの所要時間は(1)、(2)それぞれ、0.0780secと0.0952secでした。

  • jacta
  • ベストアンサー率26% (845/3158)
回答No.16

とりあえず質問に答えます。 > if文を使わずに、値が正なら1、0なら0、負なら-1を出力する方法はありますか? (b > 0) - (b < 0) とすれば、bの型やサイズや内部表現に関わらず、望みの結果が得られます。 マクロや関数テンプレートにでもしておくと、使い回しが効くので便利でしょう。 aとbの符号が異なるときにカウントアップということであれば、 count += (a != ((b > 0) - (b < 0))); で実現できます。 次にif文を使いたくない状況ですが、少なからず存在します。 最も典型的なのは結果を定数式として欲しい場合です。初期化子やcaseラベル、配列の要素数に使いたい場合のほか、テンプレート実引数に使う場合にも有用です。ジェネリックプログラミングには必須といえるでしょう。 また、コンパイラの最適化性能は処理系によってかなり異なります。極端なことをいえば、インタープリタ環境では、バイトコードコンパイルの有無程度が精一杯でそれ以上の最適化は期待できないことことも多々あります。最適化バグを回避するために、そのそも最適化を抑止しなければならない状況もあります。

回答No.15

No.6 です。 > if(a*b<=0)count++ とかでいいのでしょうか。 それでいい可能性が非常に高いです。 あと、これだと、誰が読んでも意図がわかります。 実は、もうひとつの観点があって、たとえば、 「a と b の符号が異なるときだけカウントアップ」という処理が、数万回あるとして、「この処理だけが数万回ある」ということは、ほぼあり得ないということです。 少なくとも、ループのための処理はあるでしょうし、数万個のデータが計算されるか、ファイルから読まれるかするはずです。 その「ある程度の塊」が、数万回実行されることになるのが普通なのですが、さて、その中で、比較や、浮動小数点の乗算がどの程度の時間を占めているかという観点です。 全体の1%を占めていたとして、処理時間が10倍になったとしたら、全体の処理時間は、10%増加します。 どちらも、かなり極端な仮定だと思いますが、それでも、10%増加するだけです。 10秒かかる処理が11秒になったら困りますか? もしも、10日かかる処理が、11日かかるとしたら、10日もかかるのが正しいのかということを疑うべきです(これが、アルゴリズムの検討) というわけで、こういう処理というのは、わかりやすく書いておくのがベストです。

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

数千万回「程度」で気になるほど違いが出るものなのかなぁ. 正直なところ, 「とりあえず何も考えずに実装して, どうしても気になるようならそのときになって初めて取り組む」くらいで十分だと思う. まあ, 「どのように書いたら速いのか」というのはコンパイラとかプロセッサにも依存するんだけどね.

回答No.13

「条件分岐」としての処理でいえば、「if」も「三項演算子」もそれほど違いはないので、単純に「ifを使ってない」という言葉に惑わされないように。 >数百、数千万回とループさせる場合、if文や掛け算は処理に時間がかかるからなるべく使うな、 >この部分も処理を軽くするためにif文を使わないで書け、と言われたのです。 FPGAなんかでは今でも通用する事象ですが、 μオーダーでのシピアな制御タイミングが伴わないPCアプリなら気にするほどのことでもありません。 それよりも >数百、数千万回とループさせる という処理の方が問題ありの気がしますが。

hirai2912
質問者

補足

>>数百、数千万回とループさせる >という処理の方が問題ありの気がしますが。 授業の課題として、データを大量に集めて確率などを求めるためのプログラムを作っているので、 数百、数千万回、またはそれ以上繰り返すのが前提になっています。

回答No.12

こういうのは頭の体操として考えるのが… double型とlong long int型とが同じサイズで、最上位ビットが符号であれば、これでどうでしょうか。 inline int signf( double x ){ /* programmed by Akayoroshi on 2009-12-14. */ double y=0.0-x; long long int *ix=(long long int*)&x; long long int *iy=(long long int*)&y; return (*ix>>63)-(*iy>>63); } Visual Studio 2008では、プログラムの3行目を、double y=-xとしたらyの値が-0.0になって関数の戻り値は-1になってしまいました。

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

あるいは、 if( a < 0 ){ if( b <= 0 )cnt++; }else{ if( b >= 0 )cnt++; } こうかな。

関連するQ&A