跳转到内容

模組:PythonScript/Librarys/Decimal

维基百科,自由的百科全书
-- Module:PythonScript/Librarys/Decimal
-- 純 Lua BigFloat 引擎與 Python decimal 標準庫 (基於 BigInt 10^7 基底、1000 limbs 截斷與延遲載入架構)
local DecimalMod = {}

local PyClass = require("Module:PythonScript/Class")
local Runtime = require("Module:PythonScript/Runtime")
local MathCore = require("Module:PythonScript/Runtime/Cmath")
local BigInt = MathCore.BigInt

-- 集中管理內部狀態與方法,嚴格將頂層 local 變數控制在 6 個以內
local D = {
    BASE = 10000000,         -- 10^7 (每個 limb 7 位十進位數)
    DIGITS_PER_LIMB = 7,
    MAX_LIMBS = 1000,        -- 有效數字上限:1000 個 limb (7000 位有效十進位數)
    DEFAULT_FRAC_LIMBS = 10, -- 預設小數點後計算精度:10 個 limb (70 位小數)
    initialized = false,
    cache = {},
    current_context = nil,
    ln10_cache = nil,
    ln10_prec = 0
}

-- ==========================================
-- 1. 基礎判斷與正規化核心 (BigFloat Engine)
-- ==========================================
function D.is_none(v)
    return v == nil or (type(v) == "table" and v.__class and v.__class.__name == "NoneType")
end

function D.is_decimal(v)
    return type(v) == "table" and v.__type == "instance" and v.__dict and v.__dict._is_decimal == true
end

function D.get_calc_frac_limbs(extra)
    local prec = (D.current_context and D.current_context.__dict and D.current_context.__dict.prec) or 28
    local needed = math.ceil(prec / 7) + 2
    local res = math.max(D.DEFAULT_FRAC_LIMBS, needed) + (extra or 0)
    if res > D.MAX_LIMBS then res = D.MAX_LIMBS end
    return res
end

function D.raise_dec(exc_name, msg)
    D.ensure_init()
    local exc_cls = D.cache[exc_name] or Runtime.builtins.ArithmeticError
    if D.current_context and D.current_context.__dict and D.current_context.__dict.flags then
        local flags = D.current_context.__dict.flags
        for _, p in ipairs(flags.pairs or {}) do
            if type(p.key) == "table" and p.key.__name == exc_name then p.value = 1 end
        end
    end
    Runtime.raise(exc_cls, msg or exc_name)
end

