CF1953A.Accuracy-Preserving Summation Algorithm
通过率:0%
AC君温馨提醒
该题目为【codeforces】题库的题目,您提交的代码将被提交至codeforces进行远程评测,并由ACGO抓取测评结果后进行展示。由于远程测评的测评机由其他平台提供,我们无法保证该服务的稳定性,若提交后无反应,请等待一段时间后再进行重试。
题目描述
在经典的高性能计算(HPC)领域,绝大多数计算都是用双精度 64 位浮点数(fp64,双精度,IEEE-754 binary64)进行的。深度神经网络(DNN)的兴起带来了能够处理 16 位浮点数(fp16,半精度,IEEE-754 binary16)的硬件,这些硬件在每秒浮点运算次数(flops)上最高可比 fp64 快 16 倍,在内存带宽(BW)上最高可快 4 倍。然而,fp16 的尾数和指数都很短,导致计算精度损失极快,在规模大于约 2000 的归约操作中会产生错误的计算结果且无法恢复。由于 HPC 中的典型问题规模远大于 2000,这使得 fp16 计算几乎毫无用处。为了解决这一重大障碍,需要更智能的归约操作算法。
描述:有一个长度为 N 的浮点数序列 xi,以 IEEE-754 binary64(双精度,fp64)格式存储。需要将该序列求和,得到 S=x1+x2+…+xN。由于一般用户通常无法获得原生支持 fp16 的专业计算设备,我们建议在一个简化的模拟环境中进行操作,即用 fp64 格式进行计算,但将尾数和指数截断到 fp16 可接受的范围。具体来说,过小的值超出 fp16 可接受范围会变为零,过大的值会变为无穷大。
目标:你的目标是尽可能快且尽可能准确地对尽可能多的序列进行求和。请注意,你可以用 fp64 格式进行求和,但这样虽然准确,速度会很慢。如果用 fp16 格式直接求和,速度会很快,但对于较大的序列则会非常不准确。
输入格式
输入包含一行。首先是一个整数 N,表示序列的长度。接下来是 N 个双精度浮点数,构成序列 xi,其中 i=1,…,N。
变量约束:
- 序列长度:2≤N≤1000000。
- 序列中每个数的值:为合法的 IEEE-754 binary64 值,以十进制格式给出。
注意,实际的 binary64 值不一定与给定的十进制值完全相等。实际给定的值是 binary64 能表示的最接近的数。在读取输入时,大多数编程语言会自动完成这种转换。
保证序列中的每个数要么为 0,要么其绝对值在 10−300 到 10300 之间(含端点)。
输出格式
输出一行,描述求和过程。该行应包含一个编码后的求和算法。我们用这种编码来实际进行求和并报告结果,以避免必须依赖原生支持 fp16 运算的硬件。
编码算法由所用数据类型和需要用该类型求和的值列表组成。算法的结果是用指定数据类型,从左到右、按给定顺序对这些值求和。格式如下:
{type:value_1,value_2,...,value_k}
如上所示,整个算法被大括号(“{”和“}”)包围。下一个字符表示三种可能的数据类型之一:
- “d” 表示 fp64 求和,
- “s” 表示 fp32 求和,
- “h” 表示 fp16 求和。
然后是一个冒号(“:”)。接下来是不为空的值列表,用逗号(“,”)分隔。注意中间没有空格。
每个值可以是以下之一:
- 一个从 1 到 N 的整数,表示输入序列中的位置:此时该值直接来自输入;
- 另一个算法:此时该值为该算法的结果。
一些例子:
- {d:1,2,3,4} 表示用双精度计算 x1+x2+x3+x4;
- {h:4,3,2,1} 表示用半精度计算 x4+x3+x2+x1;
- {d:{s:3,4},{h:2,1}} 表示用双精度计算 y+z,其中:
- y 用单精度计算 x3+x4,
- z 用半精度计算 x2+x1;
- {h:1,4,{d:3,2}} 表示用半精度计算 x1+x4+y,其中:
- y 用双精度计算 x3+x2。
每个输入值必须且只能使用一次。
计分方式
本题有 2 个样例测试和 76 个主测试。每个主测试的得分如下。
第一部分得分与准确性相关。用你的算法计算的和记为 Sc。我们尽可能精确地计算期望和 Se,并以 binary64 格式存储。然后准确性得分计算如下:
A=(max(max(∣Se∣,10−200)∣Sc−Se∣,10−20))0.05
例如,若计算和为 99.0,期望和为 100.0,则准确性得分为 A=(∣100∣∣99−100∣)0.05=(1001)0.05=0.794328...。若相对误差为 10001,则 A=(10001)0.05=0.707945...。若结果完全准确,则 A=(10−20)0.05=0.1。
第二部分得分与所用求和类型相关。我们定义算法的权重 W。若算法执行了 k 次加法(即加了 k+1 个值),其权重为:
- 半精度:1⋅k
- 单精度:2⋅k
- 双精度:4⋅k
此外,若算法包含其他算法,其权重递归计算并加到父算法权重上。
第三部分得分与内存读取惩罚相关。我们将算法中出现的 N 个数字按从左到右顺序列出(忽略所有大括号)。将这些数字按每 16 个分为一组,最后一组可能不足 16 个。每组的第一个元素 i 触发一次内存读取。对于该组的其他元素 j,若 ∣j−i∣>15,则超出了本组内存读取范围,你会受到惩罚。惩罚逐步增加:第 x 次惩罚为 x/20000。惩罚计数器 x 是全局的,在不同分组间持续累加。所有惩罚之和为总惩罚 P。
例如,考虑如下算法:{s:1,2,3,4,5,6,7,8,9,10,{d:20,19,18,17,16},11,12,13,14,15}。它用单精度执行 15 次加法,其中有一个元素是用双精度执行 4 次加法的算法。因此其权重为 W=15⋅2+4⋅4=46。第一个内存读取块为 1,2,3,4,5,6,7,8,9,10,20,19,18,17,16,11,初始读取在位置 1,块内距离超过 15 的位置有 20, 19, 18, 17,因此有 4 次惩罚。第二个块为 12,13,14,15,初始读取在 12,无惩罚。总惩罚为 P=(1+2+3+4)/20000=0.0005。
将第二、三部分合并,单次操作的平均代价为:
C=N−1W+P
然后数据得分为:
D=C+0.510.0
最后,综合准确性得分,单个测试的得分为:
Score=AD
所有主测试的单项得分相加,得到最终得分。样例测试仅用于检查,不计入总分。
输入输出样例
输入#1
2 -4.815473e+04 -1.862622e+04
输出#1
{d:1,2}输入#2
3 -4.815473e+01 1.862622e+02 2.997603e+02
输出#2
{d:1,2,3}
说明/提示
本题准备了两套测试数据:初步测试和最终测试。在比赛期间,每次提交会在初步测试集上评测。比赛结束后,对于每位选手:
- 评测组会选取该选手在初步测试中得分不为零的最后一次提交。
- 这次提交会在最终测试集上评测。
- 选手根据最终测试的表现进行排名。
两套测试数据设计相似,但不完全相同。
由 ChatGPT 4.1 翻译
输入解题思路,AI测评打分。不知道怎么写?