pow()

i have a function that do a calculations and also use pow(), BUT, it's really strange that when, for example, i write:

 
(int) pow (10.00, 5);


the result is:
100000


i.e. one hundred thousand

BUT, when i write:

 
(int) pow (10.00, 6);


the result is:

1000000


which is 1 MILLION!!

any1 can give an explanation..?

edit:
sorry, my bad, read my below post
Last edited on
I don't see anything strange, just basic math. 105 is 1 with 5 zeros (100,000), 106 is 1 with 6 zeros (1,000,000).

What do you expect the output to be?

chipp wrote:
any1 can give an explanation..?

It's a really good compiler ... that does exactly what it's told!
Multiply 100'000 by 10. What do you think that new number will be?

I'll give a hint...it will be 1'000'000. One million.
really good compiler ... that does exactly what it's told
I was going say that simple correct behavior is a pretty low bar to qualify a compiler as being "really good", but then I remembered that it can even get pow "wrong" sometimes, depending on the implementation of the compile-time vs. run-time pow:
https://stackoverflow.com/questions/17063102/differences-in-rounded-result-when-calling-pow
You have to hand it to pow(), though - it's pretty tight:

1
2
3
4
5
6
7
8
9
#include <iostream>
#include <cmath>
using namespace std;

int main()
{
   cout << exp( 6 * log( 10.00 ) ) - 1000000 << '\n';
   cout << pow( 10.00, 6 ) - 1000000 << '\n';
}


1.28057e-09
0
I still wish it had an int power overload. But it does a really good job on floating point powers for sure.
I still wish it had an int power overload.

<cmath> since C++11 allows integral types to be called in pow(). Promoting the integral type to a floating point type for use in pow().
https://en.cppreference.com/w/cpp/numeric/math/pow



I think jonnin's point is that it still inevitably does floating-point arithmetic. It also is not constexpr, but many compilers often have built-in functions that check if the arguments are integral or not, and will optimize calls when appropriate.
Last edited on
it is just sluggish, is my point. x*x is a ton faster than pow(x,2), give it a try :)
yes, I know why. My point is the standard should overload a smart, hot integer powers only version; we did this a couple years back in the forum and just about anything we coded beat pow by a wide margin, whether a straight up loop or using the bits of the exponent.
> x*x is a ton faster than pow(x,2)

Not necessarily; the standard library overload for integral exponents may be smart enough
(particularly when the exponent is 2).
See: https://gcc.godbolt.org/z/vGd54ev89

guys, i really feel very much stupid and feel like an idiot rn... this is probably the most embarrassing thread ever (but, i believe we also learned something even from the most ridiculous things tho)... i feel i just wanna delete this thread fr...

this probably bcoz i was quite sleepy when i write it... and also, probably, bcoz i was too much focus on the number's length...

so my code snippet was like this:
1
2
3
4
5
6
7
8
std::string num;
std::cout << "Enter: ";
std::cin >> num;
double len = num.size();

if (len == 7) {
	std::cout << "million" /* bla bla bla */;
}


i probably was too focus on the length (i.e. 7), so when pow(10.00, 6) are the one that resulting 1 million, i thought it was wrong (coz i thought the right code should be pow(10.00, 7))

this is a very embarrassing thread (fr -_-) but, since i believe there's no stupid question, i believe we can also learned many things from this

thx, guys
JLBorges wrote:
the standard library overload for integral exponents may be smart enough


Sorry in advance for being pedantic :+)

Noted that you did say may, but I am wondering if this is an implementation dependent thing, see the code below from compiler explorer using MSVC 19.30.

Edit: I am aware the standard does not specify how things are done, just how they should behave.

I couldn't find much written about it on cppreference, or in the standard. The standard just has the function signature (none of them were int), which is probably why cppreference says the integer argument is converted to double. I was looking at the draft c++23 standard (N4901), presumably the same as the previous ones in this respect, because this is not a new feature in c++23.

g++ and clang++ produce identical code:


