一区二区三区在线-一区二区三区亚洲视频-一区二区三区亚洲-一区二区三区午夜-一区二区三区四区在线视频-一区二区三区四区在线免费观看

服務器之家:專注于服務器技術及軟件下載分享
分類導航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術|正則表達式|C/C++|IOS|C#|Swift|Android|VB|R語言|JavaScript|易語言|vb.net|

服務器之家 - 編程語言 - Java教程 - Java常用數字工具類 大數乘法、加法、減法運算(2)

Java常用數字工具類 大數乘法、加法、減法運算(2)

2020-09-28 10:51龍軒 Java教程

這篇文章主要為大家詳細介紹了Java常用數字工具類,大數乘法、加法、減法運算,具有一定的參考價值,感興趣的小伙伴們可以參考一下

上篇分享了一下數字轉漢字的小功能,這里再分享一下大數相乘、相加、相減的功能。其他的不做過多的鋪墊了,我先講一下各個功能的計算原理。

Ⅰ. 乘法運算

為什么先說乘法運算——因為我先做了乘法運算。其實思路也是很多的,但是最終我參考了網絡上的一種計算方案,然后做了很多的修改。感覺這個在思路上應該是比較簡單的。

簡單點說:把數拆分成整數小數分別進行乘法運算,然后將結果放入一個特定長度的數組中,在放入是要計算存放的偏移位置,最后再對這個進行處理(進位、標記等),得到最終的結果。
是不是有點暈。請我詳細說一下吧:

  • 首先還得把數都拆成整數+小數,然后采用的是(x1+x2)(y1+y2)=x1y1+x1y2+x2y1+x2y2。這種方式來計算的,這樣來算,都變成了整數的運算了。要簡單很多。但是4個結果怎么累加起來計算呢,這就是第二步。
  • 要申明一個int數組,長度=整數長度和+小數長度和+1(小數點占1位)。通過實驗,我們可以看到任意2個整數相乘結果都不會超過這2個數的長度和。
  • 人為計算乘法的時候就是按右向左一位一位的計算的(低位對齊),所以為了對齊低位,我們將整數和小數全部反轉,并且轉化為char數組,方便運算。然后進行4次乘法。
  • 按位進行乘法運算,采用雙層for循環完成這個操作。這里最為天才的idea就是——不進位。當然必須得弄清楚整數相乘放在數組的哪些個位置、小數相乘存放的開始位置,以及整數和小數相乘結果存放的開始位置。
  • 處理結果集合,將>=10的做進位處理。
  • 這一步也是很有才的想法——對小數點位置進行標記,而不是直接替換成“.”(int數組也不能直接設定(/ □ \))。
  • 有了第6步的想法,就有了第7步的做法,處理整數部分頭部的0和小數部分末尾的0,都是無效數字,這里同樣采用標記的方式來處理
  • 最后將結果集合進行反轉輸出,遇到小數點標記和無效0標記直接替換和跳過。

這就是基本的思路了。后面又再次基礎上加上了負數的判斷、數字格式的判斷等,自己看注釋就可以明白了。
代碼如下:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
//標記為小數點
private static final int DOT=-99;
//標記為無效數字
private static final int INVALID=-100;
 
/**
 * 大數乘法
 *
 * @param a  第一個數
 * @param b  第二個數
 * @return  最終結果
 */
