互联网

当前位置:澳门威斯尼人平台登陆 > 互联网 > 进制转换,C语言部分

进制转换,C语言部分

来源:http://www.tessiz.com 作者:澳门威斯尼人平台登陆 时间:2019-11-22 10:49

原标题:深入 V8 引擎:“小整数”到底有多小?

        Java语言中的表达式是由运算符与操作数组合而成的,所谓的运算符就是用来做运算的符号。
        在Java中的运算符,基本上可分为算术运算符、关系运算符、逻辑运算符、位运算符、赋值运算符、转型运算符等。

二进制 逢二进一
自己归零 前面进一位

二进制学习时的笔记(其实也没什么用,留着给自己看的)

原文:V8 Internals: How Small is a “Small Integer?”

链接:

作者:Franziska Hinkelmann

译者:justjavac(迷渡)

一、算术运算符        所谓算术运算符,也就是我们数学中学到的加、减、乘、除等运算。这些操作可以对几个不同类型的数字进行混合运算,为了保证操作的精度,系统在运算的过程中会做相应的转换。
      1、数字精度        所谓数字精度,也就是系统在做数字之间的算术运算时,为了尽最大可能地保持计算机的准确性,而自动进行相应的转换,将不同的数据类型转变为精度最高的数据类型。规则如下:
      1)当使用运算符把两个操作数结合到一起时,在进行运算前两个操作数会转化成相同的类型。
      2)两个操作数中有一个是double类型的,则另一个将转换成double型。
      3)两个操作数中有一个是float类型的,则另一个将也转换成float型。
      4)两个操作数中有一个是long类型的,则另一个将也转换成long型。
      5)任何其它类型的操作,两个操作数都要转换成int类型。
      2、整数型运算(int型)
       对于int型的相关操作,加、减、乘的结果都是非常容易理解的,重点讲一下除(/)的运算。
       两个整数相除的结果是整数,这一点与数学中是不同的,在Java中,两个整数相除的结果类似于数学中的求模运算。整除的余数是用%表示,例如15 / 2 = 7,而不是7.5,15 % 2 = 1。我们用程序验证一下:

十进制:12
二进制:1100(逢二进一)
八进制:14(逢八进一)
十六进制 :(逢十六进一)

二进制简介
只有 0 1
优点:
1.二进制状态简单
2、可靠性、稳定性高
3、运算规则简单,简化设计
4、通用性强

原文副标题:“When binary is useful outside of a coding interview”

/*两个整数相除及求余数*/

public class Divide
{
   public static void main(String[] args)
   {
      int a = 15;
      int b = 2;
      double c = 2;
      System.out.println(a + "/" + b + "=" + (a / b));
      System.out.println(a + "%"+ b + "=" + (a % b));
      System.out.println(a + "/" + c + "=" + (a / c));
      System.out.println(a + "%" + c + "=" + (a % c));
    }
}

表示二进制 0b
八进制 0
十六进制 0x

二进制计算
正数二进制
十进制转二进制
规则: 除二倒取余
或者 把一个数字拆成2的n次方相加
55=32+16+4+2+1
2^5+2^4+2^2+2^1+2^0
110111
负数二进制
-77 -1001101
用一位二进制位当作符号为 存符号
int 32位 char 8位
char -77 ——> 最高位当做符号位 1为负号 0位正号
1100 1101 (原码 原码在计算式会出错)
对原码取反
1011 0010 (除了符号位之外 全部取反 反码)
1011 0010+1=1011 0011

V8 是谷歌的开源 Java 引擎。Chrome,Node.js 和许多其他应用程序都使用了 V8 引擎。如果你曾经听过关于 V8 的演讲,或者读过关于 V8 的文章:Understanding V8’s Bytecode(中文:),你一定听说过 Smis,小整数。本文通过深入 V8 的源代码,具体研究一下 Smis到底有多大。

输出结果:
                 15 / 2 = 7
                 15 % 2 = 1
                 15 / 2.0  =  7.5
                 15 % 2.0 = 1.0

输出 八进制%o 十六进制 %x

存放的是补码 补码相加不会出错

根据规范,Java 并不知道整数(除了最近引入的 BigInts)(中文:)。它只知道 IEEE 浮点数。但是许多操作都是基于整数,比如程序中的 for循环。所有 Java 引擎都有一个特殊的整数表示方式。V8 有所谓的 Smis小整数。

澳门威斯尼人平台登陆,        3、自增和自减运算符
        在循环与控制中,我们经常会用到类似于计数器的运算,它们的特征是每次的操作都是加1或减1。在Java中提供了自增、自减运算符,X++使变量X的当前值每次增加1,而X--是自减运算符,每次操作使当前X的值减1。例如:

二进制转十进制

8位二进制
16+
16 0001 0000
-13的二进制 1.原码 1000 1101
2.反码 1111 0010
3.补码 1111 0011
原码相加
0001 0000 +
1000 1101 =
1001 1101

Smis在 64 位平台上的范围是 -2³¹ 到 2³¹-1(2³¹≈2*10⁹)。如果你查看 V8 源码,这可能并不是非常明显。 kSmiMinValue并 kSmiMaxValue在 include/v8.h 中定义如下:

/*测试自增、自减操作*/

public class SelfAction
{
   public static void main(String[] args)
   {
     int x = 10;
     int a = x+ x++;
     System.out.println("a =" + a);
     System.out.println("x =" + x);
     int b = x + ++x;
     System.out.println("b =" + b);
     System.out.println("x =" + x);
     int c = x + x--;
     System.out.println("c =" + c);
     System.out.println("x =" + x);
     int d = x + --x;
     System.out.println("d =" + d);
     System.out.println("x =" + x);
   }
}  

从低位数开始,用低位数乘以2的多少次幂,幂数从0开始,然后在相加

补码相加
0001 0000 +
1111 0011 =
1 0001 0011 (只有8位,去掉最高位 结果正确)

  1. static const int kSmiMinValue = (static_cast<unsigned int>(-1)) << (kSmiValueSize — 1);
  2. static const int kSmiMaxValue = -(kSmiMinValue + 1);

