RoundTo: 使用 “四舍六入五成双” 的 Banker's Rounding 规则截取浮点数
函数原型:
typedef Int8 TRoundToEXRangeExtended;
Extended __fastcall RoundTo(const Extended AValue, const TRoundToEXRangeExtended ADigit);
头文件:
#include <System.Math.hpp>
命名空间:
System::Math
参数:
AValue:需要截取的浮点数,long double 类型的长浮点数。
ADigit:截取的位数,8 位整数,范围:-20 ~ 20
返回值:
ADigit = 0:返回值为取整的值,
ADigit < 0:返回值为小数点后保留 ADigit 位
ADigit > 0:返回值为取整并且整数部分低 ADigit 位清零
运算 |
值 |
说明 |
RoundTo(1234567.89 , 3) |
1235000 |
取整并且整数部分低 3 位清零,清掉的 567.89 偏向进位方向,进位 |
RoundTo( 2.4999, 0) |
2 |
取整,清掉的 4999 偏向于舍弃方向,舍弃 |
RoundTo( 2.5 , 0) |
2 |
取整,清掉的 5 在中间位置,取偶数方向,舍弃 |
RoundTo( 2.5001, 0) |
3 |
取整,清掉的 5001 偏向于进位方向,进位 |
RoundTo( 1.234 , -2) |
1.23 |
小数部分保留 2 位,清掉的 4 偏向于舍弃方向,舍弃 |
RoundTo( 1.235 , -2) |
1.24 |
小数部分保留 2 位,清掉的 5 在中间位置,取偶数方向,进位 |
RoundTo( 1.625 , -2) |
1.62 |
小数部分保留 2 位,清掉的 5 在中间位置,取偶数方向,舍弃 |
RoundTo( 1.245 , -2) |
1.25 |
由于浮点数 1.245 无法用二进制数据精确的表示出来,在电脑里面的二进制数据实际上是用 1.24500000000000011 来表示 1.245 的,清掉的 500000000000011 偏向于进位方向,进位 |
RoundTo 函数使用 “四舍六入五成双” 的 Banker's Rounding 规则 (五后有数入、五后无数凑偶数),和传统的 “四舍五入” 的区别为:
根据上面的图形可以看到:传统的 “四舍五入” 会让数量非常大的数据计算之后偏大,因为两端距离相等的时候始终选择绝对值大的,而 “四舍六入五成双” 的 Banker's Rounding 规则会让数据两端取舍的概率均等,因为对于不同的数值,偶数可能在左边,也可能在右边,计算之后的数据不会明显偏大或偏小,所以与 std::round 相比,更推荐使用 System::Math::RoundTo 函数。看下面的例子对取舍规则会有更详细的了解。
例子:
void __fastcall TForm1::Button1Click(TObject *Sender)
{
const wchar_t fmt[] = L"%6.2f %6.2f %6.2f %6.2f %6.2f %6.2llf\r\n";
UnicodeString s = L" value trunc floor ceil round RoundTo\r\n";
s.cat_sprintf(fmt, 5.4 , trunc( 5.4 ), floor( 5.4 ), ceil( 5.4 ), round( 5.4 ), RoundTo( 5.4 ,0));
s.cat_sprintf(fmt, 5.5 , trunc( 5.5 ), floor( 5.5 ), ceil( 5.5 ), round( 5.5 ), RoundTo( 5.5 ,0));
s.cat_sprintf(fmt, 6.5 , trunc( 6.5 ), floor( 6.5 ), ceil( 6.5 ), round( 6.5 ), RoundTo( 6.5 ,0));
s.cat_sprintf(fmt, 6.51, trunc( 6.51), floor( 6.51), ceil( 6.51), round( 6.51), RoundTo( 6.51,0));
s.cat_sprintf(fmt, 6.8 , trunc( 6.8 ), floor( 6.8 ), ceil( 6.8 ), round( 6.8 ), RoundTo( 6.8 ,0));
s.cat_sprintf(fmt, -5.4 , trunc(-5.4 ), floor(-5.4 ), ceil(-5.4 ), round(-5.4 ), RoundTo(-5.4 ,0));
s.cat_sprintf(fmt, -5.5 , trunc(-5.5 ), floor(-5.5 ), ceil(-5.5 ), round(-5.5 ), RoundTo(-5.5 ,0));
s.cat_sprintf(fmt, -6.5 , trunc(-6.5 ), floor(-6.5 ), ceil(-6.5 ), round(-6.5 ), RoundTo(-6.5 ,0));
s.cat_sprintf(fmt, -6.51, trunc(-6.51), floor(-6.51), ceil(-6.51), round(-6.51), RoundTo(-6.51,0));
s.cat_sprintf(fmt, -6.8 , trunc(-6.8 ), floor(-6.8 ), ceil(-6.8 ), round(-6.8 ), RoundTo(-6.8 ,0));
Memo1->Lines->Text = s;
} |
相关链接:
• ceil • floor • trunc • round • _matherr • 浮点数异常处理
|