Discuss and collaborate on GML scripts

You are not logged in.

- Topics: Active | Unanswered

Pages: **1**

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

**Comments on other scripts moved to separate topics**

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

**xot****Administrator**- Registered: 2007-08-18
- Posts: 1,239

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

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

Okay, will do.

Offline

**xot****Administrator**- Registered: 2007-08-18
- Posts: 1,239

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

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

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

**xot****Administrator**- Registered: 2007-08-18
- Posts: 1,239

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

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

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

Offline

Pages: **1**