计算机数值表示&Integer

  • 原码 反码 补码
    • 为什么在计算机中使用补码
    • 将减法转换为加法的正确性证明
  • Integer
  • Short,Long,Byte
  • Double,Float

原文章 计算机数值表示&Integer

在分析Integer类之前,先复习一下在计算机中数值的表示

原码 反码 补码

有符号数在计算机中存储,用数的最高位存放符号, 正数为0, 负数为1

  • 原码:原码就是符号位加上真值的绝对值,即用第一个二进制位表示符号(正数该位为0,负数该位为1),其余位表示值。
  • 反码:正数的反码与其原码相同;负数的反码是对其原码逐位取反,但符号位除外。
  • 补码:正数的补码就是其本身;负数的补码是在其反码的基础上+1
    例如:
  • 2 : 00000010(原码),00000010(反码),00000010(补码)
  • -2: 10000010(原码),11111101(反码),11111110(补码)

由补码求源码:

  • 如果补码的符号位为“0”,表示是一个正数,所以补码就是该数的原码。
  • 如果补码的符号位为“1”,表示是一个负数,求原码的操作可以是:符号位为1,其余各位取反,然后再整个数加1。

为什么在计算机中使用补码

对于计算机而言,加减乘数是最基础的运算, 要设计的尽量简单。我们知道,根据运算法则,减去一个正数等于加上一个负数,所以计算机内部可以只有加法而没有减法,将符号位也参与运算,将减法用加法替代。

补码的优点:

  • 可将减法变为加法,省去减法器;
  • 修复了原码中0的符号(有 [+0] [-0] 之分)以及存在两个编码(0000 0000 和 1000 0000)的问题,而且还能够多表示一个最低数。

补码的由来
负数的补码时相应的正数取反+1
假如一个数是10000110,对应的正数是00000110,该数的补码是:11111010
可以看做是0-num

100000000
-00000110
-----------11111010

1 0000 0000 = 1111 1111 + 1
因此可以将以上分为两个步骤:按位取反,加1

 11111111
-00000110
-------------11111001  +111111010

将减法转换为加法的正确性证明

已知:X、Y都为正整数,Z = X - Y = X + (-Y)
证明:Z = X的补码 + (-Y的补码)

X的补码 = X; // 正数的补码为其自身
-Y的补码 = (1111 1111 - Y) + 1; // 负数的补码为除符号位的其它位取反加1
Z = X的补码 + (-Y的补码) = X +  (1111 1111 - Y) + 1 = X - Y + 1 0000 0000= X - Y + 0000 0000= X - Y

Integer

佩服Lee Boynton,Arthur van Hoff,Josh Bloch,Joseph D. Darcy

计算机中二进制运算比普通的加减乘除快很多,因此代码中很多使用了位运算,难以阅读,挑选了几个具有代表性的函数分析

2^n-1 是一个神奇的数,在各种场景中都有它的身影,比如hashmap取索引,比如求2^n的mod

Integer具有缓存机制,当然不止是Integer,包括Long,Byte等都具有这种性质

