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

【题目描述】

输出所有形如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,因此在这里定义ndouble 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,因此在这里定义nint 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的作用是直接跳出循环,即立即结束整个循环。

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

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C语言字符串型常量

在C语言中&#xff0c;字符串型常量是由一系列字符组成的常量。字符串常量在C中以双引号&#xff08;"&#xff09;括起来&#xff0c;例如&#xff1a;“Hello, World!”。字符串常量在C中是不可变的&#xff0c;也就是说&#xff0c;一旦定义&#xff0c;就不能修改其内…

Web自动化测试流程:从入门到精通,帮你成为测试专家

摘要&#xff1a; Web应用程序在今天的软件开发中占据着越来越重要的地位。保证Web应用程序的质量和稳定性是非常必要的&#xff0c;而自动化测试是一种有效的方法。本文将介绍Web自动化测试流程&#xff0c;并提供代码示例。 步骤一&#xff1a;选取测试工具 选择适合自己团…

像SpringBoot一样使用Flask - 5.统一处理(日志、异常、响应报文)

接上文《像SpringBoot一样使用Flask - 4.拦截器》&#xff0c;通过拦截器处理一些日志&#xff0c;异常、还有统一的响应报文。 统一的目的就是为了让前后端调用请求不会因为各自习惯而随意编写&#xff0c;增加技术人员快速上手及代码的可阅读性。 一、定义一个返回类。是不是…

【前端Vue】Vue从0基础到大神完整教程第1篇:vue基本概念,vue-cli的使用【附代码文档】

Vue从0基础到大神学习完整教程完整教程&#xff08;附代码资料&#xff09;主要内容讲述&#xff1a;vue基本概念&#xff0c;vue-cli的使用&#xff0c;vue的插值表达式&#xff0c;{{ gaga }}&#xff0c;{{ if (obj.age > 18 ) { } }}&#xff0c;vue指令&#xff0c;综合…

20行代码搞定PDF表格转为Excel表

1.环境准备 安装好python并且配置好环境安装pdfplumber、xlwt库使用Vscode或者PyCharm等编辑器 在pycharm中如果报红&#xff0c;可以鼠标点击报红的库&#xff0c;altenter进行安装 2.代码部分 import pdfplumber import xlwt # 读取源pdf文件 pdf pdfplumber.open("…

图像处理ASIC设计方法 笔记8 卷积计算芯片的结构

(一) P81 卷积芯片内部模板框图 该设计有两个数据通路:图像数据和模板数据。 图像数据是经过帧控制、实时图SPRAM(写控制、 SPRAM读控制、数据读控制)、计算单元; 模板数据是经过模板SPRAM、计算单元。 4.5.4运算单元像素寄存器控制 存储SPRAM写入的64bit数据,输出为…

Unity2023.1.19_DOTS_JobSystem

Unity2023.1.19_DOTS_JobSystem 上篇我们知道了DOTS是包含Entity Component System&#xff0c;Job System&#xff0c;Burst compiler三者的。接下来看下JobSystem的工作原理和具体实现。 简介&#xff1a; 官方介绍说&#xff1a;JobSystem允许您编写简单而安全的多线程代…

C++篇 语 句

到目前为止&#xff0c;我们只见过两种语句&#xff1a; return 语句和表达式语句。根据语句对执行顺 序的影响&#xff0c;C 语言其余语句大多属于以下 3 大类。 选择语句&#xff1a; if 语句和 switch 语句。循环语句&#xff1a; while 语句&#xff0c; do...while 语句和…

XSS漏洞-存储型漏洞案例

一、环境 在github上找DVWA的靶机环境 DVWA存储库 二、复现 先将其安全等级改为低 然后点击存储型的xss&#xff0c;先随便写几条看看现象 可以看到我们写的都展示在了下面的框中 看看源码&#xff0c;分析在存储时的漏洞 我们可以看到&#xff0c;在对数据插入的时候&am…

筛选出等于1的式子

然后统计和归类 归类分行归类方法 算术符号归类 数字大小排序算术符号归类 import randomdef generate_expression(num_range, num_count, operators):nums random.sample(range(num_range[0], num_range[1]1), num_count)ops random.choices(operators, knum_count-1)expre…

