gpujs / gpu.js

GPU Accelerated JavaScript
https://gpu.rocks
MIT License
15.08k stars 650 forks source link

if condition change the value of variables #689

Closed balazsmolnar72 closed 3 years ago

balazsmolnar72 commented 3 years ago

A GIF or MEME to give some spice of the internet

What is wrong?

I wanted to create a random number generator, which generates 6 digit random numbers where a number can be only at a single place. It executes perfectly in Javascript, but when I create a kernel it starts to behave strangely. When I evaluated a condition in an if statement it added unwanted decimals to one of the variables.

Where does it happen?

GPU.js running in a Chrome Browser on a Windows 10 machine

How do we replicate the issue?

Run the code in a Chrome Browser. It always produces the issue.

How important is this (1-5)?

3

Expected behavior (i.e. solution)

Evaluating an if condition should not alter the variables.

Other Comments

The debugging possibilities described in the documentation does not work in these environment. When I add { mode: 'dev'} as a parameter to new GPU() statement It gives an error message when I try to call the kernel: Uncaught TypeError: kernel is not a function

balazsmolnar72 commented 3 years ago
<meta charset="utf-8">
<script src="dist/gpu-browser.min.js"></script>

<script>

noSamples=100;

const gpu = new GPU();

const kernel = gpu.createKernel(function() {

    function isDuplicate(numOfDigits, digit){
        let num=0;      // realized that cannot make a definition and an assignment in the same line
        num=numOfDigits;
        while(num>0){
            if(num%10==digit){
                return 1;
            }
            num=Math.floor(num/10);
        }
        return 0;
    }

    function generateSample(numDigits){
        let number=0;
        let nextDigit=0;

        for(let i=0;i<numDigits;++i){
            while(1>0){  // true simple true condition does not work
                nextDigit=Math.floor(Math.random()*9);
                if(isDuplicate(number, nextDigit)==0){
                    number*=10;
                    number+=nextDigit;
                    break;
                }
            }
        }
        return number;
    }

    return generateSample(7);
}).setOutput([100]);

let samplesArray=kernel();

for(let i=0;i<noSamples;++i){
    document.write(samplesArray[i].toString()+"<br>");
}

</script>
gliu20 commented 3 years ago

Hmm I did some testing and doing a bitwise OR seemed to fix the issue.

Change number+=nextDigit; to number += nextDigit | 0; fixed the issue. Bitwise operators are defined to work only on ints, so doing someNumber | 0 casts that to an int. It's weird that Math.floor didn't seem to work,

gliu20 commented 3 years ago

It looks like in the generated kernel, the compiler infers that your type is a float. But somehow floor doesn't work.

float generateSample(float user_numDigits) {
float user_number=0.0;
float user_nextDigit=0.0;
int user_i=0;
for (int safeI2=0;safeI2<LOOP_MAX;safeI2++){
if (!(user_i<int(user_numDigits))) break;
for (int safeI=0;safeI<LOOP_MAX;safeI++){
if (!(1.0>0.0)) break;
{
user_nextDigit=floor((nrand(vTexCoord)*9.0));if ((isDuplicate(user_number, user_nextDigit)==0.0)){
user_number*=10.0;user_number=user_number;user_number+=user_nextDigit;break;}
}
}

++user_i;}

return user_number;
}

This is the generated kernel with the OR hack.

float generateSample(float user_numDigits) {
float user_number=0.0;
float user_nextDigit=0.0;
int user_i=0;
for (int safeI2=0;safeI2<LOOP_MAX;safeI2++){
if (!(user_i<int(user_numDigits))) break;
for (int safeI=0;safeI<LOOP_MAX;safeI++){
if (!(1.0>0.0)) break;
{
user_nextDigit=floor((nrand(vTexCoord)*9.0));if ((isDuplicate(user_number, user_nextDigit)==0.0)){
user_number*=10.0;user_number=user_number;user_number+=float(bitwiseOr(int(user_nextDigit),0));break;}
}
}

++user_i;}

return user_number;
}

The difference appears to be that the int() function is called when we have the OR hack. I did notice that in the generated kernel, there is no definition for the floor function. Is that expected behavior?

balazsmolnar72 commented 3 years ago

Thanks! I can confirm that the issue with the floating number is eliminated by the OR hack. Thank you!

balazsmolnar72 commented 3 years ago

But even better if I put the OR hack to the line when the random number is generated. nextDigit=Math.floor(Math.random()*9) |0; Since I would like to use this number not only in the addition, but also as an argument of a function, where the float also causes problems. Maybe I can leave out the Math.floor() since it does not work anyway. Thanks for your hint again!

gliu20 commented 3 years ago

No problem! Glad to help!