2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

消費税 端数処理の研究

Last updated at Posted at 2025-06-28

消費税の端数処理で、整合性がとれない

  1. 本体価格に税率をかけ消費税を算出。そして税込価格(a)を算出。この税込価格(a)から、消費税・本体価格を逆算して算出しても、それらは一致する。しかし、この税込価格(a)には、算出されない数値がある。
  2. 値引きをしたり、税込み価格の商品を単純に足し算したりすることで、税込価格を最初に決め、それから本体価格(b)と消費税を算出することがある。この場合、算出した本体価格(b)から逆算して消費税・税込価格を算出すると、それらは一致しないことがある(1.で算出されない数値の税込価格を最初に決めた場合)。
  3. 2.の状態の整合性をとるには、適格請求書ごとに端数処理(切り下げ・四捨五入・切り上げ)を切り替える方法しかないように思える。しかし、その方法が、適格請求書への記載に適している分からない。

税務署に確認した。後述(2025-06-30)。

もっとも、解決すべき事柄でもないかもしれない。
この課題は、実務上は気にしなくても良いが、消費税の計算のシステム作成時には、留意しておく必要がある。

整合性のとれない例

消費税 - 高精度計算サイト

税込金額 49円、端数を四捨五入で計算
すると、税抜金額45円になる。
これを逆算して、
税抜金額45円、端数を四捨五入で計算
消費税が5円・税込金額50円となる。

image.png

image.png

実務上の解決方法

一度端数処理を行い、その整合性がとれない時は、別の端数処理を行う。
例えば、四捨五入を行い、それで整合性がとれない時は、切り捨てにする。

四捨五入、切り捨ての順

税込み価格 1円から10000円の間で、消費税を計算する時、四捨五入で端数処理を行い、整合性がとれない時は、切り捨てにする。

次の切り捨ての個数は、四捨五入の端数処理では整合性がとれなかった個数になる。

10%

個数
切り捨て 909
四捨五入 9091
総計 10000

8%

個数
切り捨て 741
四捨五入 9259
総計 10000

切り捨て、四捨五入の順

10%

個数
Floor 9091
Round 909
総計 10000

8%

個数
Floor 9260
Round 740
総計 10000

切り上げ、四捨五入の順

10%

個数
Ceiling 9090
Round 910
総計 10000

8%

個数
Ceiling 9259
Round 741
総計 10000

端数を四捨五入

本体価格と税率から算出

A 本体価格
B 本体価格の消費税 = (A × 税率)を、四捨五入
C 本体価格から税込価格 = A + B
D 税込価格から消費税 = C × 税率 ÷ ( 1 + 税率 )を、四捨五入
E 逆算した本体価格 = C - D

本体価格一致 AとEが一致するか をチェック
消費税一致 BとDが一致するか をチェック

本体価格(A)から消費税(B)を算出し、その税込価格(C)を算出する。
そして、その税込価格(C)から、逆算して、消費税(D)と本体価格(E)を算出する。
税率10%の時で、この算出方法だと、

  • 本体価格(AとE)は一致
  • 消費税(BとD)は一致
  • ただし、Cの税込価格5,16,27・・・(11ごと)は、算出されない。
