随机测试终于报错却给了我一长串数怎样把反例缩到一个元素前面的判题器文章主要在问测试能不能真的找出错误。这次接着往后走。假设它已经找到一组失败数据接下来怎么读它如果输入里有几十个数我们很容易一会儿盯住前面一会儿又怀疑后面。可以先做件更笨、也更有用的事删掉其中一部分再运行一次。删完仍然错说明那部分至少不是这次复现所必需的。这个判断能不能交给程序反复做先拿一组能手算的题试试。先约定“错”到底是什么题目是给定非空整数数组求非空连续子数组的最大和。例如[-3,-1,-2]的答案是-1不能什么也不取而返回0。我们故意放进一个边界有问题的实现作为被测程序。它的错误不是本文要优化的算法而是缩减器要追踪的对象def candidate(a): best current 0 for x in a: current max(0, current x) best max(best, current) return best参考程序则把所有非空区间枚举出来直接求和def reference(a): return max((sum(a[i:j]) for i in range(len(a)) for j in range(i 1, len(a) 1)), defaultNone)它写得慢每次求和还要扫区间总体是O(n³)但这里输入短优先要的是简单、独立、好检查。不能再写一个结构相同的优化算法结果两个程序共享同一处错误。然后给输入分三种结果def outcome(a): if not a: return INVALID return FAIL if candidate(a) ! reference(a) else PASSFAIL才说明原问题仍能复现。空数组违反题面是INVALID不能因为它触发了异常就把它当成“更好的反例”。拿真实跑出的那组数先删一半固定随机种子1103每组生成12个[-9,9]整数。本次第4452组才出现输出不一致[-3,-3,-8,-4,-4,-8, -1,-9,-5,-4,-6,-7] 参考答案-1 被测输出 0这次不是手工挑出一个漂亮输入再说它是随机生成的固定种子和生成循环都在文末。种子用来重现本次Python运行不保证所有语言的随机数生成器产生同一串数。删去前六个留下后六个。重新对拍仍然不一致原来 [前六个] [后六个] 操作 删掉 留下 [-1,-9,-5,-4,-6,-7] 参考-1被测0仍然FAIL那就接受这次删除。下一轮对剩下的六个数继续做12个数 | 删前6个仍错 v [-1,-9,-5,-4,-6,-7] | 删前3个仍错 v [-4,-6,-7] | 删前1个仍错 v [-6,-7] | 删前1个仍错 v [-7]到这里参考答案是-7被测输出还是0。只盯这个输入就容易找到问题了best从0开始current又始终不小于0全负数就永远抬不起答案。但题目要求至少选一个元素。修复这个具体算法可以从首元素初始化而不是让空区间参与竞争def corrected(a): current best a[0] for x in a[1:]: current max(x, current x) best max(best, current) return best缩减的作用不是替我们证明修复正确而是把问题缩到不容易看岔的地方。修复以后还得回归原始失败输入以及其他边界。如果删一半以后不再错了呢刚才每轮都恰好能删掉第一块这是该用例的结果不能写成通用规则。假设当前分成左右两块删左边以后通过了就把左边放回去再试删右边。两边单独删除都不能保留错误也不代表结束了。可以把当前输入划成四块一次只删一块试试。当前 [甲][乙][丙][丁] 试1 [乙][丙][丁] PASS - 不接受恢复 试2 [甲] [丙][丁] FAIL - 接受继续缩每次都拿当前仍失败的输入当起点保留元素顺序只删除一个连续块。接受以后重新分块一轮都删不掉就把块分得更细最后细到单个元素。这和delta debugging的分块缩减思想相关。本文实现只尝试“去掉一块后剩下的部分”是一个便于读懂的删除缩减器没有把它冒称为完整复刻的标准ddmin。原作者的实现与接口可以对照Andreas Zeller的Delta Debugging代码。核心函数如下test需要给出稳定的PASS、FAIL或INVALIDdef reduce_failure(values, testoutcome): current list(values) if test(current) ! FAIL: raise ValueError(input must reproduce the failure) calls 1 history [] granularity 2 while len(current) 2: parts min(granularity, len(current)) changed False for i in range(parts): lo i * len(current) // parts hi (i 1) * len(current) // parts trial current[:lo] current[hi:] result test(trial) calls 1 history.append({before: current[:], removed: [lo, hi], trial: trial, outcome: result, accepted: result FAIL}) if result FAIL: current trial granularity max(2, parts - 1) changed True break if changed: continue if parts len(current): break granularity min(len(current), parts * 2) return current, history, calls这里最值得盯住的是if result FAIL只有这一种结果可以替换current。其他结果只是说明这次删除不合适。输入长度作为一个一直下降的量防止接受操作来回打转。没有接受删除时块数会增加最多试到每块一个元素不会永远增加下去。最坏情况下单是调用test的次数就可能达到O(n²)量级。每次复制列表和运行被测程序还另有成本不能因为缩减结果很短就叫它线性算法。本例参考程序本身很慢所以我们只对小输入做这套验证。“一个也删不掉”就是最短了吗对[-7]再删就只剩空数组不满足题目它已经不能继续删除。不过不能把所有用例都概括成“缩减器能得到全局最小反例”。看一个专门展示限制的判定规则只有[1,2,3,4]、[3,4]、[1]返回FAIL其余非空输入都PASS。起点[1,2,3,4]FAIL 删前半 - [3,4]FAIL接受 再删3 - [4]PASS 再删4 - [3]PASS 所以停在[3,4] 可是[1]也FAIL而且更短。我们走到了一条保留错误的删除路径走到后来不能单独删除任何元素。这叫相对于当前删除操作的1-minimal删掉任意一个元素都无法保持有效失败。它不承诺所有删除路径里长度最短也没有把数值大小优化到最简单。失败可能依赖元素之间的组合不具有“多删一点一定更容易通过”这样的单调性。早期选择了哪条分支会影响最后留下的反例。把它接到自己的判题器要改哪里先改test不要急着改缩减策略。数组题可以返回两份答案是否不一致图题删边时还要检查点编号和连通性等题面要求操作序列删掉“创建对象”以后后面操作可能不合法。如果要追踪某类崩溃应检查退出码、错误种类或相应特征。不能原本想研究错误答案缩着缩着却变成“进程起不来”仍然一概当成同一个FAIL。超时也需要独立判定和稳定重跑不能把临时机器负载当成确定性失败。原始输入也要保留。缩小后的输入方便定位原始输入则用来确认修复没有只照顾这个小例子。附完整程序与验证方式下面保存为shrink.pyPython3直接运行不需要安装第三方库。python3 shrink.py程序保存随机起点、每次试删的下标范围、判定结果和最终反例。它还枚举长度1到6、取值来自[-2,-1,0,1,2]的全部19530个非空数组先检查修复版与暴力答案一致再对其中126个失败输入检查缩减后仍错、顺序未改、每个接受步骤仍错、单删任意一个元素都不能保持失败。另外有无效输入约束和上面的“1-minimal不等于最短”对照。这里验证的是明确的性质单看程序最后打印passed并不知道它有没有把一个已经通过的输入也接受下来。A deterministic wrong implementation and a deletion-only failing-input reducer. import itertools import json from pathlib import Path import random def reference(a): return max((sum(a[i:j]) for i in range(len(a)) for j in range(i 1, len(a) 1)), defaultNone) def candidate(a): best current 0 for x in a: current max(0, current x) best max(best, current) return best def outcome(a): if not a: return INVALID return FAIL if candidate(a) ! reference(a) else PASS def corrected(a): current best a[0] for x in a[1:]: current max(x, current x) best max(best, current) return best def reduce_failure(values, testoutcome): current list(values) if test(current) ! FAIL: raise ValueError(input must reproduce the failure) calls 1 history [] granularity 2 while len(current) 2: parts min(granularity, len(current)) changed False for i in range(parts): lo i * len(current) // parts hi (i 1) * len(current) // parts trial current[:lo] current[hi:] result test(trial) calls 1 history.append({before: current[:], removed: [lo, hi], trial: trial, outcome: result, accepted: result FAIL}) if result FAIL: current trial granularity max(2, parts - 1) changed True break if changed: continue if parts len(current): break granularity min(len(current), parts * 2) return current, history, calls def check_reduction(original, testoutcome): reduced, history, calls reduce_failure(original, test) assert test(reduced) FAIL # A subsequence, not a reordered or fabricated input. it iter(original) assert all(any(x y for y in it) for x in reduced) assert all(test(reduced[:i] reduced[i 1:]) ! FAIL for i in range(len(reduced))) for step in history: lo, hi step[removed] assert step[trial] step[before][:lo] step[before][hi:] if step[accepted]: assert test(step[trial]) FAIL assert len(step[trial]) len(step[before]) return reduced, history, calls def main(): rng random.Random(1103) attempts 0 while True: attempts 1 original [rng.randint(-9, 9) for _ in range(12)] if outcome(original) FAIL: break if attempts 100000: raise RuntimeError(no reproducible failing input) reduced, history, calls check_reduction(original) failures 0 tested 0 for n in range(1, 7): for values in itertools.product([-2, -1, 0, 1, 2], repeatn): tested 1 assert corrected(values) reference(values) if outcome(values) FAIL: check_reduction(list(values)) failures 1 # A deterministic non-monotonic predicate forces a local minimum. def local_trap(a): return FAIL if a in ([1, 2, 3, 4], [3, 4], [1]) else (INVALID if not a else PASS) trap, trap_history, _ check_reduction([1, 2, 3, 4], local_trap) assert trap [3, 4] and local_trap([1]) FAIL try: reduce_failure([1, 2]) except ValueError: pass else: raise AssertionError(a passing input must be rejected) invalid_trials [] def constrained(a): result FAIL if len(a) 2 else INVALID invalid_trials.append((a[:], result)) return result constrained_result, _, _ check_reduction([7, 8, 9], constrained) assert len(constrained_result) 2 assert any(r INVALID for _, r in invalid_trials) # Reject reducers that lose failure, change order, or accept invalid emptiness. mutants {return_empty: [], return_original: original[:], accept_passing: [1, 2]} rejected {} for name, values in mutants.items(): valid_failure outcome(values) FAIL one_minimal valid_failure and all(outcome(values[:i] values[i 1:]) ! FAIL for i in range(len(values))) rejected[name] not one_minimal assert all(rejected.values()) assert corrected(original) reference(original) record {passed: True, seed: 1103, attempts: attempts, original: original, expected: reference(original), actual: candidate(original), reduced: reduced, reducedExpected: reference(reduced), reducedActual: candidate(reduced), calls: calls, history: history, exhaustiveInputs: tested, failingInputsReduced: failures, correctedMatchesOracle: True, badOutputControlsRejected: rejected, oneMinimalNotGlobal: {input: [1, 2, 3, 4], reduced: trap, smallerFailure: [1], history: trap_history}, constrainedResult: constrained_result} out Path(__file__).with_name(results.json) out.write_text(json.dumps(record, indent2)) print(json.dumps({k: v for k, v in record.items() if k not in (history, oneMinimalNotGlobal)})) if __name__ __main__: main()
企业数字化 ERP 产品动态
相关推荐
支付回调别直接改订单状态:验签、幂等、事件解耦,qkl-finance 是这么接的 支付回调别直接改订单状态:验签、幂等、事件解耦,qkl-finance 是这么接的
微信支付的回调能重试 8 次、每次都带同样的 out_trade_no,你要是直接在回调里"改订单状态 发消息 记流水",重复回调来了就是双倍积分、双倍… · 2026/11/6 5:18:57
沪深300×LightGBM选股复盘:验证期+20.86%,测试期-2.13% 沪深300LightGBM选股复盘:验证期20.86%,测试期-2.13%排序信号是真的,但很弱。按模型预测分位分档,预测越靠前、未来 5 日平均收益越高,两期都单调(验证期前 3% 档 0.441% vs 池内 0.081%;测试期… · 2026/11/6 5:18:57
WPF 音视频四大核心方案对比 根据业务场景的复杂度,WPF 提供了四个层级的工具类:核心类名所在命名空间支持格式支持视频多轨并发音量/进度控制典型适用场景SystemSoundsSystem.Media系统内置音否否否弹窗警告、操作错误提示音SoundPlayerSystem.Media仅限 .wav否否否按钮点击短音效、… · 2026/11/6 5:18:57
基于CDC的MySQL实时数据同步方案实践 1. 项目背景与核心价值 在数据驱动的业务场景中,数据库表间数据同步是个高频需求。我最近在电商订单系统中就遇到了这个问题:订单主表数据变更后,需要实时同步到统计分析表和风控表。传统的手动同步或定时任务方式存在延迟高、易出错的问题&a… · 2026/11/6 14:00:34
JSP农贸交易系统开发与智能撮合算法实践 ## 1. 项目概述与核心价值农贸产品交易系统是连接农产品生产端与消费端的重要数字化桥梁。这个基于JSP技术的交易平台(项目编号g3608)完整包含了程序源码、数据库设计、部署指南和开发环境配置,是一套开箱即用的农产品B2B解决方案。我在参与某… · 2026/11/6 14:00:34
2025年3D建模工具选型实战指南:按工作流断点匹配生产力 1. 这不是选软件,是选你未来三年的“数字手”——为什么2025年建模工具选择比以往任何时候都更关键 2025年做3D建模,你面对的早已不是“用哪个软件画个模型”这么简单的事。它直接决定你能不能接单、能不能按时交付、能不能把想法一秒变现实、甚至决定你… · 2026/11/6 14:00:34
Qt飞机大战源码解析:QGraphicsView游戏循环与碰撞检测实战 简介:这份资源是面向Qt初学者与游戏开发入门者的「飞机大战」完整项目源码包,围绕Qt框架在经典空战游戏中的实际应用展开,可用于课程设计、自学练手或二次开发参考。压缩包共223个文件,约6.21MB,以105个C头文件与32个c… · 2026/11/6 14:00:34
老旧CMS的XSS与getshell风险防护及应急治理 项目中遇到过不少次类似的场面:群里忽然冒出一条消息,标题写得耸人听闻,核心关键词是 XSS 、 0day 、 通杀所有版本 ,还带着一个"可 getshell"的尾巴,配图往往是半个命令行窗口。消息传得飞快… · 2026/11/6 13:56:30
BOM多视图与版本基线:NX装配映射、大树性能及状态权限实践 BOM 这两个字,在研发产品设计管理平台这个圈子里出现频率极高,但真正把它做扎实的项目并不多。我参与过的这套基于 NX 的平台,第一版已经把设计 BOM 从三维装配里抽了出来,能按树展开、能导出表格、能看图号,当时团队觉… · 2026/11/6 13:56:30
双极步进电机控制实战:DRV8818PWPR与PIC18F86K22驱动调试 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/5 10:27:59
STM32F207ZG + DRV8818PWPR 步进电机驱动实战解析 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/5 10:28:03
DRV8818PWPR+dsPIC30F4013工业级双极步进电机控制方案 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/6 10:29:23
三菱PLC数据采集到数据库的时序设计:Python+MC协议实战 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/6 1:02:11
ASIC主模式RTL设计:状态机与三态驱动的流片级实现 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/6 1:02:11
STM32嵌入式C++开发:GDB调试与Renode仿真实战指南 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/6 1:02:11
双极步进电机控制实战:DRV8818PWPR与PIC18F86K22驱动调试 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/5 10:27:59
STM32F207ZG + DRV8818PWPR 步进电机驱动实战解析 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/5 10:28:03
DRV8818PWPR+dsPIC30F4013工业级双极步进电机控制方案 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/6 10:29:23