动态输出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,可能会使所有小数甚至整数部分都产生变化。这是本题最大的坑,可谓神之一坑。

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

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

相关文章

HIDS是什么,如何保护主机系统

随着网络安全攻防对抗的日趋激烈&#xff0c;主机当前企业和组织的安全运营工作面临的挑战越来越突出&#xff0c;外网防护的同时&#xff0c;内网主机安全防护也越来越重要。 HIDS(Host-based Intrusion Detection System)&#xff0c;是基于主机型入侵检测系统的简称。作为计…

30万奖金谁能瓜分?OurBMC开源大赛决赛入围名单公示

首届开放原子开源大赛基础软件赛道自今年 1 月开启报名以来&#xff0c;吸引了全国各地 BMC 技术爱好者的广泛关注和踊跃报名。该赛事由开放原子开源基金会牵头&#xff0c; OurBMC 社区及理事长单位飞腾信息技术有限公司联合承办&#xff0c;以 “基于 BMC 技术的服务器故障诊…

抖音电商罗盘品牌人群运营策略指南

【干货资料持续更新&#xff0c;以防走丢】 抖音电商罗盘品牌人群运营策略指南 部分资料预览 资料部分是网络整理&#xff0c;仅供学习参考。 抖音运营资料合集&#xff08;完整资料包含以下内容&#xff09; 目录 品牌人群运营策略&#xff0c;旨在帮助品牌通过精细化运营提…

雅虎套餐发稿独家技巧,让你的媒体宣发效率翻倍

在如今的信息时代&#xff0c;媒体宣发是每个品牌和公司都不可或缺的一部分。而雅虎套餐发稿&#xff0c;作为其中的一种方式&#xff0c;更是受到了许多人的青睐。那么&#xff0c;如何才能充分利用雅虎套餐发稿的功能&#xff0c;让你的媒体宣发效率翻倍呢&#xff1f;以下就…

Java 解决 Process 执行命令行命令报【CreateProcess error=2, 系统找不到指定的文件。】错误问题

目录 问题 问题代码 解决方案 判断操作系统 问题 使用 Process 执行命令行命令时&#xff0c;报 CreateProcess error2, 系统找不到指定的文件。但明明指定的文件是存在的。而且这种错误只在 IDEA 中运行会报错&#xff0c;打包后直接 java -jar 运行就能正常运行&#xf…

【绩效管理】帮助零售企业建立分层分类绩效考核体系项目纪实

购物中心张经理评价&#xff1a;“员工的绩效管理一直是困扰我公司的难题&#xff0c;我们只懂得怎么经营&#xff0c;至于怎么做人力资源管理&#xff0c;真是一点都不懂。这次华恒智信为我们提供的服务对我们的帮助很大。基于企业实际调研情况&#xff0c;华恒智信专家明确指…

高维解码|Redis 收紧许可证!开源软件公司如何在云时代生存?

最近&#xff0c;Redis 从开放源代码的 BSD 许可证过渡到了更加限制性的 Server Side Public License (SSPLv1)。一石激起千层浪&#xff0c;Redis 的这一举动&#xff0c;不仅分化了前 Redis 维护者&#xff0c;也再次引发业界对于“开源项目可持续性以及许可证决策对其社区的…

easyExcel - 按模板导出

目录 前言一、情景介绍二、文档介绍2.1 读取模板2.2 填充模板 三、代码示例3.1 案例一&#xff1a;工资表3.2 案例二&#xff1a;报价单 四、我所遇到的问题 前言 Java-easyExcel入门教程&#xff1a;https://blog.csdn.net/xhmico/article/details/134714025 之前有介绍过如…

无尽加班何时休--状态模式

1.1 加班&#xff0c;又是加班&#xff01; 公司的项目很急&#xff0c;所以要求加班。经理把每个人每天的工作都排得满满的&#xff0c;说做完就可以回家&#xff0c;但是没有任何一个人可以在下班前完成的&#xff0c;基本都得加班&#xff0c;这就等于是自愿加班。我走时还有…

查看Linux系统相关信息