A本体価格 B本体価格の消費税 C本体価格から税込価格 E逆算した本体価格 D税込価格から消費税 本体価格一致 消費税一致
1 0 1 1 0 TRUE TRUE
2 0 2 2 0 TRUE TRUE
3 0 3 3 0 TRUE TRUE
4 0 4 4 0 TRUE TRUE
5 1 6 5 1 TRUE TRUE
6 1 7 6 1 TRUE TRUE
7 1 8 7 1 TRUE TRUE
8 1 9 8 1 TRUE TRUE
9 1 10 9 1 TRUE TRUE
10 1 11 10 1 TRUE TRUE
11 1 12 11 1 TRUE TRUE
12 1 13 12 1 TRUE TRUE
13 1 14 13 1 TRUE TRUE
14 1 15 14 1 TRUE TRUE
15 2 17 15 2 TRUE TRUE
16 2 18 16 2 TRUE TRUE
17 2 19 17 2 TRUE TRUE
18 2 20 18 2 TRUE TRUE
19 2 21 19 2 TRUE TRUE
20 2 22 20 2 TRUE TRUE
21 2 23 21 2 TRUE TRUE
22 2 24 22 2 TRUE TRUE
23 2 25 23 2 TRUE TRUE
24 2 26 24 2 TRUE TRUE
25 3 28 25 3 TRUE TRUE
26 3 29 26 3 TRUE TRUE
27 3 30 27 3 TRUE TRUE
28 3 31 28 3 TRUE TRUE
29 3 32 29 3 TRUE TRUE
30 3 33 30 3 TRUE TRUE
31 3 34 31 3 TRUE TRUE
32 3 35 32 3 TRUE TRUE
33 3 36 33 3 TRUE TRUE
34 3 37 34 3 TRUE TRUE
35 4 39 35 4 TRUE TRUE
36 4 40 36 4 TRUE TRUE
37 4 41 37 4 TRUE TRUE
38 4 42 38 4 TRUE TRUE
39 4 43 39 4 TRUE TRUE
40 4 44 40 4 TRUE TRUE
41 4 45 41 4 TRUE TRUE
42 4 46 42 4 TRUE TRUE
43 4 47 43 4 TRUE TRUE
44 4 48 44 4 TRUE TRUE
45 5 50 45 5 TRUE TRUE
46 5 51 46 5 TRUE TRUE
47 5 52 47 5 TRUE TRUE
48 5 53 48 5 TRUE TRUE
49 5 54 49 5 TRUE TRUE
50 5 55 50 5 TRUE TRUE

税込価格と税率から算出

A 税込価格
B 税込価格の消費税 A × 税率 ÷ ( 1 + 税率 )を、四捨五入
C 税込価格から本体価格 A - B
D 本体価格から消費税 (C × 税率)を、四捨五入
E 逆算した税込価格 C + D

税込価格一致 AとEが一致するか をチェック
消費税一致 BとDが一致するか をチェック

税込価格(A)から消費税(B)を算出し、本体価格(C)を算出する。
そして、その本体価格(C)から、逆算して、消費税(D)と税込価格(E)を算出する。
税率10%の時で、この算出方法だと、

  • 税込価格(AとE)は不一致がある
  • 消費税価格(BとD)は不一致がある
  • Aの税込価格 5,16,27・・・(11ごと)、が不一致になる
A税込価格 B税込価格の消費税 C税込価格から本体価格 E逆算した税込価格 D本体価格から消費税 税込価格一致 消費税一致
1 0 1 1 0 TRUE TRUE
2 0 2 2 0 TRUE TRUE
3 0 3 3 0 TRUE TRUE
4 0 4 4 0 TRUE TRUE
5 0 5 6 1 FALSE FALSE
6 1 5 6 1 TRUE TRUE
7 1 6 7 1 TRUE TRUE
8 1 7 8 1 TRUE TRUE
9 1 8 9 1 TRUE TRUE
10 1 9 10 1 TRUE TRUE
11 1 10 11 1 TRUE TRUE
12 1 11 12 1 TRUE TRUE
13 1 12 13 1 TRUE TRUE
14 1 13 14 1 TRUE TRUE
15 1 14 15 1 TRUE TRUE
16 1 15 17 2 FALSE FALSE
17 2 15 17 2 TRUE TRUE
18 2 16 18 2 TRUE TRUE
19 2 17 19 2 TRUE TRUE
20 2 18 20 2 TRUE TRUE
21 2 19 21 2 TRUE TRUE
22 2 20 22 2 TRUE TRUE
23 2 21 23 2 TRUE TRUE
24 2 22 24 2 TRUE TRUE
25 2 23 25 2 TRUE TRUE
26 2 24 26 2 TRUE TRUE
27 2 25 28 3 FALSE FALSE
28 3 25 28 3 TRUE TRUE
29 3 26 29 3 TRUE TRUE
30 3 27 30 3 TRUE TRUE
31 3 28 31 3 TRUE TRUE
32 3 29 32 3 TRUE TRUE
33 3 30 33 3 TRUE TRUE
34 3 31 34 3 TRUE TRUE
35 3 32 35 3 TRUE TRUE
36 3 33 36 3 TRUE TRUE
37 3 34 37 3 TRUE TRUE
38 3 35 39 4 FALSE FALSE
39 4 35 39 4 TRUE TRUE
40 4 36 40 4 TRUE TRUE
41 4 37 41 4 TRUE TRUE
42 4 38 42 4 TRUE TRUE
43 4 39 43 4 TRUE TRUE
44 4 40 44 4 TRUE TRUE
45 4 41 45 4 TRUE TRUE
46 4 42 46 4 TRUE TRUE
47 4 43 47 4 TRUE TRUE
48 4 44 48 4 TRUE TRUE
49 4 45 50 5 FALSE FALSE
50 5 45 50 5 TRUE TRUE

