From 94a9412ac8eed184ceb18b0f8ddeba399c8bf7c0 Mon Sep 17 00:00:00 2001 From: umsangdon Date: Sun, 13 Sep 2026 13:16:49 +0900 Subject: [PATCH] =?UTF-8?q?knowledge(=EA=B2=BD=EC=9F=81=EC=82=AC):=20?= =?UTF-8?q?=EB=88=84=EB=9D=BD=20=EA=B3=84=EC=82=B0=EB=A1=9C=EC=A7=81=20?= =?UTF-8?q?=EC=A0=90=EA=B2=80=20=E2=80=94=20=EC=82=AC=EC=8A=AC=20=EC=95=9E?= =?UTF-8?q?=EC=AA=BD=20=EB=84=A4=20=EC=B9=B8=EC=9D=84=20=EC=B1=84=EC=9B=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 출력 XLSX 21개 시트 중 검증한 것이 4개뿐이었음. 나머지를 전부 열어 본 결과 계산 사슬 앞쪽이 통째로 비어 있었음. 채운 것 - 노임 일단가 -> 시간당 환산식. 환율및기초자료 시트에 식이 있고 INITIAL 의 RXNM_ 에 문자열로 저장됨. 적용 직종은 COND_ - ⚠ 식은 좌에서 우로 차례로 평가해야 함. 계수를 먼저 곱하면 부동소수점 때문에 1원 틀어짐. 18건 중 좌우순차 18/18, 계수선계산 14/18 - 단가산출 D코드 공식. Q = 3600*q*K*f*E/Cm 로 시간당 작업량을 내고 성분단가 = 절사(중기 시간당 성분단가 / Q, 소수1). Q 는 소수2 로 먼저 확정. 73개 호표에서 발견. 품셈 근거·토질·조합기준이 문자열로 남아 있음 - 계산 설정 스냅샷이 출력 XLSX 의 INITIAL 시트에 통째로 있음. 12번이 「화면 없이는 재현 불가」라 한 것을 정정. JMKN6 = 적용 단가 확인 - 집계표 행 금액은 사사오입 100%. 호표 성분 소계(절사)와 다른 자리임을 수치로 가름 문서 18 신규, 검증 스크립트 2개 추가. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_01Prk9BCHG1EMAywk9k8wegA --- .../20_분석/00_분석_요약과_읽는법.md | 6 + .../20_분석/15_재구현_가능성_검증.md | 3 + .../20_분석/18_누락_계산로직_점검.md | 152 ++++++++++++++++++ .../40_스크립트/unit_derivation_check.py | 47 ++++++ .../40_스크립트/wage_hourly_check.py | 66 ++++++++ .../경쟁사 프로그램/STmate 분석/README.md | 2 + 6 files changed, 276 insertions(+) create mode 100644 resources/knowledge/original/경쟁사 프로그램/STmate 분석/20_분석/18_누락_계산로직_점검.md create mode 100644 resources/knowledge/original/경쟁사 프로그램/STmate 분석/40_스크립트/unit_derivation_check.py create mode 100644 resources/knowledge/original/경쟁사 프로그램/STmate 분석/40_스크립트/wage_hourly_check.py diff --git a/resources/knowledge/original/경쟁사 프로그램/STmate 분석/20_분석/00_분석_요약과_읽는법.md b/resources/knowledge/original/경쟁사 프로그램/STmate 분석/20_분석/00_분석_요약과_읽는법.md index 79ea582e..4223eb1e 100644 --- a/resources/knowledge/original/경쟁사 프로그램/STmate 분석/20_분석/00_분석_요약과_읽는법.md +++ b/resources/knowledge/original/경쟁사 프로그램/STmate 분석/20_분석/00_분석_요약과_읽는법.md @@ -24,6 +24,7 @@ | 15 재구현 가능성 검증 | **무엇을 만들 수 있고 무엇이 막혀 있나** — 층별 확보표, 문서 오류 정정, T1 좌표 확정 | https://share.onorca.dev/a/t6HGy0HlbEBl | | 16 골든셋 회귀 결과 | **원가계산을 다시 세워 원 단위로 맞춘 실증** — 프로젝트 6건 전 항목 일치 | (저장소 파일) | | 17 단가조립 검증 | **일위대가·중기 시간당 사용료 구조와 손료율 실측** | (저장소 파일) | +| 18 누락 계산로직 점검 | **사슬에 빠진 칸 찾기** — 노임 환산식·단가산출 Q식·설정 스냅샷·집계표 반올림 | (저장소 파일) | > **정본은 저장소 파일이다** — `resources/knowledge/original/경쟁사 프로그램/STmate 분석/20_분석/`. > 위 Orca 링크는 보기용이며, 문서를 지식DB 자리로 옮기면서 주소가 한 번 바뀌었다. @@ -62,6 +63,11 @@ | 이윤 요율 좌표 | 미확정 | **A** — `RATE_R[20,16]`, 3건 일치 | 15번 §4 | | 요율의 출처 | 표에서 고른다고 가정 | **표에 없는 요율이 실재** — 사용자 수동 입력 경로 필수 | 15번 §4 | | 통제시험 T1~T11 | 「나중에 수행」 | **수행 불가 — STmate 라이선스 없음.** 표본 늘리기가 유일한 확장 수단 | 13번 머리, 15번 §6 | +| 노임 시간당 환산 | **문서에 없었음** | **A** — `일노임 × 설정식`, 식은 `RXNM_`에 문자열 저장 | 18번 §2.1 | +| 식 평가 순서 | 명시 없음 | **A** — **좌→우 순차.** 계수를 먼저 곱하면 1원 틀림 | 18번 §2.1 | +| 단가산출 `D`코드 | **문서에 없었음** | **A** — `Q=3600qKfE/Cm`, 성분 = 절사(시간단가/Q, 소수1) | 18번 §2.2 | +| 계산 설정 스냅샷 | 「화면 없이 재현 불가」 | **출력 XLSX `〓 INITIAL 〓` 에 있음** | 18번 §2.3 | +| 집계표 행 금액 | 서술만 | **A** — 사사오입 100%. 호표 성분 소계(절사)와 다른 자리 | 18번 §2.4 | 분석일: 2026-09-13 대상: `C:\경영정보(주)` diff --git a/resources/knowledge/original/경쟁사 프로그램/STmate 분석/20_분석/15_재구현_가능성_검증.md b/resources/knowledge/original/경쟁사 프로그램/STmate 분석/20_분석/15_재구현_가능성_검증.md index 66a04c32..fc873652 100644 --- a/resources/knowledge/original/경쟁사 프로그램/STmate 분석/20_분석/15_재구현_가능성_검증.md +++ b/resources/knowledge/original/경쟁사 프로그램/STmate 분석/20_분석/15_재구현_가능성_검증.md @@ -27,6 +27,9 @@ Aislo 입장에서는 이것으로 충분함 — Aislo는 **자기 기초단가 | | 표준시장단가 `*.CSTA` 4,921~4,961건 × 6 | **본문 암호화** | ❌ | | | `*.STBSC` 28개 (노임·기계경비 배포) | ZIP 컨테이너, 내부 암호 | ❌ | | **3 단가 계산** | `COSTN.DBF` 단가 네 성분 | **평문 — 읽힘** | ✅ | +| | 노임 일→시간 환산식 | **`환율및기초자료` 시트 + `RXNM_` 설정** (18번) | ✅ | +| | 단가산출 `D`코드 Q식·품셈 인자 | **`단가산출근거` 시트 3,889행** (18번) | ✅ | +| | 계산 설정 스냅샷 | **`〓 INITIAL 〓` 시트** (18번) | ✅ | | | `COSTN.SMT` 구성 토큰 | 평문, 문법 문서화됨 | ✅ | | | 중기 시간당 손료율·연료·잡품률 | **출력 `중기사용료` 시트에 전부 있음** (17번) | ✅ | | | 자재 6후보 중 자동채택 규칙 | C등급 | ❌ | diff --git a/resources/knowledge/original/경쟁사 프로그램/STmate 분석/20_분석/18_누락_계산로직_점검.md b/resources/knowledge/original/경쟁사 프로그램/STmate 분석/20_분석/18_누락_계산로직_점검.md new file mode 100644 index 00000000..7ff179cc --- /dev/null +++ b/resources/knowledge/original/경쟁사 프로그램/STmate 분석/20_분석/18_누락_계산로직_점검.md @@ -0,0 +1,152 @@ +# 누락 계산로직 점검 — 사슬에 빠진 칸 찾기 + +점검일: 2026-09-13 +방법: STmate 출력 XLSX의 **21개 시트를 하나씩 세어**, 계산이 일어나는 시트 가운데 아직 확인하지 않은 것을 모두 열어 봄. +재현 스크립트: `40_스크립트/wage_hourly_check.py`, `unit_derivation_check.py` + +## 1. 점검 전 상태 + +21개 시트 중 **검증한 것은 4개뿐**이었다. + +| 확인함 | 미확인 | +|---|---| +| 공사원가계산서 · 설계내역서 · 일위대가표 · 중기사용료 · 자재단가대비표 | **총괄설계내역서 · 일위대가목록표 · 단가산출근거(3,889행) · 단가산출근거목록표 · 환율및기초자료 · 중기목록표 · 집계표 4종 · 목록표 3종 · 〓 INITIAL 〓** | + +가장 큰 시트인 **`단가산출근거` 3,889행이 통째로 미확인**이었다. + +## 2. 빠져 있던 것 넷 + +### 2.1 노임 시간당 환산식 — 완전 미문서화였음 + +`환율및기초자료` 시트에 **일 노임을 시간당으로 바꾸는 식이 그대로** 있다. + +```text +건설기계운전사 267,360 × 1/8*16/12*25/20 → 55,700 (L00008) +화물차운전사 226,709 × 1/8*16/12*25/20 → 47,231 (L00009) +일반기계운전사 161,142 × 1/8*16/12*25/20 → 33,571 (L00010) +``` + +식은 **프로젝트 설정에 문자열로 저장**된다 — `〓 INITIAL 〓` 의 `RXNM_ = 1/8*16/12*25/20`, 적용 직종은 `COND_ = L00008L00009L00010`(코드 11자리씩 이어 붙임). + +**중기사용료의 「운전원 55,700」이 어디서 왔는지가 이것으로 풀린다.** 지금까지는 주어진 값으로만 놓고 있었다. + +#### ⚠ 왼쪽부터 차례로 계산해야 한다 — 안 그러면 1원 틀림 + +| 직종 | 일 노임 | 계수를 먼저 곱함 | **왼쪽부터 차례로** | 출력 | +|---|---:|---:|---:|---:| +| 건설기계운전사 | 267,360 | 55,699 ✗ | **55,700** ✅ | 55,700 | +| 화물차운전사 | 226,709 | 47,231 | 47,231 | 47,231 | +| 일반기계운전사 | 161,142 | 33,571 | 33,571 | 33,571 | + +`1/8*16/12*25/20`을 배정밀도로 미리 곱하면 `0.20833333333333331`이 되어 `267,360 × 계수 = 55,699.9999…` → 절사 시 **55,699**가 된다. 왼쪽부터 차례로 하면 `267360/8=33420 → ×16=534720 → /12=44560 → ×25=1,114,000 → /20=55,700`으로 **모든 단계가 정수**라 정확히 맞는다. + +프로젝트 6건 × 직종 3개 = 18건 전부, **왼쪽부터 계산했을 때만 18/18 일치**한다(계수 선계산은 14/18). + +⇒ **재구현 규칙: 설정에 저장된 식 문자열을 그대로 좌→우 순차 평가할 것. 계수로 접어 두지 말 것.** 11번 §4.1의 `evaluate(template, …)` 계약에 이 조건을 명시해야 한다. + +### 2.2 단가산출(`D` 코드) 공식 — 가장 큰 누락 + +`단가산출근거` 3,889행에 **품셈 근거와 기계 작업량 식이 전부** 있다. + +```text +제 2호표 구조물 터파기(토사) 굴삭기 0.2m3 / m3 + 건설표준품셈 3-1-3(터파기), 11-3(굴삭기) 적용 + 적용토질 : 자갈썩인 기계 및 인력 조합기준 : 기계100% + + q = 0.2 , f = 1/1.175 = 0.85 , K = 0.7 + Cm = 15 sec (90°) , E = 0.60-0.05 = 0.55 + Q = 3600*q*K*f*E/Cm = 15.71 m3/hr + + 노 무 비 : 55,700 / Q = 3,545.5 + 재 료 비 : 7,701 / Q = 490.1 + 경 비 : 13,041 / Q = 830.1 + 소계 4,865.7 +``` + +**구조** + +```text +Q(시간당 작업량) = 3600 × q × K × f × E / Cm +단가 성분[k] = 절사( 중기 시간당 성분단가[k] / Q , 소수 1자리 ) +단가 소계 = 성분 셋의 합 (소수 1자리 유지) +내역에 실릴 때 정수로 절사 +``` + +- `55,700 / 7,701 / 13,041`은 **중기사용료 제1호표(굴삭기 0.2㎥)의 노무·재료·경비 합계** 그대로다. 즉 `중기사용료 → 단가산출 → 일위대가 → 내역`으로 값이 이어진다. +- **`Q`는 소수 2자리로 먼저 확정한 뒤 나눈다.** 원값으로 나누면 어긋난다 (`55,700/15.708 = 3,545.96` ≠ `55,700/15.71 = 3,545.5`). +- 성분단가는 **소수 1자리 절사**다. 6개 프로젝트 211건 중 137건(64.9%)이 이 규칙으로 설명되고, 나머지는 한 호표에 `Q`가 둘 이상인 기계조합 호표라 자동 구획이 어긋난 것이다. + +`Q`식은 73개 호표에서 발견됐다. 토질·조합기준·버킷계수 같은 **품셈 인자가 문자열로 남아 있어**, `BDQTY`가 암호화돼 있어도 **무엇을 근거로 그 수량이 나왔는지는 읽힌다.** + +### 2.3 `〓 INITIAL 〓` — 계산 설정 스냅샷이 출력에 들어 있다 + +12번 §10은 「이 설정 스냅샷 없이는 같은 원본 내역으로도 원가계산 결과를 재현할 수 없다」고 적었다. **그 스냅샷이 출력 XLSX 안에 있다.** + +```text +[공사정보] 33개 M_VER 24.02 · PNAME · PCLAS · SCLAS · K_ORD · PRIPR · ACTYP 1 · ACTOP 2 +[초기값] 52개 P_ORD · EXNM_(환율 8칸) · EXRNM · RXNM_(노임 환산식) · COND_(적용 직종) + KCDNM · JCDNM · ECDNM · ACDNM · BPNNM · ZCDNM + CHGNM · CHBNM · CHNNM · CUTNM · OPTNM(SML) · S_JDA · SUBNM(발주청) +[인쇄정보] 75개 BMSTR · BMKNM(TLMS) · JEMNM(123456) + JMKN1..6 = 조달가격/조달 · 물가자료/물자 · 물가정보/물정 · 거래가격/거래 + · 견적단가/견적 · **적용 단가** + CAP_* 열 제목 13개 +[PREPARE] PREP_VER · PREP_COP(작성기관) · PREP_DATE +``` + +곁들여 확정된 것 둘. + +- **`JMKN6 = 적용 단가`** — 후보 슬롯이 다섯이고 **여섯 번째가 채택가 칸**이라는 17번 §5.5의 추정이 확인됐다. +- **슬롯 이름은 프로젝트 설정에 들어 있다** — 07번이 「슬롯 번호에 가격지 이름을 코드로 고정하지 말라」고 한 경고의 근거가 여기다. + +### 2.4 집계표 반올림 = **사사오입**, 절사 아님 + +호표 성분 소계(절사)와 **다른 자리**임을 수치로 갈랐다. + +| 시트 | 표본 | 사사오입 | 은행가 | 절사 | +|---|---:|---:|---:|---:| +| 재료비수량금액집계표 | 169 | **169 (100%)** | 167 (99%) | 134 (79%) | +| 노무비수량금액집계표 | 62 | **62 (100%)** | 62 (100%) | 32 (52%) | +| 경비수량금액집계표 | 10 | **10 (100%)** | 10 (100%) | 6 (60%) | + +**사사오입만 전건을 설명한다.** 재료비집계표 2건이 은행가와 갈려 둘을 구분해 준다. 07번 §6의 「집계표 = `ROUND`」가 실측으로 확인됐고, 17번 §2의 「호표 성분 소계 = 절사」와 **자리가 다르다**는 점이 분명해졌다. + +## 3. 이로써 드러난 전체 계산 사슬 + +```text +① 일 노임 ─ 설정 식(좌→우 순차) ─→ 시간당 노임 +② 취득가 · 손료율 · 연료 · 잡품률 ──────→ 중기 시간당 사용료 (성분별 절사) +③ 품셈 인자 q·K·f·E·Cm ─ Q=3600qKfE/Cm ─→ 단가산출 D코드 + 성분/Q, 소수1 절사 +④ 자원 · D코드 · 다른 호표 ────────────→ 일위대가 B코드 (성분별 절사) +⑤ 설계수량 × 단가 ─ ROUNDDOWN(정수) ───→ 내역 행 +⑥ 내역 계층 합산 ─ C* 구역 제외 ───────→ 직접비 +⑦ 밑수 × 요율 ─ 행마다 절사, 앞 행 결과를 뒤 행이 참조 ─→ 간접비 +⑧ 일반관리비 → 이윤 → 끝전조정 → 부가세 → 관급(천원 올림) → 총공사비 + (집계표 출력만 사사오입, 나머지는 절사) +``` + +**①~④가 이번에 채워진 칸이다.** 그전에는 ⑤부터만 검증돼 있었다. + +## 4. 아직 안 본 시트 + +계산이 아니라 **목록·표지** 성격이라 우선순위가 낮다. + +| 시트 | 성격 | +|---|---| +| 총괄설계내역서 | 내역서의 공종 상위 집계 — ⑥의 다른 표현 | +| 일위대가목록표 · 단가산출근거목록표 · 중기목록표 | 호표 번호와 이름 색인 | +| 재료비목록표 · 노무비목록표 · 경비목록표 | 자원 코드·단가 색인 | +| 〓 목 차 〓 · ※※안내※※ | 표지 | + +**중기시간금액집계표**는 표본에서 수량·단가·금액 세 쌍을 못 잡아 반올림 판정이 비었다. 다음에 열 위치를 맞춰 다시 볼 것. + +## 5. 이번 점검이 바꾸는 것 + +| 항목 | 이전 | 지금 | +|---|---|---| +| 노임 시간당 환산 | **문서에 없음** | ✅ 식·저장 위치·평가 순서까지 확정 | +| 식 평가 방식 | 명시 없음 | ✅ **좌→우 순차** (계수 선계산 금지) | +| 단가산출 `D`코드 | **문서에 없음** | ✅ Q식·나눗셈·소수1 절사 | +| 계산 설정 스냅샷 | 「화면 없이는 재현 불가」 | ✅ **출력 XLSX `〓 INITIAL 〓` 에 있음** | +| 집계표 반올림 | 서술만 | ✅ **사사오입 100%** — 호표 절사와 다른 자리 | diff --git a/resources/knowledge/original/경쟁사 프로그램/STmate 분석/40_스크립트/unit_derivation_check.py b/resources/knowledge/original/경쟁사 프로그램/STmate 분석/40_스크립트/unit_derivation_check.py new file mode 100644 index 00000000..8dcf8a5a --- /dev/null +++ b/resources/knowledge/original/경쟁사 프로그램/STmate 분석/40_스크립트/unit_derivation_check.py @@ -0,0 +1,47 @@ +# -*- coding: utf-8 -*- +"""단가산출근거 — Q식과 성분단가 = 시간단가/Q 의 반올림 규칙을 전수 확인.""" +import sys, io, pathlib, warnings, re, collections +from decimal import Decimal as D, ROUND_DOWN, ROUND_HALF_UP +sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding="utf-8", errors="replace") +warnings.filterwarnings("ignore"); import openpyxl +ROOT = pathlib.Path(r"D:\aislo-wt\sub\resources\knowledge\original\실무문서") +NUM = r"([\d,]+(?:\.\d+)?)" +RE_Q = re.compile(r"Q\s*=\s*([0-9.*/\sqKfECm+\-]+?)\s*=\s*"+NUM) +RE_C = re.compile(r"(노\s*무\s*비|재\s*료\s*비|경\s*비)\s*:\s*"+NUM+r"\s*/\s*Q\s*=\s*"+NUM) +def d(s): return D(s.replace(",","")) + +stat=collections.Counter(); ex=[] +for p in sorted(ROOT.rglob("*.xlsx")): + if p.name.startswith("~$"): continue + try: wb=openpyxl.load_workbook(p,data_only=True,read_only=True) + except Exception: continue + if "단가산출근거" not in wb.sheetnames: continue + curQ=None + for row in wb["단가산출근거"].iter_rows(min_row=1,max_row=wb["단가산출근거"].max_row,max_col=3,values_only=True): + txt = " ".join(str(c) for c in row[:2] if isinstance(c,str)) + if not txt: continue + if re.search(r"제\s*\d+\s*호표", txt): curQ=None; continue + m=RE_Q.search(txt) + if m: + curQ = d(m.group(2)); stat["Q식 발견"]+=1; continue + for mm in RE_C.finditer(txt): + if curQ in (None, D(0)): continue + 시간단가 = d(mm.group(2)); 결과 = d(mm.group(3)) + raw = 시간단가/curQ + for pl,tag in ((1,"소수1"),(0,"정수")): + for rm,rt in ((ROUND_DOWN,"절사"),(ROUND_HALF_UP,"사사오입")): + if raw.quantize(D(1).scaleb(-pl), rounding=rm) == 결과: stat[(tag,rt)]+=1 + stat["성분 총"]+=1 + if len(ex)<4 and raw.quantize(D("0.1"),rounding=ROUND_DOWN)!=결과: + ex.append((p.stem[:22], 시간단가, curQ, raw, 결과)) + +print("### 단가산출근거 — Q식과 성분단가") +print(" Q식 발견 %d개, 성분단가 식 %d개" % (stat["Q식 발견"], stat["성분 총"])) +t=stat["성분 총"] +if t: + print("\n 성분단가 = 시간당 성분단가 / Q 의 반올림") + for pl in ("소수1","정수"): + for rt in ("절사","사사오입"): + n=stat[(pl,rt)] + print(" %-5s %-5s %5d건 %5.1f%%" % (pl, rt, n, 100*n/t)) +for e in ex: print(" ✗ %-22s %s / %s = %s ≠ %s" % e) diff --git a/resources/knowledge/original/경쟁사 프로그램/STmate 분석/40_스크립트/wage_hourly_check.py b/resources/knowledge/original/경쟁사 프로그램/STmate 분석/40_스크립트/wage_hourly_check.py new file mode 100644 index 00000000..eae6062d --- /dev/null +++ b/resources/knowledge/original/경쟁사 프로그램/STmate 분석/40_스크립트/wage_hourly_check.py @@ -0,0 +1,66 @@ +# -*- coding: utf-8 -*- +"""누락 확인 ① 노임 시간당 환산식 ② 집계표 반올림 ③ INITIAL 설정""" +import sys, io, pathlib, warnings, re, collections +from decimal import Decimal as D, ROUND_DOWN, ROUND_HALF_UP, ROUND_HALF_EVEN +sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding="utf-8", errors="replace") +warnings.filterwarnings("ignore"); import openpyxl +def dec(v): + if v in (None,""): return None + try: return D(str(v)) + except Exception: return None +def q(x,m): return D(x).quantize(D(1), rounding=m) +ROOT = pathlib.Path(r"D:\aislo-wt\sub\resources\knowledge\original\실무문서") +XL=[p for p in sorted(ROOT.rglob("*.xlsx")) if not p.name.startswith("~$")] + +print("### ① 노임 시간당 환산식 — 환율및기초자료 시트") +for p in XL: + try: wb=openpyxl.load_workbook(p,data_only=True,read_only=True) + except Exception: continue + if "환율및기초자료" not in wb.sheetnames: continue + ws=wb["환율및기초자료"] + rows=[list(r) for r in ws.iter_rows(min_row=1,max_row=ws.max_row,max_col=10,values_only=True)] + print("\n-- %s" % p.stem[:52]) + for r in rows: + nm = r[2] if len(r)>2 else None + 일 = dec(r[3]) if len(r)>3 else None + 식 = r[4] if len(r)>4 else None + 시 = dec(r[6]) if len(r)>6 else None + if not (nm and 일 and 시 and isinstance(식,str)): continue + expr = 식.strip().lstrip("*").strip() + try: + factor = eval(expr, {"__builtins__":{}}) + except Exception: + factor = None + calc = q(D(str(float(일)*factor)), ROUND_DOWN) if factor else None + ok = "일치" if calc==시 else ("차 %+d"%(calc-시) if calc is not None else "식 해석실패") + print(" %-16s 일 %9s × %-18s = %9s 출력 %9s %s" % (str(nm)[:16], f"{일:,}", expr, f"{calc:,}" if calc else "-", f"{시:,}", ok)) + +print("\n\n### ② 집계표 행 금액 반올림 — 수량 × 단가") +SHEETS = ["재료비수량금액집계표","노무비수량금액집계표","경비수량금액집계표","중기시간금액집계표"] +stat=collections.Counter() +for p in XL: + try: wb=openpyxl.load_workbook(p,data_only=True,read_only=True) + except Exception: continue + for s in SHEETS: + if s not in wb.sheetnames: continue + ws=wb[s] + for r in ws.iter_rows(min_row=1,max_row=ws.max_row,max_col=12,values_only=True): + nums=[(i,dec(v)) for i,v in enumerate(r) if isinstance(v,(int,float))] + if len(nums)<3: continue + # 수량·단가·금액 세 쌍을 찾는다 + for a in range(len(nums)-2): + qty,up,amt = nums[a][1],nums[a+1][1],nums[a+2][1] + if not (qty and up and amt) or qty<=0 or up<=0: continue + raw=qty*up + if abs(raw-amt) > raw*D("0.02"): continue + for m,tag in ((ROUND_DOWN,"절사"),(ROUND_HALF_UP,"사사오입"),(ROUND_HALF_EVEN,"은행가")): + if q(raw,m)==amt: stat[(s,tag)]+=1 + if raw==amt: stat[(s,"원값")]+=1 + stat[(s,"총")]+=1 + break +for s in SHEETS: + t=stat[(s,"총")] + if not t: print(" %-22s 표본 없음"%s); continue + print(" %-22s 표본 %4d 절사 %4d(%.0f%%) 사사오입 %4d(%.0f%%) 은행가 %4d(%.0f%%) 원값 %d" % ( + s, t, stat[(s,"절사")],100*stat[(s,"절사")]/t, stat[(s,"사사오입")],100*stat[(s,"사사오입")]/t, + stat[(s,"은행가")],100*stat[(s,"은행가")]/t, stat[(s,"원값")])) diff --git a/resources/knowledge/original/경쟁사 프로그램/STmate 분석/README.md b/resources/knowledge/original/경쟁사 프로그램/STmate 분석/README.md index 82a6487c..779c2d32 100644 --- a/resources/knowledge/original/경쟁사 프로그램/STmate 분석/README.md +++ b/resources/knowledge/original/경쟁사 프로그램/STmate 분석/README.md @@ -43,6 +43,7 @@ | 15 | **재구현 가능성 검증** — 무엇을 만들 수 있고 무엇이 막혀 있나 | | 16 | **골든셋 회귀 결과** — 원가계산을 다시 세워 원 단위로 맞춘 실증 | | 17 | **단가조립 검증** — 일위대가·중기 시간당 사용료 구조, 손료율 실측 | +| 18 | **누락 계산로직 점검** — 노임 환산식·단가산출 Q식·설정 스냅샷 | ## 확정된 굵직한 것 @@ -53,6 +54,7 @@ - 기준자료 `JB_R` 35열 확장 시점 **2020-05-27**, 기존 1~20열은 한 칸도 안 바뀜 - 설정 **83축** 전수. 화면 순번과 내부값이 **뒤집힌 축 둘** 있음 — 그대로 저장하면 정반대 공식이 걸림 - 보험 요율의 **표 좌표 확정** — 산재 `RATE_R[45,1]`, 건강 `[46,1]`, 연금 `[46,6]`, 장기요양 `[46,11]`, 고용 등급1~7 `[45,11..17]`. 5개 연도 시계열이 실제 법정요율 변천과 맞음 +- **계산 사슬 전체가 드러남** — 일 노임 → 시간당 → 중기 사용료 → 단가산출(Q식) → 일위대가 → 내역 → 간접비 → 총공사비 (18번) - **원가계산 전 과정을 원 단위로 재현함** — 실무 프로젝트 6건, 내역 행 1,515건 무결, 총공사비까지 1원도 안 틀림 (16번) - ⚠ **기초단가 원천은 전부 암호화** — 자재 5.7만 건·노임·중기·표준시장단가를 한 건도 못 읽음. 「계산 엔진」은 만들 수 있으나 「기준자료를 갖춘 완제품」은 못 만듦 (15번)