周星星 阅读(7603) 评论(40)

[2006-01-23补充] (本应写在文章后面)
To  反对者:
假设计算机用浮点数 a_f 来表示实数 a_v,计算机用浮点数 b_f 来表示实数表示 b_v。
c_f 是计算机 a_f 和 b_f 相乘的结果,c_v 是实数 a_v 和  b_v 相乘的结果。
照你所说,就应该是 if(  c_f ==  c_v ± EPSILON  ),但请问这个EPSILON应该取值为多少?是0.1,还是1.0E-999?
假如还没有明白的话,我再问一个问题:用你这个EPSILON之后,即使你保证了应该相等的相等了①,但同时如何能保证不应该相等的决不相等②?比如你用 if( 0.3 *3 == 0.9±0.001 ) 确实可以输出“0.3*3等于0.9”,但也会输出“0.300001*3等于0.9”,小学生也知道后面一个是不成立的。但如果你把EPSILON写得非常小,使得“0.300001*3不等于0.9”,那么它又会输出“0.3*3不等于0.9”。总之,①和②是不可能同时成立的。
这只是问题之一,问题之二在于浮点数不是定点数,它和实数之间的差并不是一个固定值,何况这里面还包含运算过程中带来的累积差。

--------------------------------------------------------

[期待读者] 使用浮点数格式的语言的用户。(Fortran用户没有这个烦恼)
[前言] 本以为这是一个极其简单和基础的问题,但连续三天分别在三个不同的C/C++论坛遇到这个问题,令我不得不有发通牢骚的责任^_^。
[正文]
在浮点数上自作聪明的使用EPSILON的例子中,最出名的当属林锐博士的《高质量C++/C编程指南》,其开篇第一项就说“float x 与零值比较的 if 语句”写成“if( x == 0.0f )”是错的,应当写成“if( x>=-EPSILON && x<=EPSILON )”。
a. “if( x>=-EPSILON && x<=EPSILON )”是否是自作聪明的纂改了题意(题意是问是否等于0,而不是问是否接近0),先撇开不谈;
b. “if( x == 0.0f )”是否有错误(我不知道哪个标准说这句话错了;如果指的是逻辑,我告诉你这种用法也很平常),也先撇开不谈。
撇开a和b不谈,把问题简化为:if(a==b) 是否应当写成 if( fabs(a-b) < EPSILON ) 或类似的形式?

首先问为什么要把if(a==b)写成if( fabs(a-b) < EPSILON )?别人告诉我理由是浮点数不精确。
对于“不精确”要细细的描述,是什么不精确?是浮点数在计算机内部存储和计算不精确,还是浮点数不能精确的表示现实中的实数?
如果认为是前者的人,return "回学校重学 数字计算机 和 模拟计算机 那一章";
如果是后者,也就是不认为浮点数在计算机内部存储和计算不精确的人,既然如此,if(a==b) 和 if( fabs(a-b) < EPSILON ) 就同坐一条船,要么都对,要么都错。
还没明白^_^?因为 if( a-b < EPSILON ) 可以写成 if( a < b+EPSILON ),再把 b+EPSILON 用 c 替代就成了 if( a < c ),如果a不能和c用operator==,那么也就不能用<、>、<=、>=,道理是一样的。
(讲到这里就结束了,下面的事例是为不举例就听不懂的人准备的)

对于浮点数无法使用EPSILON的举证:
1。无法确定EPSILON,或者说唯一合理的EPSILON就是0.0。
假设把EPSILON定义为0.000001,OK!如果 a=0.0000001 请问 a 和 2a 等不等?用if( 2a-a < EPSILON )来计算它俩就是相等的,明显瞎扯。
有人说这很简单呀,只要把EPSILON定义得更小一点就可以了。错,因为总有比EPSILON更小的可能,所以EPSILON只有可能定义为0,if( fabs(a-b) < EPSILON )又等于if(a==b)了。
有人说不要那么吹毛求疵嘛,确定一个平衡些的EPSILON就行了。也错,如果你真能清楚自己当初为什么要把if(a==b)写成if( fabs(a-b) < EPSILON )的原因的话,就不会有这个蠢提议了,之所以要把if(a==b)写成if( fabs(a-b) < EPSILON )原意是因为浮点数是定长定有效位数但不定位的,所以EPSILON也应该是一个变数,而非可以用#define或const定义的常量。
还没明白^_^?回想《计算机基础》上的浮点数在实数轴上的分布点,是不是越接近±0.5-±1.0越密,其间隔是非定长的。
2。现实需求中不存在EPSILON
(因为说了太多次,所以也不说了)

