Skip to content

Commit b114f12

Browse files
committed
Add comprehensive float32 precision analysis and test suite
Investigated reported issue of false negatives in overlap detection due to float32 rounding. Created extensive test suite and detailed analysis report. Changes: - Add FLOAT32_PRECISION_ANALYSIS.md: Comprehensive investigation report - Documented code-level vulnerabilities in float32 precision handling - Identified asymmetry between float64 and float32 input handling - Analyzed theoretical risks and edge cases - Provided recommendations for mitigation - Add test_float32_overlap_issue.py: Basic precision tests - Very small overlap detection - Float32 precision boundary tests - Query method verification - ULP (Unit in Last Place) separation tests - Add test_float32_refined.py: Advanced precision tests - Internal float32 representation verification - Mixed precision (float32 tree + float64 query) scenarios - Gap creation via rounding - Specific failing case analysis - Add test_float32_extreme.py: Extreme edge case tests - Minimal overlap at ULP boundaries - Negative coordinates with precision loss - Accumulated rounding errors - Subnormal float32 values - Double rounding effects Findings: - Confirmed code vulnerability: float32 input lacks refinement mechanism - Float64 input uses idx2exact for precision refinement, float32 does not - Unable to reproduce false negatives in synthetic tests - Closed interval semantics (<=) properly handles touching boxes - Issue likely requires specific real-world data to reproduce Note: All tests pass without detecting false negatives, suggesting the issue may be context-dependent or require specific coordinate patterns.
1 parent ddb3f0c commit b114f12

File tree

4 files changed

+941
-0
lines changed

4 files changed

+941
-0
lines changed

FLOAT32_PRECISION_ANALYSIS.md