public static String multiply(String a, String b){
  //檢查數字格式
  checkNum(a);
  checkNum(b);
 
  //標記最終結果是否為負值
  boolean minus=false;
 
  //判斷是否有帶著-號
  if(a.startsWith("-") || b.startsWith("-")){
    //判斷是否全帶著-號
    if(a.startsWith("-") && b.startsWith("-")){
    }else{
      //只有1個帶著-號,則結果為負值
      minus=true;
    }
    if(a.startsWith("-")){
      a = a.substring(1);
    }
    if(b.startsWith("-")){
      b = b.substring(1);
    }
  }
 
  //獲取a,b的整數和小數部分
  String a_int = getInt(a);
  String a_fraction = getFraction(a);
  String b_int = getInt(b);
  String b_fraction = getFraction(b);
 
  //計算小數部分的總長度
  int len_fraction = a_fraction.length() +b_fraction.length() ;
 
  //a,b兩個數乘積的最大位數不會超過總位數之和+小數點(1位)
  int len = len_fraction +a_int.length()+b_int.length()+1;
 
  //創建結果數組
  int[] result = new int[len];//默認全為0
 
  //為了方便計算,去掉小數點(最后在結果中加上小數點)
  //并將高低位對調(反轉是為了低位對齊),最終轉化為char數組
  char[] s_a_int = reverseStr(a_int);
  char[] s_a_fraction = reverseStr(a_fraction);
  char[] s_b_int = reverseStr(b_int);
  char[] s_b_fraction = reverseStr(b_fraction);
 
  //將a、b都拆分成整數+小數,然后
  //采用(x1+x2)(y1+y2)=x1y1+x1y2+x2y1+x2y2公式,分別計算乘積
  multiply(s_a_int, s_b_int, len_fraction, result);
  multiply(s_a_int, s_b_fraction, (len_fraction-s_b_fraction.length), result);
  multiply(s_b_int, s_a_fraction, (len_fraction-s_a_fraction.length), result);
  multiply(s_a_fraction, s_b_fraction, 0, result);
 
  // 處理結果集合,如果是大于10的就向前一位進位,本身進行除10取余
  accumulateResultArrays(result);
 
  //標記小數點位置
  markDot(len_fraction, result);
 
  //切掉無用的0
  cutUnusedZero(len_fraction, result);
 
  //然后將數據反轉
  return (minus?"-":"") + reverseResult(result);
}
 
/**
 * 反轉字符串,并轉化為數組
 *
 * @param s    原字符串
 * @return
 */
private static char[] reverseStr(String s) {
  return new StringBuffer(s).reverse().toString().toCharArray();
}
 
/**
 * 計算2個數的每一位的乘積,放入到對應的結果數組中(未進位)
 *
 * @param a  第一個數
 * @param b  第二個數
 * @param start  開始放入的偏移位置
 * @param result  結果數組
 */
private static void multiply(char[] a, char[] b, int start , int[] result){
  // 計算結果集合
  for (int i = 0; i < a.length; i++) {
    for (int j = 0; j < b.length; j++) {
      result[i + j + start] += (int) (a[i] - '0') * (int) (b[j] - '0');
    }
  }
}
 
/**
 * 累加每一位,超過10則然后進位
 *
 * @param result  結果數組
 */
private static void accumulateResultArrays(int[] result) {
  for (int i = 0; i < result.length; i++) {
    if (result[i] >= 10) {
      result[i + 1] += result[i] / 10;
      result[i] %= 10;
    }
  }
}
 
/**
 * 標記小數點位置
 *
 * @param len_fraction  小數長度
 * @param result  結果數組(反轉的)
 */
private static void markDot(int len_fraction, int[] result) {
  if(len_fraction>0){
    //標記小數點位置
    for (int i = result.length-1 ; i > len_fraction; i--) {
      result[i] = result[i-1];
    }
    result[len_fraction]=DOT;//標記小數點位置
  }
}
 
/**
 * 去掉不必要的0(包括整數最前面的和小數最后面的0)
 *
 * @param len_fraction  小數長度
 * @param result    結果數組
 */
private static void cutUnusedZero(int len_fraction, int[] result) {
  //去掉小數部分不必要的0
  boolean flag_0_fraction = true;//標記一直是0
  for (int i =0; i< len_fraction; i++) {
    if(flag_0_fraction && result[i]==0){
      result[i]=INVALID;//為0時標記為無效
    }else{
      flag_0_fraction=false;
      break;
    }
  }
 
  //去掉整數部分的0
  boolean flag_0_int=true;
  for (int i =result.length-1; i > len_fraction || (len_fraction==0 && i==0); i--) {
    if(flag_0_int && result[i]==0){
      result[i]=INVALID;//為0時標記為無效
    }else{
      flag_0_int=false;//遇到不為0時,停止。
      break;
    }
  }
  if(flag_0_int){//整數部分全為0
    result[len_fraction+1]=0;
    if(flag_0_fraction){//同時,小數部分也全為0
      result[len_fraction]=INVALID;//不需要小數點了,所以置為無效
    }
  }else{//整數部分不為0
    if(flag_0_fraction && len_fraction>0){//小數部分全為0
      result[len_fraction]=INVALID;//不需要小數點了,所以置為無效
    }
  }
}
 
