[英]Returning double with precision
说我有一个返回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;
}
不过,我认为在某些情况下,由于浮点在内部的工作方式,您可能会得到一些奇怪的结果(最后一位数字是一个结束/结束)。
另一方面,大多数情况下,您只是按原样绕过double
,并且仅在将其输出到流时才截断double
,这是通过正确的stream标志自动完成的。
您将需要注意临界情况。 仅基于pow
和cast或fmod
任何实现有时都会给出错误的结果,尤其是基于pow(- PRECISION)
。
最安全的选择是实现C或C ++都无法提供的功能:定点算术功能。 缺少这一点,您将需要找到相关边界事件的表示。 此问题类似于有关Excel如何进行四舍五入的问题。 在那里调整我的答案: 即使Excel不精确 , Excel如何成功将其四舍五入? ,针对这个问题,
// 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
位截断到小数点后第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
意味着舍入到所需的位数,这很可能是您真正想要的。 如果您实际上是指truncate ,则可以使用其他答案给出的一种截断函数来修改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
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.