切り捨て・切り上げも同様

端数を切り捨て・切り上げも、四捨五入と同じ。
本体価格と税率から算出した時は、逆算しても一致する。ただし、税込価格は、算出されない数値がある。
税込価格と税率から算出した時は、逆算した時、不一致がある。

参照

税率による違い

現在は、8%と10%だが、将来に税率が変更になった場合に備えて、1%~100%までにして、計算を行ってみた。

税率が100%の場合、税込価格(1円~10000円)の間で、整合性がどうしてもとれない(四捨五入・切り捨て・切り上げ、いずれも不可)ものが、5000個ある。
税率が100%以上の時は、整合性のとれない価格が出てくる。

確認した事柄

2025-6-30 三国税務署に確認
税務署の話(内部でも確認してもらったので、担当者だけの見解ではない)では、

  • 法律の主旨では、総額表示が大事
  • 適格請求書の端数処理は、そこまで定められていない

そのため、端数処理は発行者に任せられる。

適格請求書ごとに、消費税の端数処理を変更しても良いか?
例:
適格請求書の、消費税の端数処理は、通常は切り捨てを利用している。
しかし、ある適格請求書では、整合性をとるために、四捨五入にした。
→ 良いと確認。

適格請求書の、10%、8%それぞれの、消費税の端数処理を、別々にしても良いか?
例:
通常は、10%、8%ともに、切り捨てにしている。
しかし、ある適格請求書では、整合性をとるために、
10%は、切り捨て 税込420円 内消費税38円
8%は、四捨五入 税込580円 内消費税43円
総額1000円 内消費税81円
にする。
→ 良いと確認。

参考

No.6371 端数計算の「適格請求書に記載すべき消費税額等の端数について」
https://www.nta.go.jp/taxes/shiraberu/taxanswer/shohi/6371.htm

最後に

消費税を計算し一覧に出力するプログラムを作成したりして、研究に時間を費やした。
しかし、そもそも、端数処理を厳密にする必要があるのか? という疑問がある。

2025-6-30 追記

税務署の話だと、適格請求書は総額表示が大事で、消費税の端数処理は発行者に任せられているし、税務署としては気にしないようだ。従って、実務上は厳密にする必要は無い。

しかし、システム作成において、消費税を計算する上では留意しておく必要がある。

  • 税込価格から本体価格・消費税を算出し、その本体価格から消費税を逆算すると、消費税・税込価格が一致しない場合がある。

この解決方法としては

  • 気にしない。つまり、税込価格を最初に決めた場合は、税込価格から算出した本体価格・消費税を表記する。
    解決方法ではないかもしれないが、実務上はこれでOK。
  • あるいは、整合性をとれるように、適格請求書ごと(税別ごとに変更しても可)に、端数処理を変更する。

のどちらかになる。

消費税計算用のコード

namespace TaxCalculation;

public class TaxCalculationHelper
{
    /// <summary>
    /// 金額に対して消費税を計算します(四捨五入)
    /// </summary>
    /// <param name="amount">税抜金額</param>
    /// <param name="taxRate">消費税率(例: 0.10)</param>
    /// <returns>消費税額</returns>
    public static decimal CalculateConsumptionTaxRound(decimal amount, decimal taxRate = 0.10m)
    {
        return decimal.Round(amount * taxRate, 0, MidpointRounding.AwayFromZero);
    }

