// REA: 932984 (10^4 정수), 93281c (실수), 4037e8 (FPU Round). const EstMath = (() => { const components = ["NC", "GC", "JC", "SC"]; const units = ["NU", "GU", "JU", "SU"]; const num = (value) => (value == null || value === "" ? 0 : Number(value)); const sum = (row) => components.reduce((n, key) => n + num(row[key]), 0); function even(value) { const sign = Math.sign(value), a = Math.abs(value), i = Math.floor(a), f = a - i; return sign * (f > 0.5 ? i + 1 : f < 0.5 ? i : i % 2 ? i + 1 : i); } function half(value) { return Math.trunc(value) + Math.trunc((value - Math.trunc(value)) * 2); } function mode(value, method) { if (method === 1) return half(value); if (method === 3) return half(value + 0.4); return Math.trunc(value); } function fixed(value, digits = 0, method = 2) { const v = even(value * 10000), k = 10 ** digits; return mode((v * k) / 10000, method) / k; } function floating(value, digits = 0, method = 2) { const k = 10 ** digits; // The original keeps x87 extended intermediates. Account for one binary64 // rounding unit before truncation so exact decimal boundaries survive JS. const scaled = value * k; return ( mode(scaled + Math.sign(value) * (2e-10 * k + Number.EPSILON * Math.abs(scaled)), method) / k ); } function precision(row, fallback = 0) { return num(row.DigetIndex) ? { digits: Math.max(0, num(row.Diget) - 1), method: num(row.DigetIndex) } : { digits: fallback, method: 2 }; } function amounts(row, digits = 0, totalFit = false) { if ([1, 3].includes(num(row.CalcIndex))) return row; const q = num(row.GN) / (["%", "%"].includes(row.Unite) ? 100 : 1); const p = precision(row, digits), raw = units.map((key) => num(row[key]) * q); components.forEach((key, i) => (row[key] = fixed(raw[i], p.digits, p.method))); row.TU = units.reduce((n, key) => n + num(row[key]), 0); if (totalFit) { const step = 10 ** -p.digits, target = fixed( raw.reduce((a, b) => a + b, 0), p.digits, p.method, ); let difference = Math.round((target - sum(row)) / step); const order = components .map((key, i) => ({ key, remainder: raw[i] - row[key] })) .sort((a, b) => (difference >= 0 ? b.remainder - a.remainder : a.remainder - b.remainder)); for (let i = 0; difference && i < 100; i++) { row[order[i % 4].key] += Math.sign(difference) * step; difference -= Math.sign(difference); } } row.TC = sum(row); return row; } function add(rows, predicate = (row) => num(row.CalcIndex) < 2) { const result = Object.fromEntries( components.map((key) => [ key, floating( rows.filter(predicate).reduce((n, row) => n + even(num(row[key]) * 10000), 0) / 10000, ), ]), ); result.TC = sum(result); return result; } return { components, units, num, sum, even, half, fixed, floating, precision, amounts, add }; })();