---
type: why
language: javascript
slug: float-precision
title: "なぜ 0.1 + 0.2 は 0.30000000000000004 になるのか"
title_tag: "なぜ 0.1 + 0.2 が 0.30000000000000004 になるのか"
summary: >
  2進数では 0.1 を正確に表せないためです。JavaScript 固有の問題ではありません。
  どこまで正確なのか、安全な比べ方、お金の扱い方までを実行して確かめます。
description: >
  二進法で 0.1 を正確に表せないためです。誤差がいつ出ていつ出ないか、比較のしかた、金額を扱うときに整数へ寄せる方法まで、実際に動かして確かめられます。
status: published
difficulty: 3
minutes: 10

versions:
  verified: "Node 22.22.3"
  since: "ES1"
  deprecated: null
  removed: null

sources:
  - title: "The Number Type — ECMAScript® 2026 Language Specification"
    url: "https://tc39.es/ecma262/#sec-ecmascript-language-types-number-type"
  - title: "Number.prototype.toFixed — ECMAScript® 2026 Language Specification"
    url: "https://tc39.es/ecma262/#sec-number.prototype.tofixed"
  - title: "IEEE 754-2019 — IEEE Standard for Floating-Point Arithmetic"
    url: "https://standards.ieee.org/ieee/754/6210/"

terms: [浮動小数点数, 倍精度, 丸め誤差, EPSILON]

links:
  related:
    - javascript/why/nan-equality

content_updated_at: 2026-09-07
published_at: 2026-09-07
---

**[num:2]進数では `0.1` を正確に表せないからです。**
`1/3` を[num:10]進数で書くと `0.333…` と終わらないのと同じことが、`0.1` に起きています。

```js run
console.log(0.1 + 0.2);
console.log(0.1 + 0.2 === 0.3);
```
```output
0.30000000000000004
false
```

これは JavaScript の不具合ではありません。[type:IEEE 754] の[type:倍精度]を使う言語では
**Python でも Java でも C でも同じ結果**になります。

## 実際に何が入っているのか

`0.1` の中身をもっと桁数を出して見ます。

```js run
console.log((0.1).toPrecision(20));
console.log((0.2).toPrecision(20));
console.log((0.3).toPrecision(20));
```
```output
0.10000000000000000555
0.20000000000000001110
0.29999999999999998890
```

`0.1` は[key:少しだけ大きく]、`0.3` は[key:少しだけ小さく]保存されています。
`0.1 + 0.2` はわずかに大きい側に寄るので、`0.3` と一致しません。

**画面に `0.1` と出るのは、そう見えるように丸めているから**です。
中身は最初から `0.1` ではありません。

## 正確に表せる数もある

[num:2]進数で書ける小数、つまり[key:2の冪の和]で作れる数は正確です。

```js run
console.log(0.5 + 0.25 === 0.75);
console.log((0.5).toPrecision(20));
console.log((0.1).toPrecision(20));
```
```output
true
0.50000000000000000000
0.10000000000000000555
```

`0.5` は `1/2`、`0.25` は `1/4` なのでぴったり入ります。
`0.1` は `1/10` で、[num:2]進数では割り切れません。

## 整数はどこまで正確か

小数と違い、整数は[key:ある大きさまで]正確です。

```js run
console.log(Number.MAX_SAFE_INTEGER);
console.log(Number.MAX_SAFE_INTEGER + 1 === Number.MAX_SAFE_INTEGER + 2);
console.log(9007199254740993);
console.log(Number.isSafeInteger(9007199254740993));
```
```output
9007199254740991
true
9007199254740992
false
```

`9007199254740991`（約[num:9]千兆）を超えると、[bad:隣り合う整数を区別できなくなります]。
`+1` と `+2` が等しくなっているのがその証拠です。

3行目に注目してください。**書いた数と、出てきた数が違います。**
`…993` は表せないので、[key:リテラルを書いた時点で]いちばん近い `…992` に置き換わっています。

大きな整数を正確に扱うなら `BigInt` です。

```js run
console.log(9007199254740991n + 2n);
console.log(typeof 9007199254740991n);
```
```output
9007199254740993n
bigint
```

## どう比べればよいか

### 誤差を許して比べる

差が十分小さければ同じとみなします。`Number.EPSILON` は
[key:1 の隣の数との差]で、この種の判定によく使われます。

```js run
const a = 0.1 + 0.2;

console.log(a === 0.3);
console.log(Math.abs(a - 0.3) < Number.EPSILON);
```
```output
false
true
```

**ただしこれは小さい数でしか通用しません。** 数が大きくなると、誤差そのものが大きくなります。

```js bad
const a = 1e10 + 0.1;
const b = 1e10 + 0.2;

console.log(Math.abs(a - b) < Number.EPSILON);
console.log(a - b);
```
```output
false
-0.10000038146972656
```

