Page 1 of 2
PB 4.20 (beta 2) expression evaluation / casting issue
Posted: Fri Feb 15, 2008 10:26 am
by dell_jockey
Consider this code:
Code: Select all
_Resolution_.w = 2000
dummyFloat.f = 1234.5678
Dim Table.f(_Resolution_ - 1)
For n = 0 To (_Resolution_ - 1) ; populate table.
Table(n) = dummyFloat.f / ( (_Resolution_.w >> 1) * n )
Next
an array of floats should be filled with values, that in part depend on an integer/word value that needs to be divided by two. For that division I intended to use the >> operator.
At that point I get the error:
Code: Select all
"Can't use any of the following operands with floats: <<, >>, &, |, !, %"
To me this means that _Resolution_.w gets cast to a float, before it is right shifted one place, even when this right shift operation is contained within its own brackets.
Shouldn't PureBasic evaluate
everything within brackets first, BEFORE casting the result to float?
If this issue really is an error, please let me know so that I can re-file under bugs.
Posted: Fri Feb 15, 2008 10:48 am
by srod
I think this has been a facet of PB right from the outset as I remember coming across something like this before. Because the rhs of your expression involves a float, everything is promoted to this type prior to the expression being evaluated.
The same would be true of a calculation involving bytes, words and longs; all the variables in question would be promoted to longs in this case prior to evaluation.
Unless I'm mistaken (which is more than possible!) c++ would do something similar.
Of course, the solution is to simply break your expression down etc.
Re: PB 4.20 (beta 2) expression evaluation / casting issue
Posted: Fri Feb 15, 2008 10:50 am
by Dare
dell_jockey wrote:Shouldn't PureBasic evaluate everything within brackets first, BEFORE casting the result to float?
I think it should. I rely on brackets getting precedence, and for casting being done only at the stage when required. So far I have been lucky. Or maybe it just hasn't made a difference to end result in my expressions.
Actually 4.1 throws that error as well.
1 vote for bug (or at least an imPurity). But hang in for others to comment.

Posted: Fri Feb 15, 2008 10:59 am
by srod
Ah, if we're voting then I vote for no bug - its just the way it is, the way I imagine a lot of compilers operate. It certainly makes the compiler somewhat simpler.
I imagine that at some point Fred made a conscious decision to proceed in this way as I find it hard to believe that it could be an accident. From that point of view then I have to say that it is likely by design rather than a bug resulting from an oversight.

Posted: Fri Feb 15, 2008 11:31 am
by dell_jockey
srod wrote:
Unless I'm mistaken (which is more than possible!) c++ would do something similar.
in C / C++ anything inside brackets or curly braces is evaluated first. Only after evaluating stuff inside brackets a cast takes place. Curly braces are even used to define a scope, i.e. variables defined within curly braces are only visible / exist within those curly braces.
Re: PB 4.20 (beta 2) expression evaluation / casting issue
Posted: Fri Feb 15, 2008 11:34 am
by dell_jockey
Dare wrote:I think it should. I rely on brackets getting precedence, and for casting being done only at the stage when required. So far I have been lucky. Or maybe it just hasn't made a difference to end result in my expressions.
at least I got an error message....
A PureBasic 'inPurity', a nice find

Posted: Fri Feb 15, 2008 11:34 am
by srod
I stand corrected on that one.
Actually, when I sat back to think about that rash statement of mine I decided that c++ probably did only promote variables when absolutely necessary! Oh well! I still think though that Fred has made a conscious decision to promote all variables at the outset of an expression evaluation etc.
Posted: Fri Feb 15, 2008 12:34 pm
by #NULL
we just had that in german forum
Code: Select all
distance.l = 10
If distance < (64 * 0.5)
Debug "less"
Else
Debug "greater"
EndIf
'0.5' is casted to integer '0' before multiplication, because of 'distance' being an integer.
it's a pity, but as srod said, that's how it works in PB, so once you know it you can just be more carefull.
other way round it works
..or you can use Int() for the braced part..
Posted: Fri Feb 15, 2008 1:18 pm
by srod
Actually #NULL, there is no multiplication being performed at runtime here; the compiler is converting 64 * 0.5 to 0 directly during compilation.
So we have two issues here; the compiler promoting / casting literal values during compilation and promoting / casting variables during runtime etc.

Posted: Fri Feb 15, 2008 1:48 pm
by dell_jockey
#NULL wrote:
other way round it works
..or you can use Int() for the braced part..
now, that does make sense, doesn't it?

alas, one more "inPurity" to keep track of...
I'm starting to befriend 'manual typecasting' à la C again. At least then the compiler doesn't do anything unexpected.
Posted: Sat Feb 16, 2008 12:36 am
by ZeHa
srod wrote:Actually #NULL, there is no multiplication being performed at runtime here; the compiler is converting 64 * 0.5 to 0 directly during compilation.
Yeah, I thought that too. But unfortunately, it isn't...
The code with the "distance" variable is from my current project, and the 64 was a constant called #TILE_HEIGHT. I also expected the multiplication to happen right at compile time and not at run time - but it really seems to happen at run time, 0.5 gets casted to long and then yields 0.
Now, if you change distance.l to distance.f, it suddenly works!
Posted: Sat Feb 16, 2008 1:00 am
by srod
If you look at the generated assembly code you can see that the compiler has changed 64 * 0.5 to 0; it is in the XOR EAX, EAX statement.
Change to 64 * 1.5 and you see explicitly (in the assembly code) that the compiler inserts 96 in it's place.
Now, if you change distance.l to distance.f, it suddenly works!
Yes it would do, everything is then promoted to floats and 64*0.5 will be replaced by 32 by the compiler (not at runtime -confimed by looking at the asm).
Posted: Sat Feb 16, 2008 10:46 am
by ZeHa
srod wrote:Change to 64 * 1.5 and you see explicitly (in the assembly code) that the compiler inserts 96 in it's place.
But isn't that crazy?!
When I'm using 64 * 0.5 and it gets casted to longs, then of course I understand that 0.5 becomes 0 and 64 * 0 is of course also 0.
When I'm using 64 * 1.5 and it gets casted to longs, I'd expect that 1.5 becomes 1 and the compiler should replace it with 64, not with 96!
And, of course, I expect the right hand side of a comparison to be evaluated BEFORE the left hand side has got to do anything with it. So, I'd expect the 64 * 0.5 to happen like it should (to become 32 at compile time), and after that, it can safely be compared with the left hand side and also be casted. But it shouldn't be casted until it has been fully evaluated.
That's the initial problem, but that weird 0.5/1.5 stuff above seems even more problematic...
Posted: Sat Feb 16, 2008 12:42 pm
by srod
Aye, I missed the significance of that.
Yes, that is very strange indeed. I've just rechecked and, in the case of longs, the compiler does indeed regard 64*0.5 as 0 whilst 64*1.5 is changed to 96.
Very strange. An inconsistency like this must go down as a bug.
@dell_jockey : no arguments with this aspect!

Do you want to make a bug report or shall I?
Posted: Sat Feb 16, 2008 7:48 pm
by dracflamloc
wow.... this could be bad. i wonder at the # of bugs i've tried to find that were caused by this...