我试图在C++中表示一组简单的3个概率。例如:在C++中表示概率
a = 0.1
b = 0.2
c = 0.7
(据我所知概率加起来必须等于1)
我的问题是,当我试图代表用C 0.7 ++为float我结束了0.69999999,从而赢得当我稍后做我的计算时没有帮助。 0.8,0.80000001一样。
在C++中有更好的表示0.0到1.0之间数字的方法吗?
请记住,这涉及如何将数字存储在内存中,以便在对数值进行测试时他们是正确的,我不关心它们如何显示/打印出来。
我试图在C++中表示一组简单的3个概率。例如:在C++中表示概率
a = 0.1
b = 0.2
c = 0.7
(据我所知概率加起来必须等于1)
我的问题是,当我试图代表用C 0.7 ++为float我结束了0.69999999,从而赢得当我稍后做我的计算时没有帮助。 0.8,0.80000001一样。
在C++中有更好的表示0.0到1.0之间数字的方法吗?
请记住,这涉及如何将数字存储在内存中,以便在对数值进行测试时他们是正确的,我不关心它们如何显示/打印出来。
你需要多少精度?您可能会考虑缩放值并以定点表示方式量化它们。
这与C++无关,所有与浮点数如何在内存中表示有关。你永远不应该使用等于运算符来比较浮点值,在这里看到更好的方法:http://www.cygnus-software.com/papers/comparingfloats/comparingfloats.htm
他没有问C++的方法而言,他并没有要求相关比较浮点值什么。 – 2009-11-20 19:43:24
是的,他做到了。 “......所以当涉及到对这些值进行测试时,他们是正确的”。我将其解释为:将这些值与其他值进行比较。 – lyricat 2009-11-20 19:51:18
有许多方法可以“测试”不涉及使用相等运算符的浮点“值”。无论如何,这不是他的问题。 – 2009-11-20 20:23:30
我的问题是,当我尝试 在C表示0.7 ++为float我最终 了0.69999999,这当我稍后进行我的计算时,将不会帮助 。 同样为0.8,0.80000001。
这是真的吗?如果您只需要更高的精度,请使用double而不是float。这应该会让你获得15位数字的精度,对于大多数工作来说绰绰有余。
考虑你的源数据。 0.7真的比0.69999999更正确吗?
如果是这样,你可以使用一个合理的数字图书馆,例如:如果问题是,概率的定义加起来1
http://www.boost.org/doc/libs/1_40_0/libs/rational/index.html
,然后将它们存储为数字集合,省略最后一个。通过从1中减去其他值的总和来推断最后一个值。
将float精度从float更改为double并不能解决问题,只是推迟它。 – hirschhornsalz 2009-11-20 19:15:54
有很多应用程序的浮点数不够精确,但双重就足够了。 – 2009-11-20 19:48:35
我喜欢上一个值为“1 - sum(所有其他值)” – 2009-11-20 21:03:04
如果您只需要几位数的精度,那么只需使用一个整数。如果您需要更高的精度,那么您将不得不寻找能够提供精度保证的不同库。
二进制机器总是将十进制小数(除了.0和.5,.25,.75等)舍入为在浮点中没有精确表示的值。这与语言C++无关。除了从代码中的数字角度处理它外,没有真正的解决方法。
至于实际制作你所寻求的概率:
float pr[3] = {0.1, 0.2, 0.7};
float accPr[3];
float prev = 0.0;
int i = 0;
for (i = 0; i < 3; i++) {
accPr[i] = prev + pr[i];
prev = accPr[i];
}
float frand = rand()/(1 + RAND_MAX);
for (i = 0; i < 2; i++) {
if (frand < accPr[i]) break;
}
return i;
“的意思,除了.0和.5”可能是误导或错误的,这取决于您想如何看待它。 – 2009-11-20 19:28:28
你是对的,我应该说分母的分母是2的幂。 – 2009-11-20 23:38:26
如果你确实需要的精确度,并与有理数坚持,我想你可以用一个固定的点arithemtic去。我以前没有这样做过,所以我不推荐任何库。
或者,你可以比较FP数字时设置的阈值,但是你必须宁可一侧或另一侧 - 说
bool fp_cmp(float a, float b) {
return (a < b + epsilon);
}
注意,过量的精度在每个计算自动截断,因此在算法中以多种不同的数量级进行操作时,应该小心。一个人为的例子来说明:
a = 15434355e10 + 22543634e10
b = a/1e20 + 1.1534634
c = b * 1e20
与
c = b + 1.1534634e20
两个效果会非常不同。使用第一种方法,前两个数字的许多精度将会在除以1e20时丢失。假设你想要的最终数值是1e20的数量级,第二种方法会给你更高的精度。
你想用你的号码做的测试将是不正确的。
对于像0.1这样的数字,在基数为2的数字系统中没有精确的浮点表示,因为它是一个infinite周期数。考虑三分之一,在base-3系统中可以精确表示为0.1,但在base-10系统中则为0.333 ...。
所以,你用浮点数0.1做的任何测试都容易出现缺陷。
中的溶液。将使用有理数(升压有其合理IIb)的,这将是始终确切为,ermm,有理数,或由数字与10的幂乘以使用自制基-10系统。
是的,如果你担心这样的事情,我会扩大数字(0-100)(0-1000)或任何你需要的固定大小。它也使得在大多数情况下更快的数学计算。回到古老的时代,我们会定义整个cos/sine表和其他整数形式的bleh,以减少浮动模糊并提高计算速度。
我的确发现有点“有趣”,就像存储上的“0.7”模糊不清。
7/10模糊类似base-2的表示,就像1/3或1/7模糊的base-10表示。没有什么不奇怪的。 – 2009-11-20 19:27:53
真的很糟糕的答案。这应该是你的“最佳答案” – 2009-11-21 02:48:28
*适用时*这是一个完全合理的答案,应该不是唯一的选择,而是作为一个可能有效的答案,因此downvotes是没有根据的。 @Roberto:关键是0.7可以被存储为700,因为知道1的概率是由1000表示的 - 精确的7/10的浮点可表示性是不相关的。 – 2011-05-25 03:32:25
我很抱歉地说你的问题并不是一个简单的答案。
它属于一个名为"Numerical Analysis"的研究领域,它处理这些类型的问题(远远不只是确保您不检查两个浮点值之间的相等性)。而通过研究领域,我的意思是有大量的书籍,期刊文章,课程等处理它。有些人在做博士论文。
我只能说我很感谢我不必非常处理这些问题,因为问题和解决方案往往非常不直观。
你可能需要做些什么来处理表示你正在处理的数字和计算,这取决于你正在做什么操作,这些操作的顺序以及你期望处理的值的范围在那些行动中。
的这里的问题是,浮点数被存储在基地2.基地2
不能完全代表以10为基数的十进制与浮点数让我们退一步第二。 .1是什么意思?还是.7?它们的意思是1x10 -1和7x10 -1。如果您使用binary作为您的电话号码,而不是像我们通常所做的那样使用基数10,则.1表示1x2 -1或1/2。 .11表示1×2 -1 + 1×2 -2或1/2 + 1/4或3/4。
请注意,在这个系统中,分母总是2的幂。如果没有分母,那么在有限数目的数字中是2的幂。例如,.1(十进制)意味着1/10,但是在二进制中,它是一个无限重复分数,0.000110011 ...(0011模式永远重复)。这与基数10中的相似,1/3是无限分数,0.3333 ....;基数10只能用一个分母来表示数字,它是2和5的倍数的分母。(顺便说一下,基数12和基数60实际上是非常方便的基数,因为12可以被2,3和4整除,并且60可以被2,3,4和5整除;但由于某种原因,我们使用十进制无论如何,我们在计算机中使用二进制)。由于浮点数(或定点数)总是有限数字的数字,所以它们不能准确地表示这些无限重复的分数。因此,它们要么将值缩短或舍入为尽可能接近实际值,但不完全等于实际值。一旦你开始添加这些四舍五入的值,你开始得到更多的错误。在十进制中,如果您的1/3表示为.333,那么三个副本将加起来为.999,而不是1.
有四种可能的解决方案。如果你所关心的只是像.1和.7这样的小数部分(如你所说的,你不关心1/3会遇到同样的问题),那么你可以用十进制表示你的数字,例如使用binary coded decimal,并操纵这些。这是金融领域的常见解决方案,许多操作都是用小数定义的。这有一个缺点,你需要自己实现所有的算术运算,而没有计算机的FPU的好处,或者找到一个decimal arithmetic library。如前所述,这也不能帮助那些不能完全用小数表示的分数。
另一种解决方案是使用分数来表示您的数字。如果你使用分数和分数(任意大数)作为分子和分母,你可以表示任何适合你计算机内存的理性数。同样,缺点是算术运算速度会变慢,您需要自己实现算术运算或use an existing library。这将解决所有有理数的问题,但是如果用基于π或√2计算的概率结束,则仍然存在相同的问题,因为无法准确表示它们,并且还需要使用一个以后的解决方案。
第三个解决方案,如果所有你关心的是让你的号码加起来正好1,是,你必须ñ可能性,只存储ň这些概率的-1值的事件,并计算最后的概率为1减去其余概率的总和。
第四种解决方案是在处理浮点数(或任何不精确的数字,例如用于表示无理数的分数)时始终需要记住的事项,并且从不比较两个数的相等性。再次在基数10中,如果您合计三份1/3,您将以.999结尾。当你想把这个数字与1进行比较时,你必须进行比较,看它是否接近1;检查差值的绝对值1-.999是否小于阈值,如.01。
根据您的应用需求了几种解决方案中的任何一个可能是最好的:
你住与先天就缺乏精度和使用浮点或双精度的。你不能测试是否相等,这意味着你不能测试你的概率与1.0相等的总和。
如前所述,如果您需要固定精度,则可以使用整数。您将0.7表示为7,0.1表示为1,0.2表示为2,它们将完全加起来为10,即1.0。如果必须用概率进行计算,特别是在进行除法和乘法运算时,则需要正确地舍入结果。这将再次引入不准确。
将您的数字表示为具有一对整数(1,2)= 1/2 = 0.5的分数。精确,比2更灵活),但你不想用这些计算。
您可以一路走下来,并使用实现有理数的库(例如gmp)。精确的,任意的精度,你可以用它来计算,但速度很慢。
强制性链接:http://docs.sun.com/source/806-3568/ncg_goldberg.html – robince 2009-11-20 19:23:29