假设我有一个返回double
的方法,但是我想确定要返回的值的点之后的精度。我不知道double
变量的值
的例子:
double i = 3.365737;
return i;
我希望返回值的精度为点
后面的3个数字含义:返回值为3.365
。
另一个例子:
double i = 4644.322345;
return i;
我希望返回值为:4644.322
您想要的是在某个数字之后截断十进制数字。您可以轻松地使用<math.h>
中的floor
函数(如果使用c++,则可以使用<cmath>
中的std::floor
):
double TruncateNumber(double In, unsigned int Digits)
{
double f=pow(10, Digits);
return ((int)(In*f))/f;
}
不过,我认为在某些情况下,由于浮点内部的工作方式,您可能会得到一些奇怪的结果(最后一位数是1/1)。
另一方面,大多数情况下,您只是按原样传递double
,并仅在将其输出到流时截断它,这是使用正确的流标志自动完成的。
您需要注意边界情况。任何仅基于pow
和强制转换或fmod
的实现都会偶尔给出错误的结果,特别是基于pow(- PRECISION)
的实现。
最安全的方法是实现C和c++都没有提供的功能:定点算术功能。如果没有,您将需要找到相关边界情况的表示。这个问题类似于Excel如何四舍五入的问题。适应我的答案在那里,Excel如何成功round浮点数,即使他们是不精确的?对于这个问题,
// Compute 10 to some positive integral power.
// Dealing with overflow (exponent > 308) is an exercise left to the reader.
double pow10 (unsigned int exponent) {
double result = 1.0;
double base = 10.0;
while (exponent > 0) {
if ((exponent & 1) != 0) result *= base;
exponent >>= 1;
base *= base;
}
return result;
}
// Truncate number to some precision.
// Dealing with nonsense such as nplaces=400 is an exercise left to the reader.
double truncate (double x, int nplaces) {
bool is_neg = false;
// Things will be easier if we only have to deal with positive numbers.
if (x < 0.0) {
is_neg = true;
x = -x;
}
// Construct the supposedly truncated value (round down) and the nearest
// truncated value above it.
double round_down, round_up;
if (nplaces < 0) {
double scale = pow10 (-nplaces);
round_down = std::floor (x / scale);
round_up = (round_down + 1.0) * scale;
round_down *= scale;
}
else {
double scale = pow10 (nplaces);
round_down = std::floor (x * scale);
round_up = (round_down + 1.0) / scale;
round_down /= scale;
}
// Usually the round_down value is the desired value.
// On rare occasions it is the rounded-up value that is.
// This is one of those cases where you do want to compare doubles by ==.
if (x != round_up) x = round_down;
// Correct the sign if needed.
if (is_neg) x = -x;
return x;
}
不能从双精度类型中"移除"精度。可以是:4644.322000。这是一个不同的数字,但精度是相同的。
就像@David Heffernan说的,当你把它转换成一个字符串来显示时要这样做
如果你想截断你的双精度值到小数点后n
位,那么你可以使用这个函数:
#import <cmath>
double truncate_to_places(double d, int n) {
return d - fmod(d, pow(10.0, -n));
}
您可以使用fmod
函数来找到您想要的精度之后的数字,然后减去它们,而不是像其他答案那样乘以和除以10的幂。
#include <math.h>
#define PRECISION 0.001
double truncate(double x) {
x -= fmod(x,PRECISION);
return x;
}
对于普通的double
s没有很好的方法,但是您可以编写class
或简单的struct
,如
struct lim_prec_float {
float value;
int precision;
};
然后有你的功能
lim_prec_float testfn() {
double i = 3.365737;
return lim_prec_float{i, 4};
}
(4 = 1前点+ 3后点。这使用了c++ 11的初始化列表,如果lim_prec_float
是具有适当构造函数的class
就更好了。
当您现在想要输出变量时,使用自定义
来执行此操作std::ostream &operator<<(std::ostream &tgt, const lim_prec_float &v) {
std::stringstream s;
s << std::setprecision(v.precision) << v.value;
return (tgt << s.str());
}
现在你可以,例如,
int main() {
std::cout << testfn() << std::endl
<< lim_prec_float{4644.322345, 7} << std::endl;
return 0;
}
将输出
3.366
4644.322
这是因为std::setprecision
意味着将四舍五入到所需的位置数,这可能是您真正想要的。如果您的意思是截断,则可以使用其他答案给出的截断函数之一修改operator<<
。
与在显示日期之前格式化日期的方法相同,您应该对double进行相同的操作。
但是,我使用了以下两种四舍五入的方法:
double roundTo3Places(double d) {
return round(d * 1000) / 1000.0;
}
double roundTo3Places(double d) {
return (long long) (d * 1000 + (d > 0 ? 0.5 : -0.5)) / 1000.0;
}
后者更快,但是数字不能大于9e15