输出结果:
                 a = 20
                 x = 11
                 b = 23
                 x = 12
                 c = 24
                 x = 11
                 d = 21
                 x = 10

二进制 :1001
12(0)=1
0
2(1)=0
02(2)=0
1
2 (3)= 8

规定正数的原码、反码和补码是一样的

它是如何等于 -2³¹ 和 2³¹-1 的呢?让我们将上面的 C++ 代码分解一下。

二、关系运算符         Java具有完美的关系运算符。这些关系运算符基本上同数学中的关系运算符是一致的。“>”大于、“<”小于、“>=”大于等于、“<=”小于等于、“==”等于、“!=”不等于。例如:

1 2 4 8 16 32

小数的二进制 和浮点型数据的存放

左移

/*关系运算符测试*/

public class RelationTest
{
   public static void main(String[] args)
   {
     boolean x, y, z;
     int a = 15;
     int b = 2;
     double c =15;
     x = a > b;  //true;
     y = a < b;  //false;
     z = a != b;  //true;
     System.out.println("x =" + x);
     System.out.println("y =" + y);
     System.out.println("z =" + z);
   }
}

二进制转八进制

小数的二进制 2^-6

<<是按位左移运算。左移意味着我们将数字的二进制表示移到左边,并用零填充右边。例如,5 << 3 = 40。

输出结果:
                 x = true
                 y = false
                 z = true

三个二进制代表一个八进制位 ,将三个二进制位转换十进制,算出后三位的相加,之后再相连

存浮点型 精度 float 32位 才精确6-7位
32位
最高位 符号位 1位 存放符号 1为负数0为正数
8位指尾数位 1+172——>存到指数位 偏移量
23位 尾数位

澳门威斯尼人平台登陆 1

三、逻辑运算符
        在Java语言中有三种逻辑运算符,它们是NOT(非,以符号“!”表示)、AND(与,以符号“&&”表示、)OR(或,以符号“||”表示)。
        1、NOT运算符          NOT运算符是用来表示相反的意思。
                        NOT逻辑关系值表                           

二进制转十六进制

1.1001001 左移一位
1.1001001*2^1 //二进制的指数形式

您可能已经注意到了,正数的左移与乘以 2 相同。

A

!A

true

false

false

true

四个二进制位掉膘一个十六进制,只需要将4个二进制转换为10进制,之后再相连

10进制
110=1.10*10^2

静态转换为无符号整数

         2、AND运算符          AND运算符表示“与”的意思,也就是和的意思。
                       AND逻辑关系值表

十进制转 二进制
除2取余 倒序取出

-3.1415
1 1000 0000 1001 001 0000 0000 0000 0000

  1. static_cast<unsigned int>(-1)

A

B

A&&B

false

false

false

true

false

false

N位二进制的取值范围
1位: 0~1 0~2(n)-1;
2位 :0~3 0~2(2)-1;
3位:0~7 0~2(3)-1;

——>127 8位指数位 ——>-127~128 +2^7-1

当我们将负值转换为无符号整数(即正数)时会发生什么?所有的二进制位保持不变,但值的表示却不同了。转换为无符号整数后,我们就可以把这个数作为正数来进行左移运算了。

false

true

false

true

true

true

源码 反码 补码
存在内存中的是补码

*/

那么 -1的二进制表示是什么呢?在二进制补码中, -1表示为 (111...111)_2因为 2⁶³-2⁶²-2⁶¹- … -2²-2¹–1 = 1。

         3、OR运算符
         OR运算符是用来表示“或”就像我们日常生活中理解的一样,两者只要有一个为“真”,结果就为“真”。
                     OR逻辑关系值表

正数三码合一 一样的

浮点型二进制

澳门威斯尼人平台登陆 2

A

B

A||B

false

false

false

true

false

true

false

true

true

负数

1.首先计算小数的二进制 2.将小数二进制转换成指数形式 3.将小数的符号位存在float的第一位,0为正数, 1为负数.指数部分加上偏移量,存入8位指数位 将指数形式的二进制的小数部分存入尾数位, 如果位数不够 ,在后面用0补齐 P.S 将小数换算成指数形式的时候,规则是将小 移动到第一个1的右边,左移几位就是乘以2的 几次幂

合在一起

true

true

true

源码
1000 0000 0000 0000 0000 0000 0000 1001
反码:符号位不变,其他位去反(0变 1 1变0)
1111 1111 1111 1111 1111 1111 1111
0110
补码: 反码 +1
1111 1111 1111 1111 1111 1111 1111
0111

澳门威斯尼人平台登陆 3

如果您查看 V8 源代码中的 definitions,您会发现在 64 位计算机上 kSmiValueSize被定义为 32,于是:

/*逻辑运算符测试*/

public class LogicSign
{
   public static void main(String[] args)
   {
     boolean x, y, z, a, b;
     a = 'a' > 'b';
     b = 'R' != 'r';
     x = !a;
     y = a && b;
     z = a || b;
     System.out.println("x =" + x);
     System.out.println("y =" + y);
     System.out.println("z =" + z);
   }
}

为什么要有原码/补码/反码?
计算机只会做加法

二次学习 补充笔记

  1. kSmiMinValue =(static_cast<unsigned int>(-1)) << (kSmiValueSize — 1)
  2. = (111...111)_2 << (32-1)
  3. = (111...111)_2 << 31
  4. = (11...1100...00)_2 // 31个零
  5. = -2^31

输出结果:
                 x = true
                 y = false
                 z = true

1 - 1 ==1+(-1)
0000 0001原码(反码) 1000 0001

数据--->二进制
除法 效率 计算机的除法用减法实现的
二进制的用途---> PS 美图 二进制操作

