Multiplying sequences with floats

  • Thread starter Christoph Zwerschke
  • Start date
C

Christoph Zwerschke

Currently, if you write 3*'*', you will get '***', but if you write
3.0*'*', you will get an error (can't multiply sequence by non-int).

I was wondering whether this should be allowed, i.e. multiplication of a
sequence with a float. There could be either an implicit typecast to int
(i.e. rounding), or the above error could occur only for floats with a
fractional part. Usage example: You want to convert a percentage value
(to a number of 0 to 4 stars. You could do this with the expression

percentage/20*'*'

However, this fails if percentage is a float. And even this fails:

percentage//20*'*'

So you have to write

int(percentage//20)*'*'

in which case you may as well write

int(percentage/20)*'*'

again. Ok, it's probably not a big deal but it somehow stroke me as odd
that you can't simply write percentage//20*'*'.

-- Christoph
 
D

Dan Sommers

Currently, if you write 3*'*', you will get '***', but if you write
3.0*'*', you will get an error (can't multiply sequence by non-int).
I was wondering whether this should be allowed, i.e. multiplication of
a sequence with a float. There could be either an implicit typecast to
int (i.e. rounding) ...

Explicit is better than implicit.

At least until some future version of python in which math.sqrt( 4.0 )
returns an integer. ;-)

Regards,
Dan
 
C

Christoph Zwerschke

Dan said:
Explicit is better than implicit.

I already knew using the word "implicit" would provoke that answer...
Anyway this would be an argument only against the variant of typecasting
a float with a fractional part. But what about the other variant which
raises an error if there is a fractional part, but works if the float is
actually an exact integer, like the result of 4.0//2.

BTW, the multiplication of a sequence with an int does an even more
implicit thing: The number is considered to be zero if it is negative.
At least until some future version of python in which math.sqrt( 4.0 )
returns an integer. ;-)

In that version, 4.0//2 would also return an integer... But that is not
something I had in mind.

-- Christoph
 
A

Andrew Koenig

Anyway this would be an argument only against the variant of typecasting a
float with a fractional part. But what about the other variant which
raises an error if there is a fractional part, but works if the float is
actually an exact integer, like the result of 4.0//2.

I think that's a really bad idea, because of the possibility that the result
might happen to be an exact integer on one implementation but not another.
In such situations, the fact that it might fail on implementation X may well
be impossible to detect by any amount of testing on implementation Y. Such
untestable errors are such a nuisance that it would better for the language
to encourage programmers to give them a wide berth.
 
C

Christoph Zwerschke

Andrew said:
I think that's a really bad idea, because of the possibility that the result
might happen to be an exact integer on one implementation but not another.
In such situations, the fact that it might fail on implementation X may well
be impossible to detect by any amount of testing on implementation Y. Such
untestable errors are such a nuisance that it would better for the language
to encourage programmers to give them a wide berth.

1./20*40 == 2 or math.sqrt(4.0) == 2 may not always be True (on my
platform it is True), but on every platform 4.0//2 == 2 should be True.
More general, the result of a//b should always be an exact integer, and
a//b == int(a/b) for all positive numbers a,b, no matter on which
platform. If not, I would consider a//b broken on that platform.

And if a//b == int(a/b) is True, I think it is also reasonable to expect
that a//b * list is the same as int(a/b) * list

-- Christoph
 
C

Caleb Hattingh

Hi Christoph


4.0//2 doesn't return an integer, but the equality against an integer
still holds. I agree that integer division should return an integer,
because using the operator at all means you expect one. Having to
cast it after integer division seems unnecessary. Unfortunately, I
have zero say on the matter :)

This issue was probably discussed at length when the integer division
operator (//) was introduced. It is possible there is a good reason
behind this, but I don't know it.

regards
Caleb
 
F

Fredrik Lundh

Caleb said:
I agree that integer division should return an integer, because
using the operator at all means you expect one.

so what is

x / y

? an integer division ? something else ?

</F>
 
C

Christoph Zwerschke

Caleb said:
4.0//2 doesn't return an integer, but the equality against an integer
still holds. I agree that integer division should return an integer,
because using the operator at all means you expect one.

There are actually two conflicting expectations here: You're right, the
semantics of a floor operation let you expect an int, but on the other
hand, the result type of all other binary operations is the common type
into which the operands are casted before the operation, and the result
type of math.floor() is always float, even for an int operand.

The thing that I thought is a bit awkward is that

a//b * some_list

will not work if a or b is a float, even if it represents an integer and
even though the result of a//b always represents an integer.

Now there are two ways to resolve this:

a) a//b always returns an int (or long)
b) n * some_list works if n is a float representing an integer

