#define _CRT_SECURE_NO_WARNINGS 1 #include<stdio.h> #include<math.h> #include<stdlib.h>
这是预处理
int NumberOf1(int n) { int i = 0, j, m, count = 0, x; x = n; if (n == -2147483648)//一个只有补码的负数 return 1; while (1) { if ((n % ((int)pow(2, i))) == n ) { break; } i++; } i--; for (j = i; j >= 0; j--) { m = n % ((int)pow(2, j)); if (m != n) count++; n %= (int)pow(2, j); } if (x < 0 && x % 2 == 0) { count = 32 - count; } if (x < 0 && x % 2 != 0) { count = 33 - count; } return count; }
这是一种解决问题的函数,缺点,会有死循环,((int)pow(-2, i))这个值的结果是整形永远达不到那个数字2147483648,我们必须自己规定那个数字
-2147483648这个数字是int的最小值没问题,确实可以等于
((int)pow(-2, i)))这个数字不可以达到-2147483648,因为是正数,所以超出范围了,数字变为1,达到这个数字必须是正数到2147483648加负号,但是没办法,正数是达不到的
由于这个数字的特殊,我们得到10000000000000000000000000000000就是他的补码,即使我们用一些方法,比如说改变判断方式,设置整形不会超出范围,我们会得到这个二进制数(2147483648的无符号整形形态),导致他没有源码和反码,所以后面的公式对他无效。
反正就是很难受,int达不到2147483648,而这导致我们的任何运算结果(整形之间的计算,甚至加个负号,最后的结果都是整形)不能达到2147483648,这种方法的局限体现的淋漓尽致
导致我必须设立个别的入口
并且速度慢
int NumberOf2(int n) { int i = 0, count = 0; for (i = 0; i < 32; i++) { if (n & (1 << i)) //只要1移位后二进制1所在的位置对应到n那边有1这个表达式结果就不会为0,如00000000000000000100000000000000非0 //如果对应的那个数字是0,则表达式结果为 count++; } return count; }
法2:移位操作符<< >>
左移,出界删掉,末位补0
右移动,有符号补符号位,无符号补0;
(-2147483648的补码就是10000000000000000000000000000000,很特殊)
(不过这个方法就是可以直接用补码来判定,并且速度快)
(正数三个码都一样)(而法一是一次一次慢慢的算出源码(-2147483648算到了符号位,顶替了hhh,导致后面的混乱),然后通过转化,但是很遗憾,-2147483648不能转化)
int main() { int n = 0; scanf("%d", &n); system("cls"); printf("%d\n", NumberOf1(n)); printf("%d", NumberOf2(n)); return 0; }
这是原函数