-3

So i have a string for exampe "-389761456.6570000000" and i need to round this number to 4 characters behind the dor. I wrote a whole function for this but its too long(100 lines). i cant convert it like this:

void Calculator::Display(string a)
{
    long double q = stod(a);
    cout << setprecision(4) << q << endl;
}

because it will look like this (3.89e^-10 etc)(just an example not the real result) and i want smth like this "-389761456.6570" is there any way to do it?

Roman
  • 37
  • 5
  • Have you tried `std::cout << std::fixed << std::setprecision(4) << q << std::endl;`? Also, [don't use `using namespace std;`](https://stackoverflow.com/questions/1452721/why-is-using-namespace-std-considered-bad-practice) – Xirema Dec 06 '17 at 16:33
  • 1
    The accepted answer here -- https://stackoverflow.com/questions/554063/how-do-i-print-a-double-value-with-full-precision-using-cout -- shows code that will do this for you. – Topological Sort Dec 06 '17 at 16:35
  • why shouldnt i use using namespace std? – Roman Dec 06 '17 at 16:36
  • Just take the substring that excludes the digits you don't want? – Baum mit Augen Dec 06 '17 at 16:36
  • Notice that when Xirema said that, they made it a link to a page that explains why not. – underscore_d Dec 06 '17 at 16:36
  • @Roman *"why shouldnt i use using namespace std?"* Try clicking the link. – Baum mit Augen Dec 06 '17 at 16:36
  • 1
    Please clarify if the string is an intermediate object or if you start from it and not from a `double` value. – Bob__ Dec 06 '17 at 16:39
  • 2
    Removed duplicate mark. The code **clearly** starts with a string, and the claimed duplicate started with a double. Unless you **absolutely know** the precision limits that are required here, converting to a double is not appropriate, because it can affect the result. – Pete Becker Dec 06 '17 at 16:51

2 Answers2

3

Sure, and it only requires a handful of lines of code; certainly not 100. Just consider the rules for rounding: to round to 4 digits, look at the 5th digit; if it's greater than '5', add one to the 4th digit; if it's less than '5', leave the 4th digit alone; if it's exactly '5', if anything after the 4th digit is not zero, add one to the 4th digit; otherwise, apply your tie-break rule (round-to-even, round-to-odd, round toward zero, etc.). When you add one to the 4th digit, it might roll over from '9' to something greater than '9'; if that happens, add one to the 3rd digit, etc. When all that is finished, discard the characters after the 4th digit.

Pete Becker
  • 74,985
  • 8
  • 76
  • 165
  • Slightly more lines would be needed if you have to deal with malformed input, but that check probadly belongs in it's own function. – MSalters Dec 06 '17 at 21:30
0

This should do what you want. It's much easier to just use the system libraries to do this, though.

#include <iostream>
#include <string>

void increment( std::string& num )
{
    for ( auto ch = num.rbegin(); ch != num.rend(); ch++ )
    {
        switch ( *ch )
        {
        case '9':
                *ch = '0';
        case '.':
                continue;
        case '-':
                num.insert( 1, 1, '1' );
                return;
        default:
            (*ch)++;
            return;
        }
    }
    num.insert( 0, 1, '1' );
}

std::string round( const std::string& num, size_t precision )
{
    size_t dot = num.find( '.' );
    if ( dot == std::string::npos || dot + precision >= num.size() )
    {
        return num;
    }
    size_t length = std::min( dot + precision + 1, num.size() );
    char lastCh = num[ length ];
    std::string result = num.substr( 0, length );
    if ( lastCh >= '5' && lastCh <= '9' )
    {
        increment( result );
    }
    return result;
}

int main()
{
    std::cout << round( "123.45", 4 ) << "\n";
    std::cout << round( "123.456", 4 ) << "\n";
    std::cout << round( "123.4567", 4 ) << "\n";
    std::cout << round( "123.45678", 4 ) << "\n";
    std::cout << round( "123.456789", 4 ) << "\n";
    std::cout << round( "123.456723", 4 ) << "\n";
    std::cout << round( "999.9999995", 4 ) << "\n";
    std::cout << round( "-123.456723", 4 ) << "\n";
    std::cout << round( "-999.9999995", 4 ) << "\n";
}
Lightness Races in Orbit
  • 378,754
  • 76
  • 643
  • 1,055
Alan Birtles
  • 32,622
  • 4
  • 31
  • 60
  • By _"just use the system libraries to do this"_, what do you mean specifically? Converting to a double and then back again? Do you think there are any risks with that approach? Or is there a standard "way to round a string" already without that return trip? – underscore_d Dec 07 '17 at 09:51
  • if your number is exactly representable as a double then yes converting it to a double and then printing it will be the simplest method. If you want to guarantee no loss of precision of arbitrary numbers then you either need to work on the string or use some precise number library. As you only want to round to 4 decimal places doubles will be accurate enough unless your numbers are very large. – Alan Birtles Dec 07 '17 at 13:25