Re: [Tutor] Trickier exercise: convert string to complex number

2009-07-11 Thread Angus Rodgers
>Date: Sat, 11 Jul 2009 14:33:58 +1000
>From: Lie Ryan 
>Message-ID: 
>
>Err... what's the question? Are you asking for style checking or the
>mentioned "bugs" in the comments?

Mainly style checking (but more generally anything silly that I'm
doing, that might leap to somebody's eye).  Any time my coding (or
in this case, mainly my commenting!) gets more elaborate (because,
in this case, I had to think harder about this exercise than about
any of the previous ones), I feel a need for somebody to look over
my shoulder, to make sure that I'm not starting to go haywire.

I was fairly pleased with the solution (because it would have been
easy to have coded something a lot more complicated and confusing)
- but also worried that I might have no good reason to be pleased!

I worry that I may be developing a silly and overly fussy style.

I tend to get obsessed with trivia, and fail to see the wood for
the trees.  On the other hand, I'm trying to discipline myself
to do even small exercises in a way that will scale up to larger
ones.

I'm trying to keep my idiosyncrasies in check, but there's no 
substitute for an external check now and then, to ensure that
I'm getting the balance at least roughly right.

>_const_func = lambda c : (lambda x : c)
>...
>def get_val(typ, prompt=None, valid=_const_func(True)):
>   ...
>
>I think that is an over-generalisation. It is much simpler to read
>def get_val(typ, prompt=None, valid=lambda x: True):
>
>because other people reading your code might not know what _const_func
>do (whether it is simply returning a lambda or it does something more
>complex).

That's a good point, and I'll change this.  (Reverting to how it
was before!  I imagined adding '_const_func' was an improvement.)

>> # A bug in this program is that, by indiscriminately removing all
>> #
>> # whitespace before processing, it fails to catch certain errors,
>> #
>> # e.g. " - 1 2 " will be passed to float("-12").  Correcting this
>> #
>> # bug is likely to make the program considerably more ... complex.
>
>You can avoid that bug by not stripping whitespaces. Ignore them inside
>the loop (put if ch == '': break) and before passing the number to
>float, compare the number's length before and after the whitespace is
>stripped. Not really considerably more complex...

D'oh!  How true.

I haven't coded this exactly as you suggested (no explicit check for
internal whitespace, and no length comparison, either), but it seems
to be roughly OK (although my testing hasn't been thorough, and I
may have introduced new bugs). float() itself strips initial and
final whitespace, so my program doesn't have to worry about that.

def atoc(num):
"""Convert string representation to complex number."""
# The algorithm still assumes there is no initial or final
# whitespace
num = num.strip()
n = len(num)
if not n:
raise ValueError
# Ignore first character (now initial whitespace has been 
# stripped)
for i, ch in enumerate(num[1:]):
if ch == 'j':
# Must be end of string (now final whitespace has been
# stripped)
if i != n - 2:
raise ValueError
# Case (ii)
return complex(0.0, float(num[:-1]))
if ch in '+-' and num[i] not in 'eE':
if num[-1] != 'j' or num[-2].isspace():
raise ValueError
if ch == '+':
# Case (iii)
return complex(float(num[:i + 1]), 
   +float(num[i + 2:-1]))
if ch == '-':
# Case (iv)
return complex(float(num[:i + 1]), 
   -float(num[i + 2:-1]))
    # Case (i)
return complex(float(num), 0.0)

(I have manually wrapped a few longish lines, just for this post
to the mailing list - the longest was 76 characters long.  I've
also corrected another bug that was in the original program - it
didn't check that the final [non-space] character was actually a
'j'.)
-- 
Angus Rodgers
___
Tutor maillist  -  Tutor@python.org
http://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] Searching backwards from end of string

2009-07-11 Thread Angus Rodgers
Robert Berman  wrote:

>A nifty 'notation like "[::-1]"' is an example of something called
>slicing which you will find very well explained in 6.1 of CORE PYTHON
>PROGRAMMING.  I thought that you had reviewed this since it precedes the
>questions in Chapter 6. It is a very handy tool for not only strings,
>but lists and dictionaries as well.

I'm baffled as to how you could read both of my messages without
seeing the bit in the first message where I explained that I had
used [::-1] in a previous exercise (and chosen, for good reasons
or bad, not to use it in this one), and then the bit in the second
message where I repeated this information, carefully and briefly,
because you seemed to have missed it the first time!  I hope I'm
not being rude, but I just don't know what else to say.  I can't
see that I'm at fault here.  If I am, please explain.
-- 
Angus Rodgers
___
Tutor maillist  -  Tutor@python.org
http://mail.python.org/mailman/listinfo/tutor