现在我们可以使用这个结果来对 kMaxValue进行初始化。

       4、“短路”现象
       在运用逻辑运算符进行相关的操作时,我们会遇到一种很有趣的现象;短路现象。
       对于true && false根据我们的讲述,处理的结果已经是false了,也就是说无论后面是结果是“真”还是“假”,整个语句的结果肯定是false了,所以系统就认为已经没有必要再进行比较下去了。也就不会再执行了,这种理象就是我们所说的短路现象。

  • 1111 1110 -1 反码 1111 1110
    1111 1111
    —————————— 9
    1111 1111 反码

重点 计算二进制 (10进制数字转换二进制)
1.日常用的都是10进制 10进制-->二进制存放
3 11
进制不同但是可以表示一个东西
2.会算
3.整数 浮点型
4.进制转换 2进制 8进制/16进制 10进制
2进制
8进制/16进制 代替2进制(可以和2进制直接转换)
10进制

  1. int kSmiMaxValue = -(kSmiMinValue + 1);

四、位运算符
          所有的数据、信息在计算机中都是以二进制形式存在的。我们可以对整数的二进制位进行相关的操作。这就是按位运算符,它主要包括:位的“与”、位的“或”、位的“非”、位的“异或”。
        1)位的“与”,用符号“&”表示,它属于二元运算符。 与位运算值表:

将计算出来的反码转换为原码,再将原码转换为十进制
1000 0000 == 反码 == -1

1.整数的二进制
1.1 正数
int char(-128~127 0~127每个整数对应一个字符 ASCII)

显而易见, kSmiMaxValue=-(-2^31+1)=2^31-1。在 64 位平台上 V8 对 Smis定义的范围是 [-2³¹,2³¹-1]。

A

B

A&B

1

1

1

1

0

0

0

1

0

1 - 1 ==1+(-1)
0000 0001 (+1补码)
1111 1111 (-补码)
—————————
(1) 0000 0000 == 0 最前面的1 舍去

170 123
除2求余
170的二进制 10101010
123的二进制 1111011
int 32位 补齐
0000 0000 0000 0000 0000 0000 0111 1011
char 8位二进制
0111 1011

32 位平台

0

0

0

位运算

unsigned 无符号
signed 有符号

在 32 位平台上 kSmiValueSize=31。所以我们把它换为 30,计算得到 kMinValue=-2^30。注意,2³⁰≈10⁹。

         2)位的“或”用符号“|”表示,它属于二元运算符。。   或位运算值表:

& 按位与
|按位或
^ 按位异或
~ 取反

int
unsigned unsigned默认表示unsigned int
unsigned char
char 默认有符号
1.2 负数
有符号 能够存放负数
负数 3-2 --->3+
最高位 当作符号位 存放符号 0表示正数 1表示负数
char作为例子
3 0000 0011
-3 1000 0011 --->用这个当作二进制的话 关于负数计算会出错
原码
反码 1111 1100 (原码 除符号位外 其余全部1变0 0变1)
补码 1111 1101
整数负数二进制 存放的是补码

为什么 Smis在 32 位平台上的范围要小一点呢?在引擎内部,V8 使用最低有效位将所有 Java 值标记为堆栈对象或者 Smis。如果最低有效位是 1,则是指针。如果是 0,则是 Smi。这意味着 32 位整数只能使用 31 位存储 Smi值,因为一位(最低有效位)用作标记。

A

B

A|B

1

1

1

0

1

1

1

0

1

按位与 &
9& 5 =?
按二进制运算
规律:一假则假 1 真 0假
1001
& 0101
———
0001 == 1
规律:任何数和1相& 结果还是那个数
1001
& 1111
————
1001

补码的原因 保证涉及到负数的二进制计算正确
取反加1码

V8 使用最低有效位将所有值标记为 Smis 或堆指针。

0

0

0

按位|
规律: 一真则真

特殊情况
1.char中-128的二进制
反码 1111 1111 原码 -->1000 0000 -128

其实 Smis并没有你想象的那么小,但它们很容易以按位编码的方式来存储到 32 位或 64 位整数中。

          3)位的“非”,用符号“~”表示,它是一元运算符,只对单个自变量起作用。它的作用是使二进制按位“取反”。 非位运算值表:

9| 5 = ?
1001
| 0101
————
1101 ==13

补码 1000 0000

附加题:给定一个非空的整数数组,其中某个元素只出现了一次,其余每个元素都出现了两次。找到那个唯一元素。您可以使用二进制表示方式,时间复杂度为 O(n),空间复杂度为 O(1),你能找到解决方案吗? class="backword">返回搜狐,查看更多

A

~A

1

0

0

1

按位异或^
规律: 不相同位1,相同位0
9^ 5 = ?
1001
^ 0101
—————
1100 == 12

2.unsigned 存放负数问题

责任编辑:

           4)位的“异或”,用符号“^”表示,它属于二元运算符。异或位运算值表:

重点:
规律:异或的结果和参与运算的顺序没有关系
9^ 5^6 = ?
5^ 9 ^ 6 =?
规律:两个相同的数异或 等于0
5^5 = ?
6^6 = ?

---->计算机用二进制处理数据 (不会报错 不代表没有错误)
按照语法来 (错误的代码再去考虑没有意义)

A

B

A^B

1

1

0

0

1

1

1

0

1

规律:任何一个数异或上0结果不变

有符号和无符号 位数是一样的
二进制不分正负

0

0

0

9 ^ 0 = ?
6 ^0 = ?

格式占位符----->打印的方式
存放二进制不分正负的 解析方式不一样 处理的结果不一样

/*测试位的四种运算*/

public class BitOperation
{
 public static void main(String[] args)
 {
  int a = 15;
  int b = 2;
  int x = a & b;
  int y = a | b;
  int z = a ^ b;
  System.out.println(a + "&" + b + "=" + x);
  System.out.println(a + "|" + b + "=" + y);
  System.out.println(a + "^" + b + "=" + z);
 }
}

规律:任何一个数异或上同一个数量两次,结果不变
955 = ?
5^ 9^5 = ?

%u 无符号10进制整数
%d 有符号10进制整数
%x 无符号16进制整数
%o 无符号8进制整数

输出结果:
                  15 & 2 = 2
                  15 | 2 = 15
                  15 ^ 2 = 13

