用字符串解决大数问题

用字符串处理数值运算
总体思想:按照小学算术运算计算,按位运算从数组最高位,一个个的取出来相加(当然的先把单个字符转换为整型),记住进位,循环计算
需要做的事情:
(1)判断输入的字符串是否为数字 (特别要考虑小数点,如果做除法,被除数不能为0)
(2)比较2个字符串长度大小,对长度小的字符串左边补0
题1:如果系统要使用超大正整数(超过long的范围),请你设计一个数据结构来存储这种超大型数字以及设计一种算法来实现超大整数的加法运算 。
分析:
1、判断输入的字符串是否为数字
短字符串左边补0
把两个的长度做比较,在左面补0,使之与较长的字符串一样长  
2、转换为整数按位运算
按位运算从数组最高位,一个个数的取出来相加(当然的先把单个字符转换为整型)
5、设置进位
result=a+b+jw两个数相加及加上进位
1)if>10,并且这不是最左边一个字符(最高位)相加,相加结果等于result=result-10,并把进位设为1;
2)如果没有大于10,就把进位设为0

如此循环,把相加的结果以字符串的形式结合起来,就得到最后的结果 

设计测试用例:

1、功能测试 
String str=doAdd("123","4567"); //都是正整数相加
2、边界测试 
3、负面测试
String str=doAdd(null,"4567"); //输入字符串为null
String str=doAdd("","4567"); //输入字符串为""
String str=doAdd("a123","4b567");//输入了非数字的字符串

写可以运行的代码:

public String doAdd(String a,String b) throws Exception {
       //输入控制(针对测试用例的负面测试)
	   if(a==null || a=="" || b==null || b="")
	      throw new Exception("input number can not be null or empty");
	   if( !isNumber(a) || !isNumber(b) ) //输入必须为数字字符串
	      throw new Exception("input parmeters must be numbers");
	   
       String str="";   //存储结果字符串
	   
	   //计算需要给较短字符串左边补零的个数
       int lenA=a.length(); 
       int lenB=b.length(); 
       int maxLen=(lenA>lenB) ? lenA : lenB; 
       int minLen=(lenA<lenB) ? lenA : lenB; 
       String strTmp=""; 
       
       for(int i=maxLen-minLen;i>0;i--) {
	        strTmp+="0"; 
	   }//end for

       //把长度调整到相同 
       if(maxLen==lenA) 
           b=strTmp+b; 
       else 
           a=strTmp+a; 

       int JW=0;//进位 

       for(int i=maxLen-1;i>=0;i--) 
       { 
           int tempA=Integer.parseInt(String.valueOf(a.charAt(i))); 
           int tempB=Integer.parseInt(String.valueOf(b.charAt(i))); 
           int temp; 
		   
           if(tempA+tempB+JW>=10 && i!=0) 
           { 
              temp=tempA+tempB+JW-10; 
              JW=1; 
           } //end if
           else 
           { 
              temp=tempA+tempB+JW; 
              JW=0; 
           } //end else 

           str=String.valueOf(temp)+str; 
       }//end for

       return str; 
} //doAdd()

//-------------------------------------------------------
//判断字符串是否为数字
private boolean isNumber(String str){
   for(int i=0;i<str.length();i++){
      char temp=str.charAt(i);
	  if( !('0'<=temp<='9'))
	     return false;
   }//end for
   
   return true;
}//end isNumber()


题2(华为):请使用代码计算: 1234567891011121314151617181920*2019181716151413121110987654321

2 JAVA BigDecimal
2.1 基本使用
//---------------------------------------------------------------------------------
BigDecimal bd1=new BigDecimal("456");
BigDecimal bd2=new BigDecimal("123");

BigDecimal add=bd1.add(bd2);             //加
BigDecimal subtract=bd1.subtract(bd2);  // 减
BigDecimal multiply=bd1.multiply(bd2); //乘
BigDecimal divide=bd1.divide(bd2);     //除
BigDecimal powerValue=bd2.pow(2);     //指数运算, 2 is exponent

multiply.setScale(1, RoundingMode.HALF_EVEN);
System.out.println(multiply.toString());
//---------------------------------------------------------------------------------
2.2 使用注意事项
(1)BigInteger和BigDecimal都是不可变(immutable)的,在进行每一步运算时,都会产生一个新的对象,由于创建对象会引起开销,它们不适合于大量的数学计算,应尽量用long,float,double等基本类型做科学计算或者工程计算。
设计BigInteger和BigDecimal的目的是用来精确地表示大整数和小数,使用于在商业计算中使用,例如进行金额等比较敏感的数据运算。
(2)BigDecimal有4个够造方法,其中的两个用BigInteger构造,另一个是用double构造,还有一个使用String构造。
应该避免使用double构造BigDecimal,因为:有些数字用double根本无法精确表示,传给BigDecimal构造方法时就已经不精确了。
比如,new BigDecimal(0.1)得到的值是0.1000000000000000055511151231257827021181583404541015625。
使用new BigDecimal("0.1")得到的值是0.1。因此,如果需要精确计算,用String构造BigDecimal,避免用double构造,尽管它看起来更简单!
(3)equals()方法认为0.1和0.1是相等的,返回true,而认为0.10和0.1是不等的,结果返回false。
方法compareTo()则认为0.1与0.1相等,0.10与0.1也相等。所以在从数值上比较两个BigDecimal值时,应该使用compareTo()而不是 equals()。
(4)另外还有一些情形,任意精度的小数运算仍不能表示精确结果。例如,1除以9会产生无限循环的小数 .111111...。
 出于这个原因,在进行除法运算时,BigDecimal可以让您显式地控制舍入。
2.3 异常处理:ArithmeticException异常
在使用BigDecimal数据类型进行计算时,会有三种情况抛出ArithmeticException,分别是:
1)当除数为0时,这种情况比较常见,所以我们在进行除法运算之前先判断下除数是否为0;
2)如果运算的结果是无线循环的小数,并且在除的时候没有对结果设置精确的位数;
BigDecimal divide方法结果为无限小数问题  10/3=3.3333333333333333.............. 
public static void main(String[] args) {
BigDecimal a = new BigDecimal("10");
BigDecimal o = new BigDecimal("3");
System.out.print(a.divide(o,2, BigDecimal.ROUND_DOWN).doubleValue());
}
Note:不设置精度范围会出现异常
3)当我们设置了结果的舍入模式是:ROUND_UNNECESSARY模式时,如果确保了计算的结果是精确的,则不会抛出异常,否则,就会抛出ArithmeticException异常!
4)只设置精度(小数点后面的位数,scale),但没有设置舍入模式(roundingModel)时,会不知道如何对小数舍入而报错。
所以在设置精度时要连舍入模式一起设置。
 //wrong code
 bd = new BigDecimal(1.5); // is actually 1.4999....
 bd.setScale(1); // throws ArithmeticException
 //wright code
 a = new BigDecimal("2.5"); // digit left of 5 is even, so round down
 b = new BigDecimal("1.5"); // digit left of 5 is odd, so round up
 a.setScale(0, BigDecimal.ROUND_HALF_EVEN).toString() // => 2
 b.setScale(0, BigDecimal.ROUND_HALF_EVEN).toString() // => 2
 5)指数运算,指数(exponent为负数时)
 If you are raising things to negative exponents, you must specify a MathContext in BigDecimal.pow(int, MathContext) so it knows how much precision to use -- otherwise, BigDecimal will try to compute it to infinite precision, which is not possible for some values.
 //wrong code
 BigDecimal powerValue=bd2.pow(-27);// -27 is exponent


你可能感兴趣的:(用字符串解决大数问题)