# 計算ロジック 社会保険料計算の根拠となるルールをまとめます。本章で用いる記号は次の通り: - $T$ … 各保険料の「全額」(標準報酬月額 × 料率、円・小数を含む) - $x_e$ … 社員側の負担額(整数円) - $x_b$ … 事業主側の負担額(整数円) - $\lfloor x \rfloor$ … 床関数(0 方向への切捨て、整数円への変換) - $[P]$ … アイバーソンの記法($P$ が真なら 1、偽なら 0) (rounding-employee)= ## 端数処理 — 社員側「50 銭超切上げ」 協会けんぽの公式保険料額表(東京支部)の注釈より: > ① 事業主が、給与から被保険者負担分を控除する場合、被保険者負担分の端数が **50 銭以下** の場合は **切り捨て**、**50 銭を超える** 場合は **切り上げて 1 円** となります。 これを式で書くと、社員側の負担額は $$ x_e = \left\lfloor \dfrac{T}{2} \right\rfloor + [\, T \bmod 2 > 1 \,] $$ となります(全額 $T$ を 2 で割ったときの端数 $T \bmod 2$ が 1 円超のときだけ 1 円切上げ)。 ### なぜこの形か 折半額 $T/2$ の端数は $0 \le \text{端数} < 1$ の範囲を取ります。これを $T$ 側に倍した量 $T \bmod 2$(値域は $0 \le T \bmod 2 < 2$)で見ると、 - 端数 50 銭 ⇔ $T \bmod 2 = 1$ - 端数 50 銭超 ⇔ $T \bmod 2 > 1$ ちょうど **50 銭(端数 0.5 円)は切捨て側に含まれる** ため、判定は厳密な不等号 $>$ を使う必要があります。 ### 動作例 ```{list-table} :header-rows: 1 * - 全額 $T$ - $\lfloor T/2 \rfloor$ - $T \bmod 2$ - $> 1$? - 社員側 $x_e$ - 説明 * - 10,093.6 - 5,046 - 1.6 - YES - **5,047** - 端数 0.8 円 → 50 銭超 → 切上げ * - 16,104 - 8,052 - 0 - NO - **8,052** - 端数なし * - 10,094 - 5,047 - 0 - NO - **5,047** - 偶数なのでぴったり * - 10,095 - 5,047 - 1 - NO - **5,047** - 端数 0.5 円ちょうど → **切捨て**(50 銭以下に含まれる) ``` 最後の例(10,095 → 5,047)に注意してください。**最近接整数への四捨五入**(0.5 を切上げる方式)を使うと 5,048 になり誤差が出ます。 ```{warning} 被保険者が **現金で事業主に支払う** 場合のルール(50 銭未満切捨て・50 銭以上切上げ)とは微妙に違います。本ドキュメントは「給与控除」前提なので前者(50 銭ちょうどは切捨て)を採用しています。 ``` ## 事業主側 — 残額方式 社員側と同じ式で事業主側 $x_b$ を出して 2 倍すると、合計が床値 $\lfloor T \rfloor$ を超えるケースがあります。例えば全額 $T = 10{,}093.6$ のとき、両側 5,047 にすると合計 10,094 で **+1 円**。 そこで事業主側は **「告知額から社員側を引いた残額」** で求めます。次節で述べるとおり、丸めの単位は保険料の種別ではなく **納入告知書(保険者)** なので、残額方式も告知書グループ単位で適用します。グループ $g$ の告知額を $N_g$、グループ内の社員側合計を $X_g$ とすると、 $$ Y_g = N_g - X_g $$ これにより、グループごとに $X_g + Y_g = N_g$ が必ず成立し、月次の納付額が年金事務所・協会けんぽの発行する通知額と一致します。 (kaigo-auto-judgment)= ## 介護該当の自動判定 ### 法的境界 ```{list-table} :header-rows: 1 * - イベント - 介護該当開始/終了月 * - 40 歳到達 - 誕生日の **前日が属する月** から介護料率を加算 * - 65 歳到達 - 誕生日の **前日が属する月** から介護料率を停止(被保険者カテゴリが 1 号に切替) ``` 「誕生日の前日が属する月」が境界となるため、4 月 1 日生まれは 3 月から、4 月 2 日生まれは 4 月から該当開始です。 ### 判定ルール 生年月日 $d$ に対して、次のように 40 歳前日 $d_{40}$ と 65 歳前日 $d_{65}$ を定義します。 $$ d_{40} = (d \text{に}40 \text{年加算した日付}) - 1\,\text{日}, \qquad d_{65} = (d \text{に}65 \text{年加算した日付}) - 1\,\text{日} $$ ある対象月 $(y, m)$ の月末日を $e_{y,m}$ とすると、その月の介護該当フラグ $K_{y,m}$ は $$ K_{y,m} = [\, d_{40} \le e_{y,m} \,] \cdot [\, e_{y,m} < d_{65} \,] $$ すなわち **「対象月末日が 40 歳前日以降、かつ 65 歳前日より前」** なら該当となります。 ### 検証例(生年月日 1986/4/15 のとき $d_{40}$ = 2026/4/14, $d_{65}$ = 2051/4/14) ```{list-table} :header-rows: 1 * - 対象月 - 月末日 - 介護該当 - 理由 * - 2026/3 - 2026/3/31 - FALSE - 月末 2026/3/31 < 40 歳前日 2026/4/14 * - 2026/4 - 2026/4/30 - **TRUE** - 月末 2026/4/30 ≥ 2026/4/14、かつ < 2051/4/14 * - 2051/3 - 2051/3/31 - TRUE - まだ 65 歳前日(2051/4/14)を超えていない * - 2051/4 - 2051/4/30 - **FALSE** - 月末 2051/4/30 ≥ 65 歳前日 2051/4/14 → 終了 ``` (kenpo-rate-dynamic)= ## 健保適用料率の動的合算 健康保険料率は **介護なし基本料率** $r_{\text{基本}}$ と **介護料率** $r_{\text{介護}}$ を分離して保持し、その月の介護該当フラグ $K$ で合算します。 $$ r_{\text{健保}} = r_{\text{基本}} + K \cdot r_{\text{介護}} $$ これにより、料率データには **分離した値を持ったまま** 月次の適用料率を年齢で自動切替できます。料率改定があっても両者は独立に管理できます。 ## 料率参照(時系列検索) 各料率は適用開始日 $s$ が変わるため、料率履歴 $R = \{(s_i, r_i)\}$ から「対象月以下で最も新しい開始日」のレコードを引きます。 対象月の月初日を $t = (y, m, 1)$ とすると、適用される料率インデックス $i^*$ は $$ i^* = \arg\max_{i} \, \{ s_i \mid s_i \le t \} $$ すなわち **適用開始日 $s_i$ が対象月以下である中で、最大の $s_i$ を持つエントリ** を採用します。料率履歴は時系列(昇順)で保持される前提です。 このルールにより、料率履歴に 1 行追加するだけで、新しい適用開始日以降の月次計算が自動で新料率に切り替わります。 (notification-grouping)= ## 納付額が通知額と一致する論理(告知書単位の合算丸め) 納入告知額の丸めは **保険料の種別ごと** ではなく **納入告知書(保険者)単位** で行います。協会けんぽ R8 料額表(東京支部)の脚注に次の規定があります。 > 納入告知書の保険料額は、被保険者個々の保険料を合算した金額になります。ただし、合算した金額に円未満の端数がある場合は、その端数を切り捨てた額となります。 すなわち **「合算してから 1 円未満切捨て」**(⌊Σ⌋)であり、種別ごとに切り捨ててから足す(Σ⌊⌋)ではありません。保険者は次の 2 つで、それぞれ別の告知書を発行します。 ```{list-table} :header-rows: 1 * - 告知書グループ $g$ - 含む保険料 - 全額の和(銭) $\to$ 告知額 $N_g$ * - 協会けんぽ - 健康保険料(介護込み) + 子ども・子育て支援金 - $N_{\text{協会}} = \lfloor T_{\text{健保}} + T_{\text{支援}} \rfloor$ * - 年金機構 - 厚生年金保険料 + 子ども・子育て拠出金 - $N_{\text{年金}} = \lfloor T_{\text{厚年}} + T_{\text{拠出}} \rfloor$ ``` 社員側はこれまでどおり折半額の欄ごとに「50 銭超切上げ」を適用した和、事業主側は告知額からの残額です。グループ $g$ について $X_g = \sum_{k \in g} x^k_e$、$Y_g = N_g - X_g$ とすると、納付額 $Z$ は ```{math} Z = \sum_g N_g = \sum_g (X_g + Y_g) = \text{通知額} ``` ```{warning} かつて本ドキュメントは「$Z = \sum_k \lfloor T_k \rfloor$(種別ごとに切捨ててから合算)が常に通知額と一致する」と記載していましたが、これは **誤り** でした。$\sum_k \lfloor T_k \rfloor$ と $\sum_g \lfloor \sum_{k \in g} T_k \rfloor$ は、**同一の告知書グループ内で銭端数を持つ保険料が 2 つ以上あり、その端数の和が 1 円以上になるとき** に食い違います。 具体的には **2026 年 5 月納付分から始まる子ども・子育て支援金**(労使折半・協会けんぽ告知)がこれに該当します。標準報酬月額 88,000 円・介護該当のとき、健保全額 10,093.6 円と支援金全額 202.4 円の銭端数 0.6 + 0.4 = 1.0 円が、種別ごとに切り捨てると丸ごと失われ、納付額が通知額より 1 円少なくなっていました。支援金導入前は協会けんぽ告知に銭端数を持つ保険料が健保しか無く、厚年全額は標準報酬月額(1,000 円単位)の性質上つねに整数円のため、種別丸めと合算丸めが偶然一致していました。 ``` 検証スクリプト `scripts/verify_payroll.py` は告知書単位の合算丸めで納付額を計算し、既知シナリオ(2026 年 4 月分 = 26,513 円、2026 年 5 月分 = 26,716 円 など)が公式の通知額と一致することを確認します。