    /// <summary>
    /// 税込み金額から消費税額を計算します(四捨五入)
    /// </summary>
    /// <param name="amountWithTax">税込み金額</param>
    /// <param name="taxRate">消費税率(例: 0.10)</param>
    /// <returns>消費税額</returns>
    public static decimal CalculateTaxFromAmountWithTaxRound(decimal amountWithTax, decimal taxRate = 0.10m)
    {
        var tax = amountWithTax * taxRate / (1 + taxRate);
        return decimal.Round(tax, 0, MidpointRounding.AwayFromZero);
    }

    /// <summary>
    /// 金額に対して消費税を計算します(切り捨て)
    /// </summary>
    /// <param name="amount">税抜金額</param>
    /// <param name="taxRate">消費税率(例: 0.10)</param>
    /// <returns>消費税額</returns>
    public static decimal CalculateConsumptionTaxFloor(decimal amount, decimal taxRate = 0.10m)
    {
        return decimal.Floor(amount * taxRate);
    }

    /// <summary>
    /// 税込み金額から消費税額を計算します(切り捨て)
    /// </summary>
    /// <param name="amountWithTax">税込み金額</param>
    /// <param name="taxRate">消費税率(例: 0.10)</param>
    /// <returns>消費税額</returns>
    public static decimal CalculateTaxFromAmountWithTaxFloor(decimal amountWithTax, decimal taxRate = 0.10m)
    {
        var tax = amountWithTax * taxRate / (1 + taxRate);
        return decimal.Floor(tax);
    }

    /// <summary>
    /// 金額に対して消費税を計算します(切り上げ)
    /// </summary>
    /// <param name="amount">税抜金額</param>
    /// <param name="taxRate">消費税率(例: 0.10)</param>
    /// <returns>消費税額</returns>
    public static decimal CalculateConsumptionTaxCeiling(decimal amount, decimal taxRate = 0.10m)
    {
        return decimal.Ceiling(amount * taxRate);
    }

    /// <summary>
    /// 税込み金額から消費税額を計算します(切り上げ)
    /// </summary>
    /// <param name="amountWithTax">税込み金額</param>
    /// <param name="taxRate">消費税率(例: 0.10)</param>
    /// <returns>消費税額</returns>
    public static decimal CalculateTaxFromAmountWithTaxCeiling(decimal amountWithTax, decimal taxRate = 0.10m)
    {
        var tax = amountWithTax * taxRate / (1 + taxRate);
        return decimal.Ceiling(tax);
    }

    #region 税込み価格から算出

