【问题标题】:Truncate a decimal value in C++在 C++ 中截断十进制值
【发布时间】:2010-09-23 04:07:44
【问题描述】:

将值为 0.6000002 的 C++ float 变量截断为 0.6000 并将其存储回变量中的最简单方法是什么?

【问题讨论】:

    标签: c++ decimal truncate


    【解决方案1】:

    首先重要的是要知道浮点数是近似的。请参阅@Greg Hewgill 提供的链接,了解为什么这个问题无法完全解决。

    但这里有几个可能会满足您需求的问题的解决方案:

    可能是更好的方法,但效率较低:

    char sz[64];
    double lf = 0.600000002;
    sprintf(sz, "%.4lf\n", lf); //sz contains 0.6000
    
    double lf2 = atof(sz);
    
    //lf == 0.600000002;
    //lf2 == 0.6000
    
    printf("%.4lf", lf2); //print 0.6000
    

    更有效的方法,但可能不太精确:

    double lf = 0.600000002;
    int iSigned = lf > 0? 1: -1;
    unsigned int uiTemp = (lf*pow(10, 4)) * iSigned; //Note I'm using unsigned int so that I can increase the precision of the truncate
    lf = (((double)uiTemp)/pow(10,4) * iSigned);
    

    【讨论】:

      【解决方案2】:

      实际上这是不可能的。这不是 C++ 的限制,而是浮点的工作方式。对于许多值,没有精确的表示,因此不能简单地截断为多个数字。

      使用 printf 格式字符串打印时可以截断。

      如果您确实只需要能够存储有限数量的数字,我建议您改用固定精度数据类型。

      【讨论】:

        【解决方案3】:

        为什么会发生这种情况的一个很好的参考可以在 David Goldberg 的 What Every Computer Scientist Should Know About Floating Point Arithmetic 中找到。

        【讨论】:

        • 感谢您发布链接 Greg,我在写答案时正在考虑那个确切的文档,但我终生无法记住标题。
        【解决方案4】:

        我认为这里应该问的问题是: 为什么需要截断它?

        如果它用于值之间的比较,也许您应该考虑使用 epsilon 测试。 (在您的情况下,具有额外的容差值,因为它似乎远大于普遍接受的 epsilon)。

        如果您只想将其打印为 0.6000 ,请使用其他人建议的方法。

        【讨论】:

          【解决方案5】:
          roundf(myfloat * powf(10, numDigits)) / powf(10, numDigits);
          

          例如,在您的情况下,您要截断三位数 (numDigits)。你会使用:

          roundf(0.6000002 * 1000) / 1000
          // And thus:
          roundf(600.0002) / 1000
          600 / 1000
          0.6
          

          (您可能会将 powf 的结果存储在某处,因为您使用了两次。)

          由于浮点数通常存储在计算机上,因此可能存在不准确之处。不过,这就是使用浮点数所得到的结果。

          【讨论】:

            【解决方案6】:

            使用这个:

            floor(0.6000002*10000)/10000
            

            【讨论】:

              【解决方案7】:

              这是一个使用其他答案中的建议的函数及其使用示例:

              #include <iostream>
              #include <cmath>
              
              static void Truncate(double& d, unsigned int numberOfDecimalsToKeep);
              
              int main(int, char*[])
              {
              
                double a = 1.23456789;
                unsigned int numDigits = 3;
              
                std::cout << a << std::endl;
              
                Truncate(a,3);
              
                std::cout << a << std::endl;
              
                return 0;
              }
              
              void Truncate(double& d, unsigned int numberOfDecimalsToKeep)
              {
                  d = roundf(d * powf(10, numberOfDecimalsToKeep)) / powf(10, numberOfDecimalsToKeep);
              }
              

              【讨论】:

                【解决方案8】:

                与其他答案类似,但您不能忘记 round、floor 和 trunc 在定义上是不同的。见下面的定义和输出示例:

                http://www.cplusplus.com/reference/cmath/trunc/

                在这种情况下,我们需要以 4 位小数的精度进行 trucate,并去掉不重要的小数:

                trunc(valueToTrunc*10000)/10000
                

                value = (double)((int)(valueToTrunc*10000))/(double)10000
                

                【讨论】:

                • 这应该是公认的答案。每当截断后的下一个数字 >= 5 时,使用 round() 而不是 trunc() 的所有其他解决方案实际上都会失败。
                【解决方案9】:

                对于 C++11,您可以使用在标头 &lt;cmath&gt; 中定义的 std::round

                auto trunc_value = std::round(value_to_trunc * 10000) / 10000;
                

                【讨论】:

                  【解决方案10】:

                  你可以用这个:

                  int n = 1.12378;
                  cout << fixed << setprecision(4) << n;
                  

                  输出将是:1.1238

                  不是:1.1237

                  只是最后一个十进制数不是全部:12.123447 ==> 12.1234

                  小心点……

                  【讨论】:

                    猜你喜欢
                    • 2013-12-30
                    • 2021-10-12
                    • 1970-01-01
                    • 2016-04-22
                    • 1970-01-01
                    • 1970-01-01
                    • 2014-03-25
                    • 2017-02-08
                    • 1970-01-01
                    相关资源
                    最近更新 更多