Chronaxis用户手册English
本页目录

chronaxis.core.numeric_point

源码基线:8904c2f744951857659abd40aaa3535d57faf53c

1"""生产逐点计算的定宽数值原语,不构造单元素数组。23输入是编译器已核实类型和单位的ScalarValue。输出保留数值类型、无效原因和4有限精度要求;整数用无界临时值验证定宽结果,float转换先检查有效尾位。5这些函数不调用参考数值实现,不读写来源,也不持有跨点状态。6"""78from math import isfinite, sqrt9import operator1011from .scalar import INTEGER_BOUNDS, ScalarValue12from .types import QualityFlag as Q, SignalDType as D, _QUALITY_BY_MASK1314_COMPARE = {'eq': operator.eq, 'ne': operator.ne, 'lt': operator.lt,15            'le': operator.le, 'gt': operator.gt, 'ge': operator.ge}16_ARITHMETIC = {'add': operator.add, 'sub': operator.sub,17               'mul': operator.mul, 'div': operator.truediv}181920def failed(dtype, quality, labels=()):21    """构造不可用结果。参数: 目标类型、真实原因、枚举域。返回: ScalarValue。异常: 模型合同错误。"""22    return ScalarValue(None, dtype, False, quality, labels)232425def exact_float(value):26    """按整数幅度的有效尾位判断float64可表示性。2728    参数: 原生int或float。返回: (有限float或None, 质量)。29    异常: 非数值结构错误;超大整数作为NONFINITE返回,不抛转换溢出。30    """31    if type(value) is float:32        return (value, Q.NONE) if isfinite(value) else (None, Q.NONFINITE)33    if type(value) is not int:34        raise TypeError('逐点浮点转换需要原生数值')35    magnitude = abs(value)36    shift = max(0, magnitude.bit_length() - 53)37    # 超出有限float64的幅度先归类,不能把无穷转换误报为一般精度失败。38    if magnitude.bit_length() > 1024:39        return None, Q.NONFINITE40    try:41        number = float(value)42    except OverflowError:43        return None, Q.NONFINITE44    if not isfinite(number):45        return None, Q.NONFINITE46    if shift and magnitude & ((1 << shift) - 1):47        return None, Q.PRECISION_LOSS48    return number, Q.NONE495051def to_float_point(value):52    """无损转换当前数值。参数: ScalarValue。返回: FLOAT64值。异常: 非数值类型。"""53    if value.dtype not in (*INTEGER_BOUNDS, D.FLOAT64):54        raise TypeError('逐点浮点转换需要数值类型')55    if not value.valid:56        return failed(D.FLOAT64, value.quality)57    number, quality = exact_float(value.value)58    return failed(D.FLOAT64, quality) if quality else ScalarValue(number, D.FLOAT64)596061def checked_result(number, dtype):62    """校验计算完成后的定宽范围或有限性。参数: 数值、静态类型。返回: typed值。异常: 非数值类型。"""63    if dtype in INTEGER_BOUNDS:64        lower, upper = INTEGER_BOUNDS[dtype]65        return (ScalarValue(number, dtype) if lower <= number <= upper66                else failed(dtype, Q.OVERFLOW))67    if dtype is D.FLOAT64:68        return ScalarValue(number, dtype) if isfinite(number) else failed(dtype, Q.NONFINITE)69    raise TypeError('逐点数值结果类型不合法')707172def binary_point(op, left, right, dtype):73    """计算已通过静态类型检查的二元运算。7475    参数: 固定操作名、两侧typed值、编译后的结果dtype。返回: ScalarValue。76    异常: 未登记操作或内部类型合同错误;除零和定宽失败转成质量。77    """78    quality = _QUALITY_BY_MASK[int(left.quality) | int(right.quality)]79    if quality:80        return failed(dtype, quality)81    if left.dtype is D.ENUM and left.labels != right.labels:82        raise ValueError('枚举比较需要相同标签域')83    a, b = left.value, right.value84    floating = dtype is D.FLOAT64 or op in _COMPARE and D.FLOAT64 in (left.dtype, right.dtype)85    if floating:86        a, aq = exact_float(a)87        b, bq = exact_float(b)88        quality = _QUALITY_BY_MASK[int(aq) | int(bq)]89        if quality:90            return failed(dtype, quality)91    # int64/uint64比较直接用精确整数,不经过NumPy混合提升或float。92    if op in _COMPARE:93        return ScalarValue(_COMPARE[op](a, b), D.BOOL)94    if op == 'div' and b == 0:95        return failed(dtype, Q.DOMAIN_ERROR)96    return checked_result(_ARITHMETIC[op](a, b), dtype)979899def unary_point(op, value):100    """计算取负或绝对值。参数: 操作名、typed数值。返回: 同型值。异常: 未知操作。"""101    if not value.valid:102        return failed(value.dtype, value.quality)103    number = abs(value.value) if op == 'abs' else -value.value if op == 'neg' else None104    if number is None:105        raise ValueError('未登记的逐点单目运算')106    return checked_result(number, value.dtype)107108109def affine_point(value, scale, offset, dtype):110    """按完整value*scale+offset换算当前值,不进行第二次DBC换算。111112    参数: 已编译的数值、系数和目标dtype。返回: ScalarValue。113    异常: 内部静态合同错误;数值失败保存为质量。114    """115    if not value.valid:116        return failed(dtype, value.quality)117    if dtype in INTEGER_BOUNDS:118        if value.dtype not in INTEGER_BOUNDS or type(scale) is not int or type(offset) is not int:119            raise ValueError('整数仿射转换需要整数输入及系数')120        return checked_result(value.value * scale + offset, dtype)121    number, nq = exact_float(value.value)122    factor, fq = exact_float(scale)123    shift, sq = exact_float(offset)124    quality = _QUALITY_BY_MASK[int(nq) | int(fq) | int(sq)]125    if quality:126        return failed(dtype, quality)127    result = number * factor + shift128    if not isfinite(result):129        return failed(dtype, Q.NONFINITE)130    # 偏移抵消为零合法,纯倍率把非零压成零才是精度丢失。131    if shift == 0 and factor != 0 and number != 0 and result == 0:132        return failed(dtype, Q.PRECISION_LOSS)133    return ScalarValue(result, dtype)134135136def logic_point(op, values):137    """按对称三值规则求布尔值。参数: 固定逻辑操作和typed值。返回: BOOL。异常: 未知操作。"""138    if op == 'not':139        value = values[0]140        return ScalarValue(not value.value, D.BOOL) if value.valid else failed(D.BOOL, value.quality)141    if op not in ('and', 'or'):142        raise ValueError('未登记的逐点逻辑操作')143    deciding = op == 'or'144    quality = Q.NONE145    for value in values:146        quality = _QUALITY_BY_MASK[int(quality) | int(value.quality)]147        if value.valid and value.value is deciding:148            return ScalarValue(deciding, D.BOOL)149    return failed(D.BOOL, quality) if quality else ScalarValue(not deciding, D.BOOL)150151152def math_point(op, values):153    """执行极值、限幅和开方。参数: 已统一类型/单位的实参。返回: typed结果。异常: 未知操作。"""154    first = values[0]155    if op == 'sqrt':156        if not first.valid:157            return failed(D.FLOAT64, first.quality)158        if first.value < 0:159            return failed(D.FLOAT64, Q.DOMAIN_ERROR)160        number = to_float_point(first)161        return number if not number.valid else ScalarValue(sqrt(number.value), D.FLOAT64)162    quality = Q.NONE163    for value in values:164        quality = _QUALITY_BY_MASK[int(quality) | int(value.quality)]165    if op == 'clip':166        lower, upper = values[1:]167        # 即使输入无效,只要两边界有效且倒置,也应保留这个域错误。168        if lower.valid and upper.valid and lower.value > upper.value:169            quality = _QUALITY_BY_MASK[int(quality) | int(Q.DOMAIN_ERROR)]170        if quality:171            return failed(first.dtype, quality)172        result = lower if first.value < lower.value else upper if first.value > upper.value else first173        return ScalarValue(result.value, first.dtype)174    if op not in ('minimum', 'maximum'):175        raise ValueError('未登记的逐点数值函数')176    if quality:177        return failed(first.dtype, quality)178    number = first.value179    compare = operator.lt if op == 'minimum' else operator.gt180    # 严格比较保留第一个相等参数及其负零符号。181    for value in values[1:]:182        if compare(value.value, number):183            number = value.value184    return ScalarValue(number, first.dtype)185186187def integer_point(node, values):188    """执行定宽取余、位操作和精确转整数。189190    参数: 编译节点及typed实参。返回: 静态dtype结果。191    异常: 未知操作;小数、越界、零除保存对应质量。192    """193    value = values[0]194    quality = value.quality195    for item in values[1:]:196        quality = _QUALITY_BY_MASK[int(quality) | int(item.quality)]197    if quality:198        return failed(node.dtype, quality)199    number = value.value200    if node.operator == 'mod':201        divisor = values[1].value202        return failed(node.dtype, Q.DOMAIN_ERROR) if divisor == 0 else ScalarValue(number % divisor, node.dtype)203    if node.operator in ('bit_test', 'bit_extract'):204        start, width = node.value205        bits = ((number & ((1 << 64) - 1)) >> start) & ((1 << width) - 1)206        return ScalarValue(bool(bits) if node.dtype is D.BOOL else bits, node.dtype)207    if node.operator not in ('to_int64', 'to_uint64'):208        raise ValueError('未登记的逐点整数操作')209    if value.dtype is D.FLOAT64 and not number.is_integer():210        return failed(node.dtype, Q.PRECISION_LOSS)211    number = int(number)212    return checked_result(number, node.dtype)213214215def lookup_point(table, axis, nodes, value):216    """用准备期只读表视图查一个有效点,不建立单元素列。217218    参数: 已核表、只读轴和值列、typed输入。返回: 表声明类型的值。219    异常: 静态表结构错误;范围、精度及非有限结果保存为质量。220    """221    query = to_float_point(value)222    if not query.valid:223        return failed(table.dtype, query.quality)224    x = query.value225    # searchsorted只返回标量下标;轴和值视图由计划持有,不在每点重建。226    hi = int(axis.searchsorted(x, side='left'))227    count = len(axis)228    index = min(hi, count - 1)229    if x == float(axis[index]):230        return ScalarValue(nodes[index].item(), table.dtype)231    if hi == 0 or hi == count:232        return (ScalarValue(nodes[index].item(), table.dtype) if table.bounds == 'clamp'233                else failed(table.dtype, Q.OUT_OF_RANGE))234    if table.mode != 'linear':235        return ScalarValue(nodes[hi - 1 if table.mode == 'previous' else hi].item(), table.dtype)236    left, right = float(axis[hi - 1]), float(axis[hi])237    y0, y1 = float(nodes[hi - 1]), float(nodes[hi])238    if y0 == y1:239        return ScalarValue(y0, table.dtype)240    span = right - left241    fraction = (x - left) / span242    # 同号避免不必要的乘加抵消;异号不形成可能溢出的y1-y0。243    result = (y0 + fraction * (y1 - y0) if (y0 >= 0) == (y1 >= 0)244              else (1.0 - fraction) * y0 + fraction * y1)245    if not isfinite(span) or not isfinite(result):246        return failed(table.dtype, Q.NONFINITE)247    if fraction == 0 or fraction == 1:248        return failed(table.dtype, Q.PRECISION_LOSS)249    return ScalarValue(result, table.dtype)250
Chronaxis 用户手册 · 离线阅读