一些有用的双精度小数函数
四舍五入、小数位数等。
引言
我经常使用 math.h 中的函数。但是,缺少一些函数,所以我自己编写了一些。它们是处理小数位的简单函数。没有什么特别的。但有时它们会很有用。
使用代码
这些函数简单明了,不言自明。这些函数依赖于 math.h(仅依赖 math.h)。
#include "math.h"
Round()
将双精度浮点数四舍五入到指定的位数。它与 Excel 的 Round 函数非常相似。
// rounds a double variable to nPlaces decimal places
double Round(double dbVal, int nPlaces /* = 0 */)
{
const double dbShift = pow(10.0, nPlaces);
return floor(dbVal * dbShift + 0.5) / dbShift;
}
GetDecimalPlaces()
计算并返回 double
的小数位数(请参阅注释 1)。
// get the number of decimal places
int GetDecimalPlaces(double dbVal)
{
static const int MAX_DP = 10;
static const double THRES = pow(0.1, MAX_DP);
if (dbVal == 0.0)
return 0;
int nDecimal = 0;
while (dbVal - floor(dbVal) > THRES && nDecimal < MAX_DP)
{
dbVal *= 10.0;
nDecimal++;
}
return nDecimal;
}
GetFmtStr()
创建一个 printf()
样式的格式字符串。
// get the number format string
const char* GetFmtStr(char* szFmt, int nDecimal)
{
sprintf(szFmt, "%%.%dlf", nDecimal);
return szFmt;
}
最后,RoundUD()
将双精度浮点数四舍五入或向下舍入到 dbUnit
步长的最接近值。
// round up/down to certain units
double RoundUD(bool bRoundUp, double dbUnit, double dbVal)
{
static const int ROUND_DP = 10;
double dbValInUnit = dbVal / dbUnit;
dbValInUnit = Round(dbValInUnit, ROUND_DP);
if (bRoundUp) // round up
dbValInUnit = ceil(dbValInUnit);
else // round down
dbValInUnit = floor(dbValInUnit);
return (dbValInUnit * dbUnit);
}
您可以使用以下代码测试上述函数
printf("rounding %lf d.p.=%d is %lf\n", 10.0, 1, Round(10.0, 1));
printf("rounding %lf d.p.=%d is %lf\n", 0.0, 0, Round(0.0, 1));
printf("rounding %lf d.p.=%d is %lf\n", 0.1, 1, Round(0.1, 1));
printf("rounding %lf d.p.=%d is %lf\n", 0.01, 1, Round(0.01, 1));
printf("rounding %lf d.p.=%d is %lf\n", 0.0123456, 0, Round(0.0123456, 0));
printf("rounding %lf d.p.=%d is %lf\n", 0.0123456, 1, Round(0.0123456, 1));
printf("rounding %lf d.p.=%d is %lf\n", 0.0123456, 2, Round(0.0123456, 2));
printf("rounding %lf d.p.=%d is %lf\n", 0.0123456, 6, Round(0.0123456, 6));
printf("rounding %lf d.p.=%d is %lf\n", -0.0123456, 6, Round(-0.0123456, 6));
printf("rounding %lf up unit=%lf is %lf\n", 0.0, 0.05, RoundUD(true, 0.05, 0.0));
printf("rounding %lf down unit=%lf is %lf\n", 0.0, 0.05, RoundUD(false, 0.05, 0.0));
printf("rounding %lf up unit=%lf is %lf\n", 0.01, 0.05, RoundUD(true, 0.05, 0.01));
printf("rounding %lf down unit=%lf is %lf\n", 0.01, 0.05, RoundUD(false, 0.05, 0.01));
printf("rounding %lf up unit=%lf is %lf\n", -0.01, 0.05, RoundUD(true, 0.05, -0.01));
printf("rounding %lf down unit=%lf is %lf\n", -0.01, 0.05, RoundUD(false, 0.05, -0.01));
printf("%lf has %d d.p.\n", 0.0, GetDecimalPlaces(0.0));
printf("%lf has %d d.p.\n", 10.0, GetDecimalPlaces(10.0));
printf("%lf has %d d.p.\n", -10.0, GetDecimalPlaces(-10.0));
printf("%lf has %d d.p.\n", 10.123, GetDecimalPlaces(10.123));
printf("%lf has %d d.p.\n", -10.123, GetDecimalPlaces(-10.123));
printf("%lf has %d d.p.\n", 10.01, GetDecimalPlaces(10.01));
printf("%lf has %d d.p.\n", -10.01, GetDecimalPlaces(-10.01));
char szFmt[32];
printf(GetFmtStr(szFmt, GetDecimalPlaces(0.0)), 0.0); printf("\n");
printf(GetFmtStr(szFmt, GetDecimalPlaces(10.0)), 10.0); printf("\n");
printf(GetFmtStr(szFmt, GetDecimalPlaces(10.010)), 10.010); printf("\n");
printf(GetFmtStr(szFmt, GetDecimalPlaces(-0.0345)), -0.0345); printf("\n");
输出将是这样的
rounding 10.000000 d.p.=1 is 10.000000
rounding 0.000000 d.p.=0 is 0.000000
rounding 0.100000 d.p.=1 is 0.100000
rounding 0.010000 d.p.=1 is 0.000000
rounding 0.012346 d.p.=0 is 0.000000
rounding 0.012346 d.p.=1 is 0.000000
rounding 0.012346 d.p.=2 is 0.010000
rounding 0.012346 d.p.=6 is 0.012346
rounding -0.012346 d.p.=6 is -0.012346
rounding 0.000000 up unit=0.050000 is 0.000000
rounding 0.000000 down unit=0.050000 is 0.000000
rounding 0.010000 up unit=0.050000 is 0.050000
rounding 0.010000 down unit=0.050000 is 0.000000
rounding -0.010000 up unit=0.050000 is 0.000000
rounding -0.010000 down unit=0.050000 is -0.050000
0.000000 has 0 d.p.
10.000000 has 0 d.p.
-10.000000 has 0 d.p.
10.123000 has 3 d.p.
-10.123000 has 3 d.p.
10.010000 has 2 d.p.
-10.010000 has 2 d.p.
0
10
10.01
-0.0345
关注点
- 注释 1:
GetDecimalPlaces()
有一些需要解释的地方。在一个循环中,double
乘以 10,然后与它的向下取整值(截断值)进行比较。如果它们相同,则意味着我们已经耗尽了小数位。由于double
的内部表示不精确,因此double
之间的比较很棘手。因此,比较必须允许一定的误差范围。误差范围由THRES
指定,其设置为 1-10。
历史
- 首次版本:2008 年 2 月 20 日。