[Tutor] Trickier exercise: convert string to complex number

2009-07-10 Thread Angus Rodgers
Wesley Chun, /Core Python Programming/, Ex. 6-13:

 "[...] An atoc() was never implemented in the string module, so
 that is your task here.  atoc() takes a single string as input,
 a string representation of a complex number [...] and returns
 the equivalent complex number object with the given value [...]"

<http://python.pastebin.com/d6f7c679f>   (retention: 1 day)
<http://python.pastebin.com/d2ea157ff>   (retention: 1 day)
(helper functions for user input)

The main functions are short enough to post here, I think, but
there are many explanatory and apologetic comments in the first
file above; also, I would welcome (with a grimace!) any comments
as to whether I am developing a cranky or baroque style (as I'm
working very much on my own, apart from whatever feedback I can
get here), and such misdemeanours are more likely to be noticed
in the second (and longer) of the two files above.

from string import whitespace

def no_spaces(str):
return ''.join([ch for ch in str if ch not in whitespace])

def atoc(num):
"""Convert string representation to complex number."""
num = no_spaces(num)
n = len(num)
if not n:
raise ValueError
# Ignore first character
for i, ch in enumerate(num[1:]):
if ch == 'j':
# Must be end of string, else invalid
if i != n - 2:
raise ValueError
return complex(0.0, float(num[:-1]))
if ch in '+-' and num[i] not in 'eE':
return complex(float(num[:i + 1]),
   float(num[i + 1:-1]))
return complex(float(num), 0.0)

-- 
Angus Rodgers
___
Tutor maillist  -  Tutor@python.org
http://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] Searching backwards from end of string

2009-07-10 Thread Angus Rodgers
On Fri, 10 Jul 2009 11:57:21 -0400, Robert Berman
 wrote:

>I think you are looking for a complex solution.

Hardly.

>How about the following example:
>
>
>In [31]: s1='abcdeefghijkl'  #find last 'e'
>
>In [32]: s2=s1[::-1]#reverses s1
>
>In [33]: j=s2.find('e') #finds first 'e' in reversed string
>
>In [36]: ind=len(s1)-j-1  #index into s1 where last occurrence of 'e' is
>
>In [37]: ind
>Out[37]: 5
>
>In [38]: s1[ind]
>Out[38]: 'e'
>
>In [39]: s1
>Out[39]: 'abcdeefghijkl' BINGO. Done.
>
>Is that not a bit simpler

I did explain (perhaps at too great a length, or with too many
irrelevancies):

>On Fri, 2009-07-10 at 16:24 +0100, Angus Rodgers wrote:
>> [...]
>> On the earlier occasion:
>> [...]
>> I wrote:
>> [...]
>> def rstrip(s):
>> return lstrip(s[::-1])[::-1]
>> # Note: far from maximally efficient (two unnecessary copies!)
>> [...]
>> On the present occasion:
>> [...]
>> I thought I had better err in the opposite direction, so I wrote:
>> [...]
>> def rfindchr(strng, ch):
>> # Surely there's a neater (but still efficient) way?
>> n = len(strng)
>> for i in range(n - 1, -1, -1):
>> if strng[i] == ch:
>> return i
>> return -1

I don't even think that's "complicated" (just ugly and clumsy).

I just wondered if there were some simplifying feature of Python
that I had either forgotten or not learned about yet.  Python code
(even mine!) is usually neater than this.