[总结]:浮点数不是定点数,因为不是定点数,所以无法使用EPSILON;意图使用EPSILON来解决浮点数和实数不一致问题的人,其错误本质还是一模一样的,只是换了一种犯错误的形式而已。

[题外话之一]:如何解决浮点数和实数不一致的问题?这本身就属于设计错误,如果你需要的是实数的计算结果,那就不应该使用浮点数来计算。

[题外话之二]:网上也有很多使用EPSILON的算法,但
a. 其算法是固定的,参与计算的数值和结果的范围也是确定的,那么有可能(也只是有可能,并非一切算法都……)存在一个合理的EPSILON,如果它被验证过的话。
b. 如果不是a,那么就一定是从fortran那里照搬过来的,照搬的人不明白浮点数的特性。

[题外话之三]:林锐博士的《高质量C++/C编程指南》开篇第一项一共说了三点,除了上面已经讲过的float和零值比较之外,另外两点也都错误。
a. “请填写BOOL , float, 指针变量 与“零值”比较的 if 语句”
C/C++中没有BOOL这个字,C中的名_Bool,在stdbool.h中定义为bool;C++中的名bool。不知道他这个BOOL从哪里来的,并说成是《高质量C++/C编程指南》?
b. “请写出 char  *p 与“零值”比较的 if 语句。”
他的答案是 if( p == NULL ),我在一个论坛里说“如果是C++,那就应该写成 if( p == 0 ),写成NULL的人,Bjarne在《The C++ Programming Language》中为你们哭泣。”


评论列表
pAnic
re: 浮点数 和 EPSILON (文章越写越啰嗦)
EPSILON一般是用在工程中的有效位数舍入计算。
在普通的运算中,使用EPSILON大概有三种情况:
1,数据结果被用作除数等场合,太小的数值更容易引起数值溢出或者逻辑溢出。
2,某些运算的振荡消除。例如一个温度控制函数:
if( t < 10.0f ) t += dt;
else if( t > 10.0f ) t -= dt;
else {} //恒温
由于dt的数值极有可能大于浮点数在10.0f附近的步进,那这个函数极有可能引起振荡而无法进入恒温状态,所以正确的做法是提供一个许可的EPSILON值,然后修改语句成类似的:
if( t < (10.0f - EPSILON) ) t += dt;
else if( t > (10.0f + EPSILON)  ) t -= dt;
else {} //恒温
3,某些几何重合。比如我们知道三角形三条角平分线相交于一点,验证的方法就是两两求交点,然后判断是否一致。
在实数域,这个运算没有任何问题,但是在浮点数域,通过运算得到的两个点坐标极有可能是不完全重合的,为了能正确表达这个“重合”,需要一个许可的“误差”,这时候也是别无选择的。
pAnic
re: 浮点数 和 EPSILON (文章越写越啰嗦)
浮点数本身是不存在EPSILON,但是用浮点数表达的现实量,在计算机的世界里是需要一个EPSILON的,就好像一个人的身高可能只需要精确到0.01m,而一个机器的零件却有可能需要0.01mm的精确度一样,EPSILON大量用于开发,而绝对相等这类判断在浮点数的应用中实属罕见。
vender
re: 浮点数 和 EPSILON (文章越写越啰嗦)
两个观点,与您商榷:

1、举个简单例子:
double      d = 10.0;
d += 135.3;
d /= 10;
d -= 14.53;
std::cout << (d == 0.0) << std::endl;
将输出0,至少于vc、gcc上

原因大家都很清楚,源自由十进制有限小数转化的二进制小数往往是无限的,以至于会超过浮点的有效位数而损失精度,只有能表示成2 ^ n的有限多项式且由其权值们转换的二进制数定点部分和幂部分都不超出浮点的有效表示范围才能精确被表示,再加上运算可能导致新的精度损失,判断结果实用范围比使用确定的数是有必要的,对楼上的表述表示赞同

