【问题标题】:Reducing the digits of a Double in C++在 C++ 中减少 Double 的位数
【发布时间】:2012-10-26 10:31:03
【问题描述】:

我需要一个降低双打精度(位数)的函数。

我需要它来计算,而不是在屏幕上输出。

到目前为止,我所拥有的是:

double setDigits(double _number, int _digits)
{
    double tenth = pow((double)10,_digits);
    _number *= tenth;
    _number = floor(_number);
    _number /= tenth;

    return _number;
}

调用 setDigits(sqrt(2),3) 得到 1.4139999999999999,而不是我想要的 1.414。

我能做什么?

【问题讨论】:

  • 1e-16 的差异对您的计算是否真的很重要? 1.414 没有精确的二进制表示,所以当你使用它时它永远不会是 1.414。所以如果 1e-16 的错误是不可接受的,你应该去四精度。
  • 您应该认真考虑浮点是如何工作的,以及这是否适合您。无法保证您实际上可以用二进制浮点表示您期望的数字。例如,如果您使用金钱,请考虑仅使用整数并存储美分而不是美元。
  • _decimals 来自哪里?
  • 本意是在比较值时使用它,所以我不知道确切的数字(我的一些数字推迟到 1E-7,这种精度不相关),我会四舍五入它们,以便于比较。
    使用浮点数解决了我的问题。

标签: c++ function double precision digit


【解决方案1】:

我能做什么?

不幸的是,根本问题没有:在您的平台中,1.414 没有精确的双重表示。您无法使用“1.414”运行计算,因为您无法将“1.414”放在您的double 中的任何位置。

例如见http://www3.ntu.edu.sg/home/ehchua/programming/java/DataRepresentation.html

可以做的就是以最大精度保持您的数字,并以降低的精度显示它。您需要计算机器精度并在计算过程中跟踪误差。

因此,您将使用 1.413999999999997 并最终得到答案,例如 41.99999137;您将与它一起显示

printf("The answer is %.3f\n", theAnswer);

或者您可以更改平台(编译器、数学库或浮点表示,例如,在支持的情况下使用 long double),但请记住,您可以以错误的 1.873 为代价获得 1.414(有为 1.87299999999 或 1.87300000001),计算会有或多或少相同的误差。

您可以使用整数运算,将初始数字乘以 1,000,000(得到 1414000)或其他合适的比例,然后在最后除。不过,整数有一个最大界限。

还有任意精度库,它们使用不同的内部表示并允许您以您想要的方式指定精度,例如 GMP (http://gmplib.org/)。当然,使用它比指定更困难

op1 = 6.0;
op2 = 7.0;
theAnswer = op1 * op2;

而且处理速度也较慢,但结果很好 - 或者和您说的一样好。

【讨论】:

  • 非常有帮助,你让我意识到我不需要双精度。将我所有的双打更改为浮点数更正了奇怪的值。
  • 好的,但请记住您选择了更改平台选项;您注意到的效果仍然存在,只是数字不同。
【解决方案2】:

以下行无效。

double tenth = pow((double)10,_decimals); //_decimals is not declared
_number = floor(_digits); //should be floor(_number)

修正后的函数是

double setDigits(double _number, int _digits)
{
    double tenth = pow((double)10,_digits);
    _number *= tenth;
    _number = floor(_number);
    _number /= tenth;

    return _number;
}

Here is a demo.

【讨论】:

  • 我已经在我的程序中写了这个,但在我的帖子中失败了,因为我重命名了一些变量以使其更具可读性
  • 是的。发现如果我把所有的双打都改成浮点数,它工作得很好。所以因为我不需要双精度,所以没有问题。
  • 查看我包含的演示。干杯。 :)
【解决方案3】:

我不知道您可能不会检查此答案,但其他人会 我是 C++ 新手,但我找到了一种方法来做到这一点

double Point::norm()

{

return (double)floor((sqrt(pow(px,2)+pow(py,2)+pow(pz,2))*1000))*0.001;

}

我使用这个,但你可以编写自己的数学课来为你做这个

【讨论】:

    【解决方案4】:
    double setDigits(double _number, int _digits)
    {
           double tenth = pow((double)10,_digits);
           int result = (_number * tenth) + 0.5; 
           double aux = result / tenth;
    
           return aux;
    }
    

    用第 10 次 = 1000 尝试以下操作;

    result = 1413,9999999999999 * 1000 +0,5
    result = 1414,4......
    result = 1414
    

    【讨论】:

      【解决方案5】:

      试试这个:

      double setDigits(double _number, int _digits)
      {
          double tenth = pow((double)10,_digits);
          return floor(_number * tenth + 0.5)/tenth;
      }
      
      std::cout<<setDigits(sqrt(2),3);
      

      Output: 1.414

      【讨论】:

      • @user1595420:这就是浮点的工作原理。看起来漂亮的数字不会存储漂亮的数字,反之亦然。这是十进制读取和二进制存储的问题。它们只是不适合这样的事情。
      【解决方案6】:

      您可以创建一个中间类,将内部数据管理为int,但输入和输出为double

      class TruncatedDouble
      {
      private:
        int value_;
      
      public:
        TruncatedDouble(double d) : value_((int)(double * 1000)) {}
        void SetValue(double d) {value_ = (int)(double * 1000);}
        double GetValue() {return (double)value_ / 1000;}
      };
      

      您还必须重载所有常用运算符,但这很容易。示例:

      TruncatedDouble& operator+=(const TruncatedDouble& rh) {value_ += rh.value_;}
      

      等等。这个类实际上会很快,因为你使用的是int而不是double,你永远不会失去精度。

      【讨论】:

      • 嗯,是的,你会失去精确度。正如这个类的名字所暗示的那样,任何小数点右边超过四位的值都将被截断。
      • @PeteBecker:我的意思是你不会因为四舍五入而失去精度,因为你将使用ints 进行操作。根据问题,丢失小数点右侧超过四位数字不是缺点,而是要求。当然,你可以取整而不是截断;为了简单起见,我进行了截断,但舍入并不难。
      • 是的,我有点迟钝。对不起。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多