1
printf("%.3lf\n", -0.0001);

This outputs -0.000, but shouldn't it be 0.000?

How can I make this print without the minus sign, i.e. 0.000 ?

Toby Speight
  • 27,591
  • 48
  • 66
  • 103
  • `-0.000` _is_ the correct output for a negative zero. What you're asking for is a way to print negative zero as if it were a positive zero. – Toby Speight Aug 21 '15 at 10:35
  • possible duplicate of [what is the best way to avoid negative zero in output?](http://stackoverflow.com/questions/12536270/what-is-the-best-way-to-avoid-negative-zero-in-output) – Toby Speight Aug 21 '15 at 12:09

4 Answers4

6

C++ inherits printf from C. In C11 standard §7.21.6.1 The fprintf function, the footnote says:

The results of all floating conversions of a negative zero, and of negative values that round to zero, include a minus sign.

Yu Hao
  • 119,891
  • 44
  • 235
  • 294
1

The float representation ( https://en.wikipedia.org/wiki/Floating_point) has a sign bit. Who implemented the printf decided to explicitly put it there even when all the printed numbers are 0.

Chris Cinelli
  • 4,679
  • 4
  • 28
  • 40
1

The correct answer has already been given. Just wanted to add that you'll get the same from c++ cout

If you want to get rid of the sign, it can be done like this:

double fixSign(double d)
{
    std::ostringstream strs;
    strs << std::fixed << std::setprecision(3) << d;
    std::string str = strs.str();

    if (str == "-0.000") return 0.0;

    return d;
}

int main()
{
    double d=-0.0001;

    printf("%.3lf\n", d);

    cout << std::fixed << std::setprecision(3) << d << endl;

    cout << std::fixed << std::setprecision(3) << fixSign(d) << endl;

    return 0;
}

output:

-0.000
-0.000
0.000


EDIT Could this be done without converting to string?

How about:

#define PRE 3
#define LIMIT -0.0005  // Must have PRE zeros after the decimal point

// VERSION WITHOUT USE OF STRING
double fixSign_v2(double d)
{
    if ((d < 0) && (d > LIMIT)) return 0;

    return d;
}

double fixSign(double d)
{
    std::ostringstream strs;
    strs << std::fixed << std::setprecision(PRE) << d;
    std::string str = strs.str();

    if (str == "-0.000") return 0.0;

    return d;
}

int main()
{
    // PRE == 2
    //double d1=-0.005;
    //double d2=-0.0049999999999;

    // PRE == 3
    double d1=-0.0005;
    double d2=-0.000499999999999;

    // PRE == 10
    //double d1=-0.00000000005;
    //double d2=-0.0000000000499999999;

    cout << std::fixed << std::setprecision(PRE+20) << d1 << endl;

    cout << std::fixed << std::setprecision(PRE) << fixSign(d1) << endl;

    cout << std::fixed << std::setprecision(PRE) << fixSign_v2(d1) << endl;

    cout << "------------------------" << endl;

    cout << std::fixed << std::setprecision(PRE) << d2 << endl;

    cout << std::fixed << std::setprecision(PRE) << fixSign(d2) << endl;

    cout << std::fixed << std::setprecision(PRE) << fixSign_v2(d2) << endl;

    return 0;
}

output:

-0.001
-0.001
-0.001
------------------------
-0.000
0.000
0.000

so it seems to work!

But it won't work for all rounding modes.

Therefore it seems safer to use the first version with string convert.

Support Ukraine
  • 42,271
  • 4
  • 38
  • 63
  • Really? Converting to string, comparing a string and depending on that returning a specific value? Plus: This will only work if the precision doesn't change. – Simon Kraemer Aug 21 '15 at 09:29
  • @SimonKraemer - yes, it is the only safe way I could think off. Do you know a better way? If you change precision you'll of cause also have to change the compare string. In real code you would probably put precision and compare string as consts somewhere instead of typing `3`several place but this is just example code. – Support Ukraine Aug 21 '15 at 11:33
  • I have posted my solution below. Just rounding the value to the required precision before printing it. So -0.0001 will become a real 0 and therefore be printed correctly. – Simon Kraemer Aug 21 '15 at 11:38
1

EDIT: My previous solution didn't solve the problem as it should.

template <int precision=0, double(*round_func)(double)=std::round>
double round(double a)
{
    auto multiplier = std::pow(10, precision);
    a *= multiplier;
    a = round_func(a);
    if (a == 0.0) return 0.0;
    a /= multiplier;
    return a;
}

int main()
{
    printf("printf: %.3lf\n", -0.0001);
    printf("round : %.3lf\n", round<3>(-0.0001));
    system("PAUSE");
}

Result: printf: -0.000 round : 0.000

Comparing printf w/ precision and round

int main()
{
    printf("printf: %05.2lf\n", 12345.6789);                        
    printf("printf: %05.2lf\n", 12345.1234);                        
    printf("\n");
    printf("round : %05.2lf\n", round<2, std::round>(12345.6789));  
    printf("round : %05.2lf\n", round<2, std::round>(12345.1234));
    printf("\n");

    printf("floor : %05.2lf\n", round<2, std::floor>(12345.6789));  
    printf("floor : %05.2lf\n", round<2, std::floor>(12345.1234));
    printf("\n");

    printf("ceil  : %05.2lf\n", round<2, std::ceil>(12345.6789));   
    printf("ceil  : %05.2lf\n", round<2, std::ceil>(12345.1234));
    system("PAUSE");
}

Result:

printf: 12345.68
printf: 12345.12

round : 12345.68
round : 12345.12

floor : 12345.67
floor : 12345.12

ceil  : 12345.68
ceil  : 12345.13

So printf seems to also round values when using precision.

---------------------------

Old answer, Please ignore:

You might use this to round your answer before printing it:

template <int precision>
double round(double a)
{
    auto multiplier = std::pow(10, precision);
    a *= multiplier;
    a = std::round(a);
    a /= multiplier;
    return a;
}

Alternatively, if you just want to cut of the rest:

template <int precision>
double round_down(double a)
{
    auto multiplier = std::pow(10, precision);
    a *= multiplier;
    a = std::floor(a);
    a /= multiplier;
    return a;
}

This works even with a negative precision:

int main()
{
    //Round at precision
    printf("%5.4lf\n", round<4>(12345.6789));           //Output = 12345.6789
    printf("%5.4lf\n", round<3>(12345.6789));           //Output = 12345.6790
    printf("%5.4lf\n", round<2>(12345.6789));           //Output = 12345.6800
    printf("%5.4lf\n", round<1>(12345.6789));           //Output = 12345.7000
    printf("%5.4lf\n", round<0>(12345.6789));           //Output = 12346.0000
    printf("%5.4lf\n", round<-1>(12345.6789));          //Output = 12350.0000
    printf("%5.4lf\n", round<-2>(12345.6789));          //Output = 12300.0000
    printf("%5.4lf\n", round<-3>(12345.6789));          //Output = 12000.0000
    printf("%5.4lf\n", round<-4>(12345.6789));          //Output = 10000.0000
    printf("%5.4lf\n", round<-5>(12345.6789));          //Output = 0.0000

    //Cut off/Round down after precision
    printf("%5.4lf\n", round_down<4>(12345.6789));      //Output = 12345.6789
    printf("%5.4lf\n", round_down<3>(12345.6789));      //Output = 12345.6780
    printf("%5.4lf\n", round_down<2>(12345.6789));      //Output = 12345.6700
    printf("%5.4lf\n", round_down<1>(12345.6789));      //Output = 12345.6000
    printf("%5.4lf\n", round_down<0>(12345.6789));      //Output = 12345.0000
    printf("%5.4lf\n", round_down<-1>(12345.6789));     //Output = 12340.0000
    printf("%5.4lf\n", round_down<-2>(12345.6789));     //Output = 12300.0000
    printf("%5.4lf\n", round_down<-3>(12345.6789));     //Output = 12000.0000
    printf("%5.4lf\n", round_down<-4>(12345.6789));     //Output = 10000.0000
    printf("%5.4lf\n", round_down<-5>(12345.6789));     //Output = 0.0000
}

Alternative solution, that allows defining the method of rounding:

template <int precision=0, double(*round_func)(double)=std::round>
double round(double a)
{
    auto multiplier = std::pow(10, precision);
    a *= multiplier;
    a = round_func(a);
    a /= multiplier;
    return a;
}

int main()
{
    printf("%05.4lf\n", round(12345.6789));                     //Output = 12345.0000
    printf("%05.4lf\n", round<1>(12345.6789));                  //Output = 12345.7000
    printf("%05.4lf\n", round<1, std::round>(12345.6789));      //Output = 12345.7000
    printf("%05.4lf\n", round<1, std::floor>(12345.6789));      //Output = 12345.6000
    printf("%05.4lf\n", round<1, std::ceil>(12345.6789));       //Output = 12345.7000
}
Simon Kraemer
  • 5,700
  • 1
  • 19
  • 49
  • I don't think 1001.0001 should be rounded to 1000.0000. Also I don't like that the template argument changes. Finally I'm not sure if all the math can give unexpected rounding for some precision values and/or rounding modes. – Support Ukraine Aug 21 '15 at 12:10
  • Rounding 1001.0001 to 1000 with a precision of *-3* is ok. Check my updated example above. I don't see anything wrong with this, especially if it's only used for output. The original value isn't changed. – Simon Kraemer Aug 21 '15 at 12:31
  • Now I understand what the purpose of -3 is. So that part is ok. However, I don't think your code will work. The purpose of the original code was only to get rid of the sign in "-0.000". For all other values the result should be exactly the same as `cout << someDouble` with precision 3. Regardless of current rounding mode. Your code can't do that as far as I can see. Also see http://stackoverflow.com/questions/20264681/how-to-specify-setprecision-rounding – Support Ukraine Aug 21 '15 at 13:01
  • `printf` with precision does round, so using the function in combination with std::round does give the same result. I will update my answer above. – Simon Kraemer Aug 21 '15 at 13:07
  • 1
    I think we should lay this to rest. I don't agree with your approach and you don't agree with mine. That's fine. I'll end this by given you a +1 for the effort. Have fun :-) – Support Ukraine Aug 21 '15 at 18:04