struct module and coercing floats to integers
It seems that the pre-2.5 struct module has some additional undocumented behavior[1] that didn't percolate into the new version: http://python.org/sf/1530559 Python 2.4 and previous will coerce floats to integers when necessary as such without any kind of complaint: $ python2.4 -c "import struct; print repr(struct.pack('>H', 0.9999999999999999))" '\x00\x00' Python 2.5 refuses to coerce float to int: $ python2.5 -c "import struct; print repr(struct.pack('>H', 0.9999999999999999))" Traceback (most recent call last): File "<string>", line 1, in <module> File "/Users/bob/src/python/Lib/struct.py", line 63, in pack return o.pack(*args) TypeError: unsupported operand type(s) for &: 'float' and 'long' The available options are to: 1. Reinstate the pre-2.5 weirdness 2. Reinstate the pre-2.5 weirdness with a DeprecationWarning 3. Break existing code that relies on undocumented behavior (seems more like a bug than lack of specification) Either 2 or 3 seems reasonable to me, with a preference for 3 because none of my code depends on old bugs in the struct module :) As far as precedent goes, the array module *used* to coerce floats silently, but it's had a DeprecationWarning since at least Python 2.3 (but perhaps even earlier). Maybe it's time to promote that warning to an exception for Python 2.5? [1] The pre-2.5 behavior should really be considered a bug, the documentation says "Return a string containing the values v1, v2, ... packed according to the given format. The arguments must match the values required by the format exactly." I wouldn't consider arbitrary floating point numbers to match the value required by an integer format exactly. Floats are not in general interchangeable with integers in Python anyway (e.g. list indexes, etc.). -bob
On 7/28/06, Bob Ippolito
[1] The pre-2.5 behavior should really be considered a bug, the documentation says "Return a string containing the values v1, v2, ... packed according to the given format. The arguments must match the values required by the format exactly." I wouldn't consider arbitrary floating point numbers to match the value required by an integer format exactly. Floats are not in general interchangeable with integers in Python anyway (e.g. list indexes, etc.).
While it may be a bug, it's not as hard to run into, nor as illogical as the presentation here makes it sound. The original code[1] took a float value between 0 and 2, and wanted to use pack('>H', round(value * 32768)) The workaround is a trivial change pack('>H', int(round(value * 32768))) but the timeframe is less than ideal, as working code will suddenly stop and recieve only mildly helpful error message. The fact that round returns a float rather than an int, while intentional, does not feature prominently in one's mine when the first version yielded the expected results. I would appreciate option 2 which retains compatibility but warns that the construct is bad. I will accept any of the options, as it's clear that floats don't make sense. It's just unfortunate that the previous implementation let them through in a way the new implementation does not. [1] http://www.sacredchao.net/quodlibet/changeset/3706 Michael -- Michael Urman http://www.tortall.net/mu/blog
Michael Urman wrote:
The fact that round returns a float rather than an int, while intentional, does not feature prominently in one's mine when the first version yielded the expected results.
As an aside, does anyone else think that it would be useful to have a builtin which rounds and converts to an int in one go? Whenever I use round(), I almost always want the result as an int, and making me do it in two steps seems unnecessarily bothersome. Since automatic float->int coercion is being increasingly disallowed, use cases for this are becoming more and more common. -- Greg
Greg Ewing wrote:
As an aside, does anyone else think that it would be useful to have a builtin which rounds and converts to an int in one go? Whenever I use round(), I almost always want the result as an int, and making me do it in two steps seems unnecessarily bothersome.
I think this would harm more than it would help. It more confusing to have several rounding-thingies to choose from than it is have an explicit two-step. BTW, I thought the traditional idiom (for positive numbers) was: int(x+.5)
Since automatic float->int coercion is being increasingly disallowed, use cases for this are becoming more and more common.
-- Greg _______________________________________________ Python-Dev mailing list Python-Dev@python.org http://mail.python.org/mailman/listinfo/python-dev Unsubscribe: http://mail.python.org/mailman/options/python-dev/rhettinger%40ewtllc.com
Raymond Hettinger wrote:
I think this would harm more than it would help. It more confusing to have several rounding-thingies to choose from than it is have an explicit two-step.
But is it more confusing enough to be worth forcing everyone to pay two function calls instead of one in the most common case? If I'm right that rounding-to-int is much more commonly needed than rounding-to-float, the least confusing thing would be for the builtin round() to return an int, and have something somewhere else, such as math.fround(), for round-to-float.
BTW, I thought the traditional idiom (for positive numbers) was: int(x+.5)
It's the "for positive numbers" that's the problem there. Most of my uses for round() involve graphics coordinates, which I can't be sure won't be negative. It's not immediately obvious what this will do with negative numbers. It's not even immediately obvious that it's doing round-to-nearest-integer unless you're familiar with the idiom. A single well-named function would be much more explicit. -- Greg
Greg Ewing wrote:
Raymond Hettinger wrote:
I think this would harm more than it would help. It more confusing to have several rounding-thingies to choose from than it is have an explicit two-step.
But is it more confusing enough to be worth forcing everyone to pay two function calls instead of one in the most common case?
I suppose you don't know about the optional argument to round that lets you round up to a certain decimal ?! If we were to follow your suggestion, we'd have round() return an integer when called without the argument and a float when called with the argument. Dependency of the return type on arguments to a function should be avoided, if possible. -- Marc-Andre Lemburg eGenix.com Professional Python Services directly from the Source (#1, Aug 01 2006)
Python/Zope Consulting and Support ... http://www.egenix.com/ mxODBC.Zope.Database.Adapter ... http://zope.egenix.com/ mxODBC, mxDateTime, mxTextTools ... http://python.egenix.com/
::: Try mxODBC.Zope.DA for Windows,Linux,Solaris,FreeBSD for free ! ::::
M.-A. Lemburg wrote:
I suppose you don't know about the optional argument to round that lets you round up to a certain decimal ?!
Yes, I know about, but I rarely if ever use it. Rounding a binary float to a number of decimal places seems a fundamentally ill-considered thing to do anyway. What are the use cases for it, given that one can easily select a number of decimal places when formatting a number for display?
If we were to follow your suggestion, we'd have round() return an integer when called without the argument and a float when called with the argument.
No, round() wouldn't have that option at all. If you wanted it, you would use fround() instead, which would have the option and return a float always. This would be a Py3k thing, obviously. If done before then, the new function would have to be given a different name. -- Greg
Greg Ewing wrote:
M.-A. Lemburg wrote:
I suppose you don't know about the optional argument to round that lets you round up to a certain decimal ?!
Yes, I know about, but I rarely if ever use it. Rounding a binary float to a number of decimal places seems a fundamentally ill-considered thing to do anyway. What are the use cases for it, given that one can easily select a number of decimal places when formatting a number for display?
You often have a need for controlled rounding when doing financial calculations or in situations where you want to compare two floats with a given accuracy, e.g. to work around rounding problems ;-) The usual approach is to use full float accuracy throughout the calculation and then apply rounding a certain key places. Float formatting is an entirely different issue.
If we were to follow your suggestion, we'd have round() return an integer when called without the argument and a float when called with the argument.
No, round() wouldn't have that option at all. If you wanted it, you would use fround() instead, which would have the option and return a float always.
This would be a Py3k thing, obviously. If done before then, the new function would have to be given a different name.
Hmm, looks like a YAGNI to me, but perhaps I'm missing something :-) -- Marc-Andre Lemburg eGenix.com Professional Python Services directly from the Source (#1, Aug 01 2006)
Python/Zope Consulting and Support ... http://www.egenix.com/ mxODBC.Zope.Database.Adapter ... http://zope.egenix.com/ mxODBC, mxDateTime, mxTextTools ... http://python.egenix.com/
::: Try mxODBC.Zope.DA for Windows,Linux,Solaris,FreeBSD for free ! ::::
On Tue, Aug 01, 2006, M.-A. Lemburg wrote:
You often have a need for controlled rounding when doing financial calculations or in situations where you want to compare two floats with a given accuracy, e.g. to work around rounding problems ;-)
The usual approach is to use full float accuracy throughout the calculation and then apply rounding a certain key places.
That's what Decimal() is for. (Note that I don't care all that much about round(), but I do think we want to canonicalize Decimal() for all purposes in standard Python where people care about accuracy. Additional float features can go into NumPy.) -- Aahz (aahz@pythoncraft.com) <*> http://www.pythoncraft.com/ "Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it." --Brian W. Kernighan
M.-A. Lemburg wrote:
You often have a need for controlled rounding when doing financial calculations
You should NOT be using binary floats for money in the first place.
or in situations where you want to compare two floats with a given accuracy,
Pseudo-rounding to decimal places is not the right way to do that. The right way is to compare the difference to a tolerance.
e.g. to work around rounding problems ;-)
As Tim Peters has pointed out many times, you can't fix binary/decimal representation problems by rounding. There are always cases that give a different result than you would want.
Hmm, looks like a YAGNI to me,
In all my programming so far I've found numerous uses for round-to-int, and exactly zero uses for round-binary-float-to-decimal- places. So from my point of view, the YAGNI applies to the *current* behavour of round()! -- Greg
Greg Ewing wrote:
M.-A. Lemburg wrote:
You often have a need for controlled rounding when doing financial calculations
You should NOT be using binary floats for money in the first place.
Believe me: you have to if you want to do more advanced calculus related to pricing and risk analysis of derivatives.
or in situations where you want to compare two floats with a given accuracy,
Pseudo-rounding to decimal places is not the right way to do that. The right way is to compare the difference to a tolerance.
This is not the same: if you round both value and then compare, you test a different interval than by taking the difference and applying a tolerance value comparison:
x = 1.12 y = 1.124999 round(x,2) == round(y,2) True abs(x-y) < 1e-2 True
yet:
y = 1.1275 round(x,2) == round(y,2) False abs(x-y) < 1e-2 True
e.g. to work around rounding problems ;-)
As Tim Peters has pointed out many times, you can't fix binary/decimal representation problems by rounding. There are always cases that give a different result than you would want.
Right, but in most real-world cases it works :-)
Hmm, looks like a YAGNI to me,
In all my programming so far I've found numerous uses for round-to-int, and exactly zero uses for round-binary-float-to-decimal- places. So from my point of view, the YAGNI applies to the *current* behavour of round()!
Most typical uses of round() don't use the optional argument, true, but I still fail to see what returning an integer instead of a float would buy you. -- Marc-Andre Lemburg eGenix.com Professional Python Services directly from the Source (#1, Aug 02 2006)
Python/Zope Consulting and Support ... http://www.egenix.com/ mxODBC.Zope.Database.Adapter ... http://zope.egenix.com/ mxODBC, mxDateTime, mxTextTools ... http://python.egenix.com/
::: Try mxODBC.Zope.DA for Windows,Linux,Solaris,FreeBSD for free ! ::::
On 8/2/06, M.-A. Lemburg
Greg Ewing wrote:
In all my programming so far I've found numerous uses for round-to-int, and exactly zero uses for round-binary-float-to-decimal- places. So from my point of view, the YAGNI applies to the *current* behavour of round()!
Most typical uses of round() don't use the optional argument, true, but I still fail to see what returning an integer instead of a float would buy you.
One hundred and sixty two type conversions! http://www.google.se/search?hl=sv&q=filetype%3Apy+%22int%28round%22&btnG=S%C3%B6k&meta= -- mvh Björn
M.-A. Lemburg wrote:
Believe me: you have to if you want to do more advanced calculus related to pricing and risk analysis of derivatives.
When you do things like that, you're treating money as though it were a continuous quantity. This is an approximation, so you can tolerate having small inaccuracies in the result. But when adding up actual, real amounts of money, where the result must be exact, using binary fractions is a very bad idea.
This is not the same: if you round both value and then compare, you test a different interval than by taking the difference and applying a tolerance value comparison:
That's exactly my point. Chopping decimal places is not a substitute for doing tolerance testing properly.
Most typical uses of round() don't use the optional argument, true, but I still fail to see what returning an integer instead of a float would buy you.
It saves you a function call in the vast majority of cases, where an int is what you ultimately want. -- Greg
Most typical uses of round() don't use the optional argument, true, but I still fail to see what returning an integer instead of a float would buy you.
It saves you a function call in the vast majority of cases, where an int is what you ultimately want.
-1 on an extra built-in just to save the time for function call -- this is a false optimization, one that is unlikely to ever be the bottleneck in any real program's running time. If it isn't time you care about but just hate writing it, what's wrong with a simple helper function like: rndint=lambda x: int(round(x)) ? There are no shortage of possible function pairs that could be proposed (perhaps list(set(x)) or int(abs(x)) for example). Of course, it would be silly to make new builtins for them. IMHO, the case is weak for adding a new variant of round(). Also, -10 on changing the semantics of int() to round instead of truncate. The truncating version is found is so many other languages and book examples, that it would be a disaster for us to choose a different meaning. Raymond
On Aug 2, 2006, at 11:26 PM, Raymond Hettinger wrote:
Also, -10 on changing the semantics of int() to round instead of truncate. The truncating version is found is so many other languages and book examples, that it would be a disaster for us to choose a different meaning.
I'd be happy to see floats lose their __int__ method entirely, replaced by an explicit truncate function. I've always thought it quite a hack that python floats have implicit truncation to ints, and then a random smattering of APIs go to extra lengths to explicitly prevent float.__int__ from being called because people thought "passing a float makes no sense!". That's right, it doesn't, and it _never_ should happen implicitly, not just in those particular few cases. Explicit is better than implicit. James
Raymond Hettinger wrote:
-1 on an extra built-in just to save the time for function call
The time isn't the main issue. The main issue is that almost all the use cases for round() involve doing an int() on it afterwards. At least nobody has put forward an argument to the contrary yet. Sure you can define your own function to do this. But that's still a considerable burden when you add up the effort over all the programs that use int(round()). -- Greg
Greg Ewing wrote:
Raymond Hettinger wrote:
-1 on an extra built-in just to save the time for function call
The time isn't the main issue. The main issue is that almost all the use cases for round() involve doing an int() on it afterwards. At least nobody has put forward an argument to the contrary yet.
I'll try to give a valid argument of the contrary. I think you are only considering part of the usefulness of round(). In statistics and science math equations, rounding isn't used to get an integer, but instead used to give an answer that is meaningful within the margin of error of the data being used. Consider an example where you are combining data that had different number of significant digits. Keeping all the digits of your answer gives a false since of accuracy. The extra digits are meaningless because the margin of error is greater than any of the digits that exceed the minimum number of significant digits in your data. So you need to remove the extraneous digits by rounding. Then this answer can be further used as data, and sense the number of significant digits is maintained, the margin of error can be calculated accurately. [ NOTE: While floating point may contribute a significant error to value that are very large or very small, in most cases it is a very small amount in relation to the precision of the calculation and so the error can be managed without too much trouble. In cases where it is a significant factor, another internal representation should probably be considered. I only mention it here because someone would point it out (again) anyway. The accuracy of floating point is not the issue being discussed in this thread. ] It makes since for round have an argument to specify the number of digits of precision to round to and also for it to return floating point numbers because rounding results to a float of n digits of precision is a necessary operation. If you have the default round() case of 0 (and negative) digits of precision return integers, you then have a function that may sometimes returns integers, and sometimes returns floats. This can be problematic if the values are further used in division operations. Which will result in many cases of.. float(round(x)) in order to convert integer results back to floats. See pep-0238: Changing the division operator. http://www.python.org/dev/peps/pep-0238/ While it is true we often will use round along with converting to an integer, it is also true that functions that are predictable and return a single type are easier to use and learn. So the question of which is better is a matter of point of view in this respect. And in regard to using round() combined with division operators in floating point math, it is an issue of least surprises.
Sure you can define your own function to do this. But that's still a considerable burden when you add up the effort over all the programs that use int(round()).
I think the only time it would be a burden is if a single program uses int(round()) many times, otherwise it is only a very small additional amount to type for each program. In the case of single program using it many times, a helper function is a very practical solution. Cheers, Ron
Ron Adam wrote:
Consider an example where you are combining data that had different number of significant digits. Keeping all the digits of your answer gives a false since of accuracy. The extra digits are meaningless because the margin of error is greater than any of the digits that exceed the minimum number of significant digits in your data. So you need to remove the extraneous digits by rounding. Then this answer can be further used as data, and sense the number of significant digits is maintained, the margin of error can be calculated accurately.
This is a fallacy though - add two numbers together each with an error of +/- 0.05, and the error in the total is +/- 0.1. The approach you propose gives the misleading impression that the error in the total is still only +/- 0.05 (as the answer will contain 1 decimal place). If you really care about error, you need to do it properly (e.g. stddev or adding the error margins). Anyway, it's not proposed to remove the "round to x decimal places" capability entirely - merely remove it from the builtin round() so that the return type can be changed.
It makes since for round have an argument to specify the number of digits of precision to round to and also for it to return floating point numbers because rounding results to a float of n digits of precision is a necessary operation.
If you have the default round() case of 0 (and negative) digits of precision return integers, you then have a function that may sometimes returns integers, and sometimes returns floats.
That's not the proposal, as Greg has already said (the fround() mentioned would probably be 'math.fround' rather than a builtin): [Greg Ewing]
No, round() wouldn't have that option at all. If you wanted it, you would use fround() instead, which would have the option and return a float always.
This would be a Py3k thing, obviously. If done before then, the new function would have to be given a different name.
[Ron Adam]
This can be problematic if the values are further used in division operations. Which will result in many cases of.. float(round(x)) in order to convert integer results back to floats.
Not in Py3k where int/int will return a float as needed.
And in regard to using round() combined with division operators in floating point math, it is an issue of least surprises.
And in Py3k, with a round that always returned an integer there wouldn't be any surprises at all: - division would do the right thing, because true division becomes the only behaviour for '/' - the result of the builtin rounding operation would be usable directly as an index without requiring subsequent coercion to an integer Cheers, Nick. -- Nick Coghlan | ncoghlan@gmail.com | Brisbane, Australia --------------------------------------------------------------- http://www.boredomandlaziness.org
Nick Coghlan wrote:
Ron Adam wrote:
Consider an example where you are combining data that had different number of significant digits. Keeping all the digits of your answer gives a false since of accuracy. The extra digits are meaningless because the margin of error is greater than any of the digits that exceed the minimum number of significant digits in your data. So you need to remove the extraneous digits by rounding. Then this answer can be further used as data, and sense the number of significant digits is maintained, the margin of error can be calculated accurately.
This is a fallacy though - add two numbers together each with an error of +/- 0.05, and the error in the total is +/- 0.1. The approach you propose gives the misleading impression that the error in the total is still only +/- 0.05 (as the answer will contain 1 decimal place).
I did say "the margin of error can be calculated accurately". I did not go into detail on the correct method to do that. You do need to round to the correct number of significant digits AND yes, you do need to also take into account the number of items in your data set. If you don't round, the value of your answer would be shifted up or down by the amount of the non significant digits. And the error range would also be shifted up or down by that amount. In any case, my point is (and my opinion) that rounding to floating point types is very common and not something that is needed rarely as it has been expressed in several messages. I don't want to debate the correct method of calculating errors and maintaining accuracy in statistical equations. I'll let the mathematicians do that.
If you really care about error, you need to do it properly (e.g. stddev or adding the error margins).
Yes
Anyway, it's not proposed to remove the "round to x decimal places" capability entirely - merely remove it from the builtin round() so that the return type can be changed.
That would work. This is one of those places where I wonder when should a function be included in a types methods and called by either using arguments with __init__, an external function to call a private method, or by having it be a public method to be called with the dot syntax like is common for strings? If you look at the Decimal type, it has quite of few rounding methods, (as well as other non-underscored methods), while int, float, and long, do not have them. Also the Decimal _round() method returns the number unchanged (max precision) if no precision argument is given where round() has a default precision of 0. Will there be more efforts (in Py3k to unifiy Decimal and the other types so they are more alike in both the way they work and in how they are used? Would it make since for the numeric type to have methods (other than the underscored ones) that can be called with the dot syntax like we do in unicode and the Decimal types that do not have the underscores? Or would it be better to remove those in favor of builtin or module functions? The extremes of both might be a foolish consistency, but this may also be a good area to make some basic improvements for python 3k. (I'm sure Guido and others here have though some on this in general.) If these types gain a round method that all work the same way, then round() can then use those and it would return the same type as it is given. So then round(float(x)), round(int(x)), round(long(x)) and round(Decimal(x)) will return their own type respectfully. And to get a specific type, you would call the types method directly. int.round(x) -> integer Which is nicer than int(round(x)). And the round methods could have arguments to designate the type of rounding to use. Where 'f','c', and 'e' are floor, ceiling, and even rounding. int.round(x, 'c') # 'f' is the default rounding mode The functions round(), roundcieling(), and roundeven() could then call the method of the type with the appropriate argument, although I'd be happy without these round functions if there are round methods are consistent across types. Well, this is the direction I would go in. Hopefully by Python 9000 the decimal type or something equivalent will be as fast as all the others and/or computers will be so fast as to make it irrelevant, then we can have just one scaler base type. ;-) Cheers, Ron
On Thu, 3 Aug 2006, Greg Ewing wrote:
The time isn't the main issue. The main issue is that almost all the use cases for round() involve doing an int() on it afterwards.
That's my experience as well. In my opinion, the purpose of round() is most commonly described as "to make an integer". So it should yield an integer. As other comments in this discussion imply, whether you want round() to return an integer really depends on your intended audience and their pattern of usage. It seems to me that for round() to produce an integer is about as intuitive as for 1/2 to produce 0.5. That is, if you bring basic mathematical intuition to the table instead of a background in how C behaves, then "1/2" suggests one-half and "rounding" suggests "convert to an integer". If you have a background in programming languages and you understand the value of type consistency, then you would see why dividing integers should yield integers and rounding floats should yield floats. Since Python was indeed changed to make 1/2 evaluate to 0.5, that suggests that it is Pythonic to target the first audience rather than the second. And that implies that it would also be Pythonic to make round() return an int. -- ?!ng
On Aug 3, 2006, at 2:34 AM, Greg Ewing wrote:
Raymond Hettinger wrote:
-1 on an extra built-in just to save the time for function call
The time isn't the main issue. The main issue is that almost all the use cases for round() involve doing an int() on it afterwards. At least nobody has put forward an argument to the contrary yet.
And I bet the main reason why round() in python returns a float is because it does in C. And it does in C because C doesn't have arbitrary size integers, so if round returned integers, round(1e+308) couldn't work. In python, however, that's no problem, since python does have arbitrarily big integers. There's also round(float("inf")), of course, which wouldn't be defined if the result was an integer, but I don't think rounding infinity is much of a use case. And I do think the extension of round to allow the specification of number of decimal places was a mistake. If you want that, you probably really mean to do something like round(x * 10**y) instead. James
James Y Knight wrote:
And it does in C because C doesn't have arbitrary size integers, so if round returned integers, round(1e+308) couldn't work.
Also, in C you can use the result directly in an int context without complaint. In Python these days, that is usually disallowed. -- Greg
Greg Ewing wrote:
M.-A. Lemburg wrote:
Believe me: you have to if you want to do more advanced calculus related to pricing and risk analysis of derivatives.
When you do things like that, you're treating money as though it were a continuous quantity. This is an approximation, so you can tolerate having small inaccuracies in the result.
But when adding up actual, real amounts of money, where the result must be exact, using binary fractions is a very bad idea.
Agreed. Those are different use cases, though.
This is not the same: if you round both value and then compare, you test a different interval than by taking the difference and applying a tolerance value comparison:
That's exactly my point. Chopping decimal places is not a substitute for doing tolerance testing properly.
As I said: those two are different ways of doing comparisons. If you are eventually rounding to say 2 decimal places in the end of the calculation, you won't want to find yourself presenting the user 1.12 and 1.13 as equal values :-)
Most typical uses of round() don't use the optional argument, true, but I still fail to see what returning an integer instead of a float would buy you.
It saves you a function call in the vast majority of cases, where an int is what you ultimately want.
-1 on that. Just saving a single function call isn't really enough to break all sorts of applications out there that use round() in calculations (with or without argument). Most such calculations do work with floats, so having round() return an int would just add another coercion to a float for those use-cases. Seriously, rounding is a complicated business. round() just implements one way of doing it. Perhaps a module providing different rounding models would be of use ?! The decimal module already has a few of those implemented, so it could benefit from such a module as well. -- Marc-Andre Lemburg eGenix.com Professional Python Services directly from the Source (#1, Aug 03 2006)
Python/Zope Consulting and Support ... http://www.egenix.com/ mxODBC.Zope.Database.Adapter ... http://zope.egenix.com/ mxODBC, mxDateTime, mxTextTools ... http://python.egenix.com/
::: Try mxODBC.Zope.DA for Windows,Linux,Solaris,FreeBSD for free ! ::::
M.-A. Lemburg wrote:
If you are eventually rounding to say 2 decimal places in the end of the calculation, you won't want to find yourself presenting the user 1.12 and 1.13 as equal values :-)
Even if, before rounding, they were actually 1.12499999999 and 1.125000000001? And if the difference were only due to the unrepresentability of some decimal fraction exactly in binary? I still maintain that (a) rounding a *binary* float to *decimal* places is wrongheaded, and (b) digit chopping is a bad way to decide whether two inexact numbers should be considered equal. Not just a different way, but a poorer way.
Most such calculations do work with floats, so having round() return an int would just add another coercion to a float for those use-cases.
I'm *not* proposing to eliminate round-to-float, despite the fact that I can't see much use for it personally. I'm also *not* advocating changing the existing behaviour of round() or int(). That was just tentative speculation. All I'm asking for is another function that does round-to-int directly. I wouldn't have thought that was such a controversial idea, given the frequency of use for that operation. -- Greg
On Sat, 29 Jul 2006 15:44:33 +1200
Greg Ewing
Michael Urman wrote:
The fact that round returns a float rather than an int, while intentional, does not feature prominently in one's mine when the first version yielded the expected results.
As an aside, does anyone else think that it would be useful to have a builtin which rounds and converts to an int in one go? Whenever I use round(), I almost always want the result as an int, and making me do it in two steps seems unnecessarily bothersome.
It's not even clear to me that int(round(x)) is always the nearest integer to x. Is it always true that float(some_int)>=some_int ? (for positive values). (ie. I am wondering if truncating the float representation of an int always gives back the original int). Simon. -- Simon Burton, B.Sc. Licensed PO Box 8066 ANU Canberra 2601 Australia Ph. 61 2 6249 6940 http://arrowtheory.com
On Jul 28, 2006, at 1:35 PM, Bob Ippolito wrote:
It seems that the pre-2.5 struct module has some additional undocumented behavior[1] that didn't percolate into the new version: http://python.org/sf/1530559
Python 2.4 and previous will coerce floats to integers when necessary as such without any kind of complaint:
$ python2.4 -c "import struct; print repr(struct.pack('>H', 0.9999999999999999))" '\x00\x00'
Python 2.5 refuses to coerce float to int:
$ python2.5 -c "import struct; print repr(struct.pack('>H', 0.9999999999999999))" Traceback (most recent call last): File "<string>", line 1, in <module> File "/Users/bob/src/python/Lib/struct.py", line 63, in pack return o.pack(*args) TypeError: unsupported operand type(s) for &: 'float' and 'long'
The available options are to:
1. Reinstate the pre-2.5 weirdness 2. Reinstate the pre-2.5 weirdness with a DeprecationWarning 3. Break existing code that relies on undocumented behavior (seems more like a bug than lack of specification)
There's a patch in the tracker for 2. It should get applied when the trunk freeze is over. -bob
participants (12)
-
Aahz
-
BJörn Lindqvist
-
Bob Ippolito
-
Greg Ewing
-
James Y Knight
-
Ka-Ping Yee
-
M.-A. Lemburg
-
Michael Urman
-
Nick Coghlan
-
Raymond Hettinger
-
Ron Adam
-
Simon Burton