Numbers
BigDecimal: doubleから作ると意図しない桁が入る
new BigDecimal(0.1d)は2進浮動小数点の値を正確に取り込み、10進数の0.1とは一致しません。
SourceBigDecimalConstruction.java
Java 21
package examples.bigdecimal;
import java.math.BigDecimal;
public final class BigDecimalConstruction {
private BigDecimalConstruction() {}
public static BigDecimal fromBinaryDouble(double value) {
return new BigDecimal(value);
}
public static BigDecimal fromDecimalLiteral(String value) {
return new BigDecimal(value);
}
}TestBigDecimalConstructionTest.java
Java 21
package examples.bigdecimal;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotEquals;
import java.math.BigDecimal;
import org.junit.jupiter.api.Test;
class BigDecimalConstructionTest {
@Test
void doubleから作るBigDecimalは10進数の0point1と厳密には一致しない() {
var fromDouble = BigDecimalConstruction.fromBinaryDouble(0.1d);
assertNotEquals(new BigDecimal("0.1"), fromDouble);
assertEquals(
"0.1000000000000000055511151231257827021181583404541015625", fromDouble.toPlainString());
}
@Test
void 文字列から作るBigDecimalは意図した10進数を保持する() {
assertEquals(new BigDecimal("0.1"), BigDecimalConstruction.fromDecimalLiteral("0.1"));
}
}01Assertion
このテストで確認できること
- new BigDecimal(0.1d)はnew BigDecimal("0.1")とequalsで一致しない
- 文字列から作ると意図した10進数0.1を保持する
金額などの10進値は文字列またはBigDecimal.valueOfから作ります。doubleの内部表現をそのままコンストラクタへ渡さないようにします。
OBSERVED RESULT
expected: new BigDecimal(0.1d).equals(0.1) → false
actual: false
expected: new BigDecimal("0.1") → 0.1
actual: 0.1