ACM中关于计算几何(浮点数)的精度问题

计算几何的精度问题说到底其实是浮点数的精度问题,但我觉得“计算几何”比“浮点数”更能吸引眼球,所以选了这个标题。

1.浮点数为啥会有精度问题:

浮点数(以C/C++为准),一般用的较多的是float, double。

 

占字节数

数值范围

十进制精度位数

float

4

-3.4e-38~3.4e38

6~7

double

8

-1.7e-308~1.7e308

14~15

如果内存不是很紧张或者精度要求不是很低,一般选用double。14位的精度(是有效数字位,不是小数点后的位数)通常够用了。注意,问题来了,数据精度位数达到了14位,但有些浮点运算的结果精度并达不到这么高,可能准确的结果只有10~12位左右。那低几位呢?自然就是不可预料的数字了。这给我们带来这样的问题:即使是理论上相同的值,由于是经过不同的运算过程得到的,他们在低几位有可能(一般来说都是)是不同的。这种现象看似没太大的影响,却会一种运算产生致命的影响: ==。恩,就是判断相等。注意,C/C++中浮点数的==需要完全一样才能返回true。来看下面这个例子:

#include<stdio.h>

#include<math.h>

int main()

{

   double a = asin(sqrt(2.0) / 2) * 4.0;

   double b = acos(-1.0);

   printf("      a = %.20lf\n", a);

   printf("      b = %.20lf\n", b);

   printf(" a - b = %.20lf\n", a - b);

   printf("a == b = %d\n", a == b);

   return 0;

}

输出:

      a = 3.14159265358979360000

      b = 3.14159265358979310000

 a - b = 0.00000000000000044409

a == b = 0

我们解决的办法是引进eps,来辅助判断浮点数的相等。

2. eps

       eps缩写自epsilon,表示一个小量,但这个小量又要确保远大于浮点运算结果的不确定量。eps最常见的取值是1e-8左右。引入eps后,我们判断两浮点数a、b相等的方式如下:

定义三出口函数如下: int sgn(double a){return a < -eps ? -1 : a < eps ? 0 : 1;}

则各种判断大小的运算都应做如下修正:

传统意义

修正写法1

修正写法2

a == b

sgn(a - b) == 0

fabs(a – b) < eps

a != b

sgn(a - b) != 0

fabs(a – b) > eps

a < b

sgn(a - b) < 0

a – b < -eps

a <= b

sgn(a - b) <= 0

a – b < eps

a > b

sgn(a - b) > 0

a – b > eps

a >= b

sgn(a - b) >= 0

a – b > -eps

这样,我们才能把相差非常近的浮点数判为相等;同时把确实相差较大(差值大于eps)的数判为不相等。

PS: 养成好习惯,尽量不要再对浮点数做==判断。例如,我的修正写法2里就没有出现==。

3. eps带来的函数越界

如果sqrt(a), asin(a), acos(a) 中的a是你自己算出来并传进来的,那就得小心了。

如果a本来应该是0的,由于浮点误差,可能实际是一个绝对值很小的负数(比如1e-12),这样sqrt(a)应得0的,直接因a不在定义域而出错。

类似地,如果a本来应该是±1,则asin(a)、acos(a)也有可能出错。

因此,对于此种函数,必需事先对a进行校正。

4. 输出陷阱I

这一节和下一节一样,都是因为题目要求输出浮点数,导致的问题。而且都和四舍五入有关。

说到四舍五入,就再扯一下相关内容,据我所知有三种常见的方法:

1. printf(“%.3lf”, a);  //保留a的三位小数,按照第四位四舍五入

2. (int)a;  //将a靠进0取整

3. ceil(a); floor(a);   //顾名思义,向上取证、向下取整。需要注意的是,这两个函数都返回double,而非int

其中第一种很常见于输出(nonsense…)。

现在考虑一种情况,题目要求输出保留两位小数。有个case的正确答案的精确值是0.005,按理应该输出0.01,但你的结果可能是0.005000000001(恭喜),也有可能是0.004999999999(悲剧),如果按照printf(“%.2lf”, a)输出,那你的遭遇将和括号里的字相同。

解决办法是,如果a为正,则输出a+eps, 否则输出a-eps

典型案例: POJ2826

5. 输出陷阱II

ICPC题目输出有个不成文的规定(有时也成文),不要输出: -0.000

那我们首先要弄清,什么时候按printf(“%.3lf\n”, a)输出会出现这个结果。

直接给出结果好了:a∈(-0.000499999……, -0.000……1)

