• Hey Guest! Ever feel like entering a Game Jam, but the time limit is always too much pressure? We get it... You lead a hectic life and dedicating 3 whole days to make a game just doesn't work for you! So, why not enter the GMC SLOW JAM? Take your time! Kick back and make your game over 4 months! Interested? Then just click here!

GameMaker bitwise shift returns 0

Z

zendraw

Guest
why is this returning me 0 sometimes? 2/3 times

krypt=1<<irandom_range(2, 100);
show_debug_message(krypt);
 

Simon Gust

Member
You can't left shift a 64bit value over it's limits, which is 63 if you start with 1. (note that leftshifting by exactly 63 here turns the value negative)
I guess game maker turns the undefined value to 0 instead of crashing your game.
 

Jman

Member
I think a visual example would help.

When you shift a bit value past the end of the amount of bits the number can hold it will "fall off".

For example if we have this:

0010 0000

then I shift it left 3 or more times it becomes this:

0000 0000

The 1 just "falls off".

But if I have this:

0110 1000

then shift it left 2 times I get this:

1010 0000

Notice how the farthest left 1 just vanishes and 0's are added onto the right side so we still have 8 bits.


When you were returning random integers you were getting numbers greater than 64 and because GMS2 usually uses 64 bit numbers
the 1 you had was "falling off" the left side. So the most you could left shift the value 1 would be 62 times because the 1 is already starting in spot 0.
(Note: I tested shifting it 63 times to get it in the final spot but like Simon Gust mentioned the final spot remained a 0)

Edit:

I just noticed that when you bit shift a bit past the left boundary GMS2 wraps it to the right side.
So for example

0100 0000 Shifted left 3 times might become:

0000 0010

I suppose that makes me wrong about the bits just "falling off"
 
Last edited:
Z

zendraw

Guest
i dont know how wrong you are but i get a value of 0 sometimes with the code i wrote, so perhaps they do just fall off

krypt=1<<irandom_range(2, 100);

if it does wrap around i shuldnt get a value of 0.
 

kburkhart84

Firehammer Games
That behavior seems like it might be platform dependent actually. But the reasoning for getting a zero there makes sense to me.

Is there a specific thing you are trying to do that this is causing to fail or is it more about a language curiosity?
 
That behavior seems like it might be platform dependent actually. But the reasoning for getting a zero there makes sense to me.
It wouldn't necessarily be platform dependent, but CPU-dependent. However, every CPU I'm familiar with has different instructions for bit-shifting (x86 uses SHR/SHL) and bit-rotating (ROR/ROL). The latter wraps around bits. The former drops bits and usually sets a carry flag, and that is what GM uses when you use the >>/<< operators.
 

Roldy

Member
Well thankfully we have a tool called a computer that lets us answer these questions:

GML:
for (var _i = 0; _i < 100; _i++) {
    show_debug_message (string(_i) + " = " +  string (1 << _i) );
}
OUTPUT:

Code:
[...]
58 = 288230376151711744
59 = 576460752303423488
60 = 1152921504606846976
61 = 2305843009213693952
62 = 4611686018427387904
63 = -9223372036854775808
64 = 0
65 = 0
66 = 0
67 = 0
68 = 0
69 = 0
[...]
Now as bonus homework look at the following:

GML:
show_debug_message(string(64) + " = " + string(1 << 64));
OUTPUT:

Code:
64 = 1
 

kburkhart84

Firehammer Games
It wouldn't necessarily be platform dependent, but CPU-dependent. However, every CPU I'm familiar with has different instructions for bit-shifting (x86 uses SHR/SHL) and bit-rotating (ROR/ROL). The latter wraps around bits. The former drops bits and usually sets a carry flag, and that is what GM uses when you use the >>/<< operators.
You seem more familiar with the specifics than me. I know enough to recognize the idea that it is a low-level enough operation to be affected by different platforms, and yes it makes sense that different CPUs would handle it differently too.

Well thankfully we have a tool called a computer that lets us answer these questions:
At the least, this proves what happens on the specific platform/CPU that Roldy is using.
 
You seem more familiar with the specifics than me. I know enough to recognize the idea that it is a low-level enough operation to be affected by different platforms, and yes it makes sense that different CPUs would handle it differently too.
GM using the platform equivalent of ROR/L instead of SHR/L depending on platform would be a massive bug that would need to be fixed immediately. All CPUs I'm aware of for platforms GM supports have dedicated rotate (wrap) instructions. GM bit shift operators do not do that, they do simple arithmetic shifts. If it did otherwise, it would be just as fatal an error as dividing instead of multiplying.

EDIT: Also, the manual section on bitwise operators explicitly states all shifted bits that exceed the size of the variable are dropped.
 
Last edited:

Roldy

Member
At the least, this proves what happens on the specific platform/CPU that Roldy is using.
The 'platform' is irrelevant to the definition. GML operators are logically defined by the language, and the output will be the same independent of hardware or OS. How they get implemented on hardware is irrelevant as long as it implements the language definition. If it doesn't then the implementation is incorrect.

The manual and the runner are your best references. If you can show a inconsistency then report a bug.

BTW: I do believe there is inconsistent output from these operators depending on platform. e.g. HTML5 will produce different output.
 
Last edited:

kburkhart84

