chronaxis.core.lookup_reference
源码基线:8904c2f744951857659abd40aaa3535d57faf53c
1"""用标量二分搜索一维表,精确命中和两种阶梯模式直接取节点原值。23输入为编译节点保存的不可变表和已换到输入轴单位的标量。线性模式只在4严格内部点做浮点运算,无效输入、越界和非有限中间运算保留各自原因。5独立参考实现不导入 NumPy,不保存时序状态。6"""78from math import isfinite9from .numeric import ScalarValue, to_float_reference10from .types import QualityFlag as Q111213def lookup_reference(table, value):14 """查询一个标量。参数: 已准备表和数值输入。返回: 表单位对应的标量。异常: 非法声明类型。"""15 x = to_float_reference(value)16 if not x.valid:17 return ScalarValue(None, table.dtype, False, x.quality)18 count = len(table.points)19 lo, hi = 0, count20 while lo < hi:21 middle = (lo + hi) // 222 if table.axis_at(middle) < x.value:23 lo = middle + 124 else:25 hi = middle26 # 精确命中先返回节点,极大端点不会因相邻差溢出丢失。27 if lo < count and table.axis_at(lo) == x.value:28 return ScalarValue(table.value_at(lo), table.dtype)29 if lo == 0 or lo == count:30 if table.bounds == 'invalid':31 return ScalarValue(None, table.dtype, False, Q.OUT_OF_RANGE)32 return ScalarValue(table.value_at(0 if lo == 0 else count - 1), table.dtype)33 if table.mode != 'linear':34 return ScalarValue(table.value_at(lo - 1 if table.mode == 'previous' else lo), table.dtype)35 # 有限的极端坐标相减仍可能溢出;不能因随后除以无穷而静默得到端点。36 left, right = table.axis_at(lo - 1), table.axis_at(lo)37 y0, y1 = table.value_at(lo - 1), table.value_at(lo)38 if y0 == y1:39 return ScalarValue(y0, table.dtype)40 span = right - left41 if not isfinite(span):42 return ScalarValue(None, table.dtype, False, Q.NONFINITE)43 fraction = (x.value - left) / span44 if fraction == 0.0 or fraction == 1.0:45 return ScalarValue(None, table.dtype, False, Q.PRECISION_LOSS)46 # 同号用差值式,异号用加权和,避免相减溢出或等号端点无故改变。47 result = (y0 + fraction * (y1 - y0) if (y0 >= 0) == (y1 >= 0) else48 (1.0 - fraction) * y0 + fraction * y1)49 return (ScalarValue(result, table.dtype) if isfinite(result) else50 ScalarValue(None, table.dtype, False, Q.NONFINITE))51