取反 ~

unsigned int x=-3;
unsigned int x=0xfffffffd;//代码中16进制表示的话前面加0x 8进制前面加0
//表示 把数据当作无符号整型处理
//计算机是否检查二进制

五、移位运算符

原码 —》 反码(取反) —》补码(+1)
补码 —》反码(-1)—》源码(取反)

可以试试 用%d 打印float类型(可以打印 不会报错 但是结果不对)

        移位运算符就是在二进制的基础上对数字进行平移。按照平移的方向和填充数字的规则分为三种:<<(左移)、>>(带符号右移)和>>>(无符号右移)。
  在移位运算时,byte、short和char类型移位后的结果会变成int类型,对于byte、short、char和int进行移位时,规定实际移动的次数是移动次数和32的余数,也就是移位33次和移位1次得到的结果相同。移动long型的数值时,规定实际移动的次数是移动次数和64的余数,也就是移动66次和移动2次得到的结果相同。
三种移位运算符的移动规则和使用如下所示:
<<运算规则:
按二进制形式把所有的数字向左移动对应的位数,高位移出(舍弃),低位的空位补零。
  语法格式:   需要移位的数字 << 移位的次数
  例如: 3 << 2,则是将数字3左移2位
  计算过程:   3 << 2
  首先把3转换为二进制数字0000 0000 0000 0000 0000 0000 0000 0011,然后把该数字高位(左侧)的两个零移出,其他的数字都朝左平移2位,最后在低位(右侧)的两个空位补零。则得到的最终结果是0000 0000 0000 0000 0000 0000 0000 1100,则转换为十进制是12.数学意义:
  在数字没有溢出的前提下,对于正数和负数,左移一位都相当于乘以2的1次方,左移n位就相当于乘以2的n次方。
>>运算规则:按二进制形式把所有的数字向右移动对应巍峨位数,低位移出(舍弃),高位的空位补符号位,即正数补零,负数补1.
  语法格式:   需要移位的数字 >> 移位的次数
  例如11 >> 2,则是将数字11右移2位
  计算过程:11的二进制形式为:0000 0000 0000 0000 0000 0000 0000 1011,然后把低位的最后两个数字移出,因为该数字是正数,所以在高位补零。则得到的最终结果是0000 0000 0000 0000 0000 0000 0000 0010.转换为十进制是3.数学意义:右移一位相当于除2,右移n位相当于除以2的n次方。
>>>运算规则:按二进制形式把所有的数字向右移动对应巍峨位数,低位移出(舍弃),高位的空位补零。对于正数来说和带符号右移相同,对于负数来说不同。
  其他结构和>>相似。
  小结
  二进制运算符,包括位运算符和移位运算符,使程序员可以在二进制基础上操作数字,可以更有效的进行运算,并且可以以二进制的形式存储和转换数据,是实现网络协议解析以及加密等算法的基础。
  实例操作:   

正数取反+1的负数
负数取反-1的正数

-3 原码
1000 0000 0000 0000 0000 0000 0000 0011
1111 1111 1111 1111 1111 1111 1111 1100
1111 1111 1111 1111 1111 1111 1111 1101

public class URShift {
  public static void main(String[] args) {
  int i = -1;
  i >>>= 10;
  //System.out.println(i);
  mTest();
  }
  public static void mTest(){
  //左移
  int i = 12; //二进制为:0000000000000000000000000001100
  i <<= 2; //i左移2位,把高位的两位数字(左侧开始)抛弃,低位的空位补0,二进制码就为0000000000000000000000000110000
  System.out.println(i); //二进制110000值为48;
  System.out.println("<br>");
  //右移
  i >>=2; //i右移2为,把低位的两个数字(右侧开始)抛弃,高位整数补0,负数补1,二进制码就为0000000000000000000000000001100
  System.out.println(i); //二进制码为1100值为12
  System.out.println("<br>");
  //右移example
  int j = 11;//二进制码为00000000000000000000000000001011
  j >>= 2; //右移两位,抛弃最后两位,整数补0,二进制码为:00000000000000000000000000000010
  System.out.println(j); //二进制码为10值为2
  System.out.println("<br>");
  byte k = -2; //转为int,二进制码为:0000000000000000000000000000010
  k >>= 2; //右移2位,抛弃最后2位,负数补1,二进制吗为:11000000000000000000000000000
  System.out.println(j); //二进制吗为11值为2
  }
  }

左移 <<
右移 >>

1Byte =8bit

  在Thinking in Java第三章中的一段话:
  移位运算符面向的运算对象也是
  二进制的“位”。 可单独用它们处理整数类型(主类型的一种)。左移位运算符(<<)能将运算符左边的运算对象向左移动运算符右侧指定的位数(在低位补0)。 “有符号”右移位运算符(>>)则将运算符左边的运算对象向右移动运算符右侧指定的位数。“有符号”右移位运算符使用了“符号扩展”:若值为正,则在高位插入0;若值为负,则在高位插入1。Java也添加了一种“无符号”右移位运算符(>>>),它使用了“零扩展”:无论正负,都在高位插入0。这一运算符是C或C++没有的。
  若对char,byte或者short进行移位处理,那么在移位进行之前,它们会自动转换成一个int。只有右侧的5个低位才会用到。这样可防止我们在一个int数里移动不切实际的位数。若对一个long值进行处理,最后得到的结果也 是long。此时只会用到右侧的6个低位,防止移动超过long值里现成的位数。但在进行“无符号”右移位时,也可能遇到一个问题。若对byte或 short值进行右移位运算,得到的可能不是正确的结果(Java 1.0和Java 1.1特别突出)。它们会自动转换成int类型,并进行右移位。但“零扩展”不会发生,所以在那些情况下会得到-1的结果。   

规律:左移就是左移的数乘以2的移动次幂
注意点:
由于左移运算,被移动的数的最高位会被抛弃(移除),所以左移可能会改变一个数的正负性
9<<1 = ?
0000 0000 0000 0000 0000 0000 0000 1001

