Re: Proposal for 'math.e' (2007-08-23)
- Posted by CChris <christian.cuvier at agricult?re.gouv?fr> Aug 23, 2007
- 761 views
Juergen Luethje wrote: > > This is my current (2007-08-23) proposal for a "math.e" standard > include file, according to the discussion here on EUforum. > > Changes compared to the previous version: > - Changed function sum(), so that it can't only add numbers, > but also sequences. > - Fixed a glitch in function rect_to_polar(). > > }}} <eucode> > global constant > E = 2.7182818284590452, > PI = 3.1415926535897932, > EULER_GAMMA = 0.57721566490153286, -- Euler-Mascheroni 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 > > 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 > As I had mentioned earlier, this type doesn't check for equal lengths of added items. As a result, sum() may crash in the middle of its operation, and the user has to figure out what happened. See my replacement proposal (search for the "sequence_of_addables" keyword). The name of the type is mysterious too. > 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 > > 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 atoms: {distance, angle} > -- - 'distance' is always >= 0 > -- - 'angle' is an atom that expresses radians, > -- and is in the half-closed interval ]-PI,+PI]. > -- If 'distance' equals 0, then 'angle' is undefined. > 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 = 0 -- 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 <snip> Also suggested, and not rejected AFAIK, were: * a gamma(a) function - standard generalisation of the integer factorial; * an erf(x) function (distribution function at x of the centered reduced Gauss probability density); * an incomplete gamma function, part_gamma(a,x) - integrate the integrand of gamma(a) over [0,x] and normalise by gamma(a). There is ample supply of free C and Fortran code around to compute them, and porting is not difficult, just tedious when the format of constants is not a little endian sequence of bytes. By the way, if I port (a small part of) the C library I have in mind, I'll have to port a polynom evaluator (uses Horner's method). Could be nice to make it global, since it would be here anyway. CChris