取模时误差小
Small error when taking modulo
本文关键字:误差 更新时间:2023-10-16
我写了一个计算一系列数字的小算法,但它们最终会变成大而存储在unsigned long long
中。这就是为什么我决定每次计算下一个数字时都取模。这是我的函数:
#define MOD 1000000007
template <typename T>
T modpow(T base, T exp, T modulus) {
base %= modulus;
T result = 1;
while (exp > 0) {
if (exp & 1) result = (result * base) % modulus;
base = (base * base) % modulus;
exp >>= 1;
}
return result;
}
vector<unsigned long long> B(int n) {
vector<unsigned long long> points;
vector<unsigned long long> cum_points;
points.push_back(0);
points.push_back(0);
cum_points = points;
unsigned long long prev = 0;
if (n >= 2){
for (int i = 0; i <= n - 2; i++) {
prev += cum_points[i];
prev %= MOD;
points.push_back((modpow((unsigned long long)2, (unsigned long long)i, (unsigned long long) MOD)+prev)%MOD);
cum_points.push_back((cum_points[i+1]+points[i+2])%MOD);
}
}
return points;
}
这将返回一个包含一系列数字的向量:
0, 0, 1, 2, 5, 12, 28, 64, 144, 320, 704, 1536, 3328, ...
等等...
问题是,当n > 50
模数略有偏差时: (第一个值是代码中没有模数计算的值,等号后的值是代码中模数的结果。
50: 1759218604441600 % 1000000007 = 592127074; this is the right answer
51: 3588805953060860 % 1000000007 = 927939229; this should be: 927939225
每次变高时,误差都会变大一点n
。这小小的偏移量从何而来?
一些可能的问题:
- 当数字时,
modpow()
不知何故没有给出正确的答案 超过一定长度。这不是问题 - 数学上有一些错误,但我相信我以正确的方式使用以下方程:
(a*b) mod c = ((a mod c)*(b mod c)) mod c
(a + b) mod c = ((a mod c)+(b mod c)) mod c
- 我的代码中也可能有一个错误的变量类型,尽管我不知道在哪里。
编辑:我已经排除了一些可能的问题,问题似乎在于i == 48
时prev
的计算。
您可以检查模量是否足够小。您是否检查过系统上无符号长长的大小?
std::cout << std::numeric_limits<unsigned long long>::max();
当你检查它时,你不妨也检查一个无符号的int的大小 与此同时。我不确定它们是否一定不同。
您的模数有 10 位数字,因此两个数字的乘积最多可以有 20 位数字。 如果您的最大无符号长长小于 MOD * MOD,则可能会收到溢出错误。
公式中的错误可能会在 n = 51 之前显示。
评论: 如果您使用的是 C++11 标准,为什么不将该宏替换为
constexpr unsigned long long MOD = 1000000007;
此外,在调用 modpow 的位置,您可以通过简单地调用所需的特定函数来避免所有这些转换unsigned long long
:modpow<unsigned long long>
.然后参数将自动转换为正确的类型。
相关文章:
- 为什么在浮点中从大到小会引入更多的误差
- 基于相邻元素 c++ 的分段误差范围的循环
- QImage::p ixel 和 QImage::setPixel 坐标超出范围误差
- 将误差线添加到 VTK 二维散点图
- 动态矩阵特征分解过程中的误差
- 转换为非标量误差是什么意思?我该如何解决?
- 特征误差:INVALID_MATRIX_PRODUCT乘向量和矩阵
- 使用不同参数匹配器的同一方法ON_CALL AND EXPECT_CALL会产生饱和和活动误差
- boost odeint 中的受控误差步进器是否支持复杂的数据类型?
- 此外,在计算大斐波那契数时存在精度误差
- C++17中不定参数函数的误差
- 多态性中独立类的基本误差.C++
- 犰狳函数的不同最小二乘误差
- 在 qt 中的绘图中拖动误差线
- variadic函数和折叠表达:试图在Visual Studio 2017中编译时致命误差
- 在Cython中使用移动方法时的汇编误差
- variadic模板代码中的GCC VS MSVC编译误差
- CMAKE和CUDA的权限误差
- OPENCV C 中的分割故障误差
- ROS中未定义的参考误差到OpenCV图像转换器