1. Standard library praise and challenge

Just some standard library praise. I was recently working with a library retrieved from the archive that was written pre 4.x. I'm not going to mention the library or author. Anyway, I was working on taking advantage of some of the standard library routines instead of the ones written in the library that accomplish the same task. I ran across ltrim, rtrim and trim. Those methods trim whitespace from the left, right or both sides of a sequence. In the standard library we have trim_head, trim_tail and trim which accomplish the same task, except that they will trim anything you want by using an optional second parameter trim(content, what = " \t\r\n") basically. Anyway... the ones written in the library I was working on were pretty simple and looked fine to me at first glance. However, one benchmark I had setup was parsing a 25mb file using the library.

Stock from the archive the library took 21 seconds to complete. Simply removing the local implementations of ltrim, rtrim and trim and using trim_head, trim_tail and trim instead from the standard library parsing time dropped to 16 seconds. That's a 24% increase in performance by a simple search/replace operation using the new standard library.

This is what the new standard libary is all about. A large collection of group maintained/peer audited/performance tested routines. Not only do we get a large number of common functions to use instead of having each programmer reinvent the wheel with each new project, we also get everyone's head wrapped around a single problem and the very best solution possible.

So... this was just a bit of praise about the standard library but also a challenge to Euphoria users. Look at the source for your favorite standard library routines. Do you see a way they can be improved? Do you see a way to make them faster? Do you see a way to make them more robust? If so, create a ticket and let the development team know! 2 eyes are better than 1, 100 eyes are better than 50.

Jeremy

new topic     » topic index » view message » categorize

2. Re: Standard library praise and challenge

I have wondered for some time. Why do max and min recurse?

Like max({"Head","Tail"}) will give you 'l' but it seems to me you would want the object with the highest value ("Tail") more often then the highest letter ('l').

There must have been a reason for this.

Shawn

new topic     » goto parent     » topic index » view message » categorize

3. Re: Standard library praise and challenge

SDPringle said...

I have wondered for some time. Why do max and min recurse?

They do!? Doesn't sound like a common requirement to me. Now that we have optional arguments, it might be better to have recursive behavior controlled by an argument with the default being NOT to recurse.

new topic     » goto parent     » topic index » view message » categorize

4. Re: Standard library praise and challenge

It would be nice if someone adds these changes to image.e: http://openeuphoria.org/pastey/90.wc

new topic     » goto parent     » topic index » view message » categorize

5. Re: Standard library praise and challenge

SDPringle said...

I have wondered for some time. Why do max and min recurse?

Like max({"Head","Tail"}) will give you 'l' but it seems to me you would want the object with the highest value ("Tail") more often then the highest letter ('l').



I'd say max({"Head","Tail"}) should give you a word, max("HeadTail") should give you a letter.

Likewise, max( { {"2,Tail"} , {"1,Head" } } ) should return a sequence.

SDPringle said...

There must have been a reason for this.

Shawn



I wouldn't bet on that.

useless

new topic     » goto parent     » topic index » view message » categorize

6. Re: Standard library praise and challenge

I am seeing most people describing the functions max and min I wrote myself. I ask you though, what should happen when you pass an empty sequence?

    1. Undefined results
    2. Die with an error message
    3. Return the 'biggest value' or the 'smallest value'.

In the last option, though arguably impossible for real life numbers, the standard library set max({}) to be the smallest representable number, and min({}) the largest representable number. I never liked that behavior either and it is impossible to return the largest representable object. Well, there is a way (in C), but you wouldn't want such a monster to exist.

Shawn Pringle

new topic     » goto parent     » topic index » view message » categorize

7. Re: Standard library praise and challenge

SDPringle said...

I am seeing most people describing the functions max and min I wrote myself. I ask you though, what should happen when you pass an empty sequence?

    1. Undefined results
    2. Die with an error message
    3. Return the 'biggest value' or the 'smallest value'.

I'm not sure, although that's not really what people are asking about. Let's look at max:

public function max(object a) 
	atom b, c 
	if atom(a) then 
		return a 
	end if 
	b = mathcons:MINF 
	for i = 1 to length(a) do 
		c = max(a[i]) 
		if c > b then 
			b = c 
		end if 
	end for 
	return b 
end function 

I can see what this is getting at. We're in math.e, and the intent is to deal with atoms only. From that perspective it makes sense, although I wonder how often it would really be used for that purpose.

An alternate is to add a more simple, but intuitive, routine, possibly in sequence.e. This other routine would simply do a compare() against each element, starting with the first. I guess the default return would probably be an empty sequence for that routine.

Matt

new topic     » goto parent     » topic index » view message » categorize

8. Re: Standard library praise and challenge

I would expect max/min to apply to top-level elements only.

So...

max( { "Head", "Tail" } ) -- "Tail" since it is higher alphabetically 
max( { 1, 2, 3 } ) -- 3 
max( {} ) -- Error condition 
max( { {1}, {2} } ) -- {2} 
max( { {1,{1}}, {1,{2}} } ) -- {1,{2}} 
max( { 1, {1} } ) -- 1? now we're getting somewhere :) 

To search deep like the current max() does for the largest atom can be useful but seems to be counter-intuitive. Maybe a max_deep() or something should do this instead so max() can get back its common intent.

new topic     » goto parent     » topic index » view message » categorize

9. Re: Standard library praise and challenge

SDPringle said...

I am seeing most people describing the functions max and min I wrote myself. I ask you though, what should happen when you pass an empty sequence?

I give you an empty bag and ask you to pull out the largest object. You can't pull out any object so therefore this is an error. The results are defined - you pull nothing out, which is of course neither the biggest nor the smallest, thus we have a problem - also known as an error situation. One way to signal this error is to just give back the bag.

