How to 'cout' the correct number of decimal places of a double value?

前端 未结 9 1744
迷失自我
迷失自我 2020-11-27 07:44

I need help on keeping the precision of a double. If I assign a literal to a double, the actual value was truncated.

int main() {
    double x =         


        
相关标签:
9条回答
  • 2020-11-27 07:57

    The only answer to this that I've come up with is that there is no way to do this (as in calculate the decimal places) correctly! THE primary reason for this being that the representation of a number may not be what you expect, for example, 128.82, seems innocuous enough, however it's actual representation is 128.8199999999... how do you calculate the number of decimal places there??

    0 讨论(0)
  • 2020-11-27 08:04

    The second part of the question, about how to preserve trailing zeroes in a floating point value from value specification to output result, has no solution. A floating point value doesn't retain the original value specification. It seems this nonsensical part was added by an SO moderator.

    Regarding the first and original part of the question, which I interpret as how to present all significant digits of 7.40200133400, i.e. with output like 7.402001334, you can just remove trailing zeroes from an output result that includes only trustworthy digits in the double value:

    #include <assert.h>         // assert
    #include <limits>           // std::(numeric_limits)
    #include <string>           // std::(string)
    #include <sstream>          // std::(ostringstream)
    
    namespace my{
        // Visual C++2017 doesn't support comma-separated list for `using`:
        using std::fixed; using std::numeric_limits; using std::string;
        using std::ostringstream;
    
        auto max_fractional_digits_for_positive( double value )
            -> int
        {
            int result = numeric_limits<double>::digits10 - 1;
            while( value < 1 ) { ++result; value *= 10; }
            return result;
        }
    
        auto string_from_positive( double const value )
            -> string
        {
            ostringstream stream;
            stream << fixed;
            stream.precision( max_fractional_digits_for_positive( value ) );
            stream << value;
            string result = stream.str();
            while( result.back() == '0' )
            {
                result.resize( result.size() - 1 );
            }
            return result;
        }
    
        auto string_from( double const value )
            -> string
        {
            return (0?""
                : value == 0?   "0"
                : value < 0?    "-" + string_from_positive( -value )
                :               string_from_positive( value )
                );
        }
    }
    
    #include<iostream>
    auto main()
        -> int
    {
        using std::cout;
        cout << my::string_from( 7.40200133400 ) << "\n";
        cout << my::string_from( 0.00000000000740200133400 ) << "\n";
        cout << my::string_from( 128.82 ) << "\n";
    }
    

    Output:

    7.402001334
    0.000000000007402001334
    128.81999999999999
    

    You might consider adding logic for rounding to avoid long sequences of 9's, like in the last result.

    0 讨论(0)
  • 2020-11-27 08:08

    Due to the fact the float and double are internally stored in binary, the literal 7.40200133400 actually stands for the number 7.40200133400000037653398976544849574565887451171875

    ...so how much precision do you really want? :-)

    #include <iomanip>    
    int main()
    {
        double x = 7.40200133400;
        std::cout << std::setprecision(51) << x << "\n";
    }
    

    And yes, this program really prints 7.40200133400000037653398976544849574565887451171875!

    0 讨论(0)
  • 2020-11-27 08:09
    std::cout << std::setprecision(8) << x;
    

    Note that setprecision is persistent and all next floats you print will be printed with that precision, until you change it to a different value. If that's a problem and you want to work around that, you can use a proxy stringstream object:

    std::stringstream s;
    s << std::setprecision(8) << x;
    std::cout << s.str();
    

    For more info on iostream formatting, check out the Input/output manipulators section in cppreference.

    0 讨论(0)
  • 2020-11-27 08:10

    Solution using Boost.Format:

    #include <boost/format.hpp>
    #include <iostream>
    
    int main() {
        double x = 7.40200133400;
        std::cout << boost::format("%1$.16f") % x << "\n";
    }
    

    This outputs 7.4020013340000004.

    Hope this helps!

    0 讨论(0)
  • 2020-11-27 08:10

    Responding to your answer-edit: There is no way to do that. As soon as you assign a value to a double, any trailing zeroes are lost (to the compiler/computer, 0.402, 0.4020, and 0.40200 are the SAME NUMBER). The only way to retain trailing zeroes as you indicated is to store the values as strings (or do trickery where you keep track of the number of digits you care about and format it to exactly that length).

    0 讨论(0)
提交回复
热议问题