返回精度为double的值



假设我有一个返回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

相关内容

最新更新