It's clear that math:max() is intended to only work with numbers, but I think we need max/min functions that work with objects too.

public function max(object a) 
    object b,c 
 
    if atom(a) then 
        return a 
    end if 
 
    if length(a) = 0 then 
        return a 
    end if 
 
    b = a[1] 
    for i = 2 to length(a) do 
        c = a[i] 
        if compare(c, b) > 0 then 
            b = c 
        end if 
    end for 
 
    return b 
end function 
new topic     » goto parent     » topic index » view message » categorize

10. Re: Standard library praise and challenge

Also with this recursing property is sum, product and or_all.

Just like max and min, these also recurse so that for any sequence s, sum(s) has the same value as sum(flatten(s)).

new topic     » goto parent     » topic index » view message » categorize

11. Re: Standard library praise and challenge

I don't see max or min of null ({}) being an error.

The max is as the min, {} (null).

The max and min of { {}, {'a'} } should be {'a'} as null cannot be less than or greater than another value.

- as in SQL.

new topic     » goto parent     » topic index » view message » categorize

12. Re: Standard library praise and challenge

bill said...

I don't see max or min of null ({}) being an error.

The empty sequence construct is not null. It is not the same as the NULL concept found in database systems. It is simply a set with no elements, a list with no items, a bag with nothing inside.

Given an empty bag, pick out the largest object.

new topic     » goto parent     » topic index » view message » categorize

13. Re: Standard library praise and challenge

SDPringle said...

Also with this recursing property is sum, product and or_all.

Just like max and min, these also recurse so that for any sequence s, sum(s) has the same value as sum(flatten(s)).

For maths library, maybe this make sense (I'm not fully convinced of that yet, by the way), but it not always the intuitive result. For example, given a list that contains a mixture of numbers and strings, return the sum of that list. Most spreadsheet programs ignore non-numbers in the summing range, so maybe that's what people expect to happen.

new topic     » goto parent     » topic index » view message » categorize

14. Re: Standard library praise and challenge

DerekParnell said...
bill said...

I don't see max or min of null ({}) being an error.

The empty sequence construct is not null. It is not the same as the NULL concept found in database systems. It is simply a set with no elements, a list with no items, a bag with nothing inside.

Given an empty bag, pick out the largest object.

That's easy, no? From an empty bag the largest object is nothing.

max({}) -- {} 
min({}) -- {} 

Jeremy

new topic     » goto parent     » topic index » view message » categorize

15. Re: Standard library praise and challenge

bill said...

I don't see max or min of null ({}) being an error.

Same here.

DerekParnell said...

The empty sequence construct is not null. It is not the same as the NULL concept found in database systems. It is simply a set with no elements, a list with no items, a bag with nothing inside.

jeremy said...

That's easy, no? From an empty bag the largest object is nothing.

Yep, except for the small hitch that Euphoria has no object or singleton that can unambiguously represent 'nothing' or the NULL concept in general.

jeremy said...
max({}) -- {} 
min({}) -- {} 

Jeremy

Like Derek said, the empty sequence is not nothing. But he also said

DerekParnell said...

I give you an empty bag and ask you to pull out the largest object. You can't pull out any object so therefore this is an error. The results are defined - you pull nothing out, which is of course neither the biggest nor the smallest, thus we have a problem - also known as an error situation. One way to signal this error is to just give back the bag.

And I, while wishing to clarify that the empty sequence is not nothing, agree with both Jeremy and Derek on this.

Of course, this is not perfect.

max({{}, {}}) -- returns {} also 

But that's close enough for me. If it really matters, I'd just do an "is_empty" check on the original sequence after calling max()/min().

new topic     » goto parent     » topic index » view message » categorize

16. Re: Standard library praise and challenge

Insolor said...

It would be nice if someone adds these changes to image.e: http://openeuphoria.org/pastey/90.wc

If no one else beats me to it, I'll review it and probably apply the patch sometime today.

new topic     » goto parent     » topic index » view message » categorize

17. Re: Standard library praise and challenge

Insolor said...

It would be nice if someone adds these changes to image.e: http://openeuphoria.org/pastey/90.wc

If no one else beats me to it, I'll review it and probably apply the patch sometime today.

new topic     » goto parent     » topic index » view message » categorize

18. Re: Standard library praise and challenge

One can say {} is the empty sequence. True.

However that is not the case when you are comparing atoms. {} has no atom, nothing, NULL. Hence when the sequence is flattened the empty sub-sequences disappear (just as in SQL, NULLs are ignored).

It leaves the problem of what to do with max(NULL) and min(NULL). They should return nothing ({} or NAN). It is odd to call it an error since this would imply that min({{},1}) should also be an error as it is saying:

"which is smaller nothing or 1?"

Note the (inconsistent) treatment of NULL by compare:

include std/math.e 
 
 1: ? compare(MINF,MINF)             0 
 2: ? compare(MINF,min({}))         -1 * 
 3: ? compare(MINF,max({}))          0 ** 
 4: ? compare(MINF,PINF)            -1 
 5: ? compare(min({}),MINF)          1 * 
 6: ? compare(min({}),min({})        0 
 7: ? compare(min({}),max({}))       1 ** 
 8: ? compare(min({}),PINF)          0 ** 
 9: ? compare(max({}),MINF)          0 ** 
10: ? compare(max({}),min({}))      -1 ** 
11: ? compare(max({}),max({}))       0 
12: ? compare(max({}),PINF)          0 * 
13: ? compare(PINF,MINF)             1 
14: ? compare(PINF,min({}))          0 ** 
15: ? compare(PINF,max({}))          1 * 
16: ? compare(PINF,PINF)             0 
new topic     » goto parent     » topic index » view message » categorize

19. Re: Standard library praise and challenge

bill said...

One can say {} is the empty sequence. True.

However that is not the case when you are comparing atoms.

Which is not the case for the (proposed) max() and min() in std/sequence.e

bill said...

Note the (inconsistent) treatment of NULL by compare:

This is not inconsistent. The current implementation of max() and min() in std/math.e do not return a value representing NULL - they always return a valid atom.

Should they return NULL? Maybe. Currently, they don't.

new topic     » goto parent     » topic index » view message » categorize

20. Re: Standard library praise and challenge

bill said...

One can say {} is the empty sequence. True.

However that is not the case when you are comparing atoms. {} has no atom, nothing, NULL. Hence when the sequence is flattened the empty sub-sequences disappear (just as in SQL, NULLs are ignored).

I can see what you're saying but one must not mistake an empty list for NULL. It really is not the same thing in Euphoria. While Euphoria does have a true NULL value, it is only used internally and we do not expose it to the coder. The NOVALUE value is not settable nor does the coder have a way to test for it. Maybe we should make this available for coders to use?

bill said...

It leaves the problem of what to do with max(NULL) and min(NULL). They should return nothing ({} or NAN). It is odd to call it an error since this would imply that min({{},1}) should also be an error as it is saying:

"which is smaller nothing or 1?"

I see the problem of min({{},1}) differently. To me this is saying, of all the atoms in the argument, which is the smallest. In this case, the answer is 1 because that is the only atom in the argument.

Likewise, min({}) is also saying, of all the atoms in the argument, which is the smallest. In this case, the question is meaningless because there are no atoms in the argument. That is why I'm saying that this situation needs to return a value that means that nothing can be returned.

new topic     » goto parent     » topic index » view message » categorize

21. Re: Standard library praise and challenge

DerekParnell said...

The NOVALUE value is not settable nor does the coder have a way to test for it. Maybe we should make this available for coders to use?

Actually, it can be tested! Use the object type. It might be good to allow euphoria code to explicitly use this. Also, I noticed that we're missing NaN in our math constants.

Matt

new topic     » goto parent     » topic index » view message » categorize

22. Re: Standard library praise and challenge

max({}) returns inf, max(1) returns 1

min({}) returns -inf, min(1) returns 1

IE max(atom x) = min(atom x): there is a problem here.

Comparing: min({}) > max({}), max({}) = MINF, min({}) = PINF, MINF < PINF.

This is all nonsense.

To be consistent min({}) and max({}) have to return the same non-value. A consistent mathematical result would be NAN or simply nothing - but one presumes that a function returns something.

By definition NAN: is not equal to NAN and NAN is not not equal to NAN. Like NULLs, NANs cannot be compared.

With sequences there are the possibiliites of an empty sequence (empty string) or NULL. An empty sequence can be compared. A NULL sequence cannot be compared (a sequence without a value assigned is an example).

new topic     » goto parent     » topic index » view message » categorize

23. Re: Standard library praise and challenge

bill said...

With sequences there are the possibiliites of an empty sequence (empty string) or NULL. An empty sequence can be compared. A NULL sequence cannot be compared (a sequence without a value assigned is an example).

We don't have "NULL sequences", whatever those are. We only have empty sequences.

bill said...

max({}) returns inf, max(1) returns 1

min({}) returns -inf, min(1) returns 1

IE max(atom x) = min(atom x): there is a problem here.

Comparing: min({}) > max({}), max({}) = MINF, min({}) = PINF, MINF < PINF.

This is all nonsense.

To be consistent min({}) and max({}) have to return the same non-value. A consistent mathematical result would be NAN or simply nothing - but one presumes that a function returns something.

By definition NAN: is not equal to NAN and NAN is not not equal to NAN. Like NULLs, NANs cannot be compared.

This works for me. I can live with math.e's max()/min() returning NaN when given {} as input.

new topic     » goto parent     » topic index » view message » categorize

24. Re: Standard library praise and challenge

bill said...

To be consistent min({}) and max({}) have to return the same non-value. A consistent mathematical result would be NAN or simply nothing - but one presumes that a function returns something.

By definition NAN: is not equal to NAN and NAN is not not equal to NAN. Like NULLs, NANs cannot be compared.

With sequences there are the possibiliites of an empty sequence (empty string) or NULL. An empty sequence can be compared. A NULL sequence cannot be compared (a sequence without a value assigned is an example).

Exactly! The current implementation is not correct. However, Euphoria doesn't yet have a NaN that we can use. We should implement such a concept, even though it is not quite that easy to do well. If NaN can be an valid value in an expression or parameter, it affects lots of existing code.

new topic     » goto parent     » topic index » view message » categorize

25. Re: Standard library praise and challenge

DerekParnell said...

However, Euphoria doesn't yet have a NaN that we can use. We should implement such a concept, even though it is not quite that easy to do well. If NaN can be an valid value in an expression or parameter, it affects lots of existing code.

I'm a bit confused. We might not have a constant in std/math.e or elsewhere, but we can do it:

constant NaN=-(2*power(10,308)/(3*power(10,308))) 
new topic     » goto parent     » topic index » view message » categorize

26. Re: Standard library praise and challenge

DerekParnell said...

However, Euphoria doesn't yet have a NaN that we can use. We should implement such a concept, even though it is not quite that easy to do well. If NaN can be an valid value in an expression or parameter, it affects lots of existing code.

I think the way to do this is to use the architecture appropriate floating point representation of NaN, similar to how we define the infinities, and expose it as a machine func via mathcons.e

Matt

new topic     » goto parent     » topic index » view message » categorize

27. Re: Standard library praise and challenge

jimcbrown said...
-- nan.ex 
constant NaN=-(2*power(10,308)/(3*power(10,308))) 
? NaN 

It's not working! sad

$ eui nan.ex 
-0.6666666667 

Matt

new topic     » goto parent     » topic index » view message » categorize

28. Re: Standard library praise and challenge

mattlewis said...
jimcbrown said...
-- nan.ex 
constant NaN=-(2*power(10,308)/(3*power(10,308))) 
? NaN 

It's not working! sad

$ eui nan.ex 
-0.6666666667 

Matt

Hmmm... works for me.

C:\temp>type nan.ex 
constant NaN=-(2*power(10,308)/(3*power(10,308))) 
? NaN 
? 3 + NaN 
 
function tn(object a) 
  return a * 2 
end function 
? tn(NaN) 
C:\temp>eui nan.ex 
nan 
nan 
nan 
 
C:\temp>eui --version 
Euphoria Interpreter v4.0.4 development 
   Windows, Using System Memory 
   Revision Date: 2011-08-05 12:12:11, Id: 5095:8351f54dd765 
 
C:\temp> 

new topic     » goto parent     » topic index » view message » categorize

29. Re: Standard library praise and challenge

DerekParnell said...
mattlewis said...
jimcbrown said...
-- nan.ex 
constant NaN=-(2*power(10,308)/(3*power(10,308))) 
? NaN 

It's not working! sad

$ eui nan.ex 
-0.6666666667 

Matt

Hmmm... works for me.

Sorry, that was my snarky way of saying that it's not a portable way to get a NaN. We use bigger floating point numbers for 64-bit euphoria, and 10e308 is a lot smaller than 1.19e4932. smile

Matt

new topic     » goto parent     » topic index » view message » categorize

30. Re: Standard library praise and challenge

mattlewis said...
jimcbrown said...
-- nan.ex 
constant NaN=-(2*power(10,308)/(3*power(10,308))) 
? NaN 

It's not working! sad

$ eui nan.ex 
-0.6666666667 

Matt

It works for me on 32bit. Try this on 64bit.

-- nan.ex 
constant NaN=(2*power(10,9008)/(3*power(10,9008))) 
? NaN 
new topic     » goto parent     » topic index » view message » categorize

31. Re: Standard library praise and challenge

jimcbrown said...
-- nan.ex 
constant NaN=(2*power(10,9008)/(3*power(10,9008))) 
? NaN 

That gives me -nan.

Matt

new topic     » goto parent     » topic index » view message » categorize

32. Re: Standard library praise and challenge

mattlewis said...

Sorry, that was my snarky way of saying that it's not a portable way to get a NaN. We use bigger floating point numbers for 64-bit euphoria, and 10e308 is a lot smaller than 1.19e4932. smile

Matt

If only I was 104 seconds faster!

new topic     » goto parent     » topic index » view message » categorize

33. Re: Standard library praise and challenge

mattlewis said...
jimcbrown said...
-- nan.ex 
constant NaN=(2*power(10,9008)/(3*power(10,9008))) 
? NaN 

That gives me -nan.

Matt

Ok, I'm stumped.

new topic     » goto parent     » topic index » view message » categorize

34. Re: Standard library praise and challenge

jimcbrown said...
mattlewis said...
jimcbrown said...
-- nan.ex 
constant NaN=(2*power(10,9008)/(3*power(10,9008))) 
? NaN 

That gives me -nan.

Matt

Ok, I'm stumped.

The representation of what you created is:

{0,0,0,0,0,0,0,192,255,255} 

The sign bit is set, hence the negative. "Positive" NaN is:

{0,0,0,0,0,0,0,192,255,127} 

Matt

new topic     » goto parent     » topic index » view message » categorize

35. Re: Standard library praise and challenge

mattlewis said...
jimcbrown said...
mattlewis said...
jimcbrown said...
-- nan.ex 
constant NaN=(2*power(10,9008)/(3*power(10,9008))) 
? NaN 

That gives me -nan.

Matt

Ok, I'm stumped.

The representation of what you created is:

{0,0,0,0,0,0,0,192,255,255} 

The sign bit is set, hence the negative. "Positive" NaN is:

{0,0,0,0,0,0,0,192,255,127} 

Matt

I understand the difference, but I'm still clueless on how to create positive NaN. Surely it's not as simple as multiplying by -1 ?

new topic     » goto parent     » topic index » view message » categorize

36. Re: Standard library praise and challenge

jimcbrown said...

I understand the difference, but I'm still clueless on how to create positive NaN. Surely it's not as simple as multiplying by -1 ?

I think you can do stuff like sqrt(-1) (assuming you have exceptions or whatever turned off correctly). The right way is to use whatever the language provides. GCC, for instance, provides a NAN macro (on machines that support NANs in the first place). For recent enough versions, they use __builtin_nanf:

// gcc nan.c -o nan 
 
#include <stdio.h> 
#include <math.h> 
 
int main(){ 
	long double ld; 
	double d; 
	d = NAN; 
	ld = NAN; 
	printf("%lg %Lg\n", d, ld ); 
	return 0; 
} 

$ gcc nan.c -o nan && ./nan 
nan nan 

The headers define floats by explicit bytes for older versions of gcc.

Matt

new topic     » goto parent     » topic index » view message » categorize

37. Re: Standard library praise and challenge

mattlewis said...
jimcbrown said...

I understand the difference, but I'm still clueless on how to create positive NaN. Surely it's not as simple as multiplying by -1 ?

I think you can do stuff like sqrt(-1) (assuming you have exceptions or whatever turned off correctly).

I was looking for a quick series of mathematical functions that'd work as-in in 4.0 and 4.1 that would do the job, to prove a point.

(sqrt(-1) does not work in 4.0, btw).

mattlewis said...

The right way is to use whatever the language provides.

Agreed. Above all, I was trying to avoid this:

mattlewis said...

The headers define floats by explicit bytes for older versions of gcc.

Anyways, back to my original point: NaN and Nothing are conceptually separate values. NaN is a floating point number with a specific set of representations that are defined as the value of certain floating point operations (such as sqrt(-1) or fdiv(inf, inf)).

While it may make sense for NaN to be the output of std/math.e's min() and max() and sum() and perhaps even or_all() when they are given an empty sequence as input, NaN does not work the same way as our NOVALUE (or even Python's Nothing object).

new topic     » goto parent     » topic index » view message » categorize

38. Re: Standard library praise and challenge

jimcbrown said...

Anyways, back to my original point: NaN and Nothing are conceptually separate values.

Yes, I totally agree. I just noticed that NaN was missing from our collection of constants.

jimcbrown said...

While it may make sense for NaN to be the output of std/math.e's min() and max() and sum() and perhaps even or_all() when they are given an empty sequence as input, NaN does not work the same way as our NOVALUE (or even Python's Nothing object).