I was actually considering solution b), not a).

By the way, solution a) has another drawback: What would you return if
a=1e200 and b=1, or a=1 and b=1e-200? Of course, a floor division would
be pretty silly with such numbers, but returning a long number with 200
digits of which most are wrong anyway somehow does not look like the
right thing to do.

-- Christoph
 
C

Caleb Hattingh

Hi Fredrik

Fair enough; I wasn't precise. Upon further reflection, I actually
meant floor division, via the // operator. In the following snippet:
2.0

We know the last two operations can only return what are effectively
integer numbers (or raise an error), but the type that gets returned
for a valid operation is a float. Now, I'm not pretending to know
much about this stuff, just pointing out that that behaviour is
interesting. Just like how MvL pointed out to me in a recent thread
that in certain cases .read().splitlines(True) is significantly faster
than .readlines() on some file objects: that's interesting.

I am sure there are good reasons for this, and I can't imagine that the
issue of return type didn't come up when discussions about the floor
division operator was discussed; in fact, thinking about it a little
more, I suspect this operator is probably more likely to be used in a
sequence of floating-point operations anyway, for which the current
implementation saves a type conversion that might have been necessary
had it been made to return int to start with.

So regarding my previous statement:

I am not so sure now :)

By the way (regarding PIL), have you seen this site:
http://www.greyc.unicaen.fr/~dtschump/greycstoration/index.html

It is an open-source project implementing fancy methods for cleaning up
images and (my interest) resizing images with better clarity on
enlargements. I had been working on a python implementation for this
kind of thing with heavy leaning on the PIL, but I saw this project on
the daily freshmeat newsletter, and so will probably use that code
instead.

regards
Caleb
 
C

Caleb Hattingh

Christoph

I understand the explanation regarding the underlying math.floor()
call. Were I using this functionality in my code,

int(a//b)* some_list

would not be something I consider a big deal. However, I see what
you're saying: The multiplcation by list can only work with an int, and
you have an integer number, but unfortunatly with type float. Well, I
guess that's life :)

Again, a small cast like that is not a problem for me, so I can't
really comment on this.

Keep well
Caleb
 
D

Dennis Lee Bieber

We know the last two operations can only return what are effectively
integer numbers (or raise an error), but the type that gets returned
for a valid operation is a float. Now, I'm not pretending to know

To most old programmers, numeric types run a hierarchy of
promotions:

integer -> (long integer) -> (float) -> double -> complex -> (double
complex)

The () are just to indicate things that may or may not be visible...
FORTRAN doesn't have long-integer; Python floats ARE double...

Typically math operations promote lesser types to the -> higher
type, and the result is always in that higher type. FORTRAN could demote
back down with the result if the final destination were of a lower type,
but intermediate results had to be explicitly converted if needed.
--
 
C

Caleb Hattingh

Hi Dennis

Sure, I get it. I do most of my work in Delphi, which is, shall we
say, not lax about floating-point types. Thinking about this more, I
realise my initial interest was in looking at the // operator as
something new, whereas I now see it probably just wraps math.floor();
obviously then, you're going to get whatever the underlying C math
library returns.

As an aside, I also realised that the OP could just subclass list to
make one that works with multiplications against floats: he could
either floor and cast the float to int in the overloaded operator, or
make a fancy system of using the fractional part of the float to
duplicate the list int(floor()) times, then add just the fraction of
the list that approximates most closely the decimal part of the float;
this is assuming the outcome is actually meaningful for any particular
problem.

As I remarked to Christoph, this whole issue is actually a non-issue to
me, and I don't want to give the impression I think there is a problem
here; just interested in the // operator is all :)

regards
Caleb
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,770
Messages
2,569,584
Members
45,077
Latest member
SangMoor21

Latest Threads

Top