编程之美 - 浮点数的精确表示
2016-04-14 21:44
381 查看
问题描述:
如何将浮点数(小数)转换为分数的形式,这样可以更精确的表达出浮点数的值。
问题分析:
小数可以分为两种,有限小数和无限循环小数。
有限小数的处理相对简单:
只要把它乘以10的N次方,转换为整数,再和10的N次方都除以它们的最大公约数即可。
例如:0.25 把它乘以 10的2次方 变成25, 25/100 分子分母除以最大公约数25变成1/4即可。
无限循环小数的处理要复杂一些:
书中使用了一个有趣的计算方法,它把无限循环小数分为一小数部分和一个循环部分 例如: X=0.a1a2...am(b1b2...bn)
这里a是小数部分,b是循环部分。
1) X先乘以10的m次方,把小数部分变为整数 X*10^m ==> a1a2...am + 0.b1b2...bn(b1b2...bn)
X = (a1a2...am + 0.b1b2...bn(b1b2...bn))/(10^m)
2) 假设 Y = 0.b1b2...bn(b1b2...bn),那么Y可以转换为 Y*10^n = b1b2...bn + 0.b1b2...bn(b1b2...bn)
Y*10^n = b1b2...bn + Y ==> Y = b1b2...bn/(10^n - 1)
3) 把Y的部分代入X的等式中 X = (a1a2...am + b1b2...bn/(10^n - 1))/(10^m)
X = (a1a2...am * (10^n - 1) + b1b2...bn) / ((10^n - 1)*10^m)
例如 0.3(3) = (3*9 + 3) / (9*10) = 30 / 90 = 1/3
实例程序:
程序中的缺陷,如果循环小数位数太多,会造成乘积超过int的范围,造成计算错误。
如何将浮点数(小数)转换为分数的形式,这样可以更精确的表达出浮点数的值。
问题分析:
小数可以分为两种,有限小数和无限循环小数。
有限小数的处理相对简单:
只要把它乘以10的N次方,转换为整数,再和10的N次方都除以它们的最大公约数即可。
例如:0.25 把它乘以 10的2次方 变成25, 25/100 分子分母除以最大公约数25变成1/4即可。
无限循环小数的处理要复杂一些:
书中使用了一个有趣的计算方法,它把无限循环小数分为一小数部分和一个循环部分 例如: X=0.a1a2...am(b1b2...bn)
这里a是小数部分,b是循环部分。
1) X先乘以10的m次方,把小数部分变为整数 X*10^m ==> a1a2...am + 0.b1b2...bn(b1b2...bn)
X = (a1a2...am + 0.b1b2...bn(b1b2...bn))/(10^m)
2) 假设 Y = 0.b1b2...bn(b1b2...bn),那么Y可以转换为 Y*10^n = b1b2...bn + 0.b1b2...bn(b1b2...bn)
Y*10^n = b1b2...bn + Y ==> Y = b1b2...bn/(10^n - 1)
3) 把Y的部分代入X的等式中 X = (a1a2...am + b1b2...bn/(10^n - 1))/(10^m)
X = (a1a2...am * (10^n - 1) + b1b2...bn) / ((10^n - 1)*10^m)
例如 0.3(3) = (3*9 + 3) / (9*10) = 30 / 90 = 1/3
实例程序:
程序中的缺陷,如果循环小数位数太多,会造成乘积超过int的范围,造成计算错误。
#include <iostream> using namespace std; typedef struct _data { unsigned long _a; unsigned long _b; // the loop part, if = 0 means no } data_t; unsigned long gcb(unsigned long a, unsigned long b) { unsigned long temp = 0, r = 0; // make sure a < b if (a > b) { temp = a; a = b; b = temp; } r = b % a; while(r != 0) { b = a; a = r; r = b%a; } return a; } void calc(data_t data) { unsigned long temp = 0, gcb_val = 0; unsigned long power_a = 1, power_b = 1; temp = data._a; while (temp != 0) { temp = temp/10; power_a *= 10; } temp = data._b; while (temp != 0) { temp = temp/10; power_b *= 10; } cout << "a->" << data._a << ":" << power_a << " b->" <<data._b << ":" << power_b << endl; // no loop part if (data._b == 0) { gcb_val = gcb(data._a, power_a); cout << data._a/gcb_val << "/" << power_a/gcb_val << endl; } else { temp = (data._a * (power_b - 1)) + data._b; power_b = power_a*(power_b - 1); gcb_val = gcb(temp, power_b); cout << temp/gcb_val << "/" << power_b/gcb_val << endl; } } int main() { data_t test; int val = 0; //test._a = 1; test._b = 0; //test._a = 23; test._b = 0; //test._a = 3; test._b = 3; test._a = 1; test._b = 1; //test._a = 285714; test._b = 285714; // error: int is overflow calc(test); cin >> val; return 0; }
相关文章推荐
- java中文乱码解决之道(三)-----编码详情:伟大的创想---Unicode编码
- [php-src]一个Php扩展的结构
- here we go
- java中文乱码解决之道(二)-----字符编码详解:基础知识 + ASCII + GB**
- C语言-郝斌笔记-003数据类型
- 函数的调用优化
- java输入学生成绩
- java怎么连接mysql数据库
- php 的快速学习和掌握。
- C++——STL所有算法介绍
- java中文乱码解决之道(一)-----认识字符集
- (2)java自带软件包javax.crypto的使用方法,保存generator中生成的key
- java基础; 面向对象编程; 对象的实例化
- C++类型转换:C++风格: static_cast、dynamic_cast、reinterpre
- C语言-郝斌笔记-002病毒程序示范
- [C语言][LeetCode][160]Intersection of Two Linked Lists
- BZOJ 3198 SDOI2013 spring
- python numpy 使用笔记 矩阵操作
- aspcms网站访问出现3706错误, 错误描述:未找到提供程序。该程序可能未正确安装,解决的方法。
- C语言-郝斌笔记-001求二次方程的根