odd behavior of ^
BlitzMax Forums/BlitzMax Programming/odd behavior of ^
| ||
Ok, I can not get my head round this, when I try and set a single bit using an equation (from a loop counter) there are rounding errors which prevent the bits from being set correctly. Code here. SuperStrict Local flags : Byte For Local i : Byte = 0 To 7 If i = 2 Or i = 5 flags :+ (2 ^ (i + 1) ) ' this is one less than it should be, why???? I don't see why it is rounding down. ' as no division is taking place, just multiplication. I know I can use bit shifting but ' this is more readable (and easier :?) Print "2 to power of " + (i+1) + " = " + (2 ^ (i + 1) ) End If Next Print Bin(flags) ' this outputs correctly Print "2 to the power of 3 = " + (2 ^ 3) Anyone have any ideas why it outputs this 2 to power of 3 = 7.9999999999999982 2 to power of 6 = 63.999999999999979 00000000000000000000000001000110 2 to the power of 3 = 8.0000000000000000 Thanks. |
| ||
'Float to Int always rounds down: a#=1.9 b=a print b It's kind of annoying. |
| ||
I know I can use bit shifting but this is more readable (and easier :?) flags :| (2 Shl (i + 1) )' flags :+ (2 ^ (i + 1) ) Anyone have any ideas why it outputs this Because ^ and Exp() are floating point operations.By the way you should never mix regular algebra with boolean algebra. They aren't directly interchangeable. |
| ||
ah, i did not realise that ^ was a floating point operation. That explains it thanks. I'll be using a left shift version then :D ^ should also work on intergers as well as floats without conversion to float first. Thanks again guys. |
| ||
@FlameDuck. That code snippet is not compatible. as that shifts 2 around. rather than being a power of 2 flags :| (1 shl i) = flags :+ (2 ^ (i+ 1)) Just thought I'd point it out. :D |
| ||
float -> int rounding down is not strange, its default behavior. Only the old blitz were that broken with their float niceness that they actually rounded instead of cut of the floating part. (that and a few other float niceness features are the reason for its sub par calculation speed compared to PB and BM) |
| ||
Still not sure why the compiler doesn't use an int version of ^ if both numbers are ints (the result will NEVER be a float) or at least offer an int version... "2 to power of 3 = 7.9999999999999982" This is totally incorrect. 2 to the power of 3 is 8.Period. 2.0 to the power of 3.0, on the other hand, could be interpreted that way with the limitations of binary floating point representation. Russell |
| ||
That code snippet is not compatible. as that shifts 2 around. You're right. My bad. :o> Still not sure why the compiler doesn't use an int version of ^ if both numbers are ints What "int" version of ^ would that be then? |
| ||
@Dreamora Your right it is not strange. At the time of posting I did not realise that ^ was a floating point op, I assumed that when operating on Ints it would be a interger op. :( Cheers. |
| ||
If you get 2^3 = 7.XXX then you have done something strange:Local a:Float = 2 Local b:Float = 3 Print a^b Print Int(a)^Int(b) Print Double(a)^b results in 8.0000000000000000 8.0000000000000000 8.0000000000000000 on my system. PS: if you do not like float incorrectness, use you can use double(x)^y to use double power functionality. This won't suffer the issues but will be slower. Best you could do would implement fixed point operations and use them if you need more "precise" results. |
| ||
what about this :i:float=2.0 Print 2.0 ^ (i+1.0) ? That gives 7.9999999999999982 <edit> or this j:int = (2 + 1) Print j Print 2.0 ^ j |
| ||
Dreamoras code gives me: 7.9999999999999982 7.9999999999999982 7.9999999999999982 |
| ||
same here too.. (in v1.22 admittedly, for stability reasons.. (I found 1.24 somewhat shaky)) |
| ||
Visual C++ 2005 and PureBasic gives the correct results using floats, whats the deal with Blitzmax being unable to do this operation correctly? |
| ||
Wonder what Dreamora is doing different to get 8.000000000 ?Print pow(2,3) Function pow:Int(a:Int, b:Int) Local c:Int = 1 While b c:* a b:-1 Wend Return c End Function |
| ||
I converted this from CFunction Pow:Double(x:Double,y:Int) Local r:Double If Not y r=1 ElseIf y<0 r=Pow(1/x,-y) ElseIf y&1 r=x*Pow(x,y-1) Else r=Pow(x*x,y/2) EndIf Return r EndFunction |
| ||
Maybe Dreamora has implemented one of the fixes I posted a while back. One fix checks if the parameters are ints, and rounds the result to the nearest int. http://www.blitzbasic.com/Community/posts.php?topic=54701#664754 The other calls c++ own pow() function which seems to be more accurate than bbFloatPow(). http://www.blitzbasic.com/Community/posts.php?topic=63424#709062 When the compiler sees the ^ token, it passes the parameters to the bbFloatPow() function, which takes Doubles and returns a Double, regardless of what the parameters are. Unfortunately, the ^ opperator is buried within the compiler and not one of the modules, so this behavior cannot be changed except by Mark. |
| ||
Yes its annoying. Its happend for years If you get the correct result, its often because the code is slower, (Though to be honest ^ calcs are slow enough not to notice) |
| ||
Do not do anything different nor have I used any of the fixes. The only thing that comes in here is that I use the right mingw version, not the official one which is that far off of my CPUs tech (core duo and core 2 duo), that it is pointless to even try it. All you have to keep in mind is that you must recompile modules manually as maxgui just will break if you try to recompile it with mingw > 3.1.X |