I wouldn't use NaN for that (ideally). I'd prefer to use NOVALUE. I suppose one issue we have with that is the way we currently check for initialized values, which is to say, as little as possible. Allowing NOVALUE to be used explicitly would cause all sorts of new bugs.

OTOH, if you're passing an empty sequence to max/min, then you probably have a bug in your code already.

Matt

new topic     » goto parent     » topic index » view message » categorize

39. Re: Standard library praise and challenge

jimcbrown said...

I understand the difference, but I'm still clueless on how to create positive NaN. Surely it's not as simple as multiplying by -1 ?

Does this work for you guys?

include std/convert.e 
constant NaN= float64_to_atom({0,0,0,0,0,192,255,127}) 
? NaN 
? 3 + NaN 
 
function tn(object a) 
  return a * 2 
end function 
? tn(NaN) 
new topic     » goto parent     » topic index » view message » categorize

40. Re: Standard library praise and challenge

DerekParnell said...

Does this work for you guys?

include std/convert.e 
constant NaN= float64_to_atom({0,0,0,0,0,192,255,127}) 
? NaN 
? 3 + NaN 
 
function tn(object a) 
  return a * 2 
end function 
? tn(NaN) 

I get all nans on 4.1 64-bit.

Matt

new topic     » goto parent     » topic index » view message » categorize

