--- title: Java BigDecimal — scale, HALF_UP rounding, money serialization source_type: official-doc url: https://docs.oracle.com/javase/8/docs/api/java/math/BigDecimal.html archive_url: status: raw confidence: high tags: [ca-tmpl, schema, serialization, bigdecimal, money, java, rounding] related_projects: [ca-tmpl] related_branches: [feature-schema-serialization-contract] created: 2026-05-22 last_reviewed: 2026-05-27 --- # Java BigDecimal — scale, HALF_UP rounding, money serialization > Layer: `raw/official-docs/` — Java SE 8 공식 Javadoc 의 `java.math.BigDecimal` 원문 발췌. ca-tmpl `BigDecimal scale 2 HALF_UP` + `Forbidden: binary floating point for money` 결정의 표준 근거. ## Parent / 활용 branch (필수) | Branch | 이 자료가 정당화하는 결정 | |---|---| | [[raw/branch-notes/feature-schema-serialization-contract]] | G-F "money/decimal = fixed scale 2 + HALF_UP default" 결정의 표준 근거 + `new BigDecimal(double)` 금지·`String` 생성자 권장의 공식 출처 | ## 컨텍스트 ca-tmpl Decisionized Work Items: `money/decimal = fixed scale 2 + HALF_UP default`. 이 결정이 단순 취향이 아니라 **부동소수점 위험 회피 + 표준 rounding 정의** 위에 서 있음을 명문화. JSON 직렬화 시 string 표현 권장 근거를 표준 Javadoc 에서 확보. ## 출처 / Source - 원본 URL: https://docs.oracle.com/javase/8/docs/api/java/math/BigDecimal.html - 아카이브 URL: (미수집) - 저자 / 조직: Oracle (Java SE 8 Javadoc) - 발행일: Java 8 (이후 버전 동일 의미) - 마지막 확인일: 2026-05-27 ## 핵심 인용 / Key quotes (verbatim) > [§scale() / class-level] "If zero or positive, the scale is the number of digits to the right of the decimal point. If negative, the unscaled value of the number is multiplied by ten to the power of the negation of the scale. For example, a scale of `-3` means the unscaled value is multiplied by 1000." > [§ROUND_HALF_UP] "Rounding mode to round towards 'nearest neighbor' unless both neighbors are equidistant, in which case round up. Behaves as for `ROUND_UP` if the discarded fraction is ≥ 0.5; otherwise, behaves as for `ROUND_DOWN`. Note that this is the rounding mode that most of us were taught in grade school." > [§BigDecimal(double val) — Notes] "One might assume that writing `new BigDecimal(0.1)` in Java creates a `BigDecimal` which is exactly equal to 0.1 (an unscaled value of 1, with a scale of 1), but it is actually equal to 0.1000000000000000055511151231257827021181583404541015625. This is because 0.1 cannot be represented exactly as a `double` (or, for that matter, as a binary fraction of any finite length)." > [§BigDecimal(double val) — Notes] "The `String` constructor, on the other hand, is perfectly predictable: writing `new BigDecimal(\"0.1\")` creates a `BigDecimal` which is _exactly_ equal to 0.1, as one would expect. Therefore, it is generally recommended that the String constructor be used in preference to this one." ## Claims Extracted / 추출된 주장 | Claim ID | Claim (이 자료가 직접 말하는 것) | Evidence quote | Strength | Applies to | Does not prove | |---|---|---|---|---|---| | SBMS-C1 | BigDecimal 의 scale 은 양수일 때 소수점 우측 자리수, 음수일 때 unscaled value 에 10^(-scale) 을 곱하는 의미 | [§scale()] "If zero or positive, the scale is the number of digits to the right of the decimal point. If negative, the unscaled value of the number is multiplied by ten to the power of the negation of the scale." | `official-vendor-doc` | java.math.BigDecimal 의 scale 의미 정의 | 모든 통화가 scale 2 라는 뜻 아님 — KRW/JPY 는 minor unit 없음 (scale 0) | | SBMS-C2 | `ROUND_HALF_UP` 은 "가장 가까운 이웃으로 반올림하되 정확히 중간일 때는 올림" — 학교에서 배우는 일반적 반올림 | [§ROUND_HALF_UP] "Rounding mode to round towards 'nearest neighbor' unless both neighbors are equidistant, in which case round up. ... Note that this is the rounding mode that most of us were taught in grade school." | `official-vendor-doc` | java.math.RoundingMode.HALF_UP 정의 | 회계·세무 표준이 HALF_UP 만을 강제한다는 뜻 아님 — ISO 4217 가이드는 명시 강제 없음 | | SBMS-C3 | `new BigDecimal(0.1)` 은 정확히 0.1 이 아니라 0.1000000000000000055511151231257827021181583404541015625 — 0.1 은 `double` 로 정확히 표현 불가 | [§BigDecimal(double) Notes] "writing `new BigDecimal(0.1)` in Java creates a `BigDecimal` ... it is actually equal to 0.1000000000000000055511151231257827021181583404541015625. This is because 0.1 cannot be represented exactly as a `double`" | `official-vendor-doc` | `BigDecimal(double)` 생성자의 정확한 동작 | 모든 `double` 입력이 동일한 패턴의 오차를 갖는다는 뜻 아님 — 0.1 의 특정 케이스 설명 | | SBMS-C4 | `new BigDecimal("0.1")` 은 정확히 0.1 — Oracle 공식 권장은 String 생성자 우선 사용 | [§BigDecimal(double) Notes] "writing `new BigDecimal(\"0.1\")` creates a `BigDecimal` which is _exactly_ equal to 0.1, as one would expect. Therefore, it is generally recommended that the String constructor be used in preference to this one." | `official-vendor-doc` | money/decimal BigDecimal 생성 방식 선택 | String 생성자만이 모든 입력에 안전하다는 뜻 아님 — `BigDecimal.valueOf(double)` (별도 `Double.toString` 경유) 도 안전 옵션으로 별도 언급됨 | ## Usage Boundaries / 적용 경계 - **이 자료가 직접 증명하는 것**: - `SBMS-C1` ~ `C4`: scale 의 정의, HALF_UP 의 정의, `new BigDecimal(double)` 의 부정확성, String 생성자 권장 - **이 자료가 증명하지 않는 것**: - JSON number vs string 직렬화 중 어느 쪽이 모든 클라이언트 환경에서 더 안전한지 (JavaScript IEEE 754 정밀도 손실은 별도 RFC / 사례 인용 필요) - Spring Boot / Jackson 의 `WRITE_BIGDECIMAL_AS_PLAIN` default (별도 Jackson 문서 인용 필요) - HALF_UP 이 모든 회계 표준에서 default 라는 사실 (도메인별 override 필요) - ISO 4217 의 통화별 minor unit (예: KRW scale 0, JPY scale 0, USD scale 2) 의 강제력 - **내 프로젝트에 적용하려면 추가 확인이 필요한 것**: - ca-tmpl 의 money 도메인이 multi-currency 인지 single-currency 인지 (scale 강제 정책 분기) - ArchUnit 등으로 `new BigDecimal(double)` / `new BigDecimal(float)` 호출을 코드 단계에서 차단할 수 있는 rule 설정 - JSON 직렬화 정책 (number vs string vs object with currency+scale) 의 클라이언트 합의 ## 메모 / Notes (내 프로젝트 해석) > 본 섹션은 자료 직접 인용 아님. ca-tmpl 결정 컨텍스트 해석. - **ca-tmpl 결정 정합**: - scale 2: 일반 통화 (KRW 제외 — 보통 정수 단위) 대부분에 적합. JPY/KRW 같은 minor-unit-없는 통화는 scale 0 이 정확. - HALF_UP: ISO 4217 가이드가 명시적으로 강제하지 않으나 **회계·세무 관행상 가장 보편**. ca-tmpl 이 domain override 허용한 것은 합리적. - JSON 직렬화 옵션 비교: | 옵션 | 장점 | 단점 | |---|---|---| | JSON number `1234.56` | 가독성, OpenAPI `format: decimal` 지원 | JavaScript number 는 IEEE 754 → client 에서 정밀도 손실 위험 | | JSON string `"1234.56"` | 정밀도 보존, scale 명시 가능 | 클라이언트가 파싱 명시 필요 | | JSON object `{ amount: "1234.56", currency: "KRW", scale: 0 }` | 통화·scale 명시 | payload 비대 | - Jackson 의 BigDecimal 처리: - `WRITE_BIGDECIMAL_AS_PLAIN=true` 권장 (지수 표기 방지). - Spring Boot 기본은 number 로 직렬화. string 강제하려면 `@JsonSerialize(using=ToStringSerializer.class)` 또는 Jackson 모듈 설정. - Trade-off (ca-tmpl 결정의 의미): - scale·rounding 을 schema 에 명시 → drift 검출 가능, 도메인 간 불일치 차단. - string serialization 강제 시 외부 client 학습 비용 ↑, 그러나 금융/결제 도메인에서는 표준. - 위험 회피: - `double`/`float` 금지 catalog 행으로 명시 (이미 ca-tmpl `Forbidden: binary floating point for money`). - `new BigDecimal(double)` 생성자도 사실상 금지에 가까움 — ArchUnit 등으로 차단 권장. ## Related / 관련 - 같은 주제 다른 official-doc: - [[raw/official-docs/schema-jackson-unknown-field-handling]] (Jackson 측 직렬화) - [[raw/official-docs/schema-protobuf-vs-json-evolution]] (Protobuf 비교) - 인용하는 branch: - [[raw/branch-notes/feature-schema-serialization-contract]] - 인용하는 wiki: (미작성)