随机数据生成 & 正确性验证
某 CQ 今天发现有不少同学会在群里面求某道题的测试数据来验证自己程序的正确性。
每个人程序的做法是不同的,错误也很可能出在五花八门的地方,也就是说,同样的数据,别人是对的你不一定对,别人是错的你也不一定就是错的。
经常在群里求数据解决问题是不可取的,首先没有那么多的测试数据来给,其次也并不知道你错在哪里,不能给出更有针对性的数据。
那么我们怎么能更高效的获得可能使你程序出错的数据呢?某 CQ 就在这里给大家介绍介绍:
首先我们需要自己写个程序来生成随机的测试数据:
C 语言怎么写随机数呢?直接上代码你就懂了!
#include<stdio.h>
#include<stdlib.h>
int random(int l, int r) {
return rand() % (r - l + 1) + l;
}
int main() {
srand(time(0));
int a = random(1, 10000), b = random(1, 10000);
printf("%d %d\n", a, b);
return 0;
}
这样就写好了一个生成 A+B Problem
的数据的随机数程序。
我们来具体解析几个陌生的东西。这些东西都在 stdlib.h
里:
time(0)
指获取当前系统时间,它会动态返回一个不同的 int
值。
srand()
指的是设置随机数种子,当你将系统时间设置为随机数种子的时候,这样种子就会在不断的变化,在这里提一嘴,同样的种子出来的随机数是不会变的,内部的计算原理某 CQ 并不清楚。
而 rand()
就是取一个范围是 1 到 65535 的随机整数值,在这里我们假定数据范围是 1 到 10000 ,所以我们自己写了一个 random 函数用来生成 l 到 r 范围内的随机数,其中用取模来限制 rand()
的值的范围。
这里要特别注意,如果需要更大的数据,你可以将多个 rand()
相乘,但是请注意范围可能会超过 int
,必要时记得开 long long
。
学会了生成随机数,我们就可以根据不同题目的输入要求来构造大量的随机数据啦!(因为每次跑代码所得到的结果都不一样)
数据有了,那我用我自己的程序跑出结果我也不知道对不对啊?而且这样手动生成数据,也太麻烦了吧,效率太低,而且找到我想要的数据就算运气好也要花不少时间,这可怎么办呢?
接下来就轮到我们的对拍上场辣!
首先我们需要一个保证正确的代码生成的可执行文件用来作为标准输出正确答案,当某 CQ 发出这个帖子之后,他会在频道当中新开一个分区用来放近期题库正确可执行文件的下载链接,各位可以自行去下载。
接下来我们假设:
接下来所有的文件都在同一个文件夹里
你的程序生成的可执行文件叫 code.exe
你的随机数程序生成的可执行文件叫 rand.exe
完全正确的程序生成的可执行文件叫 std.exe
新建一个文件 check.bat
(注意后缀名),填入以下代码:
@echo off
:loop
rand.exe > data.in
std.exe < data.in > std.out
code.exe < data.in > code.out
fc std.out code.out
if not errorlevel 1 goto loop
pause
goto loop
接下来我们来具体解释这些批处理命令:
@echooff
:关闭输入显示(否则刷屏警告):loop
:goto
嘛,洒洒水啦~>
:将输出内容附到指定文件上<
:将内容输入到程序中运行
两者可以按照逻辑顺序连用fc
:(file compare)是 windows
的指令,它会比较两个文件之间有什么区别,并且输出结果if not errorlevel 1 goto loop
:if 大家都很熟,这个 errorlevel 指的就是 fc 的程序返回值,如果是 1,那么这两个文件之间并没有差异,我们就直接 goto loop
生成之后的数据,如果不是 1,那么说明有问题,就停下来让你去 data.in
里面看是什么数据,然后当你按下任意按钮以后它会继续生成新数据。
这里要注意的是,fc对文件的判断要求可能比oj要求更高,行末的空格最好别有(
这样就造出了一个全自动的判别机,你可以开着这个程序来自动找到使你程序出错的针对性数据(虽然运气不好的话可能还是要跑很久)
提示
如果你正在使用你是 Linux,说明你是操作系统大神,这里就不介绍 Linux 下怎么写对拍了,和 Windows 下实际上是一样的,只是命令不同而已。