1. Proposal for 'math.e' (2007-08-07)
- Posted by Juergen Luethje <j.lue at gmx??e> Aug 07, 2007
- 565 views
This is my current (2007-08-07) proposal for a "math.e" standard include file, according to the recent discussion here on EUforum. Changes compared to the previous version: - Now the global constants have maximum available precision ( hopefully ). Note: E.g. EULER_NORMAL = 1/sqrt(TWO_PI) has the same precision as EULER_NORMAL = machine_func(47, {81,54,212,51,69,136,217,63}) - Aded two new global constants. - Added internal constants RADIANS_TO_DEGREES and DEGREES_TO_RADIANS. - Added a general logarithm function. - Added functions polar_to_rect() and rect_to_polar(). - Renamed 4 functions, according to this post by Fernando Bauer <http://www.openeuphoria.org/cgi-bin/esearch.exu?fromMonth=8&fromYear=C&toMonth=8&toYear=C&postedBy=Fernando+Bauer&keywords=Aug+3> and to the discussion which it triggered. - find_least() -> find_min() - find_greatest() -> find_max() - least() -> min() - greatest() -> max()
global constant E = 2.7182818284590452, PI = 3.1415926535897932, EULER_GAMMA = 0.57721566490153286, -- the Euler-Mascheroni-Soldner gamma constant LN2 = log(2), LN10 = log(10), SQRT2 = sqrt(2), HALF_SQRT2 = SQRT2/2.0, HALF_PI = PI/2.0, QUARTER_PI = PI/4.0, TWO_PI = PI*2.0, EULER_NORMAL = 1/sqrt(TWO_PI) global function log2 (object x) -- logarithm base 2 -- in : (sequence of) real number(s) > 0 -- out: (sequence of) real number(s) -- Note: This function returns _exact_ results for all integral -- powers of 2 in the half-closed interval ]0,#FFFFFFFF] if atom(x) then if x = #20000000 then return 29 -- log(x)/LN2 is imprecise in this case elsif x = #80000000 then return 31 -- log(x)/LN2 is imprecise in this case else return log(x)/LN2 end if end if for i = 1 to length(x) do x[i] = log2(x[i]) end for return x end function global function log10 (object x) -- logarithm base 10 -- in : (sequence of) real number(s) > 0 -- out: (sequence of) real number(s) return log(x)/LN10 end function type positive_not_1 (object x) if atom(x) and x > 0 then return x != 1 end if return 0 end type global function logx (object x, positive_not_1 base) -- general logarithm function -- in : x : (sequence of) atom(s) > 0 -- base: atom > 0 and != 1 -- out : (sequence of) atom(s) -- Note: If x = 1 then the function returns 0 for any possible base. return log(x)/log(base) end function global function exp (object x) return power(E, x) end function global function sinh (object x) return (exp(x) - exp(-x)) / 2 end function global function cosh (object x) return (exp(x) + exp(-x)) / 2 end function global function tanh (object x) return sinh(x) / cosh(x) end function global function arcsinh (object x) return log(x + sqrt(x*x+1)) end function type not_below_1 (object x) if atom(x) then return x >= 1.0 end if for i = 1 to length(x) do if not not_below_1(x[i]) then return 0 end if end for return 1 end type global function arccosh (not_below_1 x) return log(x + sqrt(x*x-1)) end function type abs_below_1 (object x) if atom(x) then return x > -1.0 and x < 1.0 end if for i = 1 to length(x) do if not abs_below_1(x[i]) then return 0 end if end for return 1 end type global function arctanh (abs_below_1 x) return log((1+x)/(1-x)) / 2 end function global function abs (object x) -- return the absolute value of (all elements of) x if atom(x) then if x < 0 then return -x else return x end if end if for i = 1 to length(x) do x[i] = abs(x[i]) end for return x end function global function sign (object x) -- x < 0 ==> -1 -- x = 0 ==> 0 -- x > 0 ==> +1 if atom(x) then return compare(x, 0) end if for i = 1 to length(x) do x[i] = sign(x[i]) end for return x end function global function ceil (object x) -- the opposite of floor() -- Examples: ? ceil(3.2) --> 4 -- ? ceil({-3.2,7,1.6}) --> {-3,7,2} return -floor(-x) end function global function sum (sequence list) -- Return the sum of all elements in 'list'. -- Note: This does not do a recursive sum of sub-sequences. atom ret ret = 0 for i = 1 to length(list) do ret += list[i] end for return ret end function constant RADIANS_TO_DEGREES = 180.0/PI global function radians_to_degrees (object x) -- in : (sequence of) angle(s) in radians -- out: (sequence of) angle(s) in degrees return x * RADIANS_TO_DEGREES end function constant DEGREES_TO_RADIANS = PI/180.0 global function degrees_to_radians (object x) -- in : (sequence of) angle(s) in degrees -- out: (sequence of) angle(s) in radians return x * DEGREES_TO_RADIANS end function type trig_range (object x) -- values passed to arccos and arcsin must be [-1,+1] if atom(x) then return x >= -1 and x <= 1 end if for i = 1 to length(x) do if not trig_range(x[i]) then return 0 end if end for return 1 end type global function arcsin (trig_range x) -- returns angle in radians return 2 * arctan(x / (1.0 + sqrt(1.0 - x * x))) end function global function arccos (trig_range x) -- returns angle in radians return HALF_PI - 2 * arctan(x / (1.0 + sqrt(1.0 - x * x))) end function type point_pol (object x) if sequence(x) and (length(x) = 2) and atom(x[1]) and (x[1] >= 0) and atom(x[2]) then return 1 end if return 0 end type global function polar_to_rect (point_pol p) -- convert polar coordinates to rectangular coordinates -- in : sequence of two atoms: {distance, angle}; -- 'distance' must be >= 0, 'angle' is in radians -- out: sequence of two atoms: {x, y} atom distance, angle, x, y distance = p[1] angle = p[2] x = distance*cos(angle) y = distance*sin(angle) return {x, y} end function type point_xy (object x) if sequence(x) and (length(x) = 2) and atom(x[1]) and atom(x[2]) then return 1 end if return 0 end type global function rect_to_polar (point_xy p) -- convert rectangular coordinates to polar coordinates -- in : sequence of two atoms: {x, y} -- out: sequence of two elements: {distance, angle} -- - 'distance' is always an atom >= 0 -- - 'angle' is normally an atom that expresses radians, -- and is in the half-closed interval ]-PI,+PI]. -- If 'distance' equals 0, then 'angle' is {}, -- meaning that it is undefined in this case. object angle atom distance, x, y x = p[1] y = p[2] distance = sqrt(x*x + y*y) if x > 0 then angle = arctan(y/x) elsif x < 0 then if y < 0 then angle = arctan(y/x) - PI else angle = arctan(y/x) + PI end if else if y < 0 then angle = -HALF_PI elsif y > 0 then angle = HALF_PI else angle = {} -- The angle is undefined in this case. end if end if return {distance, angle} end function global function find_min (sequence list, integer start) -- Search for the minimum value in 'list', beginning at index 'start'. -- Return the index of that element. -- Notes: This does not do a recursive compare on sub-sequences. -- An empty sequence will cause a runtime error. object temp integer ret temp = list[start] ret = start for i = start+1 to length(list) do if compare(temp, list[i]) = 1 then temp = list[i] ret = i end if end for return ret end function global function find_max (sequence list, integer start) -- Search for the maximum value in 'list', beginning at index 'start'. -- Return the index of that element. -- Notes: This does not do a recursive compare on sub-sequences. -- An empty sequence will cause a runtime error. object temp integer ret temp = list[start] ret = start for i = start+1 to length(list) do if compare(temp, list[i]) = -1 then temp = list[i] ret = i end if end for return ret end function global function min (sequence list, integer start) -- Search for the minimum value in 'list', beginning at index 'start'. -- Return the value of that element. -- Notes: This does not do a recursive compare on sub-sequences. -- An empty sequence will cause a runtime error. object ret ret = list[start] for i = start+1 to length(list) do if compare(ret, list[i]) = 1 then ret = list[i] end if end for return ret end function global function max (sequence list, integer start) -- Search for the maximum value in 'list', beginning at index 'start'. -- Return the value of that element. -- Notes: This does not do a recursive compare on sub-sequences. -- An empty sequence will cause a runtime error. object ret ret = list[start] for i = start+1 to length(list) do if compare(ret, list[i]) = -1 then ret = list[i] end if end for return ret end function global function lesser (object x1, object x2) -- Return the argument with the lesser value. -- Note: This does not do a recursive compare on sub-sequences. if compare(x1, x2) <= 0 then return x1 else return x2 end if end function global function greater (object x1, object x2) -- Return the argument with the greater value. -- Note: This does not do a recursive compare on sub-sequences. if compare(x1, x2) >= 0 then return x1 else return x2 end if end function
Regards, Juergen
2. Re: Proposal for 'math.e' (2007-08-07)
- Posted by Colin Taylor <colinetaylor at ?mail.?om> Aug 07, 2007
- 509 views
- Last edited Aug 08, 2007
Juergen Luethje wrote: > > This is my current (2007-08-07) proposal for a "math.e" standard > include file, according to the recent discussion here on EUforum. > ... > > type point_pol (object x) > if sequence(x) and (length(x) = 2) > and atom(x[1]) and (x[1] >= 0) > and atom(x[2]) then > return 1 > end if > return 0 > end type > > global function polar_to_rect (point_pol p) > -- convert polar coordinates to rectangular coordinates > -- in : sequence of two atoms: {distance, angle}; > -- 'distance' must be >= 0, 'angle' is in radians > -- out: sequence of two atoms: {x, y} > atom distance, angle, x, y > > distance = p[1] > angle = p[2] > x = distance*cos(angle) > y = distance*sin(angle) > return {x, y} > end function > > type point_xy (object x) > if sequence(x) and (length(x) = 2) > and atom(x[1]) > and atom(x[2]) then > return 1 > end if > return 0 > end type > > global function rect_to_polar (point_xy p) > -- convert rectangular coordinates to polar coordinates > -- in : sequence of two atoms: {x, y} > -- out: sequence of two elements: {distance, angle} > -- - 'distance' is always an atom >= 0 > -- - 'angle' is normally an atom that expresses radians, > -- and is in the half-closed interval ]-PI,+PI]. > -- If 'distance' equals 0, then 'angle' is {}, > -- meaning that it is undefined in this case. > object angle > atom distance, x, y > > x = p[1] > y = p[2] > distance = sqrt(x*x + y*y) > if x > 0 then > angle = arctan(y/x) > elsif x < 0 then > if y < 0 then > angle = arctan(y/x) - PI > else > angle = arctan(y/x) + PI > end if > else > if y < 0 then > angle = -HALF_PI > elsif y > 0 then > angle = HALF_PI > else > angle = {} -- The angle is undefined in this case. > end if > end if > return {distance, angle} > end function > ... > > Regards, > Juergen Hi Juergen, I disagree with your solution to the special case rect_to_polar({0,0}). By setting the undefined angle to {}, you create a situation where the result cannot be translated back to rectangular coordinates. You are creating a real problem in order to solve what (imho) is an imagined problem. Regards, Colin
3. Re: Proposal for 'math.e' (2007-08-07)
- Posted by Juergen Luethje <j.lue at ?mx.de> Aug 09, 2007
- 526 views
Colin Taylor wrote: > Juergen Luethje wrote: > > > > This is my current (2007-08-07) proposal for a "math.e" standard > > include file, according to the recent discussion here on EUforum. > > > ... > > > > type point_pol (object x) > > if sequence(x) and (length(x) = 2) > > and atom(x[1]) and (x[1] >= 0) > > and atom(x[2]) then > > return 1 > > end if > > return 0 > > end type > > > > global function polar_to_rect (point_pol p) > > -- convert polar coordinates to rectangular coordinates > > -- in : sequence of two atoms: {distance, angle}; > > -- 'distance' must be >= 0, 'angle' is in radians > > -- out: sequence of two atoms: {x, y} > > atom distance, angle, x, y > > > > distance = p[1] > > angle = p[2] > > x = distance*cos(angle) > > y = distance*sin(angle) > > return {x, y} > > end function > > > > type point_xy (object x) > > if sequence(x) and (length(x) = 2) > > and atom(x[1]) > > and atom(x[2]) then > > return 1 > > end if > > return 0 > > end type > > > > global function rect_to_polar (point_xy p) > > -- convert rectangular coordinates to polar coordinates > > -- in : sequence of two atoms: {x, y} > > -- out: sequence of two elements: {distance, angle} > > -- - 'distance' is always an atom >= 0 > > -- - 'angle' is normally an atom that expresses radians, > > -- and is in the half-closed interval ]-PI,+PI]. > > -- If 'distance' equals 0, then 'angle' is {}, > > -- meaning that it is undefined in this case. > > object angle > > atom distance, x, y > > > > x = p[1] > > y = p[2] > > distance = sqrt(x*x + y*y) > > if x > 0 then > > angle = arctan(y/x) > > elsif x < 0 then > > if y < 0 then > > angle = arctan(y/x) - PI > > else > > angle = arctan(y/x) + PI > > end if > > else > > if y < 0 then > > angle = -HALF_PI > > elsif y > 0 then > > angle = HALF_PI > > else > > angle = {} -- The angle is undefined in this case. > > end if > > end if > > return {distance, angle} > > end function > > > ... > > > > Regards, > > Juergen > > Hi Juergen, > > I disagree with your solution to the special case rect_to_polar({0,0}). By > setting the undefined angle to {}, you create a situation where the result > cannot > be translated back to rectangular coordinates. Hi Colin, sorry, I overlooked that. > You are creating a real problem > in order to solve what (imho) is an imagined problem. I think you are right. So I propose that rect_to_polar({0,0}) should return {0,0}. Do you agree with that? Regards, Juergen
4. Re: Proposal for 'math.e' (2007-08-07)
- Posted by Colin Taylor <colinetaylor at gmai??com> Aug 09, 2007
- 505 views
Juergen Luethje wrote: > ... > > Hi Colin, > > sorry, I overlooked that. > > > You are creating a real problem > > in order to solve what (imho) is an imagined problem. > > I think you are right. > So I propose that rect_to_polar({0,0}) should return {0,0}. > Do you agree with that? > > Regards, > Juergen Yes, I agree. You can document that when distance = 0, the angle is undefined. Any program that relies on the value of angle can test for the distance = 0 case. Regards, Colin
5. Re: Proposal for 'math.e' (2007-08-07)
- Posted by Juergen Luethje <j.lue at ?mx.d?> Aug 16, 2007
- 523 views
Hello all, I'd like to suggest to change the sum() function in the future 'math.e' standard include file. The current proposal is:
global function sum (sequence list) -- Return the sum of all elements in 'list'. atom ret ret = 0 for i = 1 to length(list) do ret += list[i]Rob's opinion: end for return ret end function
That means, 'list' currently can only contain atoms. But it can also be useful to calculate the sum of several sequences (taking advantage of Euphoria's built-in sequence operations). Say we have 3 points, given by their x- and y-coordinates, and we want to get the center of gravity of these points:
object A, B, C, G A = {-2, 1} B = { 5, 0} C = { 0, 5} G = sum({A,B,C}) / 3 -- calculate center of gravity ? G -- prints {1,2}; Cool, no?
IMHO there is a problem with this suggestion, though. If by accident one of the variables is an atom, say C = 7 then the program will not crash, but the sum() function will return a result that is probably not intended. In order to avoid such a silent bug, my proposal is to use an appropriate type-check for the parameter of sum(). So my new proposal is:
type sequence_of_a_xor_s (object x) -- A sequence whose top-level elements are either only atoms or only -- sequences (or which is empty). integer object_type if atom(x) then return 0 end if if length(x) = 0 then return 1 end if object_type = atom(x[1]) for i = 2 to length(x) do if object_type != atom(x[i]) then return 0 end if end for return 1 end type global function sum (sequence_of_a_xor_s list) -- Return the sum of all elements in 'list'. -- Note: This does not do a recursive sum of sub-sequences. object ret if length(list) = 0 then return 0 end if ret = list[1] for i = 2 to length(list) do ret += list[i] end for return ret end function
Regards, Juergen
6. Re: Proposal for 'math.e' (2007-08-07)
- Posted by CChris <christian.cuvier at agr?culture.gouv.?r> Aug 16, 2007
- 505 views
Juergen Luethje wrote: > > Hello all, > > I'd like to suggest to change the sum() function in the future 'math.e' > standard include file. The current proposal is: > }}} <eucode> > global function sum (sequence list) > -- Return the sum of all elements in 'list'. > atom ret > > ret = 0 > for i = 1 to length(list) do > ret += list[i]Rob's opinion: > end for > return ret > end function > </eucode> {{{ > That means, 'list' currently can only contain atoms. > > But it can also be useful to calculate the sum of several sequences > (taking advantage of Euphoria's built-in sequence operations). > Say we have 3 points, given by their x- and y-coordinates, and we want > to get the center of gravity of these points: > }}} <eucode> > object A, B, C, G > > A = {-2, 1} > B = { 5, 0} > C = { 0, 5} > > G = sum({A,B,C}) / 3 -- calculate center of gravity > ? G -- prints {1,2}; Cool, no? > </eucode> {{{ > IMHO there is a problem with this suggestion, though. > If by accident one of the variables is an atom, say > C = 7 > then the program will not crash, but the sum() function will return > a result that is probably not intended. In order to avoid such a silent > bug, my proposal is to use an appropriate type-check for the parameter > of sum(). So my new proposal is: > }}} <eucode> > type sequence_of_a_xor_s (object x) > -- A sequence whose top-level elements are either only atoms or only > -- sequences (or which is empty). > integer object_type > > if atom(x) then > return 0 > end if > > if length(x) = 0 then > return 1 > end if > > object_type = atom(x[1]) > for i = 2 to length(x) do > if object_type != atom(x[i]) then > return 0 > end if > end for > > return 1 > end type > > global function sum (sequence_of_a_xor_s list) > -- Return the sum of all elements in 'list'. > -- Note: This does not do a recursive sum of sub-sequences. > object ret > > if length(list) = 0 then > return 0 > end if > > ret = list[1] > for i = 2 to length(list) do > ret += list[i] > end for > return ret > end function > </eucode> {{{ > Regards, > Juergen The above doesn't address the case where, not less accidentally, some of the sequences being added have different lengths. I'd suggest the following replacement for the type check:
function lengt(object x) if atom(x) then return -1 -- not a length else return length(x) end if end function type sequence_of_addables (object x) -- A sequence whose top-level elements are either only atoms or only -- sequences (or which is empty); the sequences should have the same length. integer object_type object_type = compare(x,{}) if object_type < 1 then return not object_type -- atom -> 0, {} -> 1 end if object_type = lengt(x[1]) for i = 2 to length(x) do if object_type != lengt(x[i]) then return 0 end if end for return 1 end type
and change the argument type in sum() of course. CChris
7. Re: Proposal for 'math.e' (2007-08-07)
- Posted by Juergen Luethje <j.lue at g?x?de> Aug 16, 2007
- 506 views
CChris wrote: > Juergen Luethje wrote: > > > > Hello all, > > > > I'd like to suggest to change the sum() function in the future 'math.e' > > standard include file. The current proposal is: > > }}} <eucode> > > global function sum (sequence list) > > -- Return the sum of all elements in 'list'. > > atom ret > > > > ret = 0 > > for i = 1 to length(list) do > > ret += list[i]Rob's opinion: > > end for > > return ret > > end function > > </eucode> {{{ > > That means, 'list' currently can only contain atoms. > > > > But it can also be useful to calculate the sum of several sequences > > (taking advantage of Euphoria's built-in sequence operations). > > Say we have 3 points, given by their x- and y-coordinates, and we want > > to get the center of gravity of these points: > > }}} <eucode> > > object A, B, C, G > > > > A = {-2, 1} > > B = { 5, 0} > > C = { 0, 5} > > > > G = sum({A,B,C}) / 3 -- calculate center of gravity > > ? G -- prints {1,2}; Cool, no? > > </eucode> {{{ > > IMHO there is a problem with this suggestion, though. > > If by accident one of the variables is an atom, say > > C = 7 > > then the program will not crash, but the sum() function will return > > a result that is probably not intended. In order to avoid such a silent > > bug, my proposal is to use an appropriate type-check for the parameter > > of sum(). So my new proposal is: > > }}} <eucode> > > type sequence_of_a_xor_s (object x) > > -- A sequence whose top-level elements are either only atoms or only > > -- sequences (or which is empty). > > integer object_type > > > > if atom(x) then > > return 0 > > end if > > > > if length(x) = 0 then > > return 1 > > end if > > > > object_type = atom(x[1]) > > for i = 2 to length(x) do > > if object_type != atom(x[i]) then > > return 0 > > end if > > end for > > > > return 1 > > end type > > > > global function sum (sequence_of_a_xor_s list) > > -- Return the sum of all elements in 'list'. > > -- Note: This does not do a recursive sum of sub-sequences. > > object ret > > > > if length(list) = 0 then > > return 0 > > end if > > > > ret = list[1] > > for i = 2 to length(list) do > > ret += list[i] > > end for > > return ret > > end function > > </eucode> {{{ > > Regards, > > Juergen > > The above doesn't address the case where, not less accidentally, some of the > sequences being added have different lengths. That's intended. At first I wanted to include this in the type-check, that's why I developed the type 'homogeneous_sequence'. Later I realized that it's not necessary to check the sequence lengths explicitely, because Euphoria does check that anyway, when it performs sequence operations. Please try it. Use something like ? sum({ {1}, {2,3} }) with my proposed type-cheking. The program will crash. If we'll explicitely type-check for different sequence lengths, then the program won't do anything else but crash. Regards, Juergen > I'd suggest the following replacement for the type check: > }}} <eucode> > function lengt(object x) > if atom(x) then > return -1 -- not a length > else > return length(x) > end if > end function > > type sequence_of_addables (object x) > -- A sequence whose top-level elements are either only atoms or only > -- sequences (or which is empty); the sequences should have the same > length. > integer object_type > > object_type = compare(x,{}) > if object_type < 1 then > return not object_type -- atom -> 0, {} -> 1 > end if > > object_type = lengt(x[1]) > for i = 2 to length(x) do > if object_type != lengt(x[i]) then > return 0 > end if > end for > > return 1 > end type > </eucode> {{{ > > and change the argument type in sum() of course. > > CChris