最早由于做作业,结识了java的BigInrger类。读着读着,越来越觉得有趣。后来作业做完,也不忍丢下它,索性把全部代码研究一遍。

开始的时候,一个上午时间最多读懂2个方法。但是还是有滋有味的坚持了下来。下面开始一点点剖开它“隐藏”的秘密。

首先要想搞懂两个问题:BigIngeter类的目的——实现高精度数的存储和计算。基础的实现机理——用int型(32位)数组存储数据。(在代码的注释中有详细说明)

/////////////////////////////////////////////////////////////

BigInteger类中的属性:{

int signum;    符号位,负数是为-1,零时为0,正数是为1

int[] mag;     The magnitude of this BigInteger,大数的值

//其他辅助变量暂时先不看

}

首先来分析下构造函数 (构造五部曲:1.检查是否符合标准 2.去零 3.mag赋值
4.去mag中零 5.符号位赋值)

1. 使用byte(8位)型数组构造BigInteger:

/////////////////////////////////////////////////////////////////////

public BigInteger(byte[] val) {
  if (val.length == 0)
    
throw new NumberFormatException("Zero length BigInteger");
//传入数组长度为零,报错

if (val[0] < 0) {
     
  mag = makePositive(val);
    
signum = -1;    
     
     
//如果数组第一个值为负数,则将数组变正存入mag,signum赋-1
 } else {
    
mag = stripLeadingZeroBytes(val);
 //如果非负,则可直接去掉前面无效零,再赋给mag
    
signum = (mag.length == 0 ? 0 : 1);

}

}

下面看一下具体调用的函数

///////////////////////////////////////////////////////////////////////////

private static int[] stripLeadingZeroBytes(byte a[]) {
 int byteLength = a.length;
 int keep;

// Find first nonzero byte
 for (keep=0; keep<a.length
&& a[keep]==0; keep++)
 //找到第一个有效位,并用keep记录下
    
;

// Allocate new array and copy relevant part
of input array
       
int intLength = ((byteLength - keep) + 3)/4;  
//计算int[]的长度,byte[1/2/3/4]对应int[1]

int[] result = new int[intLength];
       
int b = byteLength - 1;
       
for (int i = intLength-1; i >= 0; i--) {
           
result[i] = a[b--] & 0xff;  
     
 
//向int[]赋值,&0xff的作用是消除对int前24位的影响

(计算机中使用补码存储数据,如果直接将一个第一位为“1”的byte值赋给int,则前24为将为“1”)

int bytesRemaining = b - keep + 1;
           
int bytesToTransfer = Math.min(3, bytesRemaining);
           
for (int j=8; j <= 8*bytesToTransfer; j += 8)
               
result[i] |= ((a[b--] & 0xff)
<< j);  
  //进行移位,每次移动8位,再进行或运算
       
}
       
return result;
    }

//////////////////////////////////////////////////////////////

private static int[]
makePositive(byte a[]) {

int keep, k;
     
  int byteLength = a.length;
 
// Find first non-sign (0xff) byte of input
for (keep=0; keep<byteLength
&& a[keep]==-1; keep++)
//找出非符号位(此处我看了很久才看懂)。若a[]=-1,即计算机中二进制为“11111111”,在int型中全为“1”的前几位被认为是符号位。要想转换成正的int值,只需要后几位即可。
   ;
 
     
  
for (k=keep; k<byteLength
&& a[k]==0; k++)  
   
 //由于传入参数数组第一个值必为负(由构造函数可得),所以不必考虑去零,变量k的作用只是判断需要“额外”位
   ;
 
int extraByte = (k==byteLength) ? 1 : 0;  
     
//如果除符号位以外的全部为“0”,则需要“额外”1位来存储数据
     
  int intLength = ((byteLength - keep + extraByte)
+ 3)/4;
int result[] = new int[intLength];
 
     
  int b = byteLength - 1;
     
  for (int i = intLength-1; i >= 0;
i--) {
     
      result[i]
= a[b--] & 0xff;
     
      int
numBytesToTransfer = Math.min(3, b-keep+1);
     
      if
(numBytesToTransfer < 0)
     
     
    numBytesToTransfer = 0;
     
      for (int
j=8; j <= 8*numBytesToTransfer; j += 8)
     
     
    result[i] |= ((a[b--]
& 0xff) << j);
 
     
      // Mask
indicates which bits must be complemented
     
      int mask =
-1 >>>
(8*(3-numBytesToTransfer));
 //将负值变为正值,即由原码转反码
     
      result[i]
= ~result[i] & mask;
     
  }
 
// Add one to one's complement to generate two's
complement
for (int i=result.length-1; i>=0; i--) {
     
      result[i]
= (int)((result[i] & LONG_MASK) + 1);
 //long LONG_MASK =
0xffffffffL;为了进行位运算而不考虑int符号问题
   if (result[i] != 0)
   
//(这个地方也把我蒙骗了好久)突然恍悟,其实就是+1后不为零,即不需要进位,就break退出吧!
     
     
    break;
     
  }
 
return result;
    }
 
2.  使用int(32位)型数组构造BigInteger:
/////////////////////////////////////////////////////////////
private BigInteger(int[] val) {
if (val.length == 0)
   throw new
NumberFormatException("Zero length BigInteger");
 
if (val[0] < 0) {
     
      mag =
makePositive(val);
   signum = -1;
} else {
   mag =
trustedStripLeadingZeroInts(val);
   signum = (mag.length == 0
? 0 : 1);
}
    }
 
