寻找完全平方数——浮点数陷阱

【题目描述】

输出所有形如aabb的4位完全平方数(即前两位数字相等,后两位数字也相等)。

【解析】

一、问题分析

从问题出发,题目要求输出的是满足一定条件的数。数在计算机中是要占存储空间的,要在计算机中表示一个数,一定要考虑它的数据类型、数据长度。这里是4位整数,所以用int数据类型就可以了。

如果把数看成一个对象,它也有自己的属性和方法。

二、已知条件分析

1. 已知条件转化为隐含条件。

本题对要输出的数给定了3个已知条件:

(1) 形如aabb(即前两位数字相等,后两位数字也相等)。注意括号内对aabb的解释,只要求前两位相等,后两位也相等,对ab是否相等未作要求。题目未作要求,就是没有限制,就是怎样都可以。所以不要看写着形如aabb就想当然地以为a、b要是不同的两个数。a、b只是两个字母,是未知数,在未给定条件时,它可以是任意数。

(2) 4位数。一个数是几位数是从最左侧的第一个非0数开始计算,比如0123既不是4位数,也不是3位数,因为它根本不是数。所以本题要求是4位数,a的值不能为0。也就是a的取值范围是1-9,b的取值范围是0-9。

(3)完全平方数。完全平方数(perfect square)指能表示成某个整数的平方的数。例如,0、1、4、9都是完全平方数,因为它们分别是0、1、2、3的平方。根据定义可知,完全平方数是非负整数。

2. 隐含条件转换为数学表达式。

仅仅将已知条件转化为隐含条件还不够,还要进一步转化为数学表达式,才可能将其转化为代码。

上述三个条件中主要涉及的数学表达式是aabb这个数表示,它可以表示成:a*1100 + b*11

三、算法分析

本题的本质是从一定范围的整数中找出一些符合特殊条件的整数,所以可以用“穷举法”。

穷举法的穷举范围极大地影响程序的效率,所以要尽量缩小穷举的范围。

本题的穷举范围和符合条件判断有两种:

①大范围:4位数→缩小范围:4位数+形如aabb的数(无法进一步缩小),符合条件:完全平方数。

②大范围:4位数→缩小范围:4位数+完全平方数(无法进一步缩小),符合条件:形如aabb

下面分别阐述两种算法。

1. 遍历范围:4位形如aabb的数,符合条件:完全平方数

这个4位数用aabb表示,前面讨论过,a的取值范围是1-9,b的取值范围是0-9。也就是说a取的每一位数字,都要与b取的0-9组合一遍,就像相亲节目中每个男生都会用目光欻欻歘歘朝着每个女生闪烁一遍。每个男生一个接一个上台轮流闪烁,这是一次循环;每个男生上台后闪烁对面一个接一个的女生,又是一次循环。所以程序要用到循环的嵌套:循环里面套循环。

程序主干如下:

for(int a = 1; a <= 9; a++)

    for(int b = 0; b <= 9; b++)

        if(aabb是完全平方数) printf("%d\n", aabb);

这段主干程序并不是合法的C程序,第三行代码是不符合语法规范的,因而无法运行。

这样的不能真正运行的简化代码称为伪代码(pseudocode)。伪代码主要用于描述算法梗概,避开细节,启发思路。在使用伪代码时,可以不必拘泥格式,只求简明即可。

这段伪代码完整地表现出了程序的三个部分:遍历、判断、输出。

上述伪代码要变成真正的代码,需要解决两个问题:

(1) aabb的表示。

C语言中是无法用aabb这样的形式输出数的,因为它会被编译器识别为变量。把伪代码改写成代码时,一般先选择较为容易的任务来完成。前面讲过,这个问题比较简单,只要用a*1100 + b*11这种表达式的形式表示即可。

(2) 判断aabb是否为完全平方数。

这还不简单吗?只要用sqrt()函数给aabb开平方,再判断结果是不是一个整数不就行了?

