uva1639(数学期望,利用对数减少浮点类型数据的精度损失方法)

/*
translation:
	两个盒子各有n个糖果,每天随机选一个盒子(概率为p,1-p)并且吃掉里面的一颗糖果。
	知道有一天打开盒子时发现是空的,求此时另外一个盒子里面糖果的个数的数学期望?

solution:
	数学期望,利用对数减少浮点类型数据的精度损失方法。
	假设另外第二个个盒子里面剩下了i颗,则概率为C(2n-i,n)*p^n*(1-p)^(n-i)
	同理,如果是地一个盒子里面剩下了i,则概率为C(2n-i,n)*(1-p)^n*p^(n-i)
	如此利用定理就能够算出答案了。
	但是计算的时候有一个问题,那就是p的那么多阶的次方造成的后果就是会损失很多的精度,所以可以
	利用对数的性质来将乘法操作转变为加法操作。即可减少精度的损失。

note:
	1:当浮点数据类型接近0的时候,乘法操作很可能导致精度损失,利用对数的性质将乘法操作转换为加法操作即可
	减少精度的损失!

date:2016.10.8
*/
#include <iostream>
#include <cstdio>
#include <cmath>

using namespace std;
const int maxn = 200000 + 5;

typedef long double ld;

ld logFac[maxn*2];	//logFac[i]表示i!(自然数e为底)
int n;	double p;

void initTable() {
	logFac[0] = 0;
	for(int i = 1; i <= maxn; i++) logFac[i] = logFac[i-1] + log(i);
}

ld countC(int a, int b) {
	return (ld)(logFac[a] - logFac[b] - logFac[a-b]);
}

int main() {
	//freopen("in.txt", "r", stdin);
	initTable();	//计算n!对数的值

	int kase = 0;
	while(~scanf("%d%lf", &n, &p)) {
		ld ans = 0.0;

		for(int i = 0; i <= n; i++) {	//剩余i个棋子
			ld c = countC(2*n - i, n);
			ld v1 = c + (n+1)*log(p) + (n-i)*log(1-p);
			ld v2 = c + (n+1)*log(1-p) + (n-i)*log(p);

			ans += (ld)i * (exp(v1) + exp(v2));
		}

		printf("Case %d: %.6llf\n", ++kase, ans);
	}
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值