public final class Integer extends Number implements Comparable<Integer> {@Native public static final int   MIN_VALUE = 0x80000000;@Native public static final int   MAX_VALUE = 0x7fffffff;public static final Class<Integer>  TYPE = (Class<Integer>) Class.getPrimitiveClass("int");private final int value;

MIN_VALUE表示最小值-2^31 ,MAX_VALUE表示最大值2^32-1

转换进制


public static String toString(int i, int radix) {if (radix < Character.MIN_RADIX || radix > Character.MAX_RADIX)radix = 10;/* Use the faster version */if (radix == 10) {return toString(i);}//int型的数最长32位,加上符号33位char buf[] = new char[33];boolean negative = (i < 0);int charPos = 32;//将所有的数转换为负数,主要是为了统一接下来的计算//如果不这样,负数%radix为负数,正数%radix为正数,需要分两种情况判断//为什么不转换为正数,因为最小的负数-2^31转换为正数会溢出if (!negative) {i = -i;}//开始转换while (i <= -radix) {buf[charPos--] = digits[-(i % radix)];i = i / radix;}buf[charPos] = digits[-i];if (negative) {buf[--charPos] = '-';}return new String(buf, charPos, (33 - charPos));}

转换为无符号进制数,转换为2^shift进制

private static String toUnsignedString0(int val, int shift) {// assert shift > 0 && shift <=5 : "Illegal shift value";//得到除了前导0其他的位数int mag = Integer.SIZE - Integer.numberOfLeadingZeros(val);//得到最大的长度int chars = Math.max(((mag + (shift - 1)) / shift), 1);char[] buf = new char[chars];formatUnsignedInt(val, shift, buf, 0, chars);// Use special constructor which takes over "buf".return new String(buf, true);}static int formatUnsignedInt(int val, int shift, char[] buf, int offset, int len) {int charPos = len;//要转换的进制int radix = 1 << shift;//掩码,永远时2^n-1int mask = radix - 1;//每次得到后shift位,val & mask相当于mod运算!,循环得到结果do {buf[offset + --charPos] = Integer.digits[val & mask];val >>>= shift;} while (val != 0 && charPos > 0);return charPos;}

将一个整数放入字符数值中

static void getChars(int i, int index, char[] buf) {int q, r;int charPos = index;char sign = 0;if (i < 0) {sign = '-';i = -i;}// Generate two digits per iterationwhile (i >= 65536) {q = i / 100;// really: r = i - (q * 100);r = i - ((q << 6) + (q << 5) + (q << 2));i = q;//实际上r是一个100以内的数,一次性可以确定两位,根据DigitOnes和DigitTens两个数组buf [--charPos] = DigitOnes[r];buf [--charPos] = DigitTens[r];}// Fall thru to fast mode for smaller numbers// assert(i <= 65536, i);for (;;) {q = (i * 52429) >>> (16+3);r = i - ((q << 3) + (q << 1));  // r = i-(q*10) ...buf [--charPos] = digits [r];i = q;if (i == 0) break;}if (sign != 0) {buf [--charPos] = sign;}}

求前导0的数量

public static int numberOfLeadingZeros(int i) {// HD, Figure 5-6if (i == 0)return 32;int n = 1;//先判断高16位,再判断8位...类似二分法if (i >>> 16 == 0) { n += 16; i <<= 16; }if (i >>> 24 == 0) { n +=  8; i <<=  8; }if (i >>> 28 == 0) { n +=  4; i <<=  4; }if (i >>> 30 == 0) { n +=  2; i <<=  2; }//判断最高位,若是0,则就是31位,反之30位前导0n -= i >>> 31;return n;}

求低位第一位为1的值

public static int lowestOneBit(int i) {// HD, Section 2-1return i & -i;}

求高为第一位为1的权值

public static int highestOneBit(int i) {// HD, Figure 3-1i |= (i >>  1);i |= (i >>  2);i |= (i >>  4);i |= (i >>  8);i |= (i >> 16);//此时i为11111111...return i - (i >>> 1);}

缓存机制:默认缓存范围是-128~127,因此,两个数值在此区间的Ing=teger使用==判断返回的是true,二其他相等范围的Integer则返回false。例如:

        Integer c=55;Integer d=55;System.out.println(c==d);(true)Integer e=999;Integer f=999;System.out.println(e==f);(false)

源码:

//私有的静态内部类
private static class IntegerCache {static final int low = -128;static final int high;//使用一个数组存储缓存static final Integer cache[];//静态代码块,在类加载时期就已经执行了static {int h = 127;//用于指定缓冲区的大小String integerCacheHighPropValue =sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high");if (integerCacheHighPropValue != null) {try {int i = parseInt(integerCacheHighPropValue);i = Math.max(i, 127);// Maximum array size is Integer.MAX_VALUEh = Math.min(i, Integer.MAX_VALUE - (-low) -1);} catch( NumberFormatException nfe) {// If the property cannot be parsed into an int, ignore it.}}high = h;cache = new Integer[(high - low) + 1];int j = low;for(int k = 0; k < cache.length; k++)cache[k] = new Integer(j++);assert IntegerCache.high >= 127;}private IntegerCache() {}}
//如果数值在缓存范围,获取的就是缓存的对象,而非重新new
public static Integer valueOf(int i) {if (i >= IntegerCache.low && i <= IntegerCache.high)return IntegerCache.cache[i + (-IntegerCache.low)];return new Integer(i);}

Short,Long,Byte

这些类与Integer相似,只是范围不同,它们也有缓存机制,范围都是-128~127,并且不可更改

Double,Float

注意:是允许1/0,-1/0,0/0的,其他类型都不允许

例如:

        Double a=-1.0/0.0+100;Double b=1.0/0.0;Double c=0.0/0.0;System.out.println(a);  ( -Infinity )System.out.println(b);  ( Infinity )System.out.println(c);  ( NaN )

借鉴了你真的了解补码吗

计算机数值表示Integer相关推荐

  1. Pandas把dataframe中的整数数值(integer)转化为时间(日期、时间)信息实战

    Pandas把dataframe中的整数数值(integer)转化为时间(日期.时间)信息实战 目录 Pandas把dataframe中的整数数值转化为时间(日期.时间)信息实战

  2. 计算机数值中的乘法除法原理

    乘法:被分解为左移累加. 除法:被分解为右移累减去,减法可以转换为加法. 浮点数的运算: S x 2(^F) x M 浮点数是原码表示法,S符号位,F阶码 + 127, M尾数舍弃前面的1(如果F&l ...

  3. 计算机数值仿真及虚拟现实论文,计算机仿真论文- 计算机仿真技术及其发展.doc...

    计算机仿真技术及其发展 一.引言: 作为信息技术核心的计算机技术自其诞生之日起经历了50多年的发展,以广泛应用于国民经济和社会生活中.而作为计算机技术重要组成部分的计算机三维视景仿真技术,因其有效性. ...

  4. 数值计算方法计算机,数值计算方法

    常见"问题" 1.如何认识数值计算课程?它与数学学科的其它分支以及计算机的关系如何? 2.何为算法?如何判断数值算法的优劣? 3.数值计算方法中最关注哪些误差?为什么? 4.什么是 ...

  5. 计算机数值数据的编码,计算机数值数据编码(原码,反码,补码,移码)

    机器数有无符号数和带符号数之分.无符号数表示正数,在机器数中没有符号位.对于无符号数,若约定小数点的位置在机器数的最低位以后,则是纯整数:若约定小数点的位置在机器数的最高位以前,则是纯小数.对于带符号 ...

  6. 计算机数值类型的数据为什么以补码表示,计算机为什么使用补码来存储数据

    计算机为什么使用补码来存储数据 说明:以下讨论,都是用8位来存储的数据类型:char类型, 为什么?为什么用补码呢?我反复思考着,后来在王爽的汇编语言里和网上找到了答案,有如下总结: 原码表示的数: ...

  7. 利用计算机进行数值模拟计算,数值模拟法

    差分法 差分法是把原来求解物体内随空间.时间连续分布的温度问题,转化为求在时间领域和空间领域内有限个离散点的温度值问题,再用这些离散点上的温度值去逼近连续的温度分布.差分法的解题基础是用差商来代替微商 ...

  8. 【计算机英语词汇和词组-持续更新中】

    推荐词典:有道词典 理由:在看外文网站的时候,可以实现 取词和划词翻译 这是 在看外文网站的时候,一点点 记录的学习笔记,归纳后方便记忆 按照 首字母顺序排列 备注的发音音标,都是美式的发音 持续更新 ...

  9. 计算机仿真的过程,计算机仿真的过程与方法.doc

    <通信系统仿真> 实验报告 姓名杨利刚班级A0811实验室203组号28学号28实验日期实验名称实验一 计算机仿真的过程与方法实验成绩教师签字一.实验目的 1.掌握计算机仿真的一般过程 2 ...

最新文章

  1. android git提交整个项目_使用git管理嵌入式软件版本
  2. SPOJ 27020 GST Calculator
  3. 解决packet tracer不能复制CLI内容的问题
  4. Javascript中的valueOf与toString
  5. 3.8 高级检索方式(二)
  6. P5371-[SNOI2019]纸牌【矩阵乘法】
  7. mybatis oracle trim,Mybatis trim标签
  8. bzoj 4548: 小奇的糖果 bzoj 3658: Jabberwocky(双向链表+树状数组)
  9. CorelDRAW2021版本下载 百度网盘
  10. 对于目标文件系统,文件过大放不到U盘里
  11. 《SEM长尾搜索营销策略解密》一一1.5 互联网时代,世界不再匮乏
  12. 计算几何之多边形重心
  13. wxs 实现小程序拖拽功能
  14. 相似度度量的不同方法
  15. python虚拟机管理系统_python 虚拟机 pdf
  16. H3C无线网络优化指导——经验之谈
  17. ppt转.exe文件小技巧(超链接含视频)
  18. sap中如何追踪生产订单的修改记录
  19. JS与jQuery获取任意事件的子元素下标(获取当前类数组的某一子元素下标)
  20. 一文读懂Tiger DAO VC模式,风险投资改朝换代

热门文章

  1. 中欣晶圆完成B轮33亿元融资;晶科能源与宁德时代达成战略合作 | 美通社头条...
  2. 使用微信小程序拨打电话
  3. Traefik v2.9-IngressRoute
  4. css3滤镜属性filter实现网页变黑白效果
  5. 抖音SEO,抖音SEO搜索排名详细介绍
  6. 解决开发qq音乐singer-detail组件时子路由跳转失败问题
  7. 蜘蛛爬行html语言的顺序,SEO优化 蜘蛛的爬行规则以及让蜘蛛爬行的快速办法
  8. scala 中 foreach 的作用解释
  9. 安卓系统的电视机_换机顶盒比换电视机划算,海美迪4K播放器H7 Plus体验
  10. 最好的vsftpd配置教程