[자바]시 뮬 레이 션 실현 대 정수 류
14187 단어 Java
긴 정수 류 BigInt 를 실현 하고 임 의 정밀도 의 정수 와 연산 을 지원 합 니 다.
2.데이터 구조:
public class BigInt {
private int length;
private boolean pn; //positiveor negative. + is true, - is false
private String value;
}
그 중에서 문자열 value 는 이 큰 정수 의 절대 값 이 고 length 는 이 절대 값 의 자릿수 를 저장 하 며 pn 은 이 큰 정수 의 기 호 를 기록 합 니 다.이렇게 하면 양수 문 제 를 해결 하 는 데 유리 하고 모든 큰 정 수 는 조작 할 때 value 를 직접 진행 할 수 있 으 며 마지막 으로 결 과 를 얻 은 기 호 를 통일 적 으로 고려 할 수 있다.
3.구체 적 인 방법:
1. 매개 변수 없 는 구조 함수 BigInt()
BigInt() {
this.length = 1;
this.pn = true;
this.value = "0";
}
2. 문자열 이 있 는 구조 함수 BigInt(String s)
a) 개인 적 인 방법 인 isLegal(s)을 통 해 매개 변 수 를 합 법성 으로 판단 한다.
b) 이 문자열 에 기호 가 있 는 지 판단 하고 기호 pn 을 설정 합 니 다.
c) 개인 적 인 방법 으로 findStartPos(s)를 통 해 문자열 의 진정한 의미 가 있 는 가장 높 은 위 치 를 찾 습 니 다.
d) 가장 높 은 자리 에 있 는 모든 문 자 를 value 에 저장 하고 length 에 이 value 의 길 이 를 기록 합 니 다.
e) 0 을 특별 처리 하 다.
BigInt(String s) {
//assert isLegal(s);
if (isLegal(s)) {
if (s.charAt(0)=='+' || s.charAt(0)=='-') {
this.pn = s.charAt(0)=='+' ? true:false;
}
else {
this.length = s.length();
this.pn = true;
}
int sp = findStartPos(s);
this.value = s.substring(sp);
this.length = s.length()-sp;
if (this.value.charAt(0) == '0') {
this.pn = true;
this.length = 1;
this.value = "0";
}
}
else {
System.out.println("This BigInt is not legal!");
}
}
3. BigInt 문자열 변환 publicString toString()
데이터 구조 에서 기호 위치 와 데이터 위 치 를 분리 하기 때문에 출력 할 때 기호 위치 pn==false 를 고려 할 때 value 앞 에 마이너스 번 호 를 추가 하면 됩 니 다.
public String toString() {
if (pn == false) {
return "-" + value;
}
return value;
}
4. 큰 정수 비교 가 같은 지 public boolean equals(BigInt x)
toString()과 유사 하 며 두 개의 큰 정수 기호 위치 와 데이터 위치 가 같 는 지 비교 하면 됩 니 다.주의해 야 할 것 은 데이터 비트 를 비교 할 때 equals()를 사용 하고 등호 로 실제 데이터 가 아 닌 인용 값 을 직접 비교 하 는 것 입 니 다.
public boolean equals(BigInt x) {
if (this.pn==x.pn && this.length==x.length && this.value.equals(x.value)) {
return true;
}
return false;
}
5. 큰 정수 크기 비교 public int compare(BigInt x)
반환 1 보다 크 면 반환 0,반환-1 보다 작 습 니 다.
a) 기호 비트 pn 을 통 해 두 수의 크기 를 동시에 비교 하지 않 습 니 다.
b) 기호 가 서로 다른 동시에 길이 가 서로 다른 두 수의 크기 를 비교 하면 양수 의 길이 가 크 고 음수 의 길이 가 작다.
c) 기호 길이 가 모두 같 으 면 copare To 를 통 해 두 수의 value 를 비교 하고 정 수 는 copare To 의 결과 대응 점 1 과-1 을 되 돌려 주 며 음 수 는 copare To 결과 의 반대 수의-1 과 1 을 되 돌려 줍 니 다.
public int compare(BigInt x) {
if (this.pn != x.pn) {
return this.pn==true ? 1:-1;
}
if (this.length!=x.length) {
if (this.pn) {
return this.length>x.length ? 1:-1;
}
else {
return this.length 0) {
return -1;
}
if (tmp < 0) {
return 1;
}
return tmp;
}
6. 큰 정수 덧셈 public BigInt add(BigInt x)
덧셈 조작 에 있어 서 기호 위치 가 같은 상황 만 고려 하고 기호 위치 가 다른 상황 을 뺄셈 에 버린다.
a) 0 을 특수 처리 하고 다른 수 를 되 돌려 줍 니 다.new BigInt(this.toString()와 같은 새로운 큰 정 수 를 만 드 는 것 을 주의 하 십시오.
b) 두 개의 기호 위치 가 다 르 면 x 의 백업 xx 를 만 들 고 개인 적 인 방법 으로 changePN()을 사용 하여 xx 의 기호 위 치 를 바 꾸 고 this-xx 를 계산 하여 결 과 를 되 돌려 줍 니 다.
c) 두 문자열 bigger 와 smaller 를 만 들 고 데이터 비트 가 큰 데이터 비트 와 작은 데이터 비트 를 각각 기록 합 니 다.
d) 아 날로 그 덧셈 작업:bigger 와 smaller 로 가장 낮은 위치 에서 덧셈 작업 을 하고 개인 적 인 방법 인 charAdd()를 통 해 비트 별로 추가 한 결 과 는 문자열 ans 에 기록 합 니 다.그리고 carry Value 를 통 해 현재 위치 에 따라 결 과 를 추가 하 는 지 여 부 를 기록 합 니 다.만약 에 위치 가 있 으 면 다음 덧셈 작업 을 할 때 carry Value 를 위치 에 따라 추가 하 는 작업 에 넣 어야 합 니 다.그렇지 않 으 면 이 를 제거 해 야 합 니 다.
ans[i] =bigger[bigger.length-i]+smaller[smaller.length-i]+carryValue
e) smaller 의 최고 위 치 를 다 추가 한 후에 bigger 가 더 많은 높 은 위 치 를 carry Value 와 계속 위치 별로 추가 해 야 합 니 다.
f) 가장 높 은 자리 에 진위 가 발생 하 는 지 판단 하고 발생 하면 가장 높 은 자리 1 을 보충 합 니 다.
g) ans 를 반전 시 키 고 큰 정 수 를 구성 하 며 그 기호 위 치 를 this 의 기호 위치 로 합 니 다.
public BigInt add(BigInt x) {
if (x.value.equals("0")) {
return new BigInt(this.toString());
}
if (this.value.equals("0")) {
return new BigInt(x.toString());
}
if (this.pn != x.pn) {
BigInt xx = new BigInt(x.toString());
xx.changePN();
return this.substract(xx);
}
String bigger, smaller;
if ((this.compare(x)>=0&&this.pn)||(this.compare(x)<0&&!this.pn)) {
bigger = new String(this.value);
smaller = new String(x.value);
}
else {
bigger = new String(x.value);
smaller = new String(this.value);
}
String tmpAns = new String();
int carryValue = 0;
for (int i = 1; i <= smaller.length(); i++) {
int tmpAdd = charAdd(bigger.charAt(bigger.length()-i), smaller.charAt(smaller.length()-i)) + carryValue;
carryValue = tmpAdd>=10 ? 1:0;
tmpAns += String.valueOf(tmpAdd-carryValue*10);
}
int pos = bigger.length()-smaller.length()-1;
while(carryValue!=0 && pos>=0) {
int tmpAdd = charAdd(bigger.charAt(pos), '1');
carryValue = tmpAdd>=10 ? 1:0;
tmpAns += String.valueOf(tmpAdd-carryValue*10);
pos--;
}
String ans = new String();
tmpAns = reverse(tmpAns);
if (carryValue == 0) {
ans = bigger.substring(0, Math.max(pos+1, 0))+tmpAns;
}
else if (pos < 0) {
ans = "1"+tmpAns;
}
if (!this.pn) {
ans = "-"+ans;
}
return new BigInt(ans);
}
7. 큰 정수 감법 조작 public BigInt substract(BigInt x)
덧셈 과 같이 기호 위치 가 같은 상황 만 고려 하여 기호 위치 가 다른 상황 을 덧셈 에 던 집 니 다.다음은 시 뮬 레이 션 감법 조작 만 소개 한다.
tmpSub= charSub(bigger[bigger.length()-i], smaller[smaller.length()-i], carryValue);
public BigInt substract(BigInt x) {
if (x.value.equals("0")) {
return new BigInt(this.toString());
}
else if (this.value.equals("0")) {
BigInt ans = new BigInt(x.toString());
ans.changePN();
return ans;
}
if (this.pn != x.pn) {
BigInt xx = new BigInt(x.toString());
xx.changePN();
return this.add(xx);
}
String bigger, smaller;
boolean tag = this.compare(x)>=0 ? true:false;
if ((this.compare(x)>=0&&this.pn)||(this.compare(x)<=0&&!this.pn)) {
bigger = new String(this.value);
smaller = new String(x.value);
}
else {
bigger = new String(x.value);
smaller = new String(this.value);
}
String tmpAns = new String();
int carryValue = 0;
for (int i = 1; i <= smaller.length(); i++) {
int tmpAdd = charSub(bigger.charAt(bigger.length()-i), smaller.charAt(smaller.length()-i), carryValue);
carryValue = tmpAdd<0 ? 1:0;
if (tmpAdd == -100) {
carryValue = 1;
tmpAdd = 0;
}
tmpAns += String.valueOf(Math.abs(tmpAdd));
}
int pos = bigger.length()-smaller.length()-1;
while(carryValue!=0 && pos>=0) {
int tmpAdd = charSub(bigger.charAt(pos), '0', carryValue);
carryValue = tmpAdd<0 ? 1:0;
tmpAns += String.valueOf(Math.abs(tmpAdd));
pos--;
}
String ansStr = new String();
tmpAns = reverse(tmpAns);
if (carryValue == 0) {
ansStr = bigger.substring(0, Math.max(pos+1, 0))+tmpAns;
}
BigInt ans = new BigInt(ansStr);
ans.pn = tag;
return ans;
}
그 중 개인 적 인 방법 charSub():
private int charSub(char x, char y, int c) {
int ans = x + 10 - c - y;
if (ans < 10) {
if (ans == 0) {
ans = 100;
}
return ans*(-1); // there is a negative zero problem
}
return ans-10;
}
매개 변수 0,9,1 과 같은 마이너스 0 문 제 를 해결 하기 위해 이 결 과 를-100 으로 설정 하여 특수 처 리 를 한다.
8. 큰 정수 곱셈 조작 public BigInt multiply(BigInt x)
분 치 된 사상 을 사용 하여 두 개의 수 를 각각 M1,M2 로 설정 하고 길 이 는 모두 l 이다.이 를 다음 과 같이 표시 할 수 있다.
M1=AB,A 는 전 l/2 길이 의 데이터 비트 이 고 B 는 후 l-l/2 길이 의 데이터 비트 이다.
M2=CD,C 는 앞 l/2 길이 의 데이터 비트 이 고 D 는 뒤 l-l/2 길이 의 데이터 비트 입 니 다.
그래서 M1*M2 는
M1*M2 = A*C*(10^((l-l/2)*2)) + B*D + ((A-B)*(D-C)+A*C+B*D) *(10^(l-l/2))
그러나 두 개의 데이터 비트 길이 가 모두 l 이라는 것 을 보장 할 수 없 기 때문에 데이터 비트 가 짧 은 앞 에 0 을 보충 하여 l 비트 를 보충 해 야 합 니 다.이러한 방법 을 채택 한 것 은 원래 의 곱셈 조작 이 분 해 된 후에 도 네 번 의 곱셈 이 되 고,상식 적 인 곱셈 조작 으로 분 해 된 후에 세 번 의 곱셈 조작 만 하면 시간 복잡 도 는 O(l^log(3)로 떨 어 지기 때문이다.
public BigInt multiply(BigInt x) {
if (x.value.equals("0") || this.value.equals("0")) {
return new BigInt();
}
boolean ansPN = !(this.pn ^ x.pn);
if (x.length == 1 && this.length == 1) {
int ians = Integer.parseInt(x.value)*Integer.parseInt(this.value);
BigInt ans = new BigInt(String.valueOf(ians));
ans.setPN(ansPN);
return ans;
}
String a = this.value, b = x.value;
/**********Unify Length**********/
int len1 = Math.max(a.length(), b.length())-a.length();
int len2 = Math.max(a.length(), b.length())-b.length();
for (int i = 0; i < len1; i++) {
a = "0" + a;
}
for (int i = 0; i < len2; i++) {
b = "0" + b;
}
BigInt a1 = new BigInt(a.substring(0, a.length()/2));
BigInt a2 = new BigInt(a.substring(a.length()/2));
BigInt b1 = new BigInt(b.substring(0, b.length()/2));
BigInt b2 = new BigInt(b.substring(b.length()/2));
BigInt ans1 = a1.multiply(b1);//a1*b1
BigInt ans2 = a2.multiply(b2);//a2*b2
BigInt sub1 = a1.substract(a2);
BigInt sub2 = b2.substract(b1);
BigInt ans3 = sub1.multiply(sub2);//(a1-a2)(b2-b1)
ans3 = ans3.add(ans1);
ans3 = ans3.add(ans2);
String tmp = ans1.value;
for (int i = 0; i < (a.length()-a.length()/2)*2; i++) {
tmp += "0";
}
ans1 = new BigInt(tmp);
tmp = ans3.value;
for (int i = 0; i < (a.length()-a.length()/2); i++) {
tmp += "0";
}
if (!ans3.pn) {
tmp = "-"+tmp;
}
ans3 = new BigInt(tmp);
BigInt ans = ans1.add(ans3).add(ans2);
ans.setPN(ansPN);
return ans;
}
9. 큰 정수 나 누 기 동작 Public BigInt divide(BigInt x)(나 누 기 0 이 아 님)
a) 나눗셈 의 데이터 비트 가 나 누 어 진 데이터 비트 보다 큰 지 판단 하고 크 면 0 을 되 돌려 줍 니 다.
b) x 후 0 을 보충 하여 x 를 this 보다 크 지 않 은 최대 0 으로 바 꾸 고 cnct 개 0 을 기록 하여 조작 하기에 편리 하도록 x*addZero,addZero=100...00 에 해당 하 며 그 중에서 cnct 개 0 이 있 습 니 다.
c) 업 체 quotint 를 0 으로 초기 화 합 니 다.
d) LOOP 1:cnt 회 순환 하기;
e) LOOP 2:매번 this-x,this=this-x,quotint=quotient+addZero 를 계산 합 니 다.
f) addZero 와 x 끝 을 0 으로 제거 하고 LOOP 1 로 돌리 기;
g) 상의 기호 위 치 를 this 와 x 의 기호 위치의 차이 또는 로 합 니 다.
public BigInt divide(BigInt x) {
boolean ansPN = !(this.pn ^ x.pn);
if (x.toString().equals("0")) {
System.out.println("The divider cannot be 0!");
BigInt ans = new BigInt("1");
ans.setPN(ansPN);
return ans;
}
if (unsignedCompare(x) < 0) {
return new BigInt("0");
}
String a = this.value, b = x.value, addZero = new String("1");
int cnt = a.length()-b.length();
for (int i = 0; i < cnt; i++) {
b += "0";
addZero += "0";
}
BigInt divA = new BigInt(a), divB = new BigInt(b);
BigInt quotien = new BigInt("0");
while(cnt >= 0) {
BigInt addBI = new BigInt(addZero);
while(divA.compare(divB) >= 0) {
quotien = quotien.add(addBI);
divA = divA.substract(divB);
}
divB = new BigInt(divB.value.substring(0, Math.max(1,divB.value.length()-1)));
addZero = addZero.substring(0, Math.max(1,cnt));
cnt--;
}
quotien.setPN(ansPN);
return quotien;
}
10. 큰 정수 취 여 작업 public BigInt mod(BigInt x)
a) this.divid(x)를 호출 하여 상 q 받 기;
b) q.multiply(x)를 호출 하여 적 tmp 얻 기;
c) this.substract(tmp)를 되 돌려 줍 니 다.
public BigInt mod(BigInt x) {
BigInt tmp = this.divide(x);
tmp = tmp.multiply(x);
return this.substract(tmp);
}
11. 단계 곱 하기 조작 public static BigInt factorial(BigInt x):
x.multiply(factorial(x.substract(ONE))를 재 귀적 으로 호출 하면 됩 니 다.
public BigInt factorial(BigInt x) {
if (!x.equals(ZERO)) {
return x.multiply(factorial(x.substract(ONE)));
}
return new BigInt("1");
}
12. 지수 함수 public static BigInt expo(BigInt x):
TWO.multiply(expo(x.substract(ONE)))를 재 귀적 으로 호출 하면 됩 니 다.
public BigInt expo(BigInt x) {
if (!x.equals(ZERO)) {
return TWO.multiply(expo(x.substract(ONE)));
}
return new BigInt("1");
}
4.사유 방법 과 상수:
상수:
public static final BigInt ZERO = new BigInt();
public static final BigInt ONE = new BigInt("1");
public static final BigInt TWO = new BigInt("2");
개인 정보 보호 방법:
private int unsignedCompare(BigInt x) {//
BigInt a = new BigInt(this.value);
BigInt b = new BigInt(x.value);
return a.compare(b);
}
private String reverse(String s) {//
StringBuffer sb = new StringBuffer(s);
return sb.reverse().toString();
}
private int charAdd(char x, char y) {//
return x + y - '0' - '0';
}
private int charSub(char x, char y, int c) {//
int ans = x + 10 - c - y;
if (ans < 10) {
if (ans == 0) {
ans = 100;
}
return ans*(-1); // there is a negative zero problem
}
return ans-10;
}
private void changePN() {//
this.pn = this.pn==true ? false:true;
if (this.value.charAt(0) == '0') {
this.pn = true;
}
}
private void setPN(boolean targetPN) {//
this.pn = targetPN;
}
private int findStartPos(String s) {//
for (int i = 0; i < s.length(); i++) {
if (Character.isDigit(s.charAt(i)) && s.charAt(i)!='0') {
return i;
}
}
return s.length()-1;//this is a zero!
}
private boolean isLegal(String s) {//
if (s == null || ((s.length()==1)&&(!Character.isDigit(s.charAt(0)))) || ((s.length()>1)&&(s.charAt(0)!='+')&&(s.charAt(0)!='-')&&(!Character.isDigit(s.charAt(0))))) {
return false;
}
for (int i = 1; i < s.length(); i++) {
if (!Character.isDigit(s.charAt(i))) {
return false;
}
}
return true;
}
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
JPA + QueryDSL 계층형 댓글, 대댓글 구현(2)이번엔 전편에 이어서 계층형 댓글, 대댓글을 다시 리팩토링해볼 예정이다. 이전 게시글에서는 계층형 댓글, 대댓글을 구현은 되었지만 N+1 문제가 있었다. 이번에는 그 N+1 문제를 해결해 볼 것이다. 위의 로직은 이...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.