    /// <summary>
    /// 整合性がとれる消費税を算出します。
    /// </summary>
    /// <param name="amountWithTax">税込価格</param>
    /// <param name="taxCalculationType">消費税の計算方法</param>
    /// <param name="taxRate">税率</param>
    /// <returns>消費税。消費税を計算した方法(切り捨て・四捨五入・切り上げ)</returns>
    /// <exception cref="Exception">整合性がとれない時は、エラー</exception>
    public static (decimal, TaxCalculatedTypes) CalculateTaxFromAmountWithTax(decimal amountWithTax, TaxCalculationTypes taxCalculationType, decimal taxRate = 0.10m)
    {
        switch (taxCalculationType)
        {
            case TaxCalculationTypes.Floor:
                return (CalculateTaxFromAmountWithTaxFloor(amountWithTax, taxRate), TaxCalculatedTypes.Floor);

            case TaxCalculationTypes.Round:
                return (CalculateTaxFromAmountWithTaxRound(amountWithTax, taxRate), TaxCalculatedTypes.Round);

            case TaxCalculationTypes.Ceiling:
                return (CalculateTaxFromAmountWithTaxCeiling(amountWithTax, taxRate), TaxCalculatedTypes.Ceiling);

            case TaxCalculationTypes.FloorOrRound:
                {
                    var (isSameFloor, taxFloor) = CheckTaxFloor(amountWithTax, taxRate);
                    if (isSameFloor) return (taxFloor, TaxCalculatedTypes.Floor);

                    var (isSameRound, taxRound) = CheckTaxRound(amountWithTax, taxRate);
                    if (isSameRound) return (taxRound, TaxCalculatedTypes.Round);

                    var (isSameCeiling, taxCeiling) = CheckTaxCeiling(amountWithTax, taxRate);
                    if (isSameCeiling) return (taxCeiling, TaxCalculatedTypes.Ceiling);
                }
                break;

            case TaxCalculationTypes.FloorOrCeiling:
                {
                    var (isSameFloor, taxFloor) = CheckTaxFloor(amountWithTax, taxRate);
                    if (isSameFloor) return (taxFloor, TaxCalculatedTypes.Floor);

                    var (isSameCeiling, taxCeiling) = CheckTaxCeiling(amountWithTax, taxRate);
                    if (isSameCeiling) return (taxCeiling, TaxCalculatedTypes.Ceiling);

                    var (isSameRound, taxRound) = CheckTaxRound(amountWithTax, taxRate);
                    if (isSameRound) return (taxRound, TaxCalculatedTypes.Round);
                }
                break;

            case TaxCalculationTypes.RoundOrFloor:
                {
                    var (isSameRound, taxRound) = CheckTaxRound(amountWithTax, taxRate);
                    if (isSameRound) return (taxRound, TaxCalculatedTypes.Round);

                    var (isSameFloor, taxFloor) = CheckTaxFloor(amountWithTax, taxRate);
                    if (isSameFloor) return (taxFloor, TaxCalculatedTypes.Floor);

                    var (isSameCeiling, taxCeiling) = CheckTaxCeiling(amountWithTax, taxRate);
                    if (isSameCeiling) return (taxCeiling, TaxCalculatedTypes.Ceiling);
                }
                break;

            case TaxCalculationTypes.RoundOrCeiling:
                {
                    var (isSameRound, taxRound) = CheckTaxRound(amountWithTax, taxRate);
                    if (isSameRound) return (taxRound, TaxCalculatedTypes.Round);

                    var (isSameCeiling, taxCeiling) = CheckTaxCeiling(amountWithTax, taxRate);
                    if (isSameCeiling) return (taxCeiling, TaxCalculatedTypes.Ceiling);

                    var (isSameFloor, taxFloor) = CheckTaxFloor(amountWithTax, taxRate);
                    if (isSameFloor) return (taxFloor, TaxCalculatedTypes.Floor);
                }
                break;

            case TaxCalculationTypes.CeilingOrFloor:
                {
                    var (isSameCeiling, taxCeiling) = CheckTaxCeiling(amountWithTax, taxRate);
                    if (isSameCeiling) return (taxCeiling, TaxCalculatedTypes.Ceiling);

                    var (isSameFloor, taxFloor) = CheckTaxFloor(amountWithTax, taxRate);
                    if (isSameFloor) return (taxFloor, TaxCalculatedTypes.Floor);

                    var (isSameRound, taxRound) = CheckTaxRound(amountWithTax, taxRate);
                    if (isSameRound) return (taxRound, TaxCalculatedTypes.Round);
                }
                break;

            case TaxCalculationTypes.CeilingOrRound:
                {
                    var (isSameCeiling, taxCeiling) = CheckTaxCeiling(amountWithTax, taxRate);
                    if (isSameCeiling) return (taxCeiling, TaxCalculatedTypes.Ceiling);

                    var (isSameRound, taxRound) = CheckTaxRound(amountWithTax, taxRate);
                    if (isSameRound) return (taxRound, TaxCalculatedTypes.Round);

                    var (isSameFloor, taxFloor) = CheckTaxFloor(amountWithTax, taxRate);
                    if (isSameFloor) return (taxFloor, TaxCalculatedTypes.Floor);
                }
                break;

            default:
                break;
        }
        throw new Exception("整合性のとれる消費税を算出できませんでした。");
    }

    /// <summary>
    ///  税込価格の消費税を四捨五入で算出します。そして、逆算した税込価格が一致するかを確認します。
    /// </summary>
    /// <param name="amountWithTax"></param>
    /// <param name="taxRate"></param>
    /// <returns></returns>
    public static (bool, decimal) CheckTaxRound(decimal amountWithTax, decimal taxRate = 0.10m)
    {
        var 税込価格の消費税 = TaxCalculationHelper.CalculateTaxFromAmountWithTaxRound(amountWithTax, taxRate);
        var 税込価格から本体価格 = amountWithTax - 税込価格の消費税;

        var 逆算した消費税 = TaxCalculationHelper.CalculateConsumptionTaxRound(税込価格から本体価格, taxRate);
        var 逆算した税込価格 = 税込価格から本体価格 + 逆算した消費税;
        var 税込価格一致 = amountWithTax == 逆算した税込価格;

        return (税込価格一致, 税込価格の消費税);
    }