这是正向思维,这个思路的难点在于,sqrt()函数的返回值是double类型,这种浮点数是有误差的。这意味着如果它的返回值是0.9999999999,它的真实值可能是一个整数1。

所以咱们是不能用下面这种方式来进行判断的:

if(sqrt(aabb)==最接近sqrt(aabb)的整数)

        printf("%d\n", aabb);

要判断一个浮点数是不是整数,只能用一个不太完美的办法:求这个浮点数与最接近它的值的整数的差,如果这个差小于一个很小的数,就认为它是整数。

那这个很小的数应该是多大合适呢?

系统为咱们定义了名叫DBL_EPSILON的宏,定义在头文件<float.h>中。它就是那个很小的正数,用于处理浮点数精度问题。DBL是double的缩写。EPSILON是希腊语,代表第五个希腊字母ε。ε在数学中常被用来表示一个非常小的正数,这个数可以任意小,但不等于零。

代码如下:

#include<stdio.h>

#include<math.h>

#include <float.h>

int main(){

    for(int a = 1; a <= 9; a++)

        for(int b = 0; b <= 9; b++){

            int aabb = a*1100 + b*11; //这里才开始使用n,因此在这里定义n

            double r1 =  sqrt(aabb);

            int r2 = floor(r1 + 0.5);

            if(fabs(r1 - r2) < DBL_EPSILON) printf("%d\n", aabb);

        }

    return 0;

}

注意sqrt(aabb)后面加上0.5这个细节,这是为了在转化为整数时进行四舍五入。函数floor(x)返回不超过x的最大整数。这里floor(sqrt(aabb) + 0.5)其实也可以写成:int r = (int)(sqrt(aabb) + 0.5)。后者是用数据类型强制转换的方式,舍去小数部分。它和用floor函数有什么区别呢?读者可以猜想一下。

fabs(x)返回x的绝对值。

虽然用上述代码也能输出正确的结果,但不能改变它是个天生残疾的事实。而且如果你忘了或不知道那个很小的数的宏名更当如何呢?

换一种思路,用逆向思维,就能避开浮点数误差,找到完美的算法:求出最接近sqrt(aabb)的整数,反过来判断它的平方是否等于aabb。

代码如下:

#include<stdio.h>

#include<math.h>

int main(){

    for(int a = 1; a <= 9; a++)

        for(int b = 0; b <= 9; b++){

            int aabb = a*1100 + b*11; //这里才开始使用n,因此在这里定义n

            int r = floor(sqrt(aabb) + 0.5);

            if(r*r == aabb) printf("%d\n", aabb);

        }

    return 0;

}

2. 遍历范围:4位完全平方数,符合条件:形如aabb

这种方法天生具有完美基因,因为它不涉及浮点数。

整数开方会产生小数,整数的平方只能是整数。

#include<stdio.h>

int main(){

    for(int x = 1; ; x++){

        int aabb = x * x;

        if(aabb < 1000) continue;

        if(aabb > 9999) break;

        int hi = aabb / 100;

        int lo = aabb % 100;

        if(hi/10 == hi%10 && lo/10 == lo%10) printf("%d\n", aabb);

    }

    return 0;

}

continue和break语句是C语言的两个语句。continue的作用是跳过当前循环体中剩余未执行的语句,并立即开始下一次的循环条件判定,即执行下一次循环。break的作用是直接跳出循环,即立即结束整个循环。

两种算法都介绍完了,问题来了,哪个算法效率更高呢?你猜猜!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/444045.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

linux 查看打开使用了哪些端口

你可以使用 netstat 命令来查看Linux系统中正在使用的端口。例如&#xff0c;要查看所有正在使用的TCP和UDP端口&#xff0c;你可以运行&#xff1a; sudo netstat -tulpn如果你只想查看所有正在使用的TCP端口&#xff0c;你可以运行&#xff1a; sudo netstat -tpln 如果你只…