-- 正規化 BigFloat 結構: { sign = 1|-1, limbs = {...}, limb_exp = int, special = nil|"Inf"|"NaN"|"sNaN" }
function D.normalize_raw(sign, limbs, limb_exp, special)
    sign = (sign and sign < 0) and -1 or 1
    if special then return { sign = sign, limbs = {0}, limb_exp = 0, special = special } end
    if not limbs or #limbs == 0 then return { sign = 1, limbs = {0}, limb_exp = 0 } end

    local clean = {}
    for i = 1, #limbs do clean[i] = limbs[i] or 0 end
    while #clean > 1 and clean[#clean] == 0 do table.remove(clean) end
    if #clean == 1 and clean[1] == 0 then return { sign = 1, limbs = {0}, limb_exp = 0 } end

    limb_exp = limb_exp or 0

    -- 若 limb_exp > 0 且展開後不超過 1000 個 limb,直接補齊低位 0 limb 使整數之 limb_exp 歸零
    if limb_exp > 0 and (#clean + limb_exp) <= D.MAX_LIMBS then
        local padded = {}
        for i = 1, limb_exp do padded[i] = 0 end
        for i = 1, #clean do padded[limb_exp + i] = clean[i] end
        clean = padded
        limb_exp = 0
    end

    -- 有效數字上限截斷:當 limb 數超過 1000 時,捨棄低位元 limb
    if #clean > D.MAX_LIMBS then
        local drop = #clean - D.MAX_LIMBS
        local sliced = {}
        for i = drop + 1, #clean do sliced[i - drop] = clean[i] end
        clean = sliced
        limb_exp = limb_exp + drop
        while #clean > 1 and clean[#clean] == 0 do table.remove(clean) end
        if #clean == 1 and clean[1] == 0 then return { sign = 1, limbs = {0}, limb_exp = 0 } end
    end

    -- 清除小數點後末尾全為 0 的 limb,確保所有整數皆滿足 limb_exp >= 0
    if limb_exp < 0 then
        local strip_cnt = 0
        while strip_cnt < (#clean - 1) and (limb_exp + strip_cnt) < 0 and clean[strip_cnt + 1] == 0 do
            strip_cnt = strip_cnt + 1
        end
        if strip_cnt > 0 then
            local sliced = {}
            for i = strip_cnt + 1, #clean do sliced[i - strip_cnt] = clean[i] end
            clean = sliced
            limb_exp = limb_exp + strip_cnt
        end
    end

    return { sign = sign, limbs = clean, limb_exp = limb_exp }
end

function D.make_decimal_from_raw(raw, fixed_scale)
    D.ensure_init()
    local inst = PyClass.make_instance(D.DecimalClass)
    inst.__dict._is_decimal = true
    inst.__dict.sign = raw.sign or 1
    inst.__dict.limbs = raw.limbs or {0}
    inst.__dict.limb_exp = raw.limb_exp or 0
    inst.__dict.special = raw.special
    inst.__dict._fixed_scale = fixed_scale
    return inst
end

function D.is_zero_raw(raw)
    return not raw.special and #raw.limbs == 1 and raw.limbs[1] == 0
end

-- ==========================================
-- 2. 十進位字串解析與輸出轉換
-- ==========================================
function D.from_digits_and_exp(sign, digits, dec_exp)
    digits = digits:gsub("^0+", "")
    if digits == "" then return D.normalize_raw(1, {0}, 0) end
    local trail_zeros = digits:match("(0+)$")
    if trail_zeros and #trail_zeros < #digits then
        digits = digits:sub(1, #digits - #trail_zeros)
        dec_exp = dec_exp + #trail_zeros
    end

    local max_digits = D.MAX_LIMBS * 7
    if #digits > max_digits then
        local drop_d = #digits - max_digits
        digits = digits:sub(1, max_digits)
        dec_exp = dec_exp + drop_d
    end

    local limb_exp = math.floor(dec_exp / 7)
    local rem_zeros = dec_exp - limb_exp * 7
    if rem_zeros > 0 then digits = digits .. string.rep("0", rem_zeros) end

    local limbs = BigInt.to_limbs(digits)
    return D.normalize_raw(sign, limbs, limb_exp)
end

function D.parse_string(str)
    if type(str) ~= "string" then D.raise_dec("ConversionSyntax", "Invalid literal for Decimal") end
    local s = str:match("^%s*(.-)%s*$")
    if s == "" then D.raise_dec("ConversionSyntax", "Invalid literal for Decimal: ''") end

    local sign = 1
    if s:sub(1, 1) == "-" then sign = -1; s = s:sub(2)
    elseif s:sub(1, 1) == "+" then s = s:sub(2) end

    local low = s:lower()
    if low == "inf" or low == "infinity" then return D.normalize_raw(sign, {0}, 0, "Inf")
    elseif low == "nan" or low:match("^nan%d*$") then return D.normalize_raw(sign, {0}, 0, "NaN")
    elseif low == "snan" or low:match("^snan%d*$") then return D.normalize_raw(sign, {0}, 0, "sNaN") end

    if s:find("__", 1, true) or s:sub(1, 1) == "_" or s:sub(-1) == "_" then
        D.raise_dec("ConversionSyntax", "Invalid literal for Decimal: '" .. str .. "'")
    end
    s = s:gsub("(%d)_(%d)", "%1%2"):gsub("(%d)_(%d)", "%1%2")

    local mantissa, exp_part = s:match("^([^eE]+)[eE]([%.%+%-]?%d+)$")
    local e10 = 0
    if mantissa then
        local exp_num = tonumber(exp_part)
        if not exp_num or math.floor(exp_num) ~= exp_num then
            D.raise_dec("ConversionSyntax", "Invalid literal for Decimal: '" .. str .. "'")
        end
        e10 = exp_num
        s = mantissa
    end

    local int_p, frac_p
    if s:find("%.", 1, false) then
        int_p, frac_p = s:match("^(%d*)%.(%d*)$")
        if not int_p or (int_p == "" and frac_p == "") then
            D.raise_dec("ConversionSyntax", "Invalid literal for Decimal: '" .. str .. "'")
        end
    else
        if not s:match("^%d+$") then D.raise_dec("ConversionSyntax", "Invalid literal for Decimal: '" .. str .. "'") end
        int_p, frac_p = s, ""
    end

    return D.from_digits_and_exp(sign, int_p .. frac_p, e10 - #frac_p)
end

function D.coerce_to_raw(val, allow_float)
    if D.is_none(val) then
        return D.normalize_raw(1, {0}, 0)
    elseif D.is_decimal(val) then
        return { sign = val.__dict.sign, limbs = val.__dict.limbs, limb_exp = val.__dict.limb_exp, special = val.__dict.special }
    elseif type(val) == "boolean" then
        return D.normalize_raw(1, { val and 1 or 0 }, 0)
    elseif type(val) == "number" then
        if not allow_float and math.floor(val) ~= val then
            Runtime.raise("TypeError", "Cannot implicitly convert float to Decimal. Use Decimal.from_float() or Decimal(str(x))")
        end
        if val ~= val then return D.normalize_raw(1, {0}, 0, "NaN")
        elseif val == math.huge then return D.normalize_raw(1, {0}, 0, "Inf")
        elseif val == -math.huge then return D.normalize_raw(-1, {0}, 0, "Inf")
        elseif math.floor(val) == val and math.abs(val) <= 9007199254740990 then
            if val == 0 then return D.normalize_raw(1, {0}, 0) end
            return D.normalize_raw(val < 0 and -1 or 1, BigInt.to_limbs(math.abs(val)), 0)
        else
            return D.parse_string(string.format("%.17g", val))
        end
    elseif type(val) == "table" and val.__type == "int" then
        return D.normalize_raw(val.sign, val.limbs, 0)
    elseif type(val) == "string" then
        return D.parse_string(val)
    elseif type(val) == "table" and (val.__type == "tuple" or val.__type == "list" or (val.__dict and val.__dict._is_dec_tuple)) then
        local elts = val.elements or (val.__dict and val.__dict._elts)
        if not elts or #elts ~= 3 then Runtime.raise("ValueError", "Invalid tuple size for Decimal construction") end
        local s_bit, d_seq, exp_v = elts[1], elts[2], elts[3]
        if (s_bit ~= 0 and s_bit ~= 1) or type(d_seq) ~= "table" then
            Runtime.raise("ValueError", "Invalid tuple for Decimal construction")
        end
        local sign = (s_bit == 1) and -1 or 1
        if exp_v == "F" then return D.normalize_raw(sign, {0}, 0, "Inf")
        elseif exp_v == "n" then return D.normalize_raw(sign, {0}, 0, "NaN")
        elseif exp_v == "N" then return D.normalize_raw(sign, {0}, 0, "sNaN") end
        local d_elts = d_seq.elements or {}
        local d_chars = {}
        for i = 1, #d_elts do
            local dg = d_elts[i]
            if type(dg) ~= "number" or dg < 0 or dg > 9 or math.floor(dg) ~= dg then
                Runtime.raise("ValueError", "Invalid digit in Decimal tuple")
            end
            d_chars[i] = tostring(dg)
        end
        local d_str = (#d_chars > 0) and table.concat(d_chars) or "0"
        return D.from_digits_and_exp(sign, d_str, tonumber(exp_v) or 0)
    end
    return nil
end

function D.to_digits_and_exp(raw)
    if D.is_zero_raw(raw) then return "0", 0 end
    local raw_digits = BigInt.to_string(1, raw.limbs)
    local dec_exp = raw.limb_exp * 7
    local trail_zeros = raw_digits:match("(0+)$")
    if trail_zeros and #trail_zeros < #raw_digits then
        raw_digits = raw_digits:sub(1, #raw_digits - #trail_zeros)
        dec_exp = dec_exp + #trail_zeros
    end
    return raw_digits, dec_exp
end

function D.round_to_exp(sign, raw_digits, dec_exp, target_exp, rounding_mode)
    if dec_exp >= target_exp then return raw_digits, dec_exp end
    rounding_mode = rounding_mode or (D.current_context and D.current_context.__dict.rounding) or "ROUND_HALF_EVEN"
    local drop_count = target_exp - dec_exp
    local kept_str, first_drop, rest_nonzero, any_nonzero, last_kept

    if drop_count < #raw_digits then
        kept_str = raw_digits:sub(1, #raw_digits - drop_count)
        local dropped_str = raw_digits:sub(#raw_digits - drop_count + 1)
        first_drop = tonumber(dropped_str:sub(1, 1)) or 0
        rest_nonzero = dropped_str:sub(2):find("[1-9]") ~= nil
        any_nonzero = (first_drop > 0) or rest_nonzero
        last_kept = tonumber(kept_str:sub(-1)) or 0
    elseif drop_count == #raw_digits then
        kept_str = "0"
        first_drop = tonumber(raw_digits:sub(1, 1)) or 0
        rest_nonzero = raw_digits:sub(2):find("[1-9]") ~= nil
        any_nonzero = (first_drop > 0) or rest_nonzero
        last_kept = 0
    else
        kept_str = "0"
        first_drop = 0
        any_nonzero = (raw_digits ~= "0")
        rest_nonzero = any_nonzero
        last_kept = 0
    end

    local inc = false
    if rounding_mode == "ROUND_DOWN" then inc = false
    elseif rounding_mode == "ROUND_UP" then inc = any_nonzero
    elseif rounding_mode == "ROUND_CEILING" then inc = any_nonzero and (sign > 0)
    elseif rounding_mode == "ROUND_FLOOR" then inc = any_nonzero and (sign < 0)
    elseif rounding_mode == "ROUND_HALF_UP" then inc = (first_drop >= 5)
    elseif rounding_mode == "ROUND_HALF_DOWN" then inc = (first_drop > 5) or (first_drop == 5 and rest_nonzero)
    elseif rounding_mode == "ROUND_05UP" then inc = any_nonzero and (last_kept == 0 or last_kept == 5)
    else inc = (first_drop > 5) or (first_drop == 5 and (rest_nonzero or (last_kept % 2 == 1))) end

    if inc then
        if kept_str == "0" then kept_str = "1"
        else kept_str = BigInt.to_string(1, BigInt.add_limbs(BigInt.to_limbs(kept_str), {1})) end
    end
    if kept_str == "0" then return "0", target_exp end
    return kept_str, target_exp
end

function D.format_decimal(self, apply_prec, sci_style)
    local d = self.__dict
    if d.special == "Inf" then return (d.sign < 0 and "-Infinity" or "Infinity")
    elseif d.special == "NaN" then return (d.sign < 0 and "-NaN" or "NaN")
    elseif d.special == "sNaN" then return (d.sign < 0 and "-sNaN" or "sNaN") end

    local sign_prefix = (d.sign < 0 and not D.is_zero_raw(d)) and "-" or ""
    local raw_digits, dec_exp = D.to_digits_and_exp(d)

    if d._fixed_scale ~= nil and not sci_style then
        local scale = d._fixed_scale
        local target_exp = -scale
        local rounding = (D.current_context and D.current_context.__dict.rounding) or "ROUND_HALF_EVEN"
        raw_digits, dec_exp = D.round_to_exp(d.sign, raw_digits, dec_exp, target_exp, rounding)
        if raw_digits == "0" then sign_prefix = "" end
        if scale <= 0 then return sign_prefix .. raw_digits .. string.rep("0", math.max(0, dec_exp)) end
        if dec_exp > target_exp then
            raw_digits = raw_digits .. string.rep("0", dec_exp - target_exp)
            dec_exp = target_exp
        end
        if #raw_digits > scale then
            return sign_prefix .. raw_digits:sub(1, #raw_digits - scale) .. "." .. raw_digits:sub(#raw_digits - scale + 1)
        else
            return sign_prefix .. "0." .. string.rep("0", scale - #raw_digits) .. raw_digits
        end
    end

    if raw_digits == "0" then return "0" end

    if sci_style then
        local prec = (D.current_context and D.current_context.__dict.prec) or 28
        local rounding = (D.current_context and D.current_context.__dict.rounding) or "ROUND_HALF_EVEN"
        if #raw_digits > prec then
            raw_digits, dec_exp = D.round_to_exp(d.sign, raw_digits, dec_exp, dec_exp + (#raw_digits - prec), rounding)
            local z = raw_digits:match("(0+)$")
            if z and #z < #raw_digits then raw_digits = raw_digits:sub(1, #raw_digits - #z); dec_exp = dec_exp + #z end
        end
        local adj_exp = dec_exp + #raw_digits - 1
        local e_char = (D.current_context and D.current_context.__dict.capitals == 0) and "e" or "E"
        if #raw_digits == 1 then
            return sign_prefix .. raw_digits .. e_char .. (adj_exp >= 0 and "+" or "") .. tostring(adj_exp)
        else
            return sign_prefix .. raw_digits:sub(1, 1) .. "." .. raw_digits:sub(2) .. e_char .. (adj_exp >= 0 and "+" or "") .. tostring(adj_exp)
        end
    end

    if dec_exp >= 0 then
        if (#raw_digits + dec_exp) <= (D.MAX_LIMBS * 7) then
            return sign_prefix .. raw_digits .. string.rep("0", dec_exp)
        else
            return D.format_decimal(self, apply_prec, true)
        end
    end

    if apply_prec ~= false then
        local prec = (D.current_context and D.current_context.__dict.prec) or 28
        local rounding = (D.current_context and D.current_context.__dict.rounding) or "ROUND_HALF_EVEN"
        if (-dec_exp) > prec then
            raw_digits, dec_exp = D.round_to_exp(d.sign, raw_digits, dec_exp, -prec, rounding)
            if raw_digits == "0" then return "0" end
            local z = raw_digits:match("(0+)$")
            if z and #z < #raw_digits then raw_digits = raw_digits:sub(1, #raw_digits - #z); dec_exp = dec_exp + #z end
        end
    end

    if dec_exp >= 0 then return sign_prefix .. raw_digits .. string.rep("0", dec_exp) end

    local frac_len = -dec_exp
    if #raw_digits > frac_len then
        return sign_prefix .. raw_digits:sub(1, #raw_digits - frac_len) .. "." .. raw_digits:sub(#raw_digits - frac_len + 1)
    else
        return sign_prefix .. "0." .. string.rep("0", frac_len - #raw_digits) .. raw_digits
    end
end

-- ==========================================
-- 3. 四則運算與比較核心 (BigFloat Operations)
-- ==========================================
function D.cmp_raw(a, b)
    if a.special == "NaN" or a.special == "sNaN" or b.special == "NaN" or b.special == "sNaN" then return nil end
    if a.special == "Inf" or b.special == "Inf" then
        if a.special == "Inf" and b.special == "Inf" then
            if a.sign == b.sign then return 0 end
            return a.sign < b.sign and -1 or 1
        elseif a.special == "Inf" then return a.sign > 0 and 1 or -1
        else return b.sign > 0 and -1 or 1 end
    end

    local za, zb = D.is_zero_raw(a), D.is_zero_raw(b)
    if za and zb then return 0 end
    if za then return b.sign > 0 and -1 or 1 end
    if zb then return a.sign > 0 and 1 or -1 end
    if a.sign ~= b.sign then return a.sign < b.sign and -1 or 1 end

    local top_a = #a.limbs + a.limb_exp
    local top_b = #b.limbs + b.limb_exp
    local mag_cmp = 0
    if top_a ~= top_b then
        mag_cmp = (top_a < top_b) and -1 or 1
    else
        local i, j = #a.limbs, #b.limbs
        while i >= 1 or j >= 1 do
            local va = (i >= 1) and a.limbs[i] or 0
            local vb = (j >= 1) and b.limbs[j] or 0
            if va ~= vb then mag_cmp = (va < vb) and -1 or 1; break end
            i = i - 1; j = j - 1
        end
    end
    return (a.sign > 0) and mag_cmp or -mag_cmp
end

function D.align_limbs(a, b)
    if a.limb_exp == b.limb_exp then return a.limbs, b.limbs, a.limb_exp end
    local high, low, swapped = a, b, false
    if a.limb_exp < b.limb_exp then high, low, swapped = b, a, true end
    local diff = high.limb_exp - low.limb_exp
    local low_limbs = low.limbs
    local base_exp = low.limb_exp

    local total_span = #high.limbs + diff
    if total_span > (D.MAX_LIMBS + 5) then
        local trim = total_span - (D.MAX_LIMBS + 5)
        if trim >= #low_limbs then
            low_limbs = {0}; diff = 0; base_exp = high.limb_exp
        else
            local sliced = {}
            for i = trim + 1, #low_limbs do sliced[i - trim] = low_limbs[i] end
            low_limbs = sliced; diff = diff - trim; base_exp = base_exp + trim
        end
    end

    local high_shifted = {}
    for i = 1, diff do high_shifted[i] = 0 end
    for i = 1, #high.limbs do high_shifted[diff + i] = high.limbs[i] end

    if swapped then return low_limbs, high_shifted, base_exp
    else return high_shifted, low_limbs, base_exp end
end

function D.add_raw(a, b)
    if a.special == "sNaN" or b.special == "sNaN" then D.raise_dec("InvalidOperation", "operation on sNaN") end
    if a.special == "NaN" or b.special == "NaN" then return D.normalize_raw(1, {0}, 0, "NaN") end
    if a.special == "Inf" or b.special == "Inf" then
        if a.special == "Inf" and b.special == "Inf" then
            if a.sign ~= b.sign then D.raise_dec("InvalidOperation", "-INF + INF") end
            return D.normalize_raw(a.sign, {0}, 0, "Inf")
        end
        return D.normalize_raw(a.special == "Inf" and a.sign or b.sign, {0}, 0, "Inf")
    end

    if D.is_zero_raw(a) then return D.normalize_raw(b.sign, b.limbs, b.limb_exp) end
    if D.is_zero_raw(b) then return D.normalize_raw(a.sign, a.limbs, a.limb_exp) end

    local la, lb, common_exp = D.align_limbs(a, b)
    local res_sign, res_limbs
    if a.sign == b.sign then
        res_sign = a.sign; res_limbs = BigInt.add_limbs(la, lb)
    else
        local cmp = BigInt.cmp_limbs(la, lb)
        if cmp == 0 then return D.normalize_raw(1, {0}, 0)
        elseif cmp > 0 then res_sign = a.sign; res_limbs = BigInt.sub_limbs(la, lb)
        else res_sign = b.sign; res_limbs = BigInt.sub_limbs(lb, la) end
    end
    return D.normalize_raw(res_sign, res_limbs, common_exp)
end

function D.sub_raw(a, b)
    return D.add_raw(a, { sign = -b.sign, limbs = b.limbs, limb_exp = b.limb_exp, special = b.special })
end

function D.mul_raw(a, b)
    if a.special == "sNaN" or b.special == "sNaN" then D.raise_dec("InvalidOperation", "operation on sNaN") end
    if a.special == "NaN" or b.special == "NaN" then return D.normalize_raw(1, {0}, 0, "NaN") end
    local res_sign = a.sign * b.sign
    if a.special == "Inf" or b.special == "Inf" then
        if D.is_zero_raw(a) or D.is_zero_raw(b) then D.raise_dec("InvalidOperation", "0 * INF") end
        return D.normalize_raw(res_sign, {0}, 0, "Inf")
    end
    if D.is_zero_raw(a) or D.is_zero_raw(b) then return D.normalize_raw(1, {0}, 0) end
    return D.normalize_raw(res_sign, BigInt.mul_limbs(a.limbs, b.limbs), a.limb_exp + b.limb_exp)
end

function D.div_raw(a, b, extra_limbs)
    if a.special == "sNaN" or b.special == "sNaN" then D.raise_dec("InvalidOperation", "operation on sNaN") end
    if a.special == "NaN" or b.special == "NaN" then return D.normalize_raw(1, {0}, 0, "NaN") end
    local res_sign = a.sign * b.sign
    if a.special == "Inf" and b.special == "Inf" then D.raise_dec("DivisionUndefined", "INF / INF")
    elseif D.is_zero_raw(a) and D.is_zero_raw(b) then D.raise_dec("DivisionUndefined", "0 / 0")
    elseif D.is_zero_raw(b) then D.raise_dec("DivisionByZero", "division by zero")
    elseif b.special == "Inf" then return D.normalize_raw(1, {0}, 0)
    elseif a.special == "Inf" then return D.normalize_raw(res_sign, {0}, 0, "Inf")
    elseif D.is_zero_raw(a) then return D.normalize_raw(1, {0}, 0) end

        local frac_target = D.get_calc_frac_limbs(extra_limbs)
    local q, r = BigInt.divmod_limbs(a.limbs, b.limbs)
    local cur_limb_exp = a.limb_exp - b.limb_exp
    local sig_limbs = (#q == 1 and q[1] == 0) and 0 or #q

    while not (#r == 1 and r[1] == 0) and (cur_limb_exp > -frac_target or sig_limbs < frac_target) and sig_limbs < D.MAX_LIMBS do
        table.insert(r, 1, 0)
        local lq
        lq, r = BigInt.divmod_limbs(r, b.limbs)
        local digit_limb = lq[1] or 0
        if sig_limbs == 0 then
            if digit_limb ~= 0 then q = { digit_limb }; sig_limbs = 1 end
        else
            table.insert(q, 1, digit_limb)
            sig_limbs = sig_limbs + 1
        end
        cur_limb_exp = cur_limb_exp - 1
    end

    return D.normalize_raw(res_sign, q, cur_limb_exp)
end


function D.trunc_raw(a)
    if a.special then D.raise_dec("InvalidOperation", "cannot truncate Infinity or NaN") end
    if a.limb_exp >= 0 or D.is_zero_raw(a) then return D.normalize_raw(a.sign, a.limbs, a.limb_exp) end
    local drop = -a.limb_exp
    if drop >= #a.limbs then return D.normalize_raw(1, {0}, 0) end
    local int_limbs = {}
    for i = drop + 1, #a.limbs do int_limbs[i - drop] = a.limbs[i] end
    return D.normalize_raw(a.sign, int_limbs, 0)
end

function D.divmod_raw(a, b)
    if D.is_zero_raw(b) then
        if D.is_zero_raw(a) then D.raise_dec("DivisionUndefined", "0 / 0") end
        D.raise_dec("DivisionByZero", "division by zero")
    end
    if a.special or b.special then
        if a.special == "Inf" or (b.special and b.special ~= "Inf") then
            D.raise_dec("InvalidOperation", "divmod on non-finite Decimal")
        end
        if b.special == "Inf" then return D.normalize_raw(1, {0}, 0), D.normalize_raw(a.sign, a.limbs, a.limb_exp) end
    end
    local q_full = D.div_raw(a, b, 2)
    local q_int = D.trunc_raw(q_full)
    local rem = D.sub_raw(a, D.mul_raw(b, q_int))
    return q_int, rem
end

-- ==========================================
-- 4. 進階數學函式 (sqrt, ln, log10, exp, pow)
-- ==========================================
function D.sqrt_raw(a, extra_limbs)
    if a.special == "sNaN" then D.raise_dec("InvalidOperation", "sqrt on sNaN") end
    if a.special == "NaN" then return D.normalize_raw(1, {0}, 0, "NaN") end
    if a.sign < 0 and not D.is_zero_raw(a) then D.raise_dec("InvalidOperation", "sqrt of negative Decimal") end
    if a.special == "Inf" then return D.normalize_raw(1, {0}, 0, "Inf") end
    if D.is_zero_raw(a) then return D.normalize_raw(1, {0}, 0) end

    local work_limbs = D.get_calc_frac_limbs(extra_limbs)
    local target_exp = -work_limbs
    if math.floor(a.limb_exp / 2) < target_exp then target_exp = math.floor(a.limb_exp / 2) - work_limbs end
    local shift = a.limb_exp - 2 * target_exp
    local n_limbs = {}
    if shift >= 0 then
        for i = 1, shift do n_limbs[i] = 0 end
        for i = 1, #a.limbs do n_limbs[shift + i] = a.limbs[i] end
    else
        local drop = -shift
        for i = drop + 1, #a.limbs do n_limbs[i - drop] = a.limbs[i] end
        if #n_limbs == 0 then return D.normalize_raw(1, {0}, 0) end
    end

    local n_len = #n_limbs
    local half_len = math.ceil(n_len / 2)
    local x = {}
    for i = 1, half_len do x[i] = 0 end
    if n_len % 2 == 1 then
        local top = n_limbs[n_len]
        local nxt = (n_len >= 2) and n_limbs[n_len - 1] or 0
        local nxt2 = (n_len >= 3) and n_limbs[n_len - 2] or 0
        local comb = (top * D.BASE + nxt) * D.BASE + nxt2
        local sq = math.floor(math.sqrt(comb))
        x[half_len] = math.max(1, math.floor(sq / D.BASE))
        if half_len >= 2 then x[half_len - 1] = sq % D.BASE end
    else
        local top = n_limbs[n_len] * D.BASE + n_limbs[n_len - 1]
        local nxt = (n_len >= 3) and n_limbs[n_len - 2] or 0
        local nxt2 = (n_len >= 4) and n_limbs[n_len - 3] or 0
        local comb = (top * D.BASE + nxt) * D.BASE + nxt2
        local sq = math.floor(math.sqrt(comb))
        x[half_len] = math.max(1, math.floor(sq / D.BASE))
        if half_len >= 2 then x[half_len - 1] = sq % D.BASE end
    end

    local two_limb = {2}
    for _ = 1, 14 do
        local q = BigInt.divmod_limbs(n_limbs, x)
        local nx = BigInt.divmod_limbs(BigInt.add_limbs(x, q), two_limb)
        local cmp = BigInt.cmp_limbs(nx, x)
        if cmp == 0 then x = nx; break
        elseif cmp > 0 then
            local diff = BigInt.sub_limbs(nx, x)
            if #diff == 1 and diff[1] <= 1 then x = nx; break end
        else
            local diff = BigInt.sub_limbs(x, nx)
            if #diff == 1 and diff[1] <= 1 then x = nx; break end
        end
        x = nx
    end

    return D.normalize_raw(1, x, target_exp)
end

function D.ln_unit_raw(m_raw, work_limbs)
    local one = D.normalize_raw(1, {1}, 0)
    if D.cmp_raw(m_raw, one) == 0 then return D.normalize_raw(1, {0}, 0) end
    local cur = m_raw
    local k_roots = 5
    for _ = 1, k_roots do cur = D.sqrt_raw(cur, 4) end

    local y = D.div_raw(D.sub_raw(cur, one), D.add_raw(cur, one), 4)
    local y2 = D.mul_raw(y, y)
    local term, sum = y, y
    local cutoff_exp = -(work_limbs + 3)

    for n = 3, 99, 2 do
        term = D.mul_raw(term, y2)
        if D.is_zero_raw(term) or (#term.limbs + term.limb_exp) < cutoff_exp then break end
        sum = D.add_raw(sum, D.div_raw(term, D.normalize_raw(1, {n}, 0), 4))
    end

    return D.mul_raw(sum, D.normalize_raw(1, { 2 * (2 ^ k_roots) }, 0))
end

function D.get_ln10_raw(work_limbs)
    if D.ln10_cache and D.ln10_prec >= work_limbs then return D.ln10_cache end
    local ln2 = D.ln_unit_raw(D.normalize_raw(1, {2}, 0), work_limbs + 2)
    local ln5 = D.ln_unit_raw(D.normalize_raw(1, {5}, 0), work_limbs + 2)
    D.ln10_cache = D.add_raw(ln2, ln5)
    D.ln10_prec = work_limbs
    return D.ln10_cache
end

function D.ln_raw(a)
    if a.special == "sNaN" then D.raise_dec("InvalidOperation", "ln on sNaN") end
    if a.special == "NaN" then return D.normalize_raw(1, {0}, 0, "NaN") end
    if D.is_zero_raw(a) then return D.normalize_raw(-1, {0}, 0, "Inf") end
    if a.sign < 0 then D.raise_dec("InvalidOperation", "ln of negative Decimal") end
    if a.special == "Inf" then return D.normalize_raw(1, {0}, 0, "Inf") end

    local raw_digits, dec_exp = D.to_digits_and_exp(a)
    local k = (#raw_digits - 1) + dec_exp
    local m_raw = D.from_digits_and_exp(1, raw_digits, -(#raw_digits - 1))
    local work_limbs = D.get_calc_frac_limbs(3)
    local ln_m = D.ln_unit_raw(m_raw, work_limbs)

    if k == 0 then return ln_m end
    local ln10 = D.get_ln10_raw(work_limbs)
    local k_raw = D.normalize_raw(k < 0 and -1 or 1, BigInt.to_limbs(math.abs(k)), 0)
    return D.add_raw(ln_m, D.mul_raw(k_raw, ln10))
end

function D.log10_raw(a)
    if a.special == "sNaN" then D.raise_dec("InvalidOperation", "log10 on sNaN") end
    if a.special == "NaN" then return D.normalize_raw(1, {0}, 0, "NaN") end
    if D.is_zero_raw(a) then return D.normalize_raw(-1, {0}, 0, "Inf") end
    if a.sign < 0 then D.raise_dec("InvalidOperation", "log10 of negative Decimal") end
    if a.special == "Inf" then return D.normalize_raw(1, {0}, 0, "Inf") end

    local raw_digits, dec_exp = D.to_digits_and_exp(a)
    local k = (#raw_digits - 1) + dec_exp
    if raw_digits == "1" then
        return D.normalize_raw(k < 0 and -1 or 1, BigInt.to_limbs(math.abs(k)), 0)
    end
    local work_limbs = D.get_calc_frac_limbs(3)
    local m_raw = D.from_digits_and_exp(1, raw_digits, -(#raw_digits - 1))
    local ln_m = D.ln_unit_raw(m_raw, work_limbs)
    local ln10 = D.get_ln10_raw(work_limbs)
    local log10_m = D.div_raw(ln_m, ln10, 2)
    local k_raw = D.normalize_raw(k < 0 and -1 or 1, BigInt.to_limbs(math.abs(k)), 0)
    return D.add_raw(log10_m, k_raw)
end

function D.exp_raw(a)
    if a.special == "sNaN" then D.raise_dec("InvalidOperation", "exp on sNaN") end
    if a.special == "NaN" then return D.normalize_raw(1, {0}, 0, "NaN") end
    if D.is_zero_raw(a) then return D.normalize_raw(1, {1}, 0) end
    if a.special == "Inf" then
        if a.sign > 0 then return D.normalize_raw(1, {0}, 0, "Inf")
        else return D.normalize_raw(1, {0}, 0) end
    end

    local work_limbs = D.get_calc_frac_limbs(3)
    local ln10 = D.get_ln10_raw(work_limbs)
    local q_int, r = D.divmod_raw(a, ln10)
    local k10 = tonumber(BigInt.to_string(q_int.sign, q_int.limbs)) or 0

    local scale_pow = 6
    local x = D.div_raw(r, D.normalize_raw(1, { 2 ^ scale_pow }, 0), 4)
    local one = D.normalize_raw(1, {1}, 0)
    local sum, term = one, one
    local cutoff_exp = -(work_limbs + 3)

    for n = 1, 60 do
        term = D.div_raw(D.mul_raw(term, x), D.normalize_raw(1, {n}, 0), 4)
        if D.is_zero_raw(term) or (#term.limbs + term.limb_exp) < cutoff_exp then break end
        sum = D.add_raw(sum, term)
    end

    for _ = 1, scale_pow do sum = D.mul_raw(sum, sum) end
    if k10 ~= 0 then sum = D.mul_raw(sum, D.from_digits_and_exp(1, "1", k10)) end
    return sum
end

function D.pow_raw(a, b)
    if a.special == "sNaN" or b.special == "sNaN" then D.raise_dec("InvalidOperation", "pow on sNaN") end
    if a.special == "NaN" or b.special == "NaN" then return D.normalize_raw(1, {0}, 0, "NaN") end
    if D.is_zero_raw(a) and D.is_zero_raw(b) then D.raise_dec("InvalidOperation", "0 ** 0") end
    if D.is_zero_raw(b) then return D.normalize_raw(1, {1}, 0) end
    if D.is_zero_raw(a) then
        if b.sign < 0 then D.raise_dec("DivisionByZero", "0 ** negative") end
        return D.normalize_raw(1, {0}, 0)
    end

    if not b.special and b.limb_exp >= 0 then
        local exp_num = tonumber(BigInt.to_string(1, b.limbs))
        if exp_num and exp_num <= 100000 then
            local k = math.floor(exp_num)
            local res = D.normalize_raw(1, {1}, 0)
            local base = D.normalize_raw(a.sign, a.limbs, a.limb_exp)
            while k > 0 do
                if k % 2 == 1 then res = D.mul_raw(res, base) end
                k = math.floor(k / 2)
                if k > 0 then base = D.mul_raw(base, base) end
            end
            if b.sign < 0 then return D.div_raw(D.normalize_raw(1, {1}, 0), res) end
            return res
        end
    end

    if a.sign < 0 then D.raise_dec("InvalidOperation", "negative Decimal cannot be raised to a fractional power") end
    return D.exp_raw(D.mul_raw(D.ln_raw(a), b))
end

-- ==========================================
-- 5. 供 math 模組呼叫的橋接輔助函式
-- ==========================================
function DecimalMod.to_number(dec)
    local d = dec.__dict
    if d.special == "Inf" then return d.sign < 0 and -math.huge or math.huge
    elseif d.special == "NaN" or d.special == "sNaN" then return 0/0 end
    local raw_digits, dec_exp = D.to_digits_and_exp(d)
    if raw_digits == "0" then return 0.0 end
    if #raw_digits > 20 then
        local drop = #raw_digits - 20
        raw_digits = raw_digits:sub(1, 20)
        dec_exp = dec_exp + drop
    end
    local num = tonumber((d.sign < 0 and "-" or "") .. raw_digits .. "e" .. tostring(dec_exp))
    return num or (d.sign < 0 and -math.huge or math.huge)
end

function DecimalMod.raw_to_py_int(raw)
    local int_raw = D.trunc_raw(raw)
    if D.is_zero_raw(int_raw) then return 0 end
    local s = BigInt.to_string(int_raw.sign, int_raw.limbs)
    if int_raw.limb_exp > 0 then s = s .. string.rep("0", int_raw.limb_exp * 7) end
    return Runtime.builtins.int.__call({s})
end

function DecimalMod.math_trunc(dec) return DecimalMod.raw_to_py_int(dec.__dict) end

function DecimalMod.math_floor(dec)
    local d = dec.__dict
    local t = D.trunc_raw(d)
    if d.limb_exp < 0 and d.sign < 0 then t = D.sub_raw(t, D.normalize_raw(1, {1}, 0)) end
    return DecimalMod.raw_to_py_int(t)
end

function DecimalMod.math_ceil(dec)
    local d = dec.__dict
    local t = D.trunc_raw(d)
    if d.limb_exp < 0 and d.sign > 0 then t = D.add_raw(t, D.normalize_raw(1, {1}, 0)) end
    return DecimalMod.raw_to_py_int(t)
end

function DecimalMod.math_isqrt(val)
    local raw = D.coerce_to_raw(val, true)
    if raw.sign < 0 then Runtime.raise("ValueError", "isqrt() argument must be nonnegative") end
    return DecimalMod.raw_to_py_int(D.sqrt_raw(D.trunc_raw(raw)))
end

local function compute_adjusted_ln(val)
    local raw = D.coerce_to_raw(val, true)
    if raw.special == "NaN" or raw.special == "sNaN" then return 0/0 end
    if D.is_zero_raw(raw) or raw.sign < 0 then Runtime.raise("ValueError", "math domain error") end
    if raw.special == "Inf" then return math.huge end
    local raw_digits, dec_exp = D.to_digits_and_exp(raw)
    local k = (#raw_digits - 1) + dec_exp
    local m_num = tonumber(raw_digits:sub(1, 1) .. "." .. raw_digits:sub(2, 18)) or 1.0
    return math.log(m_num) + k * math.log(10), m_num, k, (raw_digits == "1")
end

function DecimalMod.math_log(x, base)
    local lnx = compute_adjusted_ln(x)
    if base ~= nil and not D.is_none(base) then return lnx / compute_adjusted_ln(base) end
    return lnx
end

function DecimalMod.math_log10(x)
    local _, m_num, k, is_pow10 = compute_adjusted_ln(x)
    if is_pow10 then return k * 1.0 end
    return math.log10(m_num) + k
end

function DecimalMod.math_log2(x)
    return compute_adjusted_ln(x) / math.log(2)
end

-- ==========================================
-- 6. 延遲初始化 Decimal、Context 與例外類別
-- ==========================================
function D.ensure_init()
    if D.initialized then return end
    D.initialized = true

    local B = Runtime.builtins
    local C = D.cache

    -- [A] 捨入常數與模組常數
    local round_modes = {
        "ROUND_CEILING", "ROUND_DOWN", "ROUND_FLOOR", "ROUND_HALF_DOWN",
        "ROUND_HALF_EVEN", "ROUND_HALF_UP", "ROUND_UP", "ROUND_05UP"
    }
    for _, rm in ipairs(round_modes) do C[rm] = rm end

    C.MAX_PREC = D.MAX_LIMBS * 7
    C.MAX_EMAX = 999999999
    C.MIN_EMIN = -999999999
    C.MIN_ETINY = -1999999997
    C.HAVE_THREADS = false
    C.HAVE_CONTEXTVAR = false
    C.IEEE_CONTEXT_MAX_BITS = 512
    C.__version__ = "1.70"
    C.__libmpdec_version__ = "2.5.1"

    -- [B] Decimal 例外繼承樹
    local function make_dec_exc(name, bases)
        local cls = PyClass.make_class(name, bases, {})
        cls.__dict["__module__"] = "decimal"
        C[name] = cls
        return cls
    end

    local DecimalException = make_dec_exc("DecimalException", { B.ArithmeticError })
    make_dec_exc("Clamped", { DecimalException })
    local InvalidOperation = make_dec_exc("InvalidOperation", { DecimalException })
    make_dec_exc("ConversionSyntax", { InvalidOperation })
    make_dec_exc("DivisionImpossible", { InvalidOperation })
    make_dec_exc("InvalidContext", { InvalidOperation })
    make_dec_exc("DivisionByZero", { DecimalException, B.ZeroDivisionError })
    make_dec_exc("DivisionUndefined", { InvalidOperation, B.ZeroDivisionError })
    local Inexact = make_dec_exc("Inexact", { DecimalException })
    local Rounded = make_dec_exc("Rounded", { DecimalException })
    local Subnormal = make_dec_exc("Subnormal", { DecimalException })
    make_dec_exc("Overflow", { Inexact, Rounded })
    make_dec_exc("Underflow", { Inexact, Rounded, Subnormal })
    make_dec_exc("FloatOperation", { DecimalException, B.TypeError })

    -- [C] DecimalTuple 類別
    local dt_dict = {
        __init__ = { __type = "builtin_method", __call = function(a, kw)
            local self = a[1]
            local s = (a[2] ~= nil and a[2]) or (kw and kw.sign) or 0
            local dg = (a[3] ~= nil and a[3]) or (kw and kw.digits) or { __type = "tuple", elements = {0} }
            local ex = (a[4] ~= nil and a[4]) or (kw and kw.exponent) or 0
            if type(dg) == "table" and dg.__type == "list" then dg = { __type = "tuple", elements = dg.elements } end
            self.__dict._is_dec_tuple = true
            self.__dict.sign = s
            self.__dict.digits = dg
            self.__dict.exponent = ex
            self.__dict._elts = { s, dg, ex }
            return nil
        end },
        __getitem__ = { __type = "builtin_method", __call = function(a)
            local self, idx = a[1], a[2]
            if type(idx) == "number" then
                if idx < 0 then idx = 3 + idx end
                local v = self.__dict._elts[idx + 1]
                if v ~= nil then return v end
            end
            Runtime.raise("IndexError", "tuple index out of range")
        end },
        __len__ = { __type = "builtin_method", __call = function() return 3 end },
        __iter__ = { __type = "builtin_method", __call = function(a)
            return B.iter({ { __type = "tuple", elements = a[1].__dict._elts } })
        end },
        __eq__ = { __type = "builtin_method", __call = function(a)
            local self, other = a[1], a[2]
            local other_elts = (type(other) == "table") and (other.elements or (other.__dict and other.__dict._elts))
            if not other_elts or #other_elts ~= 3 then return false end
            return require("Module:PythonScript/Evaluator/Utils").py_eq(
                { __type = "tuple", elements = self.__dict._elts },
                { __type = "tuple", elements = other_elts }
            )
        end },
        __repr__ = { __type = "builtin_method", __call = function(a)
            local d = a[1].__dict
            return string.format("DecimalTuple(sign=%s, digits=%s, exponent=%s)",
                B.repr({d.sign}), B.repr({d.digits}), B.repr({d.exponent}))
        end }
    }
    dt_dict.__str__ = dt_dict.__repr__
    C.DecimalTuple = PyClass.make_class("DecimalTuple", {}, dt_dict)
    C.DecimalTuple.__dict["__module__"] = "decimal"

    -- [D] Decimal 主類別與方法庫
    local function bin_op(self, other, fn)
        local rb = D.coerce_to_raw(other, false)
        if not rb then return B.NotImplemented end
        return D.make_decimal_from_raw(fn(self.__dict, rb))
    end

    local function rbin_op(self, left, fn)
        local ra = D.coerce_to_raw(left, false)
        if not ra then return B.NotImplemented end
        return D.make_decimal_from_raw(fn(ra, self.__dict))
    end

    local dec_dict = {
        __new__ = { __type = "staticmethod", __func = { __type = "builtin_method", __name = "__new__", __call = function(a)
            local cls = a[1]
            local val = (a[2] ~= nil) and a[2] or 0
            local raw = D.coerce_to_raw(val, true)
            if not raw then Runtime.raise("TypeError", "Cannot convert " .. tostring(val) .. " to Decimal") end
            local inst = D.make_decimal_from_raw(raw)
            inst.__class = cls
            return inst
        end } },
        __init__ = { __type = "builtin_method", __name = "__init__", __call = function() return nil end },
        from_float = { __type = "classmethod", __func = { __type = "builtin_method", __name = "from_float", __call = function(a)
            local cls, f = a[1], a[2]
            if type(f) == "boolean" then f = f and 1 or 0 end
            if type(f) ~= "number" and not (type(f) == "table" and f.__type == "int") then
                Runtime.raise("TypeError", "argument must be int or float")
            end
            local inst = D.make_decimal_from_raw(D.coerce_to_raw(f, true))
            inst.__class = cls
            return inst
        end } },

        -- 字串、型別轉換與格式化
        __str__ = { __type = "builtin_method", __call = function(a) return D.format_decimal(a[1], true, false) end },
        __repr__ = { __type = "builtin_method", __call = function(a) return "Decimal('" .. D.format_decimal(a[1], true, false) .. "')" end },
        __format__ = { __type = "builtin_method", __call = function(a)
            local self, spec = a[1], a[2] or ""
            if spec == "" then return D.format_decimal(self, true, false) end
            local dot_prec, ftype = spec:match("^.*%.(%d+)([fFeEgG%%]?)$")
            if dot_prec and (ftype == "f" or ftype == "F" or ftype == "") then
                local n = tonumber(dot_prec)
                local copy = D.make_decimal_from_raw(self.__dict, n)
                return D.format_decimal(copy, false, false)
            end
            return B.format({ DecimalMod.to_number(self), spec })
        end },
        __bool__ = { __type = "builtin_method", __call = function(a) return not D.is_zero_raw(a[1].__dict) end },
        __int__ = { __type = "builtin_method", __call = function(a) return DecimalMod.raw_to_py_int(a[1].__dict) end },
        __trunc__ = { __type = "builtin_method", __call = function(a) return DecimalMod.raw_to_py_int(a[1].__dict) end },
        __float__ = { __type = "builtin_method", __call = function(a) return DecimalMod.to_number(a[1]) end },
        __hash__ = { __type = "builtin_method", __call = function(a)
            local self = a[1]
            if self.__dict.special == "NaN" or self.__dict.special == "sNaN" then
                Runtime.raise("TypeError", "Cannot hash a NaN value")
            end
            return B.hash({ DecimalMod.to_number(self) })
        end },
        __round__ = { __type = "builtin_method", __call = function(a)
            local self, ndigits = a[1], a[2]
            local d = self.__dict
            if D.is_none(ndigits) then
                local raw_digits, dec_exp = D.to_digits_and_exp(d)
                local r_digits, r_exp = D.round_to_exp(d.sign, raw_digits, dec_exp, 0, "ROUND_HALF_EVEN")
                return DecimalMod.raw_to_py_int(D.from_digits_and_exp(d.sign, r_digits, r_exp))
            end
            local n = tonumber(ndigits) or 0
            local raw_digits, dec_exp = D.to_digits_and_exp(d)
            local r_digits, r_exp = D.round_to_exp(d.sign, raw_digits, dec_exp, -n, "ROUND_HALF_EVEN")
            return D.make_decimal_from_raw(D.from_digits_and_exp(d.sign, r_digits, r_exp), n > 0 and n or nil)
        end },

        -- 一元與二元算術運算
        __pos__ = { __type = "builtin_method", __call = function(a) return D.make_decimal_from_raw(a[1].__dict) end },
        __neg__ = { __type = "builtin_method", __call = function(a)
            local d = a[1].__dict
            if D.is_zero_raw(d) then return D.make_decimal_from_raw(d) end
            return D.make_decimal_from_raw({ sign = -d.sign, limbs = d.limbs, limb_exp = d.limb_exp, special = d.special })
        end },
        __abs__ = { __type = "builtin_method", __call = function(a)
            local d = a[1].__dict
            return D.make_decimal_from_raw({ sign = 1, limbs = d.limbs, limb_exp = d.limb_exp, special = d.special })
        end },
        __add__ = { __type = "builtin_method", __call = function(a) return bin_op(a[1], a[2], D.add_raw) end },
        __radd__ = { __type = "builtin_method", __call = function(a) return rbin_op(a[1], a[2], D.add_raw) end },
        __sub__ = { __type = "builtin_method", __call = function(a) return bin_op(a[1], a[2], D.sub_raw) end },
        __rsub__ = { __type = "builtin_method", __call = function(a) return rbin_op(a[1], a[2], D.sub_raw) end },
        __mul__ = { __type = "builtin_method", __call = function(a) return bin_op(a[1], a[2], D.mul_raw) end },
        __rmul__ = { __type = "builtin_method", __call = function(a) return rbin_op(a[1], a[2], D.mul_raw) end },
        __truediv__ = { __type = "builtin_method", __call = function(a) return bin_op(a[1], a[2], D.div_raw) end },
        __rtruediv__ = { __type = "builtin_method", __call = function(a) return rbin_op(a[1], a[2], D.div_raw) end },
        __floordiv__ = { __type = "builtin_method", __call = function(a)
            local rb = D.coerce_to_raw(a[2], false); if not rb then return B.NotImplemented end
            local q, _ = D.divmod_raw(a[1].__dict, rb)
            return D.make_decimal_from_raw(q)
        end },
        __rfloordiv__ = { __type = "builtin_method", __call = function(a)
            local ra = D.coerce_to_raw(a[2], false); if not ra then return B.NotImplemented end
            local q, _ = D.divmod_raw(ra, a[1].__dict)
            return D.make_decimal_from_raw(q)
        end },
        __mod__ = { __type = "builtin_method", __call = function(a)
            local rb = D.coerce_to_raw(a[2], false); if not rb then return B.NotImplemented end
            local _, r = D.divmod_raw(a[1].__dict, rb)
            return D.make_decimal_from_raw(r)
        end },
        __rmod__ = { __type = "builtin_method", __call = function(a)
            local ra = D.coerce_to_raw(a[2], false); if not ra then return B.NotImplemented end
            local _, r = D.divmod_raw(ra, a[1].__dict)
            return D.make_decimal_from_raw(r)
        end },
        __divmod__ = { __type = "builtin_method", __call = function(a)
            local rb = D.coerce_to_raw(a[2], false); if not rb then return B.NotImplemented end
            local q, r = D.divmod_raw(a[1].__dict, rb)
            return { __type = "tuple", elements = { D.make_decimal_from_raw(q), D.make_decimal_from_raw(r) } }
        end },
        __rdivmod__ = { __type = "builtin_method", __call = function(a)
            local ra = D.coerce_to_raw(a[2], false); if not ra then return B.NotImplemented end
            local q, r = D.divmod_raw(ra, a[1].__dict)
            return { __type = "tuple", elements = { D.make_decimal_from_raw(q), D.make_decimal_from_raw(r) } }
        end },
        __pow__ = { __type = "builtin_method", __call = function(a) return bin_op(a[1], a[2], D.pow_raw) end },
        __rpow__ = { __type = "builtin_method", __call = function(a) return rbin_op(a[1], a[2], D.pow_raw) end },

        -- 比較運算
        __eq__ = { __type = "builtin_method", __call = function(a)
            local rb = D.coerce_to_raw(a[2], true)
            if not rb then return false end
            local c = D.cmp_raw(a[1].__dict, rb)
            return c == 0
        end },
        __ne__ = { __type = "builtin_method", __call = function(a)
            local rb = D.coerce_to_raw(a[2], true)
            if not rb then return true end
            local c = D.cmp_raw(a[1].__dict, rb)
            return c ~= 0
        end },
        __lt__ = { __type = "builtin_method", __call = function(a)
            local rb = D.coerce_to_raw(a[2], true)
            if not rb then Runtime.raise("TypeError", "'<' not supported between Decimal and " .. type(a[2])) end
            local c = D.cmp_raw(a[1].__dict, rb)
            if c == nil then D.raise_dec("InvalidOperation", "comparison involving NaN") end
            return c < 0
        end },
        __le__ = { __type = "builtin_method", __call = function(a)
            local rb = D.coerce_to_raw(a[2], true)
            if not rb then Runtime.raise("TypeError", "'<=' not supported") end
            local c = D.cmp_raw(a[1].__dict, rb)
            if c == nil then D.raise_dec("InvalidOperation", "comparison involving NaN") end
            return c <= 0
        end },
        __gt__ = { __type = "builtin_method", __call = function(a)
            local rb = D.coerce_to_raw(a[2], true)
            if not rb then Runtime.raise("TypeError", "'>' not supported") end
            local c = D.cmp_raw(a[1].__dict, rb)
            if c == nil then D.raise_dec("InvalidOperation", "comparison involving NaN") end
            return c > 0
        end },
        __ge__ = { __type = "builtin_method", __call = function(a)
            local rb = D.coerce_to_raw(a[2], true)
            if not rb then Runtime.raise("TypeError", "'>=' not supported") end
            local c = D.cmp_raw(a[1].__dict, rb)
            if c == nil then D.raise_dec("InvalidOperation", "comparison involving NaN") end
            return c >= 0
        end },

        -- Decimal 專屬數學與工具方法
        sqrt = { __type = "builtin_method", __call = function(a) return D.make_decimal_from_raw(D.sqrt_raw(a[1].__dict)) end },
        ln = { __type = "builtin_method", __call = function(a) return D.make_decimal_from_raw(D.ln_raw(a[1].__dict)) end },
        log10 = { __type = "builtin_method", __call = function(a) return D.make_decimal_from_raw(D.log10_raw(a[1].__dict)) end },
        exp = { __type = "builtin_method", __call = function(a) return D.make_decimal_from_raw(D.exp_raw(a[1].__dict)) end },
        logb = { __type = "builtin_method", __call = function(a)
            local d = a[1].__dict
            if D.is_zero_raw(d) then D.raise_dec("DivisionByZero", "logb of 0") end
            if d.special == "Inf" then return D.make_decimal_from_raw(D.normalize_raw(1, {0}, 0, "Inf")) end
            if d.special then return D.make_decimal_from_raw(D.normalize_raw(1, {0}, 0, "NaN")) end
            local raw_digits, dec_exp = D.to_digits_and_exp(d)
            local adj = (#raw_digits - 1) + dec_exp
            return D.make_decimal_from_raw(D.coerce_to_raw(adj, true))
        end },
        adjusted = { __type = "builtin_method", __call = function(a)
            local d = a[1].__dict
            if d.special or D.is_zero_raw(d) then return 0 end
            local raw_digits, dec_exp = D.to_digits_and_exp(d)
            return (#raw_digits - 1) + dec_exp
        end },
        quantize = { __type = "builtin_method", __call = function(a, kw)
            local self, exp_arg = a[1], a[2]
            local rounding = (a[3] ~= nil and a[3]) or (kw and kw.rounding) or (D.current_context and D.current_context.__dict.rounding) or "ROUND_HALF_EVEN"
            local exp_raw = D.coerce_to_raw(exp_arg, false)
            if not exp_raw then Runtime.raise("TypeError", "quantize() first argument must be Decimal") end
            local scale = 0
            if D.is_decimal(exp_arg) and exp_arg.__dict._fixed_scale ~= nil then
                scale = exp_arg.__dict._fixed_scale
            elseif type(exp_arg) == "string" and exp_arg:find("%.", 1, false) then
                local _, fp = exp_arg:match("^(.-)%.(.*)$")
                scale = fp and #fp or 0
            else
                local _, de = D.to_digits_and_exp(exp_raw)
                scale = -de
            end
            local d = self.__dict
            local raw_digits, dec_exp = D.to_digits_and_exp(d)
            local r_digits, r_exp = D.round_to_exp(d.sign, raw_digits, dec_exp, -scale, rounding)
            return D.make_decimal_from_raw(D.from_digits_and_exp(d.sign, r_digits, r_exp), scale)
        end },
        normalize = { __type = "builtin_method", __call = function(a)
            local d = a[1].__dict
            return D.make_decimal_from_raw(D.normalize_raw(d.sign, d.limbs, d.limb_exp, d.special))
        end },
        to_integral_value = { __type = "builtin_method", __call = function(a, kw)
            local self = a[1]
            local rounding = (a[2] ~= nil and a[2]) or (kw and kw.rounding) or (D.current_context and D.current_context.__dict.rounding) or "ROUND_HALF_EVEN"
            local d = self.__dict
            if d.special then return D.make_decimal_from_raw(d) end
            local raw_digits, dec_exp = D.to_digits_and_exp(d)
            local r_digits, r_exp = D.round_to_exp(d.sign, raw_digits, dec_exp, 0, rounding)
            return D.make_decimal_from_raw(D.from_digits_and_exp(d.sign, r_digits, r_exp))
        end },
        to_eng_string = { __type = "builtin_method", __call = function(a) return D.format_decimal(a[1], true, false) end },
        as_tuple = { __type = "builtin_method", __call = function(a)
            local d = a[1].__dict
            local s_bit = (d.sign < 0) and 1 or 0
            if d.special == "Inf" then
                return require("Module:PythonScript/Evaluator").invoke(C.DecimalTuple, { s_bit, { __type = "tuple", elements = {0} }, "F" }, {})
            elseif d.special == "NaN" then
                return require("Module:PythonScript/Evaluator").invoke(C.DecimalTuple, { s_bit, { __type = "tuple", elements = {} }, "n" }, {})
            elseif d.special == "sNaN" then
                return require("Module:PythonScript/Evaluator").invoke(C.DecimalTuple, { s_bit, { __type = "tuple", elements = {} }, "N" }, {})
            end
            local raw_digits, dec_exp = D.to_digits_and_exp(d)
            local d_elts = {}
            for i = 1, #raw_digits do d_elts[i] = tonumber(raw_digits:sub(i, i)) end
            return require("Module:PythonScript/Evaluator").invoke(C.DecimalTuple, { s_bit, { __type = "tuple", elements = d_elts }, dec_exp }, {})
        end },
        as_integer_ratio = { __type = "builtin_method", __call = function(a)
            local d = a[1].__dict
            if d.special == "Inf" then Runtime.raise("OverflowError", "cannot convert Infinity to integer ratio") end
            if d.special then Runtime.raise("ValueError", "cannot convert NaN to integer ratio") end
            local raw_digits, dec_exp = D.to_digits_and_exp(d)
            if raw_digits == "0" then return { __type = "tuple", elements = { 0, 1 } } end
            local sign_str = (d.sign < 0) and "-" or ""
            if dec_exp >= 0 then
                local num_int = B.int.__call({ sign_str .. raw_digits .. string.rep("0", dec_exp) })
                return { __type = "tuple", elements = { num_int, 1 } }
            end
            local num = B.int.__call({ sign_str .. raw_digits })
            local den = B.int.__call({ "1" .. string.rep("0", -dec_exp) })
            local Evaluator = require("Module:PythonScript/Evaluator")
            local x, y = B.abs({num}), den
            while not (y == 0 or (type(y) == "table" and #y.limbs == 1 and y.limbs[1] == 0)) do
                x, y = y, Evaluator.bigint_op(x, y, "%")
            end
            return { __type = "tuple", elements = { Evaluator.bigint_op(num, x, "//"), Evaluator.bigint_op(den, x, "//") } }
        end },
        copy_abs = { __type = "builtin_method", __call = function(a)
            local d = a[1].__dict
            return D.make_decimal_from_raw({ sign = 1, limbs = d.limbs, limb_exp = d.limb_exp, special = d.special }, d._fixed_scale)
        end },
        copy_negate = { __type = "builtin_method", __call = function(a)
            local d = a[1].__dict
            return D.make_decimal_from_raw({ sign = -d.sign, limbs = d.limbs, limb_exp = d.limb_exp, special = d.special }, d._fixed_scale)
        end },
        copy_sign = { __type = "builtin_method", __call = function(a)
            local d = a[1].__dict
            local rb = D.coerce_to_raw(a[2], true)
            return D.make_decimal_from_raw({ sign = rb and rb.sign or 1, limbs = d.limbs, limb_exp = d.limb_exp, special = d.special }, d._fixed_scale)
        end },
        compare = { __type = "builtin_method", __call = function(a)
            local rb = D.coerce_to_raw(a[2], false)
            if not rb then Runtime.raise("TypeError", "compare expects a Decimal") end
            local c = D.cmp_raw(a[1].__dict, rb)
            if c == nil then return D.make_decimal_from_raw(D.normalize_raw(1, {0}, 0, "NaN")) end
            return D.make_decimal_from_raw(D.normalize_raw(c < 0 and -1 or 1, { c == 0 and 0 or 1 }, 0))
        end },
        max = { __type = "builtin_method", __call = function(a)
            local rb = D.coerce_to_raw(a[2], false)
            local c = D.cmp_raw(a[1].__dict, rb)
            if c == nil then return D.make_decimal_from_raw(D.normalize_raw(1, {0}, 0, "NaN")) end
            return (c >= 0) and a[1] or D.make_decimal_from_raw(rb)
        end },
        min = { __type = "builtin_method", __call = function(a)
            local rb = D.coerce_to_raw(a[2], false)
            local c = D.cmp_raw(a[1].__dict, rb)
            if c == nil then return D.make_decimal_from_raw(D.normalize_raw(1, {0}, 0, "NaN")) end
            return (c <= 0) and a[1] or D.make_decimal_from_raw(rb)
        end },
        fma = { __type = "builtin_method", __call = function(a)
            local rb = D.coerce_to_raw(a[2], false)
            local rc = D.coerce_to_raw(a[3], false)
            return D.make_decimal_from_raw(D.add_raw(D.mul_raw(a[1].__dict, rb), rc))
        end },
        scaleb = { __type = "builtin_method", __call = function(a)
            local d = a[1].__dict
            local rb = D.coerce_to_raw(a[2], false)
            local shift_n = tonumber(BigInt.to_string(rb.sign, rb.limbs)) or 0
            local raw_digits, dec_exp = D.to_digits_and_exp(d)
            return D.make_decimal_from_raw(D.from_digits_and_exp(d.sign, raw_digits, dec_exp + shift_n))
        end },
        radix = { __type = "builtin_method", __call = function() return D.make_decimal_from_raw(D.normalize_raw(1, {10}, 0)) end },
        conjugate = { __type = "builtin_method", __call = function(a) return a[1] end },
        canonical = { __type = "builtin_method", __call = function(a) return a[1] end },
        is_canonical = { __type = "builtin_method", __call = function() return true end },
        is_finite = { __type = "builtin_method", __call = function(a) return a[1].__dict.special == nil end },
        is_infinite = { __type = "builtin_method", __call = function(a) return a[1].__dict.special == "Inf" end },
        is_nan = { __type = "builtin_method", __call = function(a)
            local sp = a[1].__dict.special
            return sp == "NaN" or sp == "sNaN"
        end },
        is_qnan = { __type = "builtin_method", __call = function(a) return a[1].__dict.special == "NaN" end },
        is_snan = { __type = "builtin_method", __call = function(a) return a[1].__dict.special == "sNaN" end },
        is_normal = { __type = "builtin_method", __call = function(a)
            return a[1].__dict.special == nil and not D.is_zero_raw(a[1].__dict)
        end },
        is_subnormal = { __type = "builtin_method", __call = function() return false end },
        is_signed = { __type = "builtin_method", __call = function(a) return a[1].__dict.sign < 0 end },
        is_zero = { __type = "builtin_method", __call = function(a) return D.is_zero_raw(a[1].__dict) end },
        number_class = { __type = "builtin_method", __call = function(a)
            local d = a[1].__dict
            if d.special == "NaN" then return "NaN"
            elseif d.special == "sNaN" then return "sNaN"
            elseif d.special == "Inf" then return d.sign < 0 and "-Infinity" or "+Infinity"
            elseif D.is_zero_raw(d) then return d.sign < 0 and "-Zero" or "+Zero"
            else return d.sign < 0 and "-Normal" or "+Normal" end
        end },
        real = { __type = "property", fget = { __type = "builtin_method", __call = function(a) return a[1] end } },
        imag = { __type = "property", fget = { __type = "builtin_method", __call = function() return D.make_decimal_from_raw(D.normalize_raw(1, {0}, 0)) end } }
    }
    dec_dict.to_integral = dec_dict.to_integral_value
    dec_dict.to_integral_exact = dec_dict.to_integral_value
    dec_dict.compare_total = dec_dict.compare

    D.DecimalClass = PyClass.make_class("Decimal", {}, dec_dict)
    D.DecimalClass.__dict["__module__"] = "decimal"
    C.Decimal = D.DecimalClass

    -- [E] Context 類別與上下文管理函式
    local function make_status_dict()
        local keys = { C.Clamped, C.InvalidOperation, C.DivisionByZero, C.Inexact, C.Rounded, C.Subnormal, C.Overflow, C.Underflow, C.FloatOperation }
        local pairs_list = {}
        for _, k in ipairs(keys) do table.insert(pairs_list, { key = k, value = 0 }) end
        return { __type = "dict", pairs = pairs_list }
    end

    local ctx_dict = {
        __init__ = { __type = "builtin_method", __call = function(a, kw)
            local self = a[1]
            kw = kw or {}
            self.__dict.prec = (a[2] ~= nil and a[2]) or kw.prec or 28
            self.__dict.rounding = (a[3] ~= nil and a[3]) or kw.rounding or "ROUND_HALF_EVEN"
            self.__dict.Emin = (a[4] ~= nil and a[4]) or kw.Emin or -999999
            self.__dict.Emax = (a[5] ~= nil and a[5]) or kw.Emax or 999999
            self.__dict.capitals = (a[6] ~= nil and a[6]) or kw.capitals or 1
            self.__dict.clamp = (a[7] ~= nil and a[7]) or kw.clamp or 0
            self.__dict.flags = kw.flags or make_status_dict()
            self.__dict.traps = kw.traps or make_status_dict()
            return nil
        end },
        copy = { __type = "builtin_method", __call = function(a)
            local d = a[1].__dict
            local copy_inst = PyClass.make_instance(C.Context)
            copy_inst.__dict.prec = d.prec
            copy_inst.__dict.rounding = d.rounding
            copy_inst.__dict.Emin = d.Emin
            copy_inst.__dict.Emax = d.Emax
            copy_inst.__dict.capitals = d.capitals
            copy_inst.__dict.clamp = d.clamp
            copy_inst.__dict.flags = make_status_dict()
            copy_inst.__dict.traps = make_status_dict()
            return copy_inst
        end },
        clear_flags = { __type = "builtin_method", __call = function(a)
            for _, p in ipairs(a[1].__dict.flags.pairs or {}) do p.value = 0 end
            return B.None
        end },
        clear_traps = { __type = "builtin_method", __call = function(a)
            for _, p in ipairs(a[1].__dict.traps.pairs or {}) do p.value = 0 end
            return B.None
        end },
        create_decimal = { __type = "builtin_method", __call = function(a)
            return D.DecimalClass.__dict.__new__.__func.__call({ D.DecimalClass, a[2] or 0 })
        end },
        create_decimal_from_float = { __type = "builtin_method", __call = function(a)
            return D.DecimalClass.__dict.from_float.__func.__call({ D.DecimalClass, a[2] })
        end },
        abs = { __type = "builtin_method", __call = function(a) return dec_dict.__abs__.__call({ a[2] }) end },
        add = { __type = "builtin_method", __call = function(a) return dec_dict.__add__.__call({ a[2], a[3] }) end },
        subtract = { __type = "builtin_method", __call = function(a) return dec_dict.__sub__.__call({ a[2], a[3] }) end },
        multiply = { __type = "builtin_method", __call = function(a) return dec_dict.__mul__.__call({ a[2], a[3] }) end },
        divide = { __type = "builtin_method", __call = function(a) return dec_dict.__truediv__.__call({ a[2], a[3] }) end },
        divmod = { __type = "builtin_method", __call = function(a) return dec_dict.__divmod__.__call({ a[2], a[3] }) end },
        power = { __type = "builtin_method", __call = function(a) return dec_dict.__pow__.__call({ a[2], a[3] }) end },
        sqrt = { __type = "builtin_method", __call = function(a) return dec_dict.sqrt.__call({ a[2] }) end },
        ln = { __type = "builtin_method", __call = function(a) return dec_dict.ln.__call({ a[2] }) end },
        log10 = { __type = "builtin_method", __call = function(a) return dec_dict.log10.__call({ a[2] }) end },
        exp = { __type = "builtin_method", __call = function(a) return dec_dict.exp.__call({ a[2] }) end },
        __repr__ = { __type = "builtin_method", __call = function(a)
            local d = a[1].__dict
            return string.format("Context(prec=%d, rounding=%s, Emin=%d, Emax=%d, capitals=%d, clamp=%d)",
                d.prec, tostring(d.rounding), d.Emin, d.Emax, d.capitals, d.clamp)
        end }
    }
    ctx_dict.__str__ = ctx_dict.__repr__
    C.Context = PyClass.make_class("Context", {}, ctx_dict)
    C.Context.__dict["__module__"] = "decimal"

    local function make_preset_ctx(prec, rounding)
        local inst = PyClass.make_instance(C.Context)
        ctx_dict.__init__.__call({ inst }, { prec = prec, rounding = rounding })
        return inst
    end

    C.DefaultContext = make_preset_ctx(28, "ROUND_HALF_EVEN")
    C.BasicContext = make_preset_ctx(9, "ROUND_HALF_UP")
    C.ExtendedContext = make_preset_ctx(9, "ROUND_HALF_EVEN")
    D.current_context = ctx_dict.copy.__call({ C.DefaultContext })

    C.getcontext = { __type = "builtin_method", __name = "getcontext", __call = function()
        return D.current_context
    end }

    C.setcontext = { __type = "builtin_method", __name = "setcontext", __call = function(a)
        if not a or not a[1] then Runtime.raise("TypeError", "setcontext() requires a Context argument") end
        D.current_context = a[1]
        return B.None
    end }

    local local_ctx_mgr = PyClass.make_class("_ContextManager", {}, {
        __enter__ = { __type = "builtin_method", __call = function(a)
            local self = a[1]
            self.__dict._saved = D.current_context
            D.current_context = self.__dict._work
            return D.current_context
        end },
        __exit__ = { __type = "builtin_method", __call = function(a)
            local self = a[1]
            D.current_context = self.__dict._saved
            return false
        end }
    })

    C.localcontext = { __type = "builtin_method", __name = "localcontext", __call = function(a, kw)
        local base_ctx = (a and not D.is_none(a[1]) and a[1]) or (kw and not D.is_none(kw.ctx) and kw.ctx) or D.current_context
        local work_ctx = ctx_dict.copy.__call({ base_ctx })
        if kw then
            if kw.prec ~= nil then work_ctx.__dict.prec = kw.prec end
            if kw.rounding ~= nil then work_ctx.__dict.rounding = kw.rounding end
        end
        local mgr = PyClass.make_instance(local_ctx_mgr)
        mgr.__dict._work = work_ctx
        return mgr
    end }

    C.IEEEContext = { __type = "builtin_method", __name = "IEEEContext", __call = function(a)
        local bits = tonumber(a and a[1]) or 64
        local prec_map = { [16] = 4, [32] = 7, [64] = 16, [128] = 34, [256] = 71, [512] = 146 }
        local p = prec_map[bits] or math.max(1, math.floor(bits * 0.28))
        return make_preset_ctx(p, "ROUND_HALF_EVEN")
    end }
end

-- ==========================================
-- 7. 模組延遲載入匯出介面
-- ==========================================
function DecimalMod.get_module()
    local mod_dict = {
        __getattr__ = {
            __type = "builtin_method",
            __call = function(args)
                local self, attr = args[1], args[2]
                D.ensure_init()
                local val = D.cache[attr]
                if val ~= nil then
                    self.__dict[attr] = val
                    return val
                end
                Runtime.raise("AttributeError", "module 'decimal' has no attribute '" .. tostring(attr) .. "'")
            end
        }
    }
    local mod = PyClass.make_instance(PyClass.make_class("module", {}, mod_dict))
    mod.__dict["__name__"] = "decimal"
    mod.__dict["__all__"] = {
        __type = "list",
        elements = {
            "Decimal", "Context", "DecimalTuple",
            "DefaultContext", "BasicContext", "ExtendedContext",
            "DecimalException", "Clamped", "InvalidOperation", "ConversionSyntax",
            "DivisionByZero", "DivisionImpossible", "DivisionUndefined",
            "Inexact", "InvalidContext", "Rounded", "Subnormal", "Overflow", "Underflow", "FloatOperation",
            "ROUND_DOWN", "ROUND_HALF_UP", "ROUND_HALF_EVEN", "ROUND_CEILING",
            "ROUND_FLOOR", "ROUND_UP", "ROUND_HALF_DOWN", "ROUND_05UP",
            "setcontext", "getcontext", "localcontext", "IEEEContext",
            "MAX_PREC", "MAX_EMAX", "MIN_EMIN", "MIN_ETINY",
            "HAVE_THREADS", "HAVE_CONTEXTVAR", "IEEE_CONTEXT_MAX_BITS"
        }
    }
    return mod
end

return DecimalMod