与byte[]构造原理相同,并且更为简单,不重述。有一点说明,这里使用trustedStripLeadingZeroInts可信赖的去零方法,与StripLeadingZeroInts的区别在于,对于可信赖的去零方法,如果没有无效零,则直接返回原数组,不进行复制。
 
 
转于:http://blog.sina.com.cn/s/blog_6c58b3bf01013wer.html

解析java.math.BigInteger类——构造函数的更多相关文章

  1. 算法笔记--java的BigInteger类及BigDecimal类

    引包:import java.math.*; BigInteger类: 可以使用构造方法:public BigInteger(String val),或者valueOf(int)函数,如: BigIn ...

  2. 【java.math.BigInteger】【转】常见问题

    好大的链接给原作 Q: 在java怎样将BigInteger类型的数据转成int类型的? A:BigInteger的intValue()可以获得int类型数值. Q: java.math.BigInt ...

  3. Java API —— BigInteger类

    1.BigInteger类概述        可以让超过Integer范围内的数据进行运算 2.构造方法     public BigInteger(String val) 3.BigInteger类 ...

  4. java.math.BigInteger使用心得总结(转)

    今天参考课本写了一个关于二进制与十进制转换的程序,程序算法不难,但写完后测试发现不论是二转十还是十转二,对于大于21亿即超过整数范围的数不能很好的转换.都会变成0.参考书籍发现使用使用BigInteg ...

  5. java.math.BigDecimal类

    BigDecimal类用于高精度计算.一般的float型和Double型数据只可以用来做科学计算或者是工程计算,由于在商业计算中,要求的数字精度比较高,所以要用到java.math.BigDecima ...

  6. java基础-BigInteger类常用方法介绍

    java基础-BigInteger类常用方法介绍 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.BigInteger类概述 Java中long型为最大整数类型,对于超过long ...

  7. 连接Mysql时出现java.math.BigInteger cannot be cast to java.lang.Long问题

    今天遇见这样一个坑.在连接数据库进行查询数据时,大家可能会遇见这样一个问题:java.math.BigInteger cannot be cast to java.lang.Long,然后去检查代码中 ...

  8. java.math.BigDecimal类multiply的使用

    java.math.BigInteger.multiply(BigInteger val) 返回一个BigInteger,其值是 (this * val).声明 以下是java.math.BigInt ...

  9. 初学MyBatis(踩坑)Error querying database. Cause: java.sql.SQLException: java.lang.ClassCastException: java.math.BigInteger cannot be cast to java.lang.Long

    最近在学习Mybatis,代码全部根据教程写好了,一运行结果报了一个错误,主要错误内容: Caused by: org.apache.ibatis.exceptions.PersistenceExce ...

随机推荐

  1. bzoj 2788 [Poi2012]Festival 差分约束+tarjan+floyd

    题目大意 有n个正整数X1,X2,...,Xn,再给出m1+m2个限制条件,限制分为两类: 1.给出a,b (1<=a,b<=n),要求满足Xa + 1 = Xb 2.给出c,d (1&l ...

  2. Java-动态规划-最多苹果数量的方法

    平面上有N*M个格子,每个格子中放着一定数量的苹果.你从左上角的格子开始,每一步只能向下走或是向右走,每次走到一个格子上就把格子里的苹果收集起来,这样下去,你最多能收集到多少个苹果. 思路: 解这个问 ...

  3. 【Visual Studio】Error: forget to add '#include "stdafx.h"' to your source (转)

    原文转自 http://www.cnblogs.com/qunews/articles/2200313.html [问题原因]在编译时使用了预编译头文件, [解决方法]Project-->Pro ...

  4. linux-3.2.36内核启动1-启动参数(arm平台 启动参数的获取和处理,分析setup_arch)【转】

    转自:http://blog.csdn.net/tommy_wxie/article/details/17093297 最近公司要求调试一个内核,启动时有问题,所以就花了一点时间看看内核启动. 看的过 ...

  5. 52深入理解C指针之---不透明指针

    该系列文章源于<深入理解C指针>的阅读与理解,由于本人的见识和知识的欠缺可能有误,还望大家批评指教.一.size_t:用于安全表示长度,所有平台和系统都会解析成自己对应的长度 1.定义:s ...

  6. 使用C语言和i2c-dev驱动

    原文地址:blog.csdn.NET/wyt2013/article/details/20740659 感谢作者分享. 在本博客的<使用Beaglebone Black的I2C(一)>中, ...

  7. 简单的 "双缓冲" 绘图的例子

    http://www.cnblogs.com/del/archive/2010/04/19/1715779.html 所谓双缓冲就是先画到内存画布(如: TBitmap), 然后再转帖到目的地. 譬如 ...

  8. Codeforces 490F Treeland Tour(离散化 + 线段树合并)

    题目链接 Treeland Tour 题目就是让你求树上LIS 先离散化,然后再线段树上操作.一些细节需要注意一下. #include <bits/stdc++.h> using name ...

  9. 一次完整的http请求过程以及网络I/O模型select、epoll

    a.一次完整的http请求过程 1.域名解析,得到域名对应的IP; 2.三次握手,客户端与服务器通过socket建立TCP/IP连接; 3.浏览器向服务器发送http请求,如:GET/index.ht ...

  10. Oracle hidden costs revealed, Part2 – Using DTrace to find why writes in SYSTEM tablespace are slower than in others

    http://blog.tanelpoder.com/2008/09/02/oracle-hidden-costs-revealed-part2-using-dtrace-to-find-why-wr ...