odd behavior of ^

BlitzMax Forums/BlitzMax Programming/odd behavior of ^

peltazoid(Posted 2007) [#1]
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.


JoshK(Posted 2007) [#2]
'Float to Int always rounds down:
a#=1.9
b=a
print b

It's kind of annoying.


FlameDuck(Posted 2007) [#3]
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.


peltazoid(Posted 2007) [#4]
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.


peltazoid(Posted 2007) [#5]
@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


Dreamora(Posted 2007) [#6]
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)


Russell(Posted 2007) [#7]
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


FlameDuck(Posted 2007) [#8]
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?


peltazoid(Posted 2007) [#9]
@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.


Dreamora(Posted 2007) [#10]
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.


tonyg(Posted 2007) [#11]
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



Azathoth(Posted 2007) [#12]
Dreamoras code gives me:
7.9999999999999982
7.9999999999999982
7.9999999999999982



CS_TBL(Posted 2007) [#13]
same here too..

(in v1.22 admittedly, for stability reasons.. (I found 1.24 somewhat shaky))


Azathoth(Posted 2007) [#14]
Visual C++ 2005 and PureBasic gives the correct results using floats, whats the deal with Blitzmax being unable to do this operation correctly?


Brucey(Posted 2007) [#15]
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



Azathoth(Posted 2007) [#16]
I converted this from C
Function 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



TomToad(Posted 2007) [#17]
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.


H&K(Posted 2007) [#18]
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)


Dreamora(Posted 2007) [#19]
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