大きさに合わせて許容量を変える必要があります。

```js run
function nearlyEqual(x, y, rel = 1e-9) {
  return Math.abs(x - y) <= rel * Math.max(Math.abs(x), Math.abs(y), 1);
}

console.log(nearlyEqual(0.1 + 0.2, 0.3));
console.log(nearlyEqual(1e10 + 0.1, 1e10 + 0.1));
console.log(nearlyEqual(1, 2));
```
```output
true
true
false
```

### 整数にしてから比べる

そもそも小数にしない方法もあります。**これがいちばん確実です。**

```js run
console.log((0.1 * 10 + 0.2 * 10) / 10 === 0.3);
console.log(Math.round(0.1 * 10) + Math.round(0.2 * 10) === 3);
```
```output
true
true
```

## お金は小数で持たない

金額を `19.99` のような小数で持つと、足すたびに誤差が出る……**とは限りません。**
ここが厄介なところです。

```js run
let a = 0;
for (let i = 0; i < 10; i++) a += 19.99;

let b = 0;
for (let i = 0; i < 10; i++) b += 0.7;

console.log(a, a === 199.9);
console.log(b, b === 7);
```
```output
199.9 true
7.000000000000001 false
```

`19.99` を[num:10]回足すと[em:ぴったり]合い、`0.7` を[num:10]回足すと[bad:ずれます]。

**どちらになるかは値によって変わり、見ただけでは分かりません。**
「試したら合っていた」は何の保証にもなりません。手元で通ったものが、別の値でずれます。

だから[key:最小単位の整数]で持ってください。円なら円、ドルならセントです。

```js run
let total = 0;

for (let i = 0; i < 10; i++) {
  total += 1999;
}

console.log(total);
console.log(`${Math.floor(total / 100)}.${String(total % 100).padStart(2, '0')}`);
```
```output
19990
199.90
```

## toFixed は思ったとおりに丸まらない

「見せるときだけ丸めればいい」も、そのままでは通りません。

```js bad
console.log((1.005).toFixed(2), (1.005).toPrecision(20));
console.log((1.015).toFixed(2), (1.015).toPrecision(20));
console.log((1.025).toFixed(2), (1.025).toPrecision(20));
console.log((2.675).toFixed(2), (2.675).toPrecision(20));
```
```output
1.00 1.0049999999999998934
1.01 1.0149999999999999023
1.02 1.0249999999999999112
2.67 2.6749999999999998224
```

**4つとも切り下がっています。** どれも中身が[key:見た目よりわずかに小さい]からです。
`1.005` の実体は `1.00499999999999989…` なので、
四捨五入して `1.00` になるのが[em:正しい]動きです。

`toFixed()` が間違っているのではありません。**渡している数が、もう `1.005` ではない**のです。

「見た目の値」で四捨五入したいなら、誤差を足し戻してから丸めます。

```js run
function round2(n) {
  return Math.round(n * 100 + Number.EPSILON * n * 100) / 100;
}

console.log(round2(1.005));
console.log(round2(1.015));
console.log(round2(1.025));
```
```output
1.01
1.02
1.03
```

[dim:これも万能ではありません。金額を扱うなら、最初から整数で持つのが確実です。]

## よくある誤解

### JavaScript だけの問題だと思っている

[type:IEEE 754] の[type:倍精度]を使う言語すべてで起きます。
`0.1` を正確に持てる言語は、[key:10進数の型]を別に用意しています
（Java の `BigDecimal`、Python の `decimal` など）。

### 表示された値が中身だと思っている

`console.log(0.1)` が `0.1` と出るのは、
**その値に戻る最短の10進表記**を選んで表示しているからです。

```js run
console.log(0.1);
console.log(0.1 === 0.1000000000000000055511151231257827);
```
```output
0.1
true
```

**同じ値です。** 見た目が違うだけです。

### 誤差は「たまに」出ると思っている

`0.1` を足すたびに毎回ずれています。表示のときに隠れているだけです。

```js run
console.log(0.1 + 0.1);
console.log(0.1 + 0.1 + 0.1);
console.log((0.1 + 0.1 + 0.1).toPrecision(20));
```
```output
0.2
0.30000000000000004
0.30000000000000004441
```

[num:2]回足したときは表示上ちょうど `0.2` ですが、
[num:3]回足すと隠しきれなくなって出てきます。

同じ [type:IEEE 754] が決めている `NaN` の振る舞いは
[なぜ NaN === NaN は false なのか](/ja/javascript/why/nan-equality/) にあります。

「等しい」をどう判定するかという話は、`==` と `===` の違いにも繋がります。
→ [なぜ == ではなく === を使うのか](/ja/javascript/why/strict-equality/)
