如何在C++中检查大数除以7的余数?

8

我需要检查给定的数字是否可被7整除,通常可以通过执行n % 7 == 0来完成,但问题是,给定的数字可以高达100000000,即使用long long也无法容纳。

另一个限制是,我只有几千字节的内存可用,因此不能使用数组。

我期望数字在标准输入中,并输出为1/0

这是一个例子

34123461273648125348912534981264376128345812354821354127346821354982135418235489162345891724592183459321864592158
0

只需使用大约7个整数变量和cin.get()即可完成。同时,应仅使用标准库。

9个回答

26

你可以使用一个关于7的已知除法规则: 从右边开始每次将连续的3个数字分组,轮流相加和相减,得到的结果是否能被7整除与原数相同:

例如:

testing 341234612736481253489125349812643761283458123548213541273468213
        549821354182354891623458917245921834593218645921580

   (580-921+645-218+593-834+921-245+917-458+623-891+354-182
    +354-821+549-213+468-273+541-213+548-123+458-283+761-643
    +812-349+125-489+253-481+736-612+234-341 
    = 1882 )
    % 7 != 0 --> NOK!

还有其他替代方案可以实现这个规则,而且都很容易实现。


1
第一次看到这个规则,有任何参考资料吗? - elcuco
@elcuco,这是一个很好的模块化数学技巧,使用中国剩余定理。它实际上也适用于11和13,因为1001 = 7 * 11 * 13。 - rlbond
@rlbond 对于11,您不需要将数字分成三位一组。相反,加减每隔一个数字。这是因为11可以被11整除。 :-) - starblue
这对于人类来说是一个好的规则,但对于计算机来说它是不必要复杂的。 - starblue
不错的解决方案,但是当我必须从开头到结尾读取输入时,该如何实现它呢?因为我无法确定第一组开始/结束的时间。我能想到的唯一选择是同时尝试三种组合,然后在最后确定哪一个是正确的,但这似乎不是一个非常干净的解决方案。我猜没有办法倒序读取输入吗? - Jakub Arnold
如果数字的位数不是三的倍数,这个方法还有效吗?如何将像43534和3245434564这样的数字分成三组? - Qiu YU

19

想想看您在纸上如何做除法。您查看第一个或两个数字,并写下最接近七的倍数,记录余数并继续。由于您不需要将整个数字加载到内存中,因此您可以对任意长度的数字执行此操作。


+1:从一个数字是数字列表的概念开始,对每个数字独立执行除法。 - D.Shawley
虽然“除以七规则”的答案很好,但我更喜欢这个答案,因为它是通用的。 - Jeremy

13

大多数七的整除性规则都是基于数字级别的,因此您应该没有问题将它们应用于您的字符串。


3
你可以计算数字模7的值。
也就是说,对于每个数字d和目前的值n,计算n = (10 * n + d) % 7。
这样做的好处是独立于除数7或基数10。

2

你可以计算数字模7的值。

也就是说,对于每个数字d和当前值n,计算n = (10 * n + d) % 7。

这种方法的好处是独立于除数7或基数10。

我在编程比赛中完全以同样的方式解决了这个问题。这里是你需要的代码片段:

int sum = 0;
while (true) {
  char ch;
  cin>>ch;
  if (ch<'0' || ch>'9') break; // Reached the end of stdin
  sum = sum*10; // The previous sum we had must be multiplied
  sum += (int) ch;
  sum -= (int) '0'; // Remove the code to get the value of the digit
  sum %= 7; 
}

if (sum==0) cout<<"1";
else cout<<"0";

这段代码的运行得益于模算术的简单规则。实际上,它不仅适用于7,而且适用于任何除数。


1

我会从一个可以被7整除的大数开始减。

可以被7整除的数字示例包括700、7000、70000、140000000、42000000000等。

在你给出的特定示例中,尝试减去280000000000(一些零)0000。

更容易实现的方法是反复减去最大可能的数字,如70000000000(一些零)0000。


0

N = abc

有一个简单的算法可以验证一个三位数是否是7的倍数:

将a替换为x并加上bc,其中x是一个十位数是7的倍数,其百位数是a。

N = 154; x = 2; 2 + 54 = 56; 7|56和7|154

N = 931; x = 4; 4 + 31 = 35; 7|35和7|931

N = 665; x = 5; 5 + 65 = 70; 7|70和7|665

N = 341; x = 6; 6 + 41 = 47; 7ł47和7ł341

如果N由多个周期组成,则必须将一个周期的结果的逆加性添加到下一个周期的总和中,如下所示:

N = 341.234

6 + 41 = 47; - 41 mod 7 ≡ 1; 1 + 4 + 34 = 39; 7ł39和7łN

N = 341.234.612.736.481

341.234的结果是39。继续计算:

-39 mod 7 ≡ 3;3 + 5 + 6 + 1 + 2 + 1 = 18;-18 mod 7 ≡ 3;3 + 0 + 36 = 39;-39 mod 7 ≡ 3; 3 + 1 + 81 = 85;7ł85和7łN

这个规则可以完全通过心算来应用,非常快速。 它是从我在2.005中创建的另一条规则中推导出来的。它适用于任何大小的数字以及13的可除性。


0

因为我最近做了一些与数字拆分有关的工作,所以我会提示一下如何获取特定的数字——这是你需要在其他答案中使用的——考虑整数除法和使用模数从中获取数字。

如果你有一个较小的数字,比如123,你怎么才能把123从中取出来呢?尤其是因为你是在十进制中工作...


-1

首先将大数以字符串形式输入,然后对字符串中的每个数字进行求和。最后检查是否满足(sum%7==0)。

代码:

#include <bits/stdc++.h>
using namespace std;
int main()
{
    long long int n,i,j,sum,k;
    sum=0;
    string s;
    cin>>s;
    for(i=0;i<s.length();i++)
    {
        sum=sum+(s[i]-'0');
    }

    if(sum%7==0)
    {
        printf("Yes\n");
    }
    else
    {
        printf("No\n");
    }

    return 0;
}

这仅适用于9或3(例如,您会说16是7的倍数)。如果数字足够长,则总和也会溢出。 - Teepeemm

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接