繁体   English   中英

精确返回双精度

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM