Pages: 1
Author Topic: "Choose" statement  (92,008 Views)
Offline (Unknown gender) fredcobain

Member
Joined: Apr 2011
Posts: 40
View profile
Posted on: July 03, 2011, 09:15:35 PM
Guys, in GM we have a very usefull built-in function called "choose()";

From GM Help: choose(val1,val2,val3,...) Returns one of the arguments choosen randomly. The function can have up to 16 arguments

I'd like to see some suggestions to perform the same results in Enigma.

Thanks

Fred
Offline (Unknown gender) IsmAvatar

LateralGM Developer
LGM Developer
Joined: Apr 2008
Posts: 877
View profile
Reply #1 Posted on: July 03, 2011, 09:36:24 PM
pigeonhole each of the options, then choose one with random(n). This is a simple but somewhat inefficient way to do it.

A more efficient way to do it would be the same way we plan on implementing max, which also isn't implemented at this point.

max(a) = a
max(a,b) = a > b ? a : b;
max(a,b,c) = max(a,max(b,c));
max(a,b,c,d) = max(a,max(b,max(c,d)))

likewise, instead of doing the > comparator for the secondary base case, you'd simply do a random() > 0.5 type of thing.
Offline (Unknown gender) fredcobain

Member
Joined: Apr 2011
Posts: 40
View profile
Reply #2 Posted on: July 03, 2011, 09:59:37 PM
Quote from: IsmAvatar on July 03, 2011, 09:36:24 PM
pigeonhole each of the options, then choose one with random(n). This is a simple but somewhat inefficient way to do it.

A more efficient way to do it would be the same way we plan on implementing max, which also isn't implemented at this point.

max(a) = a
max(a,b) = a > b ? a : b;
max(a,b,c) = max(a,max(b,c));
max(a,b,c,d) = max(a,max(b,max(c,d)))

likewise, instead of doing the > comparator for the secondary base case, you'd simply do a random() > 0.5 type of thing.

mmm... interesting...

does the functions round() and random() are  is implemented in enigma  (built in) ?

Offline (Unknown gender) Josh @ Dreamland

Prince of all Goldfish
Developer
Joined: Feb 2008
Posts: 2,950
View profile
Reply #3 Posted on: July 03, 2011, 10:13:10 PM
ENIGMA will have one shortly. I need to make modifications to the syntax checker to allow functions to accept enigma::varargs.
Offline (Unknown gender) RetroX

Master of all things Linux
Contributor
Joined: Apr 2008
Posts: 1,055
View profile
Reply #4 Posted on: July 04, 2011, 04:53:55 PM
Quote from: IsmAvatar on July 03, 2011, 09:36:24 PM
pigeonhole each of the options, then choose one with random(n). This is a simple but somewhat inefficient way to do it.

A more efficient way to do it would be the same way we plan on implementing max, which also isn't implemented at this point.

max(a) = a
max(a,b) = a > b ? a : b;
max(a,b,c) = max(a,max(b,c));
max(a,b,c,d) = max(a,max(b,max(c,d)))

likewise, instead of doing the > comparator for the secondary base case, you'd simply do a random() > 0.5 type of thing.
I don't get how this is more efficient.
Offline (Unknown gender) IsmAvatar

LateralGM Developer
LGM Developer
Joined: Apr 2008
Posts: 877
View profile
Reply #5 Posted on: July 06, 2011, 09:45:02 PM
I suppose, yes, pigeonholing, if done right, would be no less efficient than inlines.
Offline (Unknown gender) TheExDeus

Developer
Joined: Apr 2008
Posts: 1,860
View profile
Reply #6 Posted on: July 08, 2011, 03:25:03 PM
Why can't we use stdarg.h? Is this nested max() is really better than this:
double max(int n, ...){
        double max, tmp;
        va_list ap;
        va_start(ap, n);
        max = va_arg(ap, double);
        for(int i = 2; i <= n_args; i++) {
                if((tmp = va_arg(ap, double)) > max)
                        max = tmp;
        }
        va_end(ap);
        return max;
}


edit: Didn't see this:
QuoteENIGMA will have one shortly. I need to make modifications to the syntax checker to allow functions to accept enigma::varargs.
And whats the difference exactly between this and stdarg.h provided functionality? I guess its that Josh's thing uses variants, so I don't need to cast to double or something. So max like this:
max(int 5, double 3.14) would return integer, while this:
max(int 5, double 6) would return a double. Using the simple stdarg would only return doubles or integers.

edit: Also, if doesn't really do what I think it does, then can we finally implement them with stdarg? Its like 10min of work to implement max, min, average, median and so on. Thous are some basic functions I really need.
Offline (Unknown gender) Josh @ Dreamland

Prince of all Goldfish
Developer
Joined: Feb 2008
Posts: 2,950
View profile
Reply #7 Posted on: July 08, 2011, 04:39:23 PM
For starters, HaRRi, stdargs.h will kill the program if you pass it a var or a variant.
Also, good luck getting the argument count.
Offline (Unknown gender) TheExDeus