/**
 * 反轉結果,替換小數點,跳過無效的0
 *
 * @param result    結果數組
 * @return
 */
private static String reverseResult(int[] result) {
  //反轉
  StringBuffer sb = new StringBuffer();
  for (int i = result.length - 1; i >= 0; i--) {
    if(result[i]>INVALID){
      sb.append(result[i]==DOT ? "." : result[i]);
    }
  }
  return sb.toString();
}

我們繼續說第二個。

Ⅱ. 加法運算

有了上面的思路做鋪墊,下面的加法和減法基本上都可以秒懂了。負數及數字格式的判斷就直接略過了。直接說最基本的思路。

  • 前兩步同乘法運算。拆分整數+小數,聲明一個int數組存放結果。長度為a b整數最大的長度+1+小數最大長度+1(小數點位)。因為加法最多位數比最大長度大1,所以有一個+1。
  • 結果是整數和+小數和,整數要低位對齊,所以要反轉,小數則不用反轉。
  • 用一個for循環來計算2個整數或者小數的和,同樣不進位。
  • 剩下的同乘法4-8步。

代碼放在最后看吧。接著來說說減法。

Ⅲ. 減法運算

其實減法跟加法在代碼上看,更類似。詳細說一下:(忽略負數及數字格式的判斷)

  • 前三步同加法運算。拆分整數+小數,聲明一個int數組存放結果。長度為a b整數最大的長度+小數最大長度+1(小數點位)。結果是整數差+小數差。
  • 還是用一個for循環計算2個數的差,這里不是不進位了,而是不借位。
  • 處理結果結合跟加法和乘法不一樣,加法和乘法都是進位,這里是借位,所以處理不太一樣。
  • 剩下同加法。

具體代碼如下:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
/**
 * 大數加法
 *
 * @param a  第一個數
 * @param b  第二個數
 * @return  最終結果
 */
public static String add(String a, String b){
  //檢查數字格式
  checkNum(a);
  checkNum(b);
 
  //標記最終結果是否為負值
  boolean minus=false;
 
  //判斷是否有帶著-號
  if(a.startsWith("-") || b.startsWith("-")){
    //判斷是否全帶著-號
    if(a.startsWith("-") && b.startsWith("-")){
      //2個都帶著-號,結果肯定為負值
      minus=true;
      if(a.startsWith("-")){
        a = a.substring(1);
      }
      if(b.startsWith("-")){
        b = b.substring(1);
      }
    }else{
      //如果只有一個是負值,則調用減法來完成操作
      if(a.startsWith("-")){//a是負數
        a = a.substring(1);
        return subduct(b, a);
      }else{
        b = b.substring(1);
        return subduct(a, b);
      }
 
    }
  }
 
  //獲取a,b的整數和小數部分
  String a_int = getInt(a);
  String a_fraction = getFraction(a);
  String b_int = getInt(b);
  String b_fraction = getFraction(b);
 
  //計算小數部分最大長度
  int len_fraction = Math.max(a_fraction.length(), b_fraction.length());
 
  //計算整數部分最大長度
  int len_int = Math.max(a_int.length(), b_int.length())+1;
 
  //a,b兩個數整數最大長度和小數最大長度之和+小數點(1位)
  int len = len_fraction + len_int+1;
 
  //創建結果數組
  int[] result = new int[len];//默認全為0
 
  //為了方便計算,去掉小數點(最后在結果中加上小數點)
  //將【整數部分】高低位對調(反轉是為了低位對齊),最終轉化為char數組
  //小數部分不用調整
  char[] s_a_int = reverseStr(a_int);
  char[] s_b_int = reverseStr(b_int);
  char[] s_a_fraction = a_fraction.toCharArray();
  char[] s_b_fraction = b_fraction.toCharArray();
 
  //采用整數+整數,小數+小數的方式運算
  add(s_a_int, s_b_int, len_fraction, result);
  add(s_a_fraction, s_b_fraction, 1-len_fraction, result);
 
  // 處理結果集合,如果是大于10的就向前一位進位,本身進行除10取余
  accumulateResultArrays(result);
 
  //標記小數點位置
  markDot(len_fraction, result);
 
  //切掉無用的0
  cutUnusedZero(len_fraction, result);
 
  //然后將數據反轉
  return (minus ? "-" : "")+reverseResult(result);
}
 
