【问题标题】:Correct formatting of numbers with errors (C++)正确格式化有错误的数字 (C++)
【发布时间】:2009-06-05 22:07:07
【问题描述】:

我有三组数字,一个测量值(在 0-1 范围内),两个误差(正数和负数)。这些数字的显示应与有效数字的数量一致,四舍五入,对应于任一数字中的第一个非零条目。

如果是 1,则在测量中跳过此要求(即只需要考虑误差中的数字)。例如:

0.95637 (+0.00123, -0.02935) --> 0.96 +0.00 -0.03
1.00000 (+0.0, -0.0979) --> 1.0 +0.0 -0.1 (note had to truncate due to -ve error rounding up at first significant digit)

现在,通过 log10(num) 很容易获得第一个非零数字,但我有一个愚蠢的时刻,试图让剥离和舍入以一种干净的方式工作。

所有数据类型都是双精度类型,选择的语言是 C++。欢迎所有和任何想法!

【问题讨论】:

  • 您的实现是否存在不使用库调用的限制?
  • 还不是很清楚。 Ehy 第一行的有效位数是 2,第二行是 1?换句话说,为什么第一行+0.00123被格式化为+0.00,而第二行+0.0被格式化为+0.0?
  • 我不太明白 - 你说你想显示第一个非零数字,但你的例子显示 +0.00,而不是 +0.001。
  • 它表示任一数字中的第一个非零条目。对我来说似乎很奇怪,但他列出的规则与显示的数据一致。

标签: c++ formatting numbers rounding


【解决方案1】:

我的 C++ 生锈了,但下面的不会这样做:

std::string FormatNum(double measurement, double poserror, double negerror)
{
  int precision = 1;  // Precision to use if all numbers are zero

  if (poserror > 0)
    precision = ceil(-1 * log10(poserror));
  if (negerror < 0)
    precision = min(precision, ceil(-1 * log10(abs(negerror))));

  // If you meant the first non-zero in any of the 3 numbers, uncomment this:
  //if( measurement < 1 )
  //  precision = min(precision, ceil(-1 * log10(measurement)));

  stringstream ss;
  ss.setf(ios::fixed, ios::floatfield);
  ss.precision( precision );
  ss << measurement << " +" << poserror << " " << negerror ;
  return ss.str();
}

【讨论】:

    【解决方案2】:

    使用

    cout.setf(ios::fixed, ios::floatfield);
    cout.precision(2);
    

    在你输出数字之前,应该做你想要的。

    编辑:例如

    double a = 0.95637;
    double b = 0.00123;
    double c = -0.02935;
    
    cout.setf(ios::fixed, ios::floatfield);
    cout.precision(2);
    cout << a << endl;
    cout << b << endl;
    cout << c << endl;
    

    将输出:

    0.96
    0.00
    -0.03
    

    进一步编辑:您显然必须调整精度以匹配您的有效数字。

    【讨论】:

      【解决方案3】:

      可能是这样的:

      std::string FormatNum(double num)
      {
        int numToDisplay ((int)((num + 0.005) * 100.0));
        stringstream ss;
        int digitsToDisplay(abs(numToDisplay) % 100);
        ss << ((num > 0) ? '+' : '-') << (abs(numToDisplay) / 100) << '.' << (digitsToDisplay / 10) << (digitsToDisplay % 10);
        return ss.str();
      }
      
          stringstream ss;
          ss << FormatNum(0.95637) << ' ' << FormatNum(+0.00123) << ' ' << FormatNum(-0.02935);
      

      【讨论】:

      • 这个解决方案不仅没有回答完整的问题,而且还有一个错误 - % 100 项的前导零会发生什么情况?
      【解决方案4】:

      我不太确定 log10 将如何帮助您获得第一个非零数字,但假设它确实如此(因此您知道要四舍五入的小数位),以下函数将正确四舍五入:

      double round(double num, int decimalPlaces)
      {
          //given your example of .95637 being rounded to two decimal places
          double decimalMultiplier = pow(10, decimalPlaces); // = 100
          double roundedShiftedNum = num * decimalMultiplier + 0.5; // = 96.137
          double insignificantDigits = (roundedShiftedNum - (int)roundedShiftedNum; // = 0.137
          return (roundedShiftedNum - insignificantDigits) / decimalMultiplier; // = (96.137 - 0.137)/100 = 0.96
      }
      

      这可能不是最优雅的解决方案,但我相信它有效(虽然还没有尝试过)

      【讨论】:

        【解决方案5】:

        这是Shane Powell 提供的版本的变体。

        std::string FormatNum(double num, int decimals)
        {
            stringstream ss;
            if (num >= 0.0)
                ss << '+';
            ss << setiosflags(ios::fixed) << setprecision(decimals) << num;
            return ss.str();
        }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2016-08-01
          • 1970-01-01
          相关资源
          最近更新 更多