Developer
Joined: Apr 2008
Posts: 1,860
View profile
Reply #8 Posted on: July 08, 2011, 07:14:12 PM
Quotestdargs.h will kill the program if you pass it a var or a variant.
Yeah, that is what I meant. :D
QuoteAlso, good luck getting the argument count.
Indeed, though if you made compiler parse this:
Quotemax(10,25,34.2);
into this:
Quotemax(4,10,25,34.2);
where the first argument is the argument number, then stdargs.h could be used. You already parse that string into this:max(varargs(), (varargs(), 10, 25, 34.2));, so it seems that you can do it (and arguments are counted anyway for error reporting purposes, but I guess GCC is the one that does it).
Also, it seems that you have implemented the max function, but its chaotic in that definitions in mathc.h and .cpp are not used, but required. So if I delete max(double x,double y){ return fmax(x,y);   }, I will get an error, while the function itself isn't called. Also, it will take only 3 arguments if its written like that. I still need to change it into:
double max(double numbers, ...){} to take any number of arguments and still work.

edit: Also, if max(10,25,34.2) is called then it will return 34, not 34.2.
edit2: And I would want to study your method on how you implemented max, so I can add median and others.
edit3: Also, if it seems I'm just mumbling then ignore me. I'm in a habit of not explaining myself clearly.
Offline (Unknown gender) Josh @ Dreamland

Prince of all Goldfish
Developer
Joined: Feb 2008
Posts: 2,950
View profile
Reply #9 Posted on: July 08, 2011, 07:27:42 PM
max(varargs(), (varargs(), 10, 25, 34.2)); is incorrect; the string should come out as
max((varargs(), 10, 25, 34.2));

But I don't parse that.
#define max(x...) max((varargs(),x))

and #define won't give me the number of arguments passed.

Again, double max(double numbers, ...){} won't work. It will kill the program as soon as the user calls max(somevar,someothervar). That wasn't a joke. It's possible that C++0x offers a functionality to overload an stdargs pass, but I don't know how well it is supported.
Offline (Unknown gender) TheExDeus

Developer
Joined: Apr 2008
Posts: 1,860
View profile
Reply #10 Posted on: July 08, 2011, 08:10:15 PM
Quoteis incorrect; the string should come out as
It still works though.

QuoteAgain, double max(double numbers, ...){} won't work.
That was actually the whole working code. :D I have this in mathnc.h:double max(double n, ...);And this in mathnc.cpp:#include "stdarg.h"
double max(double n, ...){}
So nothing inside the function. And when I do this in EDL:
draw_text(100,100,string(max(12,329,21,343,1000,2981)));It correctly draws 2981. And IDE_EDIT_objectfunctionality.h has it parsed like this:
draw_text(100, 100, toString(max(varargs(), (varargs(), 12, 329, 21, 343, 1000, 2981))));That is why its weird. I don't have any code inside that would actually do the comparing, but it still works. On the other hand if I deleted the code from mathnc.cpp it would trow an error saying that the function max is undefined.
Offline (Unknown gender) Josh @ Dreamland

Prince of all Goldfish
Developer
Joined: Feb 2008
Posts: 2,950
View profile
Reply #11 Posted on: July 08, 2011, 08:16:40 PM
Ah; you've stumbled on a way to make ENIGMA honor max() having unlimited parameters. :P
That's... typically kind of dangerous, but I guess it's as good a hack as any. For the time being, you can implement those functions like this:

Code (C++) Select

variant choose(...);
int choose(const enigma::varargs& args) {
   return args.get(rand() % args.argc);
}
#define choose(x...) choose((varargs(), x))


You must declare and implement choose before defining it. In the source, you may be wise to #undef choose, then implement it. DO NOT implement choose(...); it's too segfault-prone. This way, worst-case scenario is link error, not random abort().
Offline (Unknown gender) RetroX

Master of all things Linux
Contributor
Joined: Apr 2008
Posts: 1,055
View profile
Reply #12 Posted on: July 09, 2011, 02:03:13 AM
It is possible to do choose() with variadic templates, but probably not very efficiently:

template<typename... types>
  double choose(types... vals)
  {
    return choose_impl(random(sizeof...(vals)), vals...);
  }

template<typename... types>
  double choose_impl(unsigned counter, double head, types... vals)
  {
    return counter == 0 ? head : choose_impl(counter - 1, vals...);
  }


Untested, but should work.  And requires the -std=gnu++0x flag.  Also will give very odd errors if you have arguments that can't cast to double.
Offline (Unknown gender) RetroX

Master of all things Linux
Contributor
Joined: Apr 2008
Posts: 1,055
View profile
Reply #13 Posted on: July 11, 2011, 05:45:07 PM
Bump because I thought of a better idea.

Parse choose(x, y, z...) to choose({x, y, z...}).

And have some code:
template<unsigned n> inline double choose(double vals[n])
{
  return vals[random(n)];
}


EDIT: Fix the [tt] tag. :/
Pages: 1