JavaCard 平台大数数制转换的设计与实现
- 格式:pdf
- 大小:169.18 KB
- 文档页数:6
java大数除法的简单实现-回复Java大数除法的简单实现在Java中,有时候我们需要进行大数的除法运算,也就是针对超过了常规整数范围的数字进行除法运算。
本文将一步一步回答如何实现Java中的大数除法。
1. 大数的表示方式在Java中,常规整数类型(如int、long)的范围是有限的,所以无法处理超过它们范围的大数。
为了表示大数,可以使用字符串(String)的方式来存储大数,并针对字符串进行运算操作。
2. 字符串的转换首先,我们需要将输入的大数转换为字符串的形式进行操作。
可以使用Java中的BigInteger类来实现该转换,如下所示:javaimport java.math.BigInteger;public class Main {public static void main(String[] args) {BigInteger num1 = newBigInteger("123456789012345678901234567890");BigInteger num2 = new BigInteger("12345");BigInteger result = num1.divide(num2);System.out.println("Result: " + result);}}在上述示例中,我们使用BigInteger类来表示两个大数,然后调用divide 方法进行大数除法运算,并将结果打印输出。
3. 手动实现大数除法除了使用BigInteger类,我们也可以手动实现大数的除法运算。
以下是一个简单的实现示例:javapublic class Main {public static String divide(String dividend, String divisor) { if (divisor.equals("0")) {throw new ArithmeticException("Division by zero");}StringBuilder quotient = new StringBuilder();int idx = 0;long currDividend =Long.parseLong(String.valueOf(dividend.charAt(idx++)));while (idx <= dividend.length()) {quotient.append(currDividend /Long.parseLong(divisor));currDividend = (currDividendLong.parseLong(divisor)) * 10;if (idx < dividend.length()) {currDividend +=Long.parseLong(String.valueOf(dividend.charAt(idx++)));}}return quotient.toString();}public static void main(String[] args) {String dividend = "123456789012345678901234567890";String divisor = "12345";String result = divide(dividend, divisor);System.out.println("Result: " + result);}}在上述示例中,我们通过一个divide方法来实现大数的除法运算。
Java 数字转科学计数法在实际开发过程中,我们经常会遇到处理大量数据的情况,而这些数据往往会以科学计数法的形式出现。
在 Java 中,我们要学会如何将数字转换为科学计数法表示,以便更好地处理这些数据。
我们需要了解什么是科学计数法。
科学计数法是一种用来表示非常大或非常小的数字的方法,它包括两部分:一个基数和一个指数。
基数通常是一个在1和10之间的数,而指数是10的整数次幂。
1.23 × 10^4 和4.56 × 10^-6 都是科学计数法表示的数字。
接下来,我们将讨论如何在 Java 中实现将数字转换为科学计数法表示的方法。
1. 使用 String.format 方法Java 中的 String.format 方法可以方便地将一个数字转换为科学计数法表示。
```javadouble number = xxx;String scientificNotation = String.format(".2e", number);```在这个例子中,我们将 xxx 转换为科学计数法,并且限制小数位数为2。
结果将会是 "1.23e+08"。
2. 使用 DecimalFormat 类另一种方法是使用 DecimalFormat 类来格式化数字为科学计数法。
```javadouble number = xxx;DecimalFormat df = new DecimalFormat("0.00E0");String scientificNotation = df.format(number);```在这个例子中,我们同样将 xxx 转换为科学计数法,并且限制小数位数为2。
结果同样为 "1.23E8"。
3. 自定义方法如果我们需要更加灵活地控制科学计数法的格式,可以通过自定义方法来实现。
```javapublic static String convertToScientificNotation(double number, int decimalPlaces) {double exponent =Math.floor(Math.log10(Math.abs(number)));double mantissa = number / Math.pow(10, exponent);return String.format("." + decimalPlaces + "fE+03.0f", mantissa, exponent);}```在这个例子中,我们自定义了一个 convertToScientificNotation 方法,可以传入数字和小数位数,返回对应的科学计数法表示。
java实现超⼤整数加减乘除四则运算原理:⽤数组存储数字,按照计算法则进⾏运算。
代码:package com.hdwang;import java.util.regex.Matcher;import java.util.regex.Pattern;/*** ⼤数四则运算(超出long型的⼤数(64位:18446744073709551615))* Created by hdwang on 2017/10/9.*/public class Calculator {/*** 两数相加* @param numStr1 数1* @param numStr2 数2* @return结果*/public static String add(String numStr1, String numStr2){int numLen1 = numStr1.length();int numLen2 = numStr2.length();int[] numArray1 = new int[numLen1]; //数字数组int[] numArray2 = new int[numLen2];// "12345"-> [5,4,3,2,1]for(int i=0;i<numLen1;i++){String c = numStr1.substring(i,i+1);numArray1[numLen1-i-1] = Integer.parseInt(c); //低位存字符串尾部数字}for(int i=0;i<numLen2;i++){String c = numStr2.substring(i,i+1);numArray2[numLen2-i-1] = Integer.parseInt(c); //低位存字符串尾部数字}int minLen = 0; //取长度⼩的数位数int maxLen = 0; //取长度⼤的数位数int[] maxArray = null; //长度⼤的数if(numLen1<numLen2){minLen = numLen1;maxLen = numLen2;maxArray = numArray2;}else{minLen = numLen2;maxLen = numLen1;maxArray = numArray1;}int[] resultArray = new int[maxLen+1]; //考虑到可能会进位,多给⼀个元素空间//两数长度相同的部分,同位相加,超出9进1int added = 0;int i=0;for(;i<minLen;i++){int t = numArray1[i]+numArray2[i]+added; //两数相加,再加进位if(t>9){added = 1; //进1resultArray[i] = t-10; //当前位计算结果}else{added = 0; //不进位resultArray[i] = t; //当前位计算结果}}//长度超出部分累加for(;i<maxLen;i++){int t = maxArray[i]+added; //多余位数加上进位if(t>9){added = 1; //进1resultArray[i] = t-10; //当前位计算结果}else{added = 0; //不进位resultArray[i] = t; //当前位计算结果}}resultArray[i] = added; //最⾼位//拼接结果 [1,4,8,2,0] -> 2841StringBuilder builder = new StringBuilder();for(int n=resultArray.length-1;n>=0;n--){//如果最⾼位为0,移除if(n==resultArray.length-1 && resultArray[resultArray.length-1]==0){continue; //跳过}else{builder.append(resultArray[n]);}}return builder.toString();}/*** 两数相减* @param numStr1 数1* @param numStr2 数2* @return结果*/public static String subtract(String numStr1,String numStr2){int numLen1 = numStr1.length();int numLen2 = numStr2.length();int[] numArray1 = new int[numLen1]; //数字数组int[] numArray2 = new int[numLen2];// "12345"-> [5,4,3,2,1]for(int i=0;i<numLen1;i++){String c = numStr1.substring(i,i+1);numArray1[numLen1-i-1] = Integer.parseInt(c); //低位存字符串尾部数字}for(int i=0;i<numLen2;i++){String c = numStr2.substring(i,i+1);numArray2[numLen2-i-1] = Integer.parseInt(c); //低位存字符串尾部数字}int minLen = 0; //取长度⼩的数位数int maxLen = 0; //取长度⼤的数位数int[] maxArray = null; //数值⼤的数if(numLen1<numLen2){minLen = numLen1;maxLen = numLen2;maxArray = numArray2;}else{minLen = numLen2;maxLen = numLen1;maxArray = numArray1;if(numLen1 == numLen2){ //等于maxArray = getMaxNumber(numArray1,numArray2);}}int[] minArray = maxArray==numArray1?numArray2:numArray1; //数值⼩的数int[] resultArray = new int[maxLen];//⼤数-⼩数,同位相减,⼩于0借位int subtracted = 0;int i=0;for(;i<minLen;i++){int t = maxArray[i] - minArray[i] - subtracted; //两数相减,再减借位if(t<0){subtracted = 1; //向⾼位借1,暂存起来resultArray[i] = t+10; //当前位计算结果(借1相当于借了10)}else{subtracted = 0; //不借位resultArray[i] = t; //当前位计算结果}}//⼤数超出部分减掉借位for(;i<maxLen;i++){int t = maxArray[i]-subtracted; //多余位数减掉借位if(t<0){subtracted = 1; //进1resultArray[i] = t+10; //当前位计算结果}else{subtracted = 0; //不借位resultArray[i] = t; //当前位计算结果}}//拼接结果 [1,4,8,2,0] -> 2841StringBuilder builder = new StringBuilder();boolean highBitNotEqualZero = false; //存在⾼位不为0的情况,低位0保留for(int n=resultArray.length-1;n>=0;n--){//如果⾼位为0,移除if(resultArray[n]==0 && !highBitNotEqualZero && n!=0){ //⾼位⽆⽤的0去除continue; //跳过}else{highBitNotEqualZero = true; //找到不为0的位builder.append(resultArray[n]);}}if(maxArray == numArray1){ //第⼀个数⼤或相等}else{ //第⼀个数⼩于第⼆个数,相减为负数builder.insert(0,"-");}return builder.toString();}/*** 两数相乘* @param numStr1 数1* @param numStr2 数2* @return结果*/public static String multiply(String numStr1,String numStr2){int numLen1 = numStr1.length();int numLen2 = numStr2.length();int[] numArray1 = new int[numLen1]; //数字数组int[] numArray2 = new int[numLen2];// "12345"-> [5,4,3,2,1]for(int i=0;i<numLen1;i++){String c = numStr1.substring(i,i+1);numArray1[numLen1-i-1] = Integer.parseInt(c); //低位存字符串尾部数字for(int i=0;i<numLen2;i++){String c = numStr2.substring(i,i+1);numArray2[numLen2-i-1] = Integer.parseInt(c); //低位存字符串尾部数字}int minLen = 0; //取长度⼩的数位数int maxLen = 0; //取长度⼤的数位数int[] maxArray = null; //长度⼤的数int[] minArray = null; //长度⼩的数if(numLen1<numLen2){minLen = numLen1;maxLen = numLen2;minArray = numArray1;maxArray = numArray2;}else{minLen = numLen2;maxLen = numLen1;minArray = numArray2;maxArray = numArray1;}//⼆维数组存储结果,例如:23*23 ->[[6,9],[4,6]] ,内部括号(低维)存某位的相乘结果,⾼维低位存个位,⼗位...int[][] resultArray = new int[minLen][maxLen+1];//长度⼤的数*长度⼩的数的每⼀位,分别存到相应数组中,然后累加for(int h=0;h<minLen;h++){ //⾼维int l=0;int added = 0;for(;l<maxLen;l++){ //低维int t = maxArray[l]*minArray[h]+added; //长度⼤的数的每⼀位*长度⼩的数的个位、⼗位...if(t>9){added = t/10; //进位resultArray[h][l] = t%10; //当前位计算结果}else{added = 0; //不进位resultArray[h][l] = t; //当前位计算结果}}resultArray[h][l] = added; //个位、⼗位...的计算结果的最⾼位}//对结果补位(左移),个位不动,⼗位补0,百位补00...,然后累加int[] sum = null; //最终累加结果int[] lowBitResult = null; //低位补0结果(前⼀位)for(int h=0;h<minLen;h++){int[] bitResult = resultArray[h];int[] r; //个位、⼗位...的补0结果if(h==0){ //个位r = bitResult;sum = r;lowBitResult = r; //记录下来,待下次循环累加}else{ //⼗位...的计算结果r = new int[resultArray[h].length+h]; //初始化默认就是0的int rLen = r.length-1;for(int i=bitResult.length-1;i>=0;i--){ //从⾼位开始复制到新数组r[rLen--] = bitResult[i];}//累加之前的数sum = new int[r.length+1]; //取⾼位长度+1,可能进位//================加法核⼼算法====================//两数长度相同的部分,同位相加,超出9进1int added = 0;int i=0;for(;i<lowBitResult.length;i++){int t = lowBitResult[i]+r[i]+added; //两数相加,再加进位if(t>9){added = 1; //进1sum[i] = t-10; //当前位计算结果}else{added = 0; //不进位sum[i] = t; //当前位计算结果}}//长度超出部分累加for(;i<r.length;i++){int t = r[i]+added; //多余位数加上进位if(t>9){added = 1; //进1sum[i] = t-10; //当前位计算结果}else{added = 0; //不进位sum[i] = t; //当前位计算结果}}sum[i] = added; //最⾼位//===============================================lowBitResult = sum; //记录下来,待下次循环累加}}//拼接结果 [1,4,8,2,0] -> 2841StringBuilder builder = new StringBuilder();boolean existHighNotZero = false; //⾼位存在不为0的,这个0就不能移除for(int n=sum.length-1;n>=0;n--){//移除⾼位⽆效的0,保留最后⼀个0if(sum[n]==0 && !existHighNotZero && n!=0){continue; //跳过}else{existHighNotZero = true;builder.append(sum[n]);}}return builder.toString();/*** 两数相除* @param numStr1 数1(被除数)* @param numStr2 数2(除数,不能超过long型)* @return结果*/public static String divide(String numStr1,String numStr2){int numLen1 = numStr1.length();int numLen2 = numStr2.length();int[] numArray1 = new int[numLen1]; //数字数组int[] numArray2 = new int[numLen2];// "12345"-> [5,4,3,2,1]for(int i=0;i<numLen1;i++){String c = numStr1.substring(i,i+1);numArray1[numLen1-i-1] = Integer.parseInt(c); //低位存字符串尾部数字}for(int i=0;i<numLen2;i++){String c = numStr2.substring(i,i+1);numArray2[numLen2-i-1] = Integer.parseInt(c); //低位存字符串尾部数字}int effectiveNum = (numLen1 >= numLen2 ? numLen1:numLen2)+16; //有效位数: 默认⼤数长度+16int[] resultArray = new int[effectiveNum]; //⾼位存⾼位//将被除数的每⼀位除以除数,取整为该位结果,取余暂存借给低位(除数不能⼤过long型,除⾮除法转换为减法) long yu = 0;int resultIndex = effectiveNum-1;for(int i=numArray1.length-1;i>=0;i--){long num = yu * 10 + numArray1[i]; //被除数该位为:余数*10+⾃⼰int r= (int)(num / Long.parseLong(numStr2)); //取整yu = num % Long.parseLong(numStr2); //取余resultArray[resultIndex--] = r;}int decimalPoint = effectiveNum-numArray1.length-1; //⼩数点位置if(yu!=0){int decimal = decimalPoint; //⼩数for(int i=0;i<effectiveNum-numArray1.length;i++){long num = yu * 10 + 0; //⼩数部分被除数补0int r= (int)(num / Long.parseLong(numStr2)); //取整yu = num % Long.parseLong(numStr2); //取余resultArray[decimal--] = r;if(yu==0){break; //余数为0,提前退出}}}//拼接结果StringBuilder builder = new StringBuilder();boolean existHighNotZero = false;for(int i=effectiveNum-1;i>=0;i--){if(i==decimalPoint){builder.append(".");}if(resultArray[i]==0){if(!existHighNotZero && i>decimalPoint+1){ //跳过⾼位⽆⽤的0continue;}}else{existHighNotZero = true;}builder.append(resultArray[i]);}String result = builder.toString();//去除尾部⽆⽤的0int endIndex = result.length();for(int i=result.length()-1;i>=0;i--){char c = result.charAt(i);if(c!='0'){endIndex = i+1;break;}}//去除多余的⼩数点if(result.charAt(endIndex-1)=='.'){endIndex = endIndex-1;}result = result.substring(0,endIndex);return result;}/*** 两数相除(增强版)* @param numStr1 数1(被除数)* @param numStr2 数2(除数)* @return结果*/public static String divideEnhanced(String numStr1,String numStr2){int numLen1 = numStr1.length();int numLen2 = numStr2.length();int[] numArray1 = new int[numLen1]; //数字数组int[] numArray2 = new int[numLen2];// "12345"-> [5,4,3,2,1]for(int i=0;i<numLen1;i++){String c = numStr1.substring(i,i+1);numArray1[numLen1-i-1] = Integer.parseInt(c); //低位存字符串尾部数字}for(int i=0;i<numLen2;i++){String c = numStr2.substring(i,i+1);numArray2[numLen2-i-1] = Integer.parseInt(c); //低位存字符串尾部数字}int effectiveNum = (numLen1 >= numLen2 ? numLen1:numLen2)+16; //有效位数: 默认⼤数长度+16int[] resultArray = new int[effectiveNum]; //⾼位存⾼位//将被除数的每⼀位除以除数,取整为该位结果,取余暂存借给低位(除数不能⼤过long型,除⾮除法转换为减法) String yu = "0";int resultIndex = effectiveNum-1;for(int i=numArray1.length-1;i>=0;i--){String num = "0".equals(yu)?numArray1[i]+"":add(yu+"0",numArray1[i]+""); //被除数该位为:余数*10+⾃⼰ DivideResult result = getDivideResult(num,numStr2);String r= result.getR() ; //取整yu = result.getYu(); //取余resultArray[resultIndex--] = Integer.parseInt(r); //某位上的结果肯定⼩于10}int decimalPoint = effectiveNum-numArray1.length-1; //⼩数点位置if(!"0".equals(yu)){int decimal = decimalPoint; //⼩数for(int i=0;i<effectiveNum-numArray1.length;i++){String num = yu+"0"; //⼩数部分被除数补0DivideResult result = getDivideResult(num,numStr2);String r= result.getR() ; //取整yu = result.getYu(); //取余resultArray[decimal--] = Integer.parseInt(r);if("0".equals(yu)){break; //余数为0,提前退出}}}//拼接结果StringBuilder builder = new StringBuilder();boolean existHighNotZero = false;for(int i=effectiveNum-1;i>=0;i--){if(i==decimalPoint){builder.append(".");}if(resultArray[i]==0){if(!existHighNotZero && i>decimalPoint+1){ //跳过⾼位⽆⽤的0continue;}}else{existHighNotZero = true;}builder.append(resultArray[i]);}String result = builder.toString();//去除尾部⽆⽤的0int endIndex = result.length();for(int i=result.length()-1;i>=0;i--){char c = result.charAt(i);if(c!='0'){endIndex = i+1;break;}}//去除多余的⼩数点if(result.charAt(endIndex-1)=='.'){endIndex = endIndex-1;}result = result.substring(0,endIndex);return result;}/*** 校验数字是否合法* @param numStr 数字字符串* @return是否合法*/public static boolean numberValid(String numStr){Pattern pattern = pile("^[1-9]\\d*$|0");Matcher matcher = pattern.matcher(numStr);return matcher.matches();}/*** 计算⼤数* @param numArray1 数1* @param numArray2 数2* @return⼤数*/public static int[] getMaxNumber(int[] numArray1, int[] numArray2) {for(int i=numArray1.length-1;i>=0;i--){if(numArray1[i]>numArray2[i]){return numArray1;}else{if(numArray1[i]==numArray2[i]){continue; //待继续⽐较}else{return numArray2;}}}return numArray1; //全部相等,返回第⼀个}/*** 除法转换为减法* @param numStr1 数1(被除数)* @param numStr2 数2(除数)* @return除的结果*/public static DivideResult getDivideResult(String numStr1,String numStr2){DivideResult result = new DivideResult();String r = "";// String times = "0";int times = 0; //取整不会⼤于9的(被除数(余数+某位)/除数(肯定⼤于余数)这个过程是,被除数逐渐增⼤到可以除以除数为⽌,此时被除数>=除数,刚刚好,所以被除数最多⽐除数多1位,两数相差肯定⼩于10倍)while (true){r=subtract(numStr1,numStr2);// times = add(times,"1"); //次数递增times++;if("0".equals(r)){ //除尽了result.setYu("0");result.setR(times+"");break;}else if(r.startsWith("-")){ //负数,多减了⼀次result.setYu(numStr1); //上次减下来多余的数值,就是余数// result.setR(subtract(times,"1"));result.setR((times-1)+"");break;}numStr1 = r; //被减数重置为剩余的数值}return result;}}package com.hdwang;/*** Created by hdwang on 2017/10/10.* 相除结果*/public class DivideResult {/*** 取整结果*/private String r;/*** 取余结果*/private String yu;public String getR() {return r;}public void setR(String r) {this.r = r;}public String getYu() {return yu;}public void setYu(String yu) {this.yu = yu;}}package com.hdwang;import java.util.Scanner;import static com.hdwang.Calculator.*;public class Main {public static void main(String[] args) {// write your code hereScanner scanner = new Scanner(System.in);boolean loop = true;while (loop) {System.out.println("请输⼊第⼀个⾮负整数:");String numStr1 = scanner.nextLine();if (!numberValid(numStr1)) {System.out.println(String.format("%s不合法", numStr1));continue;}System.out.println("请输⼊第⼆个⾮负整数:");String numStr2 = scanner.nextLine();if (!numberValid(numStr2)) {System.out.println(String.format("%s不合法", numStr2));continue;}String r1 = add(numStr1, numStr2);System.out.println(String.format("⼤数加法计算:%s+%s%s=%s", numStr1, numStr2,r1.length()>50?"\n":"", r1));try {System.out.println("加法直接计算:" + (Long.parseLong(numStr1) + Long.parseLong(numStr2)));}catch (Exception ex){System.out.println("加法直接计算:"+ex.getClass().getName());}String r2 = subtract(numStr1, numStr2);System.out.println(String.format("⼤数减法计算:%s-%s%s=%s", numStr1, numStr2,r2.length()>50?"\n":"", r2));try {System.out.println("减法直接计算:" + (Long.parseLong(numStr1) - Long.parseLong(numStr2)));}catch (Exception ex){System.out.println("减法直接计算:"+ex.getClass().getName());}String r3 = multiply(numStr1, numStr2);System.out.println(String.format("⼤数乘法计算:%s*%s%s=%s", numStr1, numStr2,r3.length()>50?"\n":"", r3));try {System.out.println("乘法直接计算:" + (Long.parseLong(numStr1) * Long.parseLong(numStr2)));}catch (Exception ex){System.out.println("乘法直接计算:"+ex.getClass().getName());}try {String r4 = divide(numStr1, numStr2);System.out.println(String.format("⼤数除法计算:%s/%s%s=%s", numStr1, numStr2, r4.length() > 50 ? "\n" : "", r4)); }catch (Exception ex){System.out.println("⼤数除法计算:"+ex.getClass().getName());}try {System.out.println("除法直接计算:" + ((double)Long.parseLong(numStr1) / (double) Long.parseLong(numStr2)));}catch (Exception ex){System.out.println("除法直接计算:"+ex.getClass().getName());}String r5 = divideEnhanced(numStr1, numStr2);System.out.println(String.format("增强版⼤数除法计算:%s/%s%s=%s", numStr1, numStr2,r5.length()>50?"\n":"", r5)); System.out.println("退出输⼊q,否则继续");String line = scanner.nextLine();if(line.equalsIgnoreCase("Q")){loop = false;}else{loop = true;}}}}运⾏结果:请输⼊第⼀个⾮负整数:1请输⼊第⼆个⾮负整数:1⼤数加法计算:1+1=2加法直接计算:2⼤数减法计算:1-1=0减法直接计算:0⼤数乘法计算:1*1=1乘法直接计算:1⼤数除法计算:1/1=1除法直接计算:1.0增强版⼤数除法计算:1/1=1退出输⼊q,否则继续请输⼊第⼀个⾮负整数:2请输⼊第⼆个⾮负整数:3⼤数加法计算:2+3=5加法直接计算:5⼤数减法计算:2-3=-1减法直接计算:-1⼤数乘法计算:2*3=6乘法直接计算:6⼤数除法计算:2/3=0.6666666666666666除法直接计算:0.6666666666666666增强版⼤数除法计算:2/3=0.6666666666666666退出输⼊q,否则继续请输⼊第⼀个⾮负整数:25请输⼊第⼆个⾮负整数:25⼤数加法计算:25+25=50加法直接计算:50⼤数减法计算:25-25=0减法直接计算:0⼤数乘法计算:25*25=625乘法直接计算:625⼤数除法计算:25/25=1除法直接计算:1.0增强版⼤数除法计算:25/25=1退出输⼊q,否则继续请输⼊第⼀个⾮负整数:100请输⼊第⼆个⾮负整数:50⼤数加法计算:100+50=150加法直接计算:150⼤数减法计算:100-50=50减法直接计算:50⼤数乘法计算:100*50=5000乘法直接计算:5000⼤数除法计算:100/50=2除法直接计算:2.0增强版⼤数除法计算:100/50=2退出输⼊q,否则继续请输⼊第⼀个⾮负整数:3请输⼊第⼆个⾮负整数:4⼤数加法计算:3+4=7加法直接计算:7⼤数减法计算:3-4=-1减法直接计算:-1⼤数乘法计算:3*4=12乘法直接计算:12⼤数除法计算:3/4=0.75除法直接计算:0.75增强版⼤数除法计算:3/4=0.75退出输⼊q,否则继续请输⼊第⼀个⾮负整数:4请输⼊第⼆个⾮负整数:3⼤数加法计算:4+3=7加法直接计算:7⼤数减法计算:4-3=1减法直接计算:1⼤数乘法计算:4*3=12乘法直接计算:12⼤数除法计算:4/3=1.3333333333333333除法直接计算:1.3333333333333333增强版⼤数除法计算:4/3=1.3333333333333333退出输⼊q,否则继续请输⼊第⼀个⾮负整数:1请输⼊第⼆个⾮负整数:100⼤数加法计算:1+100=101加法直接计算:101⼤数减法计算:1-100=-99减法直接计算:-99⼤数乘法计算:1*100=100乘法直接计算:100⼤数除法计算:1/100=0.01除法直接计算:0.01增强版⼤数除法计算:1/100=0.01退出输⼊q,否则继续请输⼊第⼀个⾮负整数:100请输⼊第⼆个⾮负整数:1⼤数加法计算:100+1=101加法直接计算:101⼤数减法计算:100-1=99减法直接计算:99⼤数乘法计算:100*1=100乘法直接计算:100⼤数除法计算:100/1=100除法直接计算:100.0增强版⼤数除法计算:100/1=100退出输⼊q,否则继续请输⼊第⼀个⾮负整数:1请输⼊第⼆个⾮负整数:10000000000⼤数加法计算:1+10000000000=10000000001加法直接计算:10000000001⼤数减法计算:1-10000000000=-9999999999减法直接计算:-9999999999⼤数乘法计算:1*10000000000=10000000000乘法直接计算:10000000000⼤数除法计算:1/10000000000=0.0000000001除法直接计算:1.0E-10增强版⼤数除法计算:1/10000000000=0.0000000001退出输⼊q,否则继续请输⼊第⼀个⾮负整数:1请输⼊第⼆个⾮负整数:100000000000000000000000000000000000000000000000000⼤数加法计算:1+100000000000000000000000000000000000000000000000000=100000000000000000000000000000000000000000000000001加法直接计算:ng.NumberFormatException⼤数减法计算:1-100000000000000000000000000000000000000000000000000=-99999999999999999999999999999999999999999999999999减法直接计算:ng.NumberFormatException⼤数乘法计算:1*100000000000000000000000000000000000000000000000000=100000000000000000000000000000000000000000000000000乘法直接计算:ng.NumberFormatException⼤数除法计算:ng.NumberFormatException除法直接计算:ng.NumberFormatException增强版⼤数除法计算:1/100000000000000000000000000000000000000000000000000=0.00000000000000000000000000000000000000000000000001退出输⼊q,否则继续说明:当数字的⼤⼩超过long类型的数值范围时,将⽆法对数值进⾏计算,所以必须实现⼀套算法。
标题:Java中的数字转中文大写金额方法目录:(可根据实际内容进行排版)1. 介绍2. 实现思路3. 代码示例4. 应用场景5. 总结1. 介绍在实际开发中,有时候我们需要将数字金额转换为中文大写金额,如将123456转换为“壹拾贰万叁仟肆佰伍拾陆元整”。
本文将介绍如何使用Java来实现数字转中文大写金额的方法。
2. 实现思路实现数字转中文大写金额的方法主要涉及数字的分段处理和中文数字的映射。
对于一个给定的数字,我们首先需要将其进行分段,然后对每个段进行中文数字的映射,最后将各个段拼接起来。
具体实现思路如下:- 将输入的数字按照万、千、百、十、个位进行分段处理。
如123456分成12、345、6三个段。
- 对于每个段,逐个数字进行中文数字的映射。
如123转为“壹佰贰拾叁”。
- 最终将各个段拼接起来,加上相应的“亿”、“万”、“元”等单位,得到最终的中文大写金额。
3. 代码示例下面是一个简单的Java代码示例,用于将数字金额转换为中文大写金额:```public class NumberToChinese {// 中文数字private static final String[] CHINESE_NUMBERS = {"零", "壹", "贰", "叁", "肆", "伍", "陆", "柒", "捌", "玖"};// 中文金额单位private static final String[] CHINESE_UNIT = {"", "拾", "佰", "仟", "万", "亿"};// 中文金额段落private static final String[] CHINESE_SECTION = {"", "万", "亿"};public static String toChineseAmount(double amount) {// 将金额转换为字符串形式String amountStr = String.valueOf(amount);// 分割整数和小数部分String[] parts = amountStr.split("\\.");int integerPart = Integer.parseInt(parts[0]);int decimalPart = Integer.parseInt(parts[1]);// 转换整数部分String integerChinese = toChineseInteger(integerPart); // 转换小数部分String decimalChinese = toChineseDecimal(decimalPart); return integerChinese + "元" + decimalChinese;}private static String toChineseInteger(int number) {StringBuilder sb = new StringBuilder();int section = 0;// 处理每个数字段while (number > 0) {int num = number 10000;if (num != 0) {sb.insert(0, CHINESE_SECTION[section]);StringBuilder sectionStr = new StringBuilder();// 处理每个数字段内的数字for (int i = 0; i < 4; i++) {int digit = num 10;if (digit != 0) {sectionStr.insert(0, CHINESE_NUMBERS[digit] +CHINESE_UNIT[i]);} else {if (sectionStr.length() > 0 sectionStr.charAt(0) != '零') {sectionStr.insert(0, "零");}}num /= 10;}sb.insert(0, sectionStr);} else {if (sb.length() > 0 sb.charAt(0) != '零') {sb.insert(0, "零");}}number /= 10000;section++;}if (sb.length() == 0) {sb.append("零");}return sb.toString();}private static String toChineseDecimal(int number) {StringBuilder sb = new StringBuilder();if (number == 0) {sb.append("整");} else {int digit1 = number / 10;int digit2 = number 10;if (digit1 != 0) {sb.append(CHINESE_NUMBERS[digit1] + "角");}if (digit2 != 0) {sb.append(CHINESE_NUMBERS[digit2] + "分");}}return sb.toString();}}```4. 应用场景数字转中文大写金额的方法通常用于财务软件、发票打印等场景中。
java bigdecimal数字转中文大写方法-概述说明以及解释1.引言1.1 概述在日常开发中,我们经常会遇到需要将数字转换为中文大写的场景,例如在金融系统中涉及金额的显示。
而在Java中,我们可以利用BigDecimal类来处理精确的数字计算,并结合自定义方法将数字转换为中文大写形式。
本文将介绍如何利用Java中的BigDecimal类以及自定义方法,实现数字转换为中文大写的功能。
我们将详细解释BigDecimal类的简介,以及如何编写一个方法将数字转换为中文大写形式,通过示例代码演示来帮助读者更好地理解和掌握这一技术。
最后,我们将总结本文的内容,探讨该方法的应用推广以及展望未来在该领域的发展。
通过本文的阅读,读者将能够更深入地了解并掌握将数字转换为中文大写的方法。
1.2文章结构1.2 文章结构本文主要分为引言、正文和结论三个部分。
在引言部分,我们将对Java BigDecimal类进行简要介绍,然后明确本文的目的和文章结构。
接着,我们将在正文部分详细解释如何使用Java BigDecimal类中的方法将数字转换为中文大写形式。
具体包括BigDecimal数字转中文大写的方法和示例代码演示。
在结论部分,我们将对本文的内容进行总结,探讨该方法在实际应用中的推广价值,并展望未来的发展方向。
通过本文的阐述,读者将对Java 中BigDecimal数字转中文大写的方法有一个清晰的认识,从而更好地应用于实际项目中。
1.3 目的本文旨在介绍如何使用Java BigDecimal类将数字转换为中文大写的方法。
通过详细的讲解和示例代码演示,读者能够了解这一转换过程的具体步骤和实现方式。
希望读者能够通过本文掌握如何利用Java编程语言中的BigDecimal类来实现数字转中文大写的功能,从而提升其在数字处理和字符串操作方面的技能。
同时,本文也旨在激发读者对Java编程的兴趣,让他们更加熟练地运用BigDecimal类进行数字处理,为日后的编程工作提供更多可能性和灵感。
JavaCard开发教程之规范多年以前,Sun微系统公司实现了智能卡和类似的资源约束设备的潜能,并且定义了一组Java技术子集规范来为它们创建应用程序,Java Card小应用程序。
支持这些规范的设备称为Java Card平台。
在一个Java Card平台上,来自不同的供应商的多个应用程序可以安全地共存。
一个典型的Java Card设备有一个8或16位的运行在3.7MHz的中央处理器,带有1K 的RAM和多于16K的非易失性存储器(可编程只读存储器或者闪存)。
高性能的智能卡带有单独的处理器和加密芯片,以及用于加密的内存,并且有一些还带有32位的中央处理器。
Java Card技术规范目前是2.2版,由三部分组成:·Java Card虚拟机规范,定义了用于智能卡的Java程序语言的一个子集和虚拟机。
·Java Card运行时环境规范,进一步定义了用于基于Java的智能卡的运行期行为。
·Java Card应用编程接口规范,定义了用于智能卡应用程序核心框架和扩展Java程序包和类。
Sun还提供了Java Card开发工具箱(JCDK) /products/javacard/,包含了Java Card运行期环境和Java Card虚拟机的引用实现,和其它帮助开发Java Card 小应用程序的工具。
本文的第二部分将详细讲述JCDK。
Java Card技术和J2ME平台让我们比较一下Java Card和J2ME平台技术:图. Java Card技术和J2ME平台CDC和CLDC配置以及它们JavaCard开发教程之程序元素完整的Java Card应用程序由一个后端应用程序和系统、一个主机(卡外)应用程序、一个接口设备(读卡器)和卡上小应用程序、用户证书和支持软件组成。
所有的这些元素共同组成一个安全的端到端应用程序:图1. Java Card应用程序的体系结构一个典型的Java Card应用程序不是孤立的,而是包含卡端、读取端和后端元素。
JAVA中常用数据类型之间转换的方法在Java中,常见的数据类型转换包括基本数据类型之间的转换、引用数据类型之间的转换以及基本数据类型与引用数据类型之间的转换。
下面将依次介绍这些转换方法。
1.基本数据类型之间的转换:- 自动类型转换:当两个数据类型不完全相同时,较小范围的数据类型可以自动转换为较大范围的数据类型。
例如,byte可以自动转换为short、int、long、float或double,而short可以自动转换为int、long、float或double。
- 强制类型转换:当两个数据类型完全不相同时,需要使用强制类型转换进行转换。
强制类型转换需要使用括号将目标类型放在待转换的表达式前面。
例如,int可以强制转换为byte,即`(byte)a`,其中a为int 变量。
2.引用数据类型之间的转换:- 向上转型:子类对象可以自动转换为父类对象,这种转换被称为向上转型。
向上转型可以提高代码的可扩展性和复用性。
例如,Animal类的子类可以被赋值给Animal类型的引用变量。
- 向下转型:父类对象可以通过强制类型转换为子类对象,这种转换被称为向下转型。
向下转型在编译时是合法的,但在运行时可能会抛出ClassCastException异常。
因此,在进行向下转型时,需要先使用instanceof运算符检查对象是否是目标类型的实例。
例如,Animal类的引用变量可以转换为Cat类型的引用变量,即`(Cat)animal`,其中animal为Animal类型的引用变量。
3.基本数据类型与引用数据类型之间的转换:- 基本数据类型转换为引用数据类型:基本数据类型可以通过包装类(如Integer、Double、Boolean等)的构造函数或valueOf(方法来转换为对应的包装类对象。
例如,int可以转换为Integer,即`Integer.valueOf(a)`,其中a为int变量。
- 引用数据类型转换为基本数据类型:引用数据类型可以通过调用包装类的xxxValue(方法来获取对应的基本数据类型值。
java card平台详解(一)java卡我想很多人不陌生,有些人已经用过,在java卡上开发applet应用,有些人开发过java卡平台,使用在sun那买的授权之后提供的demo实现,或者是将要进行相关的工作的人。
在这里我不想说一些大家很容易就能找到的资料,而是介绍一些更深层次的东西,而又没有侵犯到sun的保密性。
主要分为以下几个部分:1. java卡框架,java卡的主要组成部分2. java卡的运行机制,java卡到底是如何执行、如何工作的3. java卡的API库,如何定制自己的API库4. java卡的CAP文件加载器5. java卡的性能优化java卡框架native cos的基本架构首先我们来回顾一下以往native cos的基本架构:HAL层、通讯层、文件系统、算法、安全模块、个人化命令、应用命令等。
一般一个native cos只实现一个应用规范,也有同时实现两个或者更多应用规范的COS,COS实现规范里面定义的所有应用命令。
卡片上电之后,收到卡机发来的APDU后,通过解析APDU头的INS(还需要检查CLA、P1、P2之类)等步骤来找到该命令所对应的函数执行并返回结果。
可以简单点来说就是一个APDU指令对应于卡内的一个功能函数,对于非规范内规定的INS,卡片一般都直接返回6d00表示不支持或者无法解析的指令。
java卡特点的简单介绍java卡是个多应用智能卡平台,与native cos有本质的区别,它不是实现某个应用规范或者多个应用规范的cos,而是为cos应用开发人员提供了另外一种途径来实现应用规范。
简单的类比一下,java卡和native卡的区别就相当于PC上用C语言开发应用程序和用java 语言开发应用程序的区别。
java卡是个平台,是个应用容器,可以动态的装载不同的应用,也可以装载很多相同应用的不同实例。
java卡把native卡里面的HAL层、通讯层、文件系统、算法、安全等都封装成了API库,所以java卡上的智能卡应用开发人员和传统的native卡的开发人员相比,工作难度要降低了很多,像文件系统、掉电保护等等通通不用再设计了。
Java实现⼈民币⼤写⾦额转数字1、单位和⾦额映射。
单位数组添加的顺序需要按从⼤到⼩排序;⽀持错别字,只需要添加到列表元素Entry的值数组中;拾即是单位也是⾦额(⽐如壹拾元整,此时拾是单位;拾元整,此时拾是⾦额) /** 计量单位映射,按从⼤到⼩的顺序。
**/private static List<Entry<String, String[]>> units = new ArrayList<>();/** ⾦额数字映射。
**/private static List<Entry<String, String[]>> numbers = new ArrayList<>();static {units.add(new SimpleEntry<>("100000000", new String[] { "亿" }));units.add(new SimpleEntry<>("10000", new String[] { "万" }));units.add(new SimpleEntry<>("1000", new String[] { "仟" }));units.add(new SimpleEntry<>("100", new String[] { "佰" }));units.add(new SimpleEntry<>("10", new String[] { "拾" }));units.add(new SimpleEntry<>("1", new String[] { "圆" }));units.add(new SimpleEntry<>("0.1", new String[] { "⾓" }));units.add(new SimpleEntry<>("0.01", new String[] { "分" }));numbers.add(new SimpleEntry<>("0", new String[] { "零" }));numbers.add(new SimpleEntry<>("1", new String[] { "壹" }));numbers.add(new SimpleEntry<>("2", new String[] { "贰" }));numbers.add(new SimpleEntry<>("3", new String[] { "叁" }));numbers.add(new SimpleEntry<>("4", new String[] { "肆" }));numbers.add(new SimpleEntry<>("5", new String[] { "伍" }));numbers.add(new SimpleEntry<>("6", new String[] { "陆" }));numbers.add(new SimpleEntry<>("7", new String[] { "柒" }));numbers.add(new SimpleEntry<>("8", new String[] { "捌" }));numbers.add(new SimpleEntry<>("9", new String[] { "玖" }));numbers.add(new SimpleEntry<>("10", new String[] { "拾" }));}2、⼤写转数字。
JAVA大数处理(BigInteger,BigDecimal)Ⅰ基本函数:1.valueOf(parament); 将参数转换为制定的类型比如 int a=3;BigInteger b=BigInteger.valueOf(a);则b=3;String s=”12345”;BigInteger c=BigInteger.valueOf(s);则c=12345;2.add(); 大整数相加BigInteger a=new BigInteger(“23”); BigInteger b=new BigInteger(“34”);a. add(b);3.subtract(); 相减4.multiply(); 相乘5.divide(); 相除取整6.remainder(); 取余7.pow(); a.pow(b)=a^b8.gcd(); 最大公约数9.abs(); 绝对值10.negate(); 取反数11.mod(); a.mod(b)=a%b=a.remainder(b);12.max(); min();13.punlic int comareTo();14.boolean equals(); 是否相等15.BigInteger构造函数:一般用到以下两种:BigInteger(String val);将指定字符串转换为十进制表示形式;BigInteger(String val,int radix);将指定基数的 BigInteger 的字符串表示形式转换为 BigInteger Ⅱ.基本常量:A=BigInteger.ONE 1B=BigInteger.TEN 10C=BigInteger.ZERO 0Ⅲ.基本操作1. 读入:用Scanner类定义对象进行控制台读入,Scanner类在java.util.*包中Scanner cin=new Scanner(System.in);// 读入while(cin.hasNext()) //等同于!=EOF{int n;BigInteger m;n=cin.nextInt(); //读入一个int;m=cin.BigInteger();//读入一个BigInteger;System.out.print(m.toString());}Ⅳ.运用四则预算:import java.util.Scanner;import java.math.*;import java.text.*;public class Main{public static void main(String args[]){Scanner cin = new Scanner ( System.in ); BigInteger a,b;int c;char op;String s;while( cin.hasNext() ){a = cin.nextBigInteger();s = cin.next();op = s.charAt(0);if( op == '+'){b = cin.nextBigInteger();System.out.println(a.add(b));}else if( op == '-'){b = cin.nextBigInteger();System.out.println(a.subtract(b));}else if( op == '*'){b = cin.nextBigInteger();System.out.println(a.multiply(b));}else{BigDecimal a1,b1,eps;String s1,s2,temp;s1 = a.toString();a1 = new BigDecimal(s1);b = cin.nextBigInteger();s2 = b.toString();b1 = new BigDecimal(s2);c = cin.nextInt();eps = a1.divide(b1,c,4);//System.out.println(a + " " + b + " " + c);//System.out.println(a1.doubleValue() + " " + b1.doubleValue() + " " + c);System.out.print( a.divide(b) + " " + a.mod(b) + " ");if( c != 0){temp = "0.";for(int i = 0; i < c; i ++) temp += "0";DecimalFormat gd = new DecimalFormat(temp);System.out.println(gd.format(eps));}else System.out.println(eps);}}}}补充:a=a.pow(b);a=a.stripTrailingZeros();d=a.toPlainString();if(d.charAt(0)=='0') d=d.substring(1);。
JavaCard平台大数数制转换的设计与实现谷思庭,邓中亮北京邮电大学电子工程学院,北京(100876)Email:xingzhou120@摘 要:根据JavaCard平台应用开发的需求,本文提出了在此有限资源平台上实现十六进制大数转换成ASCII码数组的设想,并对其可行性加以论证。
最后设计并实现了这个功能,并提出了优化方案。
关键词:大数,JavaCard平台,十六进制,ASCII码1 引言大数,顾名思义就是位数很多的数字,在我们的日常生活中,经常会和大数打交道,因此JavaCard的一些应用也会和大数的使用相关。
但是JavaCard的资源非常有限,一般用于开发的卡片资源分布大约是1k左右的RAM,16k的可变存储空间(EEPROM或flash)和24-32k的ROM。
即使升级版本的芯片所能够提供的RAM、EEPROM和ROM空间上的提升依然很有限,执行单或双精度浮点运算、长整型数据计算等操作对这样一个设备来说所占用的空间将会大于其ROM的空间。
即使就算这些操作的空间够用,那么一定也没有剩余空间用于类库和程序编码的存储了。
同样,RAM的空间也是非常有限的。
因此JavaCard技术实现的一个可行的选择就是使用Java平台的一个子集[3]。
由于使用了Java平台的一个子集,因此JavaCard中将只能够支持布尔型、字节型、短整型和整型数据(更早版本的JavaCard甚至连整型都不能够支持)。
那么问题产生了,如果一个STK应用想实现一个大数计算器功能,那么该如何实现?由于对长整型数据的不支持,卡片不能够接收数据之后自己执行计算过程,因此我们可以考虑到将计算过程交给服务器来进行,而我们所要获得的是一个计算的结果,然后将它显示在手机屏幕上。
但是收到的计算结果往往都是十六进制数,而我们则需要将它转换后存储为一个ASCII码数组,这样才能显示在手机屏幕上,所以一个大数数制转换的需求就应运而生了。
同样,如果服务器下发的是一个信息数据,同样位数很多,例如一串鉴权密钥数据或是IP地址等等,同样需要进行这样一个转换处理之后才能显示,而不能直接作为字符串数组存放在显示内容中。
这篇文章就是来解决这样一个大数数制转换的问题。
2 算法分析由于我们最终需要得到的是一个ASCII码数组,因此在转换中不仅仅是得到最终的一个十进制数,而是要得到这个十进制数的每一位。
一般来说,进行这种数制转换有2种方法,其核心思想都是通过进行除法运算,只是取的结果不同而已,在这里可以形象地称之为取商转换法和取余转换法[4]。
取商转换法就是通过和数字数量级相同的转换因子相除,得到商和余数,商被取出,而余数作为被除数参与下一次的运算,用公式可以这样表示:假设一个十六进制数为ABCD (h),其对应的十进制数为abcd (d),则有:)3(1010)2(10010)1(100010123d c Y Y Y b X X X a ABCD ABCD L L L =÷=÷=÷=÷=÷=÷ 依照此方法,十进制数的每一位就被计算出来了。
另外一种取余转换法和上述方法的不同之处在于取余转换法的除数就是要转换的进制数,每次除法运算得到商和余数,余数被取出,商将作为被除数参与下一次运算,用公式表示为:依然以上面的十六进制数为例,则有:)3(10)2(10)1(10b a Y c Y X d X ABCD L L L =÷=÷=÷ 可以看到,这种方法得到的结果是十进制数各个位数的倒序,也就是先取出来的是个位数,然后依次是十位数、百位数等等。
比较上面两种算法,计算次数相同,但是参与计算的数据上相比,明显后一种方法要比前一种方法参与计算的数据量小,因此后一种方法也是目前比较常见的转换方法。
但是以上方法只能针对那些位数比较少,可以使用整形来表示的数有效,一旦需要转换的原始数据是一个大数,那么直接进行除法就是不可能的了,因此就要将方法进行重新设计和改进,除法运算还是要做,但是被除数应当被控制在可操作的数据范围内,而且数据量越小越好。
3 大数数制转换方法设计与实现由于是大数,因此也不会存储在一个变量中,通常的情况是将数据存储在一个数组里,一般这个数组的长度大于4(小于4的可以转换成一个十六进制的整型数据)。
当然对于小于4个字节的数据也可以通过以下方法进行数制转换。
此方法主要有以下几部分模块组成:半字节数据转换模块、被除数生成模块、数据计算模块和ASCII 码生成模块。
整个转换流程如图1所示:图1 转换流程图通过流程图可以看见,在这个过程中会有许多中间结果出现,这些结果在最后是不需要的,但是又是判断计算进程的重要数据,因此也需要临时存储一下,故首先要在RAM中申请一小块空间存放一个临时数组,这个数组的使用方式如图2设计:(假设需要转换的原始数据的字节数为Len)图2 临时数组设计由设计可以看出,这个临时数组的长度取决于原始数据的长度,如果原始数据的长度为Len字节,那么数组需要的总大小就为(4×Len+1)字节,因此要根据需求来对这个临时数组的大小进行初始化分配。
其中,半字节区域存储半字节转换结果,并复用为被除数数组,填充位在程序中写入固定值0x00,其余字节为余数数组,余数数组的最后一个字节为结果位,需要提取出来作为转换结果输入到ASCII码生成模块中。
¾半字节转换模块作用:分解大数,为被除数的生成做准备工作。
实现:使用循环语句,逐字节读入原始数据,并通过半字节转换将结果存储在临时数组中。
temp[2n] = (byte)((src[n] & 0xF0)>>4); //取出一个字节的高4位temp[(2n+1)] = (byte)(src[n] & 0x0F); //取出一个字节的低4位其中n=0,1,2……¾被除数生成模块作用:提供生成每次进行除法运算的被除数。
说明:这里所说的被除数和上述图中的被除数数组不是一个概念,这里所指的被除数是参与到每次实际运算中的被除数,由于被除数数组依然是个大数,不能直接参与运算,因此需要重新组合出参与运算的数据,具体方法见实现。
实现:被除数实际上就是将上一次除法运算的余数和被除数数组中的一个半字节数据组合成一个长度为一个字节的数据。
由于第一次运算时没有上一次运算的余数作为组合对象,所以这就是填充位设定的意义所在。
dividend = (short)((src[2*Len+n]<<4) + src[n]); //获取参与运算模块的被除数¾数据计算模块作用:进行数制转换计算,通过运算依次得出转换结果的每一位数。
实现:这个模块通过几个部分来实现。
首先是进行除法运算,通过上一节的算法分析,使用取余转换法更加节省资源,因此采用这种方法进行转换。
经过了前两个模块的处理,现在的被除数已经是一个短整型数据,完全可以直接使用除法运算。
我们将除得的商复写在被除数数组的相应字节,余数写在余数数组的相应字节,当进行完(2×Len)次除法运算后,余数数组的最后一个字节被填完,并且这个最后一个字节就是最终转换后的十进制数的个位。
循环上述整个过程就可以得到十位、百位、千位等等。
temp[n] = (byte)(dividend / 10); //计算商temp[(2*Len+n+1)] = (byte)(dividend % 10); //计算余数假设我们将转换结果存在一个新的数组里,并命名它为result[],那么:result[n] = temp[4*Len]; //转换结果(逆序)被除数生成模块和数据计算模块是不断循环进行的,由于不确定运算次数,因此不能常规的提供循环结束条件,只能通过每次得到十进制的一位后进行一个计算进程判断,也就是图1中的计算进程控制,我们只需要检查此时的被除数数组,当被除数数组内的数均为0的时候,意味着此次转换进程的结束。
至于判断数组为全0字节的方法有很多,这里就不再赘述了。
¾ASCII码生成模块作用:生成最终结果的ASCII码数组。
实现:通过查阅ASCII表不难看出,0~9这10个数字的ASCII码恰好是0x30~0x39这个范围,因此只要将上一步取出的运算结果和0x30相加(或者进行按位或运算)就可以得到相对应的ASCII码了。
当然在生成ASCII码前还要做的一个小工序就是将上述转换结果的顺序调整一下,使之成为正确的顺序。
综上所述,一个大数进制转换并保存为ASCII数组的工作就完成了,有了这个功能的实现,在文章一开始所提到的为满足那些大数需求所出现的难题也就迎刃而解了,这使得JavaCard所支持应用的范围又一次得到了扩充。
4 优化分析JavaCard应用优化主要从两个方面进行,一方面是空间优化,一方面是速度优化。
由于RAM空间十分有限,因此就要更加有效的利用RAM空间。
从这个方面考虑,就是要争取减少临时数组的长度。
在上一节的设计中,临时数组的长度为(4×Len+1)字节(其中Len 为原大数数据的字节数),可以看出当原数据比较大的时候,临时数组长度的增长是非常可观的,因此决定将被除数和余数数组作为优化对象。
优化的方案就是取消半字节转换模块,将原数据直接拷贝到临时数组的被除数数组中,并以字节为单位而不是半字节来进行,这样每次参与的被除数将是一个两个字节长度的短整型数据,除数也由原来固定的10变为100。
虽然临时数组的结构还如图2设计的那样,但是长度发生了明显变化,由(4×Len+1)字节变成了(2×Len+1)字节(其中Len为原大数数据的字节数)。
这样做节省了一定的RAM空间,可是最终结果的生成不再像上一节所述那样直接取出余数数组的最后一个字节那样简单了,因为在新的方法下,余数数组取出最后一个字节实际上是在算法分析一节中提到的取余转换法公式中(2)式的商Y,这就需要再做一次十六进制到十进制的转换,也就是上述公式中的(3)式才能得到最终的结果,虽然多了一次的转换计算,但却能在一次运算后得到两位结果,这样做无形中减少了整个转换过程的运算次数。
这个优化方案虽然从结果生成的角度看显得有些麻烦,但是从计算次数和(2×Len)字节的空间节省上看,还是一个很有价值、很值得应用的一个优化方案。
下面说说速度上的优化,其实上一优化方案中计算次数的优化已经是提高了运行速度,当然除此之外,在ASCII码数组生成模块上依然有优化之处。
上一节中该模块的实现是每得到一位就进行一次按位或运算。
其实,这个运算是可以被查表代替的,这里所谓的查表就是在EEPROM中建立一个长度为10个字节的数组,这个数组的内容就是按照顺序存储0x30~0x39这十个数。