2、关于Bjarne的哭泣
我想应该是我看书不仔细,我只看到
“Because of C++’s tighter type checking, the use of plain 0, rather than any suggested NULL macro, leads to fewer problems. If you feel you must define NULL, use
const int NULL = 0;
The const qualifier (§5.4) prevents accidental redefinition of NULL and ensures that NULL can be used where a constant is required.”
似乎没有要哭泣那么严重,呵呵
huangrg
re: 浮点数 和 EPSILON (文章越写越啰嗦)
b. “请写出 char  *p 与“零值”比较的 if 语句。”
他的答案是 if( p == NULL ),我在一个论坛里说“如果是C++,那就应该写成 if( p == 0 ),写成NULL的人,Bjarne在《The C++ Programming Language》中为你们哭泣。”
---------------------------------------------------------------
p == NULL,这个有问题吗? 
#ifndef __cplusplus
      #define NULL (void*)0
#else
      #define NULL 0
#endif
兼顾了C和C++.
pAnic
re: huangrg
建议用NULL代替直接的0,除了C语言的因素外,多半是基于一个不使用magic number的理由,而NULL不是C++标准的一部分,不同的编译器和开发环境可能会提供不同的实现,例如:
#define NULL 0
const int NULL = 0;
enum {NULL /* = 0 */ };
如此等等,而类似这样的NULL,其用途是有区别的。

从移植角度来说,用0比NULL更优越。
从编码角度来说,用0可以少打三个字母^_^
用0比较大的缺点就是,当想通过查找来寻找有多少个指针被初始化成0的时候,直接搜索0简直是场恶梦。
周星星
jb,怎么有这么多回复?
1楼:
你说的并不是我这儿的EPSILON,你只是用EPSILON来命名了你的一个变量而已。我说的是 判断a是否等于b时 可否用 EPSILON 来消除 浮点数和实数并不以一一对应所产生的误差(或者是计算的累积误差)。
2楼:
你举的例子是基于定点数的,可现在浮点数是非定点数,它在表示每一个实数时,误差都不一样。你不可以说 实数a 和 表示这个实数a的浮点数b 之间的EPSILON是多少,比如
real(1.0) 和 double(1.0) 之间的误差是 0.0
而 real(1.79E308) 和 double(1.7E308)之间的误差是 1e306
你认为EPSILON是应该取0.0还是1e306?
3楼:
我只能遗憾的说,你也不知道浮点数的特性,否则你就不会要求浮点数 (10+135.3)/10-14.53 等于 0。浮点数不是实数,因此它的结果和以实数计算的结果是不一样的,就像 1/2 == 0 而不是 == 0.5 这么简单。我相信你是知道这一点的,但如果你意图使用EPSILON来修正这个结果,那就错了,因为没有任何一个EPSILON能修改其结果,错在过程,而不是结果,缘木无法求鱼,如果EPSILON能解决这个问题,……(很多有趣的结论)。

对于p==NULL,首先得说明两点
1。C中(void*)可以付给任意指针类型,0不可以;C++中0可以付给任意指针类型,(void*)不行。
2。写NULL比写(void*)0更方便;写NULL比写0更麻烦。
基于以上两点,那么在C++中写p==NULL的是谁?
a. 认识一个class就以为自己学会了C++的C程序员,哭泣不应该?
b. 从恶心的XXX(隐藏这三个字母,免得引起争吵)代码中学来,人不学学鬼,哭泣不应该?
周星星
re huangrg:
没有不可以,但结合“《高质量C++/C编程指南》”这几个大字就不可以。
小明
re: 浮点数 和 EPSILON (文章越写越啰嗦)
我不喜欢BOOL和NULL
谢谢
vender
to 周星星
限于阅历,我真的不清楚要求判断(10.0+135.3)/10-14.53是否等于0有什么问题,我想应用中计算类似(a + b) / c - d是否为0并不少见