41. Re: Standard library praise and challenge

DerekParnell said...

Does this work for you guys?

include std/convert.e 
constant NaN= float64_to_atom({0,0,0,0,0,192,255,127}) 
? NaN 
? 3 + NaN 
 
function tn(object a) 
  return a * 2 
end function 
? tn(NaN) 

I get nan's.

C:\Development\Projects>eui test.ex 
nan 
nan 
nan 
 
C:\Development\Projects>eui -v 
Euphoria Interpreter v4.1.0 development 
   32-bit Windows, Using System Memory 
   Revision Date: 2011-09-09 18:29:16, Id: 5145:0da3aad80586 

new topic     » goto parent     » topic index » view message » categorize

42. Re: Standard library praise and challenge

mattlewis said...
jimcbrown said...
-- nan.ex 
constant NaN=-(2*power(10,308)/(3*power(10,308))) 
? NaN 

It's not working! sad

mattlewis said...
jimcbrown said...
-- nan.ex 
constant NaN=(2*power(10,9008)/(3*power(10,9008))) 
? NaN 

That gives me -nan.

Matt

Bit late, but there's no '-' in the second expression. The float64_to_atom is probably faster anyway.

Pete

new topic     » goto parent     » topic index » view message » categorize

43. Re: Standard library praise and challenge

It would surprise me that a programmer without enough forethought to check to see if a sequence has no length (or ensure it always has some length) before calling min() or max() will have forethought to check for an error code. In the case where a programmer is not diligent, whatever that error code is for passing {}, be it, the bag({}), NaN, PINF, NINF, or "WTF", will be used in the next calculation as if everything is till okay.

Most recently, I was interested in what the maximum tension on a joint inside of a truss system for choosing the kind of joint one should use. The error value would be used to determine what joint type to use. Logical errors propagate through the code until the program says that the weakest joint is okay to use.

This following is an abbreviation of what I wrote for my private library and I use it myself. If you don't want to check for errors you turn type checking off. max and min assume that s[1] exists. There is no need to return nan, PINF, NINF, or "".

type nonemptysequence(sequence s) 
    return length(s) != 0 
end type 
 
function max(nonemptysequence s) 
... 
 
function min(nonemptysequence s) 
... 

Shawn Pringle

new topic     » goto parent     » topic index » view message » categorize

44. Re: Standard library praise and challenge

SDPringle said...

It would surprise me that a programmer without enough forethought to check to see if a sequence has no length (or ensure it always has some length) before calling min() or max() will have forethought to check for an error code. In the case where a programmer is not diligent, whatever that error code is for passing {}, be it, the bag({}), NaN, PINF, NINF, or "WTF", will be used in the next calculation as if everything is till okay.

Most recently, I was interested in what the maximum tension on a joint inside of a truss system for choosing the kind of joint one should use. The error value would be used to determine what joint type to use. Logical errors propagate through the code until the program says that the weakest joint is okay to use.

This following is an abbreviation of what I wrote for my private library and I use it myself. If you don't want to check for errors you turn type checking off. max and min assume that s[1] exists. There is no need to return nan, PINF, NINF, or "".