1
2
3
4
5
6
pow2_mul(double):
        vmulsd  xmm0, xmm0, xmm0
        ret
pow2_lib(double):
        vmulsd  xmm0, xmm0, xmm0
        ret



x64 MSVC 19.30
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
n$ = 8
double pow2_mul(double) PROC                              ; pow2_mul
        movsd   QWORD PTR [rsp+8], xmm0
        movsd   xmm0, QWORD PTR n$[rsp]
        mulsd   xmm0, QWORD PTR n$[rsp]
        ret     0
double pow2_mul(double) ENDP                              ; pow2_mul

n$ = 48
double pow2_lib(double) PROC                              ; pow2_lib
$LN3:
        movsd   QWORD PTR [rsp+8], xmm0
        sub     rsp, 40                             ; 00000028H
        mov     edx, 2
        movsd   xmm0, QWORD PTR n$[rsp]
        call    double pow<double,int,0>(double,int)              ; pow<double,int,0>
        add     rsp, 40                             ; 00000028H
        ret     0
double pow2_lib(double) ENDP   
Last edited on
> I am wondering if this is an implementation dependent thing

Yes, any possible optimisation is up to the implementation.


> which is probably why cppreference says the integer argument is converted to double.

Converted to double for overload (7); not for overloads (4), (5), (6) which accept an exponent of type int
https://en.cppreference.com/w/cpp/numeric/math/pow

JLBorges wrote:
Converted to double for overload (7); not for overloads (4), (5), (6) which accept an exponent of type int


Overloads 4,5,6 are annotated "until c++11" , hopefully most of us are in the category of using something later than c++11 :+) . I have some bias, in that I am always using the latest of compilers and standards, and am always viewing things through that lens. However, I do realise that some are forced to still use old compilers / standards.

Thanks for your always expert advice; with a positive and polite attitude. Cheers :+)
Last edited on
1
2
3
4
5
6
7
8
9
#include <iostream>
#include <cmath>
using namespace std;

int main()
{
   cout << pow( -10.0, 6.0 ) << '\n';
   cout << pow( -10.0, 6.1 ) << '\n';
}
1e+06
-nan


pow() seems to be capable of recognising where the exponent is sufficiently close to an integer ... even if that exponent is a double.

Not sure that I'd rely on this behaviour, though.



Fascinating what other languages do:
Fortran:
program test
   print *, (-10.0) ** 6          ! Legitimate; will be done by repeated-multiply, not exp-log
!  print *, (-10.0) ** 6.0        ! Simply won't compile
end program test


Python:
print( (-10.0) ** 6.0 )             # OK, gives 1000000.0
print( (-10.0) ** 6.1 )             # Well, gives the (correct) complex number!
Last edited on
> Overloads 4,5,6 are annotated "until c++11"

Thanks! I hadn't noticed that.

The exponent is a floating point value now; but some library implementations do check if it is an integer.
For instance, GNU libstdc++'s __ieee754_pow has this: /* First see whether `y' is a natural number. ... */
https://github.com/bminor/glibc/blob/92b963699aae2da1e25f47edc7a0408bf3aee4d2/sysdeps/i386/fpu/e_pow.S#L117
Apropos of nothing regarding how pow() overloads work, it is interesting (to me at least) to see there are differences in output using std::format vs. using just std::cout:
1
2
3
4
5
6
7
8
9
10
11
#include <iostream>
#include <cmath>
#include <format>

int main()
{
   std::cout << pow(10, 6) << '\t';
   std::cout << pow(10, 6.1) << '\n';

   std::cout << std::format("{}\t{}\n", pow(10, 6), pow(10, 6.1));
}
1e+06   1.25893e+06
1e+06   1258925.411794166

Change the two format replacement fields so they use a specific number of digits, say {:.10}, and the output is as follows:
1e+06   1.25893e+06
1000000 1258925.412

I keep discovering new things to like about using <format> :)
Last edited on
Topic archived. No new replies allowed.