4

The following C code

int main(){
    int n=10;    
    int t1=pow(10,2);
    int t2=pow(n,2);
    int t3=2*pow(n,2);
    printf("%d\n",t1);
    printf("%d\n",t2);
    printf("%d\n",t3);
    return (0);
}

gives the following output

100
99
199

I am using a devcpp compiler. It does not make any sense, right? Any ideas? (That pow(10,2) is maybe something like 99.9999 does not explain the first output. Moreover, I got the same output even if I include math.h)

  • 9
    `pow` returns a `double`, which is a floating-point type. You're using it as an `int`. It does make sense. – Dan Fego Jun 04 '13 at 16:48
  • 3
    pow returns double not int, you are truncating the non integer part from the number. – Alexander Oh Jun 04 '13 at 16:48
  • 3
    Your code is not valid C because you call pow without declaring it. – R.. GitHub STOP HELPING ICE Jun 04 '13 at 16:48
  • printf("%.9lf", 2*pow(n,2)); – Nicholaz Jun 04 '13 at 16:50
  • You need `#include ` to make the declaration of `pow` visible. Depending on your compiler, you may also need something like `-lm` to link to the math library. – Keith Thompson Jun 04 '13 at 18:21
  • @R..: This code is a fragment of a whole program, and the lack of declarations did not cause the reported behavior. If `pow` and `printf` were not declared but the program were compiled and executed anyway, it is much more likely that “garbage” results different from 100, 99, and 199 would have been obtained. – Eric Postpischil Jun 04 '13 at 19:41
  • @KeithThompson: Ditto my above comment, the lack of including `` is merely an omission in the code shown to use, likely not in the whole program, and is not the cause of the reported behavior. – Eric Postpischil Jun 04 '13 at 19:42
  • 1
    Well this question is certainly interesting, but since the question contains fake code (missing includes, etc.) that makes it difficult to diagnose the actual problem, I'm hesitant to +1 it... – R.. GitHub STOP HELPING ICE Jun 04 '13 at 19:45
  • @EricPostpischil: It would have saved us some time if the OP had shown the `#include ` (which *can* cause garbage results from `pow` in some circumstances). Oh, and I forgot to mention `#include ` required for `printf`. It doesn't look like a code fragment, it looks like a complete runnable main program with missing `#include` directives. And when I compile and run it as-is on my system, I get some compile-time warnings and the output is `100 100 200` (one per line). – Keith Thompson Jun 04 '13 at 19:57
  • possible duplicate of [return value of pow() gets rounded down if assigned to an integer](http://stackoverflow.com/questions/7937286/return-value-of-pow-gets-rounded-down-if-assigned-to-an-integer) – Thomas Mueller Jun 05 '13 at 07:01
  • In this `possible duplicate` a man called Marcelo Cantos gives the solution of the problem such as I gave here. To avoid rounding down to 99 or 199 you must use **`round()`** function. (see my answer for more details) – yulian Jun 05 '13 at 17:29
  • See my update - there is a comment from `math.h` which describes this unexpected behaviour. It does explain the first output :) – yulian Jun 05 '13 at 18:19
  • `math.h` is the imported library... it's giving 100,100,200 for me...i'm using devcpp too – pinkpanther Jun 05 '13 at 18:37
  • @pinkpanther, *"calls to pow with both x and y as integral values sometimes produce a non-integral result"*, not each time. – yulian Jun 06 '13 at 16:20
  • @JulianKhlevnoy not each time in the sense... not each run? if it differs for execution to execution...why how? – pinkpanther Jun 06 '13 at 16:23
  • @pinkpanther, I think that it depends on compiler, etc... I've made a cycle `1..1000` and each time they vere `100`, `99` and `199`. I'm convinced that on your machine with your compiler the output each time will be `100`, `100` and `200`. – yulian Jun 06 '13 at 16:49
  • @JulianKhlevnoy but the asker and I use devcpp, dev-cpp uses gcc...though we got different outputs...so, may be it depends on architecture etc....also...what's your compiler by the way? – pinkpanther Jun 06 '13 at 16:56
  • @pinkpanther, GNU GCC. And I agree with you: there is some difference between our machines. – yulian Jun 06 '13 at 17:06

3 Answers3

6

You are using a poor-quality math library. A good math library returns exact results for values that are exactly representable.

