GMLscripts.com

Discuss and collaborate on GML scripts
Invert

You are not logged in.

#1 2009-01-02 14:38:39

xDanielx
Member
Registered: 2009-01-02
Posts: 38

Various small issues

Comments on other scripts moved to separate topics

is_even

You're doing it all wrong! It should be

return (~argument0 & 1);

Okay, not really. But actually I did the speed measurements and it turns out that the fastest is

return argument0 mod 2 == 0;

I realize that that's being meticulous beyond all reason, though. Oh, and all the cool kids are doing it this way:

return argument0 ^ 1 & 1;

Last edited by xDanielx (2009-01-05 23:11:52)

Offline

#2 2009-01-05 17:37:48

xot
Administrator
Registered: 2007-08-18
Posts: 1,201

Re: Various small issues

I don't have time to respond right now, but I'll address each of these in the near future. In the meantime, could you please create separate topics for each script as per the rules.

Forum Rules wrote:

If you spot a bug, or a shortcoming, or other issue with a script on GMLscripts.com, post your findings or changes here. The first word in the subject should be the name of the script.


Abusing forum power since 1986.

Offline

#3 2009-01-05 18:27:33

xDanielx
Member
Registered: 2009-01-02
Posts: 38

Re: Various small issues

Okay, will do.

Offline

#4 2009-01-05 21:45:38

xot
Administrator
Registered: 2007-08-18
Posts: 1,201

Re: Various small issues

Even though the is_even() critique "was kind of a joke", there is a reason this script has had so many revisions. A lot of solutions that look good have serious flaws.

return argument0 mod 2 == 0;

That may be fastest, but it can fail in bad ways when the argument is negative, not an integer, or when a real which appears to be an integer has had certain math applied to it.

I'll construct is_odd() similarly:

return argument0 mod 2 == 1;

And here is a script to help us do some tests:

// check_number(n) - displays the evenness and oddness of the given number
if (is_even(argument0)) show_message(string(argument0)+" is even.");
else show_message(string(argument0)+" is not even.");
if (is_odd(argument0)) show_message(string(argument0)+ " is odd.");
else show_message(string(argument0)+" is not odd.");

And here are some problem cases:

// FAILURE - negative numbers
n = -1;
check_number(n);

// FAILURE - certain non-integer floats
n = 2.5;
check_number(n);

// FAILURE - certain floats which appear to be integers
n = 0;
repeat (10) n += 0.1;
check_number(n);

Abusing forum power since 1986.

Offline

#5 2009-01-05 23:10:39

xDanielx
Member
Registered: 2009-01-02
Posts: 38

Re: Various small issues

I realize that "(n mod 2) == 1" doesn't catch negative odd inputs, but "(n mod 2) == 0" should work fine on negative even inputs. If we run some code like this

s = '';

for (i = -10; i <= 10; i += 1/4)
if (i mod 2 == 0)
s += (s != '')*' ' + string(i);

show_message(s);

The output is "-10 -8 -6 -4 -2 0 2 4 6 8 10", which is right.

About non-integers, technically they're considered neither even nor odd which suggests that the current scripts aren't quite correct. Take the current is_odd script for example:

return (n & 1);

If n=1.2, the & operator will round n to the nearest integer (1), and (1 & 1) evaluates to 1, indicating that n is odd, which isn't formally correct. It's probably not too important, as users usually supply integer inputs, but for complete generality I would use

// is_even(n)
return (argument0 mod 2 == 0);
// is_odd(n)
return (abs(argument0) mod 2 == 1);

Both should reject non-integers since (n%2 = 0) and (n%2 = 1) both imply (n%1 = 0). I ran some tests and the results are correct as far as I can tell.

Offline

#6 2009-01-05 23:22:02

xot
Administrator
Registered: 2007-08-18
Posts: 1,201

Re: Various small issues

xDanielx wrote:

I realize that "(n mod 2) == 1" doesn't catch negative odd inputs, but "(n mod 2) == 0" should work fine on negative even inputs. If we run some code like this

s = '';

for (i = -10; i <= 10; i += 1/4)
if (i mod 2 == 0)
s += (s != '')*' ' + string(i);

show_message(s);

The output is "-10 -8 -6 -4 -2 0 2 4 6 8 10", which is right.

Now try the same test with "i += 0.1" as the iterator, or "i += 1/10" if you prefer.

xDanielx wrote:

About non-integers, technically they're considered neither even nor odd which suggests that the current scripts aren't quite correct. Take the current is_odd script for example:

return (n & 1);

If n=1.2, the & operator will round n to the nearest integer (1), and (1 & 1) evaluates to 1, indicating that n is odd, which isn't formally correct.

True, but having a number automatically rounded to the nearest integer and correctly reporting "odd or even" is a useful feature.

xDanielx wrote:

for complete generality I would use

// is_even(n)
return (argument0 mod 2 == 0);
// is_odd(n)
return (abs(argument0) mod 2 == 1);

Both should reject non-integers since (n%2 = 0) and (n%2 = 1) both imply (n%1 = 0). I ran some tests and the results are correct as far as I can tell.

Again, rounding errors make these fail.


Abusing forum power since 1986.

Offline

#7 2009-01-06 00:01:01

xDanielx
Member
Registered: 2009-01-02
Posts: 38

Re: Various small issues

That's true.... I suppose it's a choice between theoretical correctness and practical usability.

Offline

Board footer

Powered by FluxBB