假设我有一个返回double
的方法,但我想确定要返回的值的点后的精度。我不知道double
可变的价值。
示例:
double i = 3.365737;
return i;
我希望返回值在点
之后精确为3含义:返回值为3.365
。
另一个例子:
double i = 4644.322345;
return i;
我希望返回值为:4644.322
答案 0 :(得分:6)
您想要的是在某个数字后截断十进制数字。您可以使用floor
中的<math.h>
函数轻松执行此操作(如果您使用的是C ++,则可以std::floor
来自<cmath>
):
double TruncateNumber(double In, unsigned int Digits)
{
double f=pow(10, Digits);
return ((int)(In*f))/f;
}
尽管如此,我认为在某些情况下,由于浮点内部的工作原理,你可能会得到一些奇怪的结果(最后一个数字是一个开/关)。
另一方面,大部分时间你只是按原样传递double
并仅在流上输出时截断它,这是通过右流标记自动完成的。
答案 1 :(得分:2)
您需要注意边缘情况。完全基于pow
和强制转换或fmod
的任何实施都会偶尔产生错误的结果,尤其是基于pow(- PRECISION)
的实施。
最安全的做法是实现C和C ++都不提供的东西:定点运算能力。缺乏这一点,您需要找到相关边界情况的表示。这个问题类似于Excel如何舍入的问题。在那里调整我的答案How does Excel successfully Rounds Floating numbers even though they are imprecise?,
// 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;
}
答案 2 :(得分:1)
你无法从双精度中“移除”精度。你可以:4644.322000。这是一个不同的数字,但精度是相同的。
正如@David Heffernan所说,当你把它转换成一个字符串进行显示时就这么做。
答案 3 :(得分:0)
您想要将您的双倍截断到n
小数位,然后您可以使用此功能:
#import <cmath>
double truncate_to_places(double d, int n) {
return d - fmod(d, pow(10.0, -n));
}
答案 4 :(得分:0)
您可以使用fmod
函数在所需的精度之后找到数字,然后减去删除它们,而不是像其他答案那样乘以和除以10的幂。
#include <math.h>
#define PRECISION 0.001
double truncate(double x) {
x -= fmod(x,PRECISION);
return x;
}
答案 5 :(得分:0)
使用普通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
意味着舍入到所需的位数,这可能是你真正想要的。如果您实际上是指 truncate ,则可以使用其他答案给出的截断函数之一修改operator<<
。
答案 6 :(得分:0)
以同样的方式在显示之前格式化日期,你应该用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