Firehammer Games
The 'platform' is irrelevant to the definition. GML operators are logically defined by the language, and the output will be the same independent of hardware or OS. How they get implemented on hardware is irrelevant as long as it implements the language definition. If it doesn't then the implementation is incorrect.
You are 100% right about this. There are a few documented differences in the platforms though, and I'm sure there are a few that aren't documented too.
 

TheouAegis

Member
Am I the only one still curious as to why we even need a value of 2 to the 100th power generated randomly?

Once you get the odd rollover bug sorted out, you just need to make krypt an array and pass it to a custom script that can carry bits.

Code:
var data = argument0;
var c = 0;
var dir = sign(argument1);
repeat abs(argument1) {
   if dir > 0 {
        c = data[@0] >> 63;
        data[@0] = data[@0] << 1;
        data[@1] = data[@1] << 1 | c;
    }
    else {
        c = data[@1] << 63;
        data[@1] = data[@1] >> 1;
        data[@0] = data[@0] >> 1 | c;
    }
}
 
Z

zendraw

Guest
Am I the only one still curious as to why we even need a value of 2 to the 100th power generated randomly?

Once you get the odd rollover bug sorted out, you just need to make krypt an array and pass it to a custom script that can carry bits.

Code:
var data = argument0;
var c = 0;
var dir = sign(argument1);
repeat abs(argument1) {
   if dir > 0 {
        c = data[@0] >> 63;
        data[@0] = data[@0] << 1;
        data[@1] = data[@1] << 1 | c;
    }
    else {
        c = data[@1] << 63;
        data[@1] = data[@1] >> 1;
        data[@0] = data[@0] >> 1 | c;
    }
}
the 2 is so we dont have a 1 and a 0 as a value, the second i dont understand, are you trying to bypass the bitshift falloff thing?
 
its about having variations. basically value 100 variations.
Doesn't work properly using your method when GM's variables are 64-bit signed. 40% of the time it will exceed the limits of the variable and you get the same value (0x00), 1% you'll get a huge negative nunber, and the rest works as you expect.
 

TheouAegis

Member
If you want more than 64 variations (I've had mixed luck with the highest bit being set), you'll need to turn whatever variable you are using into an array and set the higher bits inside the higher indices.
Code:
var r = irandom_range(2,100);
if r < 64
    krypt[0] = 1<<r;
else
    krypt[1] = 1<<(r-64);
or

Code:
//In this case, you'd need to pass the randomly generated number as argument0
var i = argument0 >> 6;
var n = argument0 & $3F;
krypt[@n] = 1 << n;

The code I posted earlier in this thread was for implementing ROL and ROR subroutines.
 
Last edited:

Roldy

Member
its about having variations. basically value 100 variations.
100 variations of what?

The function call irandom_range(1, 100) alone will give you 100 different numbers. Why do you what powers of 2? If you want only even numbers you can just multiply by 2 once.
 
Z

zendraw

Guest
If you want more than 64 variations (I've had mixed luck with the highest bit being set), you'll need to turn whatever variable you are using into an array and set the higher bits inside the higher indices.
Code:
var r = irandom_range(2,100);
if r < 64
    krypt[0] = 1<<r;
else
    krypt[1] = 1<<(r-64);
or

Code:
//In this case, you'd need to pass the randomly generated number as argument0
var i = argument0 >> 6;
var n = argument0 & $3F;
krypt[@n] = 1 << n;

The code I posted earlier in this thread was for implementing ROL and ROR subroutines.
thats just wraping around the bit, you end up again with same number of values. the point is to have more then 62 values based on bits. which is not possible here.

100 variations of what?

The function call irandom_range(1, 100) alone will give you 100 different numbers. Why do you what powers of 2? If you want only even numbers you can just multiply by 2 once.
just look it as value1=red, value2=blue etc. but instead of red we have 32, 64,128,256 and so on.

the main reason for bits is becouse each bit is unique and when compared it returns true only if the other value has that bit.
so comparing 8 & 72 will return true, but 32&72 will return false, but if we add 32 to 72, 32&104 will return true. basicly when we add 32 to our value, its like adding a key to a door in our keychain. now i know i can make an array and so on, but this works and i dont think ill need more then 62, but if i do i guess ill go with arrays.
 

Roldy

Member
You have more than 62 colors that not only need to be distinguished, but also selectable in every possible combination?
If he wants a bitfield then that is what he wants.

I think his original question has been answered about how the shifting works. So he probably has what he needs to continue. It is a curious though.
 

Nidoking

Member
If he wants a bitfield then that is what he wants.
In my experience, "if [x] wants [y]" rarely means "[y] is the appropriate tool for the purpose [x] is using it" and usually means "[x] heard about this cool thing called [y] and is determined to cram it into something, even if [x] has no idea what a [y] is." As it's said, we so often think about whether we can, but we don't stop often enough to think about whether we should.
 

TheouAegis

Member
thats just wraping around the bit, you end up again with same number of values. the point is to have more then 62 values based on bits. which is not possible here.
no, that is not wrapping a bit, that is turning a 64-bit value into a 128-bit value, which is precisely what you would want if you want more than 64 unique values saved into "one variable". This is the same way they handle 32-bit data on 8-bit systems, and the same applies here.
 
Top