ChatGPT 结合实际地图实现问答式地图检索功能基于Function calling

ChatGPT 结合实际地图实现问答式地图检索功能基于Function calling ChatGPT结合实际业务&#xff0c;主要是研发多函数调用&#xff08;Function Calling&#xff09;功能模块&#xff0c;将自定义函数通过ChatGPT 问答结果&#xff0c;实现对应函数执行&#xff0c;再次将结果…

List(CS61B学习记录)

问题引入 上图中&#xff0c;赋给b海象的weight会改变a海象的weight&#xff0c;但x的赋值又不会改变y的赋值 Bits 要解释上图的问题&#xff0c;我们应该从Java的底层入手 相同的二进制编码&#xff0c;却因为数据类型不同&#xff0c;输出不同的值 变量的声明 基本类型…

一步到位!快速精通Git工作流及实战技巧详解

Git是一个分布式版本控制系统。 1、git的应用场景 1.备份 小明负责的模块就要完成了&#xff0c;就在即将release之前的一瞬间&#xff0c;电脑突然蓝屏。硬盘光荣牺牲&#xff01;几个月来的努力付之东流。 场景二&#xff1a;代码还原 这个项目中需要一个很复杂的功能&…

CVHub | 初识langchain,3分钟快速了解!

本文来源公众号“CVHub”&#xff0c;仅用于学术分享&#xff0c;侵权删&#xff0c;干货满满。 原文链接&#xff1a;初识langchain 1 什么是langchain langchain[1]是一个用于构建LLM-Based应用的框架&#xff0c;提供以下能力: 上下文感知&#xff1a;可以为LLM链接上下文…

《Python源码剖析》之字符串拼接的一个效率问题

前言 我们常用的字符串拼接方法有两个&#xff0c;一个是通过“”号实现字符串的拼接&#xff0c;还一个就是通过join方法来实现拼接&#xff0c;前者在写法上更加便利&#xff0c;和数字之间的加法运算一样&#xff0c;通常只有两个运算对象&#xff0c;只不过他们的运算规则…

新贵Claude 3家族强势登场,AI领域掀起新一轮浪潮!

人工智能领域的风云再起,Anthropic公司日前放出狠招,推出了全新的大模型家族Claude 3系列。Claude 3由三款不同级别的大模型组成,分别是Claude 3 Haiku、Claude 3 Sonnet和Claude 3 Opus。这一系列产品的推出,不仅扩充了AI生态,更是对OpenAI的GPT-4等龙头产品发出了挑战。让我们…

函数柯里化:JavaScript中的高级技巧

&#x1f90d; 前端开发工程师、技术日更博主、已过CET6 &#x1f368; 阿珊和她的猫_CSDN博客专家、23年度博客之星前端领域TOP1 &#x1f560; 牛客高级专题作者、打造专栏《前端面试必备》 、《2024面试高频手撕题》 &#x1f35a; 蓝桥云课签约作者、上架课程《Vue.js 和 E…

ospf静态路由实验简述

1、ospf静态路由实验简述 实验拓扑图 实验命令 r2: sys sysname r2 undo info enable int loopb 0 ip add 2.2.2.2 32 quit int e0/0/0 ip add 23.1.1.2 24 quit ospf 1 area 0 network 23.1.1.0 0.0.0.255 network 2.2.2.2 0.0.0.0 ret r3: sys sysname r3 undo info enable …

python 蓝桥杯之动态规划入门

文章目录 DFS滑行&#xff08;DFS 记忆搜索&#xff09; 思路&#xff1a; 要思考回溯怎么写&#xff08;入参与返回值、递归到哪里&#xff0c;递归的边界和入口&#xff09; DFS 滑行&#xff08;DFS 记忆搜索&#xff09; 代码分析&#xff1a; 学会将输入的数据用二维列表…

变换,动画

面试题——需求&#xff1a;在不知道父元素与子元素的宽高时 如何让子元素在父元素内居中&#xff1f; 1.定位 父相子绝 2.子元素 top&#xff1a;50% left:50% 3.子元素 transform: translate(-50%,-50%) .parent{height: 500px;background-color: red;position: relative;}.c…