除法比较慢 整数除以2 >>1 右移一位 除以2


右移 >>

数据 超过范围--->溢出
char ch=-128; 1000 0000
ch--; 0111 1111--->127

Java 定义的位运算(bitwise operators )直接对整数类型的位进行操作,这些整数类型包括long,int,short,char,and byte 。表5.1 列出了位运算:
表5.1 位运算符及其结果

9>>1 =?
规律:右移就是右移的数除以2的移动次幂
9 >>1 == 9/2(1) =4
9>>2 == 9/2(2) ==2

2.浮点型二进制的存储
float double

运算符 结果
~ 按位非(NOT)(一元运算)
& 按位与(AND)
| 按位或(OR)
^ 按位异或(XOR)
>> 右移
>>> 右移,左边空出的位以0填充
运算符 结果
<< 左移
&= 按位与赋值
|= 按位或赋值
^= 按位异或赋值
>>= 右移赋值
>>>= 右移赋值,左边空出的位以0填充
<<= 左移赋值

符号位不变 后面开始移动 根据符号位 补 1 或零
内存储存细节

float存放数据的范围 -1.7*10^38~1.7*10^38
float 4个字节 32位 1+8+23
1位 符号位
8位 指数位
23位 尾数位

续表

内存储存细节
只要定义变量,系统就会开辟一块内存空间,内存寻址从大到下
,越先定义的变量,内存地址越大。
变量的得知就是所占的存储空间最小的字节地址
注意:由于内存寻址是从大到小,所以存储书记也是从大到小的存储(先储存)

-7.88
方法
1.先转2进制小数
符号保留
整数部分按照整数二进制求法
小数部分 乘2取整 从上往下放到小数点的右边

既然位运算符在整数范围内对位操作,因此理解这样的操作会对一个值产生什么效果是重要的。具体地说,知道Java 是如何存储整数值并且如何表示负数的是有用的。因此,在继续讨论之前,让我们简短概述一下这两个话题。

类型说明符

-111.11100001

所有的整数类型以二进制数字位的变化及其宽度来表示。例如,byte 型值42的二进制代码是00101010 ,其中每个位置在此代表2的次方,在最右边的位以20开始。向左下一个位置将是21,或2,依次向左是22,或4,然后是8,16,32等等,依此类推。因此42在其位置1,3,5的值为1(从右边以0开始数);这样42是21+23+25的和,也即是2+8+32 。

1.说明长度的(它可以用于修改所三用的存储空间的大小)
sgort;
long;
long long;
用于说明数据类型,一般情况下和int配合使用
输出需要 long (%li %ld) short (%hi %hd)

小数点移动到第一个1的右边
-1.1111100001*2^2 指数形式 左移N位 *2^N

所有的整数类型(除了char 类型之外)都是有符号的整数。这意味着他们既能表示正数,又能表示负数。Java 使用大家知道的2的补码(two’s complement )这种编码来表示负数,也就是通过将与其对应的正数的二进制代码取反(即将1变成0,将0变成1),然后对其结果加1。例如,-42就是通过将42的二进制代码的各个位取反,即对00101010 取反得到11010101 ,然后再加1,得到11010110 ,即-42 。要对一个负数解码,首先对其所有的位取反,然后加1。例如-42,或11010110 取反后为00101001 ,或41,然后加1,这样就得到了42。

2.说明符号位(它可以修改符号位)

指数存 2 8位 计算方式比较特殊 指数+偏移量
2 +127--->129 1000 0001
加上一个偏移量 2^-1

如果考虑到零的交叉(zero crossing )问题,你就容易理解Java (以及其他绝大多数语言)这样用2的补码的原因。假定byte 类型的值零用00000000 代表。它的补码是仅仅将它的每一位取反,即生成11111111 ,它代表负零。但问题是负零在整数数学中是无效的。为了解决负零的问题,在使用2的补码代表负数的值时,对其值加1。即负零11111111 加1后为100000000 。但这样使1位太靠左而不适合返回到byte 类型的值,因此人们规定,-0和0的表示方法一样,-1的解码为11111111 。尽管我们在这个例子使用了byte 类型的值,但同样的基本的原则也适用于所有Java 的整数类型。

unsigned;
signed;

8位指数位 2^8 256 一半存负数和0 一半存正数
float的指数位的范围 -127~128
0000 0000 --->-127
0000 0001 --->-126
.....
1000 0000 --->1
1000 0001 ---->2

因为Java 使用2的补码来存储负数,并且因为Java 中的所有整数都是有符号的,这样应用位运算符可以容易地达到意想不到的结果。例如,不管你如何打算,Java 用高位来代表负数。为避免这个讨厌的意外,请记住不管高位的顺序如何,它决定一个整数的符号。

//如果给变量加上修饰符signed,代表当前变量的取值可以是整数/负数/零
//如果给变量加上修饰符signed,就代表把二进制的最高位作为符号位
//而且默认情况下所有变量都是右符号的(signed)
signed int num = 0

尾数位 小数点后面的内容 后面 补齐0
1 1000 0001 111 1100 0010 0000 0000 0000

5.1 位逻辑运算符
位逻辑运算符有“与”(AND)、“或”(OR)、“异或(XOR )”、“非(NOT)”,分别用“&”、“|”、“^”、“~”表示,4-3 表显示了每个位逻辑运算的结果。在继续讨论之前,请记住位运算符应用于每个运算数内的每个单独的位。
表5.2  位逻辑运算符的结果
A 0 1 0 1 B 0 0 1 1 A | B 0 1 1 1 A & B 0 0 0 1 A ^ B 0 1 1 0 ~A 1 0 1 0

//unsigned代表物符号,无符号。无符号就代表当前的取值只能装整数/零
//如果给变量加上修饰符unsigned,就代表“不”把而精致最高最为符号位
//如果想打印无符号的变量,只能用 %u

浮点型 存放规则--->
结论
1.浮点型 存放不够精确
== 比较 x==4 整型
浮点型一般不用== 给他一个范围
d<=4.001&&d>=3.999
double和float 赋值一样但是保存的值不一样

