Skip to content

Commit 145df53

Browse files
committed
Docs: Update PostgreSQL doc to clarify float8 vs NUMERIC precision tradeoffs and benchmark noise
1 parent 206cc54 commit 145df53

2 files changed

Lines changed: 32 additions & 27 deletions

File tree

SQL/Leetcode/Basic select/1211. Queries Quality and Percentage/Claude Sonnet 4.6 Extended/Queries_Quality_and_Percentage_pandas.md

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -158,11 +158,11 @@ def queries_stats(queries: pd.DataFrame) -> pd.DataFrame:
158158

159159
```mermaid
160160
flowchart TD
161-
A["入力: queries DataFrame\nquery_name / result / position / rating"]
162-
B["notna + .copy()\nNULL除外 & CoW解消"]
163-
C["rating / position → score (float64)\nrating < 3 → poor (float64)"]
164-
D["groupby(sort=False, as_index=False)\n.agg(quality=mean, poor_%=mean)\nハッシュ集計 1パス"]
165-
E["np.floor(quality * 100 + 0.5) / 100\nnp.floor(poor_% * 10000 + 0.5) / 100\nROUND_HALF_UP ← SQL互換 ✅"]
161+
A["入力: queries DataFrame<br>query_name / result / position / rating"]
162+
B["notna + .copy()<br>NULL除外 & CoW解消"]
163+
C["rating / position → score (float64)<br>rating < 3 → poor (float64)"]
164+
D["groupby(sort=False, as_index=False)<br>.agg(quality=mean, poor_%=mean)<br>ハッシュ集計 1パス"]
165+
E["np.floor(quality * 100 + 0.5) / 100<br>np.floor(poor_% * 10000 + 0.5) / 100<br>ROUND_HALF_UP ← SQL互換 ✅"]
166166
F["出力: query_name / quality / poor_query_percentage"]
167167
168168
A --> B
@@ -393,13 +393,13 @@ final : 22.7 ms 7.97 MB ← result 列スキップ + copy=False
393393

394394
```mermaid
395395
flowchart TD
396-
A["入力: queries DataFrame\nquery_name / result / position / rating"]
397-
B["notna().to_numpy() → mask\nbool配列 O(N)"]
398-
C["to_numpy()[mask] × 3列のみ\nresult 列を完全スキップ ✅\ncopy=False で参照渡し ✅"]
399-
D["numpy ベクトル演算\nscore = rat / pos\npoor = rat < 3 → float64"]
400-
E["pd.DataFrame(copy=False)\n最小構成の一時 DF"]
401-
F["groupby.mean()\nCython 最適化パス 🔥\nsort=False でハッシュのみ"]
402-
G["to_numpy() で値取得\nnp.floor ROUND_HALF_UP"]
396+
A["入力: queries DataFrame<br>query_name / result / position / rating"]
397+
B["notna().to_numpy() → mask<br>bool配列 O(N)"]
398+
C["to_numpy()[mask] × 3列のみ<br>result 列を完全スキップ ✅<br>copy=False で参照渡し ✅"]
399+
D["numpy ベクトル演算<br>score = rat / pos<br>poor = rat < 3 → float64"]
400+
E["pd.DataFrame(copy=False)<br>最小構成の一時 DF"]
401+
F["groupby.mean()<br>Cython 最適化パス 🔥<br>sort=False でハッシュのみ"]
402+
G["to_numpy() で値取得<br>np.floor ROUND_HALF_UP"]
403403
H["出力: query_name / quality / poor_query_percentage"]
404404
405405
A --> B

SQL/Leetcode/Basic select/1211. Queries Quality and Percentage/Claude Sonnet 4.6 Extended/Queries_Quality_and_Percentage_postgresql.md

Lines changed: 20 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -132,12 +132,12 @@ GROUP BY g.query_name;
132132

