1

I have really interesting question. Recently I figured out, that Math.pow() takes only (double, double) args and I wonder why there is no overloaded functions with other types combinations such as (int, int) or (int, double) atc ...

I think this is big hole and paintfull weakness so I belive there is A REASON. Can anybody explain it to me, please?

Consider these two methods:

private int simplePow(int x) {
    return x * x;
}
private int harderPow(int x) {
    return (int) Math.pow(x, 2);
}

first one is much faster than second... problem is, that if you know, that you use power with (int, int), calculation is much effective and you don't need to take care of problems with double variables.

Snurka Bill
  • 973
  • 4
  • 12
  • 29
  • What would be gained by overloading those functions? Aren't primitives promoted (don't know the right term...) automatically? – awksp May 17 '14 at 23:09
  • Precision makes sense to me as a reason. ints can be converted to doubles without much trouble, but doubles to ints can cause loss of data. More likely the guy writing it probably thought that having one function with parameters that are easily converted to/from was sufficient. – Marshall Tigerus May 17 '14 at 23:12
  • @snukrabill That comparison isn't fair at all. Not even *close* to being a fair comparison. `Math.pow()` makes a call to to `StrictMath#pow()`, which is a native method and so would almost certainly be slower than a raw multiplication. – awksp May 17 '14 at 23:15
  • @user3580294 ok, I agree that there are unfair conditions. But I think it still shows my point. I would be absolutely fine, if pow would return double all time, but I have problem with input arguments. 1. there must be conversion int -> double two times. 2. 2.0 ^ 2.0 is much slower than 2 ^ 2 ... so why is there no method for it as in C++ for example? I still belive that there is a good reason, but you didn't convince me – Snurka Bill May 17 '14 at 23:24
  • @snukrabill My guess is that there would be extremely limited use in having integer arguments, as overflow would quickly become a problem, and doing checks to see whether promotion should occur could be more costly than just assuming the arguments are doubles. Even having `pow(double, int)` would defeat the purpose of overloading as you're still operating on a double. I'd imagine if the performance issues were that bad C++ would have overloaded their standard library, so I can't imagine them not overloading out of laziness or something. – awksp May 17 '14 at 23:29
  • 1
    @snukrabill If *you* know you'll never experience overflow, you're free to write your own `pow()` implementation, but the library designers probably went with the safer decision and required `double` inputs. Inputs up to 46342^46342 fail for simple integer powers, and depending on the calculation that might not be nearly enough range. But as I don't know enough to state authoritatively, I can't answer. – awksp May 17 '14 at 23:31
  • Other than speed, there's an accuracy issue. Since most `long` values can't be exactly represented by a `double`, a hypothetical `public static long pow(int a, int b)` would give the correct answer in many cases where `Math.pow` returns an incorrect answer. – Dawood ibn Kareem May 18 '14 at 01:27

2 Answers2

7

Well really the only one you should be concerned about is the (int, int) overload; the others that take a double parameter should result in doubles anyway so the (double, double) method will do. So why is there no (int, int) overload? Probably because exponentiation grows so fast, and since ints are only 32 bits long, there are a limited number of parameters such that one raised to the other will be in range. doubles have a much larger range so they don't have a similar problem (to be clear, doubles can overflow too, but they can hold a maximum value of about 1.8e308; much larger than that of int). You can of course implement your own method to take integer power, as is done here (the accepted answer makes use of exponentiation by squaring, which can also be applied to the (double, int) case).

Community
  • 1
  • 1
arshajii
  • 127,459
  • 24
  • 238
  • 287
  • Might want to point out that having `double` parameters also lets you raise things to nonintegral powers, which could be handy from time to time. – awksp May 17 '14 at 23:17
  • I disagree. (double, int) can be still much faster than (double, double) or (int, double), because you need only one cycle and multiply – Snurka Bill May 17 '14 at 23:17
  • 1
    @snukrabill In most contexts there will probably be a negligible difference. If you're truly worried about speed, you can apply the same technique described in the link of my answer (exponentiation by squaring) to the `(double, int)` case (even still I'm doubtful that you'll see a difference). You can't do any better with the `(int, double)` case. – arshajii May 17 '14 at 23:32
  • @snukrabill Now that I think about it, how is `(double, int)` much different than `(double, double)`? Either way you're going to be working with a `double` base, and that's going to be eating up most of your CPU, and dividing by 2 can be easily be implemented as a bit shift for an `int` or subtracting one from the exponent for a `double` – awksp May 17 '14 at 23:48
  • @user3580294 ok you are right! I did little research now and it seems that (double, int) and (double, double) takes same amount of time. – Snurka Bill May 18 '14 at 00:02
  • @snukrabill Mind sharing what kind of research? I was just going off of what seemed logical, and some hard sources might help – awksp May 18 '14 at 00:04
  • I coded it in Cpp :) ... I've forget how powering by rational exponent is calculated – Snurka Bill May 18 '14 at 00:10
  • Thank you for your time and help :) I just wanted to know why there is no overloaded methods of pow as in C. – Snurka Bill May 18 '14 at 00:12
  • @snukrabill Ah, I see. Are you satisfied with the explanations you got then? And there are overloaded `pow()` methods in the C libraries? Didn't know that... – awksp May 18 '14 at 00:17
  • yes, I am. But for some cases there is much better implement programmer's method for (int, int) if there is guarantee of low input vals – Snurka Bill May 18 '14 at 00:42
  • This answer is just not true. It is based on the false premise that doubles don't overflow in the way that `int`s do. It contains the blatant falsehood "doubles ... don't have a similar problem". Just try working out `Math.pow(100,100)` and tell me whether doubles can overflow. – Dawood ibn Kareem May 18 '14 at 00:54
  • @DavidWallace I never said doubles don't overflow. What I tried to convey is that doubles have a much larger range and so are more appropriate to work with in exponentiation. I apologize if this was unclear, I'll try to make an edit to clarify a bit. By the way `pow(100, 100)` is well within range for doubles. – arshajii May 18 '14 at 00:57
  • Oops. Sorry, I made my example a little too small (for some reason, I was thinking the limit was ~2^308, not ~10^308). Care to try `Math.pow(200,200)` though? This DOES overflow. – Dawood ibn Kareem May 18 '14 at 01:10
  • @DavidWallace Please see the revised answer, is that better? – arshajii May 18 '14 at 01:12
  • Yes, it's better. I've removed my downvote. I still don't like it very much, but I think this is a bad question to which there can be no really good answer. Ultimately, it fits into the "guess why Sun/Oracle did such and such" family of questions, which are usually unanswerable. – Dawood ibn Kareem May 18 '14 at 01:14
-1

I don't know much about java but with C++ you are primarily concerned about dynamic memory management and overloading in starting and shutting it off... I can say that in terms of optimization if the methodology of the algorithm will slow the progress of the system, then you are referring to asymetrics... However, my concern is that you are right in questioning overloading, but if there are other forms of asking the same question in your program doesn't best uses (best practices) teach that is the way to write to the results for preventing errors...