2

I have a code sample:

float f = 3.55f;
printf("%.1f\n", f);

the result is 3.5, not 3.6, which is desired.

float delta = 1e-7;
float f = 3.55f;
printf("%.1f\n", f+delta);

now the result is 3.6, but when f is 0.0499999f;

printf("%.1f\n", f+delta);

result turns out to be 0.1, not 0.0.

I need a function that transforms 3.55 to 3.6, 0.0499999 to 0.0, anybody give a clue?

Vincent Xue
  • 969
  • 1
  • 7
  • 17
  • 1
    Try this functions http://www.gnu.org/software/libc/manual/html_node/Rounding-Functions.html – Kyslik Jun 08 '13 at 14:39
  • In the second example, are you sure that merely declaring another variable changes the behavior of `printf()`? –  Jun 08 '13 at 14:42
  • Try adding one half of the desired precision, e.g. `f + 0.05`, and then print with `%.1f` (or 0.005 and `%.2f`, etc.). – Kerrek SB Jun 08 '13 at 14:43
  • 1
    By the way, `.1f` prints `.1f`, there's a `%` missing. –  Jun 08 '13 at 14:44
  • Do enable warnings when you compile your code, the compiler would have warned you about that missing '%'. Under Linux with gcc it printed `warning: too many arguments for format [-Wformat-extra-args]`, clearly something wrong on that line. – Nobilis Jun 08 '13 at 14:47
  • possible duplicate of [Manually implementing a rounding function in C](http://stackoverflow.com/questions/12525891/manually-implementing-a-rounding-function-in-c) – jxh Jun 08 '13 at 14:56
  • +1 for have a nice short clear explanation of the problem you are having. – chux - Reinstate Monica Jun 09 '13 at 22:28

6 Answers6

2

As with many floating-point issues, the problem is that your value isn't really 3.55:

float f = 3.55f;
printf("%.10f\n", f);  // 3.5499999523

See also http://floating-point-gui.de/.

So unless you use ceil(), this value will never be rounded up.

Oliver Charlesworth
  • 267,707
  • 33
  • 569
  • 680
0

A modification of this answer to a related question by H2CO3 yields the desired output:

float custom_round(float num, int prec)
{
    float trunc = round(num * pow(10, prec+7));
    trunc = round(trunc/pow(10, 7));
    return trunc / pow(10, prec);
}

The 7 extra precision is derived from the delta value. I don't think it is generally applicable, but for the two numbers 3.55f and 0.0499999f, it points to a position that the first number will round up while the second number will round down.

Community
  • 1
  • 1
jxh
  • 69,070
  • 8
  • 110
  • 193
0

Others have pointed out that the decimal values in the example have no exact binary equivalents.

Then there is the delta:

  1. Having a decimal delta will probably mess up your rounding as adding one unrepresentable number to another is less than optimal.
  2. The delta should be based on a binary value on the order of 1/(2^23) of 2^the exponent of the number displayed (single precision) or 1/(2^52) (double precision).

For a single precision number x in the range 16 <= x < 32 (exponent = 4) the delta should be 2^(4-23) or 2^-19.

Olof Forshell
  • 3,169
  • 22
  • 28
0

Q: ... function that transforms 3.55 to 3.6, 0.0499999 to 0.0 ...?
A: Using @Kninnug answer, but to 1 decimal place.

f = round(f * 10) / 10.0;

It will give you 3.5 because the number f is not originally 3.55. True, you initialized f using the text "3.55", but C and your computer were unable to exactly represent that number. There is no (float) 3.55 on your system. Instead f has a value about 3.549999952... as it is the closest choice.

Should you still want to show f rounded to 3.6 rather than 3.5, you need to nudge f up a bit. Nudging when it is 3.549999952... so it has a value >= 3.55 and when f is 0.04999990016... (0.0499999 is not exactly representable either) that the same nudging keeps it f < 0.5.

The smallest we can increase f and see a change is nextafterf(f, g). g is the value you wish to move toward.

3.549999952...   --> 3.550000190...
0.04999990016... --> 0.04999990389...

printf("%.1f\n", nextafterf(f, 2*f));
// prints 3.6 when f is 3.549999952...
// prints 0.0 when f is 0.04999990389...

Recommend you review the reference in @Oli Charlesworth answer.

chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256
-1

Here this code works. I commented the code so you could understand it.

    #include <stdio.h>
    #include <stdlib.h>

int main(int argc, char const *argv[])
{
    float delta = 1e-7;
    float f = 3.55f;

    // Here we minus f (3.55) from the integer of f (3) so 3.55 - 3 = 0.55
    // Then we check whether the value is bigger than 0.5
    if( (f-(int)f) >= 0.5 ) { 
            // If it is, then plus 0.01 to the answer. Thus making it 3.65
        f = f + 0.01;
    } else {
            // If its not, minus 0.01 from the answer.
            // Assuming f is 3.44 this will make f 3.43
        f = f - 0.01;
    }

    // Since you its to the first decimal place, the code above will output 
    // your desired result which is 3.6.
    printf("%.1f\n", f+delta);
    return 0;
}
-1

I hope this will help you. Here's a full program to round but you can use the function only.

#include <stdio.h>
#include <math.h>
#include <string.h>

//function prototypes
float roundon(float n,int to);

void main(){
    //vars
    float num;
    int roundto;
    puts("Enter the decimal to be rounded");
    scanf("%f",&num);

    puts("Enter the number of decimal places to be rounded");
    scanf("%d",&roundto);

    float rounded= roundon(num,roundto);
    printf("The rounded value is %f\n",rounded);
}

//functions
float roundon(float n, int to){
    //vars
    float rounded;

    int checker=(int) (n*pow(10,(to+1)))%10;
    int dec= (int) (n*pow(10,to));
    if(checker>=5){
        dec++;
    }

    rounded= (float) dec/(pow(10,to));
    return (rounded);
}
kandelvijaya
  • 1,545
  • 12
  • 20
  • Enter the decimal to be rounded 523.567 Enter the number of decimal places to be rounded 2 The rounded value is 523.570007 (This was my output with the above program but i am not sure where the trailing 00007 came from, but you could work that out. Anyway i was using Linux and you might have used some other OS) – kandelvijaya Jun 09 '13 at 03:37