按位非(NOT)

//不同类型的说明符可以混合使用

float快 精度要求不高 float 不然double

按位非也叫做补,一元运算符NOT“~”是对其运算数的每一位取反。例如,数字42,它的二进制代码为:

数组基本概念

**** 保存数据都是近似值

00101010

数组完全初始化
int score[3] = {1,3,5};
数组部分初始化
int scores[3] = {3,5};

3.进制转换
10进制转2进制--->除2求余
10进制转8进制 除8求余
除16求余 (a~f 表示 10~15) 可以大写A~F

经过按位非运算成为

//注意:如果没有对数组进行初始化(完全和部分),那么不要随便使用数组中的数据,可能是一段垃圾数据(随机值)
//注意:定义数组的时候,数组的元素不能使用变量,如果使用变量,那么数组中是一些随机值

16进制 --->10进制

11010101

N进制转10进制
0xAF--->从右往左 从0开始依次标号

按位与(AND)

每一位*N^标号

按位与运算符“&”,如果两个运算数都是1,则结果为1。其他情况下,结果均为零。看下面的例子:

2进制和16进制相互转换

00101010 42 &00001111 15

0xAF
2进制--> 1010 1111

00001010 10

一位16进制转4位二进制

按位或(OR)

二进制转16进制
1100 0000 1111 1100 0010 0000 0000 0000
-->C0FC2000 四位转一位 -->0xC0FC2000

按位或运算符“|”,任何一个运算数为1,则结果为1。如下面的例子所示:

一位8进制转3位二进制 3位二进制转一位8进制

00101010 42 | 00001111 15

动笔算 --->最后的结论 全部写16进制-->直接提交结果
1.算二进制 (用char 8位算)
98
-76
选做

00101111 47

  1. 算二进制(float 32位二进制算)
    -3.625

按位异或(XOR)

short
long

按位异或运算符“^”,只有在两个比较的位不同时其结果是 1。否则,结果是零。下面的例子显示了“^”运算符的效果。这个例子也表明了XOR 运算符的一个有用的属性。注意第二个运算数有数字1的位,42对应二进制代码的对应位是如何被转换的。第二个运算数有数字0的位,第一个运算数对应位的数字不变。当对某些类型进行位运算时,你将会看到这个属性的用处。

2018.05.13 21:24:13

00101010 42 ^ 00001111 15

00100101 37
位逻辑运算符的应用

下面的例子说明了位逻辑运算符:

// Demonstrate the bitwise logical operators.
class BitLogic {
public static void main(String args[]) {
String binary[] = {"0000", "0001", "0010", "0011", "0100", "0101", "0110", "0111", "1000", "1001", "1010", "1011", "1100", "1101", "1110", "1111"

};
int a = 3; // 0 + 2 + 1 or 0011 in binary
int b = 6; // 4 + 2 + 0 or 0110 in binary
int c = a | b;
int d = a & b;
int e = a ^ b;
int f = (~a & b) | (a & ~b);
int g = ~a & 0x0f;

System.out.println(" a = " + binary[a]);
System.out.println(" b = " + binary[b]);
System.out.println(" a|b = " + binary[c]);
System.out.println(" a&b = " + binary[d]);
System.out.println(" a^b = " + binary[e]);
System.out.println("~a&b|a&~b = " + binary[f]);
System.out.println(" ~a = " + binary[g]);
}
} 

    在本例中,变量a与b对应位的组合代表了二进制数所有的 4 种组合模式:0-0,0-1,1-0 ,和1-1 。“|”运算符和“&”运算符分别对变量a与b各个对应位的运算得到了变量c和变量d的值。对变量e和f的赋值说明了“^”运算符的功能。字符串数组binary 代表了0到15 对应的二进制的值。在本例中,数组各元素的排列顺序显示了变量对应值的二进制代码。数组之所以这样构造是因为变量的值n对应的二进制代码可以被正确的存储在数组对应元素binary[n] 中。例如变量a的值为3,则它的二进制代码对应地存储在数组元素binary[3] 中。~a的值与数字0x0f (对应二进制为0000 1111 )进行按位与运算的目的是减小~a的值,保证变量g的结果小于16。因此该程序的运行结果可以用数组binary 对应的元素来表示。该程序的输出如下:

a = 0011 b = 0110 a|b = 0111 a&b = 0010 a^b = 0101 ~a&b|a&~b = 0101 ~a = 1100

5.2 左移运算符
左移运算符<<使指定值的所有位都左移规定的次数。它的通用格式如下所示:

value << num
这里,num 指定要移位值value 移动的位数。也就是,左移运算符<<使指定值的所有位都左移num位。每左移一个位,高阶位都被移出(并且丢弃),并用0填充右边。这意味着当左移的运算数是int 类型时,每移动1位它的第31位就要被移出并且丢弃;当左移的运算数是long 类型时,每移动1位它的第63位就要被移出并且丢弃。

在对byte 和short类型的值进行移位运算时,你必须小心。因为你知道Java 在对表达式求值时,将自动把这些类型扩大为 int 型,而且,表达式的值也是int 型。对byte 和short类型的值进行移位运算的结果是int 型,而且如果左移不超过31位,原来对应各位的值也不会丢弃。但是,如果你对一个负的byte 或者short类型的值进行移位运算,它被扩大为int 型后,它的符号也被扩展。这样,整数值结果的高位就会被1填充。因此,为了得到正确的结果,你就要舍弃得到结果的高位。这样做的最简单办法是将结果转换为byte 型。下面的程序说明了这一点:

// Left shifting a byte value.
class ByteShift {


public static void main(String args[]) {
byte a = 64, b;
int i;


i = a << 2;
b = (byte) (a << 2);


System.out.println("Original value of a: " + a);
System.out.println("i and b: " + i + " " + b);
}
}

