Why does Int ^ Int get cast to Double?
BlitzMax Forums/BlitzMax Programming/Why does Int ^ Int get cast to Double?
| ||
To me this makes no sense since it is mathematically impossible for a whole number taken to the power of another whole number to have a fractional result. Example: For Local a = 0 To 31 Print 2 ^ a Next will print 1.0000000000000000 2.0000000000000000 4.0000000000000000 7.9999999999999982 15.999999999999998 32.000000000000000 63.999999999999979 127.99999999999997 255.99999999999994 511.99999999999994 1024.0000000000000 2048.0000000000000 4095.9999999999968 8191.9999999999945 16383.999999999991 32767.999999999985 65535.999999999978 131071.99999999996 262143.99999999994 524287.99999999994 1048576.0000000000 2097152.0000000000 4194304.0000000009 8388608.0000000019 16777215.999999976 33554432.000000015 67108863.999999918 134217728.00000009 268435455.99999970 536870912.00000036 1073741823.9999990 2147483648.0000019 If I try to 'force it' to Integer... For Local a:Int = 0:Int To 31:Int Print Int(2 ^ a) Next ...the result is: 1.0000000000000000 2.0000000000000000 4.0000000000000000 7.9999999999999982 15.999999999999998 32.000000000000000 63.999999999999979 127.99999999999997 255.99999999999994 511.99999999999994 1024.0000000000000 2048.0000000000000 4095.9999999999968 8191.9999999999945 16383.999999999991 32767.999999999985 65535.999999999978 131071.99999999996 262143.99999999994 524287.99999999994 1048576.0000000000 2097152.0000000000 4194304.0000000009 8388608.0000000019 16777215.999999976 33554432.000000015 67108863.999999918 134217728.00000009 268435455.99999970 536870912.00000036 1073741823.9999990 2147483648.0000019 ..which is incorrect. There is no Round function, so how do I get around this almost-a-bug? When I try 'Debug Pow(2,24)' in PureBasic I get: '16777216.0' (which, although for some odd reason is still a float, is correct - And this is without using the Round() procedure). So what's up? Can't these compilers see that all of the operands are integers, and therefore, the result should be, too? Russell |
| ||
that's not right, becuause when I did your code:For Local a:Int = 0:Int To 31:Int Print Int(2 ^ a) Next I get: 1 2 4 7 15 32 63 127 255 511 1024 2048 4095 8191 16383 32767 65535 131071 262143 524287 1048576 2097152 4194304 8388608 16777215 33554432 67108863 134217728 268435455 536870912 1073741823 -2147483648 which version of bmax are you using. I am using 1.22 try puting brackets like this: print (int(2 ^ a)) I just noticed the results are wrong also <EDIT> this is how I fixed it: Local b:Int = 2 For Local a:Int = 0:Int To 31:Int Local c:Int = (b ^ a+.1) Print c Next but that should not be anyway to correct this problem. I thing this is a compiler error. |
| ||
Yeah, I copied the previous results again by mistake. Your results are what I got, too (version 1.22). It would be usable if BMax didn't just take the fractional part off and actually rounded correctly (127.99999999999997 becomes 127 and not 128? DUH!) On a side note, this is the traditional function of Int(), which is to return the integer portion of a float. While casting, though, this should not be the case. I know it has to do with overflows and the limits of number representation, etc, but it's still strange behaviour, if you ask me. Russell |
| ||
yes but even when I do double I get the same results.For Local a! = 0! To 31! Print (2! ^ a) Next what puzzles me is how it get a fractional result by multiplying two whole numbers even if they are type double. |
| ||
The ^ operator is a floating point operation, executed on the FPU. |
| ||
Its a problem thats been raised before, they have to be floats (or doubles) or it would fail on 3^30, which even thou are both int would fail with int as a result.For Local a:Int = 0:Int To 31:Int Print Int(2 ^ a+0.5) Next Thats how you fix that. (Yes it a pain, but thats what you do) |
| ||
If that's not just an example chosen to show the problem, and 2 actually is the number that you want to raise to the power of an integer, try doing (1 Shl x) instead of (2 ^ x) |
| ||
PureBasic also returns (and requires as parameters) floats. But the difference is that PB returns the correct answer. (Pow(2,24) returns 16777216.0, which is correct, wheras BM returns 16777215.xxx, which is incorrect). If ^ is a floating point operator (not mentioned in the manual, once again), then why not also include an integer version or, better yet, have BM call te correctone depending on whether there are floats/doubles involved or not. As far as failing on overflow, this can be 'caught' by various means (such as checking the 'carry' flag of the processor). Another possiblity is to use this library: http://www.tc.umn.edu/~ringx004/mapm-main.html which is open source, ready to be converted to a module (hint, hint) and can handle numbers with up to BILLIONS of digits. Yes, I said Billions. Russell |
| ||
But you wouldnt want to use it in a game engine tho. Would you? Its a libary for really comples exact maths, like slingshot a spaceship round mars. Its for when you "Need" exact, not speed Mind you This IS stupid a=3 Print ((2 ^ a) = (2 ^ 3))Cos its says 2^a when a is 3, and 2^3 are not the same |
| ||
Just replacedouble bbFloatPow( double x,double y ){ double r; static const BBInt64 Nan64=0xfff8000000000000LL; if( x>0 ) return exp( y * log(x) ); if( x==0 ){ if( y>0 ) return 0; if( y==0 ) return 1; return 1.0/0.0; } if( floor(y)!=ceil(y) ) return *((double*)&Nan64); r=exp( y * log(-x) ); return ((BBInt64)floor(y) & 1) ? -r : r; }in BlitzMax\Mod\brl.mod\blitz.mod\blitz_cclib.c with double bbFloatPow( double x,double y ){ pow(x,y); }and recompile the modules. Seems I remember reading somewhere that BRL decided to rewrite the power function to be faster at the cost of slight inaccuracies. |
| ||
(Pow(2,24) returns 16777216.0, which is correct, wheras BM returns 16777215.xxx, which is incorrect) Just because the result is rounded off does not mean it's more accurate. |
| ||
16777216 is exactly correct because we're working with integers. Rounding 16777215.999999976 down to 16777215 makes no sense. Correct rounding would, indeed, give the correct answer. That means rounding to the nearest integer. On this same note, I discovered something very unusual. If you run Print 2 ^ 24 ..you get 16777216.000000000 (correct). But if you run For a = 0 To 31 Print 2 ^ a Next ..the result for 2 ^ 24 is 16777215.999999976 (wrong!)! Do literals get converted differently than variables, and if so, why? Russell |
| ||
@ Russtle, I posted that 2^a<>2^24 when a = 24 three posts up, and yesterday |
| ||
hmm int ^ int should really be int. I don't care what the internal fpu or whatever does. That's why I use blitz... And constants like 2^24 get simplified so that they aren't calculated each time. I guess it gets calculated differently when it does this. Its similar to that blitz3d bug blitz3d code: Const a=-1 Local b=-1 Print a/2 Print b/2 WaitKey End |
| ||
Where are Floyd and sswift? I'm sure they could explain it. |
| ||
Here's a function which could provide Int ^ Int returning Int:Strict Framework brl.blitz Import brl.standardio Local loop1 = 1000000 , loop2 = 1000000 Local n , x = 100 , y = 100 Local start1 = MilliSecs ( ) For Local i = 0 Until loop1 n = x ^ y Next Local end1 = MilliSecs ( ) Local start2 = MilliSecs ( ) For Local i = 0 Until loop2 n = PowInt ( x , y ) Next Local end2 = MilliSecs ( ) Print ( end1 - start1 ) / Float loop1 + " milliseconds needed for ~qn = x ^ y~q." Print ( end2 - start2 ) / Float loop2 + " milliseconds needed for ~qn = PowInt ( x , y )~q." Function PowInt:Int ( x:Int , y:Int ) NoDebug If y < 0 Return EndIf Local n = 1 While y n :* x y :- 1 Wend Return n EndFunctionIt seems to be a bit faster than doing float ^ float + rounding to int. I think the BlitzMax compiler should compile intvar ^ intvar to a call to this function. |
| ||
Visual Basic 2005 casts ^ operations to double as well. My guess is that it's because of the API routine that's being called. |