|
|
게시됨 2015. 4. 7. 오후 2:53:05
|
|
|

큰 숫자에 대한 연산 클래스는 java.math.BinInteger 클래스와 java.math.BigDecimal 클래스가 제공됩니다. 이 두 클래스는 고정밀 컴퓨팅에 사용되며, BigInteger 클래스는 큰 정수를, BigDecimal 클래스는 큰 및 소수의 처리 클래스입니다. 아래에서 BigDecimal 클래스를 소개합니다: BigDecimal 구현은 BigInteger를 활용하지만, BigDecimal은 소수점 개념을 추가합니다. 일반 float 및 이중 타입 데이터는 과학 계산이나 공학 계산에만 사용할 수 있는데, 상업용 컴퓨팅에서는 요구되는 수치 정확도가 비교적 높기 때문에 java.math.BigDecimal 클래스가 사용되며, 고정 소수점의 정밀도를 지원하며 통화 값을 정확히 계산할 수 있습니다. 아래에서는 예시와 함께 그 사용법을 간략히 소개하겠습니다
java.math.빅십진수
오늘 저는 교과서를 참고하여 이진 및 소수 변환에 관한 프로그램을 작성했는데, 프로그램 알고리즘은 어렵지 않습니다. 하지만 작성 후 2에서 10이든 10에서 2로 변환하든, 21억 이상, 즉 정수 범위를 초과하는 숫자에는 좋은 변환이 되지 않는다는 것을 알게 되었습니다. 0이 될 것입니다. 참고서들은 BigInteger를 사용하면 이 문제를 해결한다고 밝혔습니다. 그래서 JDK를 찾아보고 여러 번 테스트하다가 결국 성공적으로 작성했습니다! 사용 경험은 다음과 같습니다:
1. BigInteger는 java.math.BigInteger에 속하므로, 사용 전에 이 클래스를 가져오세요. 가끔 처음에 가져오기를 깜빡해서 프롬프트가 항상 표시되는 프롬프트에서 찾을 수 없었습니다.
2. 다양한 건축 방법이 있지만, 현재는 가끔씩 사용됩니다: BigInteger(String val) BigInteger의 십진수 문자열 표현을 BigInteger로 변환합니다. BigInteger(String val, int radix) 지정된 기수에 대한 빅정수 표현의 문자열 표현을 빅정수로 변환합니다. 정수형 2를 BigInteger 타입으로 변환하려면, BigInteger two=new BigInteger("2")로 작성하라; 참고 2: 이중 따옴표는 생략할 수 없습니다
3. BigInteger 클래스는 add()=="+", divide()=="-" 등과 같은 모든 int형 수학 연산을 시뮬레이션하지만, 그 내용은 수학적 연산을 수행할 때 직접 사용할 수 없으며, 내부 메서드를 사용해야 한다는 점을 유의하세요. 그리고 그 피연산자는 BigInteger 타입이어야 합니다. 예를 들어: two.add(2)는 잘못된 연산입니다. 왜냐하면 2는 BigInteger 타입이 되지 않기 때문입니다.
4. 계산 결과를 출력하려면 .toString 메서드를 사용해 소수점 문자열로 변환해야 하며, 자세한 내용은 다음과 같습니다: 문자열 toString() 이 빅정수(BigInteger)의 십진수 문자열 표현을 반환합니다. 출력 방법: System.out.print(two.toString());
5. 사용된 세 가지 기능을 설명하십시오. BigInteger remainder(BigInteger val) 값이 (이 % val)인 BigInteger를 반환합니다. BigInteger 부정() BigInteger는 (-this) 값을 반환합니다. int compareTo(BigInteger val) 이 빅정수를 지정된 빅정수와 비교해 보세요. 잔여 부분은 나머지 부분을 찾는 데 사용되었습니다. 부정은 피연산자를 반대 방향으로 바꿉니다. 비교는 다음과 같이 자세히 설명되어 있습니다: compareTo(비슷한 것)
public int compareTo(BigInteger val)
이 빅정수를 지정된 빅정수와 비교해 보세요. 이 방법은 여섯 개의 불리언 비교 연산자 각각에 대해 선호됩니다(<, ==, >, >=, !=, <=). 이 비교를 수행하기 위해 제안된 문장은 다음과 같습니다: (x.compareTo(y) <op> 0), 여기서 는 <op> 여섯 개의 비교 연산자 중 하나입니다.
명세자: <BigInteger> 인터페이스 비교 가능
조건: val - 이 BigInteger를 비교하는 BigInteger입니다. 뒤로:
제목: 자바에서 부동소수점 수에 대한 정밀 계산 구현 Ay(원래) 수정 키워드 Java 부동소수점 정밀 계산
질문: 만약 우리가 다음 프로그램을 컴파일하고 실행한다면 무엇을 보게 될까요? public class Test{ public static void main(String args[]){ System.out.println(0.05+0.01); System.out.println(1.0-0.42); System.out.println(4.015*100); System.out.println(123.3/100); } };
제대로 읽으셨습니다! 그 결과는 실제로 0.060000000000000005 0.5800000000000001 401.49999999999994 1.2329999999999999
Java에서 단순한 float와 이중 타입은 조작할 수 없습니다. 이 문제는 자바뿐만 아니라 많은 다른 프로그래밍 언어에서도 발견됩니다. 대부분의 경우 계산은 정확하지만, 위에서 언급한 오류와 같은 오류를 몇 번 더 시도해볼 수 있습니다(루프 같은 것도 가능합니다). 이제야 왜 BCD 코드가 있는지 이해가 가네요. 이 문제는 꽤 심각합니다. 만약 9.9999999999999999위안이 있다면, 컴퓨터는 10위안짜리 상품을 살 수 있다고 인식하지 않습니다. 일부 프로그래밍 언어는 이 상황을 처리하기 위한 특수한 통화 유형을 제공하지만, 자바는 그렇지 않습니다. 이제 어떻게 고칠지 봅시다.
반올림 우리의 첫 반응은 반올림을 하는 것입니다. 수학 클래스의 라운드 메서드는 소수점 몇 자리만 남기도록 설정할 수 없으며, 우리는 이 작업만 할 수 있습니다(두 자리를 남기면): 공개 더블 라운드(두 배 가치){ Math.round(value*100)/100.0을 반환합니다; }
안타깝게도 위 코드는 작동하지 않으며, 4.015를 이 메서드에 전달하면 위에서 본 것처럼 4.02가 아닌 4.01이 반환됩니다 4.015*100=401.49999999999994 따라서 정확한 반올림을 원한다면, 단순 타입을 사용해 어떤 연산도 수행할 수 없습니다 java.text.DecimalFormat도 이 문제를 해결하지 못합니다: System.out.println(new java.text.DecimalFormat("0.00").format(4.025)); 출력은 4.02입니다
빅 십진법 이 원리는 "Effective Java"라는 책에서도 언급되어 있으며, float와 double은 과학적 또는 공학적 계산에만 사용할 수 있고, 비즈니스 컴퓨팅에서는 java.math.BigDecimal을 사용해야 합니다. BigDecimal을 만드는 방법은 4가지가 있으며, BigInteger로 만든 두 가지는 신경 쓰지 않고, 두 가지가 더 있습니다: 빅디십진(이중 발) 더블을 빅디십진으로 번역하는 거죠. BigDecimmal(문자열 발) BigDecimal의 문자열 representation을 BigDecimmal으로 변환합니다.
API는 간략히 설명되어 있으며 보통 사용하기가 더 쉽습니다. 우리는 아무 생각 없이 사용할 수도 있는데, 무슨 문제가 있을까요? 문제가 생겼을 때, 위 방법 중 어느 것이 충분한지에 대한 상세한 설명에 다음과 같은 단락이 있다는 것을 알게 되었습니다: 참고: 이 구성자의 결과는 다소 예측 불가능할 수 있습니다. 새로운 BigDecimal(.1)이 정확히 0.1과 같다고 생각할 수 있지만, 실제로는 0.1000000000000000055511151231257827021181583404541015625와 같습니다. 이는 .1이 정확히 이중 분수(또는 유한 길이의 이진 분수)로 정확히 표현될 수 없기 때문입니다. 따라서 구성자에 전달되는 롱 값은 겉보기와 상관없이 정확히 0.1과 같지 않습니다. 반면 (String) 구성자는 완전히 예측 가능하다: 새로운 BigDecima(".1")는 예상대로 정확히 0.1과 같다. 따라서 일반적으로 (String) 구성자를 사용하는 것이 이 대신 권장됩니다.
알고 보니 정확히 계산하려면 BigDecimal을 만들기 위해 String을 사용해야 합니다! 『Effective Java』라는 책의 예시는 문자열을 사용해 BigDecima를 만들지만, 책에서는 이를 강조하지 않아 작은 실수일 수 있습니다.
해결책 이제 이 문제를 해결했으니, 원칙은 BigDecimal을 사용하고 String을 반드시 사용하는 것입니다. 하지만 덧셈 연산을 하려면 먼저 두 개의 부동소수점 수를 String으로 변환하고, 그 다음 BigDecima를 만들고, 그 중 하나에 add 메서드를 호출한 뒤, 다른 하나는 인자로 전달한 뒤, 연산 결과(BigDecimal)를 부동소수점 숫자로 변환해야 한다고 상상해 보세요. 이렇게 지루한 과정을 견딜 수 있겠습니까? 아래에는 연산을 단순화하기 위해 도구 클래스인 Arith를 제공합니다. 덧셈, 뺄셈, 곱셈과 나눗셈, 반올림 등 다음과 같은 정적 방법을 제공합니다: 공용 정적 이중 추가(double v1, double v2) 공용 정적 더블 서브(더블 V1, 더블 V2) 공용 정적 더블 멀티(Double V1, Double V2) 공용 정적 더블 디비전(더블 v1, 더블 v2) 공용 정적 더블 디비전(더블 v1, 더블 v2, int 스케일) 공개 정적 더블 라운드(더블 V, INT 스케일)
부록
출처 파일 Arith.java:
java.math.BigDecimal을 import; /** * Java의 단순 타입은 부동소수점 연산을 정확히 수행할 수 없기 때문에, 이 도구 클래스는 미금을 제공합니다 * 덧셈, 뺄셈, 곱셈, 나눗셈, 반올림을 포함한 정확한 부동소수점 연산. */
공용 클래스 Arith{
기본 사단 작전 정확도 개인 정적 최종 정수 DEF_DIV_SCALE = 10;
이 클래스는 인스턴스화할 수 없습니다 개인 Arith(){ }
/** * 정확한 덧셈 연산을 제공합니다. * @param v1이 추가되었습니다 * @param v2 추가 * @return 두 매개변수의 합 */
공개 정적 이중 추가(double v1, double v2){ BigDecimal b1 = 새로운 BigDecima(Double.toString(v1)); BigDecimal b2 = 새로운 BigDecimal(Double.toString(v2)); b1.add(b2).doubleValue(); }
/** * 정확한 뺄셈 연산을 제공합니다. * v1@param 빼버렸습니다 * @param v2 마이너스 * @return 두 매개변수의 차이 */
공용 정적 이중 서브(Double V1, Double V2){ BigDecimal b1 = 새로운 BigDecima(Double.toString(v1)); BigDecimal b2 = 새로운 BigDecimal(Double.toString(v2)); b1.subtract(b2).doubleValue(); }
/** * 정확한 곱셈 연산을 제공합니다. * @param v1은 곱셈된다 * @param v2 배수 * @return 두 매개변수의 곱 */
public static double mul(double v1, double v2){ BigDecimal b1 = 새로운 BigDecima(Double.toString(v1)); BigDecimal b2 = 새로운 BigDecimal(Double.toString(v2)); b1.multiply(b2).doubleValue(); }
/** * 무한한 나눗셈이 발생할 때 (상대적으로) 정확한 나눗셈을 제공합니다 * 소수점 10자리와 그 다음 숫자들은 반올림되었습니다. * @param v1은 나뉜다 * @param v2 약수 * @return 두 매개변수의 몫 */
공용 정적 Double Div(Double V1, Double V2){ 리턴 디비전(v1, v2, DEF_DIV_SCALE); }
/** * (상대적으로) 정확한 사단 작전을 제공합니다. 무한한 상황이 발생하면 척도 매개변수로 표시됩니다 * 정확도를 결정하고, 그 이후의 숫자는 반올림됩니다. * @param v1은 나뉜다 * @param v2 약수 * @param 척도는 소수점 몇 자리까지 정확해야 함을 나타냅니다. * @return 두 매개변수의 몫 */
공개 정적 Double Div(Double V1, Double V2, int Scale){ if(scale<0){ throw new IllegalArgumentException( "척도는 양의 정수 또는 0이어야 한다"); } BigDecimal b1 = 새로운 BigDecima(Double.toString(v1)); BigDecimal b2 = 새로운 BigDecimal(Double.toString(v2)); b1.divide(b2, scale,BigDecimal.ROUND_HALF_UP).doubleValue(); }
/** * 정확한 소수점 반올림 기능을 제공합니다. * @param V는 반올림 수를 필요로 합니다 * @param 척도는 소수점 이후에 예약되어 있습니다 * @return 반올림 결과 */
공용 정적 더블 라운드(double v,int scale){ if(scale<0){ throw new IllegalArgumentException( "척도는 양의 정수 또는 0이어야 한다"); } 빅십진분류 b = 새로운 빅십진수(Double.toString(v)); 빅십진수 1 = 새로운 빅십진수("1"); 반환 b.divide(one, scale,BigDecimal.ROUND_HALF_UP).doubleValue(); } }; |
이전의:의미가 기본 키로 된 문자열을 설정하지 않는 것이 가장 좋습니다다음:JDK, JRE, JVM 차이점 및 연결
|