该程序产生的输出下所示:
Original value of a: 64
i and b: 256 0
因变量a在赋值表达式中,故被扩大为int 型,64(0100 0000 )被左移两次生成值256 (10000 0000 )被赋给变量i。然而,经过左移后,变量b中惟一的1被移出,低位全部成了0,因此b的值也变成了0。
既然每次左移都可以使原来的操作数翻倍,程序员们经常使用这个办法来进行快速的2 的乘法。但是你要小心,如果你将1移进高阶位(31或63位),那么该值将变为负值。下面的程序说明了这一点:

// Left shifting as a quick way to multiply by 2.
class MultByTwo {


public static void main(String args[]) {
int i;
int num = 0xFFFFFFE;


for(i=0; i<4; i++) {
num = num << 1;
System.out.println(num);


}
} 

    这里,num 指定要移位值value 移动的位数。也就是,左移运算符<<使指定值的所有位都左移num位。每左移一个位,高阶位都被移出(并且丢弃),并用0填充右边。这意味着当左移的运算数是int 类型时,每移动1位它的第31位就要被移出并且丢弃;当左移的运算数是long 类型时,每移动1位它的第63位就要被移出并且丢弃。

    在对byte 和short类型的值进行移位运算时,你必须小心。因为你知道Java 在对表达式求值时,将自动把这些类型扩大为 int 型,而且,表达式的值也是int 型。对byte 和short类型的值进行移位运算的结果是int 型,而且如果左移不超过31位,原来对应各位的值也不会丢弃。但是,如果你对一个负的byte 或者short类型的值进行移位运算,它被扩大为int 型后,它的符号也被扩展。这样,整数值结果的高位就会被1填充。因此,为了得到正确的结果,你就要舍弃得到结果的高位。这样做的最简单办法是将结果转换为byte 型。下面的程序说明了这一点:

// Left shifting a byte value.
class ByteShift {


public static void main(String args[]) {
byte a = 64, b;
int i;


i = a << 2;
b = (byte) (a << 2);


System.out.println("Original value of a: " + a);
System.out.println("i and b: " + i + " " + b);
}
} 

该程序产生的输出下所示:
Original value of a: 64
i and b: 256 0
    因变量a在赋值表达式中,故被扩大为int 型,64(0100 0000 )被左移两次生成值256 (10000 0000 )被赋给变量i。然而,经过左移后,变量b中惟一的1被移出,低位全部成了0,因此b的值也变成了0。
    既然每次左移都可以使原来的操作数翻倍,程序员们经常使用这个办法来进行快速的2 的乘法。但是你要小心,如果你将1移进高阶位(31或63位),那么该值将变为负值。下面的程序说明了这一点:

// Left shifting as a quick way to multiply by 2.
class MultByTwo {


public static void main(String args[]) {
int i;
int num = 0xFFFFFFE;


for(i=0; i<4; i++) {
num = num << 1;
System.out.println(num);


}
}
} 

该程序的输出如下所示:

536870908
1073741816
2147483632
-32

初值经过仔细选择,以便在左移 4 位后,它会产生-32。正如你看到的,当1被移进31 位时,数字被解释为负值。

5.3  右移运算符
右移运算符>>使指定值的所有位都右移规定的次数。它的通用格式如下所示:

value >> num

这里,num 指定要移位值value 移动的位数。也就是,右移运算符>>使指定值的所有位都右移num位。下面的程序片段将值32右移2次,将结果8赋给变量a:

int a = 32;
a = a >> 2; // a now contains 8

当值中的某些位被“移出”时,这些位的值将丢弃。例如,下面的程序片段将35右移2 次,它的2个低位被移出丢弃,也将结果8赋给变量a:

int a = 35;
a = a >> 2; // a still contains 8

用二进制表示该过程可以更清楚地看到程序的运行过程:

00100011 35
>> 2
00001000 8

将值每右移一次,就相当于将该值除以2并且舍弃了余数。你可以利用这个特点将一个整数进行快速的2的除法。当然,你一定要确保你不会将该数原有的任何一位移出。

右移时,被移走的最高位(最左边的位)由原来最高位的数字补充。例如,如果要移走的值为负数,每一次右移都在左边补1,如果要移走的值为正数,每一次右移都在左边补0,这叫做符号位扩展(保留符号位)(sign extension ),在进行右移操作时用来保持负数的符号。例如,–8 >> 1 是–4,用二进制表示如下:

11111000 –8 >>1 11111100 –4

一个要注意的有趣问题是,由于符号位扩展(保留符号位)每次都会在高位补1,因此-1右移的结果总是–1。有时你不希望在右移时保留符号。例如,下面的例子将一个byte 型的值转换为用十六
进制表示。注意右移后的值与0x0f进行按位与运算,这样可以舍弃任何的符号位扩展,以便得到的值可以作为定义数组的下标,从而得到对应数组元素代表的十六进制字符。

// Masking sign extension.
class HexByte {
static public void main(String args[]) {

char hex[] = {
’0’, ’1’, ’2’, ’3’, ’4’, ’5’, ’6’, ’7’,
’8’, ’9’, ’a’, ’b’, ’c’, ’d’, ’e’, ’f’’
};
byte b = (byte) 0xf1;

System.out.println("b = 0x" + hex[(b >> 4) & 0x0f] + hex[b & 0x0f]);}} 

该程序的输出如下:
b = 0xf1
5.4  无符号右移
    正如上面刚刚看到的,每一次右移,>>运算符总是自动地用它的先前最高位的内容补它的最高位。这样做保留了原值的符号。但有时这并不是我们想要的。例如,如果你进行移位操作的运算数不是数字值,你就不希望进行符号位扩展(保留符号位)。当你处理像素值或图形时,这种情况是相当普遍的。在这种情况下,不管运算数的初值是什么,你希望移位后总是在高位(最左边)补0。这就是人们所说的无符号移动(unsigned shift )。这时你可以使用Java 的无符号右移运算符>>> ,它总是在左边补0。