滴滴一面:Keepalived+Nginx高可用,如何实现IP跳跃?(1)

尼恩说在前面 HashMap的工作原理是目前java面试问的较为常见的问题之一&#xff0c;在40岁老架构师 尼恩的读者交流群(50)中&#xff0c;最近有小伙伴拿到了一线互联网企业如得物、阿里、滴滴、极兔、有赞、shein 希音、百度、网易的面试资格&#xff0c;遇到很多很重要的面试…

蓝桥杯-List集合

目录 List集合实例化 List集合实例化步骤 常用方法 ArrayList方法 1&#xff1a;add(Object element) 2&#xff1a;size() 3&#xff1a;get(int index) 4&#xff1a;isEmpty() 5:contains(Object o) 6&#xff1a;remove(int index) 总结ArrayList list集合的特点…

Elasticsearch从入门到精通-03基本语法学习

Elasticsearch从入门到精通-03基本语法学习 &#x1f44f;作者简介&#xff1a;大家好&#xff0c;我是程序员行走的鱼 &#x1f4d6; 本篇主要介绍和大家一块学习一下ES基本语法,主要包括索引管理、文档管理、映射管理等内容 1.1 了解Restful ES对数据进行增、删、改、查是以…

多线程-线程池原子性并发工具类

1.线程池 1.线程状态 虚拟机中线程的六种状态 新建状态&#xff08;NEW&#xff09; --创建线程 就绪状态&#xff08;RUNNABLE&#xff09; --start方法 阻塞状态&#xff08;BLOCKED&#xff09; --无法获得锁对象 等待状态&#xff08;WAITING&#xff09; …

MySQL学习Day28——锁

一、概述: 锁是计算机协调多个进程或线程并发访问某一资源的机制。在程序开发中会存在多线程同步的问题&#xff0c;当多个线程并发访问某个数据的时候&#xff0c;尤其是针对一些敏感的数据(比如订单、金额等)需要保证这个数据在任何时刻最多只有一个线程在访问&#xff0c;保…

蓝桥杯简单题,公司名称

题目链接&#xff08;需要登录&#xff09; #include <iostream> #include <cstring> #include <algorithm> using namespace std; bool lanqiao(string str,int len){ sort(str.begin(),str.end());//对str按照ascii排序if(str.find("Laainoq")s…

HTML静态网页成品作业(HTML+CSS)——安徽宣笔设计制作(5个页面)

&#x1f389;不定期分享源码&#xff0c;关注不丢失哦 文章目录 一、作品介绍二、作品演示三、代码目录四、网站代码HTML部分代码 五、源码获取 一、作品介绍 &#x1f3f7;️本套采用HTMLCSS&#xff0c;未使用Javacsript代码&#xff0c;共有6个页面。 &#x1f3f7;️想要…

Linux系统——web服务拓展练习

目录 一、实验环境搭建 1. Centos 7-5——Client 2. Centos 7-1——网关服务器 3. Centos 7-2——Web1 4. Centos 7-3——Web2 5. Centos 7-4——Nginx 二、在Nginx服务器上搭建LNMP服务&#xff0c;并且能够对外提供Discuz论坛服务&#xff1b;在Web1、Web2服务器上搭建…

springboot255基于spring boot的疫情信息管理系统

疫情信息管理系统的设计与实现 摘要 近年来&#xff0c;信息化管理行业的不断兴起&#xff0c;使得人们的日常生活越来越离不开计算机和互联网技术。首先&#xff0c;根据收集到的用户需求分析&#xff0c;对设计系统有一个初步的认识与了解&#xff0c;确定疫情信息管理系统…

Unity Shader实现UI流光效果

效果&#xff1a; shader Shader "UI/Unlit/Flowlight" {Properties{[PerRendererData] _MainTex("Sprite Texture", 2D) "white" {}_Color("Tint", Color) (1, 1, 1, 1)[MaterialToggle] PixelSnap("Pixel snap", float…