抛开计算机实现,认为(10+135.3)/10-14.53等于0应该不为过吧,那么如果计算机计算时如果给出的是否定的答案,那么恐怕这个过程也没有意义了,既然知道采用ieee浮点的计算机实现给出否定是因为损失了精度,那么判断范围我想大致不会出现什么问题,特别是在函数连续时

我的考虑肯定不周,盼望指教“浮点数的特性”,如果不很费时间的话,先谢谢了,呵呵
pAnic
re:周星星
的确如此,但是除了纯粹的数学理论研究之外,其他场合的“浮点数”一般都是定点数,而应用中,浮点数也是在一个有限范围内作为定点数来使用的,给定范围之后,EPSILON要解决的绝不是浮点数和实数之间的表达误差,而是浮点数和实际需求的定点数之间的表达误差,两者不应该混为一谈。
乾坤一笑
to pAnic
to pAnic: "建议用NULL代替直接的0,除了C语言的因素外,多半是基于一个不使用magic number的理由" 
——
 给你个× 。

magic number 一般指除0和1之外的literal number。
证据:Brain W.Kernighan 写的《The Practice of Programming》的第1.5节。

:)
乾坤一笑
to vender :
Vender老兄,你写得太麻烦了。偶来给你个用例:
double d = 10.0;
d -= d;
d /= 10;
std::cout << (d == 0) << std::endl;

啊,不巧得很,输出结果是1。说明做为double的d在(10.0-10.0)/10这个小学生都认为是0的地方,它确实是0,嘿嘿。我想应用中计算类似(a - b) / c是否为0并不少见,比如求三角形余弦值来判角。
vender
re: 浮点数 和 EPSILON (文章越写越啰嗦)
to 乾坤一笑:

承蒙指教,多谢

我给找了个(a - b) / c,您给看看,a = (10 + 135.3) / 10,当然,这个值要求被算出来,而不能直接给14.53的字面值或者让编译器算,这实际上算是一般状况的模拟,b = 14.53,c = 10

我这里算的结果d == 0是个false,当然这并不令人惊奇,这个例子就是为了这个false而设的,但是我想它表现了runtime状况

如果有可能,特别想听听周星星关于“浮点特性”的观点
乾坤一笑
re: 浮点数 和 EPSILON (文章越写越啰嗦)
星星说道理不举具体例子是不对的,这样怎么让别人理解嘛。做培训应该显浅易懂,比如举个反例:
#define EPSILON (0.000001) //这个值随便取,简单起见,这里取一个非零正值
double a = EPSILON ; //非零正值当然大于零了,这个小学生都知道,就是说a>0,我们先记着

//okey,让我们学林锐。。。
if (a>=-EPSILON && a<=EPSILON ) // 传说中的a等于0
{
cout << "我要说:a等于0!" <<endl;
cout << "我把小学生都知道的a大于0说成a等于0,我是猪!" <<endl;
}
乾坤一笑
to vender //re: 浮点数 和 EPSILON (文章越写越啰嗦)
考!大家都在线灌水啊?开房间聊算了:p Vender,你要的周星星关于float的高论在这里,写的很罗嗦,你自己看吧:)
http://blog.vckbase.com/bruceteen/articles/240.html

PS:我给的case d == 0是个true,这也不令人惊奇,这个例子就是为了这个true而设的,但是我想它表现了float不用EPSILON未必就没法跟0比。
vender
re: 浮点数 和 EPSILON (文章越写越啰嗦)
to 乾坤一笑:
您好,我翻看了我的言论,从没提到“float不用EPSILON就没法跟0比”这个观点,仅仅是说“存在不用EPSILON就没法跟字面常数或者其他浮点数比”的情况,那么在难以预料时,我们选择什么呢?我认为EPSILON范围比较法虽不确定,但反而准确,逻辑上准确

重申一下观点,浮点运算我所知有限,简而言之,目前我对浮点的知识是:

ieee规范浮点表示把其他进制字面值转化为二进制m * 2 ^ n的方式,m是型为1.????或-1.????的二进制定点数,存储时只存????部分,n为有符号整数,数的符号占一个二进制位,浮点数分为几种精度,原理类似,只是有效位数不同(记忆久远,没及查实,有谬误还望指正)