Generally, math library routines must be approximations both because floating-point formats cannot exactly represent the exact mathematical results and because computing the various functions is difficult. However, for pow, there are a limited number of results that are exactly representable, such as 102. A good math library will ensure that these results are returned correctly. The library you are using fails to do that.

Eric Postpischil
  • 195,579
  • 13
  • 168
  • 312
  • No - this can be lead to a slower implementation, which may be unacceptable (or less desirable) for developers using floating point math correctly. – djechlin Jun 04 '13 at 17:04
  • 1) I concur with your 1st statement about "poor-quality math library". A good, and fast too, `pow()` rolled in binary64 (typical `double`) or binary32 (typical `float`) in unusual to have resulted in a non-exact answer given `pow(10, 2)`, even without resorting to "exactly representable" tests. But functions like `pow()` are allowed it be 1 ULP off, so it becomes a teachable moment for OP. 2) For the `pow(x,y)`, integer exactness test is _required_ of `y` when when x (exact integer or not) is < 0 as in `pow(-2.1, -3.0)`. – chux - Reinstate Monica Jun 04 '13 at 18:37
  • @chux: (1) I do not see a 1-ULP requirement in the C standard except in the non-normative Annex H, and it refers to a clause (5.2.8) that I do not find in the current version (2012(E)) of LIA-1. I do not see an accuracy specification in the normative but optional Annex F. (2) The requirement for an exact integer y for negative x is an issue about the domain of the function, not the accuracy of the result, and it is not relevant in this question. – Eric Postpischil Jun 04 '13 at 19:19
  • I concur that there is not a 1-ULP requirement in C. My ULP discussion should have address IEEE 754 compliant hardware which is often used to realize `double`, etc. Such hardware is guaranteed within one-half of a ULP for simple operations. For `pow()`, Wiki ULP: "Reputable numeric libraries compute the basic transcendental functions to between 0.5 and about 1 ULP, as it is computationally expensive to guarantee 0.5 ULP precision". Thus a _good_ library can be expected to obtain <= 1 ULP for `pow()`. – chux - Reinstate Monica Jun 04 '13 at 20:07
  • My comment about “exact integer” was due to @djechlin original comment. About how this would lead to a “slower implementation”. As this function needs to determine `y` integer-ness in part of its `x` range, part of any slowness, if any, was already paid, in part, due to the requirements of the domain. – chux - Reinstate Monica Jun 04 '13 at 20:08
  • 2
    @chux: Usually, anybody implementing a library with ≤ 1 ULP accuracy would actually aim for < 1 ULP. This is called “faithful rounding”, and there is an important reason for it. Faithful rounding guarantees that there is no error at all in cases where the mathematical result is actually representable, because, if the returned result is `x` and the mathematical result is x, then |`x`–x| < 1 ULP guarantees that `x` cannot be any representable value except x. Thus, a library implementing faithful rounding must return the exact result for `pow(10, 2)`. – Eric Postpischil Jun 04 '13 at 20:12
  • Yes. That's why I agreed about "poor-quality math library" and gave the first up-vote on this answer. – chux - Reinstate Monica Jun 04 '13 at 20:19
  • @djechlin: There's nothing incorrect about assuming your standard library to work. – tmyklebu Jun 05 '13 at 02:11
3

Store the result computations as doubles. Print as double, using %f instead of %d. You will see that the 99 is really more like 99.999997, and this should make more sense.

In general, when working with any floating point math, you should assume results will be approximate; that is, a little off in either direction. So when you want exact results - like you did here - you're going to have trouble.

You should always understand the return type of functions before you use them. See, e.g. cplusplus.com:

double pow (double base, double exponent); /* C90 */

From other answers I understand there are situations when you can expect pow or other floating-point math to be precise. Once you understand the necessary imprecision that plagues floating point math, please consult these.