    /// <summary>
    /// 税込価格の消費税を切り捨てで算出します。そして、逆算した税込価格が一致するかを確認します。
    /// </summary>
    /// <param name="amountWithTax"></param>
    /// <param name="taxRate"></param>
    /// <returns></returns>
    public static (bool, decimal) CheckTaxFloor(decimal amountWithTax, decimal taxRate = 0.10m)
    {
        var 税込価格の消費税 = TaxCalculationHelper.CalculateTaxFromAmountWithTaxFloor(amountWithTax, taxRate);
        var 税込価格から本体価格 = amountWithTax - 税込価格の消費税;

        var 逆算した消費税 = TaxCalculationHelper.CalculateConsumptionTaxFloor(税込価格から本体価格, taxRate);
        var 逆算した税込価格 = 税込価格から本体価格 + 逆算した消費税;
        var 税込価格一致 = amountWithTax == 逆算した税込価格;

        return (税込価格一致, 税込価格の消費税);
    }

    /// <summary>
    /// 税込価格の消費税を切り上げで算出します。そして、逆算した税込価格が一致するかを確認します。
    /// </summary>
    /// <param name="amountWithTax"></param>
    /// <param name="taxRate"></param>
    /// <returns></returns>
    public static (bool, decimal) CheckTaxCeiling(decimal amountWithTax, decimal taxRate = 0.10m)
    {
        var 税込価格の消費税 = TaxCalculationHelper.CalculateTaxFromAmountWithTaxCeiling(amountWithTax, taxRate);
        var 税込価格から本体価格 = amountWithTax - 税込価格の消費税;

        var 逆算した消費税 = TaxCalculationHelper.CalculateConsumptionTaxCeiling(税込価格から本体価格, taxRate);
        var 逆算した税込価格 = 税込価格から本体価格 + 逆算した消費税;
        var 税込価格一致 = amountWithTax == 逆算した税込価格;

        return (税込価格一致, 税込価格の消費税);
    }

    #endregion

    /// <summary>
    /// 消費税を算出した時、利用した方法
    /// </summary>
    public enum TaxCalculatedTypes
    {
        /// <summary>
        /// 四捨五入
        /// </summary>
        Round,

        /// <summary>
        /// 切り捨て
        /// </summary>
        Floor,

        /// <summary>
        /// 切り上げ
        /// </summary>
        Ceiling,
    }

    /// <summary>
    /// 消費税の計算方法
    /// </summary>
    public enum TaxCalculationTypes
    {
        /// <summary>
        /// 切り捨てを行う。
        /// </summary>
        Floor,

        /// <summary>
        /// 四捨五入を行う。
        /// </summary>
        Round,

        /// <summary>
        /// 切り上げを行う。
        /// </summary>
        Ceiling,

        /// <summary>
        /// 切り捨てを行い、不整合の時は四捨五入、さらに不整合の時は切り上げを行う。
        /// </summary>
        FloorOrRound,

        /// <summary>
        /// 切り捨てを行い、不整合の時は切り上げ、さらに不整合の時は四捨五入を行う。
        /// </summary>
        FloorOrCeiling,

        /// <summary>
        /// 四捨五入を行い、不整合の時は切り捨て、さらに不整合の時は切り上げを行う。
        /// </summary>
        RoundOrFloor,

        /// <summary>
        /// 四捨五入を行い、不整合の時は切り上げ、さらに不整合の時は切り捨てを行う。
        /// </summary>
        RoundOrCeiling,

        /// <summary>
        /// 切り上げを行い、不整合の時は切り捨て、さらに不整合の時は四捨五入を行う。
        /// </summary>
        CeilingOrFloor,

        /// <summary>
        /// 切り上げを行い、不整合の時は四捨五入、さらに不整合の時は切り捨てを行う。
        /// </summary>
        CeilingOrRound,
    }
}
2
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?