于是可以看到,第一步就存在着其他进制到二进制转换的问题,前面提到了,只有能表示成2 ^ n的有限多项式且由其权值们转换的二进制数定点部分和幂部分都不超出有效表示范围才能精确被表示。另外运算也可能导致新的精度损失

主要的就是这些,我的观点是:一般情况用epsilon法,具体情况还需具体分析。

由于上述的精度损失效应,数学=>计算机实现往往发生连续=>离散的转化,所以一般情况下,使用范围判断比使用单值判断要好,当然,这个是笼统的观点,具体情况更需具体分析,依据具体要求选择不同的解决方案绝对是有必要的

多谢提供文章链接,我拜读先
Panic
re: 浮点数 和 EPSILON (文章越写越啰嗦)
to pAnic: "建议用NULL代替直接的0,除了C语言的因素外,多半是基于一个不使用magic number的理由" 
——
 给你个× 。

magic number 一般指除0和1之外的literal number。
证据:Brain W.Kernighan 写的《The Practice of Programming》的第1.5节。

:)


我觉得你理解有误,magic number是指当一个数字并非表达其数值自身,所谓的表达数字自身,是指这样一种情况:
for(int i = 0;//是的,i等于0,i是一个初始值为0的整型变量,这个是明确的。

而不表达数字自身,例如:
switch(result)
{
case 0://....
//....
这种情况,0多半是表示某个特定的返回值或者上下文场景,例如FACILITY_NULL,NO_ERROR或者S_OK等,这个时候0就是一个magic number,而
Brain W.Kernighan 也没有一口咬定0就一定不是magic number,他是说, any number other than 0 or 1 is likely to be magic 用了likely一词,只是一种可能性的提升,多数情况,0和1用于初始化等场合,可以认为不是magic number,而其他数字则多数是magic number。
同样,一些资料也推荐 -1 也在某些场景不作为magic number,其实也是出于类似的原因。

判定一个数字是否是magic number的依据,是能否找到一个词,比数字自身更能描述当前的需求,如果这个词存在而且比原本的数字更容易理解,更有利于代码阅读,那么这个数字就认为是magic number,无论其数值是多少。

原则上讲,既然C++语法已经规定了指针赋值为0的合法性,从语言的角度讲,这时候它不是一个magic number,因此可以安全使用,而在其他场合,还需要进一步推敲。

Panic
re: 乾坤一笑
看偶关于magic number的随笔:

http://blog.vckbase.com/panic/archive/2006/01/21/17229.html
大山
老纠缠于语法。永远成为不了高手。失望死了。
  .
pAnic
re: 大山
呵呵,星星是语法高手~
一笑
to Panic :
狡辩!
好人
re: 浮点数 和 EPSILON (文章越写越啰嗦)
这个问题就好似我们在计算中如何带入圆周率的问题,完全是看计算精度,所以说浮点数的比较只要符合程序所需要的精度即可,加之很多时候(基本可以说是全部),比较2个浮点数的精度根本不需要到计算机中能表述的浮点数有效数字的最末位,所以一般程序中都会使用到相近比较来确定是否相等
颜学铭
re: 浮点数 和 EPSILON (文章越写越啰嗦)
细节决定成败!
越是细微之处,越要谨小慎微,程序员在日常编码中越是细微之处越应该知其然而后知其所以然。君不见bug常隐藏于细节之中。一家之言。
颜学铭
re: 浮点数 和 EPSILON (文章越写越啰嗦)
我认为float的比较应该在具体的上下文环境下讨论才有意义。根据你的上下文环境对精度的要求而定,EPSILON应该有不同的取值。比如你的计算结果通常在百万级以上,那么假设误差为0.1左右,其相对误差也很小。又如果你的计算结果本身就在0.0-1.0之间,那么你误差0.1其相对误差就很大了。
EPSILON也不是取值越小越好,如果小到你能表示的精度以下,其比较结果也就无意义了。
举个例子来说,假定你有一台GPS采集仪,能够测量经度和纬度,其精确度以秒计,秒以下就不精确了,那么你认为读数E103度5分30.5秒和E103度5分30.9秒到底哪一个更精确?因为秒以下就不精确了,所以我们认为N103度5分30秒是这个地点的准确值。因此我们认为两次测定的是同一个经度位置。
清风雨
re: 浮点数 和 EPSILON (文章越写越啰嗦)
看了部分,后面就不想细看下去了。因为以前也见你在论坛发表过一番感想。
这个问题,恐怕星星有所偏颇。
bool r1 = 0.0001 == 0.0001;
bool r2 = 0.0001f == 0.0001;
这两个表达式是并没有问题,只是,不加注意,或者通过运算,不是这么显示的表达,我们通常会认为r1和r2都是true的,而事实上r2是false(就你的32为PC而言)。
而通常,往往遇到的是隐式的,类似if( m == 0.0f ) 这样的比较,不论m是float还是double的,显然,和我们主观的预期通常都是相违背的(因为你运算得来的m常常并不是精确为0的,而是近似0的,而我们并不会引起注意,尤其是对初学者)。那么,我们该怎么做?所以,才用范围代替。
可能是一些朋友的简短的解释,让你有了这个想法,但,不管怎么说,对浮点,请不要精确比较,该用精度范围。
周星星
re vender:
“限于阅历,我真的不清楚要求判断(10.0+135.3)/10-14.53是否等于0有什么问题”
--- 问题在于计算机的存储是有限的,而实数是无限的。
a. 范围的无限。(这个与本题无关。)
b. 精度的无限。假设你用一亿位(足够了吧?!)来存储一个浮点数,那么有个 vender2 的就会对你说“限于阅历,我真的不清楚要求判断0.0……(一亿位)05*2是否等于0.0……(一亿位)1有什么问题”。
c. 进制转化的无限。能在有限位数内用10进制表示的数,用2进制可能就是一个无限位数,比如0.3。
周星星
re 清风雨:
这两个问题是否一致,你自己去想。

“那么,我们该怎么做?所以,才用范围代替。”
--- 没有因果关系吧。如果你问我“该怎么做?”,我得回答就是:
如果你一定要判断是否相等,那就只能使用无限精度的实数。
但如果你不需要无限精度,而又要判断是否相等,那么你应该先计算出(10.0+135.3)/10-14.53浮点数运算的结果,假设为 RESULT,然后写成if( (10.0+135.3)/10-14.53 == RESULT )。
浮点数和实数计算是有差别的,差别不是一个范围。
vender
re: 浮点数 和 EPSILON (文章越写越啰嗦)
to 周星星:
受教,您的观点是有道理的,如果指的“浮点特性”就是这个的话,我了解了。我理解您认为浮点只存在精度不够的问题,而不存在不精确,且范围判断虽然能使“正确的”幸免,但同时也放过了“错误的”,这个我同意。诚然,普适图灵机的基础就是“算法的”,“算法的”的特征就是精确的,不存在不精确的问题

我注意到,这里的逻辑的“不精确”仅仅是我提到的“数学=>计算机实现往往发生连续=>离散的转化”产生的不精确,连续的实数要求无限精度去表示,这个计算机处理不了,咱们人脑可以处理,计算机只能处理离散的信息,这就意味着不可能存在无限精度,是不是意味着对这些问题都放弃不做呢?

无限问题仅仅在数学中存在,现实物理世界却不是无限的(人类认知范围内不是),例如处理长度、时间、温度等等,都会事先给定一个精度,假设某个问题的输入输出值都最多只有小数点后3位的精度,那么可以尝试定义epsilon = 0.0000001,然后用范围去判断,很容易设想这比直接用==去判断要好得多,当然,当输入为?.???????x,x != 0时显然可能令范围判断产生可笑的结果,但是这种输入在一开始就被否定了,这就意味着在避免放过“错误的”的情况下满足实际问题的要求

对此,可以看到,我的观点比较柔和:“在一般情况下(经过一定的数学分析加上实践检验)用epsilon法还是相当不错的,在遇到特殊情况时,具体分析还是有必要的”。恕我冒昧,应该说您的观点有些极端了,现实问题往往不是那么较真的,我们并非生活在柏拉图世界,这也是我在此文后回帖的目的所在。当然抛开现实来谈,您的观点明显是正确的,但物理世界中epsilon并非是错误的化身,呵呵
周星星
re 云风:
谢谢!
不过浮点数运行是绝对精确的[见注释],既然是精确的,那么就不应该使用EPSILON。

[注]:说浮点数运行结果是精确的 不等于说 浮点数运行结果和实数运算结果相等。比如 1.0f / 3.0f 在任何时候任何机器上(程序员有意的要求编译器精度换时间的除外)其结果都应该是 0.3333333432674407958984375,这就是浮点运算,结果绝不可能偏差一丝一毫,既然丝毫不差,那就不应该使用EPSILON。
十年未晚
re: 浮点数 和 EPSILON (文章越写越啰嗦)
星星是不是语法高手不知道,但肯定是个钻牛角尖的高手:)
周星星
re 十年未晚:
1。本文所描述的问题和语法无关。
2。假如你对浮点数是“固定有效位数”这个最基础的,与编程语言无关的知识点都不知道,我只能表示遗憾。最基础的常常是最重要的,我并不想说教,你好自为之。
lable
re: 浮点数 和 EPSILON (文章越写越啰嗦)
你的帖子好像没什么价值,瞎说一通。
lable
re: 浮点数 和 EPSILON (文章越写越啰嗦)
再看一遍,更是觉得你的理论除了“人连一次都不可能踏进同一条河流”以外,真是有点让人不能理喻。
不希望你多发帖子,容易误导俺们这些愚昧的中国人
缺陷
re: 浮点数 和 EPSILON (文章越写越啰嗦)
讨论了这么多都去纠缠细节,星星也真是的,谁能把八百年都用不到的浮点数记得的那么清楚?说清楚了就完了,指了路就好了嘛。

看了这么多,中心的意思就是现在pc的浮点算法很可怜,他是个马虎的天才,知道别人不知道的数,十进制小数点好多位后的数都知道,可是连最基本的小学生都会算的算术也会算错。

那我想知道,这个问题怎么解决?如何在pc上做起码的小学生的算术,比如任意一道四则运算题,要求精确到小数点后面5位?不要告诉我没有办法,这是过程的缺陷。
缺陷
re: 浮点数 和 EPSILON (文章越写越啰嗦)
“但如果你不需要无限精度,而又要判断是否相等,那么你应该先计算出(10.0+135.3)/10-14.53浮点数运算的结果,假设为 RESULT,然后写成if( (10.0+135.3)/10-14.53 == RESULT )。 
浮点数和实数计算是有差别的,差别不是一个范围。”

我先计算出 (10.0+135.3)/10 为14.53, 然后我有
double      d = 10.0; 
d += 135.3; 
d /= 10; 
然后我写成 if (d == 14.53) 这样来比较,我的理解对吗?

缺陷
re: 浮点数 和 EPSILON (文章越写越啰嗦)
谁能告诉我下面这段话的意思?
“The float type is usually not precise enough for real programsfloat is guaranteed to offer only 6 significant digits. The double type guarantees at least 10 significant digits, which is sufficient for most calculations.” C++ Prime 4nd. 2.1.2

最后,我太累了,要休息了。我的机器上计算1f/3f的结果很遗憾是0.333333,和上文中说的6个significant digits倒很一致。

今天实在有意思,我都搞起研究来了,是不是真的老了:)
希望这是个了结了
Ricepig
“说浮点数运行结果是精确的 不等于说 浮点数运行结果和实数运算结果相等。比如 1.0f / 3.0f 在任何时候任何机器上(程序员有意的要求编译器精度换时间的除外)其结果都应该是 0.3333333432674407958984375,这就是浮点运算,结果绝不可能偏差一丝一毫,既然丝毫不差,那就不应该使用EPSILON。”

这句话说的不正确,因为毕竟浮点计算并不像理论计算,它是一个近似。虽然每次1.0f/3.0f计算的结果都是一个确定的数,但是无法保证1.0f/3.0f/3.0f*3.0f和上述结果是一模一样的。机上,浮点运算从实际上都不满足交换律、结合律。这种情况下才需要epsilon。

供您参考。
一个有志气的中国人
这就是中国人。就一个没意义的问题争论半天。呵呵哒。

发表评论
切换编辑模式