【数据分享】2000-2022年全国1km分辨率的逐日PM10栅格数据

空气质量数据是在我们日常研究中经常使用的数据&#xff01;之前我们给大家分享了2000-2022年全国范围逐日的PM2.5栅格数据和2013-2022年全国范围逐日SO2栅格数据&#xff08;可查看之前的文章获悉详情&#xff09;。 本次我们给大家带来的是2000-2022年全国范围的逐日的PM10栅…

吴恩达deeplearning.ai:倾斜数据集的误差指标精确率、召回率

以下内容有任何不理解可以翻看我之前的博客哦&#xff1a;吴恩达deeplearning.ai专栏 文章目录 倾斜数据集的误差指标罕见病预测精确率和召回率 精确率和召回率的权衡精确率和召回率的矛盾关系 F1算法 倾斜数据集的误差指标 在神经网络中&#xff0c;如果你的数据集中正例和负…

giffgaff怎么充值?giffgaff怎么续费?

-性价比高&#xff1a;0月租&#xff0c;免费接收短信&#xff0c;充值一次&#xff0c;接码可以用20年以上&#xff08;仅需半年保号一次&#xff09;&#xff0c;可能是国内性价比最高的接码实体卡&#xff01;-安全&#xff1a;实体卡无须担心因号码被风控&#xff0c;还可以…

C语言:通讯录

目录 前言 1、通讯录框架&#xff0c;基本介绍 2、程序实现&#xff0c;步骤解释 2.1. 建立菜单 2.2. 主函数框架 2.3 前期工作 2.4 初始化通讯录函数&#xff1a;void InitContact(Contact* pc); 2.5 添加信息操作&#xff1a;void AddContact(Contact* pc); 2.6 显示…

Sublime Text 格式化Json文件 之 Pretty Json

需要使用到 Pretty Json插件。 一、安装方法 sublime 下&#xff0c;按快捷键 Comand control p&#xff0c; 输入install Package,然后回车 等几秒钟&#xff0c;加载启动进程完毕后弹出的页面中输入pretty json, 然后回车 等待几秒钟&#xff0c;可以查看Sublime 最下面的…

nginx配置支持ipv6访问,ipv4改造ipv6

一、前言 本地测试nginx部署的web系统支持ipv6地址访问。 二、本机ipv6地址 cmd ipconfig 找到IPv6地址 其中带有%号其实是临时分配得到地址 我们可以ping一下看看 另一种ping的方式 加上中括号 还有就是去掉%号 三、nginx增加配置 server块里增加 listen [::]:80; 四、测…

【SQL】指定日期的产品价格(IFNULL函数)

题目描述 leetcode题目&#xff1a;指定日期的产品价格 思路 找出所有的产品的指定的日期的价格&#xff1b;若找不到某个产品的更改日期&#xff0c;则将该产品价格设置为10。 关键点&#xff1a; if没有16号的&#xff0c;怎么找到前一个日期的&#xff1f;> 日期小…

【数字人】12、DINet | 使用形变+修复模块实现高清 talking head 生成(AAAI2023)

文章目录 一、背景二、方法2.1 deformation part2.2 inpainting part2.3 Loss 函数 三、效果3.1 数据集3.2 实现细节3.3 可视化效果 论文&#xff1a;DINet: Deformation Inpainting Network for Realistic Face Visually Dubbing on High Resolution Video 代码&#xff1a;h…

Yolov8-pose关键点检测:原创自研涨点系列篇 | 空间上下文感知模块(SCAM)结合超轻量高效动态上采样DySample

💡💡💡本文独家改进:YOLOV8-pose head创新,1)一种超轻量高效动态上采样DySample, 具有更少的参数、FLOPs,效果秒杀CAFFE和YOLOv8网络中的nn.Upsample;2)加入空间上下文感知模块(SCAM)进一步提升检测精度; 改进结构图如下: Yolov8-Pose关键点检测专栏介绍:ht…