-2

I wrote this very simple and short code, but it doesn't work: when I compile and execute the returned value from the function calculateCharges() is 0 when I'm expecting 2.

Can anybody explain why, please?

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

float calculateCharges(float timeIn);

int main()
{
    printf("%d", calculateCharges(3.0));
    return 0;
}

float calculateCharges(float timeIn)
{
    float Total;

    if(timeIn <= 3.0)
        Total = 2.0;

    return Total;
}
Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
Lorenzo
  • 1
  • 1
  • 4
    `%d` is for `int` values. You should be using `%f`. (And also initializing `Total` for when it is not the case that `timeIn <= 3.0`.) Enable compiler warnings and pay attention to them. – Ry- Feb 06 '18 at 01:42
  • 2
    You invoke *Undefined Behavior* using an improper *format specifier* for the conversion. [C11 §7.21.6.1(p2 & p9) The fprintf function - insufficient arguments, or incorrect type.](http://port70.net/~nsz/c/c11/n1570.html#7.21.6.1p9) – David C. Rankin Feb 06 '18 at 01:48
  • 1
    Three problems: First, Total is not initialized, so it has a random value. Second, you're trying to print a float with %d. Finally, you're probably expecting 3.0 to be <= 3.0. Silly human. :-) – Lee Daniel Crocker Feb 06 '18 at 02:12

2 Answers2

3

There are at least three problems here, two of which should be easily noticeable if you enable compiler warnings (-Wall command-line option), and which lead to undefined behavior.

One is wrong format specifier in your printf statement. You're printing a floating point value wirh %d, the format specifier for signed integer. The correct specifier is %f.

The other is using uninitialized value. The variable Total is potentially uninitialized if the if statement in your function isn't gone through, and the behavior of such usage is undefined.

From my point of view, it's likely the wrong format specifier that caused the wrong output. But it's also recommended that you fix the second problem described above.

The third problem has to do with floating point precision. Casting values between float and double may not be a safe round-trip operation.

Your 3.0 double constant is cast to float when passed to calculateCharges(). That value is then cast up to a double in the timeIn <= 3.0 comparison (to match the type of 3.0).

It's probably okay with a value like 3.0 but it's not safe in the general case. See, for example, this piece of code which exhibits the problem.

#include <stdio.h>

#define EPI 2.71828182846314159265359

void checkDouble(double x) {
    printf("double %s\n", (x == EPI) ? "okay" : "bad");
}

void checkFloat(float x) {
    printf("float %s\n", (x == EPI) ? "okay" : "bad");
}

int main(void) {
    checkFloat(EPI);
    checkDouble(EPI);
    return 0;
}

You can see from the output that treating it as double always is okay but not so when you cast to float and lose precision:

float bad
double okay

Of course, the problem goes away if you ensure you always use and check against the correct constant types, such as by using 3.0F.

paxdiablo
  • 854,327
  • 234
  • 1,573
  • 1,953
iBug
  • 35,554
  • 7
  • 89
  • 134
  • 1
    @paxdiablo Thanks for the addition, but you really should post a separate answer in this case. Also, `3.0` can be represented exactly according to IEEE 754 (s=positive, e=1, f=.100000...) – iBug Feb 06 '18 at 02:15
  • iBug, it's well established that answers are community property (https://stackoverflow.com/help/editing), I saw little reason to duplicate your already-existing (and excellent) answer just to add one more problem. You should sit bit and enjoy the (hopefully) extra rep :-) Re the `3.0` safety issue, you're correct but that's stated in my addition. – paxdiablo Feb 06 '18 at 02:20
  • @paxdiablo Thanks anyway. You made me think 500k guys are rocking awesome :) – iBug Feb 06 '18 at 02:23
0

%d will print integers.

Total is a float, so it will not work.

You must use the proper specifier for a float.

(You should research that yourself, rather than have us give you the answer)

abelenky
  • 63,815
  • 23
  • 109
  • 159
  • I know I should have researched it by myself, abelenky, but I know about format specifiers. I just didn't notice I was using %d. I just realized now I was. – Lorenzo Feb 06 '18 at 01:51