惨痛的教训,调试半天原来是被printf坑了(如何输出长长整形)附加超大数值下如何快速求解最大公倍数最大公约数问题

程序要求算一个最大公倍数(是的非常简单的一个题,以至于出错后我都怀疑人生了)

问题在于所求的这个公倍数的数据范围很大,用无符号整形也放不下,必须使用long long整形

如图

原程序如下

unsigned long long min_gong_bei(unsigned long long a, unsigned long long b)
{
    unsigned long  long max = a * b;
    unsigned long long min_num = a < b ? a : b;
    unsigned long long ret = max;
    for (unsigned long long i = max; i >= a && i >= b; i -= min_num)
    {
        if (i % a == 0 && i % b == 0)
        {
            ret = i;
        }
    }
    return ret;
}
int main()
{
    unsigned long long sum = 0, num1 = 0, num2 = 0;
    scanf("%u%u", &num1, &num2);
    sum = max_gong_yue(num1, num2) + min_gong_bei(num1, num2);
    printf("%llu", sum);
    return 0;
}

经过判断在如下输入例子下出错

 

通过调试发现

程序最终sum的值正确但输出完全错误,以至于我差点怀疑人生了,就说这么简单的题没理由错啊,原来是被printf坑了

显然%u的极限是4个字节,长长整型就完全不行了

如图

最终修改如下

 printf("%llu", sum);

 惨痛的教训,大家引以为戒

附加:

正当我洋洋得意的再次提交代码的时候发现超时了...

原代码过于臃肿

一,求公约数,原程序使用了穷举法,修改为欧几里德法 
        //过程为: 
        //1,大的数放max_num中、小的数放min_num中,max_num 做被除数, min_num做除数,余数放在tmp中;
        //2,若tmp = 0则min_num为最大公约数;
        //3,如果tmp != 0则把min_num的值给max_num、tmp的值给max_num;

数学原理证明

(144条消息) 欧几里得算法证明_Einsam0的博客-CSDN博客_欧几里得算法证明

最后代码如下

二,求公倍数

原公倍数从大向小算起来算的太慢还有bug

修改后//只计算最大数的倍数,就可以很快循环完,因为最大公倍数一定是最大数的倍数所以每次循环加最大数,加后判断是不是最小数的倍数

如下

最后提交

竟然又超时了,这都超时,不过比刚才好很多了

 超1秒的样子,可能是我电脑不太行,继续优化

 通过查找,我们发现了一个很有趣的公式

两个数的乘积等于这两个数的最大公约数与最小公倍数的积

好家伙,上述命题的证明

设两个数分别为A与B,最大公约数为Z,最小公倍数为Y。
那么设 A/Z=a(1),B/Z=b(2)(a与b互为质数)
根据最小公倍数定义Y/A=b(3),Y/B=a(4)
式(1)与(2)等号两边分别相乘得A*B/Z/Z=ab(5)
(3)代入(4)等号两边分别相乘得Y*Y/A/B=ab(6)
将(5)代入(6)得A*B/Z/Z=Y*Y/A/B
根据相关移向得A*A*B*B=Z*Z*Y*Y
两边开方得A*B=Y*Z

最终代码修改如下

过了! 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值