所以,如果你发现a落在这个范围内,请直接输出0.000。更保险的做法是用sprintf直接判断输出结果是不是-0.000再予处理。

典型案例:UVA746

6. 范围越界

这个严格来说不属于精度范畴了,不过凑数还是可以的。请注意,虽然double可以表示的数的范围很大,却不是不穷大,上面说过最大是1e308。所以有些时候你得小心了,比如做连乘的时候,必要的时候要换成对数的和。

典型案例:HDU3558

7. 关于set<T>

有时候我们可能会有这种需求,对浮点数进行 插入、查询是否插入过 的操作。手写hash表是一个方法(hash函数一样要小心设计),但set不是更方便吗。但set好像是按==来判重的呀?貌似行不通呢。经观察,set不是通过==来判断相等的,是通过<来进行的,具体说来,只要a<b 和 b<a 都不成立,就认为a和b相等,可以发现,

如果将小于定义成:      bool operator < (const Dat dat)const{return val < dat.val - eps;}就可以解决问题了。 (基本类型不能重载运算符,所以封装了下)

8. 输入值波动过大

这种情况不常见,不过可以帮助你更熟悉eps。假如一道题输入说,给一个浮点数a, 1e-20 < a < 1e20。那你还敢用1e-8做eps么?合理的做法是把eps按照输入规模缩放到合适大小。

典型案例: HUSTOJ 1361

9. 一些建议

容易产生较大浮点误差的函数有asin、 acos。欢迎尽量使用atan2。

另外,如果数据明确说明是整数,而且范围不大的话,使用int或者long long代替double都是极佳选择,因为就不存在浮点误差了(尽管我几乎从来都只用double --!)

转自https://blog.csdn.net/entalent/article/details/47620341

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

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

相关文章

微信公众号网站开发相关记录

1 如何监听微信录音是否正常开启 wx.startRecord({success: function (ret) {alert("开始录音" JSON.stringify(ret));},fail: function (err) {alert("无法录音" JSON.stringify(err));}});

【POJ - 1182】 食物链(附超详细讲解)(并查集--种类并查集经典题)

题干&#xff1a; 动物王国中有三类动物A,B,C&#xff0c;这三类动物的食物链构成了有趣的环形。A吃B&#xff0c; B吃C&#xff0c;C吃A。 现有N个动物&#xff0c;以1&#xff0d;N编号。每个动物都是A,B,C中的一种&#xff0c;但是我们并不知道它到底是哪一种。 有人用两…

腐蚀单机怎么进_暖气片堵塞是什么原因?要怎么解决呢?

你知道散热器到底为什么堵塞吗&#xff1f;散热器堵塞了怎么办&#xff1f;下面和金旗舰散热器小编一起来看看吧~一、散热器堵塞怎么办首先&#xff0c;把进回水阀先全部关闭&#xff0c;用扳手将散热器的堵头轻轻拧开。这里需要注意的是&#xff0c;堵头对应的散热器下面要放一…

layui弹出界面空白页问题

弹出界面时&#xff0c;有时会出现空白界面&#xff0c;应该如何处理&#xff1f; 1 尝试解决方式&#xff1a;在open方法的success回调方法中&#xff0c;获取当前iframe高度&#xff0c;重新赋予新的高度&#xff1b; let ifr layero.find(iframe)[0]; let bHeight ifr.s…

vspy如何在图形面板显示报文_设备实时状态监控:如何进行工业生产设备数据采集?...

设备实时状态监控&#xff1a;如何进行工业生产设备数据采集&#xff1f;数据采集(DAQ)&#xff0c;是指从传感器和其它待测设备等模拟和数字被测单元中自动采集非电量或者电量信号,送到上位机中进行分析&#xff0c;处理。慧都设备数据采集系统解决方案工业生产设备数据采集是…

【POJ - 2236】Wireless Network (并查集)

题干&#xff1a; An earthquake takes place in Southeast Asia. The ACM (Asia Cooperated Medical team) have set up a wireless network with the lap computers, but an unexpected aftershock attacked, all computers in the network were all broken. The computers …

如何使用微信公众平台测试号进行系统开发

申请一个测试号&#xff1a;入口修改测试公众号自定义菜单&#xff08;使用微信公众平台接口调试工具&#xff09;网站开发&#xff0c;进行部署网站测试

【POJ - 1751】Highways (最小生成树)

题干&#xff1a; The island nation of Flatopia is perfectly flat. Unfortunately, Flatopia has a very poor system of public highways. The Flatopian government is aware of this problem and has already constructed a number of highways connecting some of the …

