640 lines
21 KiB
Plaintext
640 lines
21 KiB
Plaintext
from stdint import *
|
||
import t, c
|
||
import stdio
|
||
|
||
|
||
# String copy function
|
||
def strcpy(dest: str, src: str) -> str:
|
||
if dest == None or src == None: return None
|
||
original_dest: str = dest
|
||
for s in src:
|
||
dest[0] = s
|
||
dest += 1
|
||
dest[0] = 0
|
||
return original_dest
|
||
|
||
|
||
# String concatenate function
|
||
def strcat(dest: str, src: str) -> str:
|
||
if dest == None or src == None: return dest
|
||
original_dest: str = dest
|
||
# Find end of dest
|
||
while dest[0] != '\0':
|
||
dest += 1
|
||
# Copy src
|
||
for s in src:
|
||
dest[0] = s
|
||
dest += 1
|
||
dest[0] = 0
|
||
return original_dest
|
||
|
||
|
||
# String copy function with limited length
|
||
def strncpy(dest: str, src: str, n: t.CSizeT) -> str:
|
||
if dest == None or src == None or n == 0: return dest
|
||
original_dest: str = dest
|
||
i: t.CSizeT = 0
|
||
for s in src:
|
||
if i >= n: break
|
||
dest[0] = s
|
||
dest += 1
|
||
i += 1
|
||
# Fill remaining space with '\0'
|
||
while i < n:
|
||
dest[0] = 0
|
||
dest += 1
|
||
i += 1
|
||
return original_dest
|
||
|
||
|
||
# String concatenate function with limited length
|
||
def strncat(dest: str, src: str, n: t.CSizeT) -> str:
|
||
if dest == None or src == None or n == 0: return dest
|
||
original_dest: str = dest
|
||
# Find end of dest
|
||
while dest[0] != '\0':
|
||
dest += 1
|
||
# Copy up to n chars from src
|
||
i: t.CSizeT = 0
|
||
for s in src:
|
||
if i >= n: break
|
||
dest[0] = s
|
||
dest += 1
|
||
i += 1
|
||
dest[0] = 0
|
||
return original_dest
|
||
|
||
|
||
# String length function
|
||
export def strlen(src: str) -> t.CSizeT:
|
||
length: t.CSizeT = 0
|
||
for _ in src:
|
||
length += 1
|
||
return length
|
||
|
||
# String comparison function
|
||
# 注意:str1[0] - str2[0] 是 i8 减法会回绕(0xFF 表示 -1),返回前必须
|
||
# int() 提升到 i32 再相减(与下方 memcmp 的 int(p1[i]) - int(p2[i]) 一致),
|
||
# 否则 strcmp("abc","abd") 返回 255 而非 -1(StringTest Test 4 根因)。
|
||
def strcmp(str1: str, str2: str) -> int:
|
||
# 指针相等短路(降单次成本,不降调用次数):查表/自比较场景常拿同一驻留
|
||
# 字符串与自身比较(如 HashTable 以同一指针 set/lookup),指针相同则内容
|
||
# 必相同,直接返回 0,省去整趟逐字节循环;指针不同则走下方原逻辑。
|
||
# 语义严格不变(相同指针 ⇒ 内容相同 ⇒ strcmp 结果本应为 0)。
|
||
if str1 == str2:
|
||
return 0
|
||
while str1[0] != '\0' and str2[0] != '\0':
|
||
if str1[0] != str2[0]:
|
||
return int(str1[0]) - int(str2[0])
|
||
str1 += 1
|
||
str2 += 1
|
||
return int(str1[0]) - int(str2[0])
|
||
|
||
def samestr(str1: str, str2: str) -> bool:
|
||
return strcmp(str1, str2) == 0
|
||
|
||
|
||
# String compare function with limited length
|
||
def strncmp(str1: str, str2: str, n: t.CSizeT) -> int:
|
||
# 指针相等短路(同 strcmp):相同指针在任意 n 下比较结果恒为 0(相同字符串
|
||
# 的前 n 个字符必然相等),直接返回 0,语义严格不变。
|
||
if str1 == str2:
|
||
return 0
|
||
i: t.CSizeT = 0
|
||
while str1[0] != '\0' and str2[0] != '\0' and i < n:
|
||
if str1[0] != str2[0]:
|
||
return int(str1[0]) - int(str2[0])
|
||
str1 += 1
|
||
str2 += 1
|
||
i += 1
|
||
if i < n:
|
||
return int(str1[0]) - int(str2[0])
|
||
return 0
|
||
|
||
|
||
# Memory compare function
|
||
def memcmp(ptr1: t.CPtr, ptr2: t.CPtr, n: t.CSizeT) -> int:
|
||
p1: BYTEPTR = BYTEPTR(ptr1)
|
||
p2: BYTEPTR = BYTEPTR(ptr2)
|
||
i: t.CSizeT = 0
|
||
while i < n:
|
||
if p1[i] != p2[i]:
|
||
return int(p1[i]) - int(p2[i])
|
||
i += 1
|
||
return 0
|
||
|
||
|
||
# String find function
|
||
def strchr(s: str, cr: int) -> str:
|
||
while s[0] != '\0':
|
||
if s[0] == t.CChar(cr):
|
||
return str(s)
|
||
s += 1
|
||
if cr == '\0':
|
||
return str(s)
|
||
return None
|
||
|
||
# String reverse find function (find last occurrence of character)
|
||
def strrchr(s: str, cr: int) -> str:
|
||
last: str = None
|
||
while s[0] != '\0':
|
||
if s[0] == t.CChar(cr):
|
||
last = s
|
||
s += 1
|
||
if cr == '\0': return s
|
||
return last
|
||
|
||
|
||
# Substring search function (find first occurrence of needle in s, return pointer to that position, or None if not found)
|
||
# 热点优化(实测):原实现对**每个字节位置**都调用一次 strncmp,并先对 s 做一次全文 strlen。
|
||
# 实测 strstr 被调用 918 万次、strncmp 因此被调用 7.44 亿次(占全程序调用 29%,是第一名)。
|
||
# 改为先用 strchr 跳到"首字符匹配"的候选位置(跳过绝大多数不可能匹配的字节),
|
||
# 只在候选点做整段比较;同时不再预先 strlen(s)(strncmp 本身遇 '\0' 即停,安全)。
|
||
# 语义与原实现完全一致:needle 为空返回 s;未找到返回 None。
|
||
def strstr(s: str, needle: str) -> str:
|
||
if needle[0] == 0:
|
||
return s
|
||
needle_len: t.CSizeT = strlen(needle)
|
||
if needle_len == 0:
|
||
return s
|
||
first_ch: int = int(needle[0])
|
||
cur: str = s
|
||
while True:
|
||
hit: str = strchr(cur, first_ch)
|
||
if hit is None:
|
||
return None
|
||
if strncmp(hit, needle, needle_len) == 0:
|
||
return hit
|
||
cur = hit + 1
|
||
|
||
# String skip function
|
||
def strspn(s: str, skip: str = " ") -> int:
|
||
si: int = 0
|
||
while s[si] != 0:
|
||
found: int = 0
|
||
sj: int = 0
|
||
while skip[sj] != 0:
|
||
if s[si] == skip[sj]:
|
||
found = 1
|
||
break
|
||
sj += 1
|
||
if found == 0:
|
||
break
|
||
si += 1
|
||
return si
|
||
|
||
# Memory set function
|
||
export def memset(ptr: t.CPtr, value: int, num: t.CSizeT) -> t.CPtr:
|
||
# Original implementation:
|
||
# p: BYTEPTR = BYTEPTR(ptr)
|
||
# i: t.CSizeT
|
||
# for i in range(num):
|
||
# p[i] = t.CUnsignedChar(value)
|
||
if num == 0: return ptr
|
||
c.Asm(f"""mov rdi, {c.AsmInp(ptr, t.ASM_DESCR.REG_ANY)}
|
||
mov eax, {c.AsmInp(value, t.ASM_DESCR.REG_ANY)}
|
||
mov rcx, {c.AsmInp(num, t.ASM_DESCR.REG_ANY)}
|
||
rep stosb""",
|
||
op=[t.ASM_DESCR.CLOBBER_MEMORY, t.ASM_DESCR.CLOBBER_RAX,
|
||
t.ASM_DESCR.CLOBBER_RCX, t.ASM_DESCR.CLOBBER_RDI])
|
||
return ptr
|
||
|
||
|
||
def memset32(ptr: t.CPtr, value: t.CUInt32T, count: t.CSizeT) -> t.CPtr:
|
||
# Original implementation:
|
||
# p: UINT32PTR = UINT32PTR(ptr)
|
||
# i: t.CSizeT
|
||
# for i in range(count):
|
||
# p[i] = value
|
||
if count == 0: return ptr
|
||
c.Asm(f"""mov rdi, {c.AsmInp(ptr, t.ASM_DESCR.REG_ANY)}
|
||
mov eax, {c.AsmInp(value, t.ASM_DESCR.REG_ANY)}
|
||
mov rcx, {c.AsmInp(count, t.ASM_DESCR.REG_ANY)}
|
||
rep stosd""",
|
||
op=[t.ASM_DESCR.CLOBBER_MEMORY, t.ASM_DESCR.CLOBBER_RAX,
|
||
t.ASM_DESCR.CLOBBER_RCX, t.ASM_DESCR.CLOBBER_RDI])
|
||
return ptr
|
||
|
||
|
||
# Memory copy function
|
||
export def memcpy(dest: t.CPtr, src: t.CPtr, num: t.CSizeT) -> t.CPtr:
|
||
# Original implementation:
|
||
# d: BYTEPTR = BYTEPTR(dest)
|
||
# s: BYTEPTR = BYTEPTR(src)
|
||
# i: t.CSizeT
|
||
# for i in range(num):
|
||
# d[i] = s[i]
|
||
if num == 0: return dest
|
||
c.Asm(f"""mov rdi, {c.AsmInp(dest, t.ASM_DESCR.REG_ANY)}
|
||
mov rsi, {c.AsmInp(src, t.ASM_DESCR.REG_ANY)}
|
||
mov rcx, {c.AsmInp(num, t.ASM_DESCR.REG_ANY)}
|
||
rep movsb""",
|
||
op=[t.ASM_DESCR.CLOBBER_MEMORY, t.ASM_DESCR.CLOBBER_RCX,
|
||
t.ASM_DESCR.CLOBBER_RDI, t.ASM_DESCR.CLOBBER_RSI])
|
||
return dest
|
||
|
||
|
||
# 内存移动函数
|
||
def memmove(dest: t.CPtr, src: t.CPtr, num: t.CSizeT) -> t.CPtr:
|
||
# 原始实现:
|
||
# d: BYTEPTR = BYTEPTR(dest)
|
||
# s: BYTEPTR = BYTEPTR(src)
|
||
# i: t.CSizeT
|
||
# if d < s:
|
||
# for i in range(num):
|
||
# d[i] = s[i]
|
||
# elif d > s:
|
||
# for i in range(num, 0, -1):
|
||
# d[i - 1] = s[i - 1]
|
||
if num == 0: return dest
|
||
c.Asm(f"""mov rdi, {c.AsmInp(dest, t.ASM_DESCR.REG_ANY)}
|
||
mov rsi, {c.AsmInp(src, t.ASM_DESCR.REG_ANY)}
|
||
mov rcx, {c.AsmInp(num, t.ASM_DESCR.REG_ANY)}
|
||
cmp rdi, rsi
|
||
jb 2f
|
||
std
|
||
add rdi, rcx
|
||
dec rdi
|
||
add rsi, rcx
|
||
dec rsi
|
||
rep movsb
|
||
cld
|
||
jmp 3f
|
||
2:
|
||
rep movsb
|
||
3:""",
|
||
op=[t.ASM_DESCR.CLOBBER_MEMORY, t.ASM_DESCR.CLOBBER_RCX,
|
||
t.ASM_DESCR.CLOBBER_RDI, t.ASM_DESCR.CLOBBER_RSI])
|
||
return dest
|
||
|
||
|
||
def atoi(src: str) -> int:
|
||
num: int = 0
|
||
sign: int = 1
|
||
s: str = src
|
||
if s == None: return 0
|
||
# 跳过空白
|
||
while s[0] == ' ' or s[0] == '\t' or s[0] == '\n' or s[0] == '\r':
|
||
s += 1
|
||
# 符号
|
||
if s[0] == '-':
|
||
sign = -1
|
||
s += 1
|
||
elif s[0] == '+':
|
||
s += 1
|
||
for ch in s:
|
||
if ch < '0' or ch > '9': break
|
||
digit: int = ch - '0'
|
||
num = num * 10 + digit
|
||
return num * sign
|
||
|
||
|
||
def atoll(src: str) -> t.CInt64T:
|
||
num: t.CInt64T = 0
|
||
sign: t.CInt64T = 1
|
||
s: str = src
|
||
if s == None: return 0
|
||
while s[0] == ' ' or s[0] == '\t' or s[0] == '\n' or s[0] == '\r':
|
||
s += 1
|
||
if s[0] == '-':
|
||
sign = -1
|
||
s += 1
|
||
elif s[0] == '+':
|
||
s += 1
|
||
# 十六进制前缀 0x / 0X
|
||
is_hex: int = 0
|
||
if s[0] == '0' and (s[1] == 'x' or s[1] == 'X'):
|
||
is_hex = 1
|
||
s += 2
|
||
if is_hex:
|
||
for ch in s:
|
||
d: int = 0
|
||
if ch >= '0' and ch <= '9':
|
||
d = ch - '0'
|
||
elif ch >= 'a' and ch <= 'f':
|
||
d = ch - 'a' + 10
|
||
elif ch >= 'A' and ch <= 'F':
|
||
d = ch - 'A' + 10
|
||
else:
|
||
break
|
||
digit: t.CInt64T = t.CInt64T(d)
|
||
num = num * 16 + digit
|
||
else:
|
||
for ch in s:
|
||
if ch < '0' or ch > '9': break
|
||
d: int = ch - '0'
|
||
digit: t.CInt64T = t.CInt64T(d)
|
||
num = num * 10 + digit
|
||
return num * sign
|
||
|
||
|
||
# ============================================================
|
||
# 十进制字面量 → double 的正确舍入转换(N4)
|
||
#
|
||
# 旧实现用"逐位累加 + 反复乘/除 10":小数位超过 16 位后每步都舍入
|
||
# (e 偏 +1 ULP、ln2 偏 −1 ULP),指数按 while exp>0: result*=10.0 累乘
|
||
# 308 次(DBL_MAX 偏 −6 ULP)。
|
||
# 新实现:尾数装进 u64(≤19 位;第 20 位做一次舍入),用 10 的**精确幂**
|
||
# 在**双 double(hi+lo,约 106 位)**下做一次缩放,最后一次性舍入。
|
||
# 算法先在 Python 里 1:1 对拍 float()(正确舍入)通过:20 万随机样例 +
|
||
# 边界样例在**正规数范围**内 bit-exact;次正规/溢出仍走旧逐步缩放兜底
|
||
# (语义与旧实现一致,无回归)。
|
||
# 约定:不用全局表——10^0..10^22 由循环乘 10 得到(该区间每一步都可精确
|
||
# 表示);p<0 时在正规区算 10^p×2^600 再精确缩回,避免双 double 低位在
|
||
# ~1e-292 以下掉进次正规而丢有效位。
|
||
# ============================================================
|
||
|
||
# _dd_split_hi - Dekker 分裂的上半(hi = 取高 26 位)
|
||
#
|
||
# 含量级缩尺:|a| > 6.7e292 时先乘 2^-28 再算(否则 a*(2^27+1) 溢出为 inf);
|
||
# |a| 极小(< 1e-292)时先乘 2^28(否则 lo = a-hi 掉进次正规丢位)。
|
||
# 缩尺因子均为 2 的幂 ⇒ 对正规数**无损**;调用方用 lo = a - hi 取下半部分。
|
||
def _dd_split_hi(a: double) -> double:
|
||
aa: double = a
|
||
big: int = 0
|
||
small: int = 0
|
||
if a > 6.7e292 or a < -6.7e292:
|
||
aa = a * 3.725290298461914e-09
|
||
big = 1
|
||
elif (a > 0.0 and a < 1.0e-292) or (a < 0.0 and a > -1.0e-292):
|
||
aa = a * 268435456.0
|
||
small = 1
|
||
tt: double = aa * 134217729.0
|
||
hi: double = tt - (tt - aa)
|
||
if big != 0:
|
||
return hi * 268435456.0
|
||
if small != 0:
|
||
return hi * 3.725290298461914e-09
|
||
return hi
|
||
|
||
|
||
# _dd_mul - 双 double 乘法:out = a × b(out[0]=hi, out[1]=lo)
|
||
def _dd_mul(ah: double, al: double, bh: double, bl: double,
|
||
out: t.CArray[double, 2]):
|
||
p: double = ah * bh
|
||
a_hi: double = _dd_split_hi(ah)
|
||
a_lo: double = ah - a_hi
|
||
b_hi: double = _dd_split_hi(bh)
|
||
b_lo: double = bh - b_hi
|
||
e: double = ((a_hi * b_hi - p) + a_hi * b_lo + a_lo * b_hi) + a_lo * b_lo
|
||
e = e + (ah * bl + al * bh)
|
||
s: double = p + e
|
||
out[0] = s
|
||
out[1] = e - (s - p)
|
||
|
||
|
||
# _dd_add - 双 double 加法:out = a + b
|
||
def _dd_add(ah: double, al: double, bh: double, bl: double,
|
||
out: t.CArray[double, 2]):
|
||
s: double = ah + bh
|
||
bb: double = s - ah
|
||
e: double = (ah - (s - bb)) + (bh - bb)
|
||
e = e + (al + bl)
|
||
r0: double = s + e
|
||
out[0] = r0
|
||
out[1] = e - (r0 - s)
|
||
|
||
|
||
# _dd_div - 双 double 除法:out = a / b(q0 + 一步残差修正)
|
||
def _dd_div(ah: double, al: double, bh: double, bl: double,
|
||
out: t.CArray[double, 2], tmp: t.CArray[double, 2]):
|
||
q0: double = ah / bh
|
||
_dd_mul(bh, bl, q0, 0.0, tmp)
|
||
_dd_add(ah, al, -tmp[0], -tmp[1], tmp)
|
||
q1: double = tmp[0] / bh
|
||
_dd_add(q0, 0.0, q1, 0.0, out)
|
||
|
||
|
||
# _dd_from_u64 - u64 → 双 double(精确:hi 为四舍五入值,lo 为精确残差)
|
||
def _dd_from_u64(m: t.CUInt64T, out: t.CArray[double, 2]):
|
||
hi: double = double(m)
|
||
lo: double = 0.0
|
||
if m >= t.CUInt64T(9007199254740992):
|
||
lo = double(m - t.CUInt64T(hi))
|
||
s: double = hi + lo
|
||
bb: double = s - hi
|
||
out[0] = s
|
||
out[1] = (hi - (s - bb)) + (lo - bb)
|
||
|
||
|
||
# _dd_pow10 - 10^e 的双 double(e >= 0;按 ≤22 分块,每块可精确表示)
|
||
def _dd_pow10(e: int, out: t.CArray[double, 2], tmp: t.CArray[double, 2]):
|
||
out[0] = 1.0
|
||
out[1] = 0.0
|
||
k: int = e
|
||
while k > 0:
|
||
step: int = 22
|
||
if k < 22:
|
||
step = k
|
||
p10: double = 1.0
|
||
i: int = 0
|
||
while i < step:
|
||
p10 = p10 * 10.0
|
||
i += 1
|
||
_dd_mul(out[0], out[1], p10, 0.0, tmp)
|
||
out[0] = tmp[0]
|
||
out[1] = tmp[1]
|
||
k -= step
|
||
|
||
|
||
# _pow2 - 2^n(|n| <= 1000):循环乘 2/0.5,每步精确
|
||
def _pow2(n: int) -> double:
|
||
r: double = 1.0
|
||
i: int = n
|
||
if i >= 0:
|
||
while i > 0:
|
||
r = r * 2.0
|
||
i -= 1
|
||
else:
|
||
while i < 0:
|
||
r = r * 0.5
|
||
i += 1
|
||
return r
|
||
|
||
|
||
# _atof_scale_stepwise - 旧的逐步 ×/÷10 缩放(次正规/溢出场景的兜底)
|
||
def _atof_scale_stepwise(x: double, p: int) -> double:
|
||
r: double = x
|
||
e: int = p
|
||
while e > 0:
|
||
r = r * 10.0
|
||
e -= 1
|
||
while e < 0:
|
||
r = r / 10.0
|
||
e += 1
|
||
return r
|
||
|
||
|
||
def atof(src: str) -> double:
|
||
s: str = src
|
||
if s == None: return 0.0
|
||
# 跳过空白
|
||
while s[0] == ' ' or s[0] == '\t' or s[0] == '\n' or s[0] == '\r':
|
||
s += 1
|
||
# 符号
|
||
sign: double = 1.0
|
||
if s[0] == '-':
|
||
sign = -1.0
|
||
s += 1
|
||
elif s[0] == '+':
|
||
s += 1
|
||
# 尾数:有效数字装进 u64(≤19 位),同时维护十进制指数
|
||
mant: t.CUInt64T = 0
|
||
nd: int = 0
|
||
dexp: int = 0
|
||
seen_dot: int = 0
|
||
started: int = 0
|
||
rounded: int = 0
|
||
while s[0] != '\0':
|
||
ch: t.CChar = s[0]
|
||
if ch >= '0' and ch <= '9':
|
||
d: int = ch - '0'
|
||
if started == 0:
|
||
# 前导零不进尾数;小数部分的前导零要占十进制位
|
||
if d != 0:
|
||
started = 1
|
||
mant = t.CUInt64T(d)
|
||
nd = 1
|
||
if seen_dot != 0:
|
||
dexp -= 1
|
||
elif seen_dot != 0:
|
||
dexp -= 1
|
||
elif nd < 19:
|
||
mant = mant * t.CUInt64T(10) + t.CUInt64T(d)
|
||
nd += 1
|
||
if seen_dot != 0:
|
||
dexp -= 1
|
||
else:
|
||
# 第 20 位起:整数部分丢弃的位让指数 +1;小数部分丢弃的位不影响
|
||
# 指数。只用第 20 位做一次舍入(丢弃量 <= 10^-19 相对误差)。
|
||
if seen_dot == 0:
|
||
dexp += 1
|
||
elif rounded == 0:
|
||
if d >= 5:
|
||
mant += t.CUInt64T(1)
|
||
rounded = 1
|
||
elif ch == '.':
|
||
seen_dot = 1
|
||
else:
|
||
break
|
||
s += 1
|
||
if started == 0:
|
||
return sign * 0.0
|
||
# 进位:舍入可能使 19 位变 20 位
|
||
if mant >= t.CUInt64T(10000000000000000000):
|
||
mant = mant // t.CUInt64T(10)
|
||
dexp += 1
|
||
# 指数部分
|
||
exp: int = 0
|
||
if s[0] == 'e' or s[0] == 'E':
|
||
s += 1
|
||
exp_sign: int = 1
|
||
if s[0] == '-':
|
||
exp_sign = -1
|
||
s += 1
|
||
elif s[0] == '+':
|
||
s += 1
|
||
while s[0] >= '0' and s[0] <= '9':
|
||
exp = exp * 10 + (s[0] - '0')
|
||
s += 1
|
||
exp = exp * exp_sign
|
||
p: int = dexp + exp
|
||
if p == 0:
|
||
return sign * double(mant)
|
||
# 双 double 缩放:mant × 10^p,最后一次舍入
|
||
ta: t.CArray[double, 2]
|
||
tb: t.CArray[double, 2]
|
||
tc: t.CArray[double, 2]
|
||
tr: t.CArray[double, 2]
|
||
_dd_from_u64(mant, ta)
|
||
v: double = 0.0
|
||
if p > 0:
|
||
_dd_pow10(p, tb, tr)
|
||
_dd_mul(ta[0], ta[1], tb[0], tb[1], tr)
|
||
v = tr[0] + tr[1]
|
||
else:
|
||
# p < 0:在正规区算「2^600 / 10^(-p)」= 10^p × 2^600,最后精确缩回。
|
||
# 不能直接算 10^p(|p| 大时 ~1e-308,双 double 低位掉次正规丢有效位);
|
||
# 分母按 ≤308 分块累除(10^313 会先溢出成 inf 使结果变 NaN)。
|
||
tb[0] = _pow2(600)
|
||
tb[1] = 0.0
|
||
q: int = -p
|
||
while q > 0:
|
||
step2: int = 308
|
||
if q < 308:
|
||
step2 = q
|
||
_dd_pow10(step2, tc, tr)
|
||
_dd_div(tb[0], tb[1], tc[0], tc[1], tr, tc)
|
||
tb[0] = tr[0]
|
||
tb[1] = tr[1]
|
||
q -= step2
|
||
_dd_mul(ta[0], ta[1], tb[0], tb[1], tr)
|
||
v = (tr[0] + tr[1]) * _pow2(-600)
|
||
# 正规数范围(非 NaN / 非 inf / 非次正规)→ 已正确舍入的结果
|
||
if v == v and v <= 1.7976931348623157e308 and v >= -1.7976931348623157e308 \
|
||
and (v == 0.0 or v >= 2.2250738585072014e-308 or v <= -2.2250738585072014e-308):
|
||
return sign * v
|
||
# 溢出 / 次正规 / NaN → 回退旧逐步缩放(与旧实现语义一致)
|
||
return sign * _atof_scale_stepwise(double(mant), p)
|
||
|
||
|
||
def atof_out(src: str, out: double | t.CPtr) -> int:
|
||
"""atof 结果写入 out[0](输出参数方式,避免跨模块 double 返回值传递 bug)
|
||
|
||
返回值仅表示成功与否(1=成功,0=失败),结果值通过 out 指针传递,
|
||
不依赖 double 返回值的跨模块传递。
|
||
"""
|
||
if out is None:
|
||
return 0
|
||
v: double = atof(src)
|
||
out[0] = v
|
||
return 1
|
||
|
||
def split(s: str, delim: str, result: t.CArray[str], cap: int) -> int:
|
||
"""按单字符分隔符切分 s,token 指针写入 result[0..],尾部写 None 哨兵。
|
||
|
||
cap: result 数组的**声明容量**(元素个数)。此前无容量参数 → 写
|
||
result[count] 与 result[count]=None 均无上界;token 数超过调用方数组
|
||
容量时越界写(devfs 用 t.CArray[str, 256],256 个 token 即写穿 2048 字节)。
|
||
现限制 token 数 ≤ cap-1(留一格给结尾哨兵)。
|
||
"""
|
||
count: int = 0
|
||
start: str = s
|
||
if not s or not delim or not result:
|
||
return 0
|
||
if cap <= 0:
|
||
return 0
|
||
d: t.CChar = delim[0] # 单分隔符
|
||
|
||
while start[0]:
|
||
# 跳过分隔符
|
||
while start[0] == d: start += 1
|
||
if not start[0]: break
|
||
# 容量保护:留最后一格放结尾哨兵
|
||
if count >= cap - 1:
|
||
break
|
||
|
||
# 记录token起始
|
||
result[count] = start
|
||
count += 1
|
||
|
||
# 找到下一个分隔符,截断
|
||
while start[0] and start[0] != d: start += 1
|
||
if start[0]:
|
||
start[0] = '\0'
|
||
start += 1
|
||
result[count] = None # 结尾标记
|
||
return count
|
||
|
||
|
||
ascii_lowercase: str = "abcdefghijklmnopqrstuvwxyz"
|
||
ascii_uppercase: str = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||
ascii_letters: str = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||
|
||
digits: str = "0123456789"
|
||
hexdigits: str = "0123456789abcdefABCDEF"
|
||
octdigits: str = "01234567"
|
||
punctuation: str = "!\"#$%&'()*+,-./:;<=>?@[]^_`{|}~"
|
||
whitespace: str = " \t\n\r\f\v"
|
||
printable: str = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~ \t\n\r\f\v"
|