djechlin
  • 59,258
  • 35
  • 162
  • 290
  • 2
    This is not an issue about the return type of the function or about how floating-point arithmetic works. The `pow` function **can** return an exact result in this case. It does not because the implementation is poor, not because the format cannot support it or because the result cannot be calculated. – Eric Postpischil Jun 04 '13 at 19:23
  • Moreover, IEEE mandates correct results when the correct answer is exact, so failure to deliver is a bug. – R.. GitHub STOP HELPING ICE Jun 04 '13 at 19:44
  • @R..: Are you referring to IEEE 754-2008 or another standard? Which clause? 754-2008 9.2 recommends that language standards define certain functions, including `pow`, to be implemented with correct rounding, but it does not mandate this. It uses “should” and defines “should” to means that one of several possibilities is particularly suitable but does not exclude others or is preferred but not required. Is there additional text regarding exactly representable cases? – Eric Postpischil Jun 04 '13 at 20:46
  • @EricPostpischil see edit. I focused my answer to the extent that I understood floating point math. I think the more important point is the OP understand the necessary imprecision, before understanding when it's okay to expect exact results. In other words, were the OP using a more precise `pow` function, the results would have been right, for coincidental reasons, given the OP's prior knowledge of `float` and precision. – djechlin Jun 05 '13 at 02:05
2

Your variables t1, t2 and t3 must be of type double because pow() returns double.


But if you do want them to be of type int, use round() function.

int t1 = pow(10,2);
int t2 = round(pow(n,2));
int t3 = 2 * round(pow(n,2));

It rounds the returned values 99.9... and 199.9... to 100.0 and 200.0. And then t2 == 100 because it is of type int and so does t3.

The output will be:

100
100
200

Because the round function returns the integer value nearest to x rounding half-way cases away from zero, regardless of the current rounding direction.


UPDATE: Here is comment from math.h:

/* Excess precision when using a 64-bit mantissa for FPU math ops can
cause unexpected results with some of the MSVCRT math functions.  For
example, unless the function return value is stored (truncating to
53-bit mantissa), calls to pow with both x and y as integral values
sometimes produce a non-integral result. ... */
yulian
  • 1,601
  • 3
  • 21
  • 49
  • In **user2452591**'s case each value will be 99.9998 or 143.9997 ot 624.9998 and so on... **user2452591** would like to `pow` `t1`, `t2` and `t3` which are of type `int`. Thay can't be like 100.00001. For `100` the result will alvays be `99.99999...` because of double type's specifications. So `ceil()` rounds it up to `100` and it is the required result. – yulian Jun 04 '13 at 17:06
  • They're of type `double`, not type `int`. – djechlin Jun 04 '13 at 17:07
  • I'm not sure what `99.99999...` means. You do realize `double` doesn't store an infinite decimal expansion...? – djechlin Jun 04 '13 at 17:08
  • Okay, so I don't know what `99.99999...` means, or why "double type's specifications" guarantees that will be the result. – djechlin Jun 04 '13 at 17:11
  • @djechlin, I meant that floating values can't be exactly integer. Thay have a little fault which results such output as `99` and `199`. – yulian Jun 04 '13 at 17:18
  • 1
    @JulianKhlevnoy: Wrong. `double` values certainly can be exactly an integer; they just aren't _required_ to be. (and the results of mathematical computations frequently won't be) – SLaks Jun 04 '13 at 17:35
  • @JulianKhlevnoy my point is they can also be a little bit *more* than the integer they are near. Instead of being 99.999 they can come out to 100.001, so your ceiling approach would yield a different wrong answer. This of course depends on the specification/implementation of `pow` with which I am not familiar. – djechlin Jun 04 '13 at 17:37
  • @djechlin, I've edited my answer. There is another function that will round the value to the nearest. (but if I'm wrong, let me know, please) – yulian Jun 04 '13 at 17:53
  • 2
    Removed downvote. I don't quite think it's a good answer because it covers up the OP's seeming obliviousness to how doubles work, but I think this is at least correct code for the situation now. – djechlin Jun 04 '13 at 18:06
  • Thanks for your objectivity. I know that my answer isn't the most universal, but it solves the **user2452591**'s problem. – yulian Jun 04 '13 at 18:09
  • Your concern about putting `round()` around `pow()` should apply as well to `pow(10,2)` as you applied to `pow(n,2)`. `pow(10, 2)` could also be 1 ULP off. – chux - Reinstate Monica Jun 04 '13 at 18:42
  • @chux, what does "1 ULP" mean? – yulian Jun 04 '13 at 18:46
  • ULP Unit in the Last Place: the difference between x and the next representable floating point x. – chux - Reinstate Monica Jun 04 '13 at 18:54