jupyter怎么安装jieba_AI工具:Anaconda中Jupyter不能import已安装module问题解决

jupyter模式下写代码时,通过pip install package命令行安装package完成之后,无法在jupyter模式下import &#xff0c;这是个通用的问题&#xff0c;我这里遇到的是import jieba&#xff0c;可能import 别的package也会出现&#xff0c;记录下&#xff0c;也花了点时间排查。。。…

Sql Server数据库设置一个账户只能看到一个数据库

1 新建登录名&#xff0c;注意不要设置用户映射&#xff0c;服务器角色只选择public&#xff08;默认必选&#xff0c;无法去掉&#xff0c;可以添加其他服务器角色&#xff0c;但是不要添加查看所有数据库的权限&#xff0c;接下来会去掉public的查看所有数据库权限&#xff0…

boot lib分离 spring_spring boot + gradle打包bootJar分离lib

以前项目打包一直是用的maven&#xff0c;最近新开一个项目&#xff0c;使用的是spring boot 2.11 gradle 4.10.3&#xff0c;在打包的时候分离lib折腾了好几天&#xff0c;网上找了很多方法都不成功&#xff0c;老是卡在configurations.compile这里&#xff0c;总是获取不到正…

【POJ - 3494】Largest Submatrix of All 1’s(加一点思维后化成 单调栈)

题干&#xff1a; Given a m-by-n (0,1)-matrix, of all its submatrices of all 1’s which is the largest? By largest we mean that the submatrix has the most elements. Input The input contains multiple test cases. Each test case begins with m and n (1 ≤ m…

如何在修改计算机设置时,不再弹出提示框?

1 打开控制面板&#xff0c;找到安全与维护&#xff1b; 2 进入安全与维护&#xff0c;在安全中找到“用户账户控制UAC”&#xff0c;点击打开“更改设置” 3 进行设置&#xff0c;“从不通知”设置之后&#xff0c;针对计算机的所有更改将不再提示

doe五步法_DOE方法介绍

DOE, Design of Experiment。就是试验设计。想知道对于某个过程的产生影响的诸多因素中对输出结果影响最关键的因素有哪些&#xff0c;就可以用DOE方法来设计一系列试验&#xff0c;获知关键影响因素。通常的确定对输出变量最关键影响因子的试验做法有三种。1. 经验猜测法。首先…

【POJ - 1789】【ZOJ - 2158】【SCU - 1832】Truck History (最小生成树)

题干&#xff1a; Description Advanced Cargo Movement, Ltd. uses trucks of different types. Some trucks are used for vegetable delivery, other for furniture, or for bricks. The company has its own code describing each type of a truck. The code is simply a…

matlab两张图片合成一张_11. 图像合成与图像融合

本文同步发表在我的微信公众号“计算摄影学”&#xff0c;欢迎扫码关注【转载请注明来源和作者】我们终于进入了新的篇章。这一次我来给大家介绍一下图像合成与融合。我们经常看到一些很奇妙的PS技术&#xff0c;例如下面这张&#xff0c;它把1928年的一位叫做Frankie Yale的黑…

C#学习,Web界面打开winform程序

1 Web打开winform程序&#xff0c;需要使用的标签为a标签 <a href"SelfName://">连接提示</a> //SelfName 是自己的自定义协议2 Winform程序一般不需要做任何操作&#xff0c;如果需要参数传递的情况下&#xff0c;可以将Winform的Program.cs程序修…

【POJ - 2349】【UVA - 10369】 Arctic Network(最小生成树求权值第k大的边)(内附两种算法)

题干&#xff1a; The Department of National Defence (DND) wishes to connect several northern outposts by a wireless network. Two different communication technologies are to be used in establishing the network: every outpost will have a radio transceiver a…

asp.net MVC结合Blazor开发学习

1建立MVC项目&#xff08;.net 6&#xff09;; 2 在项目启动文件Program.cs中添加Blazor框架&#xff1b; var builder WebApplication.CreateBuilder(args);// Add services to the container. builder.Services.AddControllersWithViews(); builder.Services.AddServerSid…

澄海口袋机器人_汕头市澄海区在2019年汕头市中小学智能机器人竞赛上取得优异成绩...

4月14日&#xff0c;2019年汕头市中小学智能机器人竞赛在汕头市蓬鸥中学举行。本次活动由汕头市教育局和汕头市科协联合主办&#xff0c;全市93所学校的249个队伍503名选手报名参赛&#xff0c;大赛设“高铁时代”机器人现场拼装赛、丛林任务挑战赛、超级轨迹赛、综合技能比赛、…