type nonemptysequence(sequence s) 
    return length(s) != 0 
end type 
 
function max(nonemptysequence s) 
... 
 
function min(nonemptysequence s) 
... 

Shawn Pringle

Seconded.

new topic     » goto parent     » topic index » view message » categorize

45. Re: Standard library praise and challenge

Of course I'm still smarting that max(sequence s) exists at all.

It should be max_sq(sequence s) and max(atom,atom).

Pete

new topic     » goto parent     » topic index » view message » categorize

46. Re: Standard library praise and challenge

petelomax said...

It should be max_sq(sequence s) and max(atom,atom).

Or even just maxs(sequence s) and max(atom,atom). In line with puts() gets() etc...

new topic     » goto parent     » topic index » view message » categorize

47. Re: Standard library praise and challenge

euphoric said...
petelomax said...

It should be max_sq(sequence s) and max(atom,atom).

Or even just maxs(sequence s) and max(atom,atom). In line with puts() gets() etc...

Or...

public function max( object a, object b = a ) 
    if atom(a) then 
        if a >= b then 
            return a 
        else 
            return b 
        end if 
    end if 
    b = mathcons:MINF 
    atom c 
    for i = 1 to length(a) do 
        c = max(a[i]) 
        if c > b then 
            b = c 
    end if 
    end for 
    return b 
end function 

Matt

new topic     » goto parent     » topic index » view message » categorize

48. Re: Standard library praise and challenge

mattlewis said...
euphoric said...
petelomax said...

It should be max_sq(sequence s) and max(atom,atom).

Or even just maxs(sequence s) and max(atom,atom). In line with puts() gets() etc...

Or...

public function max( object a, object b = a ) 
    if atom(a) then 
        if a >= b then 
            return a 
        else 
            return b 
        end if 
    end if 
    b = mathcons:MINF 
    atom c 
    for i = 1 to length(a) do 
        c = max(a[i]) 
        if c > b then 
            b = c 
    end if 
    end for 
    return b 
end function 

Matt

But then what happens if I do

? max("First", "Second") 
new topic     » goto parent     » topic index » view message » categorize

49. Re: Standard library praise and challenge

jimcbrown said...

But then what happens if I do

? max("First", "Second") 

Under that, you'd get the max of "First". I would have documented that the function was to be used in the ways that Pete was looking for, which make sense as a math function, to me. Your use appears to be looking for the general object comparison, which I think we were saying should be somewhere else.

Matt

new topic     » goto parent     » topic index » view message » categorize

50. Re: Standard library praise and challenge

mattlewis said...

Your use appears to be looking for the general object comparison, which I think we were saying should be somewhere else.

We already have smaller_of(object,object) and larger_of(object,object)

new topic     » goto parent     » topic index » view message » categorize

51. Re: Standard library praise and challenge

DerekParnell said...
mattlewis said...

Your use appears to be looking for the general object comparison, which I think we were saying should be somewhere else.

We already have smaller_of(object,object) and larger_of(object,object)

I thought so! But I couldn't remember those names. I don't spend enough time in the stdlib. I was looking for greatest/greater/bigger.

Matt

new topic     » goto parent     » topic index » view message » categorize

52. Re: Standard library praise and challenge



As if it mattered, i believe NULL = NULL. If i have nothing in both paws, then i have the same amount of the same nothing in both paws, ergo the contents of both paws are equal. I understand NULL != zero, but i didn't define what i have nothing of in my paws, if i have "no worms" then i have zero worms, and that's not NULL.

But NaN is not the same, as if x = "blah", y = burb", x is NaN , y is a NaN, but they are different NaNs. If you are not in the right include file to deal with x and y, best you can return is their commonality, in math.e (or whatever) math.compare(x,y) = NaN. But it's not NULL, they are something, but in math.e the comparison may be illogical (or maybe it isn't). Doing this in string.e would give a different answer.

If i asked for the pointer to a function, and you gave me NULL, i believe the function does not exist. But if you give me NaN, then i believe you made an error.

useless, naturally

new topic     » goto parent     » topic index » view message » categorize

53. Re: Standard library praise and challenge

There seems to be very divergent opinions on what should happen with max

Mine are:

max(atom) => typecheck error 
max({})   => typecheck error 
max({4,32,2}) => 32 
max({"Ax",'a'}) => "Ax" 
max({"Ursula","Susan","Barbara"}) => "Ursula" 

