fix(kp): place exact angular boundaries on the opening subdivision
Upstream 8eec9a54. Floating accumulation and a 120-degree remainder put star, pada, and sub-lord on different sides of the same boundary. Random longitudes away from those boundaries are unchanged. BUG-1383. Co-Authored-By: Grok (agent loop) Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
co-authored by
Grok (agent loop)
Cursor
parent
5be864a8e4
commit
b5eb72343a
+34
-33
@@ -11,7 +11,10 @@ KP (Krishnamurti Paddhati) 占星系统模块
|
||||
"""
|
||||
|
||||
import json
|
||||
import math
|
||||
from bisect import bisect_right
|
||||
from datetime import datetime, timedelta
|
||||
from fractions import Fraction
|
||||
from pathlib import Path
|
||||
from typing import Any, Dict, List, Tuple, Optional
|
||||
|
||||
@@ -44,6 +47,29 @@ VIMSHOTTARI_YEARS = dict(zip(KP_LORDS, VIMSHOTTARI_DURATION))
|
||||
|
||||
NAKSHATRA_SPAN = 360.0 / 27.0 # 13.333... degrees
|
||||
|
||||
|
||||
def _angular_partition_starts():
|
||||
"""Exact proportional starts, rounded once at the float API boundary."""
|
||||
starts, owners = [], []
|
||||
for star in range(27):
|
||||
sub_start = Fraction(40 * star, 3)
|
||||
for offset in range(9):
|
||||
sub = (star + offset) % 9
|
||||
sub_span = Fraction(40, 3) * VIMSHOTTARI_DURATION[sub] / 120
|
||||
child_start = sub_start
|
||||
for child_offset in range(9):
|
||||
child = (sub + child_offset) % 9
|
||||
starts.append(float(child_start))
|
||||
owners.append((sub, child))
|
||||
child_start += sub_span * VIMSHOTTARI_DURATION[child] / 120
|
||||
sub_start += sub_span
|
||||
return starts, owners
|
||||
|
||||
|
||||
_KP_STARTS, _KP_OWNERS = _angular_partition_starts()
|
||||
_STAR_STARTS = [float(Fraction(40 * i, 3)) for i in range(27)]
|
||||
_PADA_STARTS = [float(Fraction(10 * i, 3)) for i in range(108)]
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[1]
|
||||
|
||||
|
||||
@@ -228,50 +254,25 @@ def get_kp_lords(degree: float) -> Dict:
|
||||
Returns:
|
||||
KP lords字典
|
||||
"""
|
||||
if isinstance(degree, bool) or not isinstance(degree, (int, float)) or not math.isfinite(degree):
|
||||
raise ValueError('KP longitude must be a finite number')
|
||||
deg = degree % 360
|
||||
|
||||
# 1. Sign lord
|
||||
sign_index = int(deg // 30)
|
||||
|
||||
# 2. Nakshatra
|
||||
nakshatra_index = int(deg // NAKSHATRA_SPAN) % 27
|
||||
nakshatra_deg = deg % NAKSHATRA_SPAN
|
||||
pada = int(nakshatra_deg // (NAKSHATRA_SPAN / 4)) + 1
|
||||
|
||||
# 3. Sublord & SubSubLord(KP核心算法)
|
||||
# 将Vimshottari 120年周期按比例投影到度数上
|
||||
deg_remainder = deg - 120 * int(deg / 120)
|
||||
deg_cumulative = 0.0
|
||||
|
||||
for i in range(9):
|
||||
deg_nl = NAKSHATRA_SPAN # 13.333... degrees per nakshatra
|
||||
for j in range(i, i + 9):
|
||||
j_mod = j % 9
|
||||
deg_sl = deg_nl * VIMSHOTTARI_DURATION[j_mod] / 120.0
|
||||
for k in range(j_mod, j_mod + 9):
|
||||
k_mod = k % 9
|
||||
deg_ss = deg_sl * VIMSHOTTARI_DURATION[k_mod] / 120.0
|
||||
deg_cumulative += deg_ss
|
||||
if deg_cumulative >= deg_remainder:
|
||||
return {
|
||||
'rasi_lord': SIGN_LORDS.get(SIGNS[sign_index], ''),
|
||||
'sign': SIGNS[sign_index],
|
||||
'nakshatra': NAKSHATRAS[nakshatra_index],
|
||||
'nakshatra_lord': STAR_LORDS[nakshatra_index],
|
||||
'pada': pada,
|
||||
'sub_lord': KP_LORDS[j_mod],
|
||||
'sub_sub_lord': KP_LORDS[k_mod],
|
||||
}
|
||||
|
||||
# Fallback
|
||||
# 2. Nakshatra. A shared boundary belongs to the subdivision that opens there.
|
||||
nakshatra_index = bisect_right(_STAR_STARTS, deg) - 1
|
||||
pada = (bisect_right(_PADA_STARTS, deg) - 1) % 4 + 1
|
||||
sub, child = _KP_OWNERS[bisect_right(_KP_STARTS, deg) - 1]
|
||||
return {
|
||||
'rasi_lord': SIGN_LORDS.get(SIGNS[sign_index], ''),
|
||||
'sign': SIGNS[sign_index],
|
||||
'nakshatra': NAKSHATRAS[nakshatra_index],
|
||||
'nakshatra_lord': STAR_LORDS[nakshatra_index],
|
||||
'pada': pada,
|
||||
'sub_lord': 'Unknown',
|
||||
'sub_sub_lord': 'Unknown',
|
||||
'sub_lord': KP_LORDS[sub],
|
||||
'sub_sub_lord': KP_LORDS[child],
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user