133133
```mermaid
134134
flowchart TD
135-
A["入力: Queries テーブル\n(query_name, result, position, rating)"]
136-
B["WHERE query_name IS NOT NULL\nNULL行を除外"]
137-
C["GROUP BY query_name\nグループ化"]
138-
D["AVG(rating::NUMERIC / position)\n→ quality"]
139-
E["COUNT FILTER(rating < 3) * 100.0 / COUNT(*)\n→ poor_query_percentage"]
140-
F["ROUND(..., 2)\n小数2桁に丸め"]
135+
A["入力: Queries テーブル<br>(query_name, result, position, rating)"]
136+
B["WHERE query_name IS NOT NULL<br>NULL行を除外"]
137+
C["GROUP BY query_name<br>グループ化"]
138+
D["AVG(rating::NUMERIC / position)<br>→ quality"]
139+
E["COUNT FILTER(rating < 3) * 100.0 / COUNT(*)<br>→ poor_query_percentage"]
140+
F["ROUND(..., 2)<br>小数2桁に丸め"]
141141
G["出力: query_name / quality / poor_query_percentage"]
142142
143143
A --> B
@@ -191,7 +191,12 @@ LATERAL版: 233ms / 47% ← 不要な二重スキャン
191191

192192
---
193193

194-
## ✅ 改善版(推奨)
194+
## ✅ 改善版(推奨・要件緩和時)
195+
196+
> **⚠️ 注意: 実行時間のブレと精度のトレードオフ**
197+
> LeetCode 上での `223 ms → 221 ms` の変化は**ベンチマークのブレの範囲内**(ノイズ)である可能性が高いです。
198+
> 中間集計に `float8`(倍精度浮動小数点)を利用すると、ネイティブ CPU 処理により微小なパフォーマンス向上が期待できますが、同時に**浮動小数点演算特有の丸め誤差(Precision Loss)**が発生するリスクがあります。
199+
> 本問のように `ROUND(..., 2)` で小数第2位までに丸める場合は許容範囲内となりますが、金融系やより厳密な精度が求められるケースでは、パフォーマンスを犠牲にしても**元解法の `NUMERIC` のまま計算するアプローチ**が推奨されます。
195200
196201
```sql
197202
-- Runtime 221 ms
@@ -209,14 +214,14 @@ WHERE query_name IS NOT NULL
209214
GROUP BY query_name;
210215
```
211216

212-
### 変更点の差分
217+
### 変更点の差分と影響
213218

214219
```diff
215220
- ROUND(AVG(rating::NUMERIC / position), 2)
216221
+ ROUND(AVG(rating::float8 / position)::NUMERIC, 2)
217222

218223
-- ↑ 中間計算を float8(倍精度浮動小数点)で行い、最後だけ NUMERIC にキャスト
219-
-- NUMERIC演算はソフトウェア実装FLOATはCPUネイティブ命令で高速
224+
-- NUMERIC演算はソフトウェア実装で正確無比FLOATはCPUネイティブ命令で高速だが誤差に注意
220225
```
221226

222227
---
@@ -225,12 +230,12 @@ GROUP BY query_name;
225230

226231
```mermaid
227232
flowchart TD
228-
A["Queries テーブル\nフルスキャン O(N)"]
229-
A_F["WHERE query_name IS NOT NULL\nNULL行を除外"]
230-
B["GROUP BY query_name\nHash Aggregate"]
231-
C["AVG(rating::float8 / position)\nFLOAT演算 CPU ネイティブ ⚡"]
232-
D["FILTER(rating < 3)\nCOUNT条件集計"]
233-
E["::NUMERIC キャスト\n最後の1回のみ"]
233+
A["Queries テーブル<br>フルスキャン O(N)"]
234+
A_F["WHERE query_name IS NOT NULL<br>NULL行を除外"]
235+
B["GROUP BY query_name<br>Hash Aggregate"]
236+
C["AVG(rating::float8 / position)<br>FLOAT演算 CPU ネイティブ ⚡"]
237+
D["FILTER(rating < 3)<br>COUNT条件集計"]
238+
E["::NUMERIC キャスト<br>最後の1回のみ"]
234239
F["ROUND(..., 2)"]
235240
G["出力"]
236241

0 commit comments

Comments
 (0)