Lines changed: 158 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
1+
# Float32 Precision Issue Analysis
2+
3+
## 報告された問題
4+
5+
float32への丸め込みで偽陰性(false negative)で重なりが検出されないという報告。
6+
7+
## 調査結果
8+
9+
### コードベースの分析
10+
11+
#### 1. 内部表現
12+
- すべてのバウンディングボックスは内部的に`Real`型(=`float`)で保存される
13+
- `include/prtree/core/detail/bounding_box.h:17`で定義: `using Real = float;`
14+
15+
#### 2. 精度補正メカニズム(float64入力時のみ)
16+
17+
**float64入力の場合** (`include/prtree/core/prtree.h:213-291`):
18+
```cpp
19+
// Constructor for float64 input (float32 tree + double refinement)
20+
PRTree(const py::array_t<T> &idx, const py::array_t<double> &x)
21+
```
22+
- 内部的にfloat32に変換してツリーを構築
23+
- しかし、元のdouble精度の座標を`idx2exact`に保存(line 274)
24+
- クエリ時に`refine_candidates()`メソッド(line 805-831)でdouble精度で再チェック
25+
26+
**float32入力の場合** (`include/prtree/core/prtree.h:138-210`):
27+
```cpp
28+
// Constructor for float32 input (no refinement, pure float32 performance)
29+
PRTree(const py::array_t<T> &idx, const py::array_t<float> &x)
30+
```
31+
- float32のまま処理
32+
- `idx2exact`は空のまま(line 157のコメント: "idx2exact is NOT populated for float32 input")
33+
- **補正が行われない**
34+
35+
#### 3. 交差判定ロジック
36+
37+
`include/prtree/core/detail/bounding_box.h:106-125`:
38+
```cpp
39+
bool operator()(const BB &target) const {
40+
// ... (省略)
41+
for (int i = 0; i < D; ++i) {
42+
flags[i] = -minima[i] <= maxima[i]; // 閉区間セマンティクス
43+
}
44+
// ...
45+
}
46+
```
47+
48+
- すべてfloat32で計算される
49+
- `<=`を使用(touching boxes are considered intersecting)
50+
51+
#### 4. query_intersections()メソッド
52+
53+
`include/prtree/core/prtree.h:894-1040`:
54+
- line 963-965と993-996で、`idx2exact`が空でない場合のみ補正を行う
55+
- **float32入力の場合は補正がスキップされる**(line 808-810)
56+
57+
### 理論的な脆弱性
58+
59+
1. **丸め込みによる精度損失**:
60+
- float64で表現された微小な重なりがfloat32に変換される際に失われる可能性
61+
- 特に大きな座標値(例: 10^7以上)では、float32のULP(Unit in Last Place)が大きくなる
62+
63+
2. **補正メカニズムの非対称性**:
64+
- float64入力: float32ツリー + double補正
65+
- float32入力: float32ツリーのみ(補正なし)
66+
- これにより、同じデータでも入力型によって結果が異なる可能性
67+
68+
3. **潜在的な偽陰性シナリオ**:
69+
- 2つのAABBが非常に小さな量で重なる
70+
- その重なりがfloat32の精度限界以下
71+
- float32に丸められた後、重ならなくなる
72+
73+
### テスト結果
74+
75+
複数のテストケースを作成して検証を試みましたが、実際の偽陰性を再現することはできませんでした:
76+
77+
1. **test_float32_overlap_issue.py**: 基本的な精度テスト
78+
2. **test_float32_refined.py**: より厳密な精度境界テスト
79+
3. **test_float32_extreme.py**: 極端なケース(ULP境界、負の座標、subnormal値など)
80+
81+
#### テスト結果の考察
82+
83+
すべてのテストで偽陰性は検出されませんでした。理由として考えられるのは:
84+
85+
1. **閉区間セマンティクス**: `<=`比較により、境界で接触するボックスは常に交差と判定される
86+
2. **一貫した丸め込み**: 両方のボックスが同じ精度(float32)で保存されるため、比較は一貫している
87+
3. **テストケースの限界**: 実際の報告された問題を再現する特定のデータセットが必要な可能性
88+
89+
## 問題の根本原因(理論的分析)
90+
91+
報告された偽陰性の問題は、以下の条件で発生する可能性があります:
92+
93+
### ケース1: 異なる精度での構築とクエリ
94+
95+
```python
96+
# float32でツリーを構築
97+
boxes_f32 = np.array([[0.0, 0.0, 100.0, 100.0]], dtype=np.float32)
98+
tree = PRTree2D(np.array([0]), boxes_f32)
99+
100+
# float64でクエリ(わずかに異なる境界値)
101+
query_f64 = np.array([100.0 + epsilon, 0.0, 200.0, 100.0], dtype=np.float64)
102+
result = tree.query(query_f64) # 偽陰性の可能性
103+
```
104+
105+
### ケース2: 大きな座標値での微小な重なり
106+
107+
float32の精度限界:
108+
- 100付近: ULP ≈ 7.6e-6
109+
- 10,000付近: ULP ≈ 0.000977
110+
- 1,000,000付近: ULP ≈ 0.0625
111+
- 16,777,216 (2^24)付近: ULP = 2.0
112+
113+
大きな座標値では、微小な重なりが丸め込みで失われやすい。
114+
115+
### ケース3: 累積丸め込みエラー
116+
117+
複数の演算を経た座標値は、累積的な丸め込みエラーにより、
118+
元の値から大きくずれる可能性がある。
119+
120+
## 推奨される対策
121+
122+
1. **float64入力の使用を推奨**:
123+
- float64入力を使用すれば、内部補正メカニズムにより高精度が保たれる
124+
125+
2. **float32入力にも補正メカニズムを追加**:
126+
- float32で構築されたツリーでも、クエリ時にはdouble精度で再チェック
127+
- ただし、元の精度情報が失われているため完全な補正は不可能
128+
129+
3. **ドキュメントの改善**:
130+
- float32使用時の精度制限を明示的に文書化
131+
- 高精度が必要な場合はfloat64の使用を推奨
132+
133+
4. **精度警告の追加**:
134+
- 大きな座標値(>10^6)でfloat32を使用する場合、警告を表示
135+
136+
## 検証スクリプト
137+
138+
以下の3つのテストスクリプトを作成しました:
139+
140+
1. `test_float32_overlap_issue.py`: 基本的な偽陰性テスト
141+
2. `test_float32_refined.py`: より厳密な精度境界テスト
142+
3. `test_float32_extreme.py`: 極端なエッジケーステスト
143+
144+
実行方法:
145+
```bash
146+
python test_float32_overlap_issue.py
147+
python test_float32_refined.py
148+
python test_float32_extreme.py
149+
```
150+
151+
## 結論
152+
153+
1. **コードレベルでの脆弱性確認**: float32入力時の補正メカニズムの欠如を確認
154+
2. **実際の偽陰性の再現**: テストケースでは再現できず
155+
3. **理論的なリスク**: 特定の条件下(大きな座標値、微小な重なり)で偽陰性が発生する可能性あり
156+
4. **推奨事項**: 高精度が必要な場合はfloat64入力を使用すること
157+
158+
この問題を完全に解決するには、報告者から具体的なデータセットや再現手順の提供が必要です。

0 commit comments

Comments
 (0)