I know efficiency is not always a major concern (and it certainly
isn't of any practical importance in a toy example like this),
but it seems downright profligate to make a reversed copy of a
string just in order to avoid searching it backwards, and to make
use of a nifty notation like "[::-1]" - even though my own first 
instinct is to do exactly that, to save "development time", and
to make use of a previous solution.
-- 
Angus Rodgers
___
Tutor maillist  -  Tutor@python.org
http://mail.python.org/mailman/listinfo/tutor


[Tutor] Searching backwards from end of string

2009-07-10 Thread Angus Rodgers
I'm probably having a bit of an off-day, so please forgive me if
this is a really silly question (even for a beginner in Python)!

I'm working through the exercises for Chapter 6 of Wesley Chun's
book [incidentally, I tried to append another endorsement to the
list, but my use of Python rather than "+1" may have looked like
a typo or the work of a lunatic, or perhaps my post is just late
in appearing - anyway, another happy reader here!], and running
again into a difficulty which I "cheated" my way through earlier.

On the earlier occasion:

 "6-6 Strings. Create the equivalent of string.strip():  Take a
 string and remove all leading and trailing whitespace. (Use of
 string.*strip() defeats the purpose of this exercise.)"

I wrote:

from string import whitespace

def lstrip(s):
if s:
for i, c in enumerate(s):
if c not in whitespace:
break
return s[i:]
else:
return s

def rstrip(s):
return lstrip(s[::-1])[::-1]
# Note: far from maximally efficient (two unnecessary copies!)

def strip(s):
return lstrip(rstrip(s))

On the present occasion:

 "6-12 Strings. ...
 (b) Create another function called rfindchr() that will find the
 last occurrence of a character in a string.  Naturally this works
 similarly to findchr(), but it starts its search from the end of
 the input string.
 ..."

I thought I had better err in the opposite direction, so I wrote:

def findchr(strng, ch):
for i, c in enumerate(strng):
if c == ch:
return i
return -1

def rfindchr(strng, ch):
# Surely there's a neater (but still efficient) way?
n = len(strng)
for i in range(n - 1, -1, -1):
if strng[i] == ch:
return i
return -1

def subchr(strng, origchar, newchar):
chars = list(strng)
for i, c in enumerate(chars):
if c == origchar:
chars[i] = newchar
return ''.join(chars)

I've quoted all my code, in case it's all bad, but it's rfindchr()
that I'm particularly worried about.
-- 
Angus Rodgers
___
Tutor maillist  -  Tutor@python.org
http://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] Fwd: thesaurus

2009-07-09 Thread Angus Rodgers
>Date: Thu, 9 Jul 2009 04:12:55 +0100
>From: Rich Lovely 
>Message-ID:
>   
>
>Natural language parsers are one of the hardest things to create.

I think the most famous illustration of this is the problem of
parsing these two sentences:

Time flies like an arrow.
Fruit flies like a banana.
-- 
Angus Rodgers
___
Tutor maillist  -  Tutor@python.org
http://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] Python Tutorials: How to create useful programs

2009-07-09 Thread Angus Rodgers
On Thu, 09 Jul 2009 02:40:19 +0200, you wrote:

>Date: Wed, 08 Jul 2009 16:59:47 -0700
>From: Emile van Sebille 
>Message-ID: 
>
>>> but if you ever come across a copy of "Core Python Programming," 
>>>i've put lots of exercises at the end of every chapter.
>> 
>> +1 from a reader/customer (vs. the author)
>
>+1 from a reviewer (vs. a reader/customer (vs. the author))
>
>:)
>
>--
>
>Date: Wed, 08 Jul 2009 20:33:16 -0400
>From: Robert Berman 
>Message-ID: <1247099596.3915.10.ca...@bermanrl-desktop>
>
>While it is not a sales pitch, the book is excellent. It and the Python
>Cookbook sit on top of my desk. Both are fantastic and pragmatic
>reference sources.

>>> happy.append(me)
>>> len(happy)
5

-- 
Angus Rodgers
___
Tutor maillist  -  Tutor@python.org
http://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] Poor style to use list as "array"?

2009-07-06 Thread Angus Rodgers
On Mon, 6 Jul 2009 01:51:22 +0100, Rich Lovely wrote:

[I wrote:]
>>                if name in plural:
>>                    name = plural[name]
>>                else:
>>                    name += 's'
>This could be written more cleanly (although arguably not as readably) as
>
>name = plural.get(name, name + "s")

Nice, and readable enough, I think.

>d.get(key, default) returns the value from d mapped to key if it
>exists, or default otherwise.
>
>You might also want to split your calculation and display code into
>two separate loops.  This might seem wasteful, but it will make your
>code easier to read and maintain, and the waste is only marginal with
>the loops you're running - there is a maximum of only 17 passes (once
>for each value of coin and note)

If I understand you correctly, this is the same idea as Bob Gailer
used in his code - in which 'buff' becomes a list, instead of (as
in my code) a string, formatted for printing.  It certainly seems 
to simplify the whole thing enormously:

<http://python.pastebin.com/d42610591>   (retention: 1 day)
(Ignore the boilerplate!)