Similar results with min. sum and product should work as if you string the members with separators + and * respectively. or_all should work as if you run or_bits(..,or_bits(..., ... ) on the members. The members of a sequence s are defined as s[1], s[2], ... , s[$]. Fortunately, we have namespaces and we can roll our own function definitions.

Shawn Pringle

new topic     » goto parent     » topic index » view message » categorize

54. Re: Standard library praise and challenge

removed

new topic     » goto parent     » topic index » view message » categorize

55. Re: Standard library praise and challenge

Re

type nonemptysequence(sequence s)  
    return length(s) != 0  
end type  
  
function max(nonemptysequence s)  
...  
  
function min(nonemptysequence s)  
... 

no good

nonemptysequence S = { {} } 
 
length(S) is 1 
 
max(S) is -inf 
new topic     » goto parent     » topic index » view message » categorize

56. Re: Standard library praise and challenge

Start with 'a' < {}.

This can only make sense if 'a' and {} are of the same type (object).

We have an order:

  MIN_REAL,..,MAX_REAL,{},{MIN_REAL},..,{MAX_REAL},{ {} },.. 

Max is declared to be max(object a) and returns the maximum atom of the flattened list.

Given this max({}) is an error as is max({}} and max({ {},{} }) even though they are valid lists.

A general form of max() would be max(sequence S) where S is a list of objects (possibly empty).

An empty list would then return an empty list; a non-empty list would return a list containing its maximum element. Min() would work similarly.

Examples:

 max({})             ==> {} 
 max({ {} })         ==> { {} } 
 max({ {},{} }       ==> { {} } 
 max({"head","tail"} ==> {"tail"} 
 max("head")         ==> ('h') 

That, I hope covers it.

new topic     » goto parent     » topic index » view message » categorize

57. Re: Standard library praise and challenge

I want to clarify that the special cases for max and min that I described here were not meant to be descriptions of the standard library functions max and min. Rather, what functions with these names in my private library return and what they should return according to my philosophy.

The standard library returns some value for max{} and min{}. It flattens its argument. Meaning max({{24,4},{400}}) is the same as max({24,4,400}) in the standard library.

The ones I developed error out when passed an atom or an empty sequence. It doesn't flatten its argument. You can find a maximum or minimum object of a sequence of elements. The arguments may all be strings or matrices.

My max and min were developed separately before I joined this project and the existing max and mins in the standard library were already there when I joined. AFAIK.

Shawn Pringle

new topic     » goto parent     » topic index » view message » categorize

58. Re: Standard library praise and challenge

I agree that the library max function is no good.

I could understand someone writing max(flatten(S)) if that is what they wanted to do (why?). I don't understand why the argument to max should be flattened as part of the max function. It makes nonsense of the sort order of object.

I don't have a problem about returning the max of {} or the max of a number because max(3,3) is 3 and max({3}) is 3. I would rather max didn't return an error unless it had to (eg max()).

My function is:

  function max(sequence S) 
 
  -- accepts a (possibly empty) sequence of objects 
  -- returns either an 0 length list or a list containing the maximum item in the list 
 
    if length(S) < 2 then return S  
    else 
      sequence R = S[1] 
      for i = 2 to length(S) do 
        if S[i] > R[1] then R[1] = S[i] end if 
      end for 
      return R 
    end if 
  end function 
 
  max({1,2,3,4})  ==> {4} 
  max({ {},{} })  ==> { {} } 
  max({1,2,{0} }) ==> { {0} } 
  max({})         ==> { } 

All are exactly what you would expect, except (perhaps) for the last. And, returning the empty list as the max of an empty list is logical and should give no one headaches.

Bill

new topic     » goto parent     » topic index » view message » categorize

59. Re: Standard library praise and challenge

I think Bill, Jim, Derek and I are in agreement of what max() and conversely min() should do when the list is not empty. When the list is empty is result is rather academic from my point of view.

Condier though:

    1. EUPHORIA's routines tend to die rather than give an error code when given bad parameters. Let's be consistent here. In general I prefer to see an error code but there is no way to tell an error code from a result here.
    2. Certainly, the idea of what a maximum of the empty set is undefined.
    3. It follows that the interpreter should die in this case.

Consider division by 0. There is no NaN returned. It dies, instead. This is the way the work is designed. Instead of going off into different directions we should try to keep with the same design principles.

Shawn Pringle

new topic     » goto parent     » topic index » view message » categorize

60. Re: Standard library praise and challenge

SDPringle said...
    1. EUPHORIA's routines tend to die rather than give an error code when given bad parameters. Let's be consistent here. In general I prefer to see an error code but there is no way to tell an error code from a result here.

I think value() provides an error code, so there is a precedent.

result = { [NOT] SUCCESS, 23 } -- one way to do it 

I suspect Derek expects an exceptions feature to eventually handle all this, but for now...?

new topic     » goto parent     » topic index » view message » categorize

61. Re: Standard library praise and challenge

euphoric said...
SDPringle said...
    1. EUPHORIA's routines tend to die rather than give an error code when given bad parameters. Let's be consistent here. In general I prefer to see an error code but there is no way to tell an error code from a result here.

I think value() provides an error code, so there is a precedent.

result = { [NOT] SUCCESS, 23 } -- one way to do it 

I suspect Derek expects an exceptions feature to eventually handle all this, but for now...?

I am not in favor of the radical change in the type of return value.

Consider this:

The input to value() could come from anywhere. When value() returned an error code, that signalled a problem but the code could still continue. E.g. if you use value() to get a number but the user types "hello world" instead, you can prompt the user to reenter the number.

This sort of error is recoverable, and can not easily be validated by the calling code (at least, not without duplicating much of the functionality of value() itself).

The sole error with max()/min() can be checked for easily (a simple length check and possibly a type check to make sure it's a sequence) - and as Matt and Shawn and others have pointed out, it's an error that usually signifies a greater problem in the calling code - one that's probably irrecoverable beyond closing all open files, showing the appropriate prompt to the user, and then dying gracefully.

Also, this is a very minor point, but consider anyways:

value() has multiple error codes (well, 2 - failure and eof) whereas we only have the one for max()/min()

new topic     » goto parent     » topic index » view message » categorize

62. Re: Standard library praise and challenge

SDPringle said...

I think Bill, Jim, Derek and I are in agreement of what max() and conversely min() should do when the list is not empty.

I can't speak for the others but I agree with this statement.

SDPringle said...

When the list is empty is result is rather academic from my point of view.

Agreed.

SDPringle said...

Condier though:

    1. EUPHORIA's routines tend to die rather than give an error code when given bad parameters. Let's be consistent here. In general I prefer to see an error code but there is no way to tell an error code from a result here.
    2. Certainly, the idea of what a maximum of the empty set is undefined.
    3. It follows that the interpreter should die in this case.

Consider division by 0. There is no NaN returned. It dies, instead. This is the way the work is designed. Instead of going off into different directions we should try to keep with the same design principles.

Shawn Pringle

Agreed. Even sqrt(-1) dies instead of returning NaN, despite the latter behavior being explicitly allowed by the floating point standard.

I think this is also keeping with the design principle of "Fail Early."

new topic     » goto parent     » topic index » view message » categorize

63. Re: Standard library praise and challenge

The only reason why I would object to dying or error on max({}) is:

One is returning the maximum of a list:
An empty list is a valid list,
{} is (potentially) a member of every list.
MAXREAL < {} < {MINREAL} i.e. it has an ordering whereas sqrt(-1) does not.

I think it would be advisable to avoid a situation where max({}) dies or raises an error but max({ {} }) and max({ {},{} }) do not.

Jim: remember I am not returning an atom.

new topic     » goto parent     » topic index » view message » categorize

64. Re: Standard library praise and challenge

bill said...

Jim: remember I am not returning an atom.

Relevance?

new topic     » goto parent     » topic index » view message » categorize

65. Re: Standard library praise and challenge

Objects:

you said:

Agreed. Even sqrt(-1) dies instead of returning NaN, despite  
the latter behavior being explicitly allowed by the floating  
point standard. 
 
I think this is also keeping with the design principle of  
"Fail Early." 

Sqrt(-1) should not return NaN because i is not anything like a real or a sequence. There cannot be an order for complex numbers unless you define 2 numbers as being equal if the distance from (0,0) (or (0,0,0) ... etc is the same) (metric spaces).

If max({}) fails what of max({ {} }). Are you say max() can only return a number?

Bill

new topic     » goto parent     » topic index » view message » categorize

66. Re: Standard library praise and challenge

bill said...

If max({}) fails what of max({ {} }). Are you say max() can only return a number?

I think that max()/min() functions only make sense if there is a minimum of two items to compare. And I certainly think the current recursive aspect of the math library functions is a mistake.

Now one might argue that an edge case is when a list has only a single item, in which case that item is returned. But when a list has no items, returning which of those non-existent items is the max/min is meaningless. In such a case, the function should either return ...

  1. a value that unambiguously indicates that an empty list was passed
  2. crash
  3. throw an exception


For now, I prefer the second option; crash the application.

There is no unambiguous value that can be returned with the current Euphoria. We can't use {} or NaN, because both of those might actually be one of the items in a non-empty list.

And of course, Euphoria doesn't have exceptions yet.

If your application has a real case in which an empty list can be validly passed to the function, then you should test for that explicitly as I suspect it would be a rare thing in general.

new topic     » goto parent     » topic index » view message » categorize

67. Re: Standard library praise and challenge

bill said...

Objects:

you said:

Agreed. Even sqrt(-1) dies instead of returning NaN, despite  
the latter behavior being explicitly allowed by the floating  
point standard. 
 
I think this is also keeping with the design principle of  
"Fail Early." 

Sqrt(-1) should not return NaN because i is not anything like a real or a sequence.

You may disagree, but this is specified in the floating point standard. After all, NaN does not specify a real number - it literally stands for Not A Number.

I suppose we could just return {} from sqrt(-1). This is clearly not a number, although the return value could be confused with the result of sqrt({}).

bill said...

If max({}) fails what of max({ {} }). Are you say max() can only return a number?

Bill

max({ {} }) returns {} but max({}) fails. max({ {}, {} }) returns {}.

new topic     » goto parent     » topic index » view message » categorize

68. Re: Standard library praise and challenge

jimcbrown said...
bill said...

...stuff...

...different stuff...

Ack. This is why I like to stay away from stdlib development and focus on the interpreter, et.al., where I can deal with less controversial subject matter like goto.

Matt

new topic     » goto parent     » topic index » view message » categorize

69. Re: Standard library praise and challenge

mattlewis said...
jimcbrown said...
bill said...

...stuff...

...different stuff...

Ack. This is why I like to stay away from stdlib development and focus on the interpreter, et.al., where I can deal with less controversial subject matter like goto.

Matt

Its posts like these that make me wish we had like buttons for the forum. :)

Shawn

new topic     » goto parent     » topic index » view message » categorize

70. Re: Standard library praise and challenge

Today I looked inside std/sequence.e and have seen this:

public function add_item(object needle, sequence haystack, integer pOrder = 1) 
	if find(needle, haystack) then 
		return haystack 
	end if 
	switch pOrder do 
		case ADD_PREPEND then 
			return prepend(haystack, needle) 
 
		case ADD_APPEND then 
			return append(haystack, needle) 
 
		case ADD_SORT_UP then 
			return stdsort:sort(append(haystack, needle)) 
 
		case ADD_SORT_DOWN then 
			return stdsort:sort(append(haystack, needle), stdsort:DESCENDING) 
 
		case else 
			error:crash("sequence.e:add_item() invalid Order argument '%d'", pOrder) 
	end switch 
 
	return haystack 
end function 

Why not to replace this

stdsort:sort(append(haystack, needle))

with some sort of binary insertion function? This approach would be is less reliable (eg. function will not know if the sequence have a proper order, presorting will be up to a user), but it would be much faster on long sequences.

P.S. something like this:

eu:insert(haystack,needle,math:abs(search:binary_search(needle,haystack)))
new topic     » goto parent     » topic index » view message » categorize

71. Re: Standard library praise and challenge

Insolor said...

Why not to replace this

stdsort:sort(append(haystack, needle))

with some sort of binary insertion function?

I wouldn't like to replace the existing functionality but we could certainly add to it. Maybe a new code INSERT_SORTED that would insert the new item into an already sorted list.

new topic     » goto parent     » topic index » view message » categorize

Search



Quick Links

User menu

Not signed in.

Misc Menu