什么是“校验和”浮点数数组的快速简便方法,同时允许指定的少量不准确度?
e.g。我有两个算法(理论上,无限精度)输出相同的数组。但它们的工作方式不同,因此浮点错误将以不同方式累积,尽管数组长度应完全相同。我想要一种快速简便的方法来测试阵列是否相同。我当然可以成对地比较数字,并报告最大误差;但是一种算法是用C ++编写的,另一种是在Mathematica中,我不想把数字写到文件或将它们从一个系统粘贴到另一个系统。这就是我想要一个简单的校验和的原因。
我可以简单地将数组中的所有数字相加。如果数组长度为N,并且我可以容忍每个数字中的错误0.0001,那么我将检查是否abs(sum1-sum2)<0.0001*N
。但是这种简单的“校验和”并不健全,例如一个条目中的错误为+10,另一个条目的错误为-10。 (无论如何,概率论说错误可能会像sqrt(N)一样增长,而不是像N.)当然,任何校验和都是一大块数据的低维概要,所以它会错过 some 错误,如果不是大多数......但简单的校验和仍然可用于查找非恶意的错误类型错误。
或者我可以创建一个二维校验和[sum(x[n]), sum(abs(x[n]))]
。但是我能做的最好,也就是说我可能会使用与sum(x[n])
“更正交”的不同功能?如果我使用了一些任意函数,例如[sum(f1(x[n])), sum(f2(x[n]))]
,那么我的“原始容错”应该如何转化为“校验和容错”?
我正在用C ++编程,但我很高兴看到任何语言的答案。
答案 0 :(得分:3)
我觉得通过像gray codes之类的东西可以实现你想要的东西。如果你可以将你的值转换成灰色代码并使用某种能够校正n位的校验和,你可以检测两个数组是否相同,除了n-1位错误,对吧? (每个错误位意味着一个数字“一个一个”,其中映射将使得这是最低有效数字的变化)。
但确切的细节超出了我的范围 - 特别是对于浮点值。
我不知道它是否有帮助,但灰色代码解决的是病态舍入的问题。舍入听起来就像它会解决问题 - 一个天真的解决方案可能会循环,然后是校验和。但简单的舍入总是有病态的情况 - 例如,如果我们使用floor,那么0.9999999和1是不同的。灰色代码方法似乎解决了这个问题,因为相邻的值总是单个位,因此基于位的校验和将准确地反映“距离”。
[更新:]更确切地说,你想要的是一个校验和,它可以估算你的灰色编码序列之间的hamming distance(如果你只关心0.0001那么灰色编码部分就很容易了,因为你可以多余的10000,并使用整数)。
似乎是这样的校验和do exist:任何纠错码都可用于错误检测。具有最小汉明距离d的代码可以检测代码字中最多d-1个错误。如果需要严格限制要检测的最小错误数,则使用基于最小距离的错误纠正代码进行错误检测是合适的。
所以,以防万一不清楚:
但我仍然不确定是对的。你仍然可以在从float到integer的转换中获得病态舍入。因此,您似乎需要最小汉明距离为1 + len(数据)(最差情况下,每个值都有舍入误差)。那可行吗?可能不适用于大型阵列。
现在可以通过更好的标签/描述再次询问一般方向是否可行?或者现在只添加标签?我们需要一个以此为生的人。 [我添加了几个标签]
答案 1 :(得分:2)
试试这个:
#include <complex>
#include <cmath>
#include <iostream>
// PARAMETERS
const size_t no_freqs = 3;
const double freqs[no_freqs] = {0.05, 0.16, 0.39}; // (for example)
int main() {
std::complex<double> spectral_amplitude[no_freqs];
for (size_t i = 0; i < no_freqs; ++i) spectral_amplitude[i] = 0.0;
size_t n_data = 0;
{
std::complex<double> datum;
while (std::cin >> datum) {
for (size_t i = 0; i < no_freqs; ++i) {
spectral_amplitude[i] += datum * std::exp(
std::complex<double>(0.0, 1.0) * freqs[i] * double(n_data)
);
}
++n_data;
}
}
std::cout << "Fuzzy checksum:\n";
for (size_t i = 0; i < no_freqs; ++i) {
std::cout << real(spectral_amplitude[i]) << "\n";
std::cout << imag(spectral_amplitude[i]) << "\n";
}
std::cout << "\n";
return 0;
}
它只返回整个数据集的傅立叶变换的几个任意点。这可以说是模糊校验和。
答案 2 :(得分:2)
我花了一段时间寻找确定性答案,却找不到答案。如果有一个好的答案,它可能需要重型数学技能(功能分析)。
我很确定没有基于“以某种狡猾的方式离散化,然后应用离散校验和”的解决方案,例如: “离散成0/1 /?的字符串,其中?表示通配符”。任何离散化都将具有两个彼此非常接近的浮点数可能最终得到不同离散码的属性,然后离散校验和不会告诉我们想要知道什么。
然而,一个非常简单的随机方案应该可以正常工作。从字母{+ 1,-1}生成伪随机字符串S,并计算csx = sum(X_i * S_i)和csy = sum(Y_i * S_i),其中X和Y是我原始的浮点数数组。如果我们将误差建模为具有均值0的独立正态随机变量,那么很容易计算csx-csy的分布。我们可以为几个字符串S执行此操作,然后进行平均误差为0的假设测试。测试所需的字符串S的数量是固定的,它不会在数组的大小中线性增长,因此它满足我需要一个“低维概要”。该方法还给出了误差标准偏差的估计,这可能很方便。
答案 3 :(得分:1)
如何通过将数据的最低有效数字归零而获得的数据计算标准整数校验和,那些你不关心的数据?