仅使用处理单个数字的I/O例程,编写一个过程以输出任意实数(可以是负的)
2014-12-01 22:47
477 查看
题目取自:《数据结构与算法分析:C语言描述_原书第二版》——Mark Allen Weiss
练习1.3 如题。
补充说明:假设仅有的I/O例程只处理单个数字并将其输出到终端,我们将这个例程命名为PrintDigit;例如"PrintDigit(4)"
将输出一个"4"到终端。
思路:根据先简后繁的原则,程序各版本完成的功能依次为:处理正整数—>处理所有整数—>处理double—>double舍入。
版本一:
版本二:
讲述版本三之前先来看一下double类型在内存中的存储情况,在code::blocks中定义如下变量:
设置断点,调试,a、b、c初始化之前的值如图一,赋值后的值如图二
图一 图二
不难看出,double类型在内存中存储是有误差的。比如我们定义的c = 9.1,内存中实际值为9.099999999...6。其实这个值也是四舍五入得来的,那么如何看到它在内存中的全貌呢,请看版本三:
版本三:
对b=1.1而言,输出结果为:1.1000000000000000888178419700125232338905334472656250000000000000000000,对比图二不难得出结论:code::blocks中所示的数值就是原double值四舍五入并且精确到小数点后16位得到的。
但是,存在一个问题,比如拿c=9.1来说事,我们令版本三中程序中的变量N的值为1,则输出结果为9.0。所以这个程序的一个问题就是:没有考虑舍入误差。那么如何处理舍入误差呢,还好有Weiss 提供的core->)。
版本四:终极进化版
可以看到,该程序不仅解决了版本三中遗留的小数点舍入问题,而且通过设定PrintReal函数的第二个参数的值为70可以得到和版本三中相同的结果。End。
—————————————————————————^_^我是分隔线^_^—————————————————————————
All Rights Reserved.
Author:海峰:)
Copyright © xp_jiang.
转载请标明出处:/article/5264971.html
练习1.3 如题。
补充说明:假设仅有的I/O例程只处理单个数字并将其输出到终端,我们将这个例程命名为PrintDigit;例如"PrintDigit(4)"
将输出一个"4"到终端。
思路:根据先简后繁的原则,程序各版本完成的功能依次为:处理正整数—>处理所有整数—>处理double—>double舍入。
版本一:
// 正整数版(更大的范围可以使用long long int) #include<stdio.h> void PrintOut(int number); void PrintDigit(int number); int main(void) { int n = 123; PrintOut(n); return 0; } void PrintOut(int number) { int value = number / 10; if(value != 0) // 考虑用while会出现什么情况,如果数字不是个位数,那么程序死循环输出首位数字。 PrintOut(value); PrintDigit(number % 10); } void PrintDigit(int number) // 对处理单个数字的I/O例程进行模拟 { printf("%d", number); }
版本二:
// 强化版:所有整数 #include<stdio.h> void PrintOut(int number); void PrintDigit(int number); void PreDispose(int number); // 对传入的参数做一些预处理工作,然后调用PrintOut函数 int main(void) { int n = -45689; PreDispose(n); return 0; } void PreDispose(int number) { if(number < 0) { putchar('-'); number = -number; } PrintOut(number); } void PrintOut(int number) { int value = number / 10; if(value != 0) PrintOut(value); PrintDigit(number % 10); } void PrintDigit(int number) { printf("%d", number); }
讲述版本三之前先来看一下double类型在内存中的存储情况,在code::blocks中定义如下变量:
设置断点,调试,a、b、c初始化之前的值如图一,赋值后的值如图二
图一 图二
不难看出,double类型在内存中存储是有误差的。比如我们定义的c = 9.1,内存中实际值为9.099999999...6。其实这个值也是四舍五入得来的,那么如何看到它在内存中的全貌呢,请看版本三:
版本三:
// 强化版二:double类型 #include<stdio.h> #include<math.h> void PrintOut(int number); void PrintDigit(int digit); void PreDispose(double number); int main(void) { double n = 9.1; PreDispose(n); return 0; } void PreDispose(double number) { double ip; // 函数modf把传入的第一个参数分为整数和小数两部分,整数部分保存在第二个参数中 // 两部分的正负号均匀x相同,该函数返回小数部分 double fraction = modf(number, &ip); // 一个更加简便的分离小数位与整数位的方法如下: // double ip, fraction; // fraction = number - (int)number; // ip = (int)number; if(ip < 0) { putchar('-'); ip = -ip; fraction = -fraction; } PrintOut(ip); putchar('.'); // 对小数部分逐位输出,理论上可以输出到小数点后任意多的数位,就这几行代码还耗了不少脑细胞呢Orz int N = 70; // 希望输出到小数点多少位,就设定N为多少(想不到更好的解释了:-) while(N--) { fraction *= 10; PrintOut((int)fraction%10); // 因为传入的参数是单个数字,所以这里也可以直接调用PrintDigit函数 fraction = fraction - (int)fraction; // 防止fraction数据过大,导致整型溢出 } } void PrintOut(int number) { int value = number / 10; if(value != 0) PrintOut(value); PrintDigit(number % 10); } void PrintDigit(int digit) { printf("%d", digit); } //输出结果:9.0999999999999996447286321199499070644378662109375000000000000000000000
对b=1.1而言,输出结果为:1.1000000000000000888178419700125232338905334472656250000000000000000000,对比图二不难得出结论:code::blocks中所示的数值就是原double值四舍五入并且精确到小数点后16位得到的。
但是,存在一个问题,比如拿c=9.1来说事,我们令版本三中程序中的变量N的值为1,则输出结果为9.0。所以这个程序的一个问题就是:没有考虑舍入误差。那么如何处理舍入误差呢,还好有Weiss 提供的core->)。
版本四:终极进化版
//下面是我根据作者提供的核心代码补全后的版本,考虑了舍入误差(四舍五入) #include<stdio.h> int IntPart(double N); // 得到N的整数部分 double DecPart(double N); // 得到N的小数部分 void PrintReal(double N, int DecPlaces); // 该函数打印double值,其中第二个参数为精确到小数点后的位数 void PrintFractionPart(double FractionPart, int DecPlaces); // 打印小数部分 double RoundUp( double N, int DecPlaces ); // 实现四舍五入的函数 void PrintOut(int number); void PrintDigit(int number); int main(void) { double value = -9.1; PrintReal(value, 1); return 0; } double RoundUp( double N, int DecPlaces ) // 窃以为该函数为整个程序的画龙点睛之笔。 { int i; double AmountToAdd = 0.5; for( i = 0; i < DecPlaces; i++ ) AmountToAdd /= 10; return N + AmountToAdd; } void PrintReal(double N, int DecPlaces) { int IntegerPart; double FractionPart; if( N < 0 ) { putchar('-'); N = -N; } N = RoundUp(N, DecPlaces); IntegerPart = IntPart( N ); FractionPart = DecPart( N ); PrintOut(IntegerPart); // 假设错误检查已经完成,即输入是常规的文本 if(DecPlaces > 0) putchar('.'); PrintFractionPart(FractionPart, DecPlaces); } void PrintFractionPart(double FractionPart, int DecPlaces) // 程序三中输出小数部分的实现思路与之类似,不过其提供了对外接口——函数外部可以设定要输出的小数位数 { int i, Adigit; for( i = 0; i < DecPlaces; i++ ) { FractionPart *= 10; Adigit = IntPart(FractionPart); PrintDigit(Adigit); FractionPart = DecPart(FractionPart); } } int IntPart(double N) { return (int)N; } double DecPart(double N) { return N - IntPart(N); } void PrintOut(int number) { int value = number / 10; if(value != 0) PrintOut(value); PrintDigit(number % 10 ); } void PrintDigit(int digit) { printf("%d", digit); } //输出结果:9.1
可以看到,该程序不仅解决了版本三中遗留的小数点舍入问题,而且通过设定PrintReal函数的第二个参数的值为70可以得到和版本三中相同的结果。End。
—————————————————————————^_^我是分隔线^_^—————————————————————————
All Rights Reserved.
Author:海峰:)
Copyright © xp_jiang.
转载请标明出处:/article/5264971.html
相关文章推荐
- java实现数据结构练习题--仅使用处理单个数字的I/O例程,编写一个过程以输出任意实数(可以是负的)
- 只使用处理IO的printDigit函数,编写一个过程以输出任意实数可以为负(java数据结构与算法习题1.3)
- 只使用处理I/O的PrintDigit函数,编写一个过程以输出任意实数
- 只使用处理I/O的PrintDigit函数,编写一个过程以输出任意实数
- 只使用处理I/O的PrintDigit函数,编写一个过程以输出任意实数
- 只使用处理IO的printDigit函数,编写一个过程以输出任意实数
- 只使用I/O的PrintDigit函数,编写一个过程以输出任意实数
- 用c语言编写输出四个整数,这四个整数可以表示1到40之间的任意一个数字。
- 题目:使用命令行参数编写一个程序,其功能是将任意一个正整数m变换为指定的n 进制数串输出。命令行的格式为:
- 《c primer pius》第十章第6题,编写一个程序,初始化一个二维double数组,并利用练习2中的任一函数来把这个数组复制到另一个二维数组(因为二维数组是数组的数组,所以可以使用处理一维数组的
- 编写一个程序,可以一直接收键盘字符,如果是小写字符就输出对应的大写字符,如果是大写字符,就输出对应的小写字符,如果是数字不输出
- C语言编写一个程序,可以一直接收键盘字符,如果是小写字符就输出对应的大写字符,如果接收的是大写字符,就输出对应的小写字符,如果是数字不输出。
- 编写一个程序,可以一直接收键盘字符,如果是小写字符就输出对应的大写字符,如果接收的是大写字符,就输出对应的小写字符,如果是数字不输出
- 请编写一个C函数,该函数可以实现将一个整数转为任意进制的字符串输出
- Linux下,使用C/C++编写的一个简单的信号处理例程
- 小易邀请你玩一个数字游戏,小易给你一系列的整数。你们俩使用这些整数玩游戏。每次小易会任意说一个数字出来,然后你需要从这一系列数字中选取一部分出来让它们的和等于小易所说的数字。 例如: 如果{2,1,2,7}是你有的一系列数,小易说的数字是11.你可以得到方案2+2+7 = 11.如果顽皮的小易想坑你,他说的数字是6,那么你没有办法拼凑出和为6 现在小易给你n个数,让你找出无法从n个数中选取部分求和
- 编写一个程序,对用户输入的任意一组数字字符如{3,1,4,7,2,1,1,2,2},输出其中出现次数最多的字符,并显示其出现次数。如果有多个字符出现次数均为最大且相等,则输出最先出现的那个字符和它出现
- 编写一个程序,可以一直接收键盘字符,如果是小写字符就输出对应的大写字符,如果接收的是大写字符,就输出对应的小写字符,如果是数字不输出。
- 请编写一个C函数,该函数可以实现将一个整数转为任意进制的字符串输出
- 编写一个程序,可以一直接收键盘字符,如果是小写字符就输出对应的大写字符,如果接收的是大写字符,就输出对应的小写字符,如果是数字不输出.