コンテンツ
1.ビット演算とベース
ビット演算の奇妙なトリック:
- パリティの判断
- バイナリビットの取得は1または0です
- 2つの整数変数の値を交換します
- 判断ステートメントを使用せずに整数の絶対値を見つける
- >>および<<演算子はビットを右または左にシフトします
- >>>演算子は上位ビットを0で埋めます;>>演算子は上位ビットを符号ビットで埋めます、<<<演算子はありません
- intの場合、1<<35は1<<3と同じです。
- AND:両方が1、結果が1;または:1が1、結果が1; XOR:2つが同じではない、結果が1
a b 〜a a&b a | b a ^ b 1 1 0 1 1 0 0 1 1 0 1 1 0 0 1 0 0 0
2.いくつかの興味深いビット演算
1.または操作とスペースを使用して、 |
英語の文字を小文字に変換します
('a' | ' ') = 'a'
('A' | ' ') = 'a'
2. AND演算 &
とアンダースコアを使用して、英字を大文字に変換します
('b' & '_') = 'B'
('B' & '_') = 'B'
3. XOR演算 ^
とスペースを使用して、英字の大文字と小文字を交換します
('d' ^ ' ') = 'D'
('D' ^ ' ') = 'd'
4.2つの数字が同じ符号であるかどうかを判断します
int x = -1, y = 2;
boolean f = ((x ^ y) < 0); // true
int x = 3, y = 2;
boolean f = ((x ^ y) < 0); // false
5.一時変数なしで2つの数値を交換します
int a = 1, b = 2;
a ^= b;
b ^= a;
a ^= b;
// a = 2, b = 1
6.1つ追加します
int n = 1;
n = -~n;
// n = 2
7.マイナス1
int n = 2;
n = ~-n;
// n = 1
ps:上記の操作は、友達の前のカップにも使用できますが、実用的ではありません。
3. n&(n-1)を使用します
n &(n-1)
この操作はアルゴリズムで一般的で あり、数値n
の2進表現の最後の1を削除するように機能します。
コアロジックはn - 1
、最後の1を削除すると同時に、後続の0を1に変更して、合計 演算がn
再度実行され &
、最後の1のみを0に変換できるようにする必要があるということです。
使用方法の例を次に示します。
1つの問題と3つの解決策:2進数の1の数
方法1:整数nはビット単位で1、つまりn&1(ビット単位で:結果は1で1)、nが2進数で右端の1として表される場合、n&1は1、count ++は1回、次にn右に移動>>1つずつ比較します。
コードに直接移動します。
#include<stdio.h>
int main()
{
int n;
int ants = 0;
scanf("%d",&n);
for (int i = 0; i < 32; i++)
{
int m = n;
if ((m>>i)&1== 1)
ants++;
}
printf("%d", ants);
return 0;
}
方法2:方法と同様です。つまり、整数nを変更せずに、1を左に移動します。ここではコードが提供されていないため、試してみることに興味があります。
方法3:上記で説明したn&n(-1)を使用しますが、ここでは詳しく説明しません。上記を確認できます。
int hammingWeight(int n) {
int res = 0;
while (n != 0) {
n = n & (n - 1);
res++;
}
return res;
}
数値が2の指数であるかどうかを判別します
数値が2の指数である場合、その2進表現には1のみが含まれている必要があります。
2^0 = 1 = 0b0001
2^1 = 2 = 0b0010
2^2 = 4 = 0b0100
使用する手法が非常に単純な場合 n & (n-1)
(演算子の優先順位に注意してください。括弧は省略できません)。
boolean isPowerOfTwo(int n) {
if (n <= 0) return false;
return (n & (n - 1)) == 0;
}
小さなテスト
>>>インデックス2(タイトルコードは上に表示されています。ご不明な点がございましたら、コメント欄でご相談ください)
4. 运用a^a=0
XOR演算の性質は、次の点に注意する必要があります。
数値とそれ自体の間のXOR演算の結果は0、つまり a ^ a = 0
;数値と0の間のXOR演算の結果はそれ自体、つまり a ^ 0 = a
。
注文数を探す
この質問では、すべての数値をXORする限り、ペアの数値は0になります。単一の数値と0のXORはそれ自体であるため、最終的なXORの結果は1回だけ現れる要素です。
int singleNumber(int[] nums) {
int res = 0;
for (int n : nums) {
res ^= n;
}
return res;
}
小さなテスト
5.ビット演算の考え方を改善する
整数のパリティビットを交換します
ここでの整数のパリティスワップは、実際にはバイナリのパリティビットのスワップです。10進数の15のパリティスワップの代わりに、51に置き換えます。たとえば、1010を0101に置き換えます。
アイデア:整数を入力し、ビット単位で010101 ...偶数の値をou(この文には好みが必要)として保持し、次にビット単位で101010 ...奇数の値をjiとして保持し、ouを移動します左に<<1ビット、右にji >> 1ビット、次にXORして目的の目的を達成します。
コード:
#include<stdio.h>
int main()
{
int n;
scanf("%d",&n);
int ji = n & 0xaaaaaaaa;//1010...
int ou = n & 0x55555555;//0101...
int c= (ou << 1) ^(ji >> 1);
printf("%d",c);
return 0;
}
浮動小数点実数の2進表現
コード:
0.625 0.5+0.125
0.101
#include<iostream>
using namespace std;
int main()
{
double n;
cin >> n;
string s1 = "0.";
while (n > 0)
{
n= n * 2;
if (n >=1)
{
s1 +="1";
n = n - 1;
}
else {
s1 += "0";
n = n;
}
if (s1.size() > 34)
{
cout << "ERROR " << endl;
}
}
cout << s1 << endl;
return 0;
}
K回発生し、1回発生します
問題解決のブレークスルー:k個のK-ary数を使用して、キャリーなしで加算することにより、結果が0であるという結論
最初に10進数をk-aryに変換し、文字列を使用して逆の順序で格納します。
余りのkで除算する方法(一般的な計算方法)を使用して、配列内の数値をk-ary番号に変換します。k-aryに変換した後、ビット(列)で計算する必要があるため、文字列の形式で格納されます。k-aryシステムに変換した後、数値のサイズが異なるため、長さも異なる場合があります.k個の数値の合計は0ですが、違いはありませんが、ビットシーケンスは必要なものにとって非常に重要です数値(計算文字列を左から右に計算する場合、および10進数に戻す場合は右から左に計算する)、したがって、kベースに変換された数値は逆の順序で格納されます。
文字列の最大長を見つけて、maxlen未満の文字列を入力します。
列ごとに計算する必要があるため、最大で何列あるか、つまりmaxlenを知る必要があります。キャリーなしでビットごとの加算を行うために、上位に「0」を入力し、maxlenの長さを構成しますキャリーなしで
加算これらの数値をキャリーなしで加算します。これはXOR演算^と同等です。または、kを法とするビット単位の加算の後に数値を取ります。出力結果、K-aryからdecimal
このステップは単純で、一般的な8進数から10進数および16進数から10進数と同じ原理です。
#include<iostream>
#include<algorithm>
#include<string>
//#include<cmath>
using namespace std;
string decTok(int dec, int k); //十进制数转K进制
int kTodec(string str, int k); // K进制转十进制
string decTok(int dec, int k)
{
string ret = ""; //作为结果
while (dec > 0) {
ret += char(dec%k + '0');//如:5+'0'='5'
dec /= k;
}
reverse(ret.begin(), ret.end());//翻转
return ret;
}
int kTodec(string str, int k)
{
int ans = 0;
for (int i = 0; i < str.size(); i++)
ans = ans * k + (str[i] - '0');//020 首位是最高位
return ans;
}
int main()
{
int n[] = { 1,1,1,3,3,3,5,5,5,9,9,9,6,7,7,7 };
int k = 3; //根据数组数据,要转换的进制
//1.十进制数转K进制
string str[16];
for (int i = 0; i < 16; i++)
str[i] = decTok(n[i], k);
//2.找出16条字符串中最大长度
int maxlen = 0;
int len;
for (int i = 0; i < 16; i++) {
len = str[i].size();
maxlen = max(maxlen, len); //maxlen=max(maxlen,str[i].size())
}
//16条字符串中,若字符串长度<maxlen,则进行补齐,以便逐位做不进位加法
for (int i = 0; i < 16; i++)
while (str[i].size() < maxlen)
str[i] = "0" + str[i];
//ans:结果初始化
string ans = "";
while (ans.size() < maxlen)
ans += "0";
//3.做不进位加法
for (int i = 0; i < 16; i++)
for (int j = 0; j < maxlen; j++)
ans[j] = char(((str[i][j] - '0') + (ans[j] - '0')) % k + '0');
cout << ans << endl; //ans字符串结果
cout<< kTodec(ans, k); //转为十进制数
return 0;
}