Python算法100例-3.6 自守数

2024-03-07 1422阅读

温馨提示:这篇文章已超过394天没有更新,请注意相关的内容是否还可用!

  • 1.问题描述
  • 2.问题分析
  • 3.算法设计
  • 4.求给定数的位数
  • 5.分离给定数中的最后几位
  • 6.确定程序框架
  • 7.完整的程序

    1.问题描述

    自守数是指一个数的平方的尾数等于该数自身的自然数。例如, 5 2 = 25 , 2 5 2 = 625 , 7 6 2 = 5776 , 937 6 2 = 87909376 5^2=25,25^2=625,76^2=5776,9376^2=87909376 52=25,252=625,762=5776,93762=87909376。求100000以内的自守数

    2.问题分析

    根据自守数的定义,求解本题的关键是知道当前所求自然数的位数,以及该数平方的尾数与被乘数、乘数之间的关系。

    3.算法设计

    采用“求出一个数的平方后再截取最后相应位数”的方法显然是不可取的,因为计算机无法表示过大的整数。

    分析手工方式下整数平方(乘法)的计算过程,以376为例:

    Python算法100例-3.6 自守数

    本问题所关心的是积的最后三位。分析产生积的后三位的过程可以看出,在每一次的部分积中,并不是它的每一位都会对积的后三位产生影响。总结规律可以得到,在三位数乘法中,对积的后三位产生影响的部分积分别如下:

    ·第一个部分积中:被乘数最后三位×乘数的倒数第一位。

    ·第二个部分积中:被乘数最后两位×乘数的倒数第二位。

    ·第三个部分积中:被乘数最后一位×乘数的倒数第三位。

    将以上部分积的后三位求和后截取后三位就是三位数乘积的后三位。这样的规律可以推广到同样问题的不同位数乘积。

    4.求给定数的位数

    求一个数的位数可以借助最高位的权值来计算,对于十进制来说,个位的权值为100,十位的权值为101,百位的权值为102,以此类推。一个存储三位数的变量n=123,每次除以10,将得到的值再赋给n,直到n的值为0,最多可以除3次;若变量n中存储的是4位数,用同样的方法去除以10最多可以除4次。可以发现,直到变量变为0,除以10的次数即为当前给定数的位数。程序如下:

    # 求给定数的位数
    if __name__=="__main__":
        print("请输入一个正整数n:", end="")
        n = int(input())
        if n  0:                       # 由number的位数确定截取数字进行乘法时的系数k
        mul //= 10
        k *= 10
    

    5.分离给定数中的最后几位

    从一个两位数(存在变量n中)开始分析,分离最低位个位:n%10;对于三位数n,分离最后两位:n%100;对于四位数n,分离最后三位:n%1000;以此类推,若分离出最后x位,只需要用原数对10x求余。

    从算法设计部分所举例子可以看出,对于第二个部分积“2632”来说其实应该是“26320”,因为对于乘数中的倒数第二位“7”来说,因其在十位,对应的权值为10,第二个部分积实质上为376×70=26 320。故求部分积的程序段为:

    while k > 0:
        # (部分积+截取被乘数的后N位×截取乘数的第M位),%a再截取部分积
        mul = (mul + (number % (k * 10))*(number % b - number % (b //  10)))%a
        k //= 10                                # k为截取被乘数时的系数
        b *= 10
    

    对于整个循环来说,变量k是由number的位数确定截取数字进行乘法时的系数。第一次执行循环体时,被乘数的所有位数都影响到平方的尾数,故第一个部分的积等于被乘数×乘数的最后一位,将部分积累加到变量mul上,再对a取余截取相应的尾数位数;第二次执行循环体,影响平方尾数的是被乘数中除了最高位之外的数(故k先除以10再参加运算),第二个部分的积等于被乘数×乘数的倒数第二位,(number%b-number%(b//10))用来求乘数中影响平方尾数的对应位上的数;第三次、第四次执行循环体的过程同上。

    6.确定程序框架

    该程序的简略流程图如图所示。

    Python算法100例-3.6 自守数

    7.完整的程序

    %%time
    #  自守数
    if __name__=="__main__":
        print("100000以内的自守数:")
        for number in range(0, 100000):
            mul = number
            k = 1
            while (mul // 10) > 0:   # 由number的位数确定截取数字进行乘法时的系数k
                mul //= 10
                k *= 10
            a = k * 10  # a为截取部分积时的系数
            mul = 0 # 积的最后n位
            b = 10  # b为截取乘数相应位时的系数
            while k > 0:
                # (部分积+截取被乘数的后N位*截取乘数的第M位),%a再截取部分积
                mul = (mul + (number % (k * 10))*(number % b - number % (b //  10)))%a
                k //= 10  # k为截取被乘数时的系数
                b *= 10
            if number == mul:  # 判定若为自守数则输出
                print("%ld " %number, end="\t")
        print('\n')
    
    100000以内的自守数:
    0 	1 	5 	6 	25 	76 	376 	625 	9376 	90625 	CPU times: user 536 ms, sys: 2.14 ms, total: 539 ms
    Wall time: 535 ms
    
VPS购买请点击我

免责声明:我们致力于保护作者版权,注重分享,被刊用文章因无法核实真实出处,未能及时与作者取得联系,或有版权异议的,请联系管理员,我们会立即处理! 部分文章是来自自研大数据AI进行生成,内容摘自(百度百科,百度知道,头条百科,中国民法典,刑法,牛津词典,新华词典,汉语词典,国家院校,科普平台)等数据,内容仅供学习参考,不准确地方联系删除处理! 图片声明:本站部分配图来自人工智能系统AI生成,觅知网授权图片,PxHere摄影无版权图库和百度,360,搜狗等多加搜索引擎自动关键词搜索配图,如有侵权的图片,请第一时间联系我们,邮箱:ciyunidc@ciyunshuju.com。本站只作为美观性配图使用,无任何非法侵犯第三方意图,一切解释权归图片著作权方,本站不承担任何责任。如有恶意碰瓷者,必当奉陪到底严惩不贷!

目录[+]