注&#xff1a; 本文只是博主学习记录分享&#xff0c;仅供参考。如有错误肯定是博主理解有问题&#xff0c;谢谢&#xff01; 一、查看当前操作系统的内核信息 命令&#xff1a;uname -a 二、查看当前操作系统版本信息 命令&#xff1a;cat /proc/version 这条命令可以查看到…

Your file appears not to be a valid OLE2 document

前言 org.apache.poi.poifs.filesystem.NotOLE2FileException:Invalid header signature; read 0x0000000000000000, expected 0xE11AB1A1E011CFD0 - Your file appears not to be a valid OLE2 document解决 Excel兼容模式打开老版本文件造成文件损坏&#xff0c;大多说的是点…

OPC UA遇见chatGPT

最近opc 基金会将召开一个会议&#xff0c;主题是”OPC UA meets IT“。由此可见&#xff0c;工业自动化行业也开始研究和评估chatGPT带来的影响了。 本文谈谈本人对OPC UA 与chatGPT结合的初步实验和思考。 构建OPC UA 信息模型 chatGPT 的确非常强大了&#xff0c;使用自然…

Redis 主从复制、哨兵模式、Cluster集群

目录 一、Redis 主从复制 1、主从复制介绍 2、主从复制的作用 3、主从复制流程&#xff1a; 4、搭建redis主从复制 4.1所有服务器搭建redis数据库 4.2修改Redis配置文件&#xff08;Master节点操作&#xff09; ​4.3修改Redis配置文件&#xff08;slave节点操作&#x…

如何搭建企业级MQ消息集成平台

企业级MQ消息集成平台的重要性在于实现不同系统之间的高效、可靠、实时的消息传递和数据交换。它可以帮助企业实现系统解耦&#xff0c;提高系统的可扩展性和灵活性&#xff0c;降低系统间的依赖性。通过消息队列中间件&#xff0c;企业可以实现异步通信、削峰填谷、流量控制等…

Mysql底层原理七:InnoDB 行记录

1.行格式 1.1 Compact行格式 1.1.1 示意图 1.1.2 准备一下 1&#xff09;建表 mysql> CREATE TABLE record_format_demo (-> c1 VARCHAR(10),-> c2 VARCHAR(10) NOT NULL,-> c3 CHAR(10),-> c4 VARCHAR(10)-> ) CHARSETascii ROW_FORMATCOM…

基于支持 GPT 的服务的初创公司

Kafkai&#xff1a;多语言长篇内容生成&#xff0c;AI写作的新趋势 介绍 随着生成式预训练 Transformer (GPT) 的出现&#xff0c;技术世界正在见证范式转变。 这种人工智能驱动的创新不仅仅是一种转瞬即逝的趋势&#xff0c;而是一种趋势。 它已成为科技行业的基石&#xff0c…

PCA算法(Principal Component Analysis)揭秘

经典PCA算法 PCA算法的应用包括降维、有损数据压缩、特征抽取、数据可视化等。目前PCA算法有两个通用定义&#xff0c;能殊途同归&#xff0c;得到相同的结果。一方面&#xff0c;我们可以用正交投影来定义PCA&#xff0c;即将数据投影到更低维的线性子空间&#xff0c;也被称…

一文2700字使用 JMeter 进行灵活的接口自动化测试!

简介&#xff1a; JMeter 是一个开源的负载测试工具&#xff0c;它可以模拟多种协议和应用程序的负载&#xff0c;包括 HTTP、FTP、SMTP、JMS、SOAP 和 JDBC 等。在进行接口自动化测试时&#xff0c;使用 JMeter 可以帮助我们快速地构建测试用例&#xff0c;模拟多种场景&#…

Windows:IntelliJ IDEA Ultimate 安装 PHP 插件

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

文档管理系统解决方案(word原件)

1.系统概述 1.1.需求描述 1.2.需求分析 1.3.重难点分析 1.4.重难点解决措施 2.系统架构设计 2.1.系统架构图 2.2.关键技术 数据备份技术 3.系统功能设计 3.1.功能清单列表 3.2.基础数据管理 3.3.位置管理 3.4.文档使用 3.5.文档管理 软件全套资料包获取方式①&#xff1a;软件项…