3

Out of curiosity I know pow() returns double

Is there any particular reason why math.h has this API with double as argument and return value.

If I have a case where I need an int as the return value I would write my own API as shown below. Why does math.h doesn't have an API something like this and have double pow(double,double);

or Is there one for this? If the answer is too obvious let me know I will delete the question. I couldn't figure out the reason behind this.

int i = pow1(2,4);

int pow1(int i,int j)
{
   int k = 1;
   while(j--)
   {
      k = k*i;
   }
   return k;
}
Gopi
  • 19,784
  • 4
  • 24
  • 36
  • 1
    implementation decision probably? btw...things have changed since C90 standard....look into http://www.cplusplus.com/reference/cmath/pow/ – ha9u63a7 Apr 01 '15 at 10:54
  • 3
    Old function. Back then, maybe they felt that having pow return a 16 bit int would overflow more than be of any use. – BitTickler Apr 01 '15 at 10:57
  • 1
    Why should it return Int? It is supposed to be a "general" (not sure how to call it) function, that's why both its arguments and the returned value are double. This is just for the old standards, as previous comments have noted. – codingEnthusiast Apr 01 '15 at 10:59
  • @ha9u63ar Still the return values are floating point values and why not int is my question. There has to be some reason why this API was designed this way. – Gopi Apr 01 '15 at 11:00
  • Probably as @user2225104 says - an int can be limited to 65535, which isn't much use for a general purpose power function compared to a double, which you can just cast to int anyway if you know it won't overflow. – teppic Apr 01 '15 at 11:01
  • 1
    As a point of interest there is a faster (and still very simple) algorithm for integer powers that you can see [here](http://stackoverflow.com/questions/101439/the-most-efficient-way-to-implement-an-integer-based-power-function-powint-int) – James Snook Apr 01 '15 at 11:03
  • @DrKoch You have a case where you need a floating point values but I have come across many situations where I need a decimal return value while calculating power so why not have some API which returns decimal power value – Gopi Apr 01 '15 at 11:06
  • 1
    @Gopi I bet this answers your question. http://stackoverflow.com/questions/2398442/why-isnt-int-powint-base-int-exponent-in-the-standard-c-libraries – codingEnthusiast Apr 01 '15 at 11:07
  • It's because `pow()` can easily overflow a `int`, good question @Gopi if you write your own `pow()` implementation be careful with integer overflow. – Iharob Al Asimi Apr 01 '15 at 11:35
  • I'll close this as duplicate to the C++ discussion as the answer is the same no matter C or C++. The accepted answer applies 100% to C. – Lundin Apr 01 '15 at 11:39
  • 2
    And no, this is not an opinion-based question. How can it be opinion-based to ask why a certain thing in the standard is implemented as it is? Just because people start posting their own subjective opinions as answers, it doesn't automatically turn the _question_ opinion-based. – Lundin Apr 01 '15 at 11:40
  • @iharob I still believe after going through answers here. It would be good to have a integer based pow() say returning `long long int` – Gopi Apr 01 '15 at 15:29
  • @Lundin Thanks for commenting why not have a pow() returning `long long int` if we want a decimal based API? – Gopi Apr 01 '15 at 15:29

3 Answers3

3

I would consider the following arguments:

  • The C standard library is already quite large, and every extra function has a cost; providing a single pow function which can (at least in principle) treat both floating-points and integers means less functions, which is a good thing;
  • The int version is sufficiently simple (modulo overflows and exceptional cases) that someone may code their own if necessary, so it is not felt as an absolute necessity (there are several other similar functions which might also have been provided in the standard library, but probably for similar reasons have not been included);
  • How to deal with overflow? IEEE-754 already specifies how to deal with all those nasty exceptional cases for floating-points, but for integers you would have to choose yourself: use errno? Limit the input argument? Provide no guarantees about overflow whatsoever? Should there be a version for each integer type? Or simply one that returns long? If so, then surely people would complain about the lack of an int version, and a short version as well...
  • One of the arguably most useful cases of pow for integers is when the base is 2, in which case shifts might be more efficient. Trying to provide an efficient function that detects such cases (otherwise, people would start arguing whether one should use shifts or call ipow, and then more discussion would ensue...), and also when the base is 4, or 8, or 1, or 0, etc., becomes a real issue for the library developer.

In the end, this hypothetical ipow function would either have an extremely verbose and over-specified description (mentioning performance aspects), or it would lack visibility: should a developer reliably expect their ipow function to be optimized for special cases? The user might end up coding their own version to have a better understanding of its behavior, and since this is a relatively simple function, different implementations would abound.

All in all, from the point of view of the user, int pow() seems lacking, but from the point of view of the library developers and maintainers, it is yet another burden that they might not be willing to undertake, for a benefit which is arguably quite limited.

It is even possible that early versions of the library considered including it, then after some discussion realized that it had several shortcomings, and decided to remove it from the API.

anol
  • 8,264
  • 3
  • 34
  • 78
  • 1
    Oh I was afraid that there was no good answer to this very interesting question. But overflow is mainly the reason, there is even a `powf()` and a `long double` version `powl()`. – Iharob Al Asimi Apr 01 '15 at 11:24
1

Anol's answer is very on-point and I believe is the most correct assessment as to why int pow() is not a part of the standard library, however I would like to amend it with another possibility.

The most useful aspect of the pow function is the ability to correctly (at least as far as floating point arithmetic is concerned) perform exponentiation to non-integer powers. This type of behavior is non-trivial to implement using integer math, let alone floating point math. Rather than asking library implementors to write both an integer exponentiation routine and a floating point exponentiation routine, they decided to ask for the more useful of the two. It also helps that the x87 instruction set, as well as many other FPU instruction sets, provides built-in floating point exponentiation instructions to make the implementation on the software side trivial.

C also doesn't have any notion of exceptions, and no language-level global state that could expose things like CPU flags. This would make overflow detection in an int pow() implementation difficult to provide. In the case of double pow(), it can just return a non-signalling NaN or Infinity in the case of exceptional circumstances. However there is no notion of NaN or Infinity in the integer world.

In the case of an exception, the program could do one of the following:

  • Overflow Silently
  • Return INT_MIN or INT_MAX
  • Change an integer whose pointer was provided to the function by the caller
  • Change some global state like errno
  • Emit a SIGFPE
  • Provide a sister function int pow_overflow_check() that can be used to boilerplate the call

None of these are desirable. The first two options would lead to hard-to-diagnose logic errors in possibly unrelated areas of a program. The third one would provide an annoying and cumbersome barrier to the use of the function. The fourth one would ruin any sort of reentrancy guarantee. The fifth option would make the entire program grind to a halt. The sixth option would work well, but would also bloat the standard more, and make the function more cumbersome to use like in the third option.

Further, just like others have stated, exponentiation to an integer power, especially if the base is 2, is trivial to implement. A first year compsci student with a basic understanding of math should be able to formulate a correct implementation that could suit most use cases.

The original C language was aimed squarely at assembly programmers, and this is one of the symptoms of that. A very common theme in the language spec is that the language library should only provide things that are either impossible to implement in-language in a portable manner, or extremely non-trivial to implement purely in-language, especially when there are commonly available CPU/FPU instructions that can do it for you.

Kaslai
  • 2,445
  • 17
  • 17
  • Thanks this answer covers lot of stuff in detail. I agree with the `(2^n)` of your explanation and it doesn't make sense to use a general API to find this value when finding this value can be done in a much better way – Gopi Apr 02 '15 at 08:20
0

It's probably a decision to keep old standards simple. Although newer standards have included similar functions, there was never a function of your liking implemented using simple int argument or return values with the intent of preventing overflow issues as other answers here have presented. Quoting http://www.cplusplus.com/reference/cmath/pow/

  • C99

    double pow  (double base     , double exponent);
    float powf (float base      , float exponent);
    long double powl (long double base, long double exponent);
    

Quoting Why isn't int pow(int base, int exponent) in the standard C++ libraries?

For example the C99 rationale document specifically carries forward two of the C89 guiding principles which limit what can be added:

  • Keep the language small and simple.
  • Provide only one way to do an operation.

Credits to the original author of the best answer in that topic. That topic might answer your question in its entirety, I believe.

Community
  • 1
  • 1
codingEnthusiast
  • 3,800
  • 2
  • 25
  • 37