    下面的程序段说明了无符号右移运算符>>> 。在本例中,变量a被赋值为-1,用二进制表示就是32位全是1。这个值然后被无符号右移24位,当然它忽略了符号位扩展,在它的左边总是补0。这样得到的值255被赋给变量a。

int a = -1; a = a >>> 24;

下面用二进制形式进一步说明该操作:

11111111 11111111 11111111 11111111 int型-1的二进制代码>>> 24 无符号右移24位00000000 00000000 00000000 11111111 int型255的二进制代码

由于无符号右移运算符>>> 只是对32位和64位的值有意义,所以它并不像你想象的那样有用。因为你要记住,在表达式中过小的值总是被自动扩大为int 型。这意味着符号位扩展和移动总是发生在32位而不是8位或16位。这样,对第7位以0开始的byte 型的值进行无符号移动是不可能的,因为在实际移动运算时,是对扩大后的32位值进行操作。下面的例子说明了这一点:

// Unsigned shifting a byte value.
class ByteUShift {
static public void main(String args[]) {
进制表示。注意右移后的值与0x0f进行按位与运算,这样可以舍弃任何的符号位扩展,以便得到的值可以作为定义数组的下标,从而得到对应数组元素代表的十六进制字符。
// Masking sign extension.
class HexByte {
static public void main(String args[]) {

char hex[] = {
’0’, ’1’, ’2’, ’3’, ’4’, ’5’, ’6’, ’7’,
’8’, ’9’, ’a’, ’b’, ’c’, ’d’, ’e’, ’f’’
};
byte b = (byte) 0xf1;

System.out.println("b = 0x" + hex[(b >> 4) & 0x0f] + hex[b & 0x0f]);}} 

该程序的输出如下:

b = 0xf1

5.4 无符号右移
正如上面刚刚看到的,每一次右移,>>运算符总是自动地用它的先前最高位的内容补它的最高位。这样做保留了原值的符号。但有时这并不是我们想要的。例如,如果你进行移位操作的运算数不是数字值,你就不希望进行符号位扩展(保留符号位)。当你处理像素值或图形时,这种情况是相当普遍的。在这种情况下,不管运算数的初值是什么,你希望移位后总是在高位(最左边)补0。这就是人们所说的无符号移动(unsigned shift )。这时你可以使用Java 的无符号右移运算符>>> ,它总是在左边补0。

下面的程序段说明了无符号右移运算符>>> 。在本例中,变量a被赋值为-1,用二进制表示就是32位全是1。这个值然后被无符号右移24位,当然它忽略了符号位扩展,在它的左边总是补0。这样得到的值255被赋给变量a。

int a = -1; a = a >>> 24;

下面用二进制形式进一步说明该操作:

11111111 11111111 11111111 11111111 int型-1的二进制代码>>> 24 无符号右移24位00000000 00000000 00000000 11111111 int型255的二进制代码

由于无符号右移运算符>>> 只是对32位和64位的值有意义,所以它并不像你想象的那样有用。因为你要记住,在表达式中过小的值总是被自动扩大为int 型。这意味着符号位扩展和移动总是发生在32位而不是8位或16位。这样,对第7位以0开始的byte 型的值进行无符号移动是不可能的,因为在实际移动运算时,是对扩大后的32位值进行操作。下面的例子说明了这一点:

// Unsigned shifting a byte value.
class ByteUShift {
static public void main(String args[]) {
int b = 2;
int c = 3;

a |= 4;
b >>= 1;
c <<= 1;
a ^= c;
System.out.println("a = " + a);
System.out.println("b = " + b);
System.out.println("c = " + c);
}
} 

该程序的输出如下所示:

a = 3
b = 1
c = 6

六、赋值运算符        

赋值运算符是程序中最常用的运算符了,只要有变量的声明,就要有赋值运算。如a

3;这里的a我们都知道是变量名,根据前面对变量的定义,我们可以知道这里的a实际上就是内存空间的一个名字,它对应的是一段内存空间,一在要在这个空间放入3这个值。这个放入的过程就实现了赋值的过程。
              赋值运算一览表

运算符

一般表示法

Java语言表示法

+=

a = a + b

a += b

-=

a = a - b

a -= b

*=

a = a * b

a *=b

/=

a=a / b

a /= b

%=

a = a % b

a %= b

>>=

a = a >> b

a >>= b

>>>=

a = a >>> b

a >>>= b

七、三元运算符         三元运算符比较罕见,因为它有三个运算对象,但它也确实属于运算符的一种,因为它最终也是产生一个值。它也可以转化为条件判断语句,只不过这种处理方式更简洁、明了。
        它的运算过程是这样的:
         如果“布尔表达式”的结果是“true”,就返回值0;
         如果“布尔表达式”的结果是“false”,就返回值1;
         它的返回值做为最终结果返回。

八、逗号运算符
        在Java中,逗号运算符的惟一使用场所就是在for循环语句中。

九、字符串运算符         “+”号这个运算符,在Java中有一项特殊的用法,它不仅起到连接不同的字符串,还有一种隐式的转型功能。

十、转型运算符
        转型运算符可以说是一种特殊的运算符,它是将一种类型的数据或对象,强制转变为另一种类型。

/*强制转型测试*/

public class TypeTran
{
   public static void main(String[] args)
   {
     int x ;
     double y;
     x = (int)22.5 + (int)34.7;  //强制转型可能引起精度丢失
     y = (double)x;
     System.out.println("x = " + x);
     System.out.println("y = " + y);
   }
}
输出结果:
                  x = 56
                  y = 56.0
分析:
          可以发现,由于强制转型,使数据精度丢失。系统会忽略强制转型的检查。所以对于强制转型,必须清楚转型是否可行。

         最后总结一下运算符的优先级

运算符

优先级

括号()

1最高

++、--

2

~、!

3

*、/、%

4

+、-(减)

5

<<、>>、>>>

6

>、<、>=、<=

7

==、!=

8

&

9

^

10

|

11

&&

12

||

13

? :

14

本文由澳门威斯尼人平台登陆发布于互联网,转载请注明出处:进制转换,C语言部分

关键词:

上一篇:韩国青瓦台,韩国拟禁止加密货币交易

下一篇:没有了