/**
 * 計算2個數的每一位的和,放入到對應的結果數組中(未進位)
 *
 * @param a  第一個數
 * @param b  第二個數
 * @param start  開始放入的偏移位置
 * @param result  結果數組
 */
private static void add(char[] a, char[] b, int start , int[] result){
  char[] c=null;
  //保證a是位數多的,如果b長度大于a,則交換a,b
  if(b.length>a.length){
    c=a;
    a=b;
    b=c;
  }
  // 計算結果集合,a的位數>=b的位數
  int i = 0, j=0;
  for (; i < a.length && j< b.length; i++,j++) {
    result[Math.abs(i + start)] += (int) (a[i] - '0') + (int) (b[j] - '0');
  }
  //如果a沒有處理完畢,直接把a剩下的值賦值給結果數組即可
  for (; i < a.length; i++) {
    result[Math.abs(i + start)] += (int) (a[i] - '0');
  }
  if(c!=null){//如果交換過,則再交換回來
    c=a;
    a=b;
    b=c;
  }
  c=null;
}
 
/**
 * 大數減法
 *
 * @param a  第一個數
 * @param b  第二個數
 * @return  最終結果
 */
public static String subduct(String a, String b){
  //檢查數字格式
  checkNum(a);
  checkNum(b);
 
  //標記最終結果是否為負值
  boolean minus=false;
 
  //判斷是否有帶著-號
  if(a.startsWith("-") || b.startsWith("-")){
    //判斷是否全帶著-號
    if(a.startsWith("-") && b.startsWith("-")){
      //2個都帶著-號
      if(a.startsWith("-")){
        a = a.substring(1);
      }
      if(b.startsWith("-")){
        b = b.substring(1);
      }
      return subduct(b, a);
    }else{
      //如果只有一個是負值,則調用加法來完成操作
      if(a.startsWith("-")){//a是負值,b是非負值
        return add(a, "-"+b);//2個負值的加法運算
      }else{//b是負值
        b = b.substring(1);
        return add(a, b);//2個正值的加法運算
      }
    }
  }
 
  //獲取a,b的整數和小數部分
  String a_int = getInt(a);
  String a_fraction = getFraction(a);
  String b_int = getInt(b);
  String b_fraction = getFraction(b);
 
  boolean isSame = false;
  //判斷大小
  if(b_int.length()>a_int.length()){
    //如果b>a
    return "-"+subduct(b, a);
  }else if(b_int.length()==a_int.length()){
    char[] s_a = a_int.toCharArray();
    char[] s_b = b_int.toCharArray();
    for (int i = 0; i < s_a.length; i++) {
      if(s_b[i]>s_a[i]){
        minus=true;
        isSame=false;
        break;
      }else if(s_b[i]<s_a[i]){
        isSame=false;
        break;
      }else{
        isSame = true;
      }
    }
    if(isSame){//整數部分全部相同,對比小數部分
      s_a = a_fraction.toCharArray();
      s_b = b_fraction.toCharArray();
      for (int i = 0; i < Math.min(s_a.length, s_b.length); i++) {
        if(s_b[i]>s_a[i]){
          minus=true;
          isSame=false;
          break;
        }else if(s_b[i]<s_a[i]){
          isSame=false;
          break;
        }else{
          isSame = true;
        }
      }
      if(isSame){//前部分全相同
        if(s_b.length>s_a.length){//前部分全相同,b小數位數多,則 b>a
          return "-"+subduct(b, a);
        }else if(s_b.length == s_a.length){
          return "0";
        }
      }else if(minus){//如果b>a
        return "-"+subduct(b, a);
      }
    }
  }
 
 
  //計算小數部分最大長度
  int len_fraction = Math.max(a_fraction.length(), b_fraction.length());
 
  //計算整數部分最大長度
  int len_int = Math.max(a_int.length(), b_int.length());
 
  //a,b兩個數整數最大長度和小數最大長度之和+小數點(1位)
  int len = len_fraction + len_int+1;
 
  //創建結果數組
  int[] result = new int[len];//默認全為0
 
  //為了方便計算,去掉小數點(最后在結果中加上小數點)
  //將【整數部分】高低位對調(反轉是為了低位對齊),最終轉化為char數組
  //小數部分不用調整
  char[] s_a_int = reverseStr(a_int);
  char[] s_b_int = reverseStr(b_int);
  char[] s_a_fraction = a_fraction.toCharArray();
  char[] s_b_fraction = b_fraction.toCharArray();
 
  //采用整數+整數,小數+小數的方式運算
  subduct(s_a_int, s_b_int, len_fraction, result);
  subduct(s_a_fraction, s_b_fraction, 1-len_fraction, result);
 
  // 處理結果集合,如果是大于10的就向前一位進位,本身進行除10取余
  subductResultArrays(result);
 
  //標記小數點位置
  markDot(len_fraction, result);
 
  //切掉無用的0
  cutUnusedZero(len_fraction, result);
 
  //然后將數據反轉
  return (minus ? "-" : "")+reverseResult(result);
}
 
