2016-06-21 4 views
5

2つの数値を掛け合わせるコードがありますが、それらの整数の数は0でなければなりません。それを数えないように1にする。私はすべての変数の「IF」条件チェックを回避し、1と交換したいC++で整数 '0'を '1'に置き換える最も最適な方法は何ですか?

y=x*z // x>0, z>0. if x==0 then x=1, if z==0, then z=1; 

はそれを行うための良い方法はあります。

+2

この 'x? z? x * z:x:z? z:1' –

+2

構文レベルで 'if'を避けようとしているのですか、生成されたマシンコードのブランチが疲れていますか? '? 'をつけたすべての解決策は、敷物の下にブランチを隠しているだけです(' if'はまだそこにあります。別の構文でカモフラージュしています)。 –

+0

何が問題なのですか? 'assert(x!= 0); assert(z!= 0);そしてアサーションが決して発動しないことを確認する?言い換えれば、なぜあなたは偽のデータを受け入れていますか?なぜ誤ったデータを強制的に拒否しないのですか?そして、何が起きているのですか? 'y = x * z; if(y == 0)y = 1; 'これはオペランドではなく結果をチェックするだけですか?答えが 'x == 0 && z == 2 'の場合、' y'の値は2でなければなりません。 –

答えて

1

は、そのうちの一つは、あなたがあなたにこの[ assembly ]コードを与える01

y = (x * z > 0 ? x * z : x + z) 
+2

xとzの両方が0でない場合 –

+1

xまたはzが負の場合、上記は機能しません。 –

15

y=(x==0?1:x)*(z==0?1:z) 

下に変更するかのよう0はその後、さらにはあなたに同じ結果を与えるである場合。


と彼の[ answer ]

y=(x+(x==0))*(z+(z==0)); 

@Jerry Coffinのコメントから借り適応はあなたにこの[ assembly ]コードを提供します。

+1

最小の[アセンブリ]を生成します(https://gcc.godbolt.org/#compilers :!((コンパイラ: :g530、オプション: ' - std%3Dc%2B%2B14 + -O3'、ソース: 'int + main(int + i、+ char ** g)%0A%7B%0A ++ int + x +%3D + * g (%%3D%3D0%3F1:x%3D%3D0%3F1:z%3D%3D0%3F1:z%3D%3D0%3F1:z )、filterAsm:(commentOnly:!t、ディレクティブ:!t、labels:!t)、version:3)。 – Viatorus

+0

@Viatorus:答えを更新しました。 :) – sjsam

+0

mmm。おそらく、-O2で最小のアセンブリをチェックするべきです。 –

6

私は正直言って、あなたが大幅にパフォーマンスが低下する方法を考え出すことができます。あなたが一番速くなると思われるものの代わりに後で読むことができるものを選んでください。この特定の操作がボトルネックとはならない可能性があります。

+1

または彼は、明確で簡潔なコードを探しています。この場合、あなたの解説はあまり役に立たないでしょう。 –

+2

わかりやすい2条件付きソリューションに対して、「明確かつ簡潔な」ソリューションの可読性のメリットを数値化することに挑戦します。 – zneak

9
y = (!x^x) * (!z^z); 

これは、ゼロを0にすると同じ番号が返されるためです。したがって、x != 0の場合は!x == 0!x^xの場合は0^xとなります。これはxです。そしてx == 0場合、!x == 1、および!x^xは、私は確かにそれはあなたのコード上の任意の正の効果を持っているだろうことを保証するつもりはないが、一つの可能​​性は、このようなものになるだろう。1.

+5

すべての要件を満たすためにプラス1、実際にそれを実際にコード化する人には-999 –

+0

@sjsamとは対照的に、2つのxor-instructionが必要です。 [アセンブリ](https://gcc.godbolt.org/#compilers:!(コンパイラ:g530、オプション: ' - std%3Dc%2B%2B14 + -O3'、ソース: 'int + main(int + i、 + char ** g)%0A%7B%0A ++ int + x +%3D + * g%5B0%5D%3B%0A ++ int + z +%3D + * g%5B1%5D%3B%0A ++ return +( )、filterAsm:(commentOnly:!t、ディレクティブ:!t、labels:!t)、version(バージョン4の場合、!x +%5E + x) :3)。 – Viatorus

+0

@Viatorus:生成されたアセンブリ命令の数は、パフォーマンスに関する限り、しばしば役に立たないメトリックです。コンパイラは一般に、高速対小規模コードのための2つの相互に排他的なフラグを持っています。 –

3

ある1^0、と等価です:

x += int(x == 0); 
z += int(z == 0); 

これはfalseまたはtrueを生産、0に変数を比較します。それはintに変換され、値が以前はゼロでなかった場合は0、ゼロの場合は1になります。その結果を変数に追加します。その結果が0の場合は、1を加えて1を返します。ゼロ以外の値だった場合はゼロを追加しますが、明らかにその値には影響しません。

+1

Or '' x + =!x; ' –

+0

ニースですが、私は実際に変数を変更したいとは思っていませんが、「私はそれを1にする必要がある」と言いました。変更は操作のためのものです。 – sjsam

+0

@CareyGregory:ニース!! – sjsam

2
y=max(x,1)*max(z,1); 

必要に応じて#defineプリプロセッサキーワードまたは通常の関数としてmax関数を定義します。

-2

正確な結果が心配な場合は、あなたのコメントにあるif文、またはほとんどの人が示唆しているように、3進演算子?を使用する必要があります。
あなたは、単にあなたができる常にOR 1、コードのこのセクションには支店がないことを気にしている場合:このコードではとxまたはzどちらも、すべてであることは枝がないだろうと

x = x | 1; 
z = z | 1; 
y = x * z; 

これでしょう保証0に等しい。 ?*(Z Z:

00000000 | 1 = 1 
10001011 | 1 = 10001011 
10101010 | 1 = 10101011 <- imprecision introduced! 
+6

2 * 2 == 9は不正確です。 –

1

それは

Y =(?1×X)を動作します:あなたは常に誤っいずれかxまたはz1を追加することができますので、しかし、支払うべき代償は、精度は、次のとおりです。 1)

0

まあ、私はthis answerからのリンクを使用し、そのようなコードを作成しました。 assembly hereでは、アセンブリが短くなるため、アセンブリの速度が遅くなる可能性があります。

int main(int i, char**g) 
{ 
    int x = *g[0]; 
    int z = *g[1]; 
    int tmp = z ? 1 : z; 
    return (x==0?tmp:x*tmp); 
} 
関連する問題