Discussion: new operators for numerical computation

Huaiyu Zhu hzhu at users.sourceforge.net
Fri Jul 28 18:27:24 EDT 2000


On 26 Jul 2000 02:10:30 +0200, Carel Fellinger <cfelling at iae.nl> wrote:
>Hai Math-lovers,
>
>Very interesting discussion sofar, and clearly heading into something
>nice and pythonic now.

Glad to hear this.  :-)

>(opt) looks to me as some expression on operators, not as a simple operator.
><opt> looks like an operator and was defenitely my favorite, until Huaiyu
>showed us <->. 

I think it was actually Tim Hochberg who noticed this.

>It still looks like an operator, but not aka some minus but
>aka some equivalence function or what have you. A big minus:( I would feel
>sorry if more of those wierd symbols would enter Python. In fact the reason
>I now favour ~opt is that that might open the way to get rid of those ugly
>bitwise operator symbols using ~ as a generic 'element/bit-wise' prefix:
>
>| becomes ~or,
>^ becomes ~xor,
>& becomes ~and, and
>~ becomes ~not, reading like bitwise or, bitwise xor etc.

This would indeed be an excellent option if not for backward compatibility.
I did a little rgrep over the python source.  It appears that each of these
symbols appears in between 200 and 1000 lines of code, depending on how much
usage in regular expressions is filtered out.  Most of the usages are rather
simple, often of the form

FLAG = FLAG1 | FLAG2 | FLAG3 | FLAG4 | FLAG5 | FLAG6 | FLAG7 | FLAG8

which would be much written as

FLAG = bitwise.or(FLAG1, FLAG2, FLAG3, FLAG4, FLAG5, FLAG6, FLAG7, FLAG8)

Changing such code is not a small undertaking, but it is not really
prohibitive.  OTOH, it is of course an entirely different story to ensure
nothing breaks "in the wild".

Even if we could not grab these operators for math right now, I'd still
suggest that a bitwise module replaces the bitwise operators.  Bitwise
operations are remnants of an older era of computing, and they are not
explicitly used in the operations of most high level objects.  It is, IMHO,
quite "unpythonic" to let them occupy four unique ascii characters as
operators with their own precedences - most users could not even remember
which is which without checking reference.  It is better to use descriptive
names.

Furthermore, unlike math operators, unless you are designing a logical
circuit, it is rare to construct complicated formulas with these operators.
So brevity is really not important for them.

>Much easier to remember but for ~not, besides thanks to the prefix ~
>there is no need for a new xor-keyword. And as ~ is never used on its
>own anymore, it's bound to be easier on the eyes in visual parsing of
>expressions, and definitely better then <opt> (see below)
>
>> a ~add b < c
>> a <add> b < c

I'd agree here.

>And now that w've got 'better' bitwise operator symbols we could use ^ to
>mean 'to the power of' (like I always think if I forget to look it up:) and
>we could use | or ~| to mean 'solve' (whatever that means).

We could still steal ^ for matrix if we want to,  (Opinions?)  like

class Matrix:
	def pow(self, other): ...
	__xor__ = __pow__ = pow

"solve" is simply "left division", like (if | is solve)

solution of x*a==b is x=div(b,a), or x=b/a
solution of a*x==b is x=sol(a,b), or x=a|b

Why do they differ?  Because for matrices, a*x==x*a is not true in general.
But why can't we use inverse (denoted by .I)?

x = b*a.I
x = a.I*b

Because calculating inverse then followed by a multiplication is quite
expensive compared with a direct division.  To see this is also true for
ordinary numbers, contrast doing 35.0/14.0 and 35.0*(1/14.0) by hand.

However, we've just figured out that the proposal of lazy execution of .I is
not so complicated to implement.  So we can let a.I be a new matrix (without
numerical work) until we see a.I*b, which is done as sol(a,b).  One key
point for feasibility is that the .H, .T, .I, .C could all be done like this
individually, because a.I.H==a.H.I, etc.


So the situation now is that we only need five new operators which parallels
the current + - * / **.  I'm going to write a PEP for using ~+, ~-, ~*, ~/,
~**.  It would take quite some effort to summarize all the pros and cons
raised in these threads, though.

BTW, if we ever desire to extend python in the future with general named
operators, perhaps @opname is a better choice because @ is associated
visually more closely with letters.  In any case, these two extensions are
of different categories. The ~op retain the precedence of existing op, while
the @opname type would have to share one fixed precedence if they are more
functionlike.


Huaiyu



More information about the Python-list mailing list