/**
 * 計算2個數的每一位的差,放入到對應的結果數組中(未進位)
 *
 * @param a  第一個數
 * @param b  第二個數
 * @param start  開始放入的偏移位置
 * @param result  結果數組
 */
private static void subduct(char[] a, char[] b, int start , int[] result){
  // 計算結果集合,a的位數>=b的位數
  int i = 0, j=0;
  for (; i < a.length && j< b.length; i++,j++) {
    result[Math.abs(i + start)] +=((int) (a[i] - '0') - (int) (b[j] - '0'));
  }
  //如果a沒有處理完畢,直接把a剩下的值賦值給結果數組即可
  for (; i < a.length; i++) {
    result[Math.abs(i + start)] +=((int) (a[i] - '0'));
  }
  //如果a沒有處理完畢,直接把a剩下的值賦值給結果數組即可
  for (; i < b.length; i++) {
    result[Math.abs(i + start)] +=-((int) (b[i] - '0'));
  }
}
 
/**
 * 檢查每一位,小于0(不含標記的小數點未和無效的0)則然后向高位借位。
 *
 * @param result  結果數組
 */
private static void subductResultArrays(int[] result) {
  for (int i = 0; i < result.length-1; i++) {
    if (result[i] < 0 && result[i]>DOT) {
      result[i + 1]--;
      result[i] += 10;
    }
  }
}

寫個main方法測試一下吧:

?
1
2
3
4
5
6
7
8
9
10
public static void main(String[] args) {
  String a = "9213213210.4508";
  String b = "12323245512512100.4500081";
  String r = multiply(a, b);
  System.out.println(a+"*"+b+"="+r);
  String r1 = add(a, b);
  System.out.println(a+"+"+b+"="+r1);
  String r2 = subduct(a, b);
  System.out.println(a+"-"+b+"="+r2);
}

測試結果如下:

Java常用數字工具類 大數乘法、加法、減法運算(2)

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持服務器之家。

原文鏈接:http://blog.csdn.net/xiaoxian8023/article/details/49834615

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 国产精品青青青高清在线密亚 | 国产精品极品美女自在线 | 国产麻豆麻豆 | 校草让我脱了内裤给全班看 | 日本在线看免费 | 精品视频手机在线观看免费 | 色呦呦网 | 美女口述又粗又大感觉 | 亚洲精品一 | 视频大全在线观看免费 | 国产一区二区三区久久精品 | 亚洲欧美成人中文在线网站 | 亚洲视频久久 | 欧美成人免费一区在线播放 | 男gay网站视频免费观看 | 日韩精品中文字幕久久 | 国产在线98福利播放视频免费 | 国产福利在线观看91精品 | 楚乔传第二部免费播放电视连续剧 | 免费看视频的 | 福利视频一区二区思瑞 | 亚洲国产欧美在线人网站 | 美女无遮挡 | 亚洲精品高清中文字幕完整版 | 故意短裙公车被强好爽在线播放 | 国产免费视 | 欧美a级在线观看 | 亚洲第一国产 | 天天快乐在线观看 | 欧美精品综合一区二区三区 | 成年看片免费高清观看 | 亚洲国产精品二区久久 | 深夜激情网站 | 男插女的下面免费视频夜色 | 女同色图 | 小柔的性放荡羞辱日记 | 亚洲国产精品久久久久久网站 | 成人天堂入口网站 | 久久精品18| 色偷偷亚洲男人 | 成人影院在线看 |