动态输出n位小数——满满都是坑!

【题目描述】

输入正整数abc,输出a/b的小数形式,精确到小数点后c位。a,b ≤10^6 ,c≤100。输入包含多组数据,结束标记为abc=0。

【样例输入】

1 6 4

0 0 0

【样例输出】

Case 1: 0.1667

【题目来源】

刘汝佳《算法竞赛入门经典  第2版》习题2-5 分数化小数(decimal)

【解析】

这道题很简单呀!

等等,以前都是题目中明确给出保留几位小数,比如要求保留3位小数,咱们就可以:

printf(“%.3f”, a/b);

本题要保留的小数位数是在程序运行时指定的,取决于用户输入的c,这该怎么办呢?难不成要写成这样:

printf(“%.%df”, c, a/b);

实际测试完全行不通,看来格式说明符是不能嵌套的。这其实很好理解,如果支持嵌套,不光看起来乱,还会导致歧义。比如%%df,按理%%应解释为转义字符,用来表示字符“%”。

一、用系统函数动态输出n位小数

1.C语言版

这里涉及一个新的语法知识点,要实现按变量的值动态输出小数位数,就要把代码改成这样子:

printf(“%.*f”, c, a/b);

*和f一样,也是一个占位符,起占位作用,它表示从参数中取一个整数值来作为浮点数的精度。

学会了这种操作,代码马上呼之欲出:

#include<stdio.h>
int main(){int a, b, c, kase=0;while(scanf("%d%d%d", &a, &b, &c)==3 && a*b*c){double f = (double)a/b;printf("Case %d: %.*f\n", ++kase, c, f);}return 0;
}

输入样例测试也满全符合,是不是大功告成了呢?

2. C++版

除了上面的C语言版,也可以使用纯C++语法动态输出小数位数(语法非常麻烦)。

#include <iostream>
#include <iomanip> // 包含 setprecision 的头文件
using namespace std;
int main() {int a, b, c, kase=0;while(scanf("%d%d%d", &a, &b, &c)==3 && a*b*c){double f = (double)a/b;cout << "Case " << ++kase << ": " << fixed << setprecision(c) << f << endl;}return 0;
}

遗憾的是,咱们费了半天劲儿,上面的面代码却都是错误的。

重点就在于题目要求c≤100,如果输入1 6 100,马上就会发现输出结果不正确。

测试是非常重要的,尤其是边界数据的测试更为重要。

因为double的有效精度只有16位,因而用printf根本无法有效输出100位小数。

怎么办呢?自己动手,丰衣足食。

二、自己动手算小数

咱们要用程序模拟小数除法运算,想想小学时学的运算规则:每次求出的余数后添0,然后继续除。比如28÷16:

算法可以描述为:

①求商的整数部分。

②求商的小数部分:重复将余数乘10继续除。

这就完了吗?别忘了“精确到小数点后c位”的意思?最后一位输出的小数需要四舍五入。

代码如下:

#include<stdio.h>
int main(){int a, b, c, kase=0;while(scanf("%d%d%d", &a, &b, &c)==3 && a*b*c){//输出小数点前的内容printf("Case %d: %d.", ++kase, a/b);//输出小数点后的c-1位a=a%b;for(int i=1; i<=c-1; i++){a*=10;printf("%d", a/b);a = a%b; //获取第i位运算后的余数}//输出第c位小数,四舍五入a*=10;printf("%d", a/b + 10*(a%b)/b/5);printf("\n");}return 0;
}

四舍五入部分当然也可以用If语句判断第c+1位小数的值是否大于等于5,这里用了一个巧算,用n/5即可实现当n≥5时,结果为1。

这回终于结束了吧!

No,No,No,客官即将迎来本题的最大深坑。

如果输入下面的数据,就知道上面的代码问题出在哪了。

999 1000 2

9999 1000 2

输出结果:

因为小数部分有一连串的9,进位会导致前面的小数甚至整数全部改变,因而按照上面的代码就会输出错误结果。

如果给咱9999/1000这道算术题,让咱保留两位小数,咱肯定不会算错。但是让咱设计保留2位小数的算法,就非常容易忽略这种情况。前者是看到某种情形,想到对应规则,后者是想到所有情形,想到对应规则,难度不可同日而语。

所以算法设计必须要穷尽所有可能性,遗漏任何一种情形都会导致出错。对于数据来讲,最容易被忽略的就是边界数据。

比如本题,小数位数100位是边界,最后一位小数要四舍五入是边界,9进位会变成0也是边界(9是最大数字)。因此,对于任何类型的数据,一定要养成思考边界、测试边界的习惯。

三、用数组解决999式进位问题

要解决这个问题,就需要用到数组,把每位小数都存到数组中,再根据各位小数值及是否要进位重新修正每位小数的值。

代码如下:

#include<stdio.h>
int main(){int a, b, c, point, d[105], kase=0;while(scanf("%d%d%d", &a, &b, &c)==3 && a*b*c){//求出小数点后的c+1位int r=a%b;for(int i=1; i<=c+1; i++){r*=10;d[i] = r/b;r%=b; //获取第i位运算后的余数}//根据是否进位修正各位小数d[0] = 0; //保存小数到整数的进位if(d[c+1] >= 5){for(int i=c; i>=0; i--){if(9 == d[i]){d[i] = 0;} else{d[i] += 1;break;}}}//输出小数点前的内容printf("Case %d: %d.", ++kase, a/b + d[0]);//输出小数部分for(int i=1; i<=c; i++){printf("%d", d[i]);}printf("\n");}return 0;
}

需要说明的是,本题是第2章习题,此章节还没学到数组,但这道题目前老金只会用数组求解。如有高人知道不用数组的解法,还望指点一二!

最后总结一下,这道题非常容易出错,它有三大神坑:

①用printf函数最多只能输出16位有效小数,无法输出100位,必须要自己模拟除法运算求小数。

②最后一位小数需要根据下一位小数四舍五入。

③最后一位小数如果是9,在四舍五入时会导致前面的小数发生变化,如果有一连串的9,可能会使所有小数甚至整数部分都产生变化。这是本题最大的坑,可谓神之一坑。

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

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

相关文章

Windows:IntelliJ IDEA Ultimate 安装 PHP 插件

在 IntelliJ IDEA Ultimate 中安装 PHP 插件&#xff0c;支持PHP开发调试 首先&#xff0c;进入File > Setting&#xff1a; 再次选择Plugins&#xff0c;然后选择上面的 Marketplace。 在搜索栏中输入 PHP&#xff0c;然后单击左侧的 Install 进行安装就可以了。 安装成功…

关于Ansible模块 ⑤

转载说明&#xff1a;如果您喜欢这篇文章并打算转载它&#xff0c;请私信作者取得授权。感谢您喜爱本文&#xff0c;请文明转载&#xff0c;谢谢。 继《关于Ansible的模块 ①》、《关于Ansible的模块 ②》与《关于Ansible的模块 ③》之后&#xff0c;继续学习ansible常用模块之…

Cannot find runner for app ——Android Studio

问题 在修改build.gradle(:app)文件或者其他操作后&#xff0c;出现了无法运行的问题&#xff1a; Cannot find runner for app 如图运行按钮不可点击。 解决方案 点击【File】下的【Sync Project with Gradle Files】同步完成后&#xff0c;一般就可运行了。

ENSP USG防火墙接入虚拟机;开启Web访问;

1.添加防火墙及云&#xff0c;启动防火墙&#xff1b; 2.配置桥接网卡&#xff1b; 默认账户&#xff1a;admin 默认密码&#xff1a;Admin123 #第一次登陆需修改密码&#xff1b; 默认G0/0/0口为管理口&#xff0c;而在模拟器中进入防火墙的web需如下配置&#xff1a; 配置 …

聊一下Redis实现分布式锁的8大坑

前两篇文章都在讲 Redis 的 5 大常用数据类型&#xff0c;以及典型的 10 大应用场景。 那么今天就来看看 Redis 实现分布式锁。 聊一聊Redis实现分布式锁的8大坑 Redis中5大常见数据类型用法 工作中Redis用的最多的10种场景 在分布式系统中&#xff0c;保证资源的互斥访问是…

高效测试丨怿星RTP协议测试解决方案

近几年&#xff0c;车内音视频娱乐系统不断发展&#xff0c;功能不断丰富&#xff0c;对于音视频的传输需求也逐渐增多&#xff0c;随着车载以太网的日渐成熟&#xff0c;各主机厂逐步方案落地、成本逐步降低&#xff0c;基于车载以太网的音视频传输也在逐步应用&#xff0c;常…

如何远程监控员工的电脑

如何远程监控员工的电脑 为什么要对员工使用电脑的行为进行监控呢&#xff1f;对企业来说是有其必要性的。其必要性主要体现以下4个方面。 1.数据安全与知识产权保护 防止数据泄露&#xff1a;企业内部往往存储着大量的敏感信息&#xff0c;如客户数据、财务资料、商业秘密、…

鸿蒙ArkUI开发实战:制作一个【简单计数器】

构建第一个页面 使用文本组件 工程同步完成后&#xff0c;在 Project 窗口&#xff0c;点击 entry > src > main > ets > pages &#xff0c;打开 Index.ets 文件&#xff0c;可以看到页面由 Row 、 Column 、 Text 组件组成。 index.ets 文件的示例如下&#xff1…

Qt+VS2019中使用QAxObject时的环境配置

在纯Qt中 在.pro中添加axcontainer模块即可 而VSqt中&#xff1a; 特别傻的是&#xff1a;我运行的是release&#xff0c;但配置的是debug的属性页&#xff0c;一直报错&#xff0c;人都傻了。 最后发现果然是人傻。

《2024工业软件行业软件授权方案使用情况调研报告》发布

深度解析行业应用与趋势 随着制造业的转型升级和数字化、智能化的加速推进&#xff0c;工业软件行业市场规模持续增长的同时也推动着行业技术和商业模式的创新。软件供应商需要根据市场需求和自身特点来制定合适的授权策略和商业模式&#xff0c;以实现软件产品的最大化商业价值…

算法练习第12天|● 239. 滑动窗口最大值● 347.前 K 个高频元素

239.滑动窗口的最大值 力扣原题 题目描述&#xff1a; 给你一个整数数组 nums&#xff0c;有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的 k 个数字。滑动窗口每次只向右移动一位。 返回 滑动窗口中的最大值 。 示例 1&#xff…

Excel返回数值的各个位数值

运行结果 千位 如下图 INT(MOD(A2,10000)/1000) 百位 如下图 INT(MOD(A2,1000)/100) 十位 如下图 INT(MOD(A2,100)/10) 个位 如下图 MOD(A2,10) 特此记录 anlog 2024年4月8日