Thanks to all of you.  I haven't adopted the suggestion of using
classes, which I think I'll leave for when I'm reading the later
chapters of the book (although I do get the gist of the idea).
-- 
Angus Rodgers
___
Tutor maillist  -  Tutor@python.org
http://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] Poor style to use list as "array"?

2009-07-05 Thread Angus Rodgers
On Mon, 06 Jul 2009 01:02:10 +0100, I hastily wrote:

>Incidentally, I forgot to quote the next line:
>
>count[-1] = m

That was copied-and-pasted from an older version of the program,
with less descriptive identifiers.  'm' should be 'amnt'.

>Of course, this is much better incorporated into the loop, thus:
>
>for i in range(LEN):
>(count[i], amnt) = divmod(amnt, value[i])
>
>[...]
>
>So it looks like we should have something like:
>
>plural = {'penny':'pennies'}
>
>counts = {}
>for val in value:
>(count, amnt) = divmod(amnt, val)
>counts[val] = count

Better, of course (I still haven't run it, but it should work):

counts = {}
for val in value:
(counts[val], amnt) = divmod(amnt, val)

>I'm much happier now, thanks!

... but also rather annoyed with myself.
-- 
Angus Rodgers
___
Tutor maillist  -  Tutor@python.org
http://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] Poor style to use list as "array"?

2009-07-05 Thread Angus Rodgers
On Sun, 5 Jul 2009 18:49:32 -0400, Kent Johnson wrote:

>On Sun, Jul 5, 2009 at 2:48 PM, Angus Rodgers wrote:
>
>> for i in range(LEN - 1):
>>    (count[i], amnt) = divmod(amnt, value[i])

Incidentally, I forgot to quote the next line:

count[-1] = m

Of course, this is much better incorporated into the loop, thus:

for i in range(LEN):
(count[i], amnt) = divmod(amnt, value[i])

and this lends itself to being rewritten in terms of some other
kind of iteration (as below).

>How about this:
>counts = []
>for val in value:
>  count, amnt = divmod(amnt, val)
>  counts.append(count)

I like that very much, because it is in the nature of the problem
that the numbers in the list 'value' are all distinct, and so can
be used as keys.  However, as this remark suggests, I think I am
going to need 'count' to be a dictionary, rather than a list, and
the same goes for 'denom', and 'plural' (although this should be
keyed by the strings in 'denom', and we don't need the 'None's).

So it looks like we should have something like:

plural = {'penny':'pennies'}

counts = {}
for val in value:
(count, amnt) = divmod(amnt, val)
counts[val] = count

and, later in the program, something like this (comments stripped
for brevity, and one new comment added):

for val in value:
amnt = counts[val]
name = denom[val]
if amnt:
to_print -= 1
if printed:
if to_print:
buff += ", "
else:
buff += " and "
printed += 1
if amnt > 1:
# This should become a function
if name in plural:
name = plural[name]
else:
name += 's'
buff += "%d %s" % (amnt, name)

I haven't run this, but I'll try rewriting the program tomorrow.
It looks like there's nothing to it.

I'm much happier now, thanks!
-- 
Angus Rodgers
___
Tutor maillist  -  Tutor@python.org
http://mail.python.org/mailman/listinfo/tutor


[Tutor] Poor style to use list as "array"?

2009-07-05 Thread Angus Rodgers
The problem this time is, given an amount of US currency in cents
(and less than a dollar), to print out a description of the coins
needed to represent it, using the smallest number of coins.  E.g.:

How many cents this time? 59
2 quarters, 1 nickel and 4 pennies.

How many cents this time? 55
2 quarters and 1 nickel.

How many cents this time? 75
3 quarters.

My program relaxes the restriction to amounts less than a dollar,
and initialises the necessary data structures as follows:

denom = ['dollar', 'quarter', 'dime', 'nickel', 'penny']
value = [100, 25, 10, 5, 1]
LEN = 5
plural = [None] * LEN
plural[-1] = 'pennies'
count = [None] * LEN   # Kludge

I use the list 'count' as a kind of array, so that e.g. count[-1]
is the number of pennies needed, count[2] is the number of dimes
needed, and so on.  Any initial values I might store as elements
of the list are never used, hence the use of 'None'. (The use of
'None' in the list 'plural' is much more defensible, I think, as
it is used to denote the formation of a regular plural by adding
's' to the name.) Instead, the actual values are assigned in a
'for' loop, as follows:

for i in range(LEN - 1):
(count[i], amnt) = divmod(amnt, value[i])

This feels like a bit of a cheat, as if I am trying to program in
Python as if it were some other more familiar language.  Should I
have coded this differently?

The full source code is here, in case anyone wants to look at it
(but I'm not soliciting any more attention, as I've already been
given quite a lot of it, and fear being offered the comfy chair!):
<http://python.pastebin.com/d5e321ae0>   (retention: 1 day)

Could I have used dictionaries instead, with the denomination names
as keys?  Is it possible to guarantee a sequence in which the keys
of a dictionary are iterated through? (If not, I suppose I could
keep the list 'denom' as it is here, and iterate through it with
"for key in denom:", although this seems a bit redundant.)
-- 
Angus Rodgers
___
Tutor maillist  -  Tutor@python.org
http://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] Is my style OK in this elementary student exercise?

2009-07-04 Thread Angus Rodgers
>Date: Sat, 4 Jul 2009 19:52:56 +0100
>From: "Alan Gauld" 
>Message-ID: 
>
>You can miss out a few else clauses, especially after 
>the try/excepts:
>
>---
>while get_bool("Continue?"): 
>try: key = eval(raw_input("Key value of type " + key_typ.__name__ + ": ")) 
>except StandardError: print "That's not a Python expression!" 
>
>if not isinstance(key, key_typ): 
>   print "That's not a value of type", key_typ.__name__ else: # User has 
> provided
>try: val = eval(raw_input("Object of type " + val_typ.__name__ + ": ")) 
>except StandardError: print "That's not a Python expression!" 
>
>if not isinstance(val, val_typ): 
>   print "That's not an object of type", val_typ.__name__ 
>else: # User has provided an object of the correct type 
>   ans[key] = val 
>return ans
>

I don't see this, because, if an exception does occur, won't
there be an attempt to access one of the objects 'key', 'val'
before it has been assigned?

Not that this matters in the largely rewritten "Version 0.1":
<http://python.pastebin.com/d7020f124>   (retention: 1 day)

(Is it time for me to get into the comfy chair yet?)  8-P
-- 
Angus Rodgers
___
Tutor maillist  -  Tutor@python.org
http://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] Is my style OK in this elementary student exercise?

2009-07-04 Thread Angus Rodgers
>Date: Sat, 04 Jul 2009 13:26:12 +0100
>From: Angus Rodgers 
>Message-ID: 
>
><http://python.pastebin.com/d7e245e0f>   (retention: 1 day)

This is just a quick(ish!) response to the feedback so far.

I realise, now, that I should have quoted what the exercise in the
book was asking for, to explain why my code is more elaborate than
the minimum that would be required to solve the problem at hand.

>From the book (2nd ed., p. 151):

 "[...] we recommend that the reader convert his or her code to
 functions that can be used in future exercises."

This requirement was uppermost in my mind.

I also remembered from previous brushes with programming (mostly
decades ago) that it is handy to have a little function that asks
a question and won't quit until the user gives a yes-or-no answer.

On the other hand, it would be overkill to try to write a program
that applies a full lexical, syntactic, and semantic analysis to
the text input by the user in an interactive console session.  In
the future I am quite likely to want to write something like that
(essentially reviving a student project from 1990, on which I got
a good enough mark to pass the course, but which suggested many
lines of further development - and whose implementation as my first
largish C++ program was simply abominable!), or else to use it
off-the-shelf from some Python library or other (suggestions?), 
but it would take months to write (perhaps weeks in Python, or
years in C++ ...), and therefore is out of the question here.

So I tried to take the middle course of writing small functions
that would be of use to me in future exercises (whether in this
book or elsewhere). The whole thing only took me an hour or so
to write (I didn't time the work, but it was certainly a matter
of minutes, rather than hours), so it wasn't overkill (I think!).

I did consider writing simpler code for input of strings as key
values, and, in a rewrite, I think I will provide such simpler
code, for this frequently-occurring default case (while still
allowing for general key types).

I also belatedly realised that I was stupidly duplicating code
in my get_dict() function, and I will rewrite this, as Daniel 
Woodhouse suggests.  get_dict() should make two calls to some
function with a name like get_val(), with a general type as a
parameter (perhaps defaulting to str - although the value type
parameter of get_dict() should, on reflection, have no default).

>--
>
>Date: Sat, 4 Jul 2009 18:50:48 +0300
>From: Daniel Woodhouse 
>Message-ID:
>   <4c0a037d0907040850r7874313cn4abacc7db5957...@mail.gmail.com>
>
>I had a look at your code, and refactored it a bit.  See my modifications at
>http://python.pastebin.com/m50acb143 You'll noticed I removed one of your
>functions completely (it was unnecessary) and the get_dict() function is not
>so heavily nested.

(See comments above.  I agree with the last bit, at least!)

>Some ideas:
>raw_input returns a string, so we can safely assume its a string.

It's definitely a good idea to treat this frequently-occurring
simple special case using simpler code (if only so that the user
doesn't have to enter those annoying quotation marks every time).

>Whether or
>not its a valid name for a student is a different matter, and if you wish to
>check such things you may wish to look at the regular expression module
>(re).

I'll certainly be investigating regular expressions (later), but
I think you'll agree that it would be overkill for this exercise.

>I wouldn't use eval as you did in the case, instead I did this to
>check the score is a valid int:
>try:
>val = int(val)
>except ValueError:
>print 'Invalid score'

I'll go halfway with you here.  I still want to keep the generality
of my code (for use in "future exercises"), but it shouldn't be
beyond my wit to avoid the overkill (and risk - see comment below)
of using eval(), and find out how to tell Python to evaluate a string
/only/ as a value of a known type (respectively, key_typ or val_typ).

I'll see if I can have a look at this after dinner, but I'll have
to do some reading of the book or the online documentation.  It's
probably just as simple as this:

ans = raw_input(prompt)
try:
key = key_typ(ans)
except ValueError:
(etc.)

except (ouch!) that I may still need to check for some more
general list of exceptions than just ValueError. (But I don't
want to start serious work on this just yet.)

>ValueError will catch invalid integers and we can ask the user to input
>again.  Generally we should only capture Exceptions that we are expecting,
>though there are exceptions to this (no pun intended)...

I'm sure you're right here.  I had an uneasy feeling that I was
doing something stupid and dangerous, which would not be a go

[Tutor] Is my style OK in this elementary student exercise?

2009-07-04 Thread Angus Rodgers

Fear not, I won't post all my exercises to the Tutor list!  But
when I seem to be doing something a little elaborate, it seems a
good idea to ask if I'm doing anything silly.  In this exercise:

<http://python.pastebin.com/d7e245e0f>   (retention: 1 day)

my /conscious/ worries are:

  (i) trapping the exception StandardError may, for all I know,
be a daft thing to do;

 (ii) I'm not bothering to be consistent in my use of single and
double string quotes (but I don't know how much difference this 
makes, to readability and/or reliability);

(iii) some of my lines of code extend beyond 79 characters (but
again, I don't know how much this matters);

 (iv) correlatively with (iii), my indentation perhaps looks a
little extreme (perhaps suggesting a redesign, I don't know);

  (v) I'm bound to be doing other silly things that I don't even
know about ("unknown unknowns").

Any comments? (I don't expect the Spanish Inquisition!)

-- 
Angus Rodgers
___
Tutor maillist  -  Tutor@python.org
http://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] Floor and modulus for complex arguments

2009-07-03 Thread Angus Rodgers
>Date: Sat, 04 Jul 2009 00:25:13 +1000
>From: Lie Ryan 
>Message-ID: 
>
>Angus Rodgers wrote:
>
>> I /think/ I would be naturally inclined to define:
>> 
>>  floor(x + yj) = floor(x) + floor(y)j for all real x, y
>> 
>>  z % w = z - floor(z / w) * wfor all complex z, w (!= 0)
>
>I'm not a mathematician, and I understand zilch about complex numbers.
>But looking literally at your definition, python 2.5 seems to define
>complex mod complex as you have defined:
>
>>>> import math
>>>> def floor(comp):
>... return math.floor(comp.real) + math.floor(comp.imag) * 1j
>...
>>>> def mod(z, w):
>... return z - floor(z / w) * w
>...
>>>> mod(10.4j+5.1, 5.2j+3.2)
>(1.8995+5.2002j)
>>>> (10.4j+5.1) % (5.2j+3.2)
>__main__:1: DeprecationWarning: complex divmod(), // and % are deprecated
>(1.8995+5.2002j)

mod(z, w) and (z % w) will give the same result whenever (z / w).imag
is >= 0 and < 1.  In particular, if also (z / w).real is >= 1 and < 2,
both expressions will be equal to z - w (as in this example).  But in
most cases they will give different results, e.g.:

>>> z = 1.5 + 1.5j
>>> mod(z, 1)
(0.5+0.5j)
>>> z % 1
(0.5+1.5j)

>> These seem like they would be mathematically useful definitions
>> (e.g. in algebraic number theory, where one has to find the
>> "nearest" Gaussian integer multiple of one Gaussian integer to
>> another - I forget the details, but it has something to do with
>> norms and Euclidean domains) [...]
>> 
>> Has there been heated debate about this (e.g. in the context
>> of Python 3, where the change to the division operator has 
>> apparently already provoked heated debate)?
>
>There is this:
>http://mail.python.org/pipermail/python-dev/2002-April/023251.html
>http://mail.python.org/pipermail/python-dev/2002-April/023259.html

I agree with Tim Peters that the original definition of complex
// and % makes no sense.  At least it makes no more sense to me
than it does to him; and that was indeed the reason for my post.

But I won't wax evangelical over my off-the-cuff definitions of
floor (and implicitly //) and % for complex numbers, especially
as the one application I only vaguely hinted at would actually 
need this instead:

 round(x + yj) = round(x) + round(y)j for all real x, y

Or, in Python, something more like this (because unfortunately
'round' is built in):

def cround(z):
return complex(round(z.real), round(z.imag))

The details I omitted are here, in case anyone wants to know!
<http://en.wikipedia.org/wiki/Gaussian_integer>
"It is easy to see graphically that every complex number is within
\frac{\sqrt 2}{2} units of a Gaussian integer. Put another way, 
every complex number (and hence every Gaussian integer) has a 
maximal distance of \frac{\sqrt 2}{2}\sqrt{N(z)} units to some
multiple of z, where z is any Gaussian integer; this turns Z[i]
into a Euclidean domain, where v(z) = N(z)."

>But it seems the reason is because when the decision was made, nobody in
>the devteam understand the reasoning behind complex numbers implementing
>the divmod, //, and % as such, and caused it to be removed due to being
>"makes no sense". Perhaps if you can convince the devteam about the math
>behind complex mod complex, this feature can be reintroduced. FWIW it
>has been 5+ years and nobody seems to complain before, it seems complex
>mod complex must have been very rarely used.

If I started to agitate for changes to a marginal and little-used
feature of the language within days of starting to learn it, might
I not quickly earn a reputation as a crank?  8-P

I don't know how useful it would be to [re]define floor(), //, % and
cround() for complex numbers.  Not very, if nobody uses them!  All 
I can say is that my suggested definitions seem to make more sense
than the original definitions seem to.  They do at least have an
easily pictured geometrical interpretation.  Imagine all multiples
of the given non-zero complex number w by complex numbers of the 
form m + nj, where m and n are integers: they form an infinite grid
of squares in the complex plane, and we are interested in which of
these squares the other given complex number z falls into, or else
we are interested in which vertex of the grid z lies closest to.
-- 
Angus Rodgers
___
Tutor maillist  -  Tutor@python.org
http://mail.python.org/mailman/listinfo/tutor


[Tutor] Apology (was:When are strings interned?)

2009-07-03 Thread Angus Rodgers
>Date: Fri, 03 Jul 2009 12:46:06 +0100
>From: Angus Rodgers 
>To: tutor@python.org
>Subject: Re: [Tutor] When are strings interned?
>Message-ID: 
>Content-Type: text/plain; charset=us-ascii
>[...]
>Date: Fri, 03 Jul 2009 14:43:21 +0100
>From: Angus Rodgers 
>To: tutor@python.org
>Subject: Re: [Tutor] When are strings interned?
>Message-ID: 
>Content-Type: text/plain; charset=us-ascii
>[...]

I'm sorry about that.  It's these new varifocal spectacles: even
after more than two weeks, I still can't see properly with them!

When I realised I'd posted using the non-existent e-mail address
, I first posted an apology, to whoever might
be using that address, thinking my post would be bounced to him.
But my apology itself bounced.

I then waited, until I saw that a message I posted later (about
complex numbers) was included in the digest.  This led me to
conclude that my earlier message had (as I expected) not been
accepted by the mailing list (because I didn't register using
that address).  So I reposted it, thinking that I had been care-
ful, considerate, and patient.  D'oh!
-- 
Angus Rodgers
___
Tutor maillist  -  Tutor@python.org
http://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] When are strings interned?

2009-07-03 Thread Angus Rodgers
This is partly a test to see if I can reply in the correct format
to a message in the tutor list (which I receive in digest format).

>Date: Thu, 02 Jul 2009 20:39:28 +1000
>From: Lie Ryan 
>
>Angus Rodgers wrote:
>[...]
>>>>> p = "green ideas"
>>>>> q = "green ideas"
>>>>> p == q
>> True
>>>>> p is q
>> False
>[...]
>In this particular case, the reason is because "colourless" can be used
>as an identifier. 
>[...] Identifiers cannot contain spaces, that's why green ideas are
>not interned.

That is very clear, thanks.

Presumably a different optimisation is going on here:

>>> "green ideas" is "green ideas"
True

[Does it create confusion to quote a dialogue with the interpreter
in this way?  The >>> looks like an instance of e-mail quotation.]

>And... have I told you not to rely on this behavior? NEVER rely on this
>implementation details. Once you get bitten by it, you'll regret it.

Noted!
-- 
Angus Rodgers
___
Tutor maillist  -  Tutor@python.org
http://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] When are strings interned?

2009-07-03 Thread Angus Rodgers
This is partly a test to see if I can reply in the correct format
to a message in the tutor list (which I receive in digest format).

>Date: Thu, 02 Jul 2009 20:39:28 +1000
>From: Lie Ryan 
>
>Angus Rodgers wrote:
>[...]
>>>>> p = "green ideas"
>>>>> q = "green ideas"
>>>>> p == q
>> True
>>>>> p is q
>> False
>[...]
>In this particular case, the reason is because "colourless" can be used
>as an identifier. 
>[...] Identifiers cannot contain spaces, that's why green ideas are
>not interned.

That is very clear, thanks.

Presumably a different optimisation is going on here:

>>> "green ideas" is "green ideas"
True

[Does it create confusion to quote a dialogue with the interpreter
in this way?  The >>> looks like an instance of e-mail quotation.]

>And... have I told you not to rely on this behavior? NEVER rely on this
>implementation details. Once you get bitten by it, you'll regret it.

Noted!
-- 
Angus Rodgers
___
Tutor maillist  -  Tutor@python.org
http://mail.python.org/mailman/listinfo/tutor


[Tutor] Floor and modulus for complex arguments

2009-07-03 Thread Angus Rodgers
I'm a little confused by: (i) the definition of the modulus and
floor division functions for complex arguments; (ii) the fact 
that these functions for complex arguments are now "deprecated";
and (iii) the fact that the math.floor() function is not defined
at all for a complex argument.

If I were thinking about this from scratch (in the context of
mathematics, rather than any particular programming language),
I /think/ I would be naturally inclined to define:

 floor(x + yj) = floor(x) + floor(y)j for all real x, y

 z % w = z - floor(z / w) * wfor all complex z, w (!= 0)

These seem like they would be mathematically useful definitions
(e.g. in algebraic number theory, where one has to find the
"nearest" Gaussian integer multiple of one Gaussian integer to
another - I forget the details, but it has something to do with
norms and Euclidean domains), and I don't understand why Python
doesn't do it this way, rather than first defining it a different
way (whose mathematical usefulness is not immediately apparent
to me) and then "deprecating" the whole thing!  It seems like
a wasted opportunity - but am I missing something?

Has there been heated debate about this (e.g. in the context
of Python 3, where the change to the division operator has 
apparently already provoked heated debate)?

Also, by the way, is there some obvious reason for Python's use
of the notation x + yj, rather than the more standard (except
perhaps among electrical engineers) x + yi?
-- 
Angus Rodgers
___
Tutor maillist  -  Tutor@python.org
http://mail.python.org/mailman/listinfo/tutor


[Tutor] When are strings interned?

2009-07-01 Thread Angus Rodgers
Hello, world!

This is my first post to the Tutor list (although I've already
posted to comp.lang.python a couple of times).

I'm currently reading Chapter 4 of Wesley Chun's book, "Core 
Python Programming" (2nd ed.).

I find this, in Python 2.5.4, on my Win98SE system (using IDLE):

>>> n = "colourless"
>>> o = "colourless"
>>> n == o
True
>>> n is o
True
>>> p = "green ideas"
>>> q = "green ideas"
>>> p == q
True
>>> p is q
False

Why the difference?
-- 
Angus Rodgers
___
Tutor maillist  -  Tutor@python.org
http://mail.python.org/mailman/listinfo/tutor