2019年1月29日训练日记

今天要写的就一个问题:
四舍五入与四舍六入五成双的问题:
首先介绍可能涉及的一些取整问题
ceil:在英文中,是天花板的意思,有向上的意思,所以,此函数是向上取整。
floor:在英文中,是地面,地板的意思,有下面的意思,所以,此函数是向下取整。
round:在英文中是有大约,环绕,在某某四周,附近的意思,所以,可以取其大约的意思,在函数中是四舍五入。
接下来步入正题:

四舍六入五成双的规则:

  1. 被修约的数字小于5时,该数字舍去;
  2. 被修约的数字大于5时,则进位;
  3. 被修约的数字等于5时,要看5前面的数字,若是奇数则进位,若是偶数则将5舍掉,即修约后末尾数字都成为偶数;若5的后面还有不为“0”的任何数,则此时无论5的前面是奇数还是偶数,均应进位。
    举例,用上述规则对下列数据保留2位小数:
    9.8249=9.82, 9.82671=9.83
    9.8350=9.84, 9.8351 =9.84
    9.8250=9.82, 9.82501=9.83

四舍六入五成双的科学性:

为了不产生系统性的偏差,当小数部分均匀分布时,我们希望“舍”和“入”产生的误差的期望的绝对值相等。
于是就取了0.5作分界点,00.5的小数部分舍去,0.51的小数部分入上,舍入产生的误差的期望的绝对值都是1/4。
如果我们考虑的是连续的均匀分布,那么小数部分正好等于0.5的概率为0,是舍是入都没有关系,为了简便,就“五入”了。
(为什么不是“五舍六入”?这样的话,舍入产生的误差的期望的绝对值分别为0.3和0.2,会产生系统偏差)
但是,实际中测量得到的数据有精度限制,所以测量结果不是连续的均匀分布,而是离散的均匀分布。
不妨设测量结果有两位小数,则小数部分服从0.00, 0.01, …, 0.99的离散均匀分布。
0.00不产生误差;0.01舍去会产生-0.01的误差,0.99入上会产生+0.01的误差,二者抵消;……;0.49舍去会产生-0.49的误差,0.51入上会产生+0.49的误差,二者抵消;但剩下的0.50若一律入上,则会产生+0.50的误差,且没有什么能与之抵消。
为了解决这个问题,就引入了“五取偶”的规则:当小数部分恰为0.5时,若个位是奇数则入,若个位是偶数则舍,总之让个位变成偶数。若个位为奇和为偶的概率也相等,则0.5产生正负误差的概率也相等,可以抵消。
(注意:只有当小数部分恰为0.5时才取偶,小数部分为0.51时是一律入上的)
如果是四舍五入
01234都变成了0,处理之后的数变小了这么多:(0+1+2+3+4)/10=1
56789都变成了10,处理之后的数变大了这么多:(5+4+3+2+1)/10=1.5
1.5-1=0.5
所以经过处理会让整个期望变大。
为了保证让处理之后的期望不变,就要让5有1/2的概率变大1/2的概率变小。
假设前面那位的数值也是随机出现的,再人为规定一下就有了4舍6入5取偶。

先写一个有关四舍五入问题的:

2135 价钱统计
夏天到了,超市里摆满了各种各样的应季水果。现在知道:西瓜的价钱是每斤 1.2 元;桃子的价格是每斤 3.5 元;葡萄的价格是每斤 4.5 元;苹果的价钱是每斤 5 元。现在分别给出上述四种所购买的斤数(均不超过 20),请你编写程序帮助售货员阿姨计算并依次输出顾客购买四种水果需要的钱数及总钱数。
输入
输入只有一行,包含四个符合题目要求的非负实数,依次表示需要购买西瓜、桃子、葡萄和苹果的斤数。两两之间用一个空格分隔。

输入的实数至多有1位小数,(也就是,一定是0.1斤的整数倍)
输出
输出应有五行,每行包含一个数,依次代表购买西瓜、桃子、葡萄、苹果所需的钱数,以及购买四种水果所需的总钱数。

所有输出数据均采取四舍五入保留一位小数(若小数点后为 0,也应输出这一位 0)。

你需要考虑「四舍六入五留双」与四舍五入之间的差别。
输入样例

4 3 2.5 6

输出样例

4.8
10.5
11.3
30.0
56.6

代码如下:

#include <cmath>
#include <cstdio>
#include <vector>
#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
int main()
{
    double a,b,c,d,w,x,y,z,s1,s2,s3,s4,s5,s;
    cin>>a>>b>>c>>d;
    w=1.2*a;
    x=3.5*b;
    y=4.5*c;
    z=5*d;
    if(w*10-floor(w*10)>=0.5)
    {
        s1=floor(w*10);
        s1=(s1+1)/10.0;
        printf("%.1lf\n",s1);
    }
    else
    {
        s1=floor(w*10);
        s1=s1/10.0;
         printf("%.1lf\n",s1);
    }
    if(x*10-floor(x*10)>=0.5)
    {
        s2=floor(x*10);
        s2=(s2+1)/10.0;
         printf("%.1lf\n",s2);
    }
    else
    {
        s2=floor(x*10);
        s2=s2/10.0;
       printf("%.1lf\n",s2);
    }
    if(y*10-floor(y*10)>=0.5)
    {
        s3=floor(y*10);
        s3=(s3+1)/10.0;
        printf("%.1lf\n",s3);
    }
    else
    {
        s3=floor(y*10);
        s3=s3/10.0;
      printf("%.1lf\n",s3);
    }
    if(z*10-floor(z*10)>=0.5)
    {
        s4=floor(z*10);
        s4=(s4+1)/10.0;
        printf("%.1lf\n",s4);
    }
    else
    {
        s4=floor(z*10);
        s4=s4/10.0;
        printf("%.1lf\n",s4);
    }
    s5=w+x+y+z;
     if(s5*10-floor(s5*10)>=0.5)
    {
        s=floor(s5*10);
        s=(s+1)/10.0;
        printf("%.1lf\n",s);
    }
      else
    {
        s=floor(s5*10);
        s=s/10.0;
        printf("%.1lf\n",s);
    }
	return 0;
}

我写的很麻烦,但思路都是一种。这个问题还有一个陷阱,就是最后的s不可以写成s=s1+s2+s3+s4;要写成s=w+x+y+z;是总的零钱,不是所有零钱进行四舍五入后再进行计算。如果写成s=s1+s2+s3+s4;则如下数据出现问题:
输入:

0.5 0.5 0.5 0.5

输出:

0.6
1.8
2.3
2.5
7.2

但是正确的输出数据是:

0.6
1.8
2.3
2.5
7.1

有一个简化一些的代码

#include <iostream>
using namespace std;
int main()
{
    float x,y,z,t,s,a,b,c,d;
    cin>>x>>y>>z>>t;
    s=1.2*x+3.5*y+4.5*z+5*t;s=int(s*10+0.5)/10.0;
    x=int(12*x+0.5)/10.0;if(x==int(x))cout<<x<<".0"<<endl;
                         else cout<<x<<endl;
    y=int(35*y+0.5)/10.0;if(y==int(y))cout<<y<<".0"<<endl;
                         else cout<<y<<endl;
    z=int(45*z+0.5)/10.0;if(z==int(z))cout<<z<<".0"<<endl;
                         else cout<<z<<endl;
    t=int(50*t+0.5)/10.0;if(t==int(t))cout<<t<<".0"<<endl;
                         else cout<<t<<endl;
    if(s==int(s))cout<<s<<".0"<<endl;
    else cout<<s<<endl;
    return 0;
}

这种思路相对简单一些。

还有更简便的。。。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;


int main()
{
	float a,b,c,d,ans = 0;
	cin>>a>>b>>c>>d;
	ans = 1.2*a+3.5*b+4.5*c+5*d;
	printf("%.1f\n%.1f\n%.1f\n%.1f\n%.1f\n",1.2*a+0.01,3.5*b+0.01,4.5*c+0.01,5*d+0.01,ans+0.01);
	return 0;
} 

另外写一个关于四舍六入五成双的问题

2103 四舍六入五留双

输入一个实数f,和一个位数d
输出实数f,在保留d位小数下的结果,采用四舍六入五留双的近似。
f至多有30位小数。
0 <= f <= 1
1 <= d <= 8
所谓四舍六入五留双,是指如果恰好是0.5的情况,会把他近似到使得前一位是偶数。
比如近似到整数,0.4为0,0.5为0,0.50001为1,0.6为1,1.5为2,2.5为2。
输入
一行一个浮点数f和一个位数d。
输出
一行一个浮点数表示答案
输入样例

0.123456789 5

输出样例

0.12346

代码如下:

#include<iostream>
#include<cstdio>
#include<cmath>
#include<iomanip>
using namespace std;
int main()
{
   double f,a,b;
   int d,q;
   cin>>f>>d;
   a=f*pow(10,d);
   q=a;//利用数据类型不同可以取出小数
   b=a-q;
   if(b<0.5)
   cout<<fixed<<setprecision(d)<<f;//保留d位小数
   else if(b>0.5)
   {
       a=(a+0.1)/pow(10,d);
       cout<<fixed<<setprecision(d)<<a;
   }
   else
   {
       int x;
       x=q%10;
       if(x%2!=0)
       {
           a=(a+0.1)/pow(10,d);
           cout<<fixed<<setprecision(d)<<a;
       }
       else
       {
           cout<<fixed<<setprecision(d)<<f;
       }
   }
   return 0;
}

下面这个更加简便:

#include<iostream>
#include<stdio.h>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<string>
#include<vector>
#include<iomanip>
using namespace std;
int main()
{
    double f;
    int d;
    cin>>f>